@@ -8,15 +8,45 @@ import {
88 addressPrompt ,
99 textPrompt ,
1010 logError ,
11+ stringToBigInt ,
1112} from 'utils' ;
1213import { common } from './main.js' ;
13- import { Address , Hex , stringToHex , isHex } from 'viem' ;
14+ import { Address , Hex , stringToHex , isHex , decodeFunctionData } from 'viem' ;
1415import {
1516 getStvPoolContract ,
1617 getTimeLockContract ,
1718} from 'contracts/defi-wrapper/index.js' ;
1819import { 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+
2050const 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+
75206commonRead
76207 . command ( 'get-operation-state' )
77208 . description ( 'get the state of a timelock operation' )
0 commit comments