ZkStaker is built of of Tally's Staker library, and incentivizes delegation within ZK Nation. The current system allows a ZK holder to stake their tokens and earn rewards in ZK tokens. Rewards are currently distributed via minting on a capped minter. In the future other reward sources can be added through a governance vote.
The staking system accepts user stake, delegates their voting power, and distributes rewards for eligible stakers.
stateDiagram-v2
direction TB
User --> CUF: Stakes tokens
state ZkStaker {
state "Key User Functions" as CUF {
stake --> claimReward
claimReward --> withdraw
}
state "Key State" as KS {
rewardRate
deposits
}
state "Admin Functions" as CAF {
setRewardNotifier
setEarningPowerCalculator
}
}
state DelegationSurrogate {
state "Per Delegatee" as PD {
HoldsTokens
DelegatesVotes
}
}
KS --> DelegationSurrogate: Holds tokens per delegatee
DelegationSurrogate --> Delegatee: Delegates voting power
GovOps --> CAF: system admin
MintRewardNotifier --> ZkStaker: Mints capped minter rewards
IdentityEarningPowerCalculator --> ZkStaker: Determines stake rewards
Before getting started make sure you have Hardhat, Typescript, and foundry-zksync installed. Once those dependencies are ready follow the steps below.
Clone the repo:
git clone https://github.com/withtally/zkstaker.git
cd zk-staker
Install the Foundry dependencies:
forge install
Install the npm dependencies:
npm install
Build the contracts, with both solc and zksolc:
npm run compile
Run the tests (both the hardhat deployment test and foundry tests are run):
npm run test
Clean build artifacts, from both solc and zksolc:
npm run clean
To deploy the project, you will first need to set up your environment variables via the .env file, and potentially change some constant values in the DeployZkStaker.ts deployment script.
cp .env.template .env
# edit the .env to fill in values for DEPLOYER_PRIVATE_KEY and ZKSYNC_RPC_URLThe DEPLOYER_PRIVATE_KEY should be the private key of the wallet you want to use for deployment.
The ZKSYNC_RPC_URL should be the RPC URL of the ZkSync network you want to deploy to (e.g., ZkSync Era, ZkSync Testnet, etc.).
Before running DeployZkStaker.ts verify the below constants are set to the correct values. The current values reflect a mainnet deploy for the ZK Nation GovOps Governor.
const REWARD_AMOUNT = "1000000000000000000";
const REWARD_INTERVAL = 30 * NUMBER_OF_SECONDS_IN_A_DAY; // 30 days
const ZK_CAPPED_MINTER = "0x721b6d77a58FaaF540bE49F28D668a46214Ba44c"; // Previously deployed ZK Capped Minter address
const MAX_BUMP_TIP = 0;
const INITIAL_TOTAL_STAKE_CAP = "1000000000000000000000000"; // Limit to the total amount of ZK tokens that can be staked
const STAKER_NAME = "ZkStaker";
For the actual deployment, you will need to use Hardhat and TypeScript. Follow these steps:
Compile the contracts:
npx hardhat compileFor an (optional) local deployment, start a local Hardhat node (in a separate terminal):
npx hardhat node-zksyncThis will start a local ZkSync Era node for testing purposes.
Deploy the contracts:
npx hardhat run script/DeployZkStaker.ts --network <network-name>Make sure to replace <network-name> with the desired network (e.g., zkSyncEra, zkSyncLocal, etc.), which should be defined in your network settings in hardhat.config.ts.
For a local deployment, use zkSyncLocal as the network-name:
npx hardhat run script/DeployZkStaker.ts --network zkSyncLocalFor a testnet deployment, use zkSyncEraTestnet as the network-name:
npx hardhat run script/DeployZkStaker.ts --network zkSyncEraTestnetFor a mainnet deployment, use zkSyncEra as the network-name
npx hardhat run script/DeployZkStaker.ts --network zkSyncEraThis will deploy the contracts to the specified network. Make sure you have enough funds in the wallet associated with DEPLOYER_PRIVATE_KEY to cover the deployment costs.
If the --network flag is not specified, the default network will be used, which is defined in hardhat.config.ts as zkSyncLocal.
This project is licensed under the MIT License. See the LICENSE file for details.