A comprehensive smart contract system for managing USDSC stablecoin yield distribution across multiple vault strategies. This repository contains upgradeable vault contracts and a yield redistribution system that enables users to earn yield through different mechanisms.
This system consists of three main components:
-
RewardRedistributor: A non-upgradeable contract that claims yield from the USDSC token (M0 extension) and distributes it proportionally to two vault types based on their total value locked (TVL).
-
EarnVault: An upgradeable vault where users deposit USDSC and earn claimable yield. Users maintain full control over their principal and can withdraw anytime, with all accrued rewards automatically claimed on withdrawal. Supports dual rewards: USDSC yield + boost rewards in other tokens (ASTR, DOT, etc.).
-
sUSDSC Vault: An ERC-4626 compliant passive yield vault where users deposit USDSC and receive sUSDSC shares. External yield inflows automatically increase the price per share (PPS) for all holders.
USDSC Token (M0 Extension)
↓ claimYield()
RewardRedistributor
↓ distribute()
├─→ EarnVault (proportional to TVL)
│ └─→ Users claim yield + boost rewards
└─→ sUSDSC Vault (proportional to TVL)
└─→ PPS increases automatically
- Proportional Yield Distribution: Yield is split between vaults based on their TVL with rounding-carry logic for long-run fairness
- Dual Vault Strategy: Two different yield mechanisms (claimable vs. automatic PPS increase)
- Upgradeable Vaults: EarnVault and sUSDSC Vault use transparent proxy pattern for future upgrades
- Boost Rewards: EarnVault supports additional rewards in multiple ERC20 tokens
- Access Control: Role-based permissions for all administrative functions
- Emergency Controls: Pause mechanisms and emergency recovery functions
Location: src/distributor/RewardRedistributor.sol
Type: Non-upgradeable (immutable)
Purpose: Claims yield from USDSC token and distributes it to vaults proportionally.
Key Functions:
distribute(): Claims yield and distributes to vaults (OPERATOR_ROLE)previewDistribute(): Preview distribution without executingsetTreasury(),setEarnVault(),setSusdscVault(),setFeeBps(): Configuration (ADMIN_ROLE)
Documentation: See RewardRedistributor.md and OPERATOR_RUNBOOK.md
Location: src/vaults/earn/EarnVaultUpgradeable.sol
Type: Upgradeable (transparent proxy)
Purpose: Users deposit USDSC and earn claimable yield with boost rewards support.
Key Features:
- Index-based yield accounting with RAY precision (1e27)
- Automatic reward claiming on withdrawal
- Multi-token boost rewards (ASTR, DOT, etc.)
- Principal protection with full withdrawal control
Key Functions:
deposit(uint256 amount): Deposit USDSCwithdraw(uint256 amount): Withdraw principal (auto-claims all rewards)claim(): Claim all accrued rewards without withdrawingonYield(uint256 amount): Receive yield distribution (YIELD_REDISTRIBUTOR only)onBoostReward(address token, uint256 amount): Receive boost rewards (BOOST_REWARD_KEEPER only)
Documentation: See earn-vault.md and earn-vault-upgradeable.md
Location: src/vaults/4626/SUSDSCVaultUpgradable.sol
Type: Upgradeable (transparent proxy)
Purpose: ERC-4626 compliant vault where yield increases price per share automatically.
Key Features:
- Full ERC-4626 standard compliance
- Passive yield mechanism (external transfers increase PPS)
- No active strategy required
Key Functions:
deposit(uint256 assets, address receiver): Deposit USDSC for sUSDSC shareswithdraw(uint256 assets, address receiver, address owner): Withdraw USDSCredeem(uint256 shares, address receiver, address owner): Redeem shares for USDSC
Documentation: See yield-vault.md
- Foundry - For compiling, testing, and deploying contracts
- Node.js >= 18 - For package management and scripts
- Yarn - Package manager (or npm)
- Install Foundry (if not already installed):
curl -L https://foundry.paradigm.xyz | bash
foundryup- Clone the repository:
git clone https://github.com/StartaleGroup/stablecoin-contracts.git
cd stablecoin-contracts- Install dependencies:
yarn install- Install Foundry dependencies:
forge install- Set up environment variables:
cp .env.example .env
# Edit .env with your configuration# Using yarn script
yarn compile
# Or using forge directly
forge build# Run all tests
yarn test
# Run tests with gas report
yarn test-gas
# Run specific test file
forge test --match-path test/unit/RewardRedistributor.t.sol
# Run specific test function
forge test --match-test test_Distribute
# Run with higher verbosity
./test.sh -v
# Run fuzz tests
yarn test-fuzz
# Run integration tests
yarn test-integration
# Run invariant tests
yarn test-invariant# Generate coverage report (lcov format)
yarn coverage
# Generate coverage with exclusions (filters out test/mock/script files)
make coverage-exclude
# Generate HTML coverage report
make coverage-html
# Opens coverage-html/index.html in browser
# View coverage summary
./scripts/coverage-summary.sh lcov.info# Format code with Prettier
yarn prettier
# Lint Solidity files
yarn solhint
# Fix solhint errors
yarn solhint-fix
# Run Slither static analysis
yarn slither# Generate and serve documentation
yarn doc
# Opens http://localhost:4000Contracts must be deployed in the following order:
- SUSDSCVault (1st) - Independent, no dependencies
- EarnVault (2nd) - Independent (use placeholder or deterministic address for YIELD_REDISTRIBUTOR initially)
- RewardRedistributor (3rd) - Requires both vault addresses
Before deploying, ensure your .env file contains:
# Network Configuration
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
DEPLOYER_PRIVATE_KEY=0x...
# Contract Addresses (for RewardRedistributor deployment)
USDSC_ADDRESS=0x...
TREASURY_ADDRESS=0x...
EARN_VAULT_ADDRESS=0x...
SUSDSC_VAULT_ADDRESS=0x...
ADMIN_ADDRESS=0x...
KEEPER_ADDRESS=0x...
# Vault-specific addresses
OWNER_ADDRESS=0x...
YIELD_REDISTRIBUTOR_ADDRESS=0x... # Set after RewardRedistributor deployment
PAUSER_ADDRESS=0x...
BOOST_REWARD_KEEPER_ADDRESS=0x...
PROXY_ADMIN_OWNER=0x... # Optional, defaults to admin/owner# Simulate deployment
forge script script/deploy/DeploySUSDSCUpgradable.sol:DeploySUSDSCVaultUpgradeable \
--rpc-url $SEPOLIA_RPC_URL -vv
# Deploy
forge script script/deploy/DeploySUSDSCUpgradable.sol:DeploySUSDSCVaultUpgradeable \
--rpc-url $SEPOLIA_RPC_URL \
--private-key $DEPLOYER_PRIVATE_KEY \
--broadcast \
--verify \
-vvvv# Simulate deployment
forge script script/deploy/DeployEarnVaultUpgradable.s.sol:DeployEarnVaultUpgradeable \
--rpc-url $SEPOLIA_RPC_URL -vv
# Deploy (use placeholder for YIELD_REDISTRIBUTOR_ADDRESS)
forge script script/deploy/DeployEarnVaultUpgradable.s.sol:DeployEarnVaultUpgradeable \
--rpc-url $SEPOLIA_RPC_URL \
--private-key $DEPLOYER_PRIVATE_KEY \
--broadcast \
--verify \
-vvvv# Update .env with EARN_VAULT_ADDRESS and SUSDSC_VAULT_ADDRESS from previous steps
# Simulate deployment
forge script script/deploy/DeployRewardRedistributor.s.sol:DeployRewardRedistributor \
--rpc-url $SEPOLIA_RPC_URL -vv
# Deploy
forge script script/deploy/DeployRewardRedistributor.s.sol:DeployRewardRedistributor \
--rpc-url $SEPOLIA_RPC_URL \
--private-key $DEPLOYER_PRIVATE_KEY \
--broadcast \
--verify \
-vvvvAfter deploying RewardRedistributor:
-
Set RewardRedistributor as yield recipient in USDSC token:
USDSC.setYieldRecipient(rewardRedistributorAddress) -
Set RewardRedistributor as yield redistributor in EarnVault:
EarnVault.setYieldRedistributor(rewardRedistributorAddress) -
Verify keeper has OPERATOR_ROLE (automatically granted during deployment)
# Start local Anvil node
anvil
# In another terminal, deploy
yarn deploy-localAll deployment scripts use CREATE3 for deterministic addresses. See deploys.md for detailed deployment information.
test/
├── unit/ # Unit tests for individual contracts
├── integration/ # Integration tests for contract interactions
├── invariants/ # Invariant tests for system properties
├── fork/ # Fork tests against mainnet/testnet
└── mocks/ # Mock contracts for testing
# All tests
yarn test
# Specific test directory
./test.sh -d test/unit
# Specific test pattern
./test.sh -t test_Distribute
# With gas reporting
yarn test-gas
# Fuzz tests
yarn test-fuzz
# Integration tests
yarn test-integration
# Invariant tests
yarn test-invariantThe project uses Foundry profiles for different test configurations:
default: Standard testing (5,000 fuzz runs, 512 invariant runs)ci: CI-optimized (100 fuzz runs, 50 invariant runs)production: Production builds with optimizations
# Use specific profile
./test.sh -p cistablecoin-contracts/
├── src/
│ ├── distributor/ # RewardRedistributor contract
│ │ ├── RewardRedistributor.sol
│ │ ├── RewardRedistributor.md
│ │ └── OPERATOR_RUNBOOK.md
│ ├── vaults/
│ │ ├── earn/ # EarnVault contracts
│ │ │ ├── EarnVaultUpgradeable.sol
│ │ │ ├── earn-vault.md
│ │ │ └── earn-vault-upgradeable.md
│ │ └── 4626/ # sUSDSC Vault contracts
│ │ ├── SUSDSCVaultUpgradable.sol
│ │ └── yield-vault.md
│ └── interfaces/ # Contract interfaces
├── script/
│ └── deploy/ # Deployment scripts
│ ├── DeploySUSDSCUpgradable.sol
│ ├── DeployEarnVaultUpgradable.s.sol
│ ├── DeployRewardRedistributor.s.sol
│ └── deploys.md
├── test/ # Test files
├── lib/ # External dependencies
├── foundry.toml # Foundry configuration
├── package.json # Node.js dependencies and scripts
├── Makefile # Build automation
└── README.md # This file
yarn build- Build contracts for productionyarn compile- Compile contractsyarn clean- Clean build artifacts
yarn test- Run all testsyarn test-gas- Run tests with gas reportyarn test-fuzz- Run fuzz testsyarn test-integration- Run integration testsyarn test-invariant- Run invariant tests
yarn coverage- Generate coverage report (lcov)yarn coverage:filtered- Generate filtered coverageyarn coverage:html- Generate HTML coverage report
yarn prettier- Format codeyarn solhint- Lint Solidity filesyarn solhint-fix- Fix solhint errorsyarn slither- Run static analysis
yarn deploy-local- Deploy to local networkyarn deploy-sepolia- Deploy to Sepolia testnet
yarn doc- Generate and serve documentation
See foundry.toml for Foundry settings including:
- Solidity version:
0.8.30 - EVM version:
prague - Optimizer: Enabled with 999,999 runs
- Test profiles for different environments
Coverage excludes test files, mocks, scripts, and interfaces. See Makefile for the exclusion pattern.
✅ This codebase has been audited by Quantstamp.
The audit report is available in the audits/ directory. Please review the audit findings before deploying to production.
- Reentrancy guards on all critical functions
- Access control with role-based permissions
- Pause mechanisms for emergency stops
- Input validation and overflow protection
- Comprehensive test coverage
Please report security issues to the repository maintainers privately before public disclosure.
- RewardRedistributor - Detailed contract documentation
- RewardRedistributor Operator Runbook - Operational procedures
- EarnVault - EarnVault documentation
- EarnVault Upgradeable - Upgrade procedures
- sUSDSC Vault - ERC-4626 vault documentation
- Audit Reports - Quantstamp security audit reports
- Deployment Guide - Deployment procedures and addresses
Addresses will be added after deployment
Addresses will be added after deployment
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
[Add license information]
For questions and support:
- Open an issue on GitHub
- Contact the development team
Built with: