Cw20 Staking App
Deploying a cw20 staking App using the Andromeda CLI.
If unfimailar with the steps of deploying an app, go back to the first example where we explain in detail all the different parts of deploying an App.
If any of the messages in this example do not work, you might want to cross reference the messages with the ADO specific section which always contains the latest ADO versions to make sure they are correct. Other than that the logic will remain the same.
The examples use uni-5 testnet. As of now, Juno has upgraded to uni-6. The steps of building the App remain the same.
For this example, we will assume that we have a project that wants to create their own cw-20 token that can be staked for rewards.
The steps we will perform:
- Mint some coins to different addresses
- Stake some of the coins for rewards of our choice
- Check that all the results are as expected
The components/ADOs we would need:
Although not necessary, if you are unfamiliar with these ADOs, it is suggested to read through each of the them before deploying an app.
Let us first start by representing the instantiation message for each of our ADOs:
Keep in mind that the app takes these messages as base64 encoded.
I will start out by giving 10000 tokens to three addresses. We have not set a minter, meaning no additional tokens can ever be minted.
{
"name": "Staking Token",
"symbol":"STK",
"decimals":6,
"initial_balances":[
{
"address":"juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem",
"amount":"10000"
},
{
"address":"juno1e53vtk7fmqzfttdvpf4a3pyx0e79wkmjzh6qsk",
"amount":"10000"
},
{
"address":"juno19s3l3wh5a3w5dpyv6v2342aej39mwmjea8vpsn",
"amount":"10000"
}
]
}
As Base64:
eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6Imp1bm8xemtwdGhxc3ozdWQ5N2ZtNnA0a3hjcmE4YWU5OWpnemF1dWd5ZW0iLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xZTUzdnRrN2ZtcXpmdHRkdnBmNGEzcHl4MGU3OXdrbWp6aDZxc2siLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xOXMzbDN3aDVhM3c1ZHB5djZ2MjM0MmFlajM5bXdtamVhOHZwc24iLCJhbW91bnQiOiIxMDAwMCJ9IF19ICA=
We have not set any additional rewards. This means that the rewards are the same as the staking token as most staking works. If you want, you can add up to 10 different reward tokens to the staking.
{
"staking_token":{
"identifier":"cw20"
}
}
As Base64:
eyJzdGFraW5nX3Rva2VuIjp7ImlkZW50aWZpZXIiOiJjdzIwIn19
The primitive address used here might be outdated in the future. Check our deployed contracts to get the latest registry.
{
"name": "Staking App",
"app": [
{
"name": "cw20",
"ado_type": "cw20",
"instantiate_msg": "eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6Imp1bm8xemtwdGhxc3ozdWQ5N2ZtNnA0a3hjcmE4YWU5OWpnemF1dWd5ZW0iLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xZTUzdnRrN2ZtcXpmdHRkdnBmNGEzcHl4MGU3OXdrbWp6aDZxc2siLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xOXMzbDN3aDVhM3c1ZHB5djZ2MjM0MmFlajM5bXdtamVhOHZwc24iLCJhbW91bnQiOiIxMDAwMCJ9IF19ICA="
},
{
"name": "staking",
"ado_type": "cw20-staking",
"instantiate_msg": "eyJzdGFraW5nX3Rva2VuIjp7ImlkZW50aWZpZXIiOiJjdzIwIn19"
}
],
"primitive_contract": "juno133fdsnvcah870exzcyxknydswyh778jfhwxzlhhgjuagh4482zpqp856dz"
}
If you do not have the CLI downloaded, go to the Introduction to Apps section to get the latest version.
First, let us open the CLI by running
andr
in our terminal. We then need to choose the chain we want to deploy on. Run "chain use"
in the CLI and select the testnet that you want to deploy on. For this example I will be using the juno testnet uni-5.If this is the first time using the CLI make sure to run
"wallets add <wallet-name>"
in order to create a wallet. Then go to that chain's faucet (usually located in their discord) and request tokens.We have already uploaded the App ADO to the uni-5 testnet. The code I will use is 98. This code Id will most likely be outdated in the future. A simple way to check the latest code id for the App ADO is to query it from the ADODB using the the chain you want to use.
In the CLI, while connected to the chain of choice, run:
ado db getcodeid app
The code Id to use will be returned.
Now we can instantiate our App. We will be using our wasm command to instantiate our app:
wasm instantiate 98 '{"name": "Staking App","app": [{"name": "cw20","ado_type": "cw20","instantiate_msg": "eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6Imp1bm8xemtwdGhxc3ozdWQ5N2ZtNnA0a3hjcmE4YWU5OWpnemF1dWd5ZW0iLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xZTUzdnRrN2ZtcXpmdHRkdnBmNGEzcHl4MGU3OXdrbWp6aDZxc2siLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xOXMzbDN3aDVhM3c1ZHB5djZ2MjM0MmFlajM5bXdtamVhOHZwc24iLCJhbW91bnQiOiIxMDAwMCJ9IF19ICA="},{"name": "staking","ado_type": "cw20-staking","instantiate_msg": "eyJzdGFraW5nX3Rva2VuIjp7ImlkZW50aWZpZXIiOiJjdzIwIn19"}],"primitive_contract": "juno133fdsnvcah870exzcyxknydswyh778jfhwxzlhhgjuagh4482zpqp856dz"}'
You will be using the contract addresses that were instantiated for you instead of the ones in this tutorial. The addresses are found in the explorer in the "Instantiates" section.
Andromeda contracts assign the original instantiator as contract owners. Due to how instantiation via a submessage operates in CosmWasm contracts, we must claim ownership of the components in order to execute messages that have authorization restrictions (owner restricted).
{
"claim_ownership":{}
}
wasm execute juno1mgwet8dksqsjvx2u7evy9wyxwtj5cp8gftw7k4zzh4cqsdmaa38ql7sueh '{"claim_ownership":{}}'
To stake tokens we perform a
send
message from Token contract and attach the Stake{}
message to it. For user 1 we will stake 3000 tokens. {
"send":{
"contract":"juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu",
"amount":"3000",
"msg":"ewogICAgInN0YWtlX3Rva2VucyI6e30KICAgIAp9"
}
}
Here the attached message is:
{
"stake_tokens":{}
}
Let us execute it:
wasm execute juno17ssms3dz3n88ltauh2735df6qslxttpxst0njsd8nx3x9vde5yfqyztl5p '{"send":{"contract":"juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu","amount":"3000","msg":"ewogICAgInN0YWtlX3Rva2VucyI6e30KICAgIAp9"}}'
We perform the same steps to stake for users 2 and 3:
Make sure to change wallet for each user.
Let us check the staker data for user 1:
junod query wasm contract-state smart juno1wf526ma0mjskhlgrun9qkytelnfsl5pny3l2gwvpgjqwhcrx2q8qpqg53f '{"staker":{"address":"juno197y44w58djquqkpu8v56pgwvm058f6jswm0jec"}}'
– Querying contract...
{
"address": "juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem",
"share": "3000",
"balance": "3000",
"pending_rewards": []
}
Here we check one of the stakers. As we can see, the pending rewards are empty and the balance is the same as the share.
Now let us send 1000 tokens to the contract. By doing this, we are telling the contract to use them as rewards for stakers.
{
"transfer":{
"recipient":"juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu",
"amount": "1000"
}
}
wasm execute juno17ssms3dz3n88ltauh2735df6qslxttpxst0njsd8nx3x9vde5yfqyztl5p '{"transfer":{"recipient":"juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu","amount": "1000"}}'
Now since the token we sent is the same one being staked, then the rewards are distributed automatically to the stakers, and there is no need to call
Claim
or UpdateGlobalIndex
.
Let us check the new balances of the users:
wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem"}}'
- Querying contract...
{
"address": "juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem",
"share": "3000",
"balance": "3300",
"pending_rewards": []
}
wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno1e53vtk7fmqzfttdvpf4a3pyx0e79wkmjzh6qsk"}}'
– Querying contract...
{
"address": "juno1e53vtk7fmqzfttdvpf4a3pyx0e79wkmjzh6qsk",
"share": "1000",
"balance": "1100",
"pending_rewards": []
}
wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno19s3l3wh5a3w5dpyv6v2342aej39mwmjea8vpsn"}}'
— Querying contract...
{
"address": "juno19s3l3wh5a3w5dpyv6v2342aej39mwmjea8vpsn",
"share": "6000",
"balance": "6600",
"pending_rewards": []
}
As we can see each of the stakers got the amount proportional to the amount staked.
This was a very simple App that showcases our cw20-staking contract. If you want to play around with it more, you can built it using the allocated rewards and add up to 10 different token rewards. It would also allow you to spread the rewards distribution to be in cycles instead of instant as we got here. This App although simple, is needed in most web3 projects that launch their own token. With Andromeda, you can have it all setup easily like we saw in this example or even using our no-code builder App which takes minutes.
Last modified 1mo ago