Skip to content

Commit c371651

Browse files
author
Temrjan
authored
Merge pull request #3 from temrjan/feature/fund-reward-pool-script
feat(contracts): add idempotent fundRewardPool script
2 parents 9e8dcea + d1ad4de commit c371651

2 files changed

Lines changed: 121 additions & 0 deletions

File tree

contracts/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"compile": "hardhat compile",
77
"test": "hardhat test",
88
"deploy:testnet": "hardhat run scripts/deploy.ts --network zkSyncSepolia",
9+
"fund:rewards": "hardhat run scripts/fundRewardPool.ts --network zkSyncSepolia",
910
"verify": "hardhat verify --network zkSyncSepolia"
1011
},
1112
"devDependencies": {
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* Fund OltinStaking.rewardPool to a target balance.
3+
*
4+
* Idempotent: ensures rewardPool >= FUND_AMOUNT_OLTIN. Mints OLTIN to admin
5+
* if balance is insufficient, approves the staking contract, then calls
6+
* fundRewardPool with the delta. Skips early if pool is already at target.
7+
*
8+
* Run:
9+
* PRIVATE_KEY=0x... npx hardhat run scripts/fundRewardPool.ts --network zkSyncSepolia
10+
*
11+
* Override amount (default 1000):
12+
* FUND_AMOUNT_OLTIN=2000 npx hardhat run scripts/fundRewardPool.ts --network zkSyncSepolia
13+
*/
14+
// Hardhat loads contracts/.env via hardhat.config.ts (dotenv.config()) before
15+
// running any script, so PRIVATE_KEY is already in process.env here.
16+
import { Wallet, Provider, Contract } from "zksync-ethers";
17+
18+
const OLTIN_ADDRESS = "0x4A56B78DBFc2E6c914f5413B580e86ee1A474347";
19+
const STAKING_ADDRESS = "0x63e537A3a150d06035151E29904C1640181C8314";
20+
const FUND_ORDER_ID = "fund-reward-pool";
21+
22+
const OLTIN_ABI = [
23+
"function mint(address to, uint256 amount, string orderId)",
24+
"function balanceOf(address) view returns (uint256)",
25+
"function approve(address spender, uint256 amount) returns (bool)",
26+
"function allowance(address owner, address spender) view returns (uint256)",
27+
];
28+
29+
const STAKING_ABI = [
30+
"function fundRewardPool(uint256 amount)",
31+
"function rewardPool() view returns (uint256)",
32+
];
33+
34+
function formatOltin(wei: bigint): string {
35+
return `${(Number(wei) / 1e18).toFixed(4)} OLTIN`;
36+
}
37+
38+
async function main() {
39+
const privateKey = process.env.PRIVATE_KEY;
40+
if (!privateKey) {
41+
throw new Error("PRIVATE_KEY not set in contracts/.env");
42+
}
43+
44+
const fundAmountRaw = process.env.FUND_AMOUNT_OLTIN ?? "1000";
45+
if (!/^\d+$/.test(fundAmountRaw)) {
46+
throw new Error(
47+
`FUND_AMOUNT_OLTIN must be a positive integer, got: ${fundAmountRaw}`,
48+
);
49+
}
50+
const fundAmountOltin = BigInt(fundAmountRaw);
51+
const targetAmount = fundAmountOltin * 10n ** 18n;
52+
53+
const provider = new Provider("https://sepolia.era.zksync.dev");
54+
const wallet = new Wallet(privateKey, provider);
55+
56+
console.log("=== Fund OltinStaking.rewardPool ===");
57+
console.log(`Admin: ${wallet.address}`);
58+
console.log(`Target rewardPool: ${formatOltin(targetAmount)}`);
59+
60+
const oltin = new Contract(OLTIN_ADDRESS, OLTIN_ABI, wallet);
61+
const staking = new Contract(STAKING_ADDRESS, STAKING_ABI, wallet);
62+
63+
// 1. Check current rewardPool — skip if already funded.
64+
const rewardPoolBefore: bigint = await staking.rewardPool();
65+
console.log(`\nCurrent rewardPool: ${formatOltin(rewardPoolBefore)}`);
66+
67+
if (rewardPoolBefore >= targetAmount) {
68+
console.log("Already at or above target. Nothing to do.");
69+
return;
70+
}
71+
72+
const toFund = targetAmount - rewardPoolBefore;
73+
console.log(`Need to add: ${formatOltin(toFund)}`);
74+
75+
// 2. Read admin's OLTIN balance and current allowance in parallel.
76+
const [balance, currentAllowance]: [bigint, bigint] = await Promise.all([
77+
oltin.balanceOf(wallet.address),
78+
oltin.allowance(wallet.address, STAKING_ADDRESS),
79+
]);
80+
console.log(`Admin OLTIN balance: ${formatOltin(balance)}`);
81+
82+
// 3. Mint OLTIN to admin if balance insufficient.
83+
if (balance < toFund) {
84+
const toMint = toFund - balance;
85+
console.log(`\nMinting ${formatOltin(toMint)} to admin...`);
86+
const mintTx = await oltin.mint(wallet.address, toMint, FUND_ORDER_ID);
87+
console.log(` tx: ${mintTx.hash}`);
88+
await mintTx.wait();
89+
console.log(` ✓ Minted`);
90+
}
91+
92+
// 4. Approve staking contract for the delta.
93+
if (currentAllowance < toFund) {
94+
console.log(`\nApproving ${formatOltin(toFund)} for staking contract...`);
95+
const approveTx = await oltin.approve(STAKING_ADDRESS, toFund);
96+
console.log(` tx: ${approveTx.hash}`);
97+
await approveTx.wait();
98+
console.log(` ✓ Approved`);
99+
}
100+
101+
// 5. Fund the reward pool.
102+
console.log(`\nCalling fundRewardPool(${formatOltin(toFund)})...`);
103+
const fundTx = await staking.fundRewardPool(toFund);
104+
console.log(` tx: ${fundTx.hash}`);
105+
await fundTx.wait();
106+
console.log(` ✓ Funded`);
107+
108+
// 6. Verify final state.
109+
const rewardPoolAfter: bigint = await staking.rewardPool();
110+
console.log(
111+
`\nRewardPool: ${formatOltin(rewardPoolBefore)}${formatOltin(rewardPoolAfter)}`,
112+
);
113+
114+
console.log("\n=== Done ===");
115+
}
116+
117+
main().catch((e: unknown) => {
118+
console.error(e instanceof Error ? e.message : e);
119+
process.exit(1);
120+
});

0 commit comments

Comments
 (0)