The JudgeToken ecosystem is a modular set of contracts thats includes the following:
- JudgeToken: This is the ERC20 token contract that defines the rules for the JUDGE governance token.
- JudgeTreasury: This is the project safe treasury that does funding for the staking rewards, team. Also functions as a bank for fees collected from misplaced tokens.
- JudgeStaking: Contract with defined rules for staking and pays out rewards in JudgeToken. Open to anyone.
- RewardsManager: This is the rewards distributor contract for base and bonus rewards handling.
The contracts were built with OpenZeppelin Access control for role based administration and also includes robust recovery systems for accidental transfers of ERC20 tokens to any of the Judge Project contracts expect the token contract. It is assumed that users are unlikely to have interactions with the token contract on a technical level
ERC20 token with the following details:
- Max Supply: 500_000_000 JUDGE
- Burnable
- ERC20Permit (gasless approvals)
- ERC20Votes: Delegation style governance
The JudgeToken contract defines allocation for:
- Staking Rewards Allocation
- Team Allocation
Acts as the Bank contract for the ecosystem
Features:
- Can mint tokens to self
- Can fund rewards manager contracts with staking base rewards
- Handles team funding too
- Supports sending bonus rewards to the Reward Manager contract.
NOTE: Bonus rewards can only be sent to the rewards manager contract if the base quarterly reward for the current quarter has been paid. A minimum of 100k blocks can be set for bonus duration. - Includes recovery function for JUDGE and other ERC20 tokens. A defined fee is paid for token recovery.
Distributes rewards to stakers in the JudgeStaking contract whenever a claim or withdrawal related functions are called by the a staker
Handles:
- Payment of quarterly base rewards.
- Payment of optional quarterly bonus rewards
- Provides JudgeStaking with the hooks below to enable claim:
sendRewards()
sendBonus() - Includes recovery function for JUDGE and other ERC20 tokens. A defined fee is paid for token recovery.
This is the core staking contract where users can lock their JUDGE tokens to earn pro-rata rewards
Reward Accounting:
- It uses
accJudgePerShareandaccBonusJudgePerShareto calculate stake earnings per share over a number of blocks Key Functions: - The
deposit()function allows any address to participate in the staking contract by staking JUDGE tokens. They simply input a stake amount and a lockup duration to create a stake. - Users can use the
claimRewards()function to withdraw their rewards while still having their stakes in the pool - The
withdraw()function when called claims pending rewards and withdraws specified amount for the target stake to the user wallet. Calling this function is not possible until the stake at the desired index is matured. Matured stakes will keep receiving a pro rata share of rewards. - The
withdrawAll()function when called claims pending rewards and withdraws all the desired stake index balance to the user wallet. Calling this function is also not possible until the stake matures. - The
earlyWithdraw()function when called claims pending rewards and withdraws specified amount for the target stake to the user wallet (penalty applies). Learn more about the penalty. - The
updatePool()function when called loops through missed quarters starting from the lastRewardBlock. For each call, the pool loops through a maximum of 4 quarters. If the pool has many stale quarters, theupdatePool()can be called repeatedly to update the staking pool to the current block. - It includes the token recovery function (recovery fee applies). Learn more about recovery fees.
Integration:
- Interacts with the Rewards Manager contract to distribute base and bonus rewards. Any time a user initiates a claim or a withdrawal, the staking contract calls the sendRewards() and sendBonus() if the pending baseReward and pending bonusRewards are greater than 0.
- Built with OpenZeppelin Access Control contract to support role based permissions across all contracts.
- Multiple gatekeepers and modifiers to handle edge cases.
- Follows the CEI security order for solidity contracts.
- Recovery functions for all ERC20 tokens in all contracts except JUDGE Token contract itself.
- Reentrancy proof
The 4 contracts somewhat have circular dependency. You can correctly deploy them in this order:
JudgeToken.solRewardsManager.solJudgeStaking.solJudgeTreasury.sol
Grant neccesary roles across contracts to allow secure and seamless interactions. Some examples below:- Grant Judge Treasury address the
MINTER_ROLE()andALLOCATION_MINTER_ROLE()from Judge Token contract - Grant Jusge Staking address the
REWARDS_DISTRIBUTOR_ROLE()
Alternatively run the deployment script in this repo to seamlessly deploy all 4 contracts
- Install foundry on linux or WSL for windows
$ curl -L https://foundry.paradigm.xyz | bash- Clone Repo
$ git clone https://github.com/raymondabiola/JUDGE-Token-Contract.git- Change directory
$ cd JUDGE-Token-Contract- Install solidity dependencies (OZ version 5.3.0 most suitable for this project)
$ forge install OpenZeppelin/openzeppelin-contracts@v5.3.0- Compile Contracts
$ forge build- Run test suite
$ forge testDeploy Contracts
Create a .env file in the project root and input the following inside it:
INFURA_API_URL,PRIVATE_KEY,ETHERSCAN_API_KEY- The infura api url looks like this
INFURA_API_URL=https://sepolia.infura.io/v3/YOUR_PROJECT_ID. You can get your infuraPROJECT_IDfrom the Infura Website - You can get your etherscan api key from EtherScan Website
The deploy script is found in
scripts/DeployJudgeContracts.sol - Run the script command below to simulate deployment on sepolia testnet
$ forge script script/DeployJudgeContracts.s.sol:DeployJudgeContracts --rpc-url $INFURA_API_URL- Run the script command below to actually deploy and also verify the contracts on the sepolia testnet
$ forge script script/DeployJudgeContracts.s.sol:DeployJudgeContracts \
--rpc-url $INFURA_API_URL \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY \
--chain-id 11155111The script will:
- Deploy all contracts, verify their source code, set key parameters on each contract,and grant neccesary roles to deployer address.
Deployed Instances on Sepolia Testnet
- JudgeToken Contract Address:
0x167043a312d6c3b8c4b5b741225173e65ff45d9a - JudgeTreasury Contract Address:
0xa370652da3773ad361b7b8075ccdc25475882a06 - RewardsManager Contract Address:
0xf3d4832ed9374ec13d8f1c15dcdc8b88a539dc14 - JudgeStaking Contract Address:
0xf18c858a94661dc4524cd7973a81c910ccb6e6fd
$ forge --help
$ anvil --help
$ cast --helpMIT
Built with 🤍 by Raymond Abiola
Feel free to follow my Github account or fork this repo for learning and testing.