A simple Ethereum staking protocol that allows users to stake ETH and earn sETH (Staked ETH) tokens as rewards.
This project implements a basic staking mechanism where users can:
- Stake ETH to earn rewards over time
- Unstake their ETH at any time
- Claim rewards in the form of sETH tokens
- View their accumulated rewards
The protocol consists of two main contracts:
StakedETH: An ERC20 token representing staking rewardsStakingContract: The main staking logic contract
- ETH Staking: Users can stake ETH and earn rewards proportional to their stake and time
- Flexible Unstaking: Users can unstake any amount of their staked ETH at any time
- Reward Tokens: Rewards are paid out in sETH tokens at a rate of 1 sETH per ETH per second
- Real-time Rewards: Users can view their accumulated rewards without claiming them
- Security: Only the staking contract can mint sETH tokens
- Type: ERC20 Token
- Symbol: sETH
- Name: Staked ETH
- Purpose: Represents staking rewards earned by users
Key Functions:
mint(address to, uint256 amount): Mint new sETH tokens (only callable by staking contract)setStakeContractAddress(address): Set the authorized staking contract address (owner only)
- Purpose: Manages ETH staking, unstaking, and reward distribution
Key Functions:
stake(uint256 amount): Stake ETH and start earning rewardsunstake(uint256 amount): Unstake ETH and receive it backclaimRewards(): Claim accumulated rewards as sETH tokensgetRewards(): View current accumulated rewards without claiming
Reward Rate:
- 1 sETH per ETH per second staked
├── src/
│ ├── StakedETH.sol # ERC20 reward token contract
│ └── StakingContract.sol # Main staking logic contract
├── test/
│ ├── StakedETH.t.sol # Tests for StakedETH contract
│ └── StakingContract.t.sol # Tests for StakingContract
├── lib/ # Dependencies (Git submodules)
│ ├── forge-std/ # Foundry testing utilities (submodule)
│ └── openzeppelin-contracts/ # OpenZeppelin contracts (submodule)
└── foundry.toml # Foundry configuration
- Foundry installed
- Git
- Clone the repository with submodules:
git clone --recursive https://github.com/Agnish1611/eth-staking.git
cd eth-stakingAlternative: If you already cloned without --recursive:
git clone https://github.com/Agnish1611/eth-staking.git
cd eth-staking
git submodule update --init --recursive- Build the contracts:
forge build- Run tests:
forge testRun all tests:
forge testRun tests with verbose output:
forge test -vvvRun specific test file:
forge test --match-path test/StakingContract.t.sol- Deploy
StakedETHcontract - Deploy
StakingContractwith theStakedETHaddress - Call
setStakeContractAddressonStakedETHwith theStakingContractaddress
// Stake 1 ETH
stakingContract.stake{value: 1 ether}(1 ether);
// Wait some time for rewards to accumulate
// Check rewards (returns amount in wei)
uint256 rewards = stakingContract.getRewards();
// Claim rewards as sETH tokens
stakingContract.claimRewards();
// Unstake 0.5 ETH
stakingContract.unstake(0.5 ether);- The
StakedETHcontract uses OpenZeppelin'sOwnablefor access control - Only the designated staking contract can mint new sETH tokens
- Users can only unstake ETH they have previously staked
- Reward calculations are based on time elapsed and amount staked
The project includes comprehensive tests covering:
- Basic staking and unstaking functionality
- Reward calculation accuracy
- Access control mechanisms
- Error conditions and edge cases
Test coverage includes:
- ✅ Initial token supply verification
- ✅ Minting restrictions (only staking contract)
- ✅ Owner-only functions
- ✅ Staking with ETH
- ✅ Unstaking validation
- ✅ Reward calculations
- ✅ Complex staking scenarios
This project uses Git submodules to manage dependencies, keeping the repository lightweight while ensuring reproducible builds.
- OpenZeppelin Contracts (
lib/openzeppelin-contracts/): For secure, audited contract implementations - Forge Standard Library (
lib/forge-std/): For testing utilities and cheat codes
Update dependencies:
# Update forge-std to latest
cd lib/forge-std
git pull origin main
cd ../..
git add lib/forge-std
git commit -m "chore: update forge-std to latest"
# Update OpenZeppelin to specific version
cd lib/openzeppelin-contracts
git checkout v5.0.0 # or any specific tag
cd ../..
git add lib/openzeppelin-contracts
git commit -m "chore: update openzeppelin-contracts to v5.0.0"For contributors: Always clone with --recursive or run git submodule update --init --recursive after pulling changes.