A Simple Staking dApp

ICONOsphere
5 min readNov 22, 2022

--

This tutorial guides you through the process of building a simple staking dApp using ink! smart contract. In this demo dApp, user can stake their ICZ and earn a staking reward at the end of the staking period.

Staking tokens have become essential to many DeFi protocols, allowing developers to create complex financial derivative products. If you’re unfamiliar with crypto/token staking, it’s best described as the process of locking/depositing crypto holdings into a DeFi protocol or a smart contract to earn interest.

What will you be doing

  • Deploy ink! staking contract to Arctic testnet
  • Run the Staking dApp frontend
  • Stake your ICZ and earn rewards

Prerequisite

NOTE: For compiling/building contracts make sure you have installed Rust and configured your Rust environment.

Setting up the project

Fork the GitHub repository where our code for ink! staking contract and frontend are available for public use.

Building the contract

For building the contract you can visit our article on Ink! smart contract and follow the steps given there to build and compile the smart contract code.

Or, you can just use the staking_contract.contract file that is already available on the repository.

Let us take a look at the staking contract code that we will be using in this tutorial.

Ink! contract definition begins with the attribute #[ink::contract]. Any method annotated with the #[ink(message)] attribute will be exposed as API. You can know more about ink! attributes by visiting this link. Let us go through the API available for calling our smart contract:

  1. add_stake: This method is used to stake the ICZ amount.
  2. early_withdraw: This method is used to withdraw ICZ before the maturity period (staking period). On early withdrawal, user will not receive any reward.
  3. redeem_stake: This method redeems the staked ICZ, adding interest to the user’s originally staked amount. This method can only be called after the locking period is over. The reward calculation formula applied in this contract is shown below:
const reward= (interest_rate * stake_amount)/100
  1. get_stake_for_account: This method returns the details of staked ICZ for a given account. Information will include: stakedAmount, depositTime, releaseTime

User actions such as early withdrawal and redemption, transfers balance out of the smart contract. It is the responsibility of the contract owner to ensure that the smart contract has enough funds to pay the users at any given time.

Deploy staking contract

Now let us deploy the staking contract into the Arctic testnet using the polkadot.js app.

  1. Head over to Polkadot.js app.

NOTE: Visit the Arctic Faucet to get Arctic testnet ICZ tokens.

2. Uploading contract code

  • Click on the upload & deploy code button on the contracts page.
  • On the popup, select the wallet you want to deploy the contract from. Then select the staking_contract.contract file and click on Next.
  • After clicking on Next, please enter the following parameters:
interestRatePerCent = 10 (in %)

stakingDuration = 7776000000 (in milliseconds)
  • After clicking on deploy, click the Sign and Submit button and confirm the transaction from your wallet.
  • Finally, your deployed contract will appear on the same page.

The contract address of the staking contract that we have deployed is: npMxzzNTBTTG3qHMFiUsvG6fV6vfRrfKTqQRnX5ibCDnCKA4s

Running the frontend

The frontend is developed using React.js. The folder structure for the frontend can be found in simple_staking_dapp/frontend/.

First of all, navigate to the frontend folder.

cd frontend

Create a .env file in the root of the frontend folder. Inside the .env file, add the contract address and Arctic testnet node web-socket URL.

REACT_APP_CONTRACT_ADDRESS= "npMxzzNTBTTG3qHMFiUsvG6fV6vfRrfKTqQRnX5ibCDnCKA4s"
REACT_APP_RPC_URL="wss://arctic-rpc.icenetwork.io:9944"

Now run the following command to start the frontend:

npm install && npm start

The DEMO staking dApp will be launched and it can be accessed on browser at http://localhost:3000.

Let’s take a look at the UI.

Demo staking dApp UI

Now let us stake some ICZ to earn rewards.

To stake ICZ, adjust the amount by moving the slider or typing the amount in the stake field. Now, hit the STAKE button which will open a pop-up for confirming your transaction.

Staking your ICZ

All the codes related to the contract API interaction can be found on the frontend/src/services/contract.js file.

Snippet for calling stake method from the frontend:

const stake = async (api, contract, accountId, stakeAmount, gasLimit) => {
try {
const injector = await web3FromAddress(accountId);

// get signer
const txObj = await contract.tx.addStake({
storageDepositLimit: null,
gasLimit,
dest: contract?.address?.toHuman(),
value: stakeAmount,
});

// execute transaction
const res = await postTransaction(txObj, accountId, { signer: injector.signer }, api);
if (res?.errorMsg) {
return {
isOk: false,
error: res?.errorMsg,
};
}
return {
isOk: true,
response: res,
};
} catch (e) {
console.log(e);
return {
isOk: false,
error: e.message || 'Unknown error occurred',
};
}
};

Once you have successfully staked your ICZ, you can view your position in the Staked Position section.

Note: In this demo dApp, one account can stake only once in a staking contract

Early Withdraw without reward

Now you can either Withdraw Early OR wait for the locking period to be over and Redeem.

Redeem with earned reward

Snippets for invoking the earlyWithdraw and redeem functions can be found in contract.js file.

Note: You will only receive rewards once the locking period has ended. If you withdraw earlier, you will only receive the amount that you had staked.

Conclusion

In this tutorial, we have deployed ink! staking smart contract to the Arctic testnet and staked some ICZ using the Demo Staking App user interface.

--

--

ICONOsphere

With a deep history of commitment to building projects that foster community growth & personal empowerment we work to create a nation built on trust with icon.