feat(ROADMAP-122): add unified transaction lifecycle state machine#38
feat(ROADMAP-122): add unified transaction lifecycle state machine#38Peolite001 wants to merge 1 commit into
Conversation
Introduces the core lifecycle types and state machine hook for unifying transaction UX across all money flows. Purely additive — no existing files modified. - types/transaction.ts: TransactionState, TransactionContext, TransactionLifecycle (uses existing TransactionErrorDetails from transactionErrors.ts) - hooks/useTransactionLifecycle.ts: FSM with submitLock idempotency guard (uses existing mapTransactionError for error mapping) - __tests__/useTransactionLifecycle.test.ts: State machine coverage - __tests__/pollTransactionStatus.test.ts: Coverage for existing poll function The existing transactionErrors.ts is already centralized; this PR builds the lifecycle orchestration on top of it. Follow-up PRs will adopt this in: - useContractMutation / useConfirmedMutation hooks - TransactionStatus UI component - StepFinalSignature, LendPageClient, repay, send-remittance
ogazboiz
left a comment
There was a problem hiding this comment.
this is the cleaner of your two ROADMAP-122 PRs and the one i'd like to land. the hook (useTransactionLifecycle) and types are well scoped and correctly reuse the existing mapTransactionError / pollTransactionStatus exports, tsc is clean. a few things before it's ready:
-
prettier fails on all 4 new files (prettier is our lint gate). run:
npx prettier --write src/app/hooks/useTransactionLifecycle.ts src/app/types/transaction.ts src/app/hooks/tests/useTransactionLifecycle.test.ts src/app/utils/tests/pollTransactionStatus.test.ts
(they're also each missing a trailing newline, prettier fixes that) -
src/app/hooks/tests/useTransactionLifecycle.test.ts:74 expects wallet_rejected for new Error("User declined"), but mapTransactionError (transactionErrors.ts:51-56) only matches rejected|denied|cancelled|canceled, so it returns unknown and the test fails. either change the test error to "User rejected", or add "declined" to the matcher in transactionErrors.ts:51.
-
src/app/utils/tests/pollTransactionStatus.test.ts:79 ("returns cancelled when abort signal") times out at 5s. it uses jest.useFakeTimers() but never advances them after controller.abort(), so the polling sleep never resolves. drive it with
await jest.advanceTimersByTimeAsync(100)after the abort, or abort before invoking and assert synchronously.
heads up on the overlap: this and #35 are competing implementations of the same 3 files. my plan is to land this one as the foundational primitive and have #35 rebase on top of it for the actual call-site wiring (or close #35). more on that over in #35.
once the above is green i'll merge. nice work.
if you want to keep contributing, join us on Telegram: https://t.me/+DOylgFv1jyJlNzM0
Closes #10
What This PR Does
Adds the unified transaction lifecycle state machine requested in ROADMAP-122.
Zero existing files are modified — this is purely additive.
Files Added
types/transaction.tsTransactionState,TransactionContext,TransactionLifecycle(uses existingTransactionErrorDetails)hooks/useTransactionLifecycle.tsuseRefidempotency guardhooks/__tests__/useTransactionLifecycle.test.tsutils/__tests__/pollTransactionStatus.test.tspollTransactionStatus(success, failed, timeout, cancelled via AbortSignal)What This PR Does NOT Do
transactionErrors.ts— already centralizedtransactionFormatter.ts— old exports preservedStepFinalSignature.tsxLendPageClient.tsxrepay/[loanId]/page.tsxuseContractMutation(PR [Infra] Stand up a full CI pipeline (lint, typecheck, unit, e2e, build, a11y) #2)TransactionStatuscomponent (PR [Frontend] Fix toStroops precision so non 7-decimal assets convert correctly #3)Verification