You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Address the release review findings for the Monerium EUR onramp - #1381
Follow-up to the deep review of release PR #1379. One commit per finding.
Fixed
Uniswap swap resume (P1 before EUR enablement).UniswapSwapExecutor checked balance, allowance and quote before the idempotent broadcast(). A mined swap consumes the allowance, so a crash between settlement and phase completion paused every retry for reconciliation although the swap had succeeded. A successful receipt for the deterministic hash now skips the pre-flight checks. Regression test: a resumed swap with allowance 0 and a settled receipt completes without resending or simulating.
Widget reconnect cancel loop (P2). The Monerium completion guard in kyc.states.ts only checked status === "APPROVED", so cancelling the reconnect prompt of an approved profile with a lost session moved on to wallet linking, which failed on the same error. The guard now also requires no rampError, and the quote screen shows the reauthentication message. Test added in ramp.machine.test.ts.
Silent 5xx token refresh (P3).getValidCredentials keeps the session on an upstream failure on purpose, but nothing logged it. It now warns with the entity and upstream status, never the token. Test asserts the session survives, the refresh is retried, and the log carries no refresh token.
Wallet link without the profile lock (P3).linkMoneriumWallet now runs its list reads, link and IBAN request under the same profile advisory lock that IBAN moves and issue registration take. Test asserts the ordering lock → link → IBAN → unlock.
Unbounded dashboard poll (P3).MoneriumWalletLinkFlow stops polling GET /v1/monerium/status after 36 polls of 5 s, the widget's bound, and offers a "Check again" link. The interval logic is a pure helper with tests.
Dead MykoboFeeUnavailableError import removed from the quote service; the Monerium issue executor test reads the EURe address from MONERIUM_ISSUE_NETWORKS instead of a literal.
docs/security-spec/05-integrations/monerium.md invariants 18 and 21 updated for the resume rule and the wallet-link lock.
Deliberately not changed
Onboarding status Monerium refresh throttle. Throttling would require caching the readiness and reauthentication outcome for the TTL, which would delay the dashboard's reaction to a reconnect or a wallet link by up to a minute. The extra load is one status read plus two list reads per poll, only while another non-terminal onboarding keeps the poll alive.
Process-local NodeCache for OAuth state and credentials: single-instance deployment assumption, unchanged.
White-label 403 treated as "profile invisible" in identity.ts: documented design decision, unchanged.
Verification
apps/api: tsc --noEmit clean; 89 unit tests across the touched suites pass; hermetic eur-onramp-monerium.scenario.test.ts plus both Polygon flow tests pass (10/10)
apps/frontend: tsc --noEmit clean; vitest run src/machines/ramp.machine.test.ts 43/43
The swap executor checked balance, allowance and quote before reaching the idempotent broadcast. A mined swap consumes the allowance, so a crash between settlement and phase completion made every retry pause the ramp for reconciliation although the swap had succeeded. A successful receipt for the deterministic hash now skips the pre-flight checks.
…celled
The completion guard only looked at the APPROVED status, so cancelling the reconnect prompt of an approved profile with a lost session moved on to wallet linking, which failed on the same reauthentication error.
A 5xx from the token endpoint keeps the session for the next attempt on purpose, but nothing logged it, so a sustained outage on an expired token was indistinguishable from a blip.
broadcast() re-reads the receipt and treats a transient RPC failure as not mined, so entering it after the resume lookup could resend the mined transaction. One lookup now decides the resume.
dataUpdateCount is cumulative for the cached query, so time spent before linking or a quick reopen consumed the budget. The baseline now restarts on open, after a successful link or move, and on Check again.
Skipping broadcast() also skipped runFinancialOperation, so a row left submitted by a crash between send and result persistence never became confirmed. The receipt read for the resume now feeds the journal's reconcile and perform callbacks, which confirms the row without a second RPC read or a resend; the receipt short-circuit that bypassed the journal is gone.
dataUpdateCount includes the immediate status fetch made when the attempt starts, so this reaches the limit after only 35 five-second refetches (~175 s), one poll earlier than the widget's 36-poll/180-second bound. Exclude that initial fetch from both the interval and exhausted calculations so the implemented timeout matches the stated bound.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to the deep review of release PR #1379. One commit per finding.
Fixed
UniswapSwapExecutorchecked balance, allowance and quote before the idempotentbroadcast(). A mined swap consumes the allowance, so a crash between settlement and phase completion paused every retry for reconciliation although the swap had succeeded. A successful receipt for the deterministic hash now skips the pre-flight checks. Regression test: a resumed swap with allowance 0 and a settled receipt completes without resending or simulating.kyc.states.tsonly checkedstatus === "APPROVED", so cancelling the reconnect prompt of an approved profile with a lost session moved on to wallet linking, which failed on the same error. The guard now also requires norampError, and the quote screen shows the reauthentication message. Test added inramp.machine.test.ts.getValidCredentialskeeps the session on an upstream failure on purpose, but nothing logged it. It now warns with the entity and upstream status, never the token. Test asserts the session survives, the refresh is retried, and the log carries no refresh token.linkMoneriumWalletnow runs its list reads, link and IBAN request under the same profile advisory lock that IBAN moves and issue registration take. Test asserts the ordering lock → link → IBAN → unlock.MoneriumWalletLinkFlowstops pollingGET /v1/monerium/statusafter 36 polls of 5 s, the widget's bound, and offers a "Check again" link. The interval logic is a pure helper with tests.MykoboFeeUnavailableErrorimport removed from the quote service; the Monerium issue executor test reads the EURe address fromMONERIUM_ISSUE_NETWORKSinstead of a literal.docs/security-spec/05-integrations/monerium.mdinvariants 18 and 21 updated for the resume rule and the wallet-link lock.Deliberately not changed
NodeCachefor OAuth state and credentials: single-instance deployment assumption, unchanged.identity.ts: documented design decision, unchanged.Verification
apps/api:tsc --noEmitclean; 89 unit tests across the touched suites pass; hermeticeur-onramp-monerium.scenario.test.tsplus both Polygon flow tests pass (10/10)apps/frontend:tsc --noEmitclean;vitest run src/machines/ramp.machine.test.ts43/43apps/dashboard:tsc --noEmitclean; wallet-step tests 7/7bun verifyclean