DEV Community

Maxwell
Maxwell

Posted on

Building StakeVault: A Full-Stack DeFi Staking Protocol with Solidity, Foundry, React and Ethers.js

Building StakeVault: A Full-Stack DeFi Staking Protocol with Solidity, Foundry, React and Ethers.js

StakeVault is a decentralized staking protocol where users deposit STAKE tokens into a smart contract and earn REWARD tokens over time.

The project was built as a full-stack Web3 application combining Solidity smart contracts with a React frontend. The protocol is deployed on Ethereum Sepolia and can be interacted with through a connected Web3 wallet.

What I Built

StakeVault consists of three primary smart contracts:

  • StakeToken — the ERC-20 token users stake.
  • RewardToken — the ERC-20 token distributed as rewards.
  • StakingVault — the core contract responsible for staking, reward accounting, withdrawals, reward claims and reward funding.

The frontend was built using React and Vite and communicates with the deployed contracts using Ethers.js and Wagmi.

Live Project

https://defi-staking-dhzkby4cm-wire4.vercel.app/

GitHub

https://github.com/max-wire/defi-staking

How Staking Works

The basic flow is:

User

Approve STAKE

StakeToken.approve()

StakingVault.stake()

User staking position increases

Global total stake increases

Reward accounting updates

Time passes

Rewards accrue

claimRewards() or exit()

The frontend provides a simple interface for performing these operations without requiring users to interact with the smart contracts manually.

Global Staking vs User Staking

One important design aspect of StakeVault is the distinction between the global protocol state and an individual user's position.

For example, if User A stakes 410 STAKE:

  • User A's staked amount becomes 410 STAKE.
  • The global totalStaked value also becomes 410 STAKE.

If User B subsequently stakes 10 STAKE:

  • User A still has 410 STAKE.
  • User B has 10 STAKE.
  • The global protocol total becomes 420 STAKE.

Therefore, Total Staked on the dashboard represents the amount currently deposited across the entire staking pool, not the connected wallet's individual position.

Finite Reward Pool

A major design decision in StakeVault is the use of a finite reward pool.

The vault maintains a rewardRemaining value representing the amount of REWARD tokens available for distribution.

Rewards are emitted over time according to the configured reward rate, but the protocol cannot continue creating reward liabilities after the funded pool has been exhausted.

Conceptually:

Reward Pool

rewardRemaining

Rewards emitted over time

Users accrue rewards

Pool reaches zero

Reward emissions stop

Additional REWARD tokens can be funded into the vault to continue distribution.

Reward Accounting

Rewards are calculated using cumulative rewardPerToken accounting.

Conceptually:

rewardPerToken =
    rewardPerTokenStored
    + (newRewards × PRECISION / totalStaked)
Enter fullscreen mode Exit fullscreen mode

A user's accrued rewards depend on:

  • Their staking balance
  • The total amount staked
  • Time elapsed
  • The configured reward rate
  • The remaining reward pool

This allows multiple users to participate in the same staking pool while maintaining separate individual positions.

Frontend

The React frontend provides:

  • Wallet connection
  • STAKE balance
  • REWARD balance
  • Individual staked amount
  • Global total staked
  • Reward rate
  • Remaining rewards
  • Token approval
  • Staking
  • Withdrawals
  • Reward claiming
  • Exit functionality
  • Automatic blockchain data refresh

The interface also performs a balance check before requesting token approval. This prevents users from signing an approval transaction when they do not have enough STAKE to perform the requested staking operation.

Testing

The smart contract system was tested using Foundry.

The test suite covers:

  • ERC-20 token behavior
  • Staking
  • Multiple staking operations
  • Withdrawals
  • Reward accrual
  • Proportional reward distribution
  • Multiple-user reward calculations
  • Reward claiming
  • Exit functionality
  • Reward funding
  • Reward rate updates
  • Pause and unpause functionality
  • Reward pool exhaustion
  • Accounting invariants
  • Edge cases and failure conditions

The project currently contains 80 passing Foundry tests.

forge test
Enter fullscreen mode Exit fullscreen mode

For detailed traces:

forge test -vvv
Enter fullscreen mode Exit fullscreen mode

Ethereum Sepolia Deployment

The production testnet deployment runs on Ethereum Sepolia.

Network: Ethereum Sepolia
Chain ID: 11155111

Contracts

StakeToken
0x6De64f2A0D3C1c93cECB67eF06D4a22ff6e00999

RewardToken
0x1D1A21d7468040b306d06E3f1c6c30eeD249F380

StakingVault
0x9A8a5DdEC15F4B8822BF10E849B5C465D6cf2C1e
Enter fullscreen mode Exit fullscreen mode

Project Hash

4ba73c3497f46ea64b0dd4e49ad8d02653085e82
Enter fullscreen mode Exit fullscreen mode

This identifies the Git commit associated with the documented project state.

Technology Stack

Smart Contracts

  • Solidity
  • Foundry
  • OpenZeppelin
  • Anvil
  • Ethereum Sepolia

Frontend

  • React
  • Vite
  • Ethers.js
  • Wagmi
  • WalletConnect
  • MetaMask
  • Coinbase Wallet
  • Vercel

Try the Application

The deployed application is available here:

https://defi-staking-dhzkby4cm-wire4.vercel.app/
The project is open source:

https://github.com/max-wire/defi-staking

Acknowledgements

This project was developed as part of the EtherAuthority Web3 training/internship program.

@etherauthority
@securechainai

Web3 #Blockchain #Ethereum #SmartContracts #DeFi #Solidity #Web3Development #BlockchainDevelopment #Staking #DApp #ERC20 #SmartContractSecurity

Top comments (0)