#
Loyalty Program
#
Feature
The Loyalty Program plugin includes the following component:
- Reward Pool: This is where you configure a list of rewards that can be randomly selected and awarded to users.
- Reward Stack: This defines the specific details of a reward, such as what it is and how it's awarded
- Rewarding Flow: This determines the specific conditions that must be met in order for a reward to be granted. It outlines the steps involved in awarding a reward

#
Installation
@Module({
imports: [
LoyaltyModule.forRoot({
dataSourceName: DataSourceSupport.POSTGRESQL
}),
]
})
#
UnitReward Registration
To register a new RewardUnit. You need implement the RewardUnitPolicy. Create a new class that implements this interface to define the specific logic and behavior of your RewardUnit.
interface RewardUnitPolicy {
type: () => string;
dataSchema: () => TObject;
resolveData: (data: unknown) => unknown;
sources: () => Promise<Sources>;
delivery: (account: Account, rewardUnitData: unknown) => Promise<void>;
}
For example to implement PerkRewardUnitPolicy
const DATA_SOURCE_NAME = 'perk';
export const PERK_REWARD_UNIT_TOKEN = 'PERK_REWARD_UNIT_TOKEN';
type DataPayload = {
type: string;
id: string;
};
type Resource = {
type: string;
data: GetAllPerkTemplatesReturnType[];
};
export class PerkRewardUnitPolicy implements RewardUnitPolicy, OnModuleInit {
private sdk: BlockchainSDK;
constructor(
private moduleRef: ModuleRef,
private readonly blockchainService: BlockchainService,
) {}
async onModuleInit() {
this.sdk = await BlockchainSDK.init({
nodeUrlPool: process.env.PUBLIC_BLOCKCHAIN_NODE_URL_POOL ?? '',
blockchainRid: process.env.PUBLIC_BLOCKCHAIN_RID ?? '',
});
const signer = new ethers.Wallet(
process.env.ADMIN_WALLET_PRIVATE_KEY ?? '',
);
await this.sdk.login(signer);
}
type = () => DATA_SOURCE_NAME;
dataSchema() {
return Type.Object({
id: Type.String(),
});
}
resolveData(perk: GetAllPerkTemplatesReturnType): DataPayload {
return {
type: DATA_SOURCE_NAME,
id: perk.id.toString(),
};
}
async sources(): Promise<Resource> {
const data = await this.sdk.perk.getAllPerkTemplatesPromise();
return {
type: DATA_SOURCE_NAME,
data,
};
}
async delivery(account: Account, data: RewardUnit) {
console.info('[DEBUG][data]', data);
if (!account.chromiaAccountId) return;
const owner = Buffer.from(account.chromiaAccountId, 'hex');
const rewardData = data.data as any;
const perk = Number(rewardData.id);
this.sdk.perk.adminGivePerkOperation(owner, perk);
return;
}
}
Once the implementation is complete, register the new RewardUnit within your application's configuration or dependency injection framework.
@Module({
imports: [
LoyaltyModule.register({
rewardUnitsPolicy: [
{
provide: PERK_REWARD_UNIT_TOKEN,
useClass: PerkRewardUnitPolicy,
},
],
loyaltyEventPolicies: [],
}),
],
})
#
Trigger Event to active the rewarding flow
After the reward unit is registered, When developer want to trigger the event to active the rewarding flow.
you can call emitEvent from LoyaltyService
const finalReward = await this.loyaltyService.emitEvent(user, {
type: 'perk',
relatedEntityId: 1,
relatedEntityType: 'game',
payload: {}
})
#
Core
Execute rule and delivery reward
@Injectable()
export class LoyaltyService {
constructor(
private readonly ruleEngineService: RewardingFlowService,
private readonly rewardService: RewardStackService
) { }
async emitEvent(account: Account, event: LoyaltyEvent): Promise<void> {
const rewardPoolId = await this.eligibilityCheck(account, event)
await this.deliveryReward(account, rewardPoolId)
}
async eligibilityCheck(account: Account, event: LoyaltyEvent) {
const response = await this.ruleEngineService.execute(account, event)
if (!response.rewardPoolId) throw new BadRequestException('rewardPoolId not found')
return response.rewardPoolId
}
async deliveryReward(account: Account, rewardPoolId: string) {
return this.rewardService.claim(account, rewardPoolId)
}
}
#
Q/A
#
How does the plugin handle multiple reward pools?
The plugin should support multiple reward pools, each with its own set of rules and rewards. This allows for targeted reward campaigns and personalized experiences.
#
How does the plugin handle reward stacking and combining?
The plugin should allow for flexible reward stacking and combining rules. This allows for more complex reward structures and personalized experiences.
#
How does the plugin ensure fairness and transparency in reward distribution?
The plugin should use a fair and transparent random selection process to distribute rewards. It should also provide clear information about the rules and eligibility criteria for each reward.
#
Can I set up a reward pool with multiple rewards, each with a different probability?
Absolutely! You can create a reward pool that contains a diverse range of rewards, each with its own unique probability of being awarded. This feature provides you with the flexibility to tailor your loyalty program to your specific needs and preferences. By assigning different probabilities, you can control the frequency with which certain rewards are distributed, ensuring that your program remains engaging and exciting for your users.
#
Can I set up multiple reward pools for different purposes and strategies?
Our plugin allows you to create multiple reward pools with customizable configurations. Each pool can have its own set of rewards, probability weights, and qualifying criteria. This flexibility enables you to build a dynamic and effective loyalty program that meets the diverse needs of your customers.