In VIP, a scoring system exists in order to distribute esINIT rewards to the users based on their activities in a Minitia.
VIP scoring process is as follows:
- Whitelist a Minitia on VIP system
- Minitias are whitelisted through a whitelisting proposal on Initia's governance.
- The information required to whitelist a Minitia are
bridge,contract, andoperatoraddresses. (see vip.move)
- Minitias score users based on their activities on each stage.
- The scoring policy is determined completely by Minitias.
- Initia provides
vip_scorecontracts as default. (e.g. vip_score.move for minimove) - For scoring user, Minitia should whitelist
deployeraddress onvip_scorecontract. - The
deployercould callvip_scorecontract to score users. - See Scoring section for detailed information about how to score users.
- Finalize the stage when scoring is done. (no more scoring is allowed)
- The VIP agent will take a snapshot of the scores.
- VIP agent is an entity that is in charge of submitting snapshots of the scores, and is selected through Initia governance.
- VIP agent will only take snapshots of Minitias that have finalized the stage.
- Rewards will be distributed to the users based on the snapshot.
- User can claim the reward.
- User can claim the reward after the snapshot is taken.
- User's reward will be decreased if the user not meet the minimum score for the stage.
This example is for minimove L2. If you are using other vm, check following:
- miniwasm: vip-cosmwasm
- minievm: vip-evm
Note that the main purpose of vip_score is to score users based on the Minitia's scoring policy. The VIP agent does not interfere with the scoring policies, but Minitias should record the score of users on the same vip_score contract interface for snapshot.
This limits the deployer address that can call vip_score contract. This is to prevent unauthorized access to the contract.
// vip_score.move
public entry fun add_deployer_script(chain: &signer, deployer: address) acquires ModuleStore {
check_chain_permission(chain);
let module_store = borrow_global_mut<ModuleStore>(@minitia_std);
///
/// ....
///
}You can add a deployer address to the whitelist by calling add_deployer_script function. This function is only callable by the chain.
const msg = new MsgExecuteMessages(validatorAddr, [
new MsgGovExecute(
'init1gz9n8jnu9fgqw7vem9ud67gqjk5q4m2w0aejne', // opchild module addr
'init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d', // 0x1
'0x1',
'vip_score',
'add_deployer_script',
[],
[bcs.address().serialize(deployerAddr).toBase64()]
)
])By this, deployer can call vip_score contract to score user.
There are two ways to score users.
This method integrates scoring logic with the smart contract. This is useful when the scoring logic is simple and can be done in a single transaction.
Check the example contract. See example
❗Note❗ For integrate with contract, you should call
prepare_stagefunction before scoring users. You can call this function only once for each stage. This function will initialize the stage and set the stage as active. Seefun prepare_stage_script()function in score_helper.move
This method is useful when the scoring logic is complex and requires multiple transactions. In this case, you can update all scores at once by calling update_score_script function.
public entry fun update_score_script(
deployer: &signer,
stage: u64,
addrs: vector<address>,
scores: vector<u64>
) acquires ModuleStore {
assert!(
vector::length(&addrs) == vector::length(&scores),
error::invalid_argument(ENOT_MATCH_LENGTH)
);
prepare_stage(deployer, stage);
vector::enumerate_ref(
&addrs,
|i, addr| {
update_score(
deployer,
*addr,
stage,
*vector::borrow(&scores, i),
);
}
);
}Calling update_score_script function might exceed the gas limit if the number of users is too large. In this case, you can divide the users into multiple transactions.
Check the example script to update the score. See example
Finalizing the stage is the last step of the scoring process. After this, no more scoring is allowed until the next stage. Stage must be finalized in order for the VIP agent to take a snapshot of the scoring result. If not finalized, reward distribution will not happen.
// vip_score.move
public entry fun finalize_script(deployer: &signer, stage: u64) acquires ModuleStore {
check_deployer_permission(deployer);
let module_store = borrow_global_mut<ModuleStore>(@minitia_std);
///
/// ....
///
}const msg = new MsgExecute(
deployerAddr,
'0x1',
'vip_score',
'finalize_script',
[],
[bcs.u64().serialize(stage).toBase64()]
)