@@ -158,7 +158,16 @@ export const ProposalLifecycleCache = ({
158158 }
159159
160160 const state = proposal . state ;
161- const stateOrder = [ 'created' , 'active' , 'queued' , 'executed' , 'failed' , 'cancelled' ] ;
161+ const stateOrder = [
162+ 'created' ,
163+ 'active' ,
164+ 'queued' ,
165+ 'executed' ,
166+ 'partially_executed' ,
167+ 'expired' ,
168+ 'failed' ,
169+ 'cancelled' ,
170+ ] ;
162171 const currentStateIndex = stateOrder . indexOf ( state ) ;
163172
164173 // Build payload creation substeps
@@ -205,9 +214,12 @@ export const ProposalLifecycleCache = ({
205214 } ) ;
206215 }
207216 payloadExecutionSubsteps . push ( {
208- stepName : `Payload ${ p . payloadId } executed on ${ getNetworkName ( p . chainId ) } ` ,
217+ stepName :
218+ p . state === 'expired'
219+ ? `Payload ${ p . payloadId } expired on ${ getNetworkName ( p . chainId ) } `
220+ : `Payload ${ p . payloadId } executed on ${ getNetworkName ( p . chainId ) } ` ,
209221 timestamp : p . executedAt ,
210- completed : p . state === 'executed' ,
222+ completed : p . state === 'executed' || p . state === 'expired' ,
211223 active : false ,
212224 networkLogo : getNetworkLogo ( p . chainId ) ,
213225 } ) ;
@@ -263,13 +275,36 @@ export const ProposalLifecycleCache = ({
263275
264276 // Add final state step
265277 const allPayloadsExecuted = ! ! payloads ?. length && payloads . every ( ( p ) => p . state === 'executed' ) ;
278+ // proposal.executedAt is the dispatch time; payloads finish later after their timelock, so the
279+ // completed step should reflect the latest payload execution, matching the on-chain finish.
280+ const payloadExecutedTimes = ( payloads ?? [ ] )
281+ . map ( ( p ) => p . executedAt )
282+ . filter ( ( t ) : t is string => ! ! t )
283+ . sort ( ) ;
284+ const lastPayloadExecutedAt = payloadExecutedTimes [ payloadExecutedTimes . length - 1 ] ?? null ;
266285
267- if ( state === 'queued' || state === 'executed' ) {
286+ if (
287+ state === 'queued' ||
288+ state === 'executed' ||
289+ state === 'partially_executed' ||
290+ state === 'expired'
291+ ) {
292+ const isTerminal = state === 'partially_executed' || state === 'expired' ;
293+ const finalStepName =
294+ state === 'expired'
295+ ? 'Expired'
296+ : state === 'partially_executed'
297+ ? 'Partially executed'
298+ : allPayloadsExecuted
299+ ? 'Payloads executed'
300+ : 'Payload execution' ;
268301 steps . push ( {
269- stepName : allPayloadsExecuted ? 'Payloads executed' : 'Payload execution' ,
270- timestamp : allPayloadsExecuted ? proposal . executedAt : proposal . queuedAt ,
271- completed : allPayloadsExecuted ,
272- active : ! allPayloadsExecuted ,
302+ stepName : finalStepName ,
303+ timestamp : allPayloadsExecuted
304+ ? lastPayloadExecutedAt ?? proposal . executedAt
305+ : proposal . queuedAt ,
306+ completed : isTerminal || allPayloadsExecuted ,
307+ active : ! isTerminal && ! allPayloadsExecuted ,
273308 lastStep : true ,
274309 substeps : payloadExecutionSubsteps ,
275310 } ) ;
0 commit comments