-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
feat: Earn mUSD support #24305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: Earn mUSD support #24305
Conversation
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
85d9656 to
b992065
Compare
| const createEventBuilderRef = useRef(createEventBuilder); | ||
|
|
||
| trackEventRef.current = trackEvent; | ||
| createEventBuilderRef.current = createEventBuilder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stale closure captures token lookup functions
Medium Severity
The getEarnToken and getOutputToken functions from useEarnTokens() are captured in the useEffect closure at mount time (line 39), but the effect has an empty dependency array (line 460). While trackEvent and createEventBuilder are correctly stored in refs to avoid stale closures (lines 43-48), this same pattern isn't applied to the token lookup functions. If the underlying earn tokens data changes after mount, the event handlers will use stale function references that may return incorrect or missing token data, causing analytics to have wrong values or token addition to fail on transaction confirmation.
Additional Locations (1)
|
|
||
| navigation.navigate('StakeScreens', { | ||
| screen: Routes.FULL_SCREEN_CONFIRMATIONS.REDESIGNED_CONFIRMATIONS, | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unawaited async call after navigation
Medium Severity
The addTransactionBatch function is called without await after navigating to the confirmation screen. Since addTransactionBatch is an async function that returns a Promise, any errors from the transaction batch creation will be unhandled. If the batch fails to be added (validation error, network issue), the user will already be on the confirmation screen with no transaction to confirm. Other uses of addTransactionBatch in the codebase (e.g., PredictController.ts) properly await the result.
| outputToken = getOutputToken({ | ||
| chainId, | ||
| address: tokenPair.outputToken as Hex, | ||
| } as TokenI); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing null check causes crash on undefined address
High Severity
When getEarnTokenPairAddressesFromState cannot find a matching market, it returns { earnToken: undefined, outputToken: undefined }. These undefined values are then passed to getEarnToken and getOutputToken (cast as Hex), which internally call token.address.toLowerCase(). This throws a TypeError: Cannot read properties of undefined (reading 'toLowerCase'), crashing the transaction event handler. This could occur when processing lending transactions for tokens not yet in the EarnController's markets list.
| | TransactionType.lendingWithdraw, | ||
| // @ts-expect-error TODO: fix this type mismatch | ||
| data: lendingTx.params?.data as string, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type Assertions Suppress TypeScript Errors for Potentially Mismatched Transaction Batch Structure
Medium Severity
The code uses @ts-expect-error comments to suppress TypeScript errors when accessing lendingTx.params.data from transactionBatchesMetadata.transactions. This indicates that the actual type of TransactionBatchTransaction from the TransactionBatchMeta type doesn't match the expected structure being accessed.
If the runtime data structure differs from what's expected (e.g., if params property doesn't exist on actual transaction batch transactions, or data is not a string), the code will either fail at runtime or produce incorrect results. The type suppression masks what could be a real incompatibility between the code's assumptions and the actual data structure provided by @metamask/transaction-controller.
- Add tests for getEarnTokenPairAddressesFromState in token-snapshot - Add deduplication and edge case tests for useEarnLendingTransactionStatus - Add null approval request test for info-root - Update EarnLendingWithdrawalConfirmationView tests (removed obsolete tests) - Achieve 100% coverage for token-snapshot.ts and lending-receive-section.tsx
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsThis PR introduces a new lending deposit confirmation UI for the Earn feature. The changes include:
The changes are focused on:
The risk is medium because:
|
|



Description
What is the reason for the change?
To enable mUSD (MetaMask USD stablecoin) deposits in the Earn feature, users need to see a confirmation screen when depositing mUSD to earn yield via Aave. This requires:
New lending deposit confirmation UI components
Transaction lifecycle tracking for lending transactions
Token snapshot fetching for receipt tokens (aTokens)
Integration with the redesigned confirmations flow
What is the improvement/solution?
New Lending Deposit Confirmation UI
lending-deposit-info/ - New confirmation info components:
lending-deposit-info.tsx - Main container with metrics tracking
lending-hero.tsx - Token avatar and deposit amount display
lending-details.tsx - APR, estimated rewards, withdrawal time, protocol info
lending-receive-section.tsx - Receipt token (aToken) preview
useLendingDepositDetails.ts - Hook to extract/calculate deposit details from transaction metadata
Transaction Lifecycle Tracking
useEarnLendingTransactionStatus.ts - Hook that subscribes to transaction events (submitted, confirmed, rejected, dropped, failed) and:
Automatically adds receipt tokens to wallet on confirmation
Pre-fetches token data on submission
Token Utilities
lending-transaction.ts - Utilities for decoding Aave supply/withdraw transaction data
token-snapshot.ts - Utilities for fetching and caching token metadata from TokenSearchDiscoveryDataController
Added LendingDepositInfo to info-root.tsx for confirmations routing
Added tooltipIconName prop to InfoRow for custom tooltip icons
Updated EarnInputView and EarnTransactionMonitor for lending flow support
Changelog
CHANGELOG entry: Added Earn 1 click deposit flow and mUSD support
Related issues
Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-94
Manual testing steps
To see mUSD flow you mus add DEV env to EarnController constructor and stakeSdkProvider
Screenshots/Recordings
Before
After
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-01-07.at.20.59.57.mp4
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Introduces lending deposit confirmation and end-to-end tx monitoring for Earn, plus navigation and utility updates.
lending-deposit-info(hero, details, receive sections) withuseLendingDepositDetails; wired ininfo-rootfor both direct and batchlendingDeposittxsuseEarnLendingTransactionStatus+EarnTransactionMonitorsubscribe to lifecycle events, track analytics, prefetch token snapshots on submit, and auto-add receipt/underlying tokens on confirmEarnInputViewusesuseConfirmNavigationto navigate to redesigned confirmations with a loader before adding the tx batchlending-transaction(decode Aave supply/withdraw, event props) andtoken-snapshot(fetch/read token metadata); export viautils/index;useEarnTokennow usesfetchTokenSnapshotInfoRowacceptstooltipIconNameWritten by Cursor Bugbot for commit e32d999. This will update automatically on new commits. Configure here.