Andromeda
Search…
⌃K

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.

Defining our App

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

Defining the Messages

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.

Cw-20 Token

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=

Cw-20 Staking

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

App

{
"name": "Staking App",
"app": [
{
"name": "cw20",
"ado_type": "cw20",
"instantiate_msg": "eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6Imp1bm8xemtwdGhxc3ozdWQ5N2ZtNnA0a3hjcmE4YWU5OWpnemF1dWd5ZW0iLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xZTUzdnRrN2ZtcXpmdHRkdnBmNGEzcHl4MGU3OXdrbWp6aDZxc2siLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6Imp1bm8xOXMzbDN3aDVhM3c1ZHB5djZ2MjM0MmFlajM5bXdtamVhOHZwc24iLCJhbW91bnQiOiIxMDAwMCJ9IF19ICA="
},
{
"name": "staking",
"ado_type": "cw20-staking",
"instantiate_msg": "eyJzdGFraW5nX3Rva2VuIjp7ImlkZW50aWZpZXIiOiJjdzIwIn19"
}
],
"primitive_contract": "juno133fdsnvcah870exzcyxknydswyh778jfhwxzlhhgjuagh4482zpqp856dz"
}

Instantiating the App

First, let us open the CLI by running andr in our terminal. We then need to chose the chain we want to deploy on. For this example I will be using the Juno testnet uni-5:
chain use 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 the Juno faucet and request some tokens.
The Andromeda CLI will open and we can now instantiate our App. We will be using our wasm command to instantiate our app:
I have already uplaoded the App contract to the uni-5 testnet. The code Id to use is 98. If you want to upload a new one to make sure it is the latest version, you need to:
-Clone our Repo and build the contract
-In artifacts, run wasm upload andromeda_app_contract.wasm in CLI
-You will get a new code Id to use
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.

Interacting with the App

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 Components

{
"claim_ownership":{}
}
wasm execute juno1mgwet8dksqsjvx2u7evy9wyxwtj5cp8gftw7k4zzh4cqsdmaa38ql7sueh '{"claim_ownership":{}}'

User 1 stakes tokens

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.

Checking Pending Rewards

Let us check the staker data for user 1:
junod query wasm contract-state smart juno1wf526ma0mjskhlgrun9qkytelnfsl5pny3l2gwvpgjqwhcrx2q8qpqg53f '{"staker":{"address":"juno197y44w58djquqkpu8v56pgwvm058f6jswm0jec"}}'

Result:

– 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.

Transfer Some Tokens as Rewards

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:

User 1:

wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem"}}'

Result:

- Querying contract...
{
"address": "juno1zkpthqsz3ud97fm6p4kxcra8ae99jgzauugyem",
"share": "3000",
"balance": "3300",
"pending_rewards": []
}

User 2:

wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno1e53vtk7fmqzfttdvpf4a3pyx0e79wkmjzh6qsk"}}'

Result:

– Querying contract...
{
"address": "juno1e53vtk7fmqzfttdvpf4a3pyx0e79wkmjzh6qsk",
"share": "1000",
"balance": "1100",
"pending_rewards": []
}

User 3:

wasm query juno15vu55e5hvegppl2nr4dkqrhtmtl4qdspt6vlpld8ult55s95mlgsql7ydu '{"staker":{"address":"juno19s3l3wh5a3w5dpyv6v2342aej39mwmjea8vpsn"}}'

Result:

— 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.

Conclusion

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.