Skip to content

Commit

Permalink
Merge pull request #531 from lidofinance/feat/easy-track-stonks-top-u…
Browse files Browse the repository at this point in the history
…p-description

feat: add more informative description in case of STONKS EasyTrack motion event
  • Loading branch information
Ivan-Feofanov authored Apr 22, 2024
2 parents 9efdd91 + 0681375 commit 5944496
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 7 deletions.
1 change: 1 addition & 0 deletions ethereum-governance/src/abi/TopUpAllowedRecipients.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"_trustedCaller","type":"address"},{"internalType":"address","name":"_allowedRecipientsRegistry","type":"address"},{"internalType":"address","name":"_finance","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_easyTrack","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"allowedRecipientsRegistry","outputs":[{"internalType":"contract AllowedRecipientsRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_creator","type":"address"},{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"createEVMScript","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"_evmScriptCallData","type":"bytes"}],"name":"decodeEVMScriptCallData","outputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"easyTrack","outputs":[{"internalType":"contract EasyTrack","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"finance","outputs":[{"internalType":"contract IFinance","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"trustedCaller","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
2 changes: 2 additions & 0 deletions ethereum-governance/src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export const INCREASE_STAKING_LIMIT_ADDRESS =
"0xfebd8fac16de88206d4b18764e826af38546afe0";
export const REWARD_PROGRAMS_REGISTRY_ADDRESS =
"0xfcad241d9d2a2766979a2de208e8210edf7b7d4f";
export const STONKS_TOP_UP_ALLOWED_RECIPIENTS_ADDRESS =
"0x6e04aed774b7c89bb43721acdd7d03c872a51b69";

// Other
export const DEPOSIT_EXECUTOR_ADDRESS =
Expand Down
21 changes: 19 additions & 2 deletions ethereum-governance/src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Finding, FindingType, TransactionEvent } from "forta-agent";
import { RUN_TIER } from "./constants";
import { BigNumberish, BigNumber, utils } from "ethers";

export enum RedefineMode {
Strict = "strict",
Expand Down Expand Up @@ -44,8 +45,8 @@ function getSubpathForNetwork(): string {
return "";
}

export function etherscanAddress(address: string): string {
return `[${address}](https://${getSubpathForNetwork()}etherscan.io/address/${address})`;
export function etherscanAddress(address: string, text = address): string {
return `[${text}](https://${getSubpathForNetwork()}etherscan.io/address/${address})`;
}

export function etherscanNft(address: string, id: number | string): string {
Expand Down Expand Up @@ -161,3 +162,19 @@ export function eventSig(abi: string) {
argsRaw.map((arg) => args.push(arg.trim().split(" ")[0]));
return `${name}(${args.join(",")})`;
}

export const formatToken = (
amount: BigNumber,
decimals: BigNumberish,
): string => {
const amountStr = utils.formatUnits(amount, decimals);

const formatter = new Intl.NumberFormat("en", {
maximumFractionDigits: 2,
minimumFractionDigits: 2,
});

return formatter.format(parseFloat(amountStr));
};

export const formatEth = (amount: BigNumber): string => formatToken(amount, 18);
13 changes: 12 additions & 1 deletion ethereum-governance/src/subagents/easy-track/agent-easy-track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@ import { ethersProvider } from "../../ethers";

import INCREASE_STAKING_LIMIT_ABI from "../../abi/IncreaseStakingLimit.json";
import NODE_OPERATORS_REGISTRY_ABI from "../../abi/NodeOperatorsRegistry.json";
import { getMotionLink, getMotionType } from "./utils";
import {
buildStonksTopUpDescription,
getMotionLink,
getMotionType,
} from "./utils";
import {
handleEventsOfNotice,
RedefineMode,
requireWithTier,
} from "../../common/utils";
import type * as Constants from "./constants";
import { EASY_TRACK_STONKS_CONTRACTS } from "./constants";

export const name = "EasyTrack";

Expand Down Expand Up @@ -95,6 +100,12 @@ async function handleEasyTrackMotionCreated(
} else {
description += `\nNo issues with keys! ✅`;
}
} else if (
EASY_TRACK_STONKS_CONTRACTS.includes(
args._evmScriptFactory.toLowerCase(),
)
) {
description += `\n${await buildStonksTopUpDescription(args)}`;
}
findings.push(
Finding.fromObject({
Expand Down
5 changes: 5 additions & 0 deletions ethereum-governance/src/subagents/easy-track/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
INCREASE_STAKING_LIMIT_ADDRESS as increaseStakinigLimitAddress,
EVM_SCRIPT_EXECUTOR_ADDRESS as evmExecutorAddress,
REWARD_PROGRAMS_REGISTRY_ADDRESS as rewardProgramRegAddress,
STONKS_TOP_UP_ALLOWED_RECIPIENTS_ADDRESS,
} from "../../common/constants";

export const INCREASE_STAKING_LIMIT_ADDRESS = increaseStakinigLimitAddress;
Expand Down Expand Up @@ -191,3 +192,7 @@ export const EASY_TRACK_TYPES_BY_FACTORIES = new Map<string, string>([
"Top up recipients (stETH reWARDS)",
],
]);

export const EASY_TRACK_STONKS_CONTRACTS = [
STONKS_TOP_UP_ALLOWED_RECIPIENTS_ADDRESS,
];
33 changes: 33 additions & 0 deletions ethereum-governance/src/subagents/easy-track/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import { ethers, getEthersProvider } from "forta-agent";
import TOP_UP_ALLOWED_RECIPIENTS_ABI from "../../abi/TopUpAllowedRecipients.json";
import { STONKS } from "../stonks-order-watcher/constants";
import { etherscanAddress, formatEth } from "../../common/utils";

export const getMotionType = (
types: Map<string, string>,
evmScriptFactory: string,
Expand All @@ -8,3 +13,31 @@ export const getMotionType = (
export const getMotionLink = (motionId: string) => {
return `[${motionId}](https://easytrack.lido.fi/motions/${motionId})`;
};

// this helper placed here because it's used in handling easy track motion events
export const buildStonksTopUpDescription = async (
args: any,
): Promise<string> => {
const topUpContract = new ethers.Contract(
args._evmScriptFactory,
TOP_UP_ALLOWED_RECIPIENTS_ABI,
getEthersProvider(),
);
const { recipients, amounts } = await topUpContract.decodeEVMScriptCallData(
args._evmScriptCallData,
);
const descriptions = recipients.map((recipient: string, idx: number) => {
const stonksData = getStonksContractInfo(recipient);
const amount = formatEth(amounts[idx]);
const etherScanAddress = etherscanAddress(
recipient,
`${stonksData?.from} -> ${stonksData?.to}`,
);
return `${etherScanAddress} pair with ${amount} stETH`;
});
return `Top up STONKS:\n ${descriptions.join("\n")}`;
};

const getStonksContractInfo = (address: string) => {
return STONKS.find((c) => c.address === address);
};
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ export async function handleBlock(blockEvent: BlockEvent) {
if (blockEvent.blockNumber % BLOCK_WINDOW != 0) {
return [];
}
const findings = await handleOrderSettlement(blockEvent);
return findings;
return handleOrderSettlement(blockEvent);
}

export async function handleTransaction(txEvent: TransactionEvent) {
Expand Down Expand Up @@ -201,10 +200,10 @@ export async function handleOrderSettlement(txBlock: BlockEvent) {
if (balance.lte(STETH_MAX_PRECISION)) {
findings.push(
Finding.fromObject({
name: "✅ Stonks: order fulfill",
name: "✅ Stonks: order fulfilled",
description: `Stonks order ${etherscanAddress(
order.address,
)} was fulfill`,
)} was fulfilled`,
alertId: "STONKS-ORDER-FULFILL",
severity: FindingSeverity.Info,
type: FindingType.Info,
Expand Down

0 comments on commit 5944496

Please sign in to comment.