Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/update caching #100

Merged
merged 5 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ node_modules
yarn-error.log

# proposal cache
cache
/cache
.idea
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@
"access": "public"
},
"dependencies": {
"@bgd-labs/aave-address-book": "2.15.3-89c77b1d7ee3574250b9bef36599806dd7a3bb94.0",
"@bgd-labs/js-utils": "^1.0.3",
"@bgd-labs/aave-address-book": "2.18.0",
"@bgd-labs/js-utils": "^1.1.1",
"@commander-js/extra-typings": "^11.1.0",
"@inquirer/prompts": "^3.3.0",
"chalk": "^4.1.2",
Expand All @@ -63,7 +63,7 @@
"ipfs-only-hash": "^4.0.0",
"json-bigint": "^1.0.0",
"object-hash": "^3.0.0",
"viem": "^2.0.6",
"viem": "^2.5.0",
"zod": "^3.22.4"
}
}
4 changes: 2 additions & 2 deletions src/commands/fork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function addCommand(program: Command) {
alias: getAlias(),
blockNumber: Number(blockNumber),
};
const governance = getGovernance({ address: DEFAULT_GOVERNANCE, publicClient: DEFAULT_GOVERNANCE_CLIENT });
const governance = getGovernance({ address: DEFAULT_GOVERNANCE, client: DEFAULT_GOVERNANCE_CLIENT });
if (proposalId) {
const payload = await governance.getSimulationPayloadForExecution(BigInt(proposalId));
const fork = await tenderly.fork({
Expand All @@ -54,7 +54,7 @@ export function addCommand(program: Command) {
if (!payloadsControllerAddress) throw new Error('you need to provide a payloadsController');
const payloadsController = getPayloadsController(
payloadsControllerAddress as Hex,
CHAIN_ID_CLIENT_MAP[forkConfig.chainId as keyof typeof CHAIN_ID_CLIENT_MAP] as PublicClient
CHAIN_ID_CLIENT_MAP[forkConfig.chainId as keyof typeof CHAIN_ID_CLIENT_MAP]
);
const payload = await payloadsController.getSimulationPayloadForExecution(Number(payloadId));
const fork = await tenderly.fork({
Expand Down
42 changes: 23 additions & 19 deletions src/commands/governance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ import { IDataWarehouse_ABI, IVotingMachineWithProofs_ABI, IVotingPortal_ABI } f
import { HUMAN_READABLE_STATE, getGovernance } from '../govv3/governance';
import { CHAIN_ID_CLIENT_MAP } from '@bgd-labs/js-utils';
import { logError, logInfo, logSuccess } from '../utils/logger';
import { Hex, PublicClient, encodeAbiParameters, encodeFunctionData, getContract } from 'viem';
import { Address, Hex, encodeAbiParameters, encodeFunctionData, getContract } from 'viem';
import { confirm, input, select } from '@inquirer/prompts';
import { getCachedIpfs } from '../ipfs/getCachedProposalMetaData';
import { toAddressLink, toTxLink } from '../govv3/utils/markdownUtils';
import { getAccountRPL, getBlockRLP } from '../govv3/proofs';
import { DEFAULT_GOVERNANCE, DEFAULT_GOVERNANCE_CLIENT, FORMAT } from '../utils/constants';
import { getPayloadsController } from '../govv3/payloadsController';
import {
cacheGovernance,
cachePayloadsController,
readBookKeepingCache,
writeBookKeepingCache,
} from '../govv3/cache/updateCache';

enum DialogOptions {
DETAILS,
Expand Down Expand Up @@ -41,12 +47,12 @@ export function addCommand(program: Command) {
.option('--payloadsController <string>', 'PayloadsController address')
.action(async ({ payloadId: _payloadId, payloadsController: payloadsControllerAddress, chainId }, options) => {
const payloadId = Number(_payloadId);
const payloadsController = getPayloadsController(
payloadsControllerAddress as Hex,
CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP] as PublicClient
);
const logs = await payloadsController.cacheLogs();
const config = await payloadsController.getPayload(payloadId, logs);
const client = CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP];
const payloadsController = getPayloadsController(payloadsControllerAddress as Hex, client);
const cache = readBookKeepingCache();
const { eventsCache } = await cachePayloadsController(client, payloadsControllerAddress as Address, cache);
writeBookKeepingCache(cache);
const config = await payloadsController.getPayload(payloadId, eventsCache);
await payloadsController.simulatePayloadExecutionOnTenderly(Number(payloadId), config);
});

Expand All @@ -56,10 +62,12 @@ export function addCommand(program: Command) {
.action(async (opts) => {
const governance = getGovernance({
address: DEFAULT_GOVERNANCE,
publicClient: DEFAULT_GOVERNANCE_CLIENT,
client: DEFAULT_GOVERNANCE_CLIENT,
blockCreated: 9640498n,
});
const logs = await governance.cacheLogs();
const cache = readBookKeepingCache();
const { eventsCache } = await cacheGovernance(DEFAULT_GOVERNANCE_CLIENT, DEFAULT_GOVERNANCE, cache);
writeBookKeepingCache(cache);
const count = await governance.governanceContract.read.getProposalsCount();
const proposalIds = [...Array(Number(count)).keys()].reverse();
const selectedProposalId = BigInt(
Expand All @@ -77,7 +85,7 @@ export function addCommand(program: Command) {
),
})
);
const { proposal, ...proposalLogs } = await governance.getProposalAndLogs(selectedProposalId, logs);
const { proposal, ...proposalLogs } = await governance.getProposalAndLogs(selectedProposalId, eventsCache);
let exitLvl2 = false;
while (!exitLvl2) {
const moreInfo = await select({
Expand Down Expand Up @@ -174,11 +182,7 @@ export function addCommand(program: Command) {
else {
logSuccess(
'VotingMachine',
toAddressLink(
machine,
false,
CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP] as PublicClient
)
toAddressLink(machine, false, CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP])
);
if (FORMAT === 'raw') {
logSuccess('Method', 'submitVote');
Expand Down Expand Up @@ -214,7 +218,7 @@ export function addCommand(program: Command) {
const machineContract = getContract({
address: machine,
abi: IVotingMachineWithProofs_ABI,
client: CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP] as PublicClient,
client: CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP],
});
const dataWarehouse = await machineContract.read.DATA_WAREHOUSE();
const roots = await governance.getStorageRoots(selectedProposalId);
Expand All @@ -223,7 +227,7 @@ export function addCommand(program: Command) {
toAddressLink(
dataWarehouse,
false,
CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP] as PublicClient
CHAIN_ID_CLIENT_MAP[Number(chainId) as keyof typeof CHAIN_ID_CLIENT_MAP]
)
);
const block = await DEFAULT_GOVERNANCE_CLIENT.getBlock({ blockHash: proposal.snapshotBlockHash });
Expand Down Expand Up @@ -265,7 +269,7 @@ export function addCommand(program: Command) {
.action(async (name, options) => {
const governance = getGovernance({
address: DEFAULT_GOVERNANCE,
publicClient: DEFAULT_GOVERNANCE_CLIENT,
client: DEFAULT_GOVERNANCE_CLIENT,
});
const proposalId = BigInt(options.getOptionValue('proposalId'));
const proposal = await governance.getProposal(proposalId);
Expand Down Expand Up @@ -313,7 +317,7 @@ export function addCommand(program: Command) {
.action(async (name, options) => {
const governance = getGovernance({
address: DEFAULT_GOVERNANCE,
publicClient: DEFAULT_GOVERNANCE_CLIENT,
client: DEFAULT_GOVERNANCE_CLIENT,
});
const proposalId = BigInt(options.getOptionValue('proposalId'));
const voter = options.getOptionValue('voter') as Hex;
Expand Down
70 changes: 70 additions & 0 deletions src/govv3/cache/modules/governance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { IGovernanceCore_ABI } from '@bgd-labs/aave-address-book';
import { strategicGetLogs } from '@bgd-labs/js-utils';
import { Address, Client, getAbiItem } from 'viem';
import type { ExtractAbiEvent } from 'abitype';
import { getBlock } from 'viem/actions';
import { LogWithTimestamp } from '../../../utils/logs';

export type ProposalCreatedEvent = LogWithTimestamp<ExtractAbiEvent<typeof IGovernanceCore_ABI, 'ProposalCreated'>>;
export type ProposalQueuedEvent = LogWithTimestamp<ExtractAbiEvent<typeof IGovernanceCore_ABI, 'ProposalQueued'>>;
export type ProposalCanceledEvent = LogWithTimestamp<ExtractAbiEvent<typeof IGovernanceCore_ABI, 'ProposalCanceled'>>;
export type ProposalExecutedEvent = LogWithTimestamp<ExtractAbiEvent<typeof IGovernanceCore_ABI, 'ProposalExecuted'>>;
export type ProposalPayloadSentEvent = LogWithTimestamp<ExtractAbiEvent<typeof IGovernanceCore_ABI, 'PayloadSent'>>;
export type ProposalVotingActivatedEvent = LogWithTimestamp<
ExtractAbiEvent<typeof IGovernanceCore_ABI, 'VotingActivated'>
>;

export enum ProposalState {
Null, // proposal does not exists
Created, // created, waiting for a cooldown to initiate the balances snapshot
Active, // balances snapshot set, voting in progress
Queued, // voting results submitted, but proposal is under grace period when guardian can cancel it
Executed, // results sent to the execution chain(s)
Failed, // voting was not successful
Cancelled, // got cancelled by guardian, or because proposition power of creator dropped below allowed minimum
Expired,
}

export function isProposalFinal(state: ProposalState) {
return [ProposalState.Executed, ProposalState.Failed, ProposalState.Cancelled, ProposalState.Expired].includes(state);
}

export async function getGovernanceEvents(
governanceAddress: Address,
client: Client,
fromBlockNumber: bigint,
toBlockNumber: bigint
) {
const logs = await strategicGetLogs({
client,
events: [
getAbiItem({ abi: IGovernanceCore_ABI, name: 'ProposalCreated' }),
getAbiItem({ abi: IGovernanceCore_ABI, name: 'ProposalQueued' }),
getAbiItem({ abi: IGovernanceCore_ABI, name: 'ProposalExecuted' }),
getAbiItem({ abi: IGovernanceCore_ABI, name: 'PayloadSent' }),
getAbiItem({ abi: IGovernanceCore_ABI, name: 'VotingActivated' }),
getAbiItem({ abi: IGovernanceCore_ABI, name: 'ProposalCanceled' }),
],
address: governanceAddress,
fromBlock: fromBlockNumber,
toBlock: toBlockNumber,
});
return await Promise.all(
logs.map(async (l) => ({
...l,
timestamp: Number((await getBlock(client, { blockNumber: l.blockNumber as bigint })).timestamp),
}))
);
}

export async function findProposalLogs(logs: Awaited<ReturnType<typeof getGovernanceEvents>>, proposalId: bigint) {
const proposalLogs = logs.filter((log) => String(log.args.proposalId) === String(proposalId));
return {
createdLog: proposalLogs.find((log) => log.eventName === 'ProposalCreated') as ProposalCreatedEvent,
votingActivatedLog: proposalLogs.find((log) => log.eventName === 'VotingActivated') as ProposalVotingActivatedEvent,
queuedLog: proposalLogs.find((log) => log.eventName === 'ProposalQueued') as ProposalQueuedEvent,
executedLog: proposalLogs.find((log) => log.eventName === 'ProposalExecuted') as ProposalExecutedEvent,
payloadSentLog: proposalLogs.filter((log) => log.eventName === 'PayloadSent') as ProposalPayloadSentEvent[],
canceledLog: proposalLogs.find((log) => log.eventName === 'ProposalCanceled') as ProposalCanceledEvent,
};
}
78 changes: 78 additions & 0 deletions src/govv3/cache/modules/payloadsController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { IPayloadsControllerCore_ABI } from '@bgd-labs/aave-address-book';
import { strategicGetLogs } from '@bgd-labs/js-utils';
import { Address, Client, getAbiItem } from 'viem';
import { getBlock } from 'viem/actions';
import type { ExtractAbiEvent } from 'abitype';
import { LogWithTimestamp } from '../../../utils/logs';

export type PayloadCreatedEvent = LogWithTimestamp<
ExtractAbiEvent<typeof IPayloadsControllerCore_ABI, 'PayloadCreated'>
>;
export type PayloadQueuedEvent = LogWithTimestamp<ExtractAbiEvent<typeof IPayloadsControllerCore_ABI, 'PayloadQueued'>>;
export type PayloadExecutedEvent = LogWithTimestamp<
ExtractAbiEvent<typeof IPayloadsControllerCore_ABI, 'PayloadExecuted'>
>;

export enum PayloadState {
None,
Created,
Queued,
Executed,
Cancelled,
Expired,
}

export const HUMAN_READABLE_PAYLOAD_STATE = {
[PayloadState.None]: 'None',
[PayloadState.Created]: 'Created',
[PayloadState.Queued]: 'Queued',
[PayloadState.Executed]: 'Executed',
[PayloadState.Cancelled]: 'Cancelled',
[PayloadState.Expired]: 'Expired',
};

export function isPayloadFinal(state: number) {
return [
PayloadState.Cancelled,
PayloadState.Executed,
PayloadState.Expired,
// -1, // error
].includes(state);
}

export async function getPayloadsControllerEvents(
payloadsControllerAddress: Address,
client: Client,
fromBlockNumber: bigint,
toBlockNumber: bigint
) {
const logs = await strategicGetLogs({
client,
events: [
getAbiItem({ abi: IPayloadsControllerCore_ABI, name: 'PayloadCreated' }),
getAbiItem({ abi: IPayloadsControllerCore_ABI, name: 'PayloadQueued' }),
getAbiItem({ abi: IPayloadsControllerCore_ABI, name: 'PayloadExecuted' }),
],
address: payloadsControllerAddress,
fromBlock: fromBlockNumber,
toBlock: toBlockNumber,
});
return await Promise.all(
logs.map(async (l) => ({
...l,
timestamp: Number((await getBlock(client, { blockNumber: l.blockNumber as bigint })).timestamp),
}))
);
}

export async function findPayloadLogs(
logs: Awaited<ReturnType<typeof getPayloadsControllerEvents>>,
payloadId: number
) {
const proposalLogs = logs.filter((log) => String(log.args.payloadId) === String(payloadId));
return {
createdLog: proposalLogs.find((log) => log.eventName === 'PayloadCreated') as PayloadCreatedEvent,
queuedLog: proposalLogs.find((log) => log.eventName === 'PayloadQueued') as PayloadQueuedEvent,
executedLog: proposalLogs.find((log) => log.eventName === 'PayloadExecuted') as PayloadExecutedEvent,
};
}
Loading
Loading