Skip to content

Commit 60f6a37

Browse files
authored
chore(protocol-contracts): improve staking tasks (#1776)
1 parent 809804c commit 60f6a37

File tree

11 files changed

+166
-166
lines changed

11 files changed

+166
-166
lines changed

protocol-contracts/staking/.env.example

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ DAO_ADDRESS=0x70997970C51812dc3A010C7d01b50e0d17dc79C8 # accounts[1] (address)
1818
# ----------------------------------------------------------------------------
1919
# Coprocessor
2020
# ----------------------------------------------------------------------------
21-
PROTOCOL_STAKING_COPRO_TOKEN_NAME=ProtocolStakingCoprocessors
22-
PROTOCOL_STAKING_COPRO_TOKEN_SYMBOL=stZAMAcoprocessors
21+
PROTOCOL_STAKING_COPRO_TOKEN_NAME="Staked ZAMA (Coprocessor)"
22+
PROTOCOL_STAKING_COPRO_TOKEN_SYMBOL=stZAMA-Coprocessor
2323
PROTOCOL_STAKING_COPRO_VERSION=1
2424

2525
# Cooldown period in seconds before unstaked tokens can be released
@@ -32,8 +32,8 @@ PROTOCOL_STAKING_COPRO_REWARD_RATE=10000000000000000
3232
# ----------------------------------------------------------------------------
3333
# KMS
3434
# ----------------------------------------------------------------------------
35-
PROTOCOL_STAKING_KMS_TOKEN_NAME=ProtocolStakingKMS
36-
PROTOCOL_STAKING_KMS_TOKEN_SYMBOL=stZAMAkms
35+
PROTOCOL_STAKING_KMS_TOKEN_NAME="Staked ZAMA (KMS)"
36+
PROTOCOL_STAKING_KMS_TOKEN_SYMBOL=stZAMA-KMS
3737
PROTOCOL_STAKING_KMS_VERSION=1
3838

3939
# Cooldown period in seconds before unstaked tokens can be released
@@ -52,9 +52,10 @@ PROTOCOL_STAKING_KMS_REWARD_RATE=10000000000000000
5252
# The number of OperatorStaking for coprocessors must be equal to the number of addresses defined below
5353
NUM_OPERATOR_STAKING_COPRO=2
5454

55+
# ----------------------------------------------------------------------------
5556
# OperatorStaking coprocessor 1
56-
OPERATOR_STAKING_COPRO_TOKEN_NAME_0="OperatorStakingCopro1"
57-
OPERATOR_STAKING_COPRO_TOKEN_SYMBOL_0="stZAMAcopro1"
57+
OPERATOR_STAKING_COPRO_TOKEN_NAME_0="Zama1 Staked ZAMA (Coprocessor)"
58+
OPERATOR_STAKING_COPRO_TOKEN_SYMBOL_0="stZAMA-Zama1-Coprocessor"
5859

5960
# Initial assets (in the smallest unit of $ZAMA, using 10^18 decimals) and receiver
6061
OPERATOR_STAKING_COPRO_INITIAL_DEPOSIT_ASSETS_0=100000000000000000000000
@@ -68,9 +69,10 @@ OPERATOR_REWARDER_COPRO_BENEFICIARY_0="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb9226
6869
OPERATOR_REWARDER_COPRO_MAX_FEE_0=2000
6970
OPERATOR_REWARDER_COPRO_FEE_0=2000
7071

72+
# ----------------------------------------------------------------------------
7173
# OperatorStaking coprocessor 2
72-
OPERATOR_STAKING_COPRO_TOKEN_NAME_1="OperatorStakingCopro2"
73-
OPERATOR_STAKING_COPRO_TOKEN_SYMBOL_1="stZAMAcopro2"
74+
OPERATOR_STAKING_COPRO_TOKEN_NAME_1="Zama2 Staked ZAMA (Coprocessor)"
75+
OPERATOR_STAKING_COPRO_TOKEN_SYMBOL_1="stZAMA-Zama2-Coprocessor"
7476

7577
# Initial assets (in the smallest unit of $ZAMA, using 10^18 decimals) and receiver
7678
OPERATOR_STAKING_COPRO_INITIAL_DEPOSIT_ASSETS_1=250000000000000000000000
@@ -90,9 +92,10 @@ OPERATOR_REWARDER_COPRO_FEE_1=1000
9092
# The number of OperatorStaking for KMS must be equal to the number of addresses defined below
9193
NUM_OPERATOR_STAKING_KMS=3
9294

95+
# ----------------------------------------------------------------------------
9396
# OperatorStaking KMS 1
94-
OPERATOR_STAKING_KMS_TOKEN_NAME_0="OperatorStakingKms1"
95-
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_0="stZAMAkms1"
97+
OPERATOR_STAKING_KMS_TOKEN_NAME_0="Zama1 Staked ZAMA (KMS)"
98+
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_0="stZAMA-Zama1-KMS"
9699

97100
# Initial assets (in the smallest unit of $ZAMA, using 10^18 decimals) and receiver
98101
OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_ASSETS_0=500000000000000000000000
@@ -106,9 +109,10 @@ OPERATOR_REWARDER_KMS_BENEFICIARY_0="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
106109
OPERATOR_REWARDER_KMS_MAX_FEE_0=2000
107110
OPERATOR_REWARDER_KMS_FEE_0=1500
108111

112+
# ----------------------------------------------------------------------------
109113
# OperatorStaking KMS 2
110-
OPERATOR_STAKING_KMS_TOKEN_NAME_1="OperatorStakingKms2"
111-
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_1="stZAMAkms2"
114+
OPERATOR_STAKING_KMS_TOKEN_NAME_1="Zama2 Staked ZAMA (KMS)"
115+
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_1="stZAMA-Zama2-KMS"
112116

113117
# Initial assets (in the smallest unit of $ZAMA, using 10^18 decimals) and receiver
114118
OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_ASSETS_1=750000000000000000000000
@@ -122,9 +126,10 @@ OPERATOR_REWARDER_KMS_BENEFICIARY_1="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"
122126
OPERATOR_REWARDER_KMS_MAX_FEE_1=2000
123127
OPERATOR_REWARDER_KMS_FEE_1=1000
124128

129+
# ----------------------------------------------------------------------------
125130
# OperatorStaking KMS 3
126-
OPERATOR_STAKING_KMS_TOKEN_NAME_2="OperatorStakingKms3"
127-
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_2="stZAMAkms3"
131+
OPERATOR_STAKING_KMS_TOKEN_NAME_2="Zama3 Staked ZAMA (KMS)"
132+
OPERATOR_STAKING_KMS_TOKEN_SYMBOL_2="stZAMA-Zama3-KMS"
128133

129134
# Initial assets (in the smallest unit of $ZAMA, using 10^18 decimals) and receiver
130135
OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_ASSETS_2=1000000000000000000000000

protocol-contracts/staking/APY.ipynb

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"cells": [
33
{
44
"cell_type": "code",
5-
"execution_count": 1,
5+
"execution_count": 7,
66
"id": "df0d74f3-487b-4f31-9750-fd9f7d572932",
77
"metadata": {},
88
"outputs": [],
@@ -12,12 +12,89 @@
1212
},
1313
{
1414
"cell_type": "code",
15-
"execution_count": 2,
15+
"execution_count": 8,
1616
"id": "4cd2e6ad-55c0-431c-971c-9a9208904f5c",
1717
"metadata": {},
1818
"outputs": [],
1919
"source": [
20-
"SECONDS_PER_YEAR = 365 * 24 * 60 * 60"
20+
"SECONDS_PER_YEAR = 365 * 24 * 60 * 60\n",
21+
"\n",
22+
"TOTAL_YEARLY_INFLATION_PROPORTION = 0.05\n",
23+
"TOTAL_SUPPLY = 11_000_000_000 * 10**18"
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": 9,
29+
"id": "dea5a1cb",
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"def get_reward_rate() -> tuple[int, int]:\n",
34+
" \"\"\"\n",
35+
" Compute the reward rates for KMS and Coprocessors based on total supply.\n",
36+
" \n",
37+
" Let totalFeesRewards be the total yearly fees and rewards (i.e. TOTAL_YEARLY_INFLATION_PROPORTION % of current total supply)\n",
38+
" Divide totalFeesRewards into totalFeesRewardsKMS (60%) and totalFeesRewardsCoprocessors (40%)\n",
39+
" Let rateKMS = totalFeesRewardsKMS / SECONDS_PER_YEAR\n",
40+
" Let rateCoprocessors = totalFeesRewardsCoprocessors / SECONDS_PER_YEAR\n",
41+
" \n",
42+
" :return: A tuple (rateKMS, rateCoprocessors) in tokens per second (with 18 decimals)\n",
43+
" \"\"\"\n",
44+
" # Calculate the total yearly fees and rewards\n",
45+
" total_fees_rewards = int(TOTAL_SUPPLY * TOTAL_YEARLY_INFLATION_PROPORTION)\n",
46+
" \n",
47+
" # Divide into KMS (60%) and Coprocessors (40%)\n",
48+
" total_fees_rewards_kms = int(total_fees_rewards * 0.60)\n",
49+
" total_fees_rewards_coprocessors = int(total_fees_rewards * 0.40)\n",
50+
" \n",
51+
" # Calculate the per-second rates\n",
52+
" rate_kms = total_fees_rewards_kms // SECONDS_PER_YEAR\n",
53+
" rate_coprocessors = total_fees_rewards_coprocessors // SECONDS_PER_YEAR\n",
54+
" \n",
55+
" return rate_kms, rate_coprocessors"
56+
]
57+
},
58+
{
59+
"cell_type": "code",
60+
"execution_count": 10,
61+
"id": "0baefc2f",
62+
"metadata": {},
63+
"outputs": [
64+
{
65+
"name": "stdout",
66+
"output_type": "stream",
67+
"text": [
68+
"Total Supply: 11,000,000,000 tokens\n",
69+
"Total Yearly Rewards (5.0%): 550,000,000 tokens\n",
70+
" - KMS (60%): 330,000,000 tokens/year\n",
71+
" - Coprocessors (40%): 220,000,000 tokens/year\n",
72+
"\n",
73+
"Per-Second Rates (raw value with 18 decimals):\n",
74+
" - rateKMS: 10464231354642313336\n",
75+
" - rateCoprocessors: 6976154236428209254\n",
76+
"\n",
77+
"Per-Second Rates (in tokens):\n",
78+
" - rateKMS: 10.46 tokens/second\n",
79+
" - rateCoprocessors: 6.98 tokens/second\n"
80+
]
81+
}
82+
],
83+
"source": [
84+
"rate_kms, rate_coprocessors = get_reward_rate()\n",
85+
"\n",
86+
"print(f\"Total Supply: {TOTAL_SUPPLY / 10**18:,.0f} tokens\")\n",
87+
"print(f\"Total Yearly Rewards ({TOTAL_YEARLY_INFLATION_PROPORTION * 100}%): {TOTAL_SUPPLY * TOTAL_YEARLY_INFLATION_PROPORTION / 10**18:,.0f} tokens\")\n",
88+
"print(f\" - KMS (60%): {TOTAL_SUPPLY * TOTAL_YEARLY_INFLATION_PROPORTION * 0.60 / 10**18:,.0f} tokens/year\")\n",
89+
"print(f\" - Coprocessors (40%): {TOTAL_SUPPLY * TOTAL_YEARLY_INFLATION_PROPORTION * 0.40 / 10**18:,.0f} tokens/year\")\n",
90+
"print()\n",
91+
"print(f\"Per-Second Rates (raw value with 18 decimals):\")\n",
92+
"print(f\" - rateKMS: {rate_kms}\")\n",
93+
"print(f\" - rateCoprocessors: {rate_coprocessors}\")\n",
94+
"print()\n",
95+
"print(f\"Per-Second Rates (in tokens):\")\n",
96+
"print(f\" - rateKMS: {rate_kms / 10**18:.2f} tokens/second\")\n",
97+
"print(f\" - rateCoprocessors: {rate_coprocessors / 10**18:.2f} tokens/second\")\n"
2198
]
2299
},
23100
{

protocol-contracts/staking/Makefile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ ENV_PATH=.env.example
55
prettier:
66
npx prettier . --write
77

8+
lint:
9+
npm run lint:sol:fix
10+
npm run lint:js:fix
11+
812
compile:
913
npx hardhat compile
1014

@@ -24,4 +28,4 @@ test-tasks: clean
2428

2529

2630
# Conform to pre-commit checks
27-
conformance: prettier
31+
conformance: prettier lint

protocol-contracts/staking/contracts/mocks/ERC20Mock.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20P
66

77
contract ERC20Mock is ERC1363, ERC20Permit {
88
uint8 private immutable _decimals;
9+
uint256 public constant MAX_MINT_AMOUNT_TOKENS = 1_000_000;
10+
11+
error MintAmountExceedsMax(uint256 amount, uint256 maxAmount);
912

1013
constructor(string memory name_, string memory symbol_, uint8 decimals_) ERC20(name_, symbol_) ERC20Permit(name_) {
1114
_decimals = decimals_;
@@ -16,6 +19,10 @@ contract ERC20Mock is ERC1363, ERC20Permit {
1619
}
1720

1821
function mint(address to, uint256 amount) public virtual {
22+
uint256 maxMintAmount = MAX_MINT_AMOUNT_TOKENS * 10 ** _decimals;
23+
if (amount > maxMintAmount) {
24+
revert MintAmountExceedsMax(amount, maxMintAmount);
25+
}
1926
_mint(to, amount);
2027
}
2128
}

protocol-contracts/staking/tasks/deployment/mocks/ERC20Mock.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { task } from 'hardhat/config';
22
import { HardhatRuntimeEnvironment } from 'hardhat/types';
33

4+
export const ERC20_MOCK_CONTRACT_NAME = 'ERC20Mock';
5+
export const ERC20_MOCK_TOKEN_NAME = 'ZamaMock';
6+
export const ERC20_MOCK_TOKEN_SYMBOL = 'ZAMAMock';
7+
export const ERC20_MOCK_TOKEN_DECIMALS = 18;
8+
49
// Deploy an ERC20Mock contract
510
async function deployERC20MockAndMint(
611
tokenName: string,
@@ -15,10 +20,8 @@ async function deployERC20MockAndMint(
1520
const { deployer } = await getNamedAccounts();
1621
const deployerSigner = await ethers.getSigner(deployer);
1722

18-
const contractName = 'ERC20Mock';
19-
2023
// Get the contract factory and deploy the ERC20Mock contract
21-
const erc20MockFactory = await ethers.getContractFactory(contractName, deployerSigner);
24+
const erc20MockFactory = await ethers.getContractFactory(ERC20_MOCK_CONTRACT_NAME, deployerSigner);
2225
const erc20Mock = await erc20MockFactory.deploy(tokenName, symbol, decimals);
2326
await erc20Mock.waitForDeployment();
2427

@@ -38,15 +41,15 @@ async function deployERC20MockAndMint(
3841
].join('\n'),
3942
);
4043

41-
// Mint the deployer account with 1 billion tokens
42-
const amount = BigInt(10 ** 9) * BigInt(10 ** decimals);
44+
// Mint the deployer account with 1 million tokens
45+
const amount = BigInt(10 ** 6) * BigInt(10 ** decimals);
4346
await erc20Mock.connect(deployerSigner).mint(deployer, amount);
4447

4548
console.log(`👉 Minted ${amount} tokens to deployer account ${deployer}`);
4649

4750
// Save the ERC20Mock contract artifact
48-
const artifact = await getArtifact(contractName);
49-
await save(contractName, { address: erc20MockAddress, abi: artifact.abi });
51+
const artifact = await getArtifact(ERC20_MOCK_CONTRACT_NAME);
52+
await save(ERC20_MOCK_CONTRACT_NAME, { address: erc20MockAddress, abi: artifact.abi });
5053

5154
return erc20MockAddress;
5255
}
@@ -55,13 +58,9 @@ async function deployERC20MockAndMint(
5558
// Example usage:
5659
// npx hardhat task:deployERC20MockAndMintDeployer --network testnet
5760
task('task:deployERC20MockAndMintDeployer').setAction(async function (_, hre) {
58-
const name = 'ZamaMock';
59-
const symbol = 'ZAMAMock';
60-
const decimals = 18;
61-
62-
console.log(`Deploying mocked ERC20 Zama token: ${name} (${symbol})...\n`);
61+
console.log(`Deploying mocked ERC20 Zama token: ${ERC20_MOCK_TOKEN_NAME} (${ERC20_MOCK_TOKEN_SYMBOL})...\n`);
6362

64-
await deployERC20MockAndMint(name, symbol, decimals, hre);
63+
await deployERC20MockAndMint(ERC20_MOCK_TOKEN_NAME, ERC20_MOCK_TOKEN_SYMBOL, ERC20_MOCK_TOKEN_DECIMALS, hre);
6564

6665
console.log('Mocked ERC20 Zama token deployment complete\n');
6766
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './ERC20Mock';
2+
export * from './verify';
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ERC20_MOCK_TOKEN_NAME, ERC20_MOCK_TOKEN_SYMBOL, ERC20_MOCK_TOKEN_DECIMALS } from './ERC20Mock';
2+
import { task, types } from 'hardhat/config';
3+
4+
// Verify a mock ERC20 contract
5+
// Example usage:
6+
// npx hardhat task:verifyERC20Mock --contract-address 0x1234567890123456789012345678901234567890 --network testnet
7+
task('task:verifyERC20Mock')
8+
.addParam('contractAddress', 'The address of the ERC20Mock contract to verify', '', types.string)
9+
.setAction(async function ({ contractAddress }, hre) {
10+
const { run } = hre;
11+
12+
console.log(`Verifying ERC20Mock contract at ${contractAddress}...\n`);
13+
await run('verify:verify', {
14+
address: contractAddress,
15+
constructorArguments: [ERC20_MOCK_TOKEN_NAME, ERC20_MOCK_TOKEN_SYMBOL, ERC20_MOCK_TOKEN_DECIMALS],
16+
});
17+
console.log(`ERC20Mock contract verification complete\n`);
18+
});

protocol-contracts/staking/tasks/deposit.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,17 @@ task('task:depositOperatorStakingFromDeployer')
7070
);
7171
});
7272

73+
// Deposit assets into all coprocessor operator staking contracts from the deployer account
74+
// Example usage:
75+
// npx hardhat task:depositAllCoproOperatorStakingFromDeployer --network testnet
7376
task('task:depositAllCoproOperatorStakingFromDeployer').setAction(async function (_, hre: HardhatRuntimeEnvironment) {
7477
console.log('Depositing assets into all coprocessor operator staking contracts from the deployer account...\n');
7578

7679
// Get the addresses of all coprocessor operator staking contracts
7780
const operatorStakingAddresses = await getAllOperatorStakingCoproAddresses(hre);
7881

7982
for (let i = 0; i < operatorStakingAddresses.length; i++) {
80-
const assets = BigInt(parseInt(getRequiredEnvVar(`OPERATOR_STAKING_COPRO_INITIAL_DEPOSIT_ASSETS_${i}`)));
83+
const assets = BigInt(getRequiredEnvVar(`OPERATOR_STAKING_COPRO_INITIAL_DEPOSIT_ASSETS_${i}`));
8184
const receiver = getRequiredEnvVar(`OPERATOR_STAKING_COPRO_INITIAL_DEPOSIT_RECEIVER_${i}`);
8285

8386
await hre.run('task:depositOperatorStakingFromDeployer', {
@@ -88,14 +91,17 @@ task('task:depositAllCoproOperatorStakingFromDeployer').setAction(async function
8891
}
8992
});
9093

94+
// Deposit assets into all KMS operator staking contracts from the deployer account
95+
// Example usage:
96+
// npx hardhat task:depositAllKMSOperatorStakingFromDeployer --network testnet
9197
task('task:depositAllKMSOperatorStakingFromDeployer').setAction(async function (_, hre: HardhatRuntimeEnvironment) {
9298
console.log('Depositing assets into all KMS operator staking contracts from the deployer account...\n');
9399

94100
// Get the addresses of all KMS operator staking contracts
95101
const operatorStakingAddresses = await getAllOperatorStakingKMSAddresses(hre);
96102

97103
for (let i = 0; i < operatorStakingAddresses.length; i++) {
98-
const assets = BigInt(parseInt(getRequiredEnvVar(`OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_ASSETS_${i}`)));
104+
const assets = BigInt(getRequiredEnvVar(`OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_ASSETS_${i}`));
99105
const receiver = getRequiredEnvVar(`OPERATOR_STAKING_KMS_INITIAL_DEPOSIT_RECEIVER_${i}`);
100106

101107
await hre.run('task:depositOperatorStakingFromDeployer', {
@@ -106,6 +112,9 @@ task('task:depositAllKMSOperatorStakingFromDeployer').setAction(async function (
106112
}
107113
});
108114

115+
// Deposit assets into all operator staking contracts from the deployer account
116+
// Example usage:
117+
// npx hardhat task:depositAllOperatorStakingFromDeployer --network testnet
109118
task('task:depositAllOperatorStakingFromDeployer').setAction(async function (_, hre: HardhatRuntimeEnvironment) {
110119
console.log('Depositing assets into all operator staking contracts from the deployer account...\n');
111120

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
11
export * from './protocolStakingManagerRole';
22
export * from './protocolStakingGovernorRole';
3-
export * from './operatorStakingOwner';

0 commit comments

Comments
 (0)