A sophisticated staking system for the SOLO token, implementing rebasing mechanics and withdrawal management through stSOLO (Staked SOLO) tokens.
This project implements a robust staking system with the following core components:
- SOLO → stSOLO: Stake SOLO tokens to receive stSOLO tokens (initially 1:1 ratio)
- Rebasing Mechanism: stSOLO tokens appreciate in value through periodic rebases based on fixed annual emission
- Withdrawal System: Managed withdrawal process with configurable delay periods (0-30 days)
- Dual Architecture: Both standard and upgradeable contract versions available
The system follows modern staking principles similar to Lido's stETH, allowing for seamless integration with DeFi protocols while maintaining security through controlled withdrawal processes.
- Share-based Accounting: Efficient rebasing through share calculations
- Block & Timestamp Tracking: Enhanced security with
lastRebaseBlockandlastRebaseTime - Configurable Parameters: Withdrawal delay (0-30 days), rebase intervals (1 hour - 30 days)
- Rebase Exclusion System: Specific addresses can be excluded from rebasing rewards
- Emergency Functions: Owner can withdraw tokens in emergency situations
- Fixed Annual Emission: Predictable reward distribution based on
tokensPerYear
src/
├── core/ # Standard (non-upgradeable) contracts
│ ├── SOLOStaking.sol # Core staking contract
│ ├── StSOLOToken.sol # Rebasing staked SOLO token
│ ├── interfaces/
│ │ ├── ISOLOStaking.sol # Staking contract interface
│ │ ├── IStSOLOToken.sol # Token contract interface
│ │ └── IERC20.sol # ERC20 interface
│ └── mock/
│ └── SOLOToken.sol # Mock SOLO token for testing
├── upgradeable/ # Upgradeable contract versions
│ ├── SOLOStaking.sol # Upgradeable staking contract
│ ├── StSOLOToken.sol # Upgradeable staked token
│ ├── interfaces/ # Upgradeable interfaces
│ └── lib/ # Shared libraries
└── lib/ # External dependencies
forge installforge buildRun all tests:
forge testRun tests with higher verbosity:
forge test -vvRun tests with gas reporting:
forge test --gas-reportThe test suite includes:
- Unit tests for core functionalities
- Rebase mechanism testing
- Withdrawal system verification
- Share-based accounting validation
- Access control checks
- Integration tests between contracts
- Fuzz testing for edge cases
- Create a
.envfile with your deployment parameters:
PRIVATE_KEY=your_private_key_here
RPC_URL=your_rpc_url_here
INITIAL_REWARD_RATE=initial_reward_rate_in_basis_points
WITHDRAWAL_DELAY=initial_withdrawal_delay_in_seconds- Run the deployment script:
# For SOLO testnet
forge script script/Deploy.s.sol --rpc-url $SOLO_TESTNET_RPC_URL --broadcast --verify
# For other networks
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast --verifyThe deployment script will:
- Deploy upgradeable proxy implementations for all contracts
- Deploy StSOLOToken with initial
tokensPerYearemission rate - Deploy SOLOStaking with configured withdrawal delay
- Set up contract permissions and links between contracts
- Output all contract addresses and proxy addresses
// Approve SOLO spending
SOLO.approve(address(SOLOStaking), amount);
// Stake SOLO and receive stSOLO
SOLOStaking.stake(amount, recipient);// Approve stSOLO spending
stSOLO.approve(address(SOLOStaking), amount);
// Request withdrawal (burns stSOLO immediately)
SOLOStaking.requestWithdrawal(stSOLOAmount);// Process a pending withdrawal after delay period
SOLOStaking.processWithdrawal(requestId);// Get all withdrawal requests for an address
(soloAmounts, stSOLOAmounts, requestTimes, processed) = SOLOStaking.getPendingWithdrawals(userAddress);
// Check share information
uint256 shares = stSOLO.shareOf(userAddress);
uint256 tokenPerShare = stSOLO.getTokenPerShare();
// View rebase timing
uint256 lastRebase = stSOLO.lastRebaseTime();
uint256 lastBlock = stSOLO.lastRebaseBlock();
// Check if address is excluded from rebasing
bool isExcluded = stSOLO.excludedFromRebase(userAddress);// Update annual emission rate in tokens per year (only owner)
stSOLO.setRewardTokensPerYear(newTokensPerYear);
// Trigger manual rebase (owner or staking contract)
stSOLO.rebase();// Update withdrawal delay (only owner)
SOLOStaking.setWithdrawalDelay(newDelay);// Set address exclusion from rebases (only owner)
// Note: Can only exclude addresses with zero balance
stSOLO.setExcluded(address, excluded);
// Update rebase interval (only owner)
// Min: 1 hour, Max: 30 days
stSOLO.setRebaseInterval(newInterval);
// View excluded addresses
address[] memory excluded = stSOLO.getExcludedAddresses();// Emergency token withdrawal (only owner)
SOLOStaking.emergencyWithdrawToken(tokenAddress, recipient, amount);View gas snapshots:
forge snapshotThe contracts implement various gas optimization techniques:
- Efficient share-based accounting
- Minimal storage operations
- Optimized array operations
- Strategic use of view functions
forge fmt- Withdrawal Delay: 0 - 30 days
- Rebase Interval: 1 hour - 30 days (default: 12 hours)
- Max Tokens Per Year: 100,000,000,000 SOLO
- Precision Factor: 1e18 (for share calculations)
The system uses a share-based model where:
- 1 SOLO initially equals 1 share
tokenPerShareincreases with each rebase- User balance = shares * tokenPerShare / PRECISION_FACTOR
- Excluded addresses maintain 1:1 ratio
The contracts include gas mining functionality for reward distribution based on gas usage patterns.
MIT