Skip to content

Commit

Permalink
Feat/update caching (#100)
Browse files Browse the repository at this point in the history
* feat: update caching

* fix: remoe obsolete stuff

* fix: add export

* fix: migrate to new js-utils

* fix: remove ipfs cache from governance
  • Loading branch information
sakulstra authored Jan 24, 2024
1 parent 1691b0e commit e659eaf
Show file tree
Hide file tree
Showing 27 changed files with 512 additions and 342 deletions.
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

0 comments on commit e659eaf

Please sign in to comment.