diff --git a/developers/developer-guides/integrating-initia-apps/usernames.mdx b/developers/developer-guides/integrating-initia-apps/usernames.mdx index 5ded2b50..0f6e63fa 100644 --- a/developers/developer-guides/integrating-initia-apps/usernames.mdx +++ b/developers/developer-guides/integrating-initia-apps/usernames.mdx @@ -1,5 +1,5 @@ --- -title: Querying Initia Usernames +title: Integrating Initia Usernames --- ## Module Addresses @@ -10,77 +10,179 @@ title: Querying Initia Usernames ## Tutorials -### Getting Address from Usernames +### Registering a Username -To retrieve an address from a username, the `get_address_from_name` view function is used. The function interface is as follows: +To register and set a username, the `register_domain` and `set_name` functions are used. The function interfaces are as follows: ```move -#[view] -public fun get_address_from_name(name: String): Option
+public entry fun register_domain(account: &signer, domain_name: String, duration: u64) +public entry fun set_name(account: &signer, domain_name: String) ``` -```js InitiaJS -const { LCDClient, bcs } = require('@initia/initia.js'); - -const moduleAddress = '0x...'; -const lcdUri = 'https://...'; -const name = 'initia'; -const lcd = new LCDClient(lcdUri); - -lcd.move - .view( - moduleAddress, - 'usernames', - 'get_address_from_name', - [], - [bcs.string().serialize(name).toBase64()] +The following example demonstrates how to register and set a username using InitiaJS: + +```ts InitiaJS +import { bcs, LCDClient, MnemonicKey, MsgExecute, Wallet } from '@initia/initia.js'; + +async function main() { + const moduleAddress = '0x...'; + const lcdUri = 'https://...'; + + const domainName = 'initia'; + const duration = 31557600; // 1 year + + const lcd = new LCDClient('https://lcd.ininiation-1.initia.xyz', { + gasAdjustment: '1.75', + gasPrices: '0.15uinit' + }) + + const wallet = new Wallet( + lcd, + new MnemonicKey({ + mnemonic: 'power elder gather acoustic valid ... ' + }) ) - .then(console.log); - -// Response: -// { -// data: '"0x.."', -// events: [], -// gas_used: '5699' -// } + + const msgs = [ + new MsgExecute( + wallet.key.accAddress, + moduleAddress, + 'usernames', + 'register_domain', + [], + [ + bcs.string().serialize(domainName).toBase64(), + bcs.u64().serialize(duration).toBase64(), + ] + ), + new MsgExecute( + wallet.key.accAddress, + moduleAddress, + 'usernames', + 'set_name', + [], + [ + bcs.string().serialize(domainName).toBase64(), + ] + ) + ] + + const signedTx = await wallet.createAndSignTx({ msgs }) + await wallet.lcd.tx.broadcastSync(signedTx).then(res => console.log(res)); +} ``` -### Getting Usernames from Address +### Getting Address and Usersnames -To retrieve a username from an address, the `get_name_from_address` view function is utilized: +To retrieve an address from a username, the `get_address_from_name` and `get_name_from_address` view function is used. The function interfaces are as follows: ```move +#[view] +public fun get_address_from_name(name: String): Option
+ #[view] public fun get_name_from_address(addr: address): Option ``` -```js InitiaJS -const { LCDClient, bcs } = require('@initia/initia.js'); - -const moduleAddress = '0x...'; -const lcdUri = 'https://...'; -const address = "init1..."; -const lcd = new LCDClient(lcdUri); - -lcd.move - .view( - moduleAddress - 'usernames', - 'get_name_from_address', - [], - [ - bcs - .address() - .serialize(address) - .toBase64(), - ] +The following example demonstrates how to retrieve an address from a username using InitiaJS: + +```ts InitiaJS +import { bcs, LCDClient } from '@initia/initia.js'; + +async function main() { + const moduleAddress = '0x...'; + const lcdUri = 'https://...'; + const name = 'initia'; + const lcd = new LCDClient(lcdUri); + + lcd.move + .view( + moduleAddress, + 'usernames', + 'get_address_from_name', + [], + [bcs.string().serialize(name).toBase64()] + ) + .then(console.log); + + // Response: + // { + // data: '"0x.."', + // events: [], + // gas_used: '5699' + // } + + lcd.move + .view( + moduleAddress + 'usernames', + 'get_name_from_address', + [], + [ + bcs + .address() + .serialize(address) + .toBase64(), + ] + ) + .then(console.log); + + // Response: + // { + // data: '"abc..."', + // events: [], + // gas_used: '5699' + // } +} +``` + +### Extening expiration dates + +To extend the expiration date of a domain, the `extend_expiration` function is used. The function interface is as follows: + +```move +public entry fun extend_expiration(account: &signer, domain_name: String, duration: u64) +``` + +The following example demonstrates how to extend the expiration date of a domain using InitiaJS: + +```ts InitiaJS +import { bcs, LCDClient, MnemonicKey, MsgExecute, Wallet } from '@initia/initia.js'; + +async function main() { + const moduleAddress = '0x...'; + const lcdUri = 'https://...'; + + const domainName = 'initia'; + const duration = 31557600; // 1 year + + const lcd = new LCDClient('https://lcd.ininiation-1.initia.xyz', { + gasAdjustment: '1.75', + gasPrices: '0.15uinit' + }) + + const wallet = new Wallet( + lcd, + new MnemonicKey({ + mnemonic: 'power elder gather acoustic valid ... ' + }) ) - .then(console.log); - -// Response: -// { -// data: '"abc..."', -// events: [], -// gas_used: '5699' -// } + + const msgs = [ + new MsgExecute( + wallet.key.accAddress, + moduleAddress, + 'usernames', + 'extend_expiration', + [], + [ + bcs.string().serialize(domainName).toBase64(), + bcs.u64().serialize(duration).toBase64(), + ] + ) + ] + + const signedTx = await wallet.createAndSignTx({ msgs }) + await wallet.lcd.tx.broadcastSync(signedTx).then(res => console.log(res)); +} ``` \ No newline at end of file diff --git a/developers/developer-guides/vm-specific-tutorials/evm/vip-scoring-tutorial.mdx b/developers/developer-guides/vm-specific-tutorials/evm/vip-scoring-tutorial.mdx new file mode 100644 index 00000000..653dfe1a --- /dev/null +++ b/developers/developer-guides/vm-specific-tutorials/evm/vip-scoring-tutorial.mdx @@ -0,0 +1,5 @@ +--- +title: VIP Scoring Tutorial +--- + +Comming soon. \ No newline at end of file diff --git a/developers/developer-guides/vm-specific-tutorials/movevm/vip-scoring-tutorial.mdx b/developers/developer-guides/vm-specific-tutorials/movevm/vip-scoring-tutorial.mdx new file mode 100644 index 00000000..6e1218bf --- /dev/null +++ b/developers/developer-guides/vm-specific-tutorials/movevm/vip-scoring-tutorial.mdx @@ -0,0 +1,328 @@ +--- +title: VIP Scoring Tutorial +--- + +## Introduction + +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: + +1. **Whitelist a Minitia**: Minitias are whitelisted via Initia governance, requiring details like `bridge id`, `vip score contract address`, and `operator address` etc. +2. **Score Users**: Minitias score users based on activities using the `vip_score` contract. After scoring, the stage is finalized, preventing further updates. +3. **Snapshot by VIP Agent**: The VIP agent, selected through governance, takes snapshots of finalized scores for reward distribution. +4. **Claim Reward**: Users can claim rewards after the snapshot is taken. + +## Interacting with the `vip_score` contract + +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. + +#### How to Setup + +This section explains how to compile and deploy the `vip_score` contract. + +[VIP Move contract](https://github.com/initia-labs/movevm/blob/main/precompile/modules/minitia_stdlib/sources/vip/score.move) is deployed default on MiniMove Chain + + + + Check the `rev = "e13e78d"` in `Move.toml`. The value should be the same as the commit hash of the movevm version. You can check your `movevm` version in minimove `go.mod` file. + + Compile the contract by running the following command: + + ```bash + cd contract/minimove + minitiad move build + ``` + + If compiled successfully, you can get `build` directory like: + + ``` + . + ├── Move.toml + ├── build + └── sources + └── score.move + ``` + + Get the `vip_score.mv` from `build/score/bytecode_modules/vip_score.mv` + + + The `score.move` contract is a contract deployed only on L2. To deploy this contract, the key of the L2 operator (validator) is required. + + + + ```ts InitiaJS + const score = path.join(filePath, 'vip_score.mv') + const msg = new MsgExecuteMessages(validatorAddr, [ + new MsgGovPublish( + 'init1gz9n8jnu9fgqw7vem9ud67gqjk5q4m2w0aejne', // opchild module addr + 'init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d', // 0x1 + [fs.readFileSync(score, 'base64')], + 1 + ) + ]) + ``` + + + You can get `code_bytes` easily by using some [tools](https://base64.guru/converter/encode/file). + + ```json + // msg.json + { + "messages": [ + { + "@type": "/initia.move.v1.MsgGovPublish", + "authority": "init1gz9n8jnu9fgqw7vem9ud67gqjk5q4m2w0aejne", + "sender": "init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d", + "code_bytes": ["oRzrCwYAAAALAQAOAg4oAzb9AQSzA..."], // vip_score.mv + "upgrade_policy": 1 // compatible policy + } + ] + } + ``` + + ```bash + minitiad tx opchild execute-messages ./msg.json \ + --from operator \ + --chain-id [chain-id] \ + --gas auto \ + --gas-adjustment 1.5 \ + --node [rpc-url] + ``` + + + + + +#### How to Use + +This section explains how to use the `vip_score` contract to score users. + + + + + This limits the deployer address that can call `vip_score` contract. This is to prevent unauthorized access to the contract. + Same deployer can't be added more than once. + + The `add_deployer_script` function is used to whitelist the deployer address. + ```move + // vip_score.move + public entry fun add_deployer_script(chain: &signer, deployer: address) acquires ModuleStore {} + ``` + + ```ts InitiaJS + const msg = new MsgExecuteMessages(validatorAddr, [ + new MsgGovExecute( + 'init1gz9n8jnu9fgqw7vem9ud67gqjk5q4m2w0aejne', // opchild module addr + 'init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d', // 0x1 + '0x1', + 'vip_score', + 'add_deployer_script', + [], + [bcs.address().serialize(deployerAddr).toBase64()] + ) + ]) + ``` + You have to add your bcs serialized `deployerAddr` in `args` field. + + > For now, we can serialize bcs serialized addr using `initia.js`. + > we will soon support bcs serialization using `minitiad`. + > + > ```ts InitiaJS + > import { bcs } from "@initia/initia.js" + > console.log(bcs.address().serialize("init1wgl839zxdh5c89mvc4ps97wyx6ejjygxs4qmcx").toBase64()) // AAAAAAAAAAAAAAAAcj54lEZt6YOXbMVDAvnENrMpEQY= + > ``` + + + ```json + // msg.json + { + "messages": [ + { + "@type": "/initia.move.v1.MsgGovExecute", + "authority": "init1gz9n8jnu9fgqw7vem9ud67gqjk5q4m2w0aejne", + "sender": "init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d", + "module_address": "0x1", + "module_name": "vip_score", + "function_name": "add_deployer_script", + "type_args":[], + "args":[ + "AAAAAAAAAAAAAAAAcj54lEZt6YOXbMVDAvnENrMpEQY=" // deployerAddr + ] + } + ] + } + ``` + + ```bash + minitiad tx opchild execute-messages ./msg.json \ + --from operator \ + --chain-id [chain-id] \ + --gas auto \ + --gas-adjustment 1.5 \ + --node [rpc-url] + ``` + + By this, `deployer` can call `vip_score` contract to score user. + + + + Prepare the stage before scoring users. This function should be called only once for each stage. This function will initialize the stage and set the stage as active. + ```move + // vip_score.move + public entry fun prepare_stage(deployer: &signer, stage: u64) acquires ModuleStore {} + ``` + + ```ts InitiaJS + const msg = new MsgExecute( + deployerAddr, + '0x1', + 'vip_score', + 'prepare_stage', + [], + [bcs.u64().serialize(stage).toBase64()] + ) + ``` + + + 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. + + For integrate with contract, you should call `prepare_stage` function 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. See `fun prepare_stage_script()` function in [score_helper.move](./example/1.integrate-with-contract/sources/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. + + ```move + public entry fun update_score_script( + deployer: &signer, + stage: u64, + addrs: vector
, + scores: vector + ) acquires ModuleStore {} + ``` + + 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. + + ```ts InitiaJS + const BCS_BUFFER_SIZE = 1000 * 1024 // 1MB + const msg = new MsgExecute( + deployerAddr, + '0x1', + 'vip_score', + 'update_score_script', + [], + [ + bcs.u64().serialize(stage).toBase64(), + bcs.vector(bcs.address()).serialize(addresses, { size: BCS_BUFFER_SIZE }).toBase64(), + bcs.vector(bcs.u64()).serialize(scores, { size: BCS_BUFFER_SIZE }).toBase64() + ] + ) + ``` + + + + + Finalizing the stage is the last step of the scoring process. + 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. + + ```move + // vip_score.move + public entry fun finalize_script(deployer: &signer, stage: u64) acquires ModuleStore {} + ``` + + ```ts InitiaJS + const msg = new MsgExecute( + deployerAddr, + '0x1', + 'vip_score', + 'finalize_script', + [], + [bcs.u64().serialize(stage).toBase64()] + ) + ``` + + No more scoring is allowed after finalizing the stage. + + + + + +#### Claiming Operator Reward + +This is a guide for claiming operator reward on VIP system. + +- The operator address and bridge_id should match the information whitelisted during registration in the VIP system. +- The operator reward must be claimed on the L1 chain, not on the L2 chain. +- All stages that can be claimed must be provided in sequence. + + + + ```ts InitiaJS + import { + bcs, + LCDClient, + MnemonicKey, + MsgExecute, + Wallet, + } from '@initia/initia.js'; + + async function claimOperatorVesting() { + const lcd = new LCDClient('[rest-url]', { + gasPrices: '0.15uinit', + gasAdjustment: '1.5', + }); + + const key = new MnemonicKey({ + mnemonic: 'beauty sniff protect ...', + }); + const wallet = new Wallet(lcd, key); + + const bridgeId = 1; + const stages = [1,2,3]; // stages to claim + const msgs = [ + new MsgExecute( + key.accAddress, + '0x1', + 'vip', + 'batch_claim_operator_reward_script', + [], + [ + bcs.u64().serialize(bridgeId).toBase64(), + bcs.vector(bcs.u64()).serialize(stages).toBase64(), + ] + ), + ]; + + // sign tx + const signedTx = await wallet.createAndSignTx({ msgs }); + // broadcast tx + lcd.tx.broadcastSync(signedTx).then(res => console.log(res)); + // { + // height: 0, + // txhash: '0F2B255EE75FBA407267BB57A6FF3E3349522DA6DBB31C0356DB588CC3933F37', + // raw_log: '[]' + // } + } + + claimOperatorVesting(); + ``` + + + ```bash + # assume that claiming operator reward for stages 1,2,3 + initiad tx move execute 0x1 vip batch_claim_operator_reward_script \ + --args '["u64:1", "vector:1,2,3"]' \ + --from [key-name] \ + --gas auto --gas-adjustment 1.5 --gas-prices 0.15uinit \ + --node [rpc-url]:[rpc-port] --chain-id [chain-id] + ``` + + \ No newline at end of file diff --git a/developers/developer-guides/vm-specific-tutorials/wasmvm/vip-scoring-tutorial.mdx b/developers/developer-guides/vm-specific-tutorials/wasmvm/vip-scoring-tutorial.mdx new file mode 100644 index 00000000..a698b543 --- /dev/null +++ b/developers/developer-guides/vm-specific-tutorials/wasmvm/vip-scoring-tutorial.mdx @@ -0,0 +1,196 @@ +--- +title: VIP Scoring Tutorial +--- + +## Introduction + +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: + +1. **Whitelist a Minitia**: Minitias are whitelisted via Initia governance, requiring details like `bridge id`, `vip score contract address`, and `operator address` etc. +2. **Score Users**: Minitias score users based on activities using the `vip_score` contract. After scoring, the stage is finalized, preventing further updates. +3. **Snapshot by VIP Agent**: The VIP agent, selected through governance, takes snapshots of finalized scores for reward distribution. +4. **Claim Reward**: Users can claim rewards after the snapshot is taken. + +## Interacting with the `vip_score` contract + +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. + +#### How to Setup + +For deploy the `vip_score` contract, refer the [CosmWasm official docs](https://docs.cosmwasm.com/). + +You can deploy [VIP CosmWasm contract](https://github.com/initia-labs/vip-cosmwasm) as same as other CosmWasm contracts. + +#### How to Use + +This section explains how to use the `vip_score` contract to score users. + + + + When you instantiate the contract, you should provide the `allow_list` as arguments. + + ```ts InitiaJS + const msg = new MsgInstantiateContract( + key.accAddress, // sender + key.accAddress, // admin + 9, // code id + 'vip_score', // label + Buffer.from(JSON.stringify({ allow_list: [key.accAddress] })).toString('base64'), // instantiate msg + new Coins() + ) + ``` + + + Prepare the stage before scoring users. This function should be called only once for each stage. This function will initialize the stage and set the stage as active. + + ```ts InitiaJS + const msg = new MsgExecuteContract( + key.accAddress, + 'init1jue5rlc9dkurt3etr57duutqu7prchqrk2mes2227m52kkrual3qdrydg6', // contract address + Buffer.from( + JSON.stringify({ + prepare_stage: { + stage: 1, + }, + })).toString('base64'), + new Coins() + ) + ``` + + + There are two ways to score users. + + + 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` function. + Calling `update_score` 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. + + ```ts InitiaJS + const msg = new MsgExecuteContract( + key.accAddress, + 'init1jue5rlc9dkurt3etr57duutqu7prchqrk2mes2227m52kkrual3qdrydg6', // contract address + Buffer.from( + JSON.stringify({ + update_scores: { + stage: 1, + scores: [ + ['init1lf0swvvhy3vqautdemmvunfmp0grfrjgzznx9s', 400], + ['init1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqr5e3d', 300], + [ + 'init1436kxs0w2es6xlqpp9rd35e3d0cjnw4sv8j3a7483sgks29jqwgs9nxzw8', + 700, + ], + ], + }, + }) + ).toString('base64'), + new Coins() + ) + ``` + + + 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. + For integrate with contract, you should call `prepare_stage` function 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. + + + + + Finalizing the stage is the last step of the scoring process. + 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. + + ```ts InitiaJS + const msg = new MsgExecuteContract( + key.accAddress, + 'init1jue5rlc9dkurt3etr57duutqu7prchqrk2mes2227m52kkrual3qdrydg6', // contract address + Buffer.from( + JSON.stringify({ + finalize_stage: { + stage: 1, + }, + }) + ).toString('base64'), + new Coins() + ) + ``` + + No more scoring is allowed after finalizing the stage. + + + + + +#### Claiming Operator Reward + +This is a guide for claiming operator reward on VIP system. + +- The operator address and bridge_id should match the information whitelisted during registration in the VIP system. +- The operator reward must be claimed on the L1 chain, not on the L2 chain. +- All stages that can be claimed must be provided in sequence. + + + + ```bash + # assume that claiming operator reward for stages 1,2,3 + initiad tx move execute 0x1 vip batch_claim_operator_reward_script \ + --args '["u64:1", "vector:1,2,3"]' \ + --from [key-name] \ + --gas auto --gas-adjustment 1.5 --gas-prices 0.15uinit \ + --node [rpc-url]:[rpc-port] --chain-id [chain-id] + ``` + + + ```ts InitiaJS + import { + bcs, + LCDClient, + MnemonicKey, + MsgExecute, + Wallet, + } from '@initia/initia.js'; + + async function claimOperatorVesting() { + const lcd = new LCDClient('[rest-url]', { + gasPrices: '0.15uinit', + gasAdjustment: '1.5', + }); + + const key = new MnemonicKey({ + mnemonic: 'beauty sniff protect ...', + }); + const wallet = new Wallet(lcd, key); + + const bridgeId = 1; + const stages = [1,2,3]; // stages to claim + const msgs = [ + new MsgExecute( + key.accAddress, + '0x1', + 'vip', + 'batch_claim_operator_reward_script', + [], + [ + bcs.u64().serialize(bridgeId).toBase64(), + bcs.vector(bcs.u64()).serialize(stages).toBase64(), + ] + ), + ]; + + // sign tx + const signedTx = await wallet.createAndSignTx({ msgs }); + // broadcast tx + lcd.tx.broadcastSync(signedTx).then(res => console.log(res)); + // { + // height: 0, + // txhash: '0F2B255EE75FBA407267BB57A6FF3E3349522DA6DBB31C0356DB588CC3933F37', + // raw_log: '[]' + // } + } + + claimOperatorVesting(); + ``` + + \ No newline at end of file diff --git a/mint.json b/mint.json index 12d13694..698ca5ec 100644 --- a/mint.json +++ b/mint.json @@ -208,7 +208,8 @@ ] }, "developers/developer-guides/vm-specific-tutorials/evm/connect-oracles", - "developers/developer-guides/vm-specific-tutorials/evm/ibc-hooks" + "developers/developer-guides/vm-specific-tutorials/evm/ibc-hooks", + "developers/developer-guides/vm-specific-tutorials/evm/vip-scoring-tutorial" ] }, { @@ -217,7 +218,8 @@ "pages": [ "developers/developer-guides/vm-specific-tutorials/movevm/creating-move-coin", "developers/developer-guides/vm-specific-tutorials/movevm/connect-oracles", - "developers/developer-guides/vm-specific-tutorials/movevm/ibc-hooks" + "developers/developer-guides/vm-specific-tutorials/movevm/ibc-hooks", + "developers/developer-guides/vm-specific-tutorials/movevm/vip-scoring-tutorial" ] }, { @@ -225,7 +227,8 @@ "icon": "rust", "pages": [ "developers/developer-guides/vm-specific-tutorials/wasmvm/connect-oracles", - "developers/developer-guides/vm-specific-tutorials/wasmvm/ibc-hooks" + "developers/developer-guides/vm-specific-tutorials/wasmvm/ibc-hooks", + "developers/developer-guides/vm-specific-tutorials/wasmvm/vip-scoring-tutorial" ] } ]