Add calculation of stakers (to who we propose to restore rewards) locked balances & use multicall, speed up scripts execution more than 10 times
This commit is contained in:
parent
dbd12a63a2
commit
55a6540a13
86
abi/MultiCallABI.json
Normal file
86
abi/MultiCallABI.json
Normal file
@ -0,0 +1,86 @@
|
||||
[
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentBlockTimestamp",
|
||||
"outputs": [{ "name": "timestamp", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": false,
|
||||
"inputs": [
|
||||
{
|
||||
"components": [
|
||||
{ "name": "target", "type": "address" },
|
||||
{ "name": "callData", "type": "bytes" }
|
||||
],
|
||||
"name": "calls",
|
||||
"type": "tuple[]"
|
||||
}
|
||||
],
|
||||
"name": "aggregate",
|
||||
"outputs": [
|
||||
{ "name": "blockNumber", "type": "uint256" },
|
||||
{ "name": "returnData", "type": "bytes[]" }
|
||||
],
|
||||
"payable": false,
|
||||
"stateMutability": "nonpayable",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getLastBlockHash",
|
||||
"outputs": [{ "name": "blockHash", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "addr", "type": "address" }],
|
||||
"name": "getEthBalance",
|
||||
"outputs": [{ "name": "balance", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentBlockDifficulty",
|
||||
"outputs": [{ "name": "difficulty", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentBlockGasLimit",
|
||||
"outputs": [{ "name": "gaslimit", "type": "uint256" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [],
|
||||
"name": "getCurrentBlockCoinbase",
|
||||
"outputs": [{ "name": "coinbase", "type": "address" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
},
|
||||
{
|
||||
"constant": true,
|
||||
"inputs": [{ "name": "blockNumber", "type": "uint256" }],
|
||||
"name": "getBlockHash",
|
||||
"outputs": [{ "name": "blockHash", "type": "bytes32" }],
|
||||
"payable": false,
|
||||
"stateMutability": "view",
|
||||
"type": "function"
|
||||
}
|
||||
]
|
1
data/stakersLockedBalanceSum.txt
Normal file
1
data/stakersLockedBalanceSum.txt
Normal file
@ -0,0 +1 @@
|
||||
Locked balance of stakers to who we want restore rewards: 392252226884126520706939 (~ 392252.23 TORN)
|
73
package.json
73
package.json
@ -1,39 +1,38 @@
|
||||
{
|
||||
"name": "proposal-25-restore-rewards",
|
||||
"version": "1.0.0",
|
||||
"description": "Proposal to restore old rewards value (as before hack) after redeploying Staking contract",
|
||||
"scripts": {
|
||||
"computeRewards": "npx ts-node scripts/writeStakersData.ts",
|
||||
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17466009",
|
||||
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --gas-report"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.tornado.ws/Theo/proposal-25-restore-rewards"
|
||||
},
|
||||
"author": "Theo",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^3.2.0-rc.0",
|
||||
"@openzeppelin/upgrades-core": "^1.0.1",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"dotenv": "^16.1.4",
|
||||
"torn-token": "^1.0.4",
|
||||
"web3": "^1.10.0",
|
||||
"web3-utils": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.2.3",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.6",
|
||||
"chai": "^4.3.7",
|
||||
"ethereum-waffle": "^4.0.10",
|
||||
"ethers": "^6.5.1",
|
||||
"@nomicfoundation/hardhat-foundry": "^1.0.1",
|
||||
"@nomicfoundation/hardhat-verify": "^1.0.1",
|
||||
"@nomiclabs/hardhat-ethers": "^2.2.3",
|
||||
"ethers": "^5",
|
||||
"hardhat": "^2.15.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
"name": "proposal-25-restore-rewards",
|
||||
"version": "1.0.0",
|
||||
"description": "Proposal to restore old rewards value (as before hack) after redeploying Staking contract",
|
||||
"scripts": {
|
||||
"computeRewards": "npx ts-node scripts/writeStakersData.ts",
|
||||
"test": "forge test -vvv --fork-url https://rpc.mevblocker.io --fork-block-number 17466009",
|
||||
"testGas": "forge test -vvv --fork-url https://rpc.mevblocker.io --gas-report",
|
||||
"testStakersLocked": "npx ts-node test/stakersLockedBalanceSum.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.tornado.ws/Theo/proposal-25-restore-rewards"
|
||||
},
|
||||
"author": "Theo",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^3.2.0-rc.0",
|
||||
"@openzeppelin/upgrades-core": "^1.0.1",
|
||||
"bignumber.js": "^9.1.1",
|
||||
"dotenv": "^16.1.4",
|
||||
"torn-token": "^1.0.4",
|
||||
"web3": "^1.10.0",
|
||||
"web3-utils": "^1.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.2.3",
|
||||
"@nomiclabs/hardhat-waffle": "^2.0.6",
|
||||
"chai": "^4.3.7",
|
||||
"ethereum-waffle": "^4.0.10",
|
||||
"ethers": "^5",
|
||||
"@nomicfoundation/hardhat-foundry": "^1.0.1",
|
||||
"@nomicfoundation/hardhat-verify": "^1.0.1",
|
||||
"hardhat": "^2.15.0",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.1.3"
|
||||
}
|
||||
}
|
||||
|
21
test/stakersLockedBalanceSum.ts
Normal file
21
test/stakersLockedBalanceSum.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
import { getStakersLockedBalancesSum } from "../utils/stakers";
|
||||
import { currentProposalVotingStartBlock } from "../utils/config";
|
||||
|
||||
async function main() {
|
||||
const stakersLockedBalanceSum = await getStakersLockedBalancesSum(currentProposalVotingStartBlock);
|
||||
|
||||
console.log("Locked balance of stakers to who we want restore rewards:", stakersLockedBalanceSum.div(1e18).toFixed(2), "TORN");
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join("data", "stakersLockedBalanceSum.txt"),
|
||||
`Locked balance of stakers to who we want restore rewards: ${stakersLockedBalanceSum.toString(10)} (~ ${stakersLockedBalanceSum
|
||||
.div(1e18)
|
||||
.toFixed(2)} TORN)`,
|
||||
{ encoding: "utf-8" }
|
||||
);
|
||||
}
|
||||
|
||||
main();
|
@ -1,5 +1,8 @@
|
||||
export const governanceAddress = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
|
||||
export const oldStakingAddress = "0x2FC93484614a34f26F7970CBB94615bA109BB4bf";
|
||||
export const multicallContractAddress = "0xeefBa1e63905eF1D7ACbA5a8513c70307C1cE441";
|
||||
|
||||
export const currentProposalVotingStartBlock = 17492630;
|
||||
export const governanceDeployedBlock = 11474695;
|
||||
export const governanceRewardsProposalBlock = 14173399;
|
||||
export const hackBlock = 17299139;
|
||||
export const hackBlock = 17299139;
|
||||
|
@ -4,10 +4,11 @@ import { AbiItem } from "web3-utils";
|
||||
import { EthAddress, IStaker } from "./@types/staker";
|
||||
|
||||
import * as dotenv from "dotenv";
|
||||
import { governanceAddress, governanceRewardsProposalBlock, hackBlock, oldStakingAddress } from "./config";
|
||||
import { governanceAddress, governanceRewardsProposalBlock, hackBlock, oldStakingAddress, multicallContractAddress } from "./config";
|
||||
|
||||
import GovernanceAbi from "../abi/GovernanceAbi.json";
|
||||
import StakingAbi from "../abi/StakingABI.json";
|
||||
import MulticallABI from "../abi/MultiCallABI.json";
|
||||
|
||||
dotenv.config();
|
||||
|
||||
@ -41,16 +42,25 @@ export async function getStakersWithRewardsBeforeHack(): Promise<Array<IStaker>>
|
||||
const stakingContract = new web3.eth.Contract(StakingAbi as AbiItem[], oldStakingAddress);
|
||||
const stakersAddresses = await getAddressesStakersWithProssibleRewards();
|
||||
|
||||
let stakersWithRewardsBeforeHack: Array<IStaker> = [];
|
||||
for (const address of stakersAddresses) {
|
||||
// Check stakers rewards on previous block before hack
|
||||
const rewardsBeforeHack = await stakingContract.methods.checkReward(address).call({}, hackBlock - 1);
|
||||
// Discard stakers with rewards less than 1 TORN, because accruing each reward requires paying gas
|
||||
if (BigNumber(rewardsBeforeHack).div(1e18).isGreaterThan(1))
|
||||
stakersWithRewardsBeforeHack.push({ address, rewardBalance: BigNumber(rewardsBeforeHack) });
|
||||
}
|
||||
const multiCallQuery: Array<[string, object]> = stakersAddresses.map((stakerAddress) =>
|
||||
stakingContract.methods.checkReward(stakerAddress).encodeABI()
|
||||
);
|
||||
const stakersWithRewardsBeforeHackRawData = await useMultiCall(oldStakingAddress, multiCallQuery, hackBlock - 1);
|
||||
const stakersWithRewardsBeforeHack: Array<IStaker> = stakersWithRewardsBeforeHackRawData.map((reward, index) => ({
|
||||
address: stakersAddresses[index],
|
||||
rewardBalance: BigNumber(reward),
|
||||
}));
|
||||
|
||||
return stakersWithRewardsBeforeHack;
|
||||
// let stakersWithRewardsBeforeHack: Array<IStaker> = [];
|
||||
// for (const address of stakersAddresses) {
|
||||
// // Check stakers rewards on previous block before hack
|
||||
// const rewardsBeforeHack = await stakingContract.methods.checkReward(address).call({}, hackBlock - 1);
|
||||
// // Discard stakers with rewards less than 1 TORN, because accruing each reward requires paying gas
|
||||
// if (BigNumber(rewardsBeforeHack).div(1e18).isGreaterThan(1))
|
||||
// stakersWithRewardsBeforeHack.push({ address, rewardBalance: BigNumber(rewardsBeforeHack) });
|
||||
// }
|
||||
|
||||
return stakersWithRewardsBeforeHack.filter((staker) => staker.rewardBalance.div(1e18).isGreaterThan(1));
|
||||
}
|
||||
|
||||
export async function getStakersWithdrawedAfterHack(): Promise<Array<EthAddress>> {
|
||||
@ -61,3 +71,30 @@ export async function getStakersWithdrawedAfterHack(): Promise<Array<EthAddress>
|
||||
|
||||
return stakersWithdrawedAfterHack;
|
||||
}
|
||||
|
||||
async function useMultiCall(contractAddress: EthAddress, queryArray: Array<Object>, callBlock?: number): Promise<any[]> {
|
||||
const multiCallContract = new web3.eth.Contract(MulticallABI as AbiItem[], multicallContractAddress);
|
||||
const multicallQueryArray = queryArray.map((query) => [contractAddress, query]);
|
||||
const { returnData } = await multiCallContract.methods.aggregate(multicallQueryArray).call({}, callBlock);
|
||||
return returnData;
|
||||
}
|
||||
|
||||
export async function getStakersLockedBalancesSum(block: number): Promise<BigNumber> {
|
||||
const governanceContract = new web3.eth.Contract(GovernanceAbi as AbiItem[], governanceAddress);
|
||||
|
||||
// All stakers who had more than 1 TORN in rewards at the time of the hack
|
||||
const stakersWithRewardsBeforeHack = await getStakersWithRewardsBeforeHack();
|
||||
// Stakers who withdrew rewards from the time of hack until the balance of the old Staking contract was nullified
|
||||
const stakersWithdrawedAfterHack = await getStakersWithdrawedAfterHack();
|
||||
|
||||
// It makes no sense to restore awards to those who already withdrew them from the old Staking contract
|
||||
const stakersToRestoreRewards = stakersWithRewardsBeforeHack.filter((staker) => !stakersWithdrawedAfterHack.includes(staker.address));
|
||||
|
||||
const lockedBalances: Array<string> = await useMultiCall(
|
||||
governanceAddress,
|
||||
stakersToRestoreRewards.map((staker) => governanceContract.methods.lockedBalance(staker.address).encodeABI()),
|
||||
block
|
||||
);
|
||||
|
||||
return lockedBalances.reduce((acc, cur) => acc.plus(BigNumber(cur)), BigNumber(0));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user