-
-
Notifications
You must be signed in to change notification settings - Fork 316
feat(suite-native): wire approval and revoke screen to trade data #22138
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: develop
Are you sure you want to change the base?
feat(suite-native): wire approval and revoke screen to trade data #22138
Conversation
922ae03
to
8598d73
Compare
8598d73
to
b913f78
Compare
@coderabbitai review |
β Actions performedReview triggered.
|
Walkthrough
Estimated code review effortπ― 4 (Complex) | β±οΈ ~60 minutes Pre-merge checks and finishing touchesβ Failed checks (2 warnings)
β Passed checks (3 passed)
β¨ Finishing touches
π§ͺ Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
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.
Actionable comments posted: 2
π§Ή Nitpick comments (2)
suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts (1)
225-225
: Consider explicit params for TradingExchangePreview navigation.The tests pass an empty object
{}
for TradingExchangePreview params. While technically valid sinceisApproved
is optional, consider being more explicit for clarity:-expect(mockNavigation.navigate).toHaveBeenCalledWith('TradingExchangePreview', {}); +expect(mockNavigation.navigate).toHaveBeenCalledWith('TradingExchangePreview', { isApproved: false });This makes the intent clearer and matches the param type definition.
Also applies to: 287-287, 311-311
suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/__tests__/ExchangeApprovalLimitSheet.comp.test.tsx (1)
101-111
: Strengthen the βpasses correct propsβ assertionsThese two tests never interact with the sheet β they just confirm that the mocked callback exists, so a regression in the approval-type wiring would still pass. Please drive the component (e.g., press the Unlimited/Limited card) and assert that
mockOnApprovalTypeSelect
receives'INFINITE'
/'MINIMAL'
, and optionally that the selected state updates. This will turn the tests into real safeguards.
π Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
π Files selected for processing (15)
suite-native/intl/src/messages.ts
(1 hunks)suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/ExchangeApprovalLimitSheet.tsx
(4 hunks)suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/__tests__/ExchangeApprovalLimitSheet.comp.test.tsx
(4 hunks)suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
(2 hunks)suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts
(3 hunks)suite-native/module-trading/src/hooks/exchange/useExchangeSelectQuote.ts
(3 hunks)suite-native/module-trading/src/screens/TradingExchangeApprovalScreen.tsx
(5 hunks)suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx
(3 hunks)suite-native/module-trading/src/screens/TradingExchangeRevokeScreen.tsx
(5 hunks)suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
(2 hunks)suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx
(3 hunks)suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx
(2 hunks)suite-native/module-trading/src/utils/general/__tests__/approvalStatusUtils.test.ts
(2 hunks)suite-native/module-trading/src/utils/general/approvalStatusUtils.ts
(1 hunks)suite-native/navigation/src/navigators.ts
(2 hunks)
π§° Additional context used
π§ Learnings (5)
π Learning: 2025-08-27T09:59:23.527Z
Learnt from: vytick
PR: trezor/trezor-suite#20985
File: suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx:92-106
Timestamp: 2025-08-27T09:59:23.527Z
Learning: The TradingExchangePreviewScreen in suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx is POC code with intentional technical debt around error handling in flow steps, as it will be heavily reworked in follow-up PRs.
Applied to files:
suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx
suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts
suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx
suite-native/navigation/src/navigators.ts
suite-native/module-trading/src/hooks/exchange/useExchangeSelectQuote.ts
suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx
suite-native/module-trading/src/screens/TradingExchangeRevokeScreen.tsx
suite-native/module-trading/src/screens/TradingExchangeApprovalScreen.tsx
π Learning: 2025-02-04T13:18:21.530Z
Learnt from: jbazant
PR: trezor/trezor-suite#16668
File: suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx:0-0
Timestamp: 2025-02-04T13:18:21.530Z
Learning: The mock data arrays in `suite-native/module-trading/src/components/TradeableAssetsSheet/TradeableAssetsSheet.tsx` are intentionally used as visual stubs and will be replaced with real data fetching in future commits.
Applied to files:
suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
suite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx
π Learning: 2025-02-21T23:00:49.788Z
Learnt from: jbazant
PR: trezor/trezor-suite#17164
File: suite-native/module-trading/src/components/general/TradeableAssetsSheet/__tests__/TradeableAssetListItem.comp.test.tsx:61-75
Timestamp: 2025-02-21T23:00:49.788Z
Learning: The `renderWithStore` utility from `suite-native/test-utils` accepts a `preloadedState` option to set up initial Redux state for tests. The store initialization is asynchronous, so tests should use `findBy*` queries instead of `getBy*` queries.
Applied to files:
suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx
π Learning: 2025-09-30T20:12:08.320Z
Learnt from: jbazant
PR: trezor/trezor-suite#22046
File: suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangeFeePickerCard.tsx:13-28
Timestamp: 2025-09-30T20:12:08.320Z
Learning: In suite-native/module-trading, when a parent component like ExchangePreviewView is memoized, child components such as ExchangeFeePickerCard don't need to be memoized as they won't re-render unless the parent re-renders, and adding memo() would only introduce unnecessary overhead.
Applied to files:
suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
π Learning: 2025-09-30T20:12:19.587Z
Learnt from: jbazant
PR: trezor/trezor-suite#22046
File: suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangeFromAccountTradePreviewCard.tsx:16-38
Timestamp: 2025-09-30T20:12:19.587Z
Learning: In suite-native/module-trading, when a component like ExchangeFromAccountTradePreviewCard is only used from an already memoized parent component (like ExchangePreviewView), adding React.memo to the child component adds overhead without performance benefit and should be avoided.
Applied to files:
suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
π Additional comments (12)
suite-native/module-trading/src/screens/__tests__/TradingExchangeApprovalScreen.comp.test.tsx (2)
15-20
: LGTM! Mock for useExchangeFlow is well-structured.The mock provides the necessary
confirmTrade
andfetchFeesAndCompose
functions that the screen under test expects from the exchange flow hook.
56-69
: Approve code:quote
extracted from route.params TradingExchangeApprovalScreen destructuresquote
on line 48; no changes needed.suite-native/intl/src/messages.ts (1)
2318-2318
: LGTM! Translation key properly added.The new
approvalSuccessAlert
message is correctly placed undermoduleTrading.tradingExchangePreviewScreen
and provides clear user-facing text for the approval success state.suite-native/module-trading/src/screens/__tests__/TradingExchangeRevokeScreen.comp.test.tsx (2)
38-51
: LGTM! Test properly updated for route-based data flow.The renderScreen function now correctly passes the route prop with
{ params: { quote: testQuote } }
, aligning with the updated navigation parameter types.
75-80
: Correct test update for multiple matching elements.Using
getAllByText
and expecting 2 occurrences of "0 USDC" is the proper way to test when the same text appears multiple times on screen (for current limit and new limit).suite-native/module-trading/src/hooks/exchange/__tests__/useExchangeSelectQuote.test.ts (1)
258-399
: Excellent test coverage of approval status navigation paths.The new test suite thoroughly covers all approval status scenarios:
approved
β TradingExchangePreviewnot_needed
β TradingExchangePreviewneeds_approval
β TradingExchangeApprovalneeds_increase
with token support β TradingExchangeApproval with shouldIncreaseLimitneeds_increase
without token support β TradingExchangeRevoke with shouldIncreaseLimitsuite-native/module-trading/src/screens/__tests__/TradingExchangePreviewScreen.comp.test.tsx (1)
56-66
: Well-designed test helper with optional parameter.The
renderTradingExchangePreviewScreen
helper now accepts an optionalisApproved
parameter (defaulting tofalse
), making it easy to test both the approval success alert and normal preview flows.suite-native/module-trading/src/screens/TradingExchangePreviewScreen.tsx (2)
39-43
: LGTM! Route params properly extracted.The component correctly destructures
params
from the route prop and extractsisApproved
. The type system guaranteesparams
exists (as an object with optionalisApproved
), so the destructuring is safe.
143-155
: Approval success alert properly implemented.The conditional rendering of the approval success alert wrapped in
Animated.View
is well-structured:
- Alert only shows when
isApproved
is truthy- Uses proper translation key for the message
- Success variant provides appropriate visual feedback
- VStack provides consistent spacing
suite-native/navigation/src/navigators.ts (2)
2-2
: LGTM! Required type import added.The
ExchangeTrade
import frominvity-api
is necessary for typing the route params that now carry quote data.
342-353
: Navigation param types properly defined.The updated param types for the trading exchange flow are well-structured:
TradingExchangePreview
: Simple optional boolean flag for approval success stateTradingExchangeApproval
: Quote data plus optional flags for limit increase and revoke statusTradingExchangeRevoke
: Quote data plus optional flag for limit increaseThis enables type-safe route-based data flow across the approval/revoke screens.
suite-native/module-trading/src/components/exchange/ExchangeApprovalLimitSheet/ExchangeApprovalLimitSheet.tsx (1)
59-74
: Nice token-aware formattingGreat touch splitting into
CryptoAmountFormatter
vsTokenAmountFormatter
; this keeps network and token approvals formatted with the right precision.
suite-native/module-trading/src/components/exchange/ExchangePreview/ExchangePreviewView.tsx
Show resolved
Hide resolved
suite-native/module-trading/src/screens/TradingExchangeApprovalScreen.tsx
Show resolved
Hide resolved
} | ||
}, [isVisible, openModal]); | ||
useEffect( | ||
() => (isVisible ? openModal() : closeModal()), |
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.
This calls openModal when removing from parent, right? Do we want it? Why did the previous version not work?
} | ||
|
||
const limitAmount = `200.32 ${coinSymbol}`; //TODO | ||
const limitAmount = |
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.
nit:
const limitAmount = | |
const limitAmountFormatter = |
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.
I would avoid unnecessary re-renders for this one. Could we use a useMemo
or useCallback
here, please?
contractAddress={contractAddress} | ||
isChecked={true} | ||
isChecked={selectedApprovalType === 'INFINITE'} | ||
onChange={() => { |
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.
nit
onChange={() => { | |
onChange={() => onApprovalTypeSelect('INFINITE')} |
contractAddress={contractAddress} | ||
isChecked={false} | ||
isChecked={selectedApprovalType === 'MINIMAL'} | ||
onChange={() => { |
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.
nit
onChange={() => { | |
onChange={() => onApprovalTypeSelect('MINIMAL')} |
<ExchangeFeePickerCard quote={quote} isTxnError={isTxnError} /> | ||
</VStack> | ||
</ScrollView> | ||
<> |
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.
Q: are there now correct spaces between children? previously 20pts
export const TradingExchangeApprovalScreen = ({ | ||
route: { params }, | ||
}: TradingExchangeApprovalScreenProps) => { | ||
const { quote, shouldIncreaseLimit, isRevoked } = params; |
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.
I am still not sure about passing quote via params, but lets give it a try and refactor later if necessary
|
||
if (success) { | ||
// TODO | ||
await fetchFeesAndCompose(); |
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.
This wont be needed here, lets delete so we are not confused later
return 'needs_approval'; | ||
}; | ||
|
||
export const tokenSupportsIncreasingAllowance = (contractAddress?: string): boolean => { |
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.
This can be easily moved to suite-common/trading from desktop and reused. Please, lets do that, so there is single source of truth for both apps.
return ( | ||
<Screen header={<ExchangePreviewScreenHeader />}> | ||
<ExchangePreviewView quote={quote} txnErrorString={txnErrorString} /> | ||
<VStack spacing="sp20" paddingVertical="sp20"> |
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.
Please move this into ExchangePreviewView
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.
I have tested it and it seems to work as expected. Only a few small changes and it is good to merge π
({ isVisible, onDismiss }: ExchangeApprovalLimitSheetProps) => { | ||
const { bottomSheetRef, openModal } = useBottomSheetModal(); | ||
({ | ||
isVisible, |
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.
What about moving useBottomSheetModal
one level up instead of using isVisible
? It feels redundant.. maybe we could change the logic directly in useBottomSheetControls What do you think?
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.
Then you could remove the the useEffect
logic below as well
const isIncreasingAllowanceSupported = | ||
tokenSupportsIncreasingAllowance(contractAddress); | ||
|
||
if (approvalStatus === 'needs_increase' && isIncreasingAllowanceSupported) { |
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.
nit: Maybe we can simpify it a bit?
if (approvalStatus === 'needs_increase') {
const route = isIncreasingAllowanceSupported
? TradingStackRoutes.TradingExchangeApproval
: TradingStackRoutes.TradingExchangeRevoke;
return navigation.navigate(route, {
quote: candidateQuote,
shouldIncreaseLimit: true,
});
}
// fallback
return navigation.navigate(TradingStackRoutes.TradingExchangeApproval, {
quote: candidateQuote,
});
variant="info" | ||
/> | ||
{!!shouldIncreaseLimit && ( | ||
<Animated.View> |
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.
nit: we can use AnimatedBox from atoms
<Button | ||
onPress={() => { | ||
// TODO | ||
if (shouldIncreaseLimit) { |
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.
nit: could we extract it to a separate function please?
Description
Related Issue
Resolve #21192
ππ₯οΈ Suite native android test results: View in Currents