Skip to content

Commit 4ad86ed

Browse files
committed
feat: timelock utility
1 parent 969e318 commit 4ad86ed

File tree

2 files changed

+132
-57
lines changed
  • programs/defi-wrapper

2 files changed

+132
-57
lines changed

programs/defi-wrapper/contracts/factory/write.ts

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -136,62 +136,6 @@ factoryWrite.on('option:-cmd2json', function () {
136136

137137
// CREATE POOL COMMANDS
138138

139-
applyCommonOptions(
140-
factoryWrite
141-
.command('create-pool-ggv')
142-
.description('initiates deployment of a GGV strategy pool')
143-
.argument('<address>', 'factory address', stringToAddress),
144-
)
145-
.option(...RR_GAP_BP_OPTION)
146-
.action(
147-
async (
148-
address: Address,
149-
{
150-
reserveRatioGapBP,
151-
...baseOptions
152-
}: BaseFactoryOptions & MintableOptions,
153-
) => {
154-
const contract = await getFactoryContract(address);
155-
const { vaultConfig, timelockConfig, commonPoolConfig } =
156-
await promtBaseVaultConfiguration(baseOptions);
157-
158-
const reserveRatioGapBPValue =
159-
await getReserveRatioGapBP(reserveRatioGapBP);
160-
161-
const confirmationMessage = `Are you sure you want to create a new GGV strategy pool with a configured wrapper?\n
162-
${prepareCreationConfigrationText(
163-
vaultConfig,
164-
timelockConfig,
165-
commonPoolConfig,
166-
)}
167-
reserveRatioGapBP: ${reserveRatioGapBPValue}\n`;
168-
const confirm = await confirmOperation(confirmationMessage);
169-
if (!confirm) return;
170-
171-
const result = await callWriteMethodWithReceipt({
172-
contract,
173-
methodName: 'createPoolGGVStart',
174-
payload: [
175-
vaultConfig,
176-
timelockConfig,
177-
commonPoolConfig,
178-
BigInt(reserveRatioGapBPValue),
179-
],
180-
});
181-
182-
if (!result.receipt || !result.tx) {
183-
logInfo(FIRST_STEP_MESSAGE);
184-
return;
185-
}
186-
187-
const eventData = await getCreatePoolEventData(result.receipt, result.tx);
188-
189-
await logCreatePoolEventData(eventData);
190-
191-
await finalizePoolCreation(contract, eventData);
192-
},
193-
);
194-
195139
applyCommonOptions(
196140
factoryWrite
197141
.command('create-pool-stv')

programs/defi-wrapper/use-cases/timelock-governance/common/read.ts

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,45 @@ import {
88
addressPrompt,
99
textPrompt,
1010
logError,
11+
stringToBigInt,
1112
} from 'utils';
1213
import { common } from './main.js';
13-
import { Address, Hex, stringToHex, isHex } from 'viem';
14+
import { Address, Hex, stringToHex, isHex, decodeFunctionData } from 'viem';
1415
import {
1516
getStvPoolContract,
1617
getTimeLockContract,
1718
} from 'contracts/defi-wrapper/index.js';
1819
import { getPublicClient } from 'providers';
1920

21+
import { DashboardAbi } from 'abi';
22+
import { StvPoolAbi } from 'abi/defi-wrapper/StvPool.js';
23+
import { StvStETHPoolAbi } from 'abi/defi-wrapper/StvStETHPool.js';
24+
import { WithdrawalQueueAbi } from 'abi/defi-wrapper/WithdrawalQueue.js';
25+
import { OssifiableProxyAbi } from 'abi/defi-wrapper/OssifiableProxy.js';
26+
import { TimeLockAbi } from 'abi/defi-wrapper/TimeLock.js';
27+
import { DistributorAbi } from 'abi/defi-wrapper/Distributor.js';
28+
29+
// all abis of expected timelock governed contracts
30+
const mixAbi = [
31+
...DashboardAbi,
32+
...StvPoolAbi,
33+
...StvStETHPoolAbi,
34+
...WithdrawalQueueAbi,
35+
...OssifiableProxyAbi,
36+
...TimeLockAbi,
37+
...DistributorAbi,
38+
];
39+
40+
const getTimelock = async (argAddress: Address | undefined) => {
41+
if (argAddress) return getTimeLockContract(argAddress);
42+
43+
const timelockPrompt = await addressPrompt(
44+
'Enter timelock contract address',
45+
'timelock',
46+
);
47+
return getTimeLockContract(timelockPrompt.timelock as Address);
48+
};
49+
2050
const commonRead = common
2151
.command('read')
2252
.alias('r')
@@ -72,6 +102,107 @@ commonRead
72102
logResult({ data });
73103
}
74104
});
105+
106+
commonRead
107+
.command('get-last-operations')
108+
.description('get last timelock operations')
109+
.argument('[timelock]', 'timelock contract address', stringToAddress)
110+
.option(
111+
'-n, --number <number>',
112+
'number of blocks to look back',
113+
stringToBigInt,
114+
5000n,
115+
)
116+
.action(
117+
async (
118+
timelockAddress: Address | undefined,
119+
options: { number: bigint },
120+
) => {
121+
const client = await getPublicClient();
122+
const timelock = await getTimelock(timelockAddress);
123+
const currentBlock = await client.getBlock({ blockTag: 'latest' });
124+
125+
const toBlock = currentBlock.number;
126+
let fromBlock = toBlock - options.number;
127+
if (fromBlock < 0n) fromBlock = 0n;
128+
129+
const events = await timelock.getEvents.CallScheduled(undefined, {
130+
toBlock,
131+
fromBlock,
132+
strict: true,
133+
} as const);
134+
135+
logInfo(
136+
`Found ${events.length} CallScheduled events from block ${fromBlock} to ${toBlock}:`,
137+
);
138+
139+
for (const event of events) {
140+
const { data, delay, id, index, predecessor, target, value } =
141+
event.args as Required<typeof event.args>;
142+
143+
let waitTime = 0n;
144+
const timestamp = 0n;
145+
146+
const state = await callReadMethodSilent({
147+
contract: timelock,
148+
methodName: 'getOperationState',
149+
payload: [[id]],
150+
});
151+
152+
if (state === 1) {
153+
const timestamp = await callReadMethodSilent({
154+
contract: timelock,
155+
methodName: 'getTimestamp',
156+
payload: [[id]],
157+
});
158+
159+
const now = currentBlock.timestamp;
160+
waitTime = timestamp > now ? timestamp - now : 0n;
161+
}
162+
163+
const stateNames = ['Unset', 'Waiting', 'Ready', 'Done'];
164+
const stateName = stateNames[state] || 'Unknown';
165+
166+
let args, functionName;
167+
168+
try {
169+
const decodeResult = decodeFunctionData({
170+
abi: mixAbi,
171+
data,
172+
});
173+
args = decodeResult.args;
174+
functionName = decodeResult.functionName;
175+
} catch (e) {
176+
args = [];
177+
functionName = 'Unknown function';
178+
}
179+
180+
logResult({
181+
data: [
182+
['Operation ID', id],
183+
['Operation Index', index.toString()],
184+
['State', stateName],
185+
['Target', target],
186+
['Value (ETH)', value.toString()],
187+
['Data', data],
188+
['Function', functionName],
189+
[
190+
'Arguments',
191+
JSON.stringify(args, (_key, value) =>
192+
typeof value === 'bigint' ? value.toString() + 'n' : value,
193+
),
194+
],
195+
196+
['Delay (seconds)', delay.toString()],
197+
['Predecessor', predecessor],
198+
['Wait Time (seconds)', waitTime.toString()],
199+
['Ready Timestamp', timestamp.toString()],
200+
],
201+
});
202+
}
203+
},
204+
);
205+
75206
commonRead
76207
.command('get-operation-state')
77208
.description('get the state of a timelock operation')

0 commit comments

Comments
 (0)