Commit 0e264ec
refactor(card): B1 foundation – race-safe tx confirmation + Money Account delegation (#30000)
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.
In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->
## **Description**
<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->
This is the **B1 foundation** branch of the Money Account ↔ Card linkage
stack. It establishes clean controller and utility infrastructure that
the subsequent hook/UX branches (B2, B3) will build on.
### Why
The existing `useCardDelegation` hook contained two structural problems:
1. **Race condition** – the EVM approval flow subscribed to
`TransactionController:transactionConfirmed` _after_ calling
`addTransaction`. A fast-confirming transaction would fire the event
before the subscription was registered, silently leaving the delegation
incomplete.
2. **Inline SIWE message formatting** – the hook built the
Sign-In-With-Ethereum message itself, duplicating provider-specific
logic (EVM vs Solana wording, chain-ID mapping, expiration rules) that
lives in the Baanx provider.
Additionally, `CardController` had no way to orchestrate the full Money
Account delegation flow (SIWE sign + background ERC-20 approval +
`approveFunding` callback) without pushing that logic into a UI hook.
### What
| Layer | Change |
|---|---|
| **`awaitTransactionConfirmed` util** | New utility that subscribes to
`TransactionController:transactionConfirmed` **before** submitting the
transaction, stashes events that arrive while waiting for the tx ID,
then replays them once the ID is known. Handles timeout (5 min default)
and graceful unsubscription. |
| **`moneyAccountCardToken` util** | New utility to resolve the Monad
USDC `CardFundingToken` out of the provider's delegation-settings
response; drives `linkMoneyAccountCard` without touching the UI layer. |
| **Messenger delegation** |
`TransactionController:transactionConfirmed` is now delegated to
`CardControllerMessenger` so `CardController` can subscribe natively
without reaching through the root messenger. |
| **`ICardProvider.generateCardDelegationSignatureMessage`** | New
optional method on the provider interface; implemented in
`BaanxProvider` with correct EVM (includes `Expiration Time`) and Solana
(omits it, uses Solana wording) variants. |
| **`CardController.generateCardDelegationSignatureMessage`** | Thin
public wrapper that forwards to the active provider — the single source
of SIWE message truth accessible to both the controller and UI hooks. |
| **`CardController.linkMoneyAccountCard`** | New controller method that
orchestrates the full background MA linkage: validates input → resolves
token → fetches delegation challenge → signs SIWE message via
`KeyringController` → submits ERC-20 approval with `requireApproval:
false` using `awaitTransactionConfirmed` → calls
`provider.approveFunding`. |
| **`useCardDelegation` (EVM path)** | Replaces the
`subscribeOnceIf`-after-`addTransaction` pattern with
`awaitTransactionConfirmed`, eliminating the race condition. SIWE
message generation now delegates to
`CardController.generateCardDelegationSignatureMessage`. |
All changes are covered by unit tests (190 passing).
## **Changelog**
<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`
If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`
(This helps the Release Engineer do their job more quickly and
accurately)
-->
CHANGELOG entry: null
## **Related issues**
<!--
Link a real GitHub or Jira issue using `Fixes:`, `Closes:`, or `Refs:`.
If no issue exists, write an explicit one-line rationale.
-->
No issue: internal refactor foundation for the Money Account ↔ Card
linkage stack (B1 of a three-branch stack).
## **Manual testing steps**
<!--
This branch contains no user-visible behaviour changes (no new UI, no
flag changes). All observable paths are covered by unit tests.
-->
N/A
## **Screenshots/Recordings**
<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->
### **Before**
N/A
### **After**
N/A
## **Pre-merge author checklist**
<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.
Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->
- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.
#### Performance checks (if applicable)
- [ ] I've tested on Android
- Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example
For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).
## **Pre-merge reviewer checklist**
<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->
- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.
<!-- Generated with the help of the pr-description AI skill -->
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Medium Risk**
> Medium risk because it changes transaction-confirmation waiting
behavior (new subscribe/unsubscribe + failure/timeout handling) and adds
a new background allowance-approval flow in `CardController` that signs
messages and submits transactions without user confirmation.
>
> **Overview**
> Introduces a new `awaitTransactionConfirmed` utility that subscribes
to `TransactionController:transactionConfirmed` and
`TransactionController:transactionFailed` *before* submitting a
transaction, stashes early events, enforces a timeout, and always
unsubscribes.
>
> Moves SIWE/delegation signature message construction out of
`useCardDelegation` into the provider layer via
`ICardProvider.generateCardDelegationSignatureMessage` (implemented in
`BaanxProvider`) and exposes it through
`CardController.generateCardDelegationSignatureMessage`;
`useCardDelegation` now uses this plus `awaitTransactionConfirmed` for
EVM approvals and listens for `transactionFailed` events.
>
> Adds `CardController.linkMoneyAccountCard` to orchestrate Money
Account �4 Card linkage (resolve Monad USDC from delegation settings,
fetch challenge, sign message, submit ERC-20 approve with
`requireApproval:false`, then call `approveFunding`), plus a
`moneyAccountCardToken` resolver util and messenger/event delegation
updates. Also hardens spending-limit token list building by making the
SDK token lookup callback non-optional, and skips notifications for
`MMM_CARD`-origin transactions.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
26851d8. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent 17e338a commit 0e264ec
19 files changed
Lines changed: 1679 additions & 619 deletions
File tree
- app
- components/UI/Card
- hooks
- util
- core
- Engine
- controllers/card-controller
- providers
- utils
- messengers/card-controller-messenger
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
55 | 56 | | |
56 | 57 | | |
57 | 58 | | |
| |||
65 | 66 | | |
66 | 67 | | |
67 | 68 | | |
| 69 | + | |
| 70 | + | |
68 | 71 | | |
69 | 72 | | |
70 | 73 | | |
| |||
169 | 172 | | |
170 | 173 | | |
171 | 174 | | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
172 | 182 | | |
173 | 183 | | |
174 | 184 | | |
| |||
209 | 219 | | |
210 | 220 | | |
211 | 221 | | |
212 | | - | |
213 | | - | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
214 | 225 | | |
215 | | - | |
216 | | - | |
217 | | - | |
218 | | - | |
219 | | - | |
220 | | - | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
221 | 233 | | |
222 | | - | |
| 234 | + | |
223 | 235 | | |
| 236 | + | |
224 | 237 | | |
225 | 238 | | |
226 | 239 | | |
| |||
602 | 615 | | |
603 | 616 | | |
604 | 617 | | |
605 | | - | |
606 | | - | |
607 | | - | |
608 | | - | |
609 | | - | |
610 | | - | |
611 | | - | |
612 | | - | |
613 | | - | |
614 | | - | |
615 | | - | |
| 618 | + | |
| 619 | + | |
616 | 620 | | |
617 | 621 | | |
618 | 622 | | |
| |||
872 | 876 | | |
873 | 877 | | |
874 | 878 | | |
875 | | - | |
876 | | - | |
| 879 | + | |
| 880 | + | |
877 | 881 | | |
878 | 882 | | |
879 | 883 | | |
| |||
882 | 886 | | |
883 | 887 | | |
884 | 888 | | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
885 | 896 | | |
886 | 897 | | |
887 | 898 | | |
| |||
892 | 903 | | |
893 | 904 | | |
894 | 905 | | |
895 | | - | |
896 | | - | |
897 | | - | |
898 | | - | |
899 | | - | |
900 | | - | |
901 | | - | |
902 | | - | |
903 | | - | |
904 | | - | |
905 | | - | |
906 | | - | |
907 | | - | |
908 | | - | |
909 | | - | |
910 | | - | |
911 | | - | |
| 906 | + | |
912 | 907 | | |
913 | 908 | | |
914 | | - | |
| 909 | + | |
915 | 910 | | |
916 | 911 | | |
917 | 912 | | |
| |||
928 | 923 | | |
929 | 924 | | |
930 | 925 | | |
931 | | - | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
932 | 930 | | |
933 | | - | |
934 | | - | |
| 931 | + | |
| 932 | + | |
935 | 933 | | |
936 | | - | |
937 | 934 | | |
938 | 935 | | |
939 | 936 | | |
| |||
963 | 960 | | |
964 | 961 | | |
965 | 962 | | |
966 | | - | |
967 | | - | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
968 | 971 | | |
969 | 972 | | |
970 | 973 | | |
971 | | - | |
972 | | - | |
973 | 974 | | |
974 | | - | |
975 | | - | |
976 | | - | |
977 | | - | |
978 | | - | |
979 | | - | |
980 | | - | |
981 | | - | |
982 | | - | |
983 | | - | |
984 | | - | |
985 | | - | |
986 | | - | |
987 | | - | |
988 | | - | |
989 | | - | |
990 | | - | |
| 975 | + | |
991 | 976 | | |
992 | 977 | | |
993 | | - | |
| 978 | + | |
994 | 979 | | |
995 | 980 | | |
996 | 981 | | |
| |||
1000 | 985 | | |
1001 | 986 | | |
1002 | 987 | | |
1003 | | - | |
1004 | | - | |
1005 | | - | |
1006 | | - | |
1007 | | - | |
1008 | | - | |
1009 | | - | |
1010 | | - | |
1011 | | - | |
1012 | | - | |
1013 | | - | |
1014 | | - | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
1015 | 991 | | |
1016 | 992 | | |
1017 | | - | |
| 993 | + | |
1018 | 994 | | |
1019 | 995 | | |
1020 | 996 | | |
| |||
1024 | 1000 | | |
1025 | 1001 | | |
1026 | 1002 | | |
1027 | | - | |
1028 | | - | |
1029 | | - | |
1030 | | - | |
1031 | | - | |
1032 | | - | |
1033 | | - | |
1034 | | - | |
1035 | | - | |
1036 | | - | |
1037 | | - | |
1038 | | - | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
1039 | 1006 | | |
1040 | 1007 | | |
1041 | 1008 | | |
| |||
1094 | 1061 | | |
1095 | 1062 | | |
1096 | 1063 | | |
1097 | | - | |
| 1064 | + | |
1098 | 1065 | | |
1099 | 1066 | | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
1100 | 1070 | | |
1101 | 1071 | | |
1102 | 1072 | | |
| |||
1109 | 1079 | | |
1110 | 1080 | | |
1111 | 1081 | | |
1112 | | - | |
1113 | | - | |
1114 | | - | |
1115 | | - | |
1116 | | - | |
1117 | | - | |
1118 | | - | |
| 1082 | + | |
| 1083 | + | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
1119 | 1090 | | |
1120 | | - | |
1121 | | - | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
1122 | 1094 | | |
1123 | 1095 | | |
1124 | 1096 | | |
| |||
1150 | 1122 | | |
1151 | 1123 | | |
1152 | 1124 | | |
1153 | | - | |
| 1125 | + | |
1154 | 1126 | | |
1155 | 1127 | | |
1156 | 1128 | | |
1157 | | - | |
1158 | | - | |
1159 | | - | |
1160 | | - | |
1161 | | - | |
1162 | | - | |
1163 | | - | |
1164 | | - | |
1165 | | - | |
1166 | | - | |
1167 | | - | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
| 1133 | + | |
| 1134 | + | |
| 1135 | + | |
| 1136 | + | |
1168 | 1137 | | |
1169 | | - | |
1170 | | - | |
| 1138 | + | |
| 1139 | + | |
| 1140 | + | |
1171 | 1141 | | |
1172 | 1142 | | |
1173 | 1143 | | |
| |||
1178 | 1148 | | |
1179 | 1149 | | |
1180 | 1150 | | |
1181 | | - | |
1182 | | - | |
1183 | | - | |
1184 | | - | |
1185 | 1151 | | |
1186 | 1152 | | |
1187 | 1153 | | |
1188 | | - | |
| 1154 | + | |
1189 | 1155 | | |
1190 | 1156 | | |
1191 | 1157 | | |
1192 | | - | |
1193 | | - | |
1194 | | - | |
1195 | | - | |
1196 | | - | |
1197 | | - | |
1198 | | - | |
1199 | | - | |
1200 | | - | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
1201 | 1166 | | |
1202 | | - | |
1203 | | - | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
1204 | 1170 | | |
1205 | 1171 | | |
1206 | 1172 | | |
| |||
0 commit comments