Skip to content

Commit

Permalink
fix: order logs by block number and timestamp, get latest rune adddre…
Browse files Browse the repository at this point in the history
…ss by account
  • Loading branch information
woodenfurniture committed Jun 4, 2024
1 parent 4289dd2 commit 8700373
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 26 deletions.
18 changes: 6 additions & 12 deletions scripts/rewards-distribution/calculateRewards/calculateRewards.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Address, Block } from "viem";
import { RFoxLog, StakeLog, UnstakeLog } from "../events";
import { getStakingAmount, isLogType } from "../helpers";
import { isLogType } from "../helpers";
import { REWARD_RATE, WAD } from "../constants";
import assert from "assert";

Expand Down Expand Up @@ -143,14 +143,14 @@ export const calculateRewards = (
// the previous epoch. This prevents us missing rewards for the first block in the epoch.
previousEpochEndBlock: Block,
epochEndBlock: Block,
logs: { log: RFoxLog; timestamp: bigint }[],
orderedLogs: { log: RFoxLog; timestamp: bigint }[],
) => {
let totalStaked = 0n;
let rewardPerTokenStored = 0n;
let lastUpdateTimestamp = contractCreationBlock.timestamp;
const stakingInfoByAccount: Record<Address, StakingInfo> = {};

const stakingLogs = logs.filter(
const stakingLogs = orderedLogs.filter(
(
logWithTimestamp,
): logWithTimestamp is { log: StakeLog | UnstakeLog; timestamp: bigint } =>
Expand Down Expand Up @@ -250,19 +250,13 @@ export const calculateRewards = (
);
}

const epochMetadataByAccount: Record<
Address,
{ runeAddress: string; earnedRewards: bigint }
> = {};
const epochMetadataByAccount: Record<Address, bigint> = {};

for (const [account, epochEndReward] of Object.entries(
epochEndRewardsByAccount,
)) {
epochMetadataByAccount[account as Address] = {
runeAddress: stakingInfoByAccount[account as Address].runeAddress,
earnedRewards:
epochEndReward - (epochStartRewardsByAccount[account as Address] ?? 0n),
};
epochMetadataByAccount[account as Address] =
epochEndReward - (epochStartRewardsByAccount[account as Address] ?? 0n);
}

return epochMetadataByAccount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const distributeAmount = (
totalRuneAmountToDistroBaseUnit: bigint,
earnedRewardsByAccount: Record<Address, bigint>,
) => {
// Set the precision to the maximum possible value to avoid rounding errors
BigNumber.config({ DECIMAL_PLACES: 1e9 });
// Set the precision to a high value to avoid rounding errors
BigNumber.config({ DECIMAL_PLACES: 100 });

const totalEarnedRewards = Object.values(earnedRewardsByAccount).reduce(
(sum, earnedRewards) => sum + earnedRewards,
Expand Down
27 changes: 27 additions & 0 deletions scripts/rewards-distribution/getLatestRuneAddressByAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Address } from "viem";
import { RFoxLog, StakeLog, SetRuneAddressLog } from "./events";
import { hexToUtf8, isLogType } from "./helpers";

export const getLatestRuneAddressByAccount = (
orderedLogs: { log: RFoxLog; timestamp: bigint }[],
) => {
const runeAddressByAccount: Record<Address, string> = {};

for (const { log } of orderedLogs) {
if (isLogType("Stake", log)) {
const stakeLog = log as StakeLog;
runeAddressByAccount[stakeLog.args.account] = hexToUtf8(
stakeLog.args.runeAddress,
);
}

if (isLogType("SetRuneAddress", log)) {
const setRuneAddressLog = log as SetRuneAddressLog;
runeAddressByAccount[setRuneAddressLog.args.account] = hexToUtf8(
setRuneAddressLog.args.newRuneAddress,
);
}
}

return runeAddressByAccount;
};
5 changes: 3 additions & 2 deletions scripts/rewards-distribution/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import {
ARBITRUM_RFOX_PROXY_CONTRACT_ADDRESS,
GET_LOGS_BLOCK_STEP_SIZE,
} from "./constants";
import { AbiEvent, Block, Log, PublicClient } from "viem";
import { AbiEvent, Log, PublicClient } from "viem";
import cliProgress from "cli-progress";
import colors from "ansi-colors";
import { RFoxEvent, RFoxLog, StakeLog, UnstakeLog } from "./events";
import { RFoxLog, StakeLog, UnstakeLog } from "./events";
import { stakingV1Abi } from "./generated/abi-types";
import assert from "assert";

// we cache promises to prevent async race conditions hydrating the cache
const blockNumberToTimestampCache: Record<string, Promise<bigint>> = {};
Expand Down
26 changes: 16 additions & 10 deletions scripts/rewards-distribution/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
} from "./input";
import { distributeAmount } from "./distributeAmount/distributeAmount";
import { Address } from "viem";
import { orderBy } from "lodash";
import { getLatestRuneAddressByAccount } from "./getLatestRuneAddressByAccount";

const main = async () => {
const [currentBlock, [initLog]] = await Promise.all([
Expand Down Expand Up @@ -65,19 +67,23 @@ const main = async () => {
toBlock,
);

const epochMetadataByAccount = calculateRewards(
// sort logs by block number and log index, ascending
// this is necessary because logs can arrive from RPC out of order
const orderedLogs = orderBy(
logs,
["blockNumber", "logIndex"],
["asc", "asc"],
);

const earnedRewardsByAccount = calculateRewards(
contractCreationBlock,
previousEpochEndBlock,
epochEndBlock,
logs,
orderedLogs,
);

const earnedRewardsByAccount: Record<Address, bigint> = {};
for (const [account, { earnedRewards }] of Object.entries(
epochMetadataByAccount,
)) {
earnedRewardsByAccount[account as Address] = earnedRewards;
}
// Get the latest rune address for each account
const runeAddressByAccount = getLatestRuneAddressByAccount(orderedLogs);

await validateRewardsDistribution(
publicClient,
Expand All @@ -96,8 +102,8 @@ const main = async () => {

console.log("Rewards distribution calculated successfully!");

const tableRows = Object.entries(epochMetadataByAccount).map(
([account, { runeAddress }]) => {
const tableRows = Object.entries(runeAddressByAccount).map(
([account, runeAddress]) => {
return {
account,
runeAddress,
Expand Down
2 changes: 2 additions & 0 deletions scripts/rewards-distribution/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@types/cli-progress": "^3.11.5",
"@types/inquirer": "^8.1.3",
"@types/jest": "^29.5.12",
"@types/lodash": "^4.17.4",
"@types/node": "^20.12.4",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
Expand All @@ -21,6 +22,7 @@
"ansi-colors": "^4.1.3",
"cli-progress": "^3.12.0",
"inquirer": "8.2.4",
"lodash": "^4.17.21",
"viem": "^2.9.9"
}
}
5 changes: 5 additions & 0 deletions scripts/rewards-distribution/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,11 @@
expect "^29.0.0"
pretty-format "^29.0.0"

"@types/lodash@^4.17.4":
version "4.17.4"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.4.tgz#0303b64958ee070059e3a7184048a55159fe20b7"
integrity sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==

"@types/node@*":
version "20.12.12"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050"
Expand Down

0 comments on commit 8700373

Please sign in to comment.