Cw20 Staking App

Deploying a cw20 staking App using the Andromeda CLI.

If unfamiliar 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.

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 Instantiation Messages

The components/ADOs we would need:

Let us first start by representing the instantiation message for each of our ADOs:

CW20 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. I specify 3 addresses to receive an initial balance.

{
 "name": "Staking Token",
 "symbol":"STK",
 "decimals":6,
 "initial_balances":[
                {
              "address":"andr1v0an0ar6js3kwmgwr6pp5kuswm6wh0gwdnjska",
              "amount":"10000"
          },
                   {
              "address":"andr1dzrcm9swj22v2d05sqfktlwrz3u8hskgujyqhk",
              "amount":"10000"
          },
                   {
              "address":"andr1gzk2m0k40e30wn6wv9j9kcrx4ljlk4ks8whrgq",
              "amount":"10000"
          }
             
        ],
"kernel_address":"andr14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9shptkql"
 }  

As Base64:

eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6ImFuZHIxdjBhbjBhcjZqczNrd21nd3I2cHA1a3Vzd202d2gwZ3dkbmpza2EiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZHpyY205c3dqMjJ2MmQwNXNxZmt0bHdyejN1OGhza2d1anlxaGsiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZ3prMm0wazQwZTMwd242d3Y5ajlrY3J4NGxqbGs0a3M4d2hyZ3EiLCJhbW91bnQiOiIxMDAwMCJ9XSwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifSAg

CW20 Staking

{
"staking_token":"./cw20",
"kernel_address":"andr14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9shptkql"
}

As Base64:

eyJzdGFraW5nX3Rva2VuIjoiLi9jdzIwIiwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifQ==

App

{
  "name": "Staking App",
  "app_components": [
    {
      "name": "cw20",
      "ado_type": "cw20",
      "component_type":{
       "new":"eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6ImFuZHIxdjBhbjBhcjZqczNrd21nd3I2cHA1a3Vzd202d2gwZ3dkbmpza2EiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZHpyY205c3dqMjJ2MmQwNXNxZmt0bHdyejN1OGhza2d1anlxaGsiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZ3prMm0wazQwZTMwd242d3Y5ajlrY3J4NGxqbGs0a3M4d2hyZ3EiLCJhbW91bnQiOiIxMDAwMCJ9XSwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifSAg"
       }
    },
    {
      "name": "staking",
      "ado_type": "cw20-staking",
      "component_type":{
       "new":"eyJzdGFraW5nX3Rva2VuIjoiLi9jdzIwIiwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifQ=="
       }
    }
  ],
"kernel_address":"andr14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9shptkql"
  }

There are several components found here. A simple name for the app, the components of the app itself and a reference to the “Kernel”. Each component of the app provides two values: a name used for referencing for other components within the app, and the base64 encoded instantiation message.

Instantiating the App

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 Andromeda test-net Galileo-3.

We have already uploaded the App ADO to the Andromeda testnet. A simple way to check the latest code id for the App ADO is to query it from the ADODB using the chain you want to use.

In the CLI, while connected to the chain of choice, run:

os adodb getcodeid app-contract

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:

 instantiate "<app-code-id>" '{"name": "Staking App","app_components": [{"name": "cw20","ado_type": "cw20","component_type":{"new":"eyJuYW1lIjogIlN0YWtpbmcgVG9rZW4iLCJzeW1ib2wiOiJTVEsiLCJkZWNpbWFscyI6NiwiaW5pdGlhbF9iYWxhbmNlcyI6W3siYWRkcmVzcyI6ImFuZHIxdjBhbjBhcjZqczNrd21nd3I2cHA1a3Vzd202d2gwZ3dkbmpza2EiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZHpyY205c3dqMjJ2MmQwNXNxZmt0bHdyejN1OGhza2d1anlxaGsiLCJhbW91bnQiOiIxMDAwMCJ9LHsiYWRkcmVzcyI6ImFuZHIxZ3prMm0wazQwZTMwd242d3Y5ajlrY3J4NGxqbGs0a3M4d2hyZ3EiLCJhbW91bnQiOiIxMDAwMCJ9XSwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifSAg"}},{"name": "staking","ado_type": "cw20-staking","component_type":{"new":"eyJzdGFraW5nX3Rva2VuIjoiLi9jdzIwIiwia2VybmVsX2FkZHJlc3MiOiJhbmRyMTRoajJ0YXZxOGZwZXNkd3h4Y3U0NHJ0eTNoaDkwdmh1anJ2Y21zdGw0enIzdHhtZnZ3OXNocHRrcWwifQ=="}}],"kernel_address":"andr14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9shptkql"}'

Instantiation

Interacting with the App

User 1 stakes tokens

To stake tokens we perform a send message from CW20w contract and attach the Stake{} message to it. For user 1 we will stake 3000 tokens.

{
 "send":{
    "contract":"<staking-contract-address>",
    "amount":"3000",
    "msg":"ewogICAgInN0YWtlX3Rva2VucyI6e30KICAgIAp9"
    }
 }

Here the attached message is:

{
"stake_tokens":{}
}

Let us execute it:

wasm execute <cw20-contract-address> '{"send":{"contract":"<staking-contract-address>","amount":"3000","msg":"ewogICAgInN0YWtlX3Rva2VucyI6e30KICAgIAp9"}}' 

User 1 stakes 3000 tokens

We perform the same steps to stake for users 2 and 3:

User 2 stakes 1000 tokens

User 3 stakes 6000 tokens

Checking Pending Rewards

Let us check the staker data for user 1:

wasm query  <staking-contract-address> '{"staker":{"address":"<user-address>"}}' 

Result:

{
  "address": "andr1v0an0ar6js3kwmgwr6pp5kuswm6wh0gwdnjska",
  "share": "3000",
  "balance": "3000",
  "pending_rewards": []
}

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":"<staking-contract-address>",
      "amount": "1000"
      }
 }
wasm execute <cw20-contract-address> '{"transfer":{"recipient":"<staking-contract-address>","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  <staking-contract-address> '{"staker":{"address":"<user1-address>"}}' 

Result:

{
  "address": "andr1v0an0ar6js3kwmgwr6pp5kuswm6wh0gwdnjska",
  "share": "3000",
  "balance": "3300",
  "pending_rewards": []
}

User 2:

wasm query  <staking-contract-address> '{"staker":{"address":"<user2-address>"}}' 

Result:

{
  "address": "andr1dzrcm9swj22v2d05sqfktlwrz3u8hskgujyqhk",
  "share": "1000",
  "balance": "1100",
  "pending_rewards": []
}

User 3:

wasm query  <staking-contract-address> '{"staker":{"address":"<user3-address>"}}' 

Result:

{
  "address": "andr1gzk2m0k40e30wn6wv9j9kcrx4ljlk4ks8whrgq",
  "share": "6000",
  "balance": "6600",
  "pending_rewards": []
}

As we can see each of the stakers got the amount proportional to the amount staked. Each user can now claim these tokens by calling the ClaimRewards message.

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.

Last updated

Was this helpful?