Skip to content
Open
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
6 changes: 6 additions & 0 deletions src/modules/governance/StateBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export enum ProposalBadgeState {
Executed = 'Executed',
Cancelled = 'Cancelled',
Expired = 'Expired',
PartiallyExecuted = 'Partially executed',
}

type BadgeProps = {
Expand Down Expand Up @@ -52,6 +53,7 @@ const Badge = styled('span')<BadgeProps>(({ theme, state }) => {
[ProposalBadgeState.Executed]: theme.palette.success.main,
[ProposalBadgeState.Cancelled]: theme.palette.error.main,
[ProposalBadgeState.Expired]: theme.palette.error.main,
[ProposalBadgeState.PartiallyExecuted]: theme.palette.warning.main,
[ProposalBadgeState.Failed]: theme.palette.error.main,
};
const color = COLOR_MAP[state] || '#000';
Expand Down Expand Up @@ -91,6 +93,8 @@ export const stateToString = (stateToString: ProposalBadgeState) => {
return 'Cancelled';
case ProposalBadgeState.Expired:
return 'Expired';
case ProposalBadgeState.PartiallyExecuted:
return 'Partially executed';
case ProposalBadgeState.Failed:
return 'Failed';
}
Expand All @@ -110,6 +114,8 @@ export const stringToState = (state: string) => {
return ProposalBadgeState.Cancelled;
case 'Expired':
return ProposalBadgeState.Expired;
case 'Partially executed':
return ProposalBadgeState.PartiallyExecuted;
case 'Failed':
return ProposalBadgeState.Failed;
}
Expand Down
4 changes: 4 additions & 0 deletions src/modules/governance/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ export function cacheStateToBadge(state: string): ProposalBadgeState {
return ProposalBadgeState.Failed;
case 'cancelled':
return ProposalBadgeState.Cancelled;
case 'expired':
return ProposalBadgeState.Expired;
case 'partially_executed':
return ProposalBadgeState.PartiallyExecuted;
default:
return ProposalBadgeState.Created;
}
Expand Down
51 changes: 43 additions & 8 deletions src/modules/governance/proposal/ProposalLifecycleCache.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,16 @@ export const ProposalLifecycleCache = ({
}

const state = proposal.state;
const stateOrder = ['created', 'active', 'queued', 'executed', 'failed', 'cancelled'];
const stateOrder = [
'created',
'active',
'queued',
'executed',
'partially_executed',
'expired',
'failed',
'cancelled',
];
const currentStateIndex = stateOrder.indexOf(state);

// Build payload creation substeps
Expand Down Expand Up @@ -205,9 +214,12 @@ export const ProposalLifecycleCache = ({
});
}
payloadExecutionSubsteps.push({
stepName: `Payload ${p.payloadId} executed on ${getNetworkName(p.chainId)}`,
stepName:
p.state === 'expired'
? `Payload ${p.payloadId} expired on ${getNetworkName(p.chainId)}`
: `Payload ${p.payloadId} executed on ${getNetworkName(p.chainId)}`,
timestamp: p.executedAt,
completed: p.state === 'executed',
completed: p.state === 'executed' || p.state === 'expired',
active: false,
networkLogo: getNetworkLogo(p.chainId),
});
Expand Down Expand Up @@ -263,13 +275,36 @@ export const ProposalLifecycleCache = ({

// Add final state step
const allPayloadsExecuted = !!payloads?.length && payloads.every((p) => p.state === 'executed');
// proposal.executedAt is the dispatch time; payloads finish later after their timelock, so the
// completed step should reflect the latest payload execution, matching the on-chain finish.
const payloadExecutedTimes = (payloads ?? [])
.map((p) => p.executedAt)
.filter((t): t is string => !!t)
.sort();
const lastPayloadExecutedAt = payloadExecutedTimes[payloadExecutedTimes.length - 1] ?? null;

if (state === 'queued' || state === 'executed') {
if (
state === 'queued' ||
state === 'executed' ||
state === 'partially_executed' ||
state === 'expired'
) {
const isTerminal = state === 'partially_executed' || state === 'expired';
const finalStepName =
state === 'expired'
? 'Expired'
: state === 'partially_executed'
? 'Partially executed'
: allPayloadsExecuted
? 'Payloads executed'
: 'Payload execution';
steps.push({
stepName: allPayloadsExecuted ? 'Payloads executed' : 'Payload execution',
timestamp: allPayloadsExecuted ? proposal.executedAt : proposal.queuedAt,
completed: allPayloadsExecuted,
active: !allPayloadsExecuted,
stepName: finalStepName,
timestamp: allPayloadsExecuted
? lastPayloadExecutedAt ?? proposal.executedAt
: proposal.queuedAt,
completed: isTerminal || allPayloadsExecuted,
active: !isTerminal && !allPayloadsExecuted,
lastStep: true,
substeps: payloadExecutionSubsteps,
});
Expand Down
Loading