From 2f0e016a902698f7e15f2c629ed23d1277f10526 Mon Sep 17 00:00:00 2001 From: Matthew Grainger <46547583+Matt561@users.noreply.github.com> Date: Tue, 16 Jun 2026 07:40:36 -0400 Subject: [PATCH 01/23] feat: refactor MoneyOnboardingRive to use latest Rive animation and API (#31724) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Updated `MoneyOnboardingView` to use latest Rive animation and API syntax. ## **Changelog** CHANGELOG entry: updated MoneyOnboardingView to use latest Rive animation and API syntax ## **Related issues** Fixes: [MUSD-996: Update MoneyOnboardingView to use latest Rive animation and API](https://consensyssoftware.atlassian.net/browse/MUSD-996) ## **Manual testing steps** ```gherkin Feature: Updated Rive Money Onboarding Flow Scenario: user can access latest onboarding flow Given user has not already seen the onboarding flow When user clicks the Money balance card on Wallet home **or** the Money navbar button Then latest Money onboarding flow is rendered Scenario: user can navigate forward using the continue button Given user has not already seen the onboarding flow When user taps the continue button Then user moves forward to the next onboarding step Scenario: user can navigate backwards and forwards through the onboarding flow Given user has not already seen the onboarding flow When user taps the left (forward) or right (backward) edge of the screen Then onboarding flow navigates in the correct direction Scenario: user can exit out of the onboarding flow Given user has not already seen the onboarding flow When user taps the close "X" button Then user is redirected to Money Home ``` ## **Screenshots/Recordings** ### **Before** N/A - Old Rive animation file ### **After** https://github.com/user-attachments/assets/c9e507bc-c10b-4ba3-9355-90d71baff3f1 ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- ...money_account_onboarding_animation_v4.riv} | Bin 5637972 -> 4810521 bytes .../MoneyOnboardingView.test.tsx | 365 +++++++++--------- .../MoneyOnboardingView.testIds.ts | 3 + .../MoneyOnboardingView.tsx | 282 +++++++------- 4 files changed, 332 insertions(+), 318 deletions(-) rename app/animations/{money_account_onboarding_animation.riv => money_account_onboarding_animation_v4.riv} (77%) create mode 100644 app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.testIds.ts diff --git a/app/animations/money_account_onboarding_animation.riv b/app/animations/money_account_onboarding_animation_v4.riv similarity index 77% rename from app/animations/money_account_onboarding_animation.riv rename to app/animations/money_account_onboarding_animation_v4.riv index e2f3a2e1e74da78bed961f135c2a2051ffd3b384..528edb63e983945c6309d9d37606a16867446db7 100644 GIT binary patch delta 400358 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%0AvbBue?=39+-8}BoI;%T$a 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 z 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

t7o7gQ~_swsyPs_h-dJ104~f15|E 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

mNuaK{%>#bBw~U(h{+#eyzh_| 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
;GK=H}Rg>^*0-5oM(FtpO>%{@&hR+jv=J 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

sm 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%0ABfuDQQ(B=xiIue2ijyoop9eMEgm=LGwaNPL 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 #E;NlO4Nt~9U3gB;zQM*n+-}x; zVfsRJ{9Di##uxg}(o5U<_!niQi9v`Tgir2wd#)%gO^3buq4(iIZE1?D+__@t;)13{ zb7{&80uym8D~P6aIgy{J0G6J$uUbq6--Tfp(ti^A#@+OSHLyBDl&eQ21Lw(E{w&$K zXc;T5Hz3^Ywue~F`nD-yR|XYHB4#ASHbTTS$VzkrVY+vwVABqj3`V#2Bj8=dy!*}8o1-qoD)ZZDq`tw^@{=#FM#sh2 zrGeGH3v%C;n%UYr%WO@FzI%|f#NNt6btC-+M;Wwws9M++VFae7j*2*Zdxm`(`tG5( zLB&qgrV{sq{g)S=E@Gc%M_a!fk+)<0FIh8aY@cRlTm7(dS6i4EkYLbSIix^lB?QUp5>ukh)A44oeU30`{Y>SWxd(A{QzQIIy zgF#T+;_*#~W-9VK_O5a_%Pq*+`{Eiy{$nr^Hv|ty6*Ufw^>F& zirT#;OvJ(obQ1tM)w-o=rax~Nu}j~s6cOd?MT=rbBEhIBQMO2XO} zuEBGb-38tYrse6%!&wOHK>6NyboYbPlgtYFi%H4fwzg=xAE{o`q%Q#&BHQIfCr41r zws@fx6#f-~t~nItf%2~iYTGU$BKxScqMAmC*h0DxPxXZ)Uqo?Eyh9%Qlr}$l@Fz)B+QgNd7>=O>CL$&8g36+HRp zKpu%^jWRi_m5qT^1^51Qhg5KW_|`c4PxEQC;e(LD`dwt*2RC|g;9Mg`_W?`WF7T*I zz5A%Tn0`UWL}y6^*`xnJOz%X9Nzs4YyAN3MT!k`ebRV$Lf;hVmxy_fN|A41q)@qit z`VUyXjI3ut|4Gq(bOP@_Krv#{dLu)mj`HpUbdqWbwdnl^xXmCdF9@wwE;FsdCayARl@U86MA*hFC-dVzS3ff8Hr z83L!z#M7`VqP<1gQL>t7y>)P^rcA3|h_m=_jB}VW?T>Ou?-Oxv@};?uX!Q=o9_0}* zGbw7%ActwtPmB0b(Vbzscn~adpA7zoww|E^ZKeiy_J1DzCn4Kl21>@&du5#&B!OyK+RpGCa zdZbcMqMR(_B@as56(ZlMn**URpj!b4;ve2BgNzfSVLQ7rrk|1&j2U61U@)^@paB%j zpN}}p?Pwbo#XYIwBfrDdY1x0wWlJ?gwbSjZneB{|(k&;O#(xl-NJpRE-Ax7$pm&W? z4wDP5ba9Bo^y|OW6AIL&LmIhLTdszkbEYrE;tb<9cX z%&nOPc|{c*kyl$@9O01h7pfgR(JQk!Ok)Q4ic;_KeKMwATD< zGYbll$BJ}9tz<{ME+`{aLEj-NsMgKfrwIzti}75)oX74glO~gru!RpPotqe1GkYff zt;wW5tSe5W6BSZNjD;#gD;V{QFdMvnMYsB8A4kR4VeXtmux9YXQ;esV`4bhu(xdO6u7bevWfa{jL%<&L z7h{1G)sB_xSxw42{dYkQKL#-$oBG+69jkOPRLy|LKk@wxq5`v%cC4Zw2RXIq^?*w$ z69+qKQwAI{=6r_tpolz{)AUyFUCL-qWpMuH(uRtmWt!L6&n}aaSQiRC1m)r{$&?}W z!3KJ&f~(CN3^DDDPw)28^d79EHMh4W{R(K4vHQ)q?Wm)lv#D3jxRkzMgPI_Bsim4t zQNJG5thEave)^WA*JQc_K{!-JFx9<+gO{@3{P7Z1P>k7{p-Xp7`6R?}mcxzW1=E3G z9By1WRY8<>lquIZMmk#YB^<6*pLDH><1}&znn^%*d(5wV|S^+Q~-9 zsc{i(u1tnY$){;Q35xB+H7;iAp4lS8QTW-VkCVP>^6%N;)782hp1$mCzsFf*$6^t; zE@eIijLv{f23i4>z=t8^_CjsjMP$`Q%lU$!g*u;#Wm97FY4p)bFg~-l6HV!d?A4@t z4VMY>-eYsk)_SL~Io3R8F3&T#qad2*+{kE`hFvNm$p4m$G+P_CfYorebR=iVe>96| zvX02j8&k-}wbcIvC(S+jdXc7roHFPAQ!w?mK8Mv^usK4F&4cHoXuz9%GiOjYOt7RM zl4Pb@vI!3Fobb|7g2zaBnha+7EN&xVx|{G1@iBm)J{0~F*-+>j35ONINZ7CzJ#PX} z-78l`HWHeqU?iOPy%63P`Ql|)s%I|5#r*WBoZHSB-tO@Nd z5Xf2nXbNwd{711st+5Ov;plpJrv6HpFCI9{{u5^zKC=O_%^t%4sbvzPF*He!GIgDX zXbgX4pko+{J=ombf>py{I=XA}wY-ft_FP-O$4>J8xtoeIexCp2|Zr= zSa9y2MU)m5%!P-Tr++Y8Z*^@fC_NqYkzt5RQm>;p=vcf*AB)eyi^H29cxEpxXEBv} zZW8fa08VY5wB2O3{`?MyHd3oiq+Nj}_%^I(G+RNcTkW+V_v*Bj69UIKwU}D;x+Yln z4R|IfPrK5S1f*!NsW#akmQ+zH+oPx^pYz6PL-q*7bTFJR$MttM8a6;@Jk@}#hl#zw zHbd^UGt#n`I{qpadI0^cbPcEq)LJ{>oTikkLH7(mc+{qX1>NkGCT(?C1bJkkduHpf z7)0GwN5tPEx`Ky(*%C{ze@iwUo8q3Ct$ViR z5fxi~>RJjGr$*9+8i)w|wgKHva~U~L+8Ogy?`a{H2{A5I9Un3*ir8B~3;!~NEOnyz zq(fQ&Bi!gR%3`{h`5#eo*aP8^k~6E>y0xsIrj&n`g|n2J0^h7dy>VJ(5Bea;h4YE~>axQv3*Z*#h z;jC)dH@My%qf!pTOV>&Q+jT7)l3dNhevSo{7<7b6F zNu*LixZD$0K7^0;^3=>xh zT~sjB-bK)JCn+%4I&(KBszhNTi)4aBHe$Jg6y~>a-rvFguhSn6CN-78Fqx)y-9ku@ ziyJCsCv(l$7!+EMX{-dn zLcc~DD?zZNwi4v`=y5^F%j+V!FSIHwAjsDyWXFH1fU84A;z1b{56bE=zta;khxq4R zx+?^ij@E<)e0|ee$WH$AtNg-0-oJLGTJfjST_d-2lM$mzKZ*0t{n-n|tDG2l_aAe1 z@}J+?_3PvOYdzWxCQNusUT8e16DaPj840^ZWO}8;AeUaS6ovWOEqpFk8Zm+e+^y z9#YfDn5m;e)fIMz&RV&JIP0viS8>BBHVZbbwt}=&K4u^8M zfJ1FoXr9dUL;4tQgxPKZ^#=R|a+Mol#>5k|h@RU7saK^qL9X;yX<{6JP^La^Vm&ys z4qjuE;B9;A>}^s2q--)983X>oVHAfuIlRi@R}Kr>Li5ywz(4*TOWqG0upeziM=vj* zsIly<-$pu21ZDHq<>hC1c71L5mf){ern|$G@Y$EF*)g>=jX1-A ziNgYO(4HV-aPOJ$j7-X9w@P>5IeI3V+MGzxd=5)EfWz4w?&0t{hyMYRN^9}-4+qvm z22JY!8@w_*zo92JI^osoYMS*xL^`w5{x52ZBL`_N%V98w^Elkk;qAG&Jj%P|8hQ@8f(E$Q3^DJwI!!|Wv|91JGX|3W6RB4B5Tsxc%z_Fgv_ zMXAtQc;)@OZ~`$hL5Tfjteq0vQ2G&^HMgw2@vlxfVi7>S8{c+$C}4F&ts?Rl>SS4a z+YXW;;1v#&I4rP;{cc%=<_S@sE6&pp1vQgqUE1zfyRv%vD^e099Kac8bGV1Y>m2?E z7zhCax-S$ES9^?IYFWRWUH*C>i~Zp>Z;?FUwzvIBD1dW0+{fW9z`#Ac#%4T+ zGY4ImRLPE2DXlT`7ZVY~`zClP(6{0Eb5=|4QK%GrZk85$cz42DFc_N9?N5lZ7>Zd?+Zld>P_*jzA-gqdi zxJ54`MJod5;{)*WDweJ(P-oWko8E43yRjVI5%9xuR4<@u1%tIY>;M>eyS?$+e0U+| ztzfZBbH4b9a+z&7l+9Ti4q4sA52OVm=}MmD2!~HO^k0b<2obq!O@#kNCZpXNQ573P zUHi`B3B{Ex&(0i<2dshwTh4@8aQ|y?tkk$Oe4Cc-k0h-K1nb{zuuHRcMy&OEhNYTP zGky%0l)xo?=dkc9Cb+NTtp_l0Q;#GZmi&}gTU&IBy%|2%i&E9 z)2(6jVjR}zuqTJp*0^T=3E{Sl$fw*ZS4pJa3qIIIXu8&B8R@~ z8DBXLn{zmT!`Xo98`nY_hHK@9&mH~`CSE4KB1^)l;kq>3_`cm)2ZG?y$x%nA+33Lt z(4|9;klV^Sdh*0x2jY%Kk?sZR=R)vycTractxATf1a}j?XM+d&YV|{n$?8-I2DB-I zu1Ae-nmfAU)-l|+a57VrO6EoJF+_*MDHC4*@HpaA%`w~d4WR+v(c!j38&Fw*k2%b` zk>M2p1Cj84`Z*4Csq31Qel7L^Z+%~Dwpy>@M5J1Kx>JFqgLslT9PZ`tCWq-ZF_Fap zvn~nOhx>iuwibi}I1n)7zHp=0s0j{R?5@y!P?JmqVfXNP=$i zY=04x4WY&0~bT*k4eNaP)21!%7gy?M;n(Ouxvk$w zw+EV~-X3?f>~FX^&)XWP))6P%(MLVk;+*iW#XN0?j1%3dl@GMxC{>`t4yM469ifG5 zK~}#YJ5!gLLc=4cJB#CE7}vpgIOZRL_IPF>6?`|9)bzLxwhIuTf}ve-?0#HCvkQ{e zWiq^VmJA~e6@*LHXZ!WB323#G?X;9AAJ{T71>L~0m;XjSI^julG7akl@^B)tBm@OPL2GvOBg2w^1-z0N-nloscza|z$LghKmZ zWkJI1t*~`n(_P&w7){-qiM@mI-r+^K4s_};KjiuLVGxmJ?_g6QqX`(+RMkY&s`+CD z>FWpF+S~gf7#I7BjMtR2=|dPR`)=so-0L97S0P=9q$MA;ORWxES0@r!E*b_Q;9Tlp%Y_IHaS=XOc@Dj6HASY7MDU_Vt=YUm%48 z;p6?n7F)JGn6xi-utN_Gr-sFL5>g1V=WBV3 z?G=zJK(>}IO%_K*HR-qQYw+2qZk7TdRf9xjkQu|gj{)gsAYDcl0ND{aMXgX2R@rGXER97EEvvhebWoj;yerM@Xe_sN zse4yC79U3n0>Z!@bIJ9!kAf6FAHGo3*q*!|9sosr*Kw99zt1EGkn;qovkDJ@st0X@ z4~AyTh{T_#|7)>j-x!)JbCB<4#%)`F5Zce|XgkH>YYuZBV!u}htb(*fzC~N`I8!D~ z8XcLS$-hJ_;n_`Uxt5$%evY-?oO@kU)<%!#lBaSB(SU)F@VfJS3trXesYx@J!1Jcr z#U*Cz%Xjd+DJU%DN#64$#=|W0S{#ORIQlTg3SAla*$dXIrxOHa-&I|}HqLknPz0m1 z9+@$)XWA-f`$UN8j>ZRX;@s}6yyg$vxo z;aR}ENYK0PF^i|Yj0AqiFbV(`KZe-~jLx#My720I$9=}bq{K7l_A=1r%c_7hl>FNk9Nc$)6jvKuMhT1wZ3K${P;!9n6#Fx0D*?y!6L?m-Y5nXk3`2J>q{MN`A?FO z7^OIgtO46__!ozZ0joet<;p8rGAZ)H4NY#|lDdF^aJUi7dLqwy@iiVnS&-pRQYc7z z$0g)B#U%gAVS5fo0k(vIdOIuF;ev34M9PBKEZ&|Ztw|@iiuG!B1c}{+QWEh-ikdRa z=4Tt1m%}!u`M%}ybDw7U*5ojZL-jOjk^X%S+^r*!_Yg6ILAZ56?+0J=8$1GfaaTfDMtP=JpqMw1kzs-{2J&UQ$Y+ zMRPW+&mD1lAi<1oR*Bmn+%e~KN855D7w`~ZO)ypsKc`_JtVSLTB;m0c)OR;=(vo0adV1vRol|zjd)RQW2Fy2`;gxKNb{SVvQ8# zH-uqZQ*B6o#(OJq-CXVYOpsdVn4rmdrfxP{BX?#Hl?9ElIHfEVGaV2Rm#~OvD|jw6 zPc0;JRs!qk^X6iI-dRagIw3yTHqot;C>;TVI@$W2L#Y5~0_Fu{iHcz&Cg}cxwCtZ) zL7qQmFUb=OXOI(Ne9RMMJtEV<49#L zVh~RhxIw^$>B5(H*)>C|VA$FTfj%-? z^wG-=C5;s5hI~aS)y_^kr^m@;DF#BqXWR74p#{9RcCtlZhBEkRLhfJ-o_G8zNOKxB zK_Hwecy;JT2Y4`+cwdC4`hJ0l>JrkLhIVd<8WLI37^d(@Xc>^KpWvhes&ShY;Y%^A7XO z{Q2`q++FO?F8totqR%t&o#_7TfldfBR?<1j>*&zOhsZJp=z#965St@8npdsRo|8|1 zEJYKOkpSFNe$VTHeqD>YpwxuV0S+7oBtu=IY1$MhAG_i^>GgP~lQDL2onM?{fK&as zR2_Zy?SO{*r-k$}Tse(uQ5D`!;TzAa=41aqky^e>~Z+s30J$G+OhqR z%a;8_sL}gICz~k&q5x}i*a0xB&L~v%x7){TXp>64cL~$5gaZ7%<{4m0%#?r9J|O+Hh6^Ip-$@{Z0`R`G~or`SSh>?0&vCU9&WZxza8r5JuAYt=r)uDbO5Tl z5Z4Gog&2r*ni(BIoL_KZ1YE#M(h-w<1RZ^~+K1F8&>WH2HQ^r=XxlC(ceLY!@)py$ zr!!)8X0?tx8H0>F+O|toVy^3=DM~9Phv7X2G#c`cI!;YWH$B+@^O6c0#$DcXrd(g#ytV=(4(-5Yn(3v1o}^m9eXS|tTPyZhQ|yo?2eC~HQx>| zD?f5>M)meF?253dcVQ>&ia=1ImYS*HxXPlGu4o=Xj%$P1x)Yz^I(6>X)HDU_L9luQ zKH@OTJ%*R(umxa7hc~r;*tj1oDQTDbNR(g@^o;PP65_ zADW|rUPnHL!zATxGfm01Nyw#a*0_5o4kt1WN7&^1C>G!l4(D?i%i$dkGdy5?B{*!z zVQ;|9yn@d~*lgryz!(m1FgW`m`?)BG^*HRo;ZzQzABN^p&P8CK6}M=4bpb_l^FVoZ zfg0QqR}U!aW1!4eM9=DiPWcltrn~CrZiKBNe(?tE&EY?Q8Sk>}ZAuF(PR5AS^GDYrds7&38qR1K-I@41 zmzZG*$z{D&A-G_rhbIZ=Cveh>h3Vmr3AVAFJ$XLsJf%Sn16z9H$+@zPdMMU^y*iNi zAW!T}$DB!>aW(#$9p5z@8FO@WaO`D`p=Bn(-zf!pd3jDUAc5KHZ?nT&BpK>r-uV_o zjytLXr#U(E|F^So#&bAl@%(kPQZ&#fyXKaRplqp&r!={|MK9ZtFwGxhrTg_B#>$R|=@EQRy_0a^tH#FycBOSBb-+VntG~&P z&Au&s)r`k&`C6a+1$Dskp=2h~uqzAF9RWf7#;zD-w%)5PYRcn>rbm5HE}(TTI~?eYvDO*`aFVuQCB3%;!t}W38hM~d zlfrfvK%};^2txdJMhQ*%H4@u0v{I;UgQAvbtm$-o0QXWa{8Oy{)O80^N>mIrV*$}g zlR7QJ1*AgRx0tOeHb(^Izy>-Og2&4%K)`TZfPd=zZSQmWl(4LBEI-J>YtZB%2Pwj1 zOak@~E(lVY<_PGJzC{Ikwk9ae50~RC!*iMiEb_1YA79rUXVdk>SyouAwNdt|(OVEb z!oGW#)w|pxg5)QQRhH<4xRxwo$y&Yl5+z#n^6p!`_bxh-RiZ7?{k}8z-1pwDC4c0z zsewds_!UA6jg!6mR4T`rGFA@Wk23_ z%pdSt&~K*WS;?E?T)ga2OZqJuYJH#6guQZFQW~eh4gE#_rJP!ewCN0_whbsFaPGAj z;6kyaWs>s6dWtr71e=W(Ap5Ozh7tmW_2=|}Z$#hkwfK^j0?_A%-jRG;4&eDCaV8=@ zEhVj4F3jYe)tVqs( zAIKudG0D45Wr*fXJ+!Rb_pjt|&B-7uTtno{juB36rVBRXkOjX`H-Lio7bSRDT#~Y{ z8%pq$pE%K}9jlHKJkfhH^l7n_bjn+-4T{|o;MDHj$tc6-%>$KKJW56dq)U=kYc@>UYd#&pPDc%%;RD(`wQR3T%KEKg-wGV=7|oC+@Nqj3ANLjbi$B07t0d_2YA2Kt4UY6E ztG}(!K}i|61IgYcdlhkN6MGji_4;2GA@V@k`82|iX)BkMgLhDa=WT~NPVL{5D8aKM zV;zCRgW{dVi!X+VS&W`E+)GAA$ot>zO4MbP;K7pQ)IiVFiJtW(W+p>467Kh3%O|OG zzxvFnfh}BkB)%*h?#c9NrNr(+J+b!l!-qI+1`Ka_f`fkU^DAA-i$Mr*(FUqH_n-vN zhP=Fu0R;xMSL#d^Q8S@C@%Oih4>6T34c1A@UtbtlvYAYYY~3V%U6Ikg%+R!1%EK&p zl;`#j@EYR??bV%vF`S5phJdr1WlMK%PC)pue1`E(ZCXx*54W8{a!>|;pv2r=B4an( zE-6O_Qv5Jmp6O04?Iob5Ipb2OBPw--m_ZFq4>Pb^DTO+l zSk5SN7QEKJO;CE*72OOxVEh{?*N? zRVdw9(#JgO?&&dl)3M`aF>feFEqcS71rLAJ?OQS|)I*XoW>q0WRzKZS9F}M_ZV=O7 z*1*l&^)H=HP~g3I3{vEjCcH&}x3X*f!W==Z=7G1iNRi7{b*cEp$tF0sT`KB_9r`FP z5bxZJ9L+t=aDn(qMK)3JTaV0G+FUF{f-?;Y?%Mm8zyB-I_x>(US^;?b6-J&w?c9yy zrhYE{O!^!es*So$0fsxUY$I`l_{Yqxom$*A+#oJHUlk}kv0iIUT%JNGi0n3tN{*FA z0`>ETOIf=YH;8Nf`#-1F_Z)5z|8}K~z~R{-7L>s3NZGq_3JY_v|4W=_glib*n5C;G zx&n8c%SXqU;Sqd{`6U8}_G%_9>#F3p0C=hBT(Y8*gGORiI#&2#`-1cntCfC-;Y|kO z-vlxmWFnmclze{c{jg1nPFKGef=!};ZoTpz`jU0)6aVoMIT}}c7?zX%SFmxlAL*j& zYr_5}oc!a!E^>Zet-zAjS#FXw2$LhAJB{eH#%DPj%(w!32a?+&LK+%b%F*SO93qfF z+Gn-2iTf-8KCeuuu)pqex4P8Cw%0i1np0msGDe`BKa!iA>t{@*nU>M5hTI(B)N=QZ zmUQ~dqSA6x4$8CbWnvja6!ZIAk_S=9OPOWIoVzRy>yox~SJE3TTqx_|!PUTBu`gZlZd3**# z7f0qQmf*nCBB9onyzJ3<@r$PI^Pu38YtD41a{DLPFyDnMPHofAHqqKh{vZq7VT)9Ub!yYvXDK1<1pC@dXAic=%9BTN8k=dX0Z@VB>}j zPl_ZsM&@!zN=p+(g-7i-vN^T-+fh~c_Gh08oa*a7r+nJ`PD@RzjfxiEY#)S6U3{Ei z78qm}P@giw_SY?oK&g4)1(vPo!Z!g1oGojC)&QVtE`10M#EgOW(zm*lJ=62b>Ve4( zVHUToYU=abHWxUf!q5{f5N zQ65I1%-jVjJAdS?*jo802^S<-HHcSgf#$N%B8nA(75F;coU%`_Vs}G>R0Xbl_*P{l z_1z694YOoSz{LpO-R#Znr$7`6s$69nbqXlQ3uh*Yqs@&U{GvV0>Xq2tY%&P$x|A&4 zvAZ2?gWYZSQtWQ4;&^wnnW?)0yW21Iu)FOahuv*a1MF_&X2y#zW%0W~-Vpm#_}=EW z7V=;I(mprk7@Epo)3Ljq&H0;C8?y}cF?ObB_anYks?A1m0azoT@-rNA*SoF?~Ikz`AL+oy7sZ{AdawTJTORSFF?O*}yZtnZo z-MX&rA-W?~!Mvo`KDfJq%B7+w+(?YGb~mxPt=Lz<)DzqC83rgT>+N^L--XR>-T~vG zr2h80w4m>rv(}9l8&d3U_(|Oj@Dr`bhutmu3+!%l2V!^I5QW_>awacWK=H_o&+g`{ z7<)wDg|7f$g^c^$hJ#?OO+BdT$#J~9q2=07$0#`@(WNY`SxZtA8-D{WU5edpZ7Vj` zfxe?cLpkVgRK|yJv1hcCfi+ei4pW%9g>v_TAioa>JnMAQpUfH=zms{)b6< zN0P&gmv4ZLt1Tt@XWtjV^xAk|5ZdW>pkyfRJ7|rJujAWlbjjxnuI_ctbks0B*xUN_ zHhoAJTHVX#1J>QJ!1Upx{xv^ewst=K!VQb5k<0q<+&tfjR*zC&j0m~cVk#Y^Y^Ao` zQieZTviL1`;xcA>86FwSol$cJx8F6sXYVf&)h~x75yoc*>(~ zcXq)8Wq-flB%BoBmYTg8ZmBeRb{ZskXlWA{jQ4rt@7sPU%PoZlT5NEfO6Hcza13s# z^MA8j3Md^r?vb!Y+M>XZ$8pY!5H+A&`{@@6&PTYVeymp7RQ(piEtU8s+)_rs(}IEp zzcTeC+NicGl`btc)$-lziH5RkXN5YNkIkLjEd{EP@mVFD?ckOwI1X;9YCpp*HLDxk zQhg3C62E2MybBQDdggPvcTrZs|$RK+RdhC}}3ZYlhh z8)(s>^;6POcAtC*XsEtUmK~_9_aV0wP}*&2AR90uZNF5H;Nj$#Ld*1NIGa*~MTD(&*f4l3lTOe+~Dsf!jq3DxE#yfgJ*GO=3uDR*6qDmoENkUMome`h+a>`rh$0X+Tr45-m%=TD20ZwcDB&=e(l6z4 zO95xNJAgvXa7(?+j7yo-6XBN9)*}g?98{PHps@M`wX)q(?CU{NlxV0nirrEG7tdHo zG7h&?sUI+t2}2EDPtig@#&f6eORDhHYk={fR!r6$@aPkFio0q zB&i&I00^HKJv=hOr3Gk+KD^Dt(FZg{)WEfm&;Udq_WR>)OpZRBZeQ0laDky2F%O&# zPnKGwnKPA-NjM^OKv;a8?>8AlJeHyl_Rk2kycHt)fQDx!XVSxlh(7$d>bgs%n1lAV zE}{=2vH+C2#)b)WUj1P70XSM73a?%f<2u}WT zI3kTzewmUM1-G8#L_PnrQnLOql26n?@yrm`3lw~1qdwV!v9JU33Lesa2>QHRaL6fx zKN{+80R7exaO)-ZfLrg=tVNw#nJTE^ARK8x89OC?m}A|(WL~}gJ>k{6*t#wa3Q)N3 zWPuxGu0j}6y7g=_*pjy^+iSwD#}0X4x1P;Rt?%L1EAkl6`LxPjNVxU9%y38AZLz(2 z)DcTh$TdR`j(|*#l^4l@_(8WGP-6N-v+Z{H@uomzq}(D4tQZG#o6z{_xmH zt2@ApUzue`>kH!=z1!D?Q8p?It zRT|hwQvHTO7Q3Co6UDDSYb{WEhUUWq2zX3K=`qBV)UO?#+5W+gxAg)2Vj1F51hCXv zNgqAGw)hD`oni1N9*~sSK)hTMRJt5KdtJl0n?HiQ6&fD%U`NV z7f?<}iaxF+LWa$`$L*wp^Xj-PDTgg0x-=?`H-^<6 z3>-$0d&x%J%5yk`&nPt$A&8)gcyzD>-+2I;))Baa<6VeOHn}baSj1$364VNV2QRUy zRJe{(%`3`BI+~@0xg{Z{;GP%{|JDMY8Vyx>Y=`X7CaUW#zw{A#R zw9>njQPpt=q-gbT#E*{`27R24w`+Qxt0r7{FT`N>2u8^;ocCNxg5Dj^C5*Wks_iTV zsp~r8l0fk*Q#}mn%Xv&Cw%kRhO0hnz@`5sM{ciiahQQg|2wfaIrJOiUHEkax)Ku8e z;O+DPNFq#LJV4pJtf{sepT(&KJMfg!=6^E_F2BEpBrp7e$JE!>hX01ZT z(qXuwpDt8+nH^W#zt0vW9tBny>#Pn^{L18 z#{wlZ07+gn{K|!mP85^8?Sv2aWof6r@htnt!SB@W$h*bjBq?)hmUF9Rd*k>Q_73kr zHoo$m;J0x#1BEYH6svcE3$5wPyg1iR8Y<~6N8}SYaNva@C~c_)YWG?T7;J5?c5P`; zKa8%MOUm1F9ZYp?(Yj9UIwC;&m+Qg>l`8GzFx;BVDk}>H!HjG-s3YRy@fBr5FB{N7 z;CL1v%Z}s)GT8r3GEeK8ad0v&DJ7Ao^>hdJw4UjJI`zxxs$~-SKLMU>GEqkS@KH?* zjEqNXwNd%W;fdDY_rT0)9Z`ZoqeIBrSz~1cj%SPJEe(QXB#d#TFkoM4hOjbGuzq~_ zP(ITKY*jtT?SmXWX{_6a)ae1s=@@T+7;I4nNIg2Gg7UULI7=Jr_FWcS<0EeDoJgVM z=GbnaMgL}j&#(#!3h}WTu~4py>n7+-3Bk zY}0kBWe#qBb-RoCk7~uD}&^j0%f=(asc;QdT{Anc{7OmjnePkb6Z%>Vu;Y`Xaetf)eCko|F*lHoK+t)>g zsa{C16@MSdQ@g(uOwZf}Qrx9r|F_9x=hqX3Y6Tvv(~o55wIw@mF#nqhz`2Xs6%wew z5#Y#N72Fo6+{i*6QyaY3;$L!K4HC%ZFYR#qw06W>SSdj-<+BTr$Cv^%ka$mwirgG@{G1(zl|;+X%18-Cx1lBGfH?qg4Y@T&u5a&62h zpNrXpX>fq9{a6I(7EfZYA#nP;V%Q@{0Xo}-nREg!OcBfi%B7-X+_WC^^&km{7~6v> ztYDi876~pdE~`=DQ}I+N)jFrYuoyBk2Dk~2-DWCxU2tK>w2Vg~>5f@V{pvRp1P=G< z^nmlGwYz&=nBG3Mj(B2PR9bI<2a|rQxoT&^Ef>(UzO?MoG81LuEN0vuW+cOho6`g0 zO;4Xpk7Y0E!Yd1gnGD~@rbwd|xx~oGJ|n}-@Bm-S6kw_}s@nBs#bupFnkCOp*O-b4 zGib)TY+ER77YMo7TE)2qI4kSTy+)O?yCqZ=tSIB>A|5L*_R z{;qG`aA$ywHv+vTEh5lF&_cQRqKj8Fd`(p^GfaiMWbCYuU66XB^)B97vOI1c^_Q z(Qu{NA5Pdji%i9c4aio$UA20A_fe4FNd6v$X96^O3uRbCADm(Po3KK%@1(UO~<|r;6&8eNV!?V zOl9?w!tjzOz6#aa=0eVb7XFf~5THCh5hFRcd<6>(Dvt|+;Y7A||%0pGPvtOGU~xQy^pfG79BH#%c8!%Let zI@4wsqBC)2c~JsN>xfB)>?1(lwN2z604Fkjl}zEJ4@GBy(jz#5JRWV#4@75xvhc^f zmV4Qf9}%5FgTXCyiolHW=X%l*Lh*fb56}=%Bbt&nVm=g|0ZOatm=|c3Sj)(Mv(!Pz z9ZYLuixd9-!g;5tQUeEZ#!W_HRS(!Gmu&_W%to zH?0#sfq9D&ooO4CB02*UkIYy*Bj+B_GGo}b(g7N3^qqWB7z%(@+O4)gt?ysRJ(w{P zQppV)o-83pQb*G#IfMZ@d|Pi5GpnPlaxQ3TuW zQRUzMJ2=P)^TCECCO~F$ZzK4a%3ngYk8b6YB>hJhyR<+x zf9teVDWIgR>_3RozdN$K@itB4 zRTKV+$C9!-EUl!LIQW7@01X+Uk+WN(!T?G8c^mQ)SJn%oXaX8=mtz}j-D9jK$iL|k zj7Rm@%T=O6Nr7{v85Y(O6^0TH+*8OF=7S_2H2IHrVvxbyIANBtDr>rzt|WyJPGySETt^yYVf+}WA za%^~Fl{7Tff-z-8RH;XBZO@0%?SYBGveIDqUd z_jI^h|J$GI=to1m3{D~{4e@I;ZhTrRk*15Q@DBT&GPDz)aicq-esFouF~tVOxdh;i zs)*yJ0PnTPNVA33+gXsDk^b3T_2xn)ifiE;Z8`Y?O)(d z$edyxGF9Bz2zE)zvJ>?s^-&1CRJ{uz243J;UV)Ogd~I@MjF*(Fofb)InH_L}@^sa5 zI!StdB|SyI7~~z3rr17-t?Y!NfH-B*K}@5VL>fIjmfZ9HXqn!BlWCp5O6A4*t3)4U zqWzUA3WaFOjua@dZ>IU4zp9N&5X&{&8D1(chcq;m%6)MDO0yg1uYhM+-1^x|9DK4_ z!0`(*!R9ovU=7zdBfb=0Iz6BW9|le3dHWDkz4|S}A7j5RD(imb3k#Ih-_sIyEWyrKBev<%mAM#G_!J-c6M~=Csl1oSbDa!|NA=487NF$<1#va-%^| z(utroGRh4wgS$?WlK(#(ZkU->ayChSbBm|W?vwX?%N-HQh3opALaxpnXdPIrj^=L- zZ!x})7VYQDbXf!2xFp*nZM;B{`4+bp}Gc24LK)Ku7C?ZZV zhmK^D)Z2&QKqxsA4jTFki~?tB_qP&75A9P79b$YPG(cJM&rK=SLyU0H*i>wvh>wHD z;}cspl!o>i|%=Pu^3o_Ygz9v-oW|=vP4{Vk#Uo-`+t| zc+n#n5yaVPcd5kO>9TOp7?u5eJT$h0248CXcCPnemWqQ0C``s4nN%D!Kw)NV4;b=X z;Fi(g0Fx~T7=+XCtP3YZ@4NyWQrvdXtow!|!a&)&36}gv95g_Q(%_@C6)qJAjZK9; zD@HO8jmJS_Gvjs85DS*x5L*~(pfrD7j`B^CIcSbNMhz@laV(VjW@bR$BhVT-k*X5b6&WT)cH zu&J;!!%8(ZQs$c4%vkF{2do2`(jt-C*P8*9(xuRo)Ybvv%mB)?8i+N1#F+trFMq z{sWw)6VM&6H-m1#Sf@13Z(@`SGYU{S!3iF3Mha&JsC<(FJ!WUdyaV1;Q#7<_jhYVZ z%<#QPfrh}NMzJs}!y)xtQ{Z@n#@a^6-oT;MwrBkP--^BqX9mEK#o&X$WT~cTaCa-n z#oc_I8Ah^PQ{eE-rsmBMxu!tLH3%chZa$w}(*?LlF|bG*5>}w_Y;da2w+1d!B2#a|c)4dq%GKH|X`>J4m-YHd ztLPJG*wVGL3s&Gu?B8FncBvW0ZFg!>{*`2%{<2VtPFZfkDFWXI+gQU}>=#Su>~;es z3&j|eqYpW`$4N@J0u3a!eak+Q*5Onxx1ObFAA!?0YC7FPUd|^_NeyZ>kgW+*r@t&R zOa<{Vw<7Pug>R+;dZtc)`7nciiFaIy1;`lePu`qQwYvo!p}sKVZeNZV+h6dA&Uxw0M`U@(Th8jlk*4XeIyY8mPxP$sY4=7c(L zb1DlCV-$KF!+Y=7(_$2Ip2mCcjIyiND9OXVq!u*9!P|suHyIhfGPU8CNQ)_GrCD>FWNb>VCGvdo1aVGQ*rq>JLWroRc zpYUUBj>HVHWswQ?AD&F6r}Uh^!@d_Y#}eteks)34Wbj-U~LN@H|LjhB+ zJcZH$@|WPiBEbO2e0V`-+KbGf$j{@BXYgMW8PeD9Gyc9%KsFcIy(3KEHIWADB5QOI zN2*@xCNRiEryoQ|_w64tfq@ctb2uISGK%8?dGE>M#|==c;Ezp(GxhKUvTXtzK0!+0 zFf)A3B6SlODBLG+f{fP$_Vfuw>roAmsdQKZ6PV0r?Lx*(l1?Tyq!Uz5q#12e+MwaG z9%Qy7rjl&}1Exh9nd2>8k?h?JDTs+Ir zdd~y~%Ei%%w5qPhY{1sEPPZd;#3;#dMDKudFzBF{^HfY=o66WJ1`^@Chh(E&RwUv_ z+GKdBz4>(SnZO|Pv($*H(kDx&^EH8i5;M59S2R+Zz=p*zli@z4ZUPHk-WwTG?p>J6 z))^ZV8M^?-PQgLe3pxk><3zM?i3?vr>)^+33R$jqX?opNrk*qsK1r*kV9ciyF5PIR zav@C?IWEjm}Ro$|Wu( z`~6F%`t}Y7jPT>RqjFgd+Uc7pG+K2E7aTyt_8W!i7^~oc-{}FeO0IeBtL6Po{Y_iG zZUdBGld4my2H1bru8gcYvcZpEVEKK+rT_k4aq;2OOTVFu#&d<0|Lw_|f`3sg9b{TZ z43(|iv)V4G*6XqjoLbW}=_UPa>xP0#f7cipsoTiH{NIeXsEu2{l~X%f0wLDkc{#)i zDj9;~$x!|>RAHaEn*023w945nVu=J8Gq|6~&*nK`aAYpr(BZX3q{IR5MTKq@Wx*w$ zVRd^;YUzXEyiXl?d^%sKDcFj;*_aYP?X0uBS#cHUVm1RoP2^JxoYm>7$d)_jlPnHX zJ$58L&iW?{%lhD(=>>4dIW^_w8%h7Ufm?=x)X`|Zx<+FYNv<`cPbj% zzIEX&Yb4)ze$QJR#jo$i(YJszD90ZhkoDbo7Qe&g_3)z81WMFxL^)I2ctil%roz|z za(tIoR+lvLx!z|8GRzHc8NW5bnd_@1xZk&9Iihs#+Pr0e%&9WyiB~(k8&A=ae0d!x zO3NfZBbrLW6llkq09@}oz5&GxZdZCok^t7aO}@}Vr7_oB1}^Atia;2eI)|OgS*mo6oYVh zX1$lXy!ZRylow>09^XTS9C5$z@2Yi7^=MBdc>cKwXRZa^tuvPoM@s2XoVi{d<}=qX zuutFNKP%jHaWm{w`^eQ9M=k?Kf9H@+;iHhANM|lDsN6VAF`|*3sew#W3r}`<8t7-@ zsAjiPbs!%qbaER--gxV`W=hcLVgNhXKPDNIySL$n{i(d^D0gpsXFF&=p>xRPS|@ja znD`5oWik}9`yB@G(;%c zXnh)?-*X8buvRKyn5T6IwNhMpB#4WuaX9mCU%ReWV4Y!ecY^o=G5!lX!^evg=8V6a z(D>V6r|?W(Pr19`SAB&>7_xlZG-rb7nF%f zUl1R3qm#cTo4>1L$9g)sjyjpae|=|M8Ngwj*v9UHO^+WHK~5A}=GV#Kb}ZVCf`@34 z)Q*8uad&7h&U?#qbMhcirgqQc<{_XhO;QWLfowBX(J;zw?OEOiCR%yuJhwtOyDXx8 z3gRs4B}yC_bo>)Xa={Wl7aH&#AF@TI0&m0bdq&C*rb-N|M2os3>BO|fQIU(VEub0v z_N(c`s%XeW1F&DxEmjR08m7tvKpa|B`97MLDsx1mXRS!gQIP*Sk9O=311!V@Aphb$ za1_m+7kQLHl{Cd9?d2cwfjIdjp#dzqspGzL1Qy+P$ANp@U(up)MR`nB zR|+b)c85%>ELB|MN^d zLGi~44C=`P8&iM%*d{}%;MS05y~=#x)JuO^ zAF&Cz75q$6>1P^9nL3f8{YNlDe7F^ST~_Jq8aOg_;>aRncgL-u6S7L3(9kiLP93vQ z>_H)B;2@%*uudN$yvOp zIN6}U<~rl=Rz`h>BuXBX-_J~xk`D^Yp{d$~A|)RbCLk*YerH;v0$NBa;ZYHT!hFam z$5G$31_d0+$p?kIBP-~G%Ni7POtuDv1jhEC-4QY))C0rQK4_}#|0_{pDh(lU(rdM3 zN1hh7WaStx}ji3O3n;Z zkrn*bZ7~CSs6$B11RMUNlPPuPjtzDMj!<}mOtN<0r=3IoIbYn3VC`+%z5wRl*kTi< zIgmyJtaGlo?9=+ciuI^))?!~|{8k{N)orx~`^Qd9Yxo#P?`qH35%_BYfBTK~?YEtA z4{S<;qr_Y;iVU!9?GXu%>{aX1ase=L<3L}q?nKQOIihVxU$A9^9!TrS#Wj)f+ni%! zQ4_@r_jnj5u!H>HcowvgUGVVqs0284xhOKgTgQ6)g5OPzPH>c7nw3^^W*h1DU63Y@ zGAQ6vtmJ9pFVp^n2GkwJ+vKBBBspY5Cdp7&wAq2|gvB`bJXN`JCUB;9Z=B#LHx6a| zmyO1yfG-vuc4}WA!li(yX@>=wLaUo6I1=kuCG#Dt{hMb`X(xmn(qGn>n9AV)1(?d9 zig37H{N$ih3mS>CCSEG}4dUkA+Eu0k7G#xJ(3ZZ&bD!g{>=b0UCtnpgBfJ9C6Kh== z--Z+3!Ee821@J=YbzCjD^HW*3`em7UPVLMrEGvI6n=h!`&-!VCWB1!GrgF^4;#Mby z&A_=?>u%sK)g%cb_Hy1UPQM<}WYPm-6rc{59#Dy}CI5`bOnf)78+lxdGuM_J)#a*2L0GzO4 zH4_k3{>P;ZG*RpA-d`J$_J0R~+zrS66kqy!a+r6#O*LxwTOM!t3-OmV-b`iH#7C0y zxM^0mIxpV__(qy^mh=^q*9#P8rtI2JX>G(JbfBWKE4hmZ%y6H!w?u`EN>B31YV?bt zkdFhEO+Eg`FhPdLqi5cwl2U#01xc;fgAac82x2-VZP&hwl0IwPI`Io0{=8X{Otps7*3QQ%E)?yjSGDFC#klUEtUX} z)Gz1~a<%L(_xn8rt%S~x0$ho z-bhvIfx|sXP3rqKW2pxU3LKzPPjadMVkM;h(rlJ`pmcEj=1wW~N9%N#^hVEF=oc7W z5T_sJwxs@S45U7xFH1dsyr%g)w^n$ z>Vtc-)T4n%kfr|VaY+4$@htUd;NfSfzjOvtAGB3Sy)E<$x)|0hveX+tLh6GWq>y@$ z@kq5L^(+A%so&ZqWW^t=O_qAAomWWGZ(XeVKzY@s(8uK;IDfBf;r^KX110j$_TKsM zm4C?NheQeO=bxvHBRiU9@9p z;Y%_}wn~G_o%HD?hs}&zwV9E0n;FReko@%}9~q;b&`yTTHftxd$?(cR`w|2uq~0d^Y0~sz{wE()a78g zrky~goj{wP4q+Br*DaLTH^p2Y&Lz*DfDP8#6KpE1V@Z>cipW%Gcd)4#HaA{fB^E4O zQ0OX9V&7z^RKyQ%P(V4^1U8y&5Tv52HkIV6YWVC>9+5uY1!dXcE%%x)sQyTOMnmJp z8DvN8e5GV1bc>2inRdsW+Na+IyY>3Bjti90tKqJ$Fm0tUO={=MOtv3>%MAsS_K{@> z@LJ{)s0qX{lO`D8I5wyeE;xHa5R~>*hRg5|R0K=PgN?OE<^CwBd%lOH@6Xm>pv)TD zPIg>xl~Zi2yvwsUbJ8hxJmPb$pTc+WUxu`@vZ#2ltbSG(F5crt(6^@UXw4a2z==)| z=fV2LV+HGeWgrdAD>ryqZ&qL>v1<2(L1CkU%DIQ*W!q#0_~-|K17_k{9d|Qq*kn{~ z{o=l)tx~VU{`oY!J#hV+jgTGtZ&i?$jj@$XRgPW(*Kh`8T}+z3O!U(;FV<3{-#cmv zH~YzM!c?t?CmsYRHYoT67?k+P!#2PyeoqW~hj^U}oB>|=;{(}|_VNjrRy{xN@Fo4q z8x9(zJ&-O@VMp} zc>IN79st)IfJGWE7p8QHxue84o5>+zj&Ikjaw*sA(-l5790|G!4@~`sj^P4j>!we` z9O(wsHkE@HafL5&Bm!(nEpdhKR4;ax zQV6>N>j0g@0Io5cgwe9#wtmK7+}G!XDpOCbhEE?i3v+ZWlTlV&0Vpw&%gBn_PuK2N zlk{ST{Xk}c1hj@!z%w`+O3P+gGFgMTttOo0w4ElB#m5RC|W`wdTBpyJrL7@Qv z`8PhGK_nSl3>hA_=o%8!b(|0jFZfsF3L=TtCk01@IZ}YVUieej(Yn0Z=r9L?)*)$3 z!!FcyG@RM}TbQF_|IBV>!TK*`weg1hPHnZ(7`I%_s|5v4EoVGxa(q?LtxU-CR#IKh zQD@}-8B{act#Fn%$V_<$6gmJ~2S2*0V6laRven=N^5_KnkFn4Ad>8A7G})xUd_R0$ z8xD74QrAFS|3wG?M%y=yc}Kxw(@G2PkECo3=0qZHAO_As$ZbVPBhiAUJP0t#w@ zBv=u+s8^FDwe_^Waih8DYg4DcEGp5HGNC3do<*%;&17KNU{)6s4@PFEy}~AAbiu(o zIOA(cEf#zmsh~9>4_A{CeVKVyGM`)N{h$!ut5~ciZIa21uT#ja4lR#9QSWr>oyAP!YH%=LX@={uV8*nVS@j3pe%WW-7ASou z{7Ub8T3s^LN|inpD*$!QqJmsMw`XJ!|Fefi@)??>H@|xa*t7-R$oP(!8N_TgH1hn!x`ciDBFxa3%m?V>g)$4 z#2kp(22SvBFe6p@%~XD#Gh0$;mRRJ}&j0+#)VrKqD98*<+`yNaQ1xaXO8vGOi^EI0 zT&VOrtyr``;W;R@+Rtrm+<0M(#mbO%Bzp=RE%25g(?1^`G^srbmyl}ZK-HT?pK_d< z81C~#Fw@sP+f?HhfSI^ik0kw^W-~J??76o~rZwAaPgCctZa1!WUyO`_p>bP7^L@jg zC7lMz!eNGKSS_L9H>N$hwzDgqo9j+*@$i$oHdrC!UlMc;Af9P=J5qp*>`}FSUFmkF zu{~8?OE|!~2AqO1Gt88_22pU^atV|hi*R>~qur_N8c@bg3G|MMq}cPA=3*pE=j@2nD49FzODvvV(EU1wU`NA!(xW45L(Q9b?vn1 zomVL6LEdCq2bAINF7!HKGOdGXnYL&FrP`=@RJoB>39iZfp4I_p;g2Y$lS1pFFGK5^ zzh*%PN^G|he4ptoX5V(jF#awjt4+6HoqoLTp-YdeH&&4OSwim3tz*|+ zO5-Oe{@1Q$HK%s!6^j2&ALtY)(UWi;1@9c2%AbAkhRyNtPn=rwsv}LE{<4@Uw0a9A zgH0pnG2GNUpOzH1_1rw=3B>?6bMt@<9&&!x_2A(z;;*ick5rQ3l?OO-mIXK zn*V{!zjvML(u#%P)R)FoSZp>;*P&`L<%;77thBLyq*rWCt|TR37b> zOm*9tSlHjUTRUWZ*p-oj%(b7oQBKVuQ~CP44W_#P37<^x^;s2nj+sHZyZD%)cIrSS+oa+P@Tyu_40aA4F@SO}u9?Xhs60I8#!*%`t*|Ro% z+G)+3ssYM(rCF`pe z`HPVmlmqA4pCuHj7+19s65%xnE63G`lw2m5F`kv|Ln$p!CFQ_6m#H4e2I2B2N#~wW zgAbT|2YJ~wM7fbE40(S`w_CevV(~R%(#2!wKry=D?23ho%DEsKck#}AoXfsMH15E_ zdF=lO&f^pJDP!+XA*Ihs{w1U|qQ(_s)F$)xREV9=;6InYgt9*%XrVAOc=1)tGO=LI zGO=Z$oF0&y>K=j$v7jCp=$MD<9}62Gy88PZfiv8V$_#ZkOj&uMzQe$m`8V8w@((eJ zSqtDN_%$B1q7L{j(8Ie~1A_N*sV6Y?xPlxXv7;x|Ci+0>vMnf#3V54J;A$j`@@w9e zjDe<3e_1HSGT)F%&5dLnk{aK8Qhf+%;3>44>L@L`-C4O zF9bi*TnW*W z{*ND&DW#Vj5||cRk_<~WDpleL6L8+1 zs!!D{LFVYEkPVxRq-Sc(q5%|~Z@kPvEx`f?6s}TY%VLJ9aF@K&0(!De^n9fyqyHo^ z8Z|FrGyvRw6-E_9(#Xo=fe?(m4wV1&6%3%vuM_TN0NW2rrxOFFJry>Uf-#Mx56Ff1 zDm_dsS#r@Pu9kC3!-Ms+2B2+A103HA#!UJ55~LrnBRvXu+T-s#`Sfjc+5QRhP4Z_+ zV#i8-kag)-!87^({oNW0uUp~Q> z$Ue7L;Du?^=>)s58y}k&b%W0|f+|1sp#!WBNFEY^FNd_|))XM!^I;M=?{z~kqFn;g zcpF+#V?(c0=?QfbEmhj}O2DHuU&%^T?L?>g>eU{n_UqNsi1|$3Cs62x9Y<_8)Q#;{ zX0W9GbrJWDijG3X)X$r46DSXt45P|+@Na(B&LyeCrX3Rv`CIo(aLmm!QqsED+AQg1 z+R}z%(1(MENRWf>H!o-`aU#xRozP1 z+0SKlLM;58@tOa2>1h_Skpq-_E!xvehFe>hp&l=MQOwiJA$J5bHx@NZKpu2uw=%j1 z43$;mH{r#;qK}+OycogmZzOld;Ao3;{6l<6DVV+poi^Az0a6yEyey-+jV9m2Px|NuZqkP-Sn~l5X`z;k9_csc9NX|KH8kg5S^p zDFL^^i=)KEKmKktX&(6PS7-#(Sm7NVAF6SsMgr2#H?roKYKCY8XRYleZpV5-W_}$x z!I8x;H!`=3ex`aZ^Fj=8p)9iQ{uSE`uTlt^t%na4 zr{X<+!U6koNEc!Z4K=RhPr$hwQrT%g9IzMW=SLBh{_wvxP4}5ViN7C`fPFfzTiIRq zEs}Gn1-E?QaO<*!9k3u1+buUSSBrE6%EH7z~|CKjhJVXvmYe5kNS;kS}Xzttv% zqqq5!$c8sO-0bg%v&*iX@Oh|pZlRR_W%w8OpZP~HWA{lIzSI-TxS`%zUoyIMbEBF! zs8lKsmq+Ua_(KzGz`b~Gzulz_(N)|iLUPVjzAXdyV(xY6kerxv75s~Sv38%@Z9y2_ z?vtsaE*bYp^6693o66piF|CnV5d2!wX^bppqHcG!23R?=E03wtsA|ZF6enj=<3oU&P>T8#qNS#<)>BI-Of-R=kv? zjvR_>_BV3CznJMy4%7gJ=YSqHwp5C5r?6ZFoLwN8X%n|aP&r?;EN&vMf_k5Rj8$z* zuJHmTG~l3@88~NcZX|GHGZP+r%-bhZ<=G}p(5ZJ;x1(10u z7K+U;o8H*3cA&vy2|evb4=Ceu6e&tF^*~FGm7kcb9tsJNN&=KjJAlH@m=xLp88B@b z080BHJc(pWlBB+;9Yn<-pAM@B36Ld9KI-9bGm}C)9*u@}>Qct$YfkmGVEij2b3CDK*e5^QrVb*a;Yeo;qm2- z$>5#ISM`8n_vu5bH(#K5RZr|#Xh?b!9QHBQ1Ipe;NP!URq5<>fJ=Ft_(FJVU(k`|v zNV{oEJ5Wkg2&Bgjuw#9@20Kd z_D|1_1(dRD;qkQB`cza8D0t|Q9G=+AeReFvXUpa^{P~e&Hc1i4AbUEB(+5zWh31mK^K|qT@(w!(WM33JXZJ^iWc?n#5O3~6-dhw;u0QlIvA;|ZVFMv|Z2`U^A_Wu_FVHyt_89e{!8JW+*zzoNOR~rA| zbVS2S11ww21o`iavXd{)h~9aVFFrYPp8A9aNBW+WY=bcHp`AD!wI7UNXN@m#IHJES z6!T{|KWu(e$-Ov(^=EZDaKn+;>yvOgx>g2}*O-ymYJNV;VPJe|#Fu@!Sg)y^{vF8| zx#q)DS11n-M_bEBi!bpUcw>Xx{E;%qVl`-ZoIuH36!(fa3Vd}2jJyWb5Ct|`halut zrXotM30%dwgF+_6HCBMttHrM{%vhDbNSI|Z=X_0z5tcA<$m>!42n#Nk&%2x zhWSNuqMdxP+m=C87d9wDXF}I*M}?%l zT-_o;8tw@(qv7_estHzz*|@$5G3Ft25VlL~ff)0N>FjL;&hf%!6Ra3>*F1=M7JCdC zX<1t~^$?Zi9w_n%Zy`C($LQ>*&}Ld<&}j}$2Pvwlt$rBZ~LLH=Ac zrUWGhP3^y32r)+)pK^>DE!p?NwVEQvT>MrIQ{NQJF=m@LZ;aWmj2&Y> zu#;V@K&ieC17(Gn@56I@qYa$!MW-ReJS=9K;H}U4ca;5x5Oc1l84S0YJ?|L2WK|0> z=C30uBtX-4)rABj)O--G&-Y@?K$(^O4JB|P#ys(#cvOwQg@Ni;10m+5XB=V%%A)Pa zkmC^Z7pD+nUa}1#<_ZI#Z+{&BReZ>p+MOOQinA9P zGyr=^^N&-29&W8A+24O`cbMLXJY)be`+}+sCcW83kFbmNB))qH+UfkteFWID0g`Xp z#2L&t;Q#t&q~bv~IA(J+ncOz^fr^cN!Avhcr&1XUXbAAzx)U=jn=0Z{e8h|d0u;a<`mAv+f(Wia0W1Is4) zf|=`{ms7C49Bg0B@AjuA>2HXsDl$5%u4^rR!$ zzWeX5Ea{aFvn>IXO{>~aNE-#FXjxa0hbl}skr4ruUN2gOA)@@lAlg>*zLtmU)E2alG%MWzO=3VJI0h-KDe( z&o8Sxat(573B&MgVp0(sC5P0^+ieMv@!1@@FcBG_Nqw@Zl&Apz@{y?0lG=3j0PG|| zuoL!g8zfMe1xNa4B0=Ba;&uM?W9}2Rc*W1vJ>=(O-8}PXgF;OJwmLA-6Hm6my^V5H zOaoxpBb-#k;sX!{>3g8TqZaHx4yH4|UBIUElM}}i0$l}XQt)|icQ&2(b;l9wER_%s z5$;k^b`K3V7CohR<`5OG)as7YdPa*wkm6}Dpv2rwk6V>gT|Vu%KclqmxN%Nx*sqz~ zh8|vj91RU{dWK@}SUankq!jDplGM{jSPal`aNa97;%T)d?VsiwacQezJMjztFmfIw z<@C~wcsB7^6*#t6!KXR)D8lkgv|tPtPkt)2a=_=PHSnquQl}=Lb?Q&9R|SeeAD+4E z40Y@(MWq_ZaQR0H`x#G)3o_N$?IFkZSxNaLYh_vORzD|f&A->V^dmPM0%dCVZEn0v zxdnmmJqR2h_!CcsZm*64Z{mR^d}v_eCO4HfRloNQ7{ zQVvI8q{@tW9IB;lm;qHK3MSF*1&|49wU<`yXHF$!%_~l|2d)z^JO))St)qGOyYDjUJv-4VrZKGf7NL>YYrnV7r(x$)>E)}7<`5IJ5xGRCRtm#@3@rDlvk8Segz zK*1*5xgyXgb(9U6%^eohrltF@7KPH%;?tJF5sXZemf`!HqC}vPMB8UIJS5R6s0nb z!}@!izoa1JSLTx2@%=4~6lGMQf$MiMTxm~b^uNj_E3ioWF2G$UQ8XDSEjJBy;~Azu!~$^Zm@%JrG`pqxy62_^ zCLB;{>;Yz=RtEjbED;+mz077cRI1brS2Af`%@>C4I$!wKP_1mv>XN>B^Jbbx{5CY8 z2FdJS^i8a8SaifE`@8a@I1RN}-z1njW_Q=$|7CZ?qT}gRh#bV24JI6j7a;#81<1&r zjpJSSkf_@iUC8`FM4zSF8#qM#eKBWo!}E3|4nx*MmNqkG z*Wy7UdPzX#M<0(YK*@?aIe8@j3inBzP%x_AQhh=mfKsL11t%sORBr!W%&pRIHLCq? zKg|i0K}L=t^vs0CO)AeM0O#z2sgkEprb<1rB%gX`4c;K4!Xx8-$MX3WTwbOzvQU^A z9$!4A35$%L=EOUexEvxLvfSI<_PLDdVfBtxiDhQlBX~1t?sQQx5-9W}6)Yxfcl2PS z^#bL^Yq-3;Vg@gxKxrTJ-09(5QvV%nirElPM-mk#bG+~jm-1+0l%!61HUjA>QCZ!3 z@u4;u9%?*qB^E_u0RsS!9kGSpflRIM$I^SCpyGYUvesW&WxaVFJ`w}v=zl0qW{ZZW zMl9kFI`QR0hWnKIJC?#0n$!a~BU;KV(iSIT($R4KNM3rW?1OR)6u&YL#BA+eYNRH} zz$v@-w0F`a)ho!N=A=!A%0yFnVNvXurr&Y)lnrGL5z zlr0T#BOvL`shZYf-~}gO`G@_5A20lIxXiCSX=|eXLix5goQ{Qt>C^g(l8AM$QWc8F zFh6Q%ggxz!2@_O#BD})E^%;GI15}=WU4q^sNhTb#mq9onY;4>EXF^B_y*g|y93JWL z3WrUGg(D(&R=kN0G52}olt+P?Nlk4;6-m2Gts`)|0v(Z6gLqPT(DD}nvk2m=|9R9g!*OMqC&{r&&w0SEs|I%@L$Ngt40 z4*(lx*~P8CARbt!-36_aYd@u%5xj8#jO~^&44`4dY0~_SE9-NxTroDz0yrIdzEr9W zDtdas-jN8%A=)iS^M^~dS>+2daMAPlf#gy+UfXSP z&;b$P!x#hJuL&XDXvzR5ZcO6~ZY=?8$&3AT^95gU!T5V_BxyFMQO9q0Kjm zDx8%3+aUivJ#636u^uSF<4B-oU>kmR4C~Lqc{n_J;1Jgr0SQRPu0*A-1mCB6gw$^i z0}*@@-!@pKT>!BSurlDhSS z{Zr%0J5woFwkQt$zvIHipy_zDEv_}pGRA3Dy(U@PK|%r&H?9&J;g_A*9Rf1NZ{9U6 zuWsp)c(kq0)6IwpA| zg$JADtP}+WC}GhO6;54bW|$1N8cD&A;dsGsH4v0^B53i;%xvp}qxinuCGeEu+pWlq z9EMliitOI#+ogLgK4W<^(x}uEYZnt2$-(f^jvZ)jacg11LOkR4)h?K_^|#^`H~P!^ z(xT6YyYUnuf-AQZLNY>lGIGfiZAP>XIM$qDc1Z*OOCS(2&QSjncp9-cOpWh>EpAIx33HENQ)4>;`Y_I*coc#6}NL8xhMfpa*p|hs&1lm!`dBq#jV`bUz}Ql z7B3Nht2N;l@g*J=uLKlYjXv>WL4R4yY&;G!D4q?6$5;qbuCyS-uef=s46Wb8jr{xF zu*=?|yv5|^U}oK%KuLG*<*5TRo>8UCkuYAlCmwZsLh3enyRB|EDD(^9m8*>;TipN_ z>)Vo^Sz~nrI3)jTy??n z;vmZ7QBb!%?^386Q1p9)P@#m>jo(Q8P4=jprENg@_T(>=jPca?khl}9Njq5GY;6Myk3yW`S#aM|H{c8}KbULP;}%CW)UC&BL~MQ44JdOCuazuy>+}lh z#=7sTZb0#js&xS8jtFgo{W1Q>klk@R=?1GqZ1l&hb0``P87pMC6a!?X^6g5JI$=Uz z6lrXTDs27lu;C4q+#46jxRGOJ)JrPg*6=5y+#t4gfVYmhsSXcz`V7>{pwVRo@}GH$ z!8;}7EQzvluR!U&~?<4!lO`gJATXGoHg`} z)!+kqYyfs6&%y^b%{42w0yINAD!8k+}?|0a#apC@Nzc@sK0+erS!KSnqREZOSskf#+zs@s( z0{=J26w45ADp|fsE32cfAu$33O`Ql@WSE(PF|SPJc{X?hX1~QT_P_gqrrxhnfRL7e}CP{y}kkt%0e??XdgOX1$ z6|US*J<*(Ve?ukJyEZeh;KJZk$S*4MaQZvSm;Xqn9Ss?;OaLc*$w6@ko@ai7s+ zY`Y{ScT6E!{dOy^!5pcKw3ORL*gFrD>HX1TKE^CAfWrL?%0vkAY2vHUlW4IhL2N|a zlk`_}uZfn>&k@&IJL?l!Db)^7zYhtxj_`4J6z;Ei`4V~I?A6NOf3@i1^l8&vm?nT@ z8kYD!UsoL;#qq_l1P>4_KyV1|RwTD~XmDErN^$3hCpc__YXeO~a0~7dD3;qxaQEVb zpbf4qMStHnGkbS2`Ujs(=iS?x+1Yt--uupXY`8vjkzL)H3H!0u(({dydiA=2O0JPSLQc_mAB?($Dc4K#m*ignfhVJLUvB}Ue(A@hE)qk zruYE(`9uC?VF-E>4LUVJj;XoNP#!-yL3g5sny{oaL`^fQ(3Tjlu)`bZmhyc=b+5dC zUfhSC?H|f~^aDeEe8S2_=c9k{5%HoenWD{E%YYO(5;i{=Ym%rw-pY4dujsHM)?=(mQ# ze@o;H34d(keir?NFZ`qi?FmDBo=xoW9lZYghIU@dZr8?eJ}tR9#w(&ShBLdzIo|E_ zLy_mk-RMY@(SE_LNc#m8TNk=Xxo65X>&`OEys>J-E6~94J|yB?MPRh-y!bQ>S>i;+ z0f#^b=@L#+HqwAEz|(;b>Xmg1(|_fQbQpCoKa zRWWr0!wxE%WqCJe zyU+-6;E9lY+@c`dK%oIs%YmlYFMy0mXmRILG8+@>12EnQJy}8}$e2A58&5{|!M>$} zo!Cka5roWXQw%jfR{*9j3C9Z)!49lIr34%=O$P$f*WoAQjhxvhP*wz*gh~RZ z2sHL1vi$E(d^Tk5l4&FP~p^GUs@hEgErqNo9>5HTi28fuP4pnxp%tc|GH*2E?OuJ+oH zYiF)3DLtpvhSnzqfHGXfQqgEWYum+QI2S?dh2lDWym0U(p`}A@nXV>`F=Tz(g0Y68 z|8^Zg=&sb`6xN>*%jel~>{%XFx5X_1l#h z?7~C4+-XoQt1@eK1B-g*z6M(9iUC4oz@c2kPgEbtcSl95()+UB(W18g^}1c#{6{w- z)9uj(fAqbV!6$3ykV#@}5ioMLADdyoe~?-8!C~a#e=h-7kMhN$#l(u6k z7PxEyJqaQJT@Yav?~;4oi1cxhE(iKch`g_|$PG%)1Xkg45a5|+}sh{I@h-lwV0+KM%B_W$|{EkU6^2G_E* z`a8QaVp3C!+GHa}hW_G>(c}Gs4c?k|siqoA+&_@{)CWkhiSru?nS!1EAoeWtHL;Ol zn^sq!hImgla5tAjl7nBSaquTa)}I50U+0rTeM%VoO`fal=TJz!>RnjRAZheW)0y$~ zh@`HSW1v3a+X`wdRFvsl%Zdy?k~hgyV?m_dzAjc^b5f+nf=KkKFkDNw{urpS9_wY2 zp~iwt!`U0G$mk}Z#>$+xIBwv~Ezz(*Bp_~=6=&$07%5O=LFCEjJrr12M4u9{IWB6f zak(mTEjkEGpk_qBiz!iKLCt}tXv~;+VAhhS#)3$%y5W?*F)d;eYAlG@SBw?ZSf}#> zw!CBlV9V?E3cxMT{)we}Av46gCk3Dq;g(S`L8?HEQot?OCEW7-i?{`gjlw^rWePcf z8q2a6u;tA&0b4%02(aa&dESVDVr_FR)^5~T-iMhjhW=sxdx=LXMQSXFOnr8ea!}}E z^3+%m!O}&|H(|>rL{QQMNChH6p=YQg=?wYLy?`z2M2Mws%mv&sk!0~cc~t=36LE`r z@|v1}_(UoIsVIHmJNO1s&Xit$matra+D5>5(2X`wGQd!wcU8Ly-9cfD9dS<~MXv5jd;Jp>Q%CnUDPe2^Ld{00z?{ zNU->J-br)>kv@I$Gu9vWZ4ixFtR?)w&48@bh<%0dbJl7X!;w25mdjZ0VHJ1ms`K^RJ(Wj-vZzc5O!_5;eoeuD!XDokJ#TNcdJn+lL zO15yXyZq^_rV0wW*si}F2Dk%Wx$yT=_ow3&Na^#7g!~rvz9)@aGWYR(h z?$o69r!Ou_s`8WA$P1DxRAksPjxJg+2bmkKrt?^X{4Fc6#!J?)U?D25MS$d}V5f$X`mN1=Nt0sdieH>P zg9l?@FUj{U*k(OCG$+vn*ia!A3%oO_r*JBvsIIb+j6t&olTcGOHnkH7-@yqJ}-{ zXJ{(|i;MPNEG84F)*|tJ;Syb4d|-k;2x?R>s7aN|iu^{hEL9LWITDSbU04bvRS+pR zeGmmjCi}~IMh~j`xju1%NAgpA&5ktz^Llj64_H=se(+pzwp|gx9woaIi^mM zl!JXnI$5e192p`T8c!phBKRuIpV^j}q>7#t04>DfA{VTOI6<$q@cRWxmA*m@&GWVs z=-gO9N-R}Svu?@2XyEcxvB6{6cou#UBvlYu{;C6==4z4>Nfktb!&(rdIQD>>X#Oe0 zO_hM93Nm}&HKs#KdlIr#p<+xt4&e2wyB#c5%WgPHs!&m|Q%5>`hfG4B6%%n_u>?TE z#fE^S>ULEm*x3|1y{cO@=mcOzbE(fQip`^|MfKG$18ZFW8QW(;O+XyFco|n9B;F?q zmMVx$eKwkAqIXIpRS;>n4`UfO_KGkb*toJ;CTXr&#=e|>^Opf@oIFbv)Z921NU^uU z?krU~+8niLB^ojO7(_bt>O&`Y%Np{-svxPFw-Lz^cakcIgv7Lq&UbZme|xedRminM z=41PSXzcC}SmYw#Jsb*gQzc-jf{0gzM$uUCerKN!u~ad@Ap+HcqzWRPLz+e-n}gk& z?j)&tk`^RY;qO+7cMy33?+=?)CrOpQHz7+E)Hs(p{tg(_!?~2M9gcTYJQ}f+%CwZ4 zMf-|V6jnv?P~cC|aJmx|;krUVKiQ0XIKw9KJmTV|dv7o_z3Y?`lln|-kZ94@|D>`(>_{GQa!-55dmbQLL znk$g0(Pazq-X|JMRQP8K;}z(*S!8{1cJ1(R#9n=!Ju{1fP~jO|MszKD6}ZfTw)-aJGJ{B$1G#zE+(T; z)$nGqqI=goJdWksvbx_%i#qsTafddo z6N~3VMD^P0j|J|MB>#5=XY_aI(Qy{F>_9{nt-V+b9WvJ-h_foR~650yYvF}}-H5EQ;fRPkQ!E21&QZ%wx%sQA^8%Qit!@$S%9qC!9X z0ej_-?cW*dmeGhRPR&4G32DueMj~=z*r`Jc5LFEBBU@DKJ46+SWN0l!SlgbrEiJ5t zFuh2SA{Z$|(y0q15OAh;$fa*1s5raMzZTUo5JAO5XIZ*k$CL8j07m8Xsz!D>e&8`f zDgCvb=oluX#FlQ=eiu>2)^}ON6Tev9s1N1H>Kk(E0*ET+ehpLB!$&nVV|`EYV6cu! zXg<>BYtAC7_&MDe94_mJpyHhnhMa|#1r4&{tYw?I>&Z@Gm&Vp~X3*=#o)>D4H*Zg@ z=F<=xPKT)Ch@LRkT3`IW$+7vT846A$VWhSosyH~nF4Sym($b0@ zRB5X`=@6odX@?oWC9FW~>{fL{h&aCuZamn&iIxR3o$~i^pP9CFR%WJX9_gvHlOvga z)J%N_mM*YR15216`|R4Q5w+~zvW1~VE#FM~A+lpQri4sV1K$>ZQ!9;~fo%?F6RUDiL;LoD%I1`S7UCLor$ctJZM6Y7(} znlDYc^dkFyEn+B*877x-iqV)>J@!dl&8mrrCFc4C;nDOfF&^|6f70?-qa@y#unq_% zMzrW_QTuN~C^2A5cM{Q|X3!I0*UUZ{3iX6`o#40#n=I4>hasLDd19|5NB@ghB70KR z%7`Vpp48>QP6A`${kDQ}gZdPP~3)E%)N&6uE9 zacB)MBlOHH z>6rIH6Pve905%{pL3+i`Q#<6&FR&HJtLMalq2sBMGaUcxV(}#TK^meBYU92Y`116Q zUCS(Q6C!MsU8}N-uNLQK=(|f>GGmk{FU_S16+*RCxf3UVv|#Rw&+uVN|g!LgONG-wlx5t7!P&)bKKo^ zr8V2#K*T>&F+QqthK8f<%JFJP%qGOPMh!w3hPwHtX3=h(WtIUyne3=$<8N_p`CJZ# z-kn;eV0%fU_sQEwmY(}x>vl;a|aIm55TY(v6Y=KW4TVNAu z(eb1fwMvVbx$yTxc7>*+`gKqht44E_Kgl_(`Lfn;K4!K1viAE3KJhobF|)+tMWEur z+7h;WmF_&mt;T7JS(TyN7XjN8?Ted=HZNnjM#xmy1&q-syDnz6iTeX`=`)-75Rqyi zHbuuK<=@nwa06ig@=GlSB@t(k_rcu8Sg;0tZytXNOZY;{;&dg%k*S5tuzL`A!O8hssbHG2jift~FWlD+P(CPc19 zAb!YP&5;?Azux{^94=7U22XRv0%r3e;yqb!Lf>VIt|nxHLYvwWyPBJ~!qvR%$6QT_ ztQp#df^pbzxLnO{UEylZy~nkXIkKD9*TymscAJNttb7RKzts%}WGzk{pU<6{reePb*hcKn%8q7flWSW0#_3v2x8jYoEbM)lY5#FX_y&Wn5Q!P zybh#I^>XhRf9i4WC%Ig;NWW=WX$hna7&Es|k^% zM>>keth_bFP`X}(t9fkzTupKX@ohk)N(QVNW|x?!$>Xn1R}(UyCPK{*Tuq3026q!L zaBzFLn)TB4KrlNsveshf=KnY(}?aJneOBXx*)Q9z!+jYL#CSu zy7Z(BU67fWWhjLqk?D3ZbTxlb47UnM5)CCpTHPN&G3W%DZg+w%h|Fx)pTfQ=X1XC_ z*9#-y$uix^Gju_wW;ry5WxD(MfT8Qf$Rgl|a3kn~NcUZciMle~NeH?i5`1-%Am}Rj zuLZZB&qJm=ea(EjRXg0AWx62~b8IS6pe4$5qhjB$cqJ^;UD1wAcZ*9b(~Sx_0x1iY z=~h=E)4gRKGTk>PAk&??I?HrJgtg6;=}tt@h4?3AE>y!v@l3aqp{vR?Fm$z@&wLw* zwC&V2nrFJf(3K297etod{h6AdVx}7+eKK^Rjv&*0cLOrr@Bh)UIdso-L#Cd8Z^6)2 z%m4r$9m%{}?SD%r{bT^-iO!u|*WvtrSRV>pDk%||Bi4hN( z?(`Lrn(I9PlhvJ|3nHg4Oo`T$X1YI9i*>~dM@i$(Iqc#6d5UVna0w0HB zNPVl549_gOtMK%AF~X>VsAO3(th)@!j@dmQoyeIyXcHoInYzR8Zo!mXuDDBlnX2;GYj zy3e;q2nk1?7-^Bm)P#ZibJ*2;F@Abt_{2t<85hJz-g{P`9L9tDP2)Jo;CS-aVo<<89JPuKH+9)-D$v`6EO zqf07z`?G(lNK`YpS7ZNm?AGqToCcnd+v5$5{^BD46)8#Nh<@16#g+&D$rq#W>=-s{ zQDYVgk$$WBAd3)MyHYTBEX?yyc$6+=Lh5@8HD6Wi*67D-pBqTiT^nSod3y;ADy%V6 zFJZGbWY$!Hsmu?40^XQ8w-B(NF1iFl1%BHmA_-yxif%vo{K>&bX6tX*tm!l$>dmXz zt)09&Td4VbJ0l-f`NWHnV8NQgOd@_fYXvIkMW_{RszrM}^`iL2+Nk#q{t~C=!DfwK zojR>IHf!`cdE0gjk9Rod0^MlDHtxiAAa1IIe%5|`o>n=1VeHmE=fq(8{fgb%=(pyS z>J*gDH8JgcVtNk8W{svOf08-gR_++ENuAx}>~(8ogOM0b;v}gtScLG=LOiJX;~4eJ@MJk(4M#YnOX@EHoZI4UL(FW z^DZ+((+f`>C}if;hMG>jo*8oNN9@t&M*U(@m*>PDt@VkHLWI3G7mPI35JVc-2ABTg zPh!X8nU>*MsvF908=)m42exRWkBhKRRy0OOIFy>e$4uO;h6XpxjFpA;DZUN1Xw(z+ zdA(wi_N`P0_r}n8a2JP-2Mrm694rd-sj_G?e{1Vi4lr3CnKM z+x8+(?D{b)I@`^h#a)3o-4sK-gXZB1LBxxS23wa~F`IyZ{r4p<4vV~xt;(tXAQGDp z&Q>Id^eZ+U&kywhHX_SP(3+)IH(1my5g8rYrB=+4K<0HG00g}%4434rA;4s`_GDlU zRNUDEaABo8y(IO64g7EOrC^#C=7WI=m*l9?Sf;D|+1{c)`8H9~I`?TUMD!atLP_Rb zo~ZkR0ItN%b{6$)1rWgb%PdZ8sUF6U4~Q> z^M$|80kK=>dT?~dOa`&rh&mxc@!||itvIg;U}e9Hu-UncgP17ql*5DN2S*M0eS2V~-@UE}%HHm+LF`tvflbIPt#+Pb;O`B&cSCF%vhJ%7M8Qj7 zEeyX#LZm_ibkVh#?#Vq)ET(H>mkW`0`y#BsB|J6ctw9wGrQh}cfq3&#L95n#zWJ^L z+AIMmSZ|3`B-|)N5qT1rbqXuFeG;8RdKhv@^-PF&HA#)oW$i(db|_maA+o6KX3EGE zHsmS)tL#vAPig_6O)G~*E7rNK5UCq`gdl;3?Q+Lu;B~9-4d}w7CE#`QIR3_zx&9gn z1a@xd$N><$`Ak>=LYcweE!y5GD}|a|+dfeQK9eM;X$-8zGCT4*J43UpPHH;sSl{_eXS4JP^g+Wd}GPfMV`th=`fbM;Uu^cj>Ojr@9y4 z#Rl7eA7j+F5dQlq!UL}2!JiONa6aF(H%|k7dVcRk4`CFtDCRwZc#Es}bNk^oogi}t z4k9i_;J`%%n)Pygv{%n@z69}m7067%>p&2UUn3&RL{y-t7)w;3sZxPuD0wPSi0Dt@ zRko;gQIanO!xC%>o`;C+%8a^0EBwEC^a>%fmZ(5qj&F?w+YFe3Eoaz_LPZav0zLn4 zA}UbVgEyo^1qzY9Q{WW`!~qYG92F>b$B?N;RG{Ck+#`PzQSu~Ipb)vR`P>5uY-{*i$n?nx*dIkZo?94Hu>}onO z3Omw5&BDR;Q=$Tenhn}|&9@O1 z=$DNtQi0;P-b4lZ<&pr1*#ivRG^SqR2EdAn291Mo`eb%A|XTt+U?Pal&C-< z5;N^1vGmLq79$B2C`8yNyKt}$gvH@9Fc|}<-SJnWHE_4(m~)F5A0X3-s6c~4vByuI z3KSyQi3+q-l?`@z+$orh1s`GP=M3&=(H>=FAq0pVyS|O$ z>dg>)a;E}?8s{>{Es3B470Y0F5D1PM(s9y6RG_FRL{y--o5-CCG}9nZf$rjmJRlPP z=dTXLQ=C+w`i0eW(%Gz8dgLQ{@+iJKsSxcgik{A5ueyn-Kq1$?YHJ5ySCgj#g~L#c_QL#3vfX-|9Gg0OpGgo~NkJUjw#fS$7=s&%>^F&u zOxS5S)(3$*2vndKizPz^sv{n=mI`C;Dn#0R0TpPCE-{h} z#zUm!@*}hV{!(g($$bcs&^l>pOX$sJiTg=7K?Q1R=~Wld6dZrk1%+bPKj%8BK+VSV zn-3Dt@sH!Vo!Kuhvepb*hx@`AI*Y)vv$ppY56 z7F3{SpOT>hg$UDPj*Q_P8Js)D81eCCjbY;pHd2GLo8I4~`#GsVUj>@sn@G_+_9?MB zlY|NsB8x|jw_xK2bC*07C`4Z80Trm(avTWx&xC6TD$vLvovR6m0|)!)@BhPTwYdlf zxl@6fjj0<8*Odm?MCKxnBd9;@I6 z*;@CBEOOrQGvokPl*Z? zBE_36w!&~-aHj%=|Am^Y!zL3=(G>p#RG_FBxHyP*8xQPq#WQ6kC2bo^LMl**uovN) z97(7^A#zGCMTAP2Vy?;Y^*pFR56{)v?0`(~d_Gp^c$>3>AYx*2m}=PMNS+GRY)o>W zji3UB21QGr63J$Uy2wo_=&EHYtlk0lBAHN(GRU-Rek0<^Dr5QKdV=HJ7h6sSN^Q8pnJ z=&ogq3KSK|Q-N|-$xwm1Rj}j5fE9AOQQb|Kh^C7gRG3c}YmDpZ$y0$Y<+)!$1-iU- z_ZY9+Yw}T7Us6{=I3DEFJOIx6u4NLvKq~4~t{a<;UKz@(t0UKvs3_HFENZLg*hBt7 zf}%_Ke*9~4&`edV$etvg@9FU|2qB$8OoiyuPdX>mL`{}7OC2~ZSuG{CM2I?8NzGLnWD z0}giqCS!z`WNkG;{sj^5$@Lw`%4D#*k$-uWD`aRtg9eN@A>EU*4(#C1OL9bckbmv1 z)=N~}O>@Tp0OOjZz8L)+hwqEU@d_OmB=|aj@TibH`B%b8!&fDuj$@PBjC9Ny$@~8P z>mQ^Q#d}Lj(VhdD8Z|pu!SeUKAS#L$wm1N2EMUl-6-;-h1rsvt&9ZwSXaJOwo@Ne2 z7l#2;ZCvIRyo_fs}|*DIMSxovQ%_vP4`7m6Y=9xF&3H5~j3438l_-p{~^(?1wE4i$4tZ;b+eI9gJ>rrD)~2z|vQ zp>?xmlm%gh^j7(G3t+zr{Mipkz|6HIjsD^fX048Gom)&3j|dY_IKKPuLS*|NHza(e zuroVfm9{FYHrsHm!}8Q%3$xW1BEJm!PXhg3oFucGI2Ch)YG?&2-J#7Vnt6BFO9@Dt zC`tC;)L&8-%`yDdKXM^;P~09PM0}qeld!Q_BgreY2#fM0*w3N{X0Phd=07Ygo&>NP z(T|2m^3S`=T9h7L5FXy`>5nAEv}Yuu<4JRF1=x|QY$wV6i(IoP9vu*x3hRRLK9Yw; zrXa$`n`rjrHOnURv=*_m#Dm)H ztBx##UZk>}GqWGQV0JdZcq8$g|HgT-$T1EpC4SQU#4QP%eZ&JkzlWcm4|A>w$BqaBAo^kd$ zG>Z`F^KUu}7Ocwt@=tHGIFzk5Zu+YQeS0BMbR||yA-&1)cnf0QlPz-XbyYB!<%(O> zmi}8T+RWBPg_?JTr%7;JPFmy}Q5IY#Q}p*wP-OD%r0%&TG7g9qF*Qy6}4Klv8cVn^j{_I%y^czf|>@twXKMwvN$9n z{kY0c^oh8p_-AqXP#HQRP{=C3t=rpBs#XIz>Ai#5tXisa>?i}Y_&)n4;mmS9t3160 z(AJI401n-AN>!^?=mtYNK!h(oSbKE7q%zJ|=j!w)CVUkn9msm~HzUYNQSrU#6e8fP z>`qR4s1?Xbr+;ISJczvAG17|lD>bbV2y)^;7Ws5$h43FxY%+WyvV*MbN!3)w^!muo zVoBKCF>+E=?0$-k10zIzm>J}xXPPARqSgC?Hffe1n z5{f^?jKq28H{@QLYjIrWcQo9n*!vE|9oainK}e^JpQI4MuX-T55N_`|w?~Ma(G5Cz z^+LEDG*P(AG0dNRvC#6|amtFbi9;m0Xaj(_w#|+J#57n!#!SD#5?PSBQtqV{u#vwl z^1WsCkVw3mn#?*XYFE$Bxj(tq36lBX61B5X*uR(|-+2WH&QBjl02L4ka^U41MvJ!j z4oqdkZ0RF*&MZjb{;9?2n7j9In4?4O>R6QulrxmUK{!|(F`=+k`>UNI)Py{YrR5~6 zUEUtH(NN~j$P^P6H=ugue3~Z5oh0K?QI5cr} zbPh3}zyMEVw|E=yka-2y#ft1ZIeEFRRjb|WRXtv@DNS)=;ILZdJx5}ql>U8#{nb7H z)wgQ&7Z;g!voP{6;Pw)Zf9Z*HSUap*nsQB?y~|5L(7IN6)2J&Jeu{MM^a>7b{EqxW zB=)?w4P3ybta8UgA(B!vu$VQP?0>3-+ z-XlqSo3EXyNgtclhV!e)xZOMuU?`SWT`g*k(Eu^!d-t;tS-S;C6o7TL${D6d;S$Z0 zzk-cDE7qCW&Dp^LJlOeN@nwejlC;d2k*0f?e-(=UV?}a+vxab5a-In8x^NCX>E1}6 zBJDic^@LVAS6msZ@~BC7{J`ho+GJ#t^BRpr?j&{4)|z?|M!KPqQc}J5j832UxB|MZw^SX6Upp{X7!P)aRT~9g<^oG|;FB3Po~)(f&p3sccnh-Oh-O zUY#p;ZP&HTLPTHw3TM25W5mgXLf<5XYSg1wa2I!_+1Z86wk9W8+Z^1UF{U%t=t_4Y zc?EBlS+u%Fc-km%dd+k8%q$8JDT?~VVm+NKizu_ANaeD( z#6KXz?z{K_iWDLQ=73WeWRXL&0Yp0BIq-)|{%L1uu@85OC*dRvwGtrG5;{Pni|?Kj z6|H()Ft|hcx;;RoYnm|Z50rk{sOJ+{Nt{9j<99mjW8z8yMS979u6z4U#H9p=JnV+x zSKuHs2a!U}-ggBBZc|I2$*TNU2}qviZvZ0Q{Dg(~AOibL43GekF1!gq3LAx9-|pCT zEvw3$BFLDdOz#;HeecO8ige9TVD;EQ0sHLF)p)gmpGUt{;~D`(n&GUeCEl-!#6hG# zorRy*donE;o`miZt*0R)$i0AwZ;bkV2c)d$wpy zP^gcc4Xga96gu-qD8HYcJ?CFst*;5wlkJ(E}#^2edO8WC01{j%c0=a!IdqT zT88Dr`{Z5B2P)2_C{p;<0z?Wmto`Pc0&fycsYa&&BK`F&+kis^#4{G>#I!pnrqyj? zvf|PGMz*28@x}~j{{Fi zJyAbb0iJZ33^nd!v_*`O3nj^V$09cZu?3Oi&1=~?)-r59@T0>%wzsGsiohFdsF!5c z95QTbCkG&<`$W-nh=AP1&heueid2`Bd11d;RP@fF{SnFVqh@1VkSEtEE~1{~TGk9b zYdE#&xVDPa+(-`qDgDJ|*yn0C#=!jsfJL#*oxqRcNeyS8F?gSrH35FKAv&U_Ux*`q z0gpTIF=94u&nWOW&bGo&X2>72DA1aF^ieo#gG`HA7DWLQh4f4t4)){66aqytw)NU1 zMS~z7tY%cSot8*saNJ? zS@|^c=RaWObFCNW#3=lLl@B759p9|sg>Hc*4TUcoQ`^FADCnXF4Nc{c*JxuUg$Val zuN??)yp<}@yfpRyfO-!ioq9c>4KlQ3(nc7{Kjq;7En`QAE{6zX{5+>EIObzg@3*skhMDM*w0y`U4)BJWYtJff@SWW=q}^dL&3hHvf$Q3VN85g z*CUeQ))VpwnWf0BC-l3x_3%IDzbGcS^-y@dzKGz~Giw;Po^Yh&M>RRqP=jR0C@!rmS$;KRGP^>%#)w_ew809yb*F^a8VuSfYDE%HC2 zrwgPYhFg(w>!Dm>S9exT4|6M$AIfxidVCm#WJGT|!PZPfbOg5^DuTmsTo2dkS>-pw za3S=m8aOs`#RDO`*iI+tJws&2@X179hx^4+;MRl8f(AGkSYg*(DFL@0Dv*9A#n&)IIVuHiJv=G;6kZ$4Efqe4sCCW8qbzFC zl^zc5X$T7tL8MpRsZaxMZ@#w?_8Q(byHbd~{9*pka=dvqM@rm!OwG7xO1rreYRu34 z*si5ovt2Z}@YMeFDjN##+QqH+ws-pd7WMVRR~GHO_dy}@ zX<{=X@xyk_jayG#{?0sDG^Wy>hS5m7%}dCwhl)(s@N#N&nPsSFvjDtTxMUxpbwL9y znzB=dJZKH@-ueO!8^v7+@3%b2LSXo9!`V33xc40ns-?iK2bt(o=pto6xr2!N6NG~( zxb-0N?aD|xHV5laVsZsTxeT_X2L+Z=@`7P#+2u>?Lp*q4Jl z*TJplp97KYxN6zhsRPM8b$}z0&2n$uCqp{!WY3;U3Ihb>y(2mOVb%Po6F zV_O|5Y=AKH(qXUs^5ryd3 z;&QwE_*ZPI8&qL&PgE4_R0wBVk?cswql21H6U#^Q9H%1)o9g)W@CDp?bRfdoj~t-* z?33{5K%~n79PmU~&g9WaOrrylIDKp}`Y8O}KYMo`9mtsDo#eA;bR}RHq4ECa;96Wf zI?!S<*?1sQH};8xH)i!yY^qNcKuY6-Gy&PmH>X(63o^@J0r711DH$Feh~S`w$o@9! zjH8*I;^42i^XNb%wsl$}e9eMT_ur%K%ACl{8albLGOS1fvhnqGAu z5GELJ(a#IJ>Pau~7TtMtAac3oUxeo5bHPZ;qXQAve58~aGn3(DX0n>hOb}V!2q#O~ z#00^U9RyE$j0Fr&IGV`_p2*spd*|I^V| z32_cY3Qxs>KvN5db4W|APx-AH5%KT`Wl2*i+SwTJ=IDuubD-w%ha#d+F5;Zcr?Gc# zbqZ?S$LNq4qiWT1iqN4T#X&{gSWJT_pPL%8V;FYKS7V1^@G@Y>yuZabY79g$ZGoO; zc~~|yNmy|p)8zovl$-9EgcV1S;+Rc<`yz~nxQ+q~k^uTa1o17G7D0;B`W2!IdXCfM zMQh^dQ#2dnZZ!le4%FN@2Q{ouw_0MyOg&LoFU5(=xKj)sZ8nC+18*B4Fg6}eC-NAr zM*SRY_2g@&J|_M#Js&moyDefLu~lwX4oURjz}?8B;-Iw_GdWU-)S9`|k?-V4tnj)% zQc|vG#tQ#=NM?sde{n6jwjHE+;66zX*@P1y_xJ1&6)kE3+d?0ZdjHy9Nqe4t9aZRf z@bk8auVRR;^4B_ul~kDqqkHDJyh!pkXO5=XYS))QHivtNv8~Sv{T*tTC-BmDN&aPR zUMpWSOa5FRhr;fz6(SXOzAV&+vZ3@z=@ykb}`10wN${T*=kd)fKN(&YfcKg>qa zUwoh*tep*Lk^ZPnlze3DH>^`1M_SY`KbNs;wZf3rV6Q}~v6xPYfC0VbJy0>68PuKf zu+TsM1x}$*1ut$mwwcbY)TiwOYF9Tx3@cF)F1V;2(GSQMv#5^-%Q@aV@-9*QnU`BG zXT7tl`;_U1wzhgR(U?yYe#}@>K z9fw75lK%A5e}NJ1jU$vD zrz{2yUo9Md^YnnsF#k++$7~x(o|+e#XSvqjfJDV1^GttnkxF;oOY9BGEmD=WDr-H; zNNQ~K8@ty1KX(2KT0k7aGWv!bnF`lF_B7gpQtxI_L)X^Got$dwS!vQ5a_CSGEFC$3 z{K&Qub6~*-mZ^jqoZuqbGw#_+xC_w6#*{vw#zM=6V|6K0{>qSTt#RJymxz)$R9qfg zmW-!ZG80-dY$-ti>#PpByj~DA*PVTSLZ5IxRC}Gej!@I7*JlX{YjaT*Kng6Xg0~K8 zXp;u#7i3b$s!E2E^Y{v!5SDQ-iG2t&HxR+P%fLg1e7E3UP)l|>Db&NCx5NDl*A4aB zBha^Oss&^+5Vi;C@(#oSIoWbvY5NJXAKlglC3%aY!qcuZaihLqKl zByHdCESLwG0fzwF#-*S1wO}W~);%_d;l?<7GRn$rBm={l?^et^RaJsMhN4w%X;3ZBqZ^UY}a1%?% zLj=Pm0n&3wk~ee)T}$BNBNnyq(>(B92Cy#yBJ7$gw%Z?l)NUxt4EisKTvC zUj%V$iYUqV(TGwkwXzQdQf3hsxDqHB#k#S8X(TF=4pW7v$CNP$VjxlO+8q$olCQj& zDD?Uu;ywAJ6{{3*s^^aA`6Wftp8$blEe11o5??NpQN54^zB>8_P-pMMBqeWTT1k!Y z{$gn3UZ)jm4h3Ge(h?-@6r}AF|Gw!jH!W;e`g6H2LQ7afq$Uf#XB;?F#^}5?3kO$q z$a~}PWj_7yp+$W&3m)8ITfAtD*(WjIs3+X|39@7KX{OE3h9ig2QmqnfXs77MxYqSZ zeq4lr&hf@P`HTqG^S0M>BzsZ19OtnX6H${XYEz|Ggi8zbA! z`-GF=)ZqDJ;FSY_@%GXk90rTdh>cTzAb~T~nP6!27Z+(W7eP9+y^=D@E{S&_-Zr#k z*n-A%4q0u;_ckxbk<|BxENaDbxH)is@k7l2hs?skK%i_mmewK97*SeM>Q)Bq^g*tI zShIGAiYKvm;98GdIGlo=nCk;A<8lE_!Lh&2mDb$B-(q!1AReH11qE8>&2idq$VrM&z3bhj2B&Z1v8)*BHO@heM zBb{yBCLNE4P5Rm=kxha~l?3O;mJ1T6_ zy8E~+%i|x|Bz9TWuUVN*f=GwjV25Njsct#gq^38RO+p2AL}xXyFQUw?kGIFl1OT4$ zBLiYg*jc zy6dKHN%IgjsfHlF$RIDJ4gm5J@*a?vfM-MF^DM!vCQnFov>GYY*ppp>TaIB5Ej@RQQOy}$fn4%+IFr9VtGE)SRt)CF8 zXA~41J)Yz~UQ-RbkN0a?*v{e0p{8Ob*v=Z?nO!s+!!FWYbr+^Hu>T357;@q`Lr~*0 zqP=EEgz2P?@Bts4`5}quP;)m8;tfpAOK;fDNmbCNZGXddy86^VRW3S2A7#jBjKLdI zDGH`Dx*&7Hp{2prY_2PYlevx;B0J-9ijlEpg6VAQ`vm(>>YYZt;{)vXu&@|lG{I1) z3F@Y5u$?s2T*T~?2!OJl(91I;N0-F=bD=KgRk?h&QnJ#AZ>hZKZ^HjXuRD1Vr|%Lwng>xN&=7UN5a*Yf=;g6WIGAZ!j`-D}#}S#>o6mJUs4T2`HG}xdfO+0S!ZO zv*nc&8DDH%XP|OE+h9vQLGy%Zt;ET1kRa7v5cVjTM#0qF5sM4MNo13 z+Iaz-+hoTo@;FPTgsTWdx>r5!$fy5c8G+3Hxkp&r5-uaCs8f6gufQ_mR&-lMUW~zg zH9ihE&>PJ{3@|D-b?ZzQpWtd?-DnDG=3~`&U@LJEw}7;K#&STA`PhCk1#7P3^vhQ) zBg@Xi4T)R-+0e@EJ1*3mn=$K$R|`W+&zI92fb;xp$UgtYNs4^=7-)6Qftk6L#;mRm zncLTb#8_qj2;gbXR~wOJYX@rPD_~FM4Gy2zoDOCcbI7Bw<1|^}<1mW@YiBaFOEQ~S z&~k25X4YA;()7KGBrIFnFBbbOw1l*uLf9g3D4$J_(>YC>AEfX9K5hZI(r&+ynOpjW zov$?2IzBa&Q;jc*iY>mY4ZP|^R}168D`%cC07rUl$c^8FnR(sf+7{Km6_}oC18a)k zvbMP}J%!(!X{~oU=h1^2@3l?o#_Gd{oOkh9TsZg=OUAf1Ks{tbY=n=(myO+t{vy%U z!uV~6Qv--o5myWENwdn(V*W879GtGB1HSBKyZkE-rYQ#k8zSl-4`$}}|N7z&ZreLajP3pSJwoLDSC9{| ztA(o-Dh-$TJ7Uj$eQ*iL^eik8j#mC}bXkL6E&QnfVn)sW0VkpUsUU6v8B&(*rXe#p zBF;{5dl57ev0Ma=Og7FjII~yTAlfKNK6Dc?qr0m&;M1DzY1KA7WFbvx37@y!;8zQS z>&mVW*OeME9WkTpw)LXD;@i+o?A)ot@K@Yd@#$m1Yn|7@XqEUx+CP`+M@7k?QwH** zIAwA%BQ62a_F%OfoEw*byl%FD^h0EbcZBQmUCDVzvZ0B~cOla2mqSGb*6 zy00wmBSa=U>Nr55z9>qz|N9n~fb49F;KEjn$6i@WzMfD#H zYUbQ48VQle6I~o`FDJ=`!sye2qN;;mDE#Ss8i%rO6tuWsC=8L)tNiI?A>Lp08h$$N z;#uDa9Lf1JO4=_QS*#N>&XMO6j`hUpAN?`bC*t=xjQUJKF@#k`#kx%Gl2Ga`kN^#+ zd5JA-5c%VuVsum<&)>fT`7ect^wjIP0$w9>J-j{0M4s>xlzOY@*>TO`B(^z3#mxdN zt^`WG0yRLX*V7g(e!(8hDE0QXLVnE_hVyOilzRAWk)DH1N(*m!&hDo$frYV-heHFRj;$>MC|0(W=Y7Z2a#nt@Zh6GvP&{>zZNCq+`c%;(+6X_ zDtm9CwZ#5ONm%vb2LX0bZ@@hv!bb2%ta^CTtlx^z>%{@%%_(6(lF;cvO9ub-R$5maa--acD#{tw!hmdB`@y1Bn#dLw$b9jM`XQYjM4neV zF6i_&w7zaAp>}5GP%&dFUc%BNpwnx+@VcRG7}H*~?cwBgiRtuIj{vag)zxd*gv^%N zi+)I_2mSs_rv8vl4zzU>^Wz83h|suG*=QP8kL^qyurOL<|4*94H9%77hV{-uJ~Va0yo*5a>A?v=t&P zYK73pdBmMSFLqyFi`M+%8zFL_=`O*a*F6f^iBU6FfR?fSBoOFTAH%}!XiQ1Zqdz3j zgUFLPr@}A%#V62<oZql_DOs+)DdnhsdrqYMXibyMc`V%&qG=++Hi)yO(t3sbZU*|@46J(!T#=8XPn_b zQ2>|{XkRLh)Xwo(e6jF>HL%1Vcd+ zfZyK|<7d_W`Tcf62jGNwW3Fx7*}BLgFrTu_X_i)nNKl$mbUyI0Bv0@zVO1W!4YR2G z*5xp?eqIadnGmT{yt0k9Xp-C`;41=p58;iJ4#ZCS%h8Q20t%TU^${F4w?&eI3&uoZ zhwgWFQ*)r{97Dde7!G-;Ws^mnyBYg>riMLh##mKvqr@h3%|$VA8cpvJN~FEZh6!!7ENY$dE({F5*t@_K!0I`xLeblnkZ zD2-2}F%PC-Cr!=bT25#G>Y9XxVqR1Y94o+$|_Dm zN=PGml%y!&rmGN|a`8O&z1l9ugqz+Si_ny(N9+8VD|OdS>9ivsDz zvYAazgHtxwjI)@3vj@Y7hCF5Q1;{)N14xTuMMpga(c@gY<<562{F4Wgg9Z*FksUiS z93BWl!{DD-4q;!+DsmSDy07StNs=1a82(A%EfzmFAIuI$zZ?($8L2Rt^**4QHccE~x19N^tYp7m<0-G$B&^FN7O_ z;d6(IRvW+DuEj>N7#kXs@jnDDvUm7TlI;U@I4Fhll>%qSYB(q@Z^#Ra+4r(IBkTsA(e-{G@Nt69{dDnENVv{5+0$;V@YREokmNUO~|cGsfJ=raYk zAdbawFN>SRMRc5+u0>IcPCpENi_-?@}qZ%ard5#7aLg$jhXVlUxmn=W&lajcX7>0f^5bKXkyCX;^2MMg3k3 zzD(ORyM#!`X*JmV6U(wI?6#rC3n8-o55%8vE>?HQOTL!DeSP~5S=2&%-dVIKISe85 zI!_+z6Bs3bIf_YBsB$DWbO?8iJQoty-v| z=2!(^rd*$4qT-it6!@xeALI*l2`bv*yk=2XHH9-1^R2UxS=F~J-3$Q|N)PW>7Ula3 zpg`t5M1ne7*X}~3*BNxth5Dg575~_Z{bshUwY5PsN1RUF4X9}K0n@Qa{S9A+VpqJC zFS6>m)_C!v{p_6>ia?5B!zr+$G|lLnWsnJ?YEX!(K_&VIjp!RhXTRag0eaVvv;7Ru z<_iF#>bke^Y_7B#B1F7eS0+$uEXX3pf#wUO` zI~_cp<6riPCpnin?$NL?b#@Q23{D&8v+Co10-H1yky6I+!)y)xg^`2EZhhQc2O!op zap&Sdcs%S5*b5=>c$!XR83f2|T=NfYUqOcek|9a)8+q2E9yH+b9C>zDsEPOc?!bYN z24b~vu@+&K5h6^>t^dB+<+tV2;1-N>r;+YoIafEdvwPUmORb^Cu%nXqBH{6{#stP@ zF|=D38H&;D69{@}!T{jqVl8s@>9?RTq2=4Pk`9G_t5WAQ(#N}9WzkrI*q|}`5D6P) zYJz&{=v+yoc5#_3p#U+NeKHj43HNx!ZN6v>Q^Q8avhp`Wq47`;UQBJ(XpFcP))+Rv z_&;!5keV7TvO3(< zu<3(KG6nYnHGzNP)GXeZ&!_*Qo0QMlj81)GYFMAB2@3T@ZCkEC2*O8UF>y}mrQ?ubyw0#)!mh1b*o$` z53Yt7^)%3;wr>Vn5Bdu&fyl<3fXFehC|mzIt%vTc5r{De=64|K!;0*8tk`bfH{tLK zS`Ww#xO;=nN-y1fD0O>gtgQ0&DbJBA6F zPcNF&u|_{b4k(I*M|9eb328m>q|7D$rgO3I3;tcT(NH>%pCW$SW7R))aO>nwNb7-L zNXL9FINZDp%g1)mdR$Jg-vR=;CvdS!cebg53~QWgiD}@Qh}Hulh2Q_gxNr

pGkp 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πuADy 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≤gz=9`5{`9{YhKxt4Rf?3YJ1d}sE>3@tB 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 ({ useMoneyAnalytics: jest.fn(), })); -const mockNavigate = jest.fn(); -const mockDispatch = jest.fn(); -const mockUseSelector = jest.fn(); - jest.mock('@react-navigation/native', () => ({ useNavigation: () => ({ navigate: mockNavigate }), })); jest.mock('react-redux', () => ({ useDispatch: () => mockDispatch, - useSelector: (selector: unknown) => mockUseSelector(selector), })); jest.mock('../../hooks/useMoneyAccountBalance', () => ({ @@ -38,17 +32,35 @@ jest.mock('../../hooks/useMoneyAccountBalance', () => ({ default: () => ({ apyPercent: 4 }), })); -jest.mock('react-native-linear-gradient', () => 'LinearGradient'); - -jest.mock('react-native-reanimated', () => { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const Reanimated = require('react-native-reanimated/mock'); - Reanimated.default.call = jest.fn(); - return Reanimated; +let mockOnStateChanged: (stateMachineName: string, stateName: string) => void; +let mockTriggerCallbacks: Record void> = {}; +const mockSetString = jest.fn(); +const mockSetNumber = jest.fn(); + +jest.mock('rive-react-native', () => { + const mockRiveRef = {}; + + return { + __esModule: true, + default: jest.fn(({ onStateChanged, ...props }) => { + mockOnStateChanged = onStateChanged; + // eslint-disable-next-line @typescript-eslint/no-require-imports + const { View } = require('react-native'); + return ; + }), + useRive: () => [jest.fn(), mockRiveRef], + useRiveString: () => [undefined, mockSetString], + useRiveNumber: () => [undefined, mockSetNumber], + useRiveTrigger: (_riveRef: unknown, path: string, callback: () => void) => { + mockTriggerCallbacks[path] = callback; + }, + AutoBind: (value: boolean) => ({ type: 'autobind', value }), + Fit: { Layout: 'layout' }, + }; }); jest.mock( - '../../../../../animations/money_account_onboarding_animation.riv', + '../../../../../animations/money_account_onboarding_animation_v4.riv', () => 1, { virtual: true }, ); @@ -56,220 +68,219 @@ jest.mock( describe('MoneyOnboardingView', () => { beforeEach(() => { jest.clearAllMocks(); - __clearLastMockedMethods(); - // Stepper animation (Rive) enabled by default; every other selector is irrelevant here. - mockUseSelector.mockImplementation( - (selector: unknown) => - selector === selectMoneyOnboardingStepperAnimationEnabled, - ); + mockTriggerCallbacks = {}; (useMoneyAnalytics as jest.Mock).mockReturnValue({ trackOnboardingEvent: mockTrackOnboardingEvent, }); }); describe('Rendering', () => { - it('renders the onboarding stepper container', () => { + it('renders the Rive animation component', () => { const { getByTestId } = render(); - expect( - getByTestId(RiveOnboardingStepperTestIds.CONTAINER), - ).toBeOnTheScreen(); - }); - it('renders the progress bar', () => { - const { getByTestId } = render(); expect( - getByTestId(RiveOnboardingStepperTestIds.PROGRESS_BAR), + getByTestId(MoneyOnboardingViewTestIds.RIVE_ANIMATION), ).toBeOnTheScreen(); }); + }); - it('renders five progress segments', () => { - const { getByTestId } = render(); - [0, 1, 2, 3, 4].forEach((index) => { - expect( - getByTestId( - `${RiveOnboardingStepperTestIds.PROGRESS_SEGMENT}-${index}`, - ), - ).toBeOnTheScreen(); + describe('Analytics initialization', () => { + it('initializes useMoneyAnalytics with onboarding screen and stepper component', () => { + render(); + + expect(useMoneyAnalytics).toHaveBeenCalledWith({ + screen_name: SCREEN_NAMES.MONEY_ONBOARDING, + component_name: COMPONENT_NAMES.RIVE_ONBOARDING_STEPPER, }); }); + }); - it('renders the Rive animation', () => { - const { getByTestId } = render(); - expect( - getByTestId(RiveOnboardingStepperTestIds.RIVE_ANIMATION), - ).toBeOnTheScreen(); - }); + describe('State changes (onStateChanged)', () => { + it('tracks VIEWED event with step 1 when state changes to UI1', () => { + render(); - it('renders the footer button', () => { - const { getByTestId } = render(); - expect( - getByTestId(RiveOnboardingStepperTestIds.FOOTER_BUTTON), - ).toBeOnTheScreen(); - }); + mockOnStateChanged('State Machine 1', 'UI1'); - it('renders the close button', () => { - const { getByTestId } = render(); - expect( - getByTestId(RiveOnboardingStepperTestIds.CLOSE_BUTTON), - ).toBeOnTheScreen(); + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith({ + step: 1, + step_title: expect.any(String), + total_steps: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, + redirect_target: SCREEN_NAMES.MONEY_ONBOARDING, + }); }); - it('renders the first step title', () => { - const { getByText } = render(); - expect(getByText('Money accounts are here')).toBeOnTheScreen(); - }); + it('tracks VIEWED event with step 2 when state changes to APY', () => { + render(); - it('renders the first step body text', () => { - const { getByText } = render(); - expect( - getByText( - 'Earn up to 4% APY on your balance, available across your entire wallet.', - ), - ).toBeOnTheScreen(); + mockOnStateChanged('State Machine 1', 'APY'); + + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith({ + step: 2, + step_title: expect.any(String), + total_steps: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, + redirect_target: SCREEN_NAMES.MONEY_ONBOARDING, + }); }); - it('renders the first step footer text', () => { - const { getByText } = render(); - expect( - getByText('APY is variable and not guaranteed.'), - ).toBeOnTheScreen(); + it('tracks VIEWED event with step 3 when state changes to Card', () => { + render(); + + mockOnStateChanged('State Machine 1', 'Card'); + + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith({ + step: 3, + step_title: expect.any(String), + total_steps: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, + redirect_target: SCREEN_NAMES.MONEY_ONBOARDING, + }); }); - }); - describe('when the onboarding stepper flag is disabled', () => { - beforeEach(() => { - mockUseSelector.mockImplementation(() => false); + it('tracks VIEWED event with step 4 when state changes to Coins', () => { + render(); + + mockOnStateChanged('State Machine 1', 'Coins'); + + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith({ + step: 4, + step_title: expect.any(String), + total_steps: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, + redirect_target: SCREEN_NAMES.MONEY_ONBOARDING, + }); }); - it('does not render the Rive animation', () => { - const { queryByTestId } = render(); - expect( - queryByTestId(RiveOnboardingStepperTestIds.RIVE_ANIMATION), - ).toBeNull(); + it('does not track events for unknown state names', () => { + render(); + + mockOnStateChanged('State Machine 1', 'SomeTransitionState'); + + expect(mockTrackOnboardingEvent).not.toHaveBeenCalled(); }); - it('still renders the onboarding content (container, title, footer button)', () => { - const { getByTestId, getByText } = render(); - expect( - getByTestId(RiveOnboardingStepperTestIds.CONTAINER), - ).toBeOnTheScreen(); - expect(getByText('Money accounts are here')).toBeOnTheScreen(); - expect( - getByTestId(RiveOnboardingStepperTestIds.FOOTER_BUTTON), - ).toBeOnTheScreen(); + it('tracks VIEWED event when FinalState fires', () => { + render(); + + mockOnStateChanged('State Machine 1', 'FinalState'); + + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( + expect.objectContaining({ + step: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, + }), + ); }); - }); - describe('Navigation', () => { - it('dispatches setMoneyOnboardingSeen and navigates to Money home when close button is pressed', () => { - const { getByTestId } = render(); + it('tracks COMPLETED event when FinalState fires', () => { + render(); - fireEvent.press(getByTestId(RiveOnboardingStepperTestIds.CLOSE_BUTTON)); + mockOnStateChanged('State Machine 1', 'FinalState'); - expect(mockDispatch).toHaveBeenCalledWith( - expect.objectContaining({ type: 'SET_MONEY_ONBOARDING_SEEN' }), + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( + expect.objectContaining({ + step: 5, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.COMPLETED, + redirect_target: SCREEN_NAMES.MONEY_HOME, + }), ); + }); + + it('navigates to Money home when FinalState fires', () => { + render(); + + mockOnStateChanged('State Machine 1', 'FinalState'); + expect(mockNavigate).toHaveBeenCalledWith(Routes.HOME_TABS, { screen: Routes.MONEY.ROOT, params: { screen: Routes.MONEY.HOME }, }); }); - it('dispatches setMoneyOnboardingSeen and navigates to Money home on completion', () => { - jest.useFakeTimers(); - const { getByTestId } = render(); - const footerButton = getByTestId( - RiveOnboardingStepperTestIds.FOOTER_BUTTON, + it('dispatches setMoneyOnboardingSeen when FinalState fires', () => { + render(); + + mockOnStateChanged('State Machine 1', 'FinalState'); + + expect(mockDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'SET_MONEY_ONBOARDING_SEEN', + payload: { seen: true }, + }), ); + }); + }); - // Step 0 -> 1 (button starts enabled at step 0) - fireEvent.press(footerButton); - act(() => jest.advanceTimersByTime(MONEY_ONBOARDING_STEP_DURATION_MS)); + describe('Close trigger', () => { + it('tracks EXITED event at current step when close trigger fires', () => { + render(); + mockOnStateChanged('State Machine 1', 'APY'); + jest.clearAllMocks(); - // Step 1 -> 2 - fireEvent.press(footerButton); - act(() => jest.advanceTimersByTime(MONEY_ONBOARDING_STEP_DURATION_MS)); + mockTriggerCallbacks.close(); - // Step 2 -> 3 - fireEvent.press(footerButton); - act(() => jest.advanceTimersByTime(MONEY_ONBOARDING_STEP_DURATION_MS)); + expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( + expect.objectContaining({ + step: 2, + step_action: MONEY_ONBOARDING_STEP_ACTIONS.EXITED, + redirect_target: SCREEN_NAMES.MONEY_HOME, + }), + ); + }); - // Step 3 -> 4 (last step, autoComplete timer starts) - fireEvent.press(footerButton); + it('navigates to Money home when close trigger fires', () => { + render(); + mockOnStateChanged('State Machine 1', 'APY'); + jest.clearAllMocks(); - // Auto-complete timer fires onComplete after durationMs - act(() => jest.advanceTimersByTime(MONEY_ONBOARDING_STEP_DURATION_MS)); + mockTriggerCallbacks.close(); - expect(mockDispatch).toHaveBeenCalledWith( - expect.objectContaining({ type: 'SET_MONEY_ONBOARDING_SEEN' }), - ); expect(mockNavigate).toHaveBeenCalledWith(Routes.HOME_TABS, { screen: Routes.MONEY.ROOT, params: { screen: Routes.MONEY.HOME }, }); - - jest.useRealTimers(); - }); - - it('does not navigate to Money home when continuing between non-final steps', () => { - const { getByTestId } = render(); - fireEvent.press(getByTestId(RiveOnboardingStepperTestIds.FOOTER_BUTTON)); - expect(mockNavigate).not.toHaveBeenCalled(); }); - describe('analytics', () => { - it('initialises useMoneyAnalytics with MONEY_ONBOARDING screen_name and RIVE_ONBOARDING_STEPPER component_name', () => { - render(); + it('dispatches setMoneyOnboardingSeen when close trigger fires', () => { + render(); - expect(useMoneyAnalytics).toHaveBeenCalledWith({ - screen_name: SCREEN_NAMES.MONEY_ONBOARDING, - component_name: COMPONENT_NAMES.RIVE_ONBOARDING_STEPPER, - }); - }); - - it('calls trackOnboardingEvent with VIEWED action for step 1 on initial render', () => { - render(); - - expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( - expect.objectContaining({ - step: 1, - step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, - total_steps: 5, - }), - ); - }); - - it('calls trackOnboardingEvent with EXITED action for step 1 when close is pressed at step 0', () => { - const { getByTestId } = render(); + mockTriggerCallbacks.close(); - fireEvent.press(getByTestId(RiveOnboardingStepperTestIds.CLOSE_BUTTON)); + expect(mockDispatch).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'SET_MONEY_ONBOARDING_SEEN', + payload: { seen: true }, + }), + ); + }); + }); - expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( - expect.objectContaining({ - step: 1, - step_action: MONEY_ONBOARDING_STEP_ACTIONS.EXITED, - redirect_target: SCREEN_NAMES.MONEY_HOME, - total_steps: 5, - }), - ); + describe('Rive text run initialization', () => { + it('sets all expected step text and numeric config on mount', () => { + render(); + + const expectedStrings = [ + strings('money.rive_onboarding.step1_title'), + strings('money.rive_onboarding.step1_body', { percentage: 4 }), + strings('money.rive_onboarding.step1_footer_text'), + strings('money.rive_onboarding.step2_title'), + strings('money.rive_onboarding.step2_body'), + strings('money.rive_onboarding.step2_footer_text'), + strings('money.rive_onboarding.step3_title'), + strings('money.rive_onboarding.step3_body', { percentage: 3 }), + strings('money.rive_onboarding.step3_footer_text'), + strings('money.rive_onboarding.step4_title'), + strings('money.rive_onboarding.step4_body'), + strings('money.rive_onboarding.step4_footer_text'), + ]; + + expectedStrings.forEach((text) => { + expect(mockSetString).toHaveBeenCalledWith(text); }); - it('calls trackOnboardingEvent with VIEWED action for step 2 when footer advances to step 1', () => { - const { getByTestId } = render(); - jest.clearAllMocks(); - - fireEvent.press( - getByTestId(RiveOnboardingStepperTestIds.FOOTER_BUTTON), - ); - - expect(mockTrackOnboardingEvent).toHaveBeenCalledWith( - expect.objectContaining({ - step: 2, - step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, - total_steps: 5, - }), - ); - }); + expect(mockSetNumber).toHaveBeenCalledWith(300); + expect(mockSetNumber).toHaveBeenCalledWith(0); }); }); }); diff --git a/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.testIds.ts b/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.testIds.ts new file mode 100644 index 00000000000..08adfeb6b9b --- /dev/null +++ b/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.testIds.ts @@ -0,0 +1,3 @@ +export const MoneyOnboardingViewTestIds = { + RIVE_ANIMATION: 'money-onboarding-rive-animation', +} as const; diff --git a/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.tsx b/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.tsx index ed6cd4ef3dc..728a9dcb03c 100644 --- a/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.tsx +++ b/app/components/UI/Money/Views/MoneyOnboardingView/MoneyOnboardingView.tsx @@ -1,58 +1,61 @@ -import React, { useCallback, useMemo } from 'react'; -import LinearGradient from 'react-native-linear-gradient'; +import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import { useNavigation } from '@react-navigation/native'; import { type StackNavigationProp } from '@react-navigation/stack'; -import { useDispatch, useSelector } from 'react-redux'; -import { - ButtonVariant, - IconColor, - TextColor, -} from '@metamask/design-system-react-native'; +import { useDispatch } from 'react-redux'; import { strings } from '../../../../../../locales/i18n'; import Routes from '../../../../../constants/navigation/Routes'; -import RiveOnboardingStepper, { - type OnboardingStep, - type RiveConfig, -} from '../../../RiveOnboardingStepper'; import useMoneyAccountBalance from '../../hooks/useMoneyAccountBalance'; -import { selectMoneyOnboardingStepperAnimationEnabled } from '../../../../../selectors/featureFlagController/moneyAccount'; -import { useTheme } from '../../../../../util/theme'; import { setMoneyOnboardingSeen } from '../../../../../actions/user'; -import { AppThemeKey } from '../../../../../util/theme/models'; -import { useTailwind } from '@metamask/design-system-twrnc-preset'; import { useMoneyAnalytics } from '../../hooks/useMoneyAnalytics'; import { COMPONENT_NAMES, MONEY_ONBOARDING_STEP_ACTIONS, SCREEN_NAMES, } from '../../constants/moneyEvents'; +import Rive, { + AutoBind, + useRive, + useRiveString, + useRiveNumber, + Fit, + useRiveTrigger, +} from 'rive-react-native'; +import { PixelRatio } from 'react-native'; +import { MoneyOnboardingViewTestIds } from './MoneyOnboardingView.testIds'; // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires, import-x/no-commonjs -const MoneyOnboardingAnimation = require('../../../../../animations/money_account_onboarding_animation.riv'); +const MoneyOnboardingAnimationV4 = require('../../../../../animations/money_account_onboarding_animation_v4.riv'); /** * State machine constants must match the Rive file authored for this animation. * Update these if the Rive file's state machine or trigger names change. */ const RIVE_STATE_MACHINE_NAME = 'State Machine 1'; -const RIVE_TRIGGER_NAME = 'Trig'; - -// eslint-disable-next-line @metamask/design-tokens/color-no-hex -const GRADIENT_COLORS = ['#190066', '#3F6FD0']; -const GRADIENT_START = { x: 0, y: 0 }; -const GRADIENT_END = { x: 0, y: 1 }; - +const RIVE_ARTBOARD_NAME = 'Money_Account'; const CARD_CASHBACK_PERCENTAGE = 3; +const CLOSE_TRIGGER = 'close'; -const RIVE_ANIMATION_STYLE = { flex: 1, top: 100 }; +/** + * The keys in this mapping refer to the step state names in the Rive file. + * Do not change the keys without updating the Rive file. + */ +const RIVE_STEP_NAMES = { + UI1: 'UI1', + APY: 'APY', + CARD: 'Card', + COINS: 'Coins', + FINAL_STATE: 'FinalState', +}; -const RIVE_CONFIG: RiveConfig = { - source: MoneyOnboardingAnimation, - stateMachineName: RIVE_STATE_MACHINE_NAME, - triggerName: RIVE_TRIGGER_NAME, +const RIVE_STATE_TO_STEP_INDEX: Record = { + [RIVE_STEP_NAMES.UI1]: 0, + [RIVE_STEP_NAMES.APY]: 1, + [RIVE_STEP_NAMES.CARD]: 2, + [RIVE_STEP_NAMES.COINS]: 3, + [RIVE_STEP_NAMES.FINAL_STATE]: 4, }; -export const MONEY_ONBOARDING_STEP_DURATION_MS = 4 * 1000; // 4 seconds +const TOTAL_ONBOARDING_STEPS = Object.keys(RIVE_STATE_TO_STEP_INDEX).length; const MoneyOnboardingView = () => { const navigation = @@ -65,80 +68,35 @@ const MoneyOnboardingView = () => { component_name: COMPONENT_NAMES.RIVE_ONBOARDING_STEPPER, }); - const { colors, themeAppearance } = useTheme(); - - const isStepperAnimationEnabled = useSelector( - selectMoneyOnboardingStepperAnimationEnabled, - ); - - const tw = useTailwind(); + const { apyPercent } = useMoneyAccountBalance(); - const isDarkTheme = themeAppearance === AppThemeKey.dark; + const [ref, riveRef] = useRive(); - const progressBarColor = isDarkTheme - ? colors.primary.default - : colors.primary.inverse; + const stepRef = useRef(0); - // Title and text color - const textColor = isDarkTheme - ? TextColor.TextDefault - : TextColor.PrimaryInverse; + // --- Text runs (stepText1–4: title, content, footer) --- + const [, setStep1Title] = useRiveString(riveRef, 'stepText1/title'); + const [, setStep1Content] = useRiveString(riveRef, 'stepText1/content'); + const [, setStep1Footer] = useRiveString(riveRef, 'stepText1/footer'); - const footerTextColor = isDarkTheme - ? TextColor.TextDefault - : TextColor.PrimaryInverse; + const [, setStep2Title] = useRiveString(riveRef, 'stepText2/title'); + const [, setStep2Content] = useRiveString(riveRef, 'stepText2/content'); + const [, setStep2Footer] = useRiveString(riveRef, 'stepText2/footer'); - const iconColor = isDarkTheme - ? IconColor.IconDefault - : IconColor.PrimaryInverse; + const [, setStep3Title] = useRiveString(riveRef, 'stepText3/title'); + const [, setStep3Content] = useRiveString(riveRef, 'stepText3/content'); + const [, setStep3Footer] = useRiveString(riveRef, 'stepText3/footer'); - const buttonIsInverse = !isDarkTheme; + const [, setStep4Title] = useRiveString(riveRef, 'stepText4/title'); + const [, setStep4Content] = useRiveString(riveRef, 'stepText4/content'); + const [, setStep4Footer] = useRiveString(riveRef, 'stepText4/footer'); - const { apyPercent } = useMoneyAccountBalance(); + // --- Number inputs --- + const [, setTransitionSpeed] = useRiveNumber(riveRef, 'transitionSpeed'); + const [, setCoinSeq] = useRiveNumber(riveRef, 'coinSeq'); + const [, setCardSeq] = useRiveNumber(riveRef, 'cardSeq'); - const steps: OnboardingStep[] = useMemo( - () => [ - { - title: strings('money.rive_onboarding.step1_title'), - body: strings('money.rive_onboarding.step1_body', { - percentage: apyPercent, - }), - footerText: strings('money.rive_onboarding.step1_footer_text'), - durationMs: MONEY_ONBOARDING_STEP_DURATION_MS, - buttonLabel: strings('money.rive_onboarding.continue'), - }, - { - title: strings('money.rive_onboarding.step2_title'), - body: strings('money.rive_onboarding.step2_body'), - footerText: strings('money.rive_onboarding.step2_footer_text'), - durationMs: MONEY_ONBOARDING_STEP_DURATION_MS, - buttonLabel: strings('money.rive_onboarding.continue'), - }, - { - title: strings('money.rive_onboarding.step3_title'), - body: strings('money.rive_onboarding.step3_body', { - percentage: CARD_CASHBACK_PERCENTAGE, - }), - footerText: strings('money.rive_onboarding.step3_footer_text'), - durationMs: MONEY_ONBOARDING_STEP_DURATION_MS, - buttonLabel: strings('money.rive_onboarding.continue'), - }, - { - title: strings('money.rive_onboarding.step4_title'), - body: strings('money.rive_onboarding.step4_body'), - footerText: strings('money.rive_onboarding.step4_footer_text'), - durationMs: MONEY_ONBOARDING_STEP_DURATION_MS, - buttonLabel: strings('money.rive_onboarding.continue'), - }, - { - durationMs: MONEY_ONBOARDING_STEP_DURATION_MS, - showCloseButton: false, - }, - ], - [apyPercent], - ); - - // Hardcoded to use English step titles to simplify event tracking. + // Hardcoded to English to simplify event tracking. const stepTitlesEnglish: string[] = useMemo( () => [ strings('money.rive_onboarding.step1_title', { locale: 'en' }), @@ -150,12 +108,65 @@ const MoneyOnboardingView = () => { [], ); + useEffect(() => { + if (!riveRef) return; + + // Step 1 + setStep1Title(strings('money.rive_onboarding.step1_title')); + setStep1Content( + strings('money.rive_onboarding.step1_body', { percentage: apyPercent }), + ); + setStep1Footer(strings('money.rive_onboarding.step1_footer_text')); + + // Step 2 + setStep2Title(strings('money.rive_onboarding.step2_title')); + setStep2Content(strings('money.rive_onboarding.step2_body')); + setStep2Footer(strings('money.rive_onboarding.step2_footer_text')); + + // Step 3 + setStep3Title(strings('money.rive_onboarding.step3_title')); + setStep3Content( + strings('money.rive_onboarding.step3_body', { + percentage: CARD_CASHBACK_PERCENTAGE, + }), + ); + setStep3Footer(strings('money.rive_onboarding.step3_footer_text')); + + // Step 4 + setStep4Title(strings('money.rive_onboarding.step4_title')); + setStep4Content(strings('money.rive_onboarding.step4_body')); + setStep4Footer(strings('money.rive_onboarding.step4_footer_text')); + + // Config + setTransitionSpeed(300); + setCoinSeq(0); + setCardSeq(0); + }, [ + riveRef, + apyPercent, + setStep1Title, + setStep1Content, + setStep1Footer, + setStep2Title, + setStep2Content, + setStep2Footer, + setStep3Title, + setStep3Content, + setStep3Footer, + setStep4Title, + setStep4Content, + setStep4Footer, + setTransitionSpeed, + setCoinSeq, + setCardSeq, + ]); + const handleClose = useCallback( (stepIndex: number) => { trackOnboardingEvent({ step: stepIndex + 1, // Use 1-based index for event tracking to match total_steps count. step_title: stepTitlesEnglish[stepIndex], - total_steps: steps.length, + total_steps: TOTAL_ONBOARDING_STEPS, step_action: MONEY_ONBOARDING_STEP_ACTIONS.EXITED, redirect_target: SCREEN_NAMES.MONEY_HOME, }); @@ -166,13 +177,7 @@ const MoneyOnboardingView = () => { params: { screen: Routes.MONEY.HOME }, }); }, - [ - dispatch, - navigation, - stepTitlesEnglish, - steps.length, - trackOnboardingEvent, - ], + [dispatch, navigation, stepTitlesEnglish, trackOnboardingEvent], ); const handleStepViewed = useCallback( @@ -180,12 +185,12 @@ const MoneyOnboardingView = () => { trackOnboardingEvent({ step: stepIndex + 1, // Use 1-based index for event tracking to match total_steps count. step_title: stepTitlesEnglish[stepIndex], - total_steps: steps.length, + total_steps: TOTAL_ONBOARDING_STEPS, step_action: MONEY_ONBOARDING_STEP_ACTIONS.VIEWED, redirect_target: SCREEN_NAMES.MONEY_ONBOARDING, }); }, - [stepTitlesEnglish, steps.length, trackOnboardingEvent], + [stepTitlesEnglish, trackOnboardingEvent], ); const handleComplete = useCallback( @@ -194,7 +199,7 @@ const MoneyOnboardingView = () => { trackOnboardingEvent({ step: stepIndex + 1, // Use 1-based index for event tracking to match total_steps count. step_title: stepTitlesEnglish[stepIndex], - total_steps: steps.length, + total_steps: TOTAL_ONBOARDING_STEPS, step_action: MONEY_ONBOARDING_STEP_ACTIONS.COMPLETED, redirect_target: SCREEN_NAMES.MONEY_HOME, }); @@ -204,45 +209,40 @@ const MoneyOnboardingView = () => { params: { screen: Routes.MONEY.HOME }, }); }, - [ - dispatch, - navigation, - stepTitlesEnglish, - steps.length, - trackOnboardingEvent, - ], + [dispatch, navigation, stepTitlesEnglish, trackOnboardingEvent], ); - const renderBackground = useCallback( - () => ( - - ), - [tw], + useRiveTrigger(riveRef, CLOSE_TRIGGER, () => { + handleClose(stepRef.current); + }); + + const handleStateChanged = useCallback( + (_stateMachineName: string, stateName: string) => { + const stepIndex = RIVE_STATE_TO_STEP_INDEX[stateName]; + + if (stepIndex !== undefined) { + stepRef.current = stepIndex; + handleStepViewed(stepIndex); + } + + if (stateName === RIVE_STEP_NAMES.FINAL_STATE) { + handleComplete(stepRef.current); + } + }, + [handleStepViewed, handleComplete], ); return ( - ); }; From c56cd05b11f0b1a20941ae062efc487542ce80bd Mon Sep 17 00:00:00 2001 From: Davide Brocchetto Date: Tue, 16 Jun 2026 04:50:27 -0700 Subject: [PATCH 02/23] fix: fix Snap E2E tests flakiness (#31745) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The snap management tests (disable, enable, remove) were failing at times in the pipeline because `tapSettings()` has a nested retry loop that fights itself under `disableSynchronization: true`— once the account menu overlay opens, the tab bar is hidden, and retries can never recover. Replaced with a step-by-step navigation helper that uses explicit waits between each tap. ## **Changelog** CHANGELOG entry: ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- .../smoke/snaps/test-snap-management.spec.ts | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/tests/smoke/snaps/test-snap-management.spec.ts b/tests/smoke/snaps/test-snap-management.spec.ts index 78ec735392e..dc9c3a344fa 100644 --- a/tests/smoke/snaps/test-snap-management.spec.ts +++ b/tests/smoke/snaps/test-snap-management.spec.ts @@ -10,6 +10,28 @@ import SnapSettingsView from '../../page-objects/Settings/SnapSettingsView'; import { Assertions } from '../../framework'; import BrowserView from '../../page-objects/Browser/BrowserView'; import AccountMenu from '../../page-objects/AccountMenu/AccountMenu'; +import WalletView from '../../page-objects/wallet/WalletView'; + +/** + * Navigate from the browser to Snap Settings. + * With disableSynchronization the tab bar may not be immediately available + * after closing the browser, so we navigate step-by-step with explicit waits. + */ +async function navigateFromBrowserToSnapSettings() { + await BrowserView.tapCloseBrowserButton(); + await TabBarComponent.tapWallet(); + await WalletView.tapHamburgerMenu(); + await Assertions.expectElementToBeVisible(AccountMenu.container, { + timeout: 10000, + description: 'Account menu should be visible', + }); + await AccountMenu.tapSettings(); + await Assertions.expectElementToBeVisible(SettingsView.title, { + timeout: 10000, + description: 'Settings view title should be visible', + }); + await SettingsView.tapSnaps(); +} jest.setTimeout(150_000); @@ -40,9 +62,7 @@ describe(SmokeSnaps('Snap Management Tests'), () => { disableSynchronization: true, }, async () => { - await BrowserView.tapCloseBrowserButton(); - await TabBarComponent.tapSettings(); - await SettingsView.tapSnaps(); + await navigateFromBrowserToSnapSettings(); await SnapSettingsView.selectSnap('Dialog Example Snap'); await SnapSettingsView.toggleEnable(); @@ -73,9 +93,7 @@ describe(SmokeSnaps('Snap Management Tests'), () => { disableSynchronization: true, }, async () => { - await BrowserView.tapCloseBrowserButton(); - await TabBarComponent.tapSettings(); - await SettingsView.tapSnaps(); + await navigateFromBrowserToSnapSettings(); await SnapSettingsView.selectSnap('Dialog Example Snap'); await SnapSettingsView.toggleEnable(); @@ -107,9 +125,7 @@ describe(SmokeSnaps('Snap Management Tests'), () => { disableSynchronization: true, }, async () => { - await BrowserView.tapCloseBrowserButton(); - await TabBarComponent.tapSettings(); - await SettingsView.tapSnaps(); + await navigateFromBrowserToSnapSettings(); await SnapSettingsView.selectSnap('Dialog Example Snap'); await SnapSettingsView.removeSnap(); From 716f9a85a004fe0b8c348fcdc6c95be4a32dc23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Tani=C3=A7a?= Date: Tue, 16 Jun 2026 07:51:52 -0400 Subject: [PATCH 03/23] perf(predict): fix JS-thread FPS collapse on market details with live prices cp-7.82.0 (#31801) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR fixes severe JS-thread performance degradation on the Predict market details screen (`PredictMarketDetails` / `PredictGameDetailsContent`). When opening a market with a live price feed — most noticeably a live soccer game — the JS thread FPS would collapse to near 0, making the screen unusable. **Reason for the change:** The live Polymarket WebSocket price stream drives high-frequency updates. The code was (1) doing an `O(subscriptions × tokens)` `new Set(key.split(','))` allocation on *every* incoming price message, and (2) re-rendering the entire details screen on every single message because nothing was throttled or memoized. Profiling showed `performWorkOnRoot` (React render) consuming ~70% of the trace, with `new Set()`/`Object.assign`/`JSON.stringify` allocation churn dominating self-time. **Improvements:** - **`WebSocketManager`** - Precompute the parsed `Set` per subscription once at subscribe time instead of rebuilding it (`new Set(key.split(','))`) on every message. This removes the single largest self-time hotspot. - Coalesce/throttle price emission with a leading + trailing edge (250ms, mirroring the existing orderbook throttle) so subscribers are notified at most ~4×/sec instead of at the full WebSocket message rate. - Clean up the new timer/buffer/Set state on disconnect and full cleanup. - **`useLiveMarketPrices`** — skip the state update entirely when an incoming tick carries no actual value change (`price`/`bestBid`/`bestAsk`), preventing redundant re-renders. - **`usePredictPrices`** — memoize the per-render `JSON.stringify(queries)` so it only runs when the queries change. - **`useOpenOutcomes`** - Disable the live price subscription for game markets, where its result is never rendered (the game branch runs its own subscriptions). Removed a redundant full-screen re-render source. - Preserve object identity for outcomes/tokens whose computed price did not change, so only rows that actually changed get a new reference. - **`PredictMarketDetails`** — memoize `handleBackPress`/`handleBuyPress`/`handleClaimPress` so stable callbacks no longer defeat child memoization. - **`PredictGameDetailsContent`** and **`PredictMarketOutcome`** — wrap in `React.memo` so a parent re-render no longer re-renders these subtrees/rows when their props are unchanged. **Result:** JS-thread FPS went from ~0 → mid-50s on live game events, and regular markets from ~25–35 → comparable smoothness, with re-renders now scoped to the components whose data actually changed. ## **Changelog** CHANGELOG entry: Fixed severe performance degradation on the Predict market details screen for markets with live price updates. ## **Related issues** Fixes: [PRED-1014](https://consensyssoftware.atlassian.net/browse/PRED-1014) ## **Manual testing steps** ```gherkin Feature: Predict market details performance with live prices Scenario: user opens a live game market Given a live soccer game market is available in Predict And the JS-thread FPS monitor / performance overlay is enabled When the user opens the PredictGameDetailsContent screen Then the screen remains responsive And the JS-thread FPS stays in a healthy range (not collapsing toward 0) Scenario: user opens a regular market with live prices Given a regular open market with live price updates is available in Predict When the user opens the PredictMarketDetails screen Then the outcomes list updates live without re-rendering unchanged rows And the JS-thread FPS stays in a healthy range Scenario: live prices still update correctly Given the user is on a market details screen When the underlying token prices change over the WebSocket feed Then the displayed prices/odds update to reflect the new values ``` ## **Screenshots/Recordings** ### **Before** https://github.com/user-attachments/assets/1cc444f5-a693-4584-80f8-072305a3147c ### **After** https://github.com/user-attachments/assets/1fe95b3c-1fb4-4fa0-a794-8450cbe08f88 ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. [PRED-1014]: https://consensyssoftware.atlassian.net/browse/PRED-1014?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ --- .../PredictGameDetailsContent.tsx | 12 +- .../PredictMarketOutcome.tsx | 9 +- .../UI/Predict/hooks/useLiveMarketPrices.ts | 24 ++++ .../UI/Predict/hooks/usePredictPrices.tsx | 7 +- .../polymarket/WebSocketManager.test.ts | 5 +- .../providers/polymarket/WebSocketManager.ts | 121 ++++++++++++++---- .../PredictMarketDetails.tsx | 102 +++++++++------ .../hooks/useOpenOutcomes.ts | 82 +++++++++--- 8 files changed, 264 insertions(+), 98 deletions(-) diff --git a/app/components/UI/Predict/components/PredictGameDetailsContent/PredictGameDetailsContent.tsx b/app/components/UI/Predict/components/PredictGameDetailsContent/PredictGameDetailsContent.tsx index 566c9b8f785..9aae867b225 100644 --- a/app/components/UI/Predict/components/PredictGameDetailsContent/PredictGameDetailsContent.tsx +++ b/app/components/UI/Predict/components/PredictGameDetailsContent/PredictGameDetailsContent.tsx @@ -12,7 +12,7 @@ import { TextVariant, } from '@metamask/design-system-react-native'; import { useTailwind } from '@metamask/design-system-twrnc-preset'; -import React, { useCallback, useMemo } from 'react'; +import React, { memo, useCallback, useMemo } from 'react'; import { Pressable, RefreshControl, ScrollView } from 'react-native'; import { SafeAreaView, @@ -37,7 +37,9 @@ import { PREDICT_GAME_DETAILS_CONTENT_TEST_IDS } from './PredictGameDetailsConte const CHIPS_STICKY_INDEX = 2; -const PredictGameDetailsContent: React.FC = ({ +const PredictGameDetailsContentComponent: React.FC< + PredictGameDetailsContentProps +> = ({ market, onBack, onRefresh, @@ -231,4 +233,10 @@ const PredictGameDetailsContent: React.FC = ({ ); }; +// Memoized so a parent (PredictMarketDetails) re-render driven by its own live +// subscriptions does not re-render this entire subtree when our props are +// unchanged. The screen's live odds updates are driven by this component's own +// hooks instead. +const PredictGameDetailsContent = memo(PredictGameDetailsContentComponent); + export default PredictGameDetailsContent; diff --git a/app/components/UI/Predict/components/PredictMarketOutcome/PredictMarketOutcome.tsx b/app/components/UI/Predict/components/PredictMarketOutcome/PredictMarketOutcome.tsx index a341bbc9024..8a2dc2b8546 100644 --- a/app/components/UI/Predict/components/PredictMarketOutcome/PredictMarketOutcome.tsx +++ b/app/components/UI/Predict/components/PredictMarketOutcome/PredictMarketOutcome.tsx @@ -8,7 +8,7 @@ import { } from '@metamask/design-system-react-native'; import { useTailwind } from '@metamask/design-system-twrnc-preset'; import { NavigationProp, useNavigation } from '@react-navigation/native'; -import React from 'react'; +import React, { memo } from 'react'; import { Image, View } from 'react-native'; import { strings } from '../../../../../../locales/i18n'; import Button, { @@ -50,7 +50,7 @@ interface PredictMarketOutcomeProps { const MAX_LABEL_LENGTH = 6; -const PredictMarketOutcome: React.FC = ({ +const PredictMarketOutcomeComponent: React.FC = ({ market, outcome, entryPoint = PredictEventValues.ENTRY_POINT.PREDICT_FEED, @@ -221,4 +221,9 @@ const PredictMarketOutcome: React.FC = ({ ); }; +// Memoized so that in a live-updating outcomes list only the rows whose +// `outcome` reference actually changed re-render. Relies on useOpenOutcomes +// preserving identity for unchanged outcomes/tokens. +const PredictMarketOutcome = memo(PredictMarketOutcomeComponent); + export default PredictMarketOutcome; diff --git a/app/components/UI/Predict/hooks/useLiveMarketPrices.ts b/app/components/UI/Predict/hooks/useLiveMarketPrices.ts index f8d1dc28b98..83069342a37 100644 --- a/app/components/UI/Predict/hooks/useLiveMarketPrices.ts +++ b/app/components/UI/Predict/hooks/useLiveMarketPrices.ts @@ -74,6 +74,10 @@ export const useLiveMarketPrices = ( const isMountedRef = useRef(true); const tokenIdsRef = useRef(tokenIds); + // Mirrors the latest `prices` map so we can detect no-op ticks without + // adding `prices` to `handlePriceUpdates`' dependencies. Kept in sync inside + // every state updater below. + const pricesRef = useRef(prices); // Use JSON.stringify to avoid key collisions if token IDs contain commas const tokenIdsKey = useMemo( @@ -95,11 +99,30 @@ export const useLiveMarketPrices = ( liveMarketPriceCache.set(update.tokenId, { price: update, updatedAt }); }); + // Skip the state update entirely when none of the incoming values differ + // from what we already have. This prevents a re-render of the whole + // subscriber tree for redundant ticks that carry no visible change. + const current = pricesRef.current; + const hasChange = updates.some((update) => { + const existing = current.get(update.tokenId); + return ( + !existing || + existing.price !== update.price || + existing.bestBid !== update.bestBid || + existing.bestAsk !== update.bestAsk + ); + }); + + if (!hasChange) { + return; + } + setPrices((prevPrices) => { const newPrices = new Map(prevPrices); updates.forEach((update) => { newPrices.set(update.tokenId, update); }); + pricesRef.current = newPrices; return newPrices; }); @@ -125,6 +148,7 @@ export const useLiveMarketPrices = ( nextPrices.set(tokenId, cachedPrice); } }); + pricesRef.current = nextPrices; return nextPrices; }); diff --git a/app/components/UI/Predict/hooks/usePredictPrices.tsx b/app/components/UI/Predict/hooks/usePredictPrices.tsx index eb448292ee4..1db1343abda 100644 --- a/app/components/UI/Predict/hooks/usePredictPrices.tsx +++ b/app/components/UI/Predict/hooks/usePredictPrices.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react'; +import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import Engine from '../../../../core/Engine'; import Logger from '../../../../util/Logger'; import { DevLogger } from '../../../../core/SDKConnect/utils/DevLogger'; @@ -62,7 +62,10 @@ export const usePredictPrices = ( } }, [enabled]); - const queriesKey = JSON.stringify(queries); + // Memoize so the (potentially large) serialization only runs when the + // queries array identity actually changes, not on every re-render driven + // by live price ticks. + const queriesKey = useMemo(() => JSON.stringify(queries), [queries]); const fetchPrices = useCallback(async () => { if (!enabled) { diff --git a/app/components/UI/Predict/providers/polymarket/WebSocketManager.test.ts b/app/components/UI/Predict/providers/polymarket/WebSocketManager.test.ts index d2391b5037f..f3de4a40c7a 100644 --- a/app/components/UI/Predict/providers/polymarket/WebSocketManager.test.ts +++ b/app/components/UI/Predict/providers/polymarket/WebSocketManager.test.ts @@ -2335,6 +2335,9 @@ describe('WebSocketManager', () => { ], timestamp: '2025-01-12T12:00:01Z', }); + // Price emission is throttled: the first message flushes immediately + // (leading edge) and the second is coalesced into the trailing flush. + jest.advanceTimersByTime(250); expect(throwingCallback).toHaveBeenCalledTimes(2); expect(healthyCallback).toHaveBeenCalledTimes(2); @@ -2378,7 +2381,7 @@ describe('WebSocketManager', () => { context: { name: 'WebSocketManager', data: { - method: 'handleMarketMessage', + method: 'flushMarketPriceUpdates', subscriptionKey: 'token1', }, }, diff --git a/app/components/UI/Predict/providers/polymarket/WebSocketManager.ts b/app/components/UI/Predict/providers/polymarket/WebSocketManager.ts index 9697c5a3312..536e0b00ec4 100644 --- a/app/components/UI/Predict/providers/polymarket/WebSocketManager.ts +++ b/app/components/UI/Predict/providers/polymarket/WebSocketManager.ts @@ -40,6 +40,7 @@ const RTDS_CRYPTO_PRICES_CHAINLINK_TOPIC = 'crypto_prices_chainlink'; const RTDS_PING_INTERVAL_MS = 5000; const DEFAULT_THROTTLE_INTERVAL_MS = 16; const ORDERBOOK_EMIT_THROTTLE_MS = 250; +const MARKET_PRICE_EMIT_THROTTLE_MS = 250; const HEARTBEAT_CHECK_INTERVAL_MS = 5000; const MARKET_STALE_THRESHOLD_MS = 60000; @@ -107,7 +108,16 @@ export class WebSocketManager { private gameSubscriptions: Map> = new Map(); private priceSubscriptions: Map> = new Map(); + // Parsed token-id set per subscription key, precomputed once at subscribe + // time so the high-frequency message handler never re-runs + // `key.split(',')` + `new Set(...)` per message. + private priceSubscriptionTokenSets: Map> = new Map(); private marketPriceCache: Map = new Map(); + // Coalesced price emission: token ids that changed since the last flush, plus + // the leading/trailing throttle timer. Avoids re-rendering subscribers at the + // full WebSocket message rate. + private marketPricePendingTokenIds: Set = new Set(); + private marketPriceEmitTimer: ReturnType | null = null; private orderbookSubscriptions: Map> = new Map(); private orderbookState: Map< @@ -431,6 +441,10 @@ export class WebSocketManager { if (!callbacks) { callbacks = new Set(); this.priceSubscriptions.set(subscriptionKey, callbacks); + this.priceSubscriptionTokenSets.set( + subscriptionKey, + new Set(subscriptionKey.split(',').filter(Boolean)), + ); } callbacks.add(callback); @@ -471,6 +485,7 @@ export class WebSocketManager { subscriptionCallbacks.delete(callback); if (subscriptionCallbacks.size === 0) { this.priceSubscriptions.delete(subscriptionKey); + this.priceSubscriptionTokenSets.delete(subscriptionKey); const remainingPriceTokenIds = this.getSubscribedMarketTokenIds(); const tokenIdsToUnsubscribe = tokenIds.filter( (tokenId) => @@ -626,6 +641,74 @@ export class WebSocketManager { }; } + /** + * Throttle market price fan-out with a leading + trailing edge, mirroring + * {@link scheduleOrderbookEmit}. The first change in a window is delivered + * immediately; subsequent changes within the window are batched and flushed + * once when the window closes. + */ + private scheduleMarketPriceEmit(): void { + if (this.marketPriceEmitTimer === null) { + this.flushMarketPriceUpdates(); + this.marketPriceEmitTimer = setTimeout(() => { + this.marketPriceEmitTimer = null; + if (this.marketPricePendingTokenIds.size > 0) { + this.flushMarketPriceUpdates(); + } + }, MARKET_PRICE_EMIT_THROTTLE_MS); + } + } + + private flushMarketPriceUpdates(): void { + if (this.marketPricePendingTokenIds.size === 0) { + return; + } + + const changedTokenIds = this.marketPricePendingTokenIds; + this.marketPricePendingTokenIds = new Set(); + + this.priceSubscriptions.forEach((callbacks, key) => { + if (callbacks.size === 0) { + return; + } + const subscribedTokenIds = this.priceSubscriptionTokenSets.get(key); + if (!subscribedTokenIds) { + return; + } + + const relevantUpdates: PriceUpdate[] = []; + changedTokenIds.forEach((tokenId) => { + if (subscribedTokenIds.has(tokenId)) { + const cached = this.marketPriceCache.get(tokenId); + if (cached) { + relevantUpdates.push(cached); + } + } + }); + + if (relevantUpdates.length === 0) { + return; + } + + callbacks.forEach((callback) => { + try { + callback(relevantUpdates); + } catch (error) { + DevLogger.log('WebSocketManager: Market price subscriber failed', { + error, + subscriptionKey: key, + }); + Logger.error( + this.toError(error), + this.getErrorContext('flushMarketPriceUpdates', 'market', { + subscriptionKey: key, + }), + ); + } + }); + }); + } + private emitOrderbookSnapshot(tokenId: string): void { const cached = this.orderbookState.get(tokenId); const callbacks = this.orderbookSubscriptions.get(tokenId); @@ -821,36 +904,12 @@ export class WebSocketManager { updates.forEach((update) => { this.marketPriceCache.set(update.tokenId, update); + this.marketPricePendingTokenIds.add(update.tokenId); }); - this.priceSubscriptions.forEach((callbacks, key) => { - const subscribedTokenIds = new Set(key.split(',')); - const relevantUpdates = updates.filter((u) => - subscribedTokenIds.has(u.tokenId), - ); - - if (relevantUpdates.length > 0) { - callbacks.forEach((callback) => { - try { - callback(relevantUpdates); - } catch (error) { - DevLogger.log( - 'WebSocketManager: Market price subscriber failed', - { - error, - subscriptionKey: key, - }, - ); - Logger.error( - this.toError(error), - this.getErrorContext('handleMarketMessage', 'market', { - subscriptionKey: key, - }), - ); - } - }); - } - }); + // Coalesce emission instead of fanning out synchronously on every + // message. Live odds stream far faster than the UI needs to render. + this.scheduleMarketPriceEmit(); // Intentionally NOT forwarding `price_change` to orderbook subscribers. // The payload only carries `best_bid` / `best_ask` (no per-level @@ -1054,6 +1113,11 @@ export class WebSocketManager { this.cleanupMarketConnection(); this.marketReconnectAttempts = 0; this.marketPriceCache.clear(); + if (this.marketPriceEmitTimer) { + clearTimeout(this.marketPriceEmitTimer); + this.marketPriceEmitTimer = null; + } + this.marketPricePendingTokenIds.clear(); // Drop cached orderbook state so a future reconnect doesn't replay a // stale snapshot to subscribers. The provider's REST bootstrap and the // next live `book` event will repopulate. Also flush throttle timers so @@ -1456,6 +1520,7 @@ export class WebSocketManager { this.disconnectAll(); this.gameSubscriptions.clear(); this.priceSubscriptions.clear(); + this.priceSubscriptionTokenSets.clear(); this.cryptoPriceSubscriptions.clear(); this.marketPriceCache.clear(); this.orderbookSubscriptions.clear(); diff --git a/app/components/UI/Predict/views/PredictMarketDetails/PredictMarketDetails.tsx b/app/components/UI/Predict/views/PredictMarketDetails/PredictMarketDetails.tsx index 12c17dc506d..4e5c19c7f0b 100644 --- a/app/components/UI/Predict/views/PredictMarketDetails/PredictMarketDetails.tsx +++ b/app/components/UI/Predict/views/PredictMarketDetails/PredictMarketDetails.tsx @@ -228,69 +228,87 @@ const PredictMarketDetails: React.FC = () => { timeframes, } = useChartData({ market, hasAnyOutcomeToken }); + // The game branch (PredictGameDetailsContent) does not consume openOutcomes / + // yesPercentage and runs its own live price subscriptions internally. Keeping + // this hook live for game markets only adds a redundant high-frequency price + // subscription that re-renders this whole screen on every tick. const shouldRefreshOpenOutcomePrices = - market?.status === PredictMarketStatus.OPEN && !isBuySheetOpen; + market?.status === PredictMarketStatus.OPEN && + !isBuySheetOpen && + !market?.game; const { closedOutcomes, openOutcomes, yesPercentage } = useOpenOutcomes({ market, enabled: shouldRefreshOpenOutcomePrices, }); - const handleBackPress = () => { + const handleBackPress = useCallback(() => { if (navigation.canGoBack()) { navigation.goBack(); } else { // If we can't go back, navigate to the main predict screen navigation.navigate(Routes.PREDICT.ROOT); } - }; + }, [navigation]); - const handleBuyPress = ( - token: PredictOutcomeToken, - selectedMarket: typeof market = market, - ) => { - if (!selectedMarket) { - return; - } - executeGuardedAction( - () => { - const selectedOpenOutcomes = - selectedMarket.id === market?.id - ? openOutcomes - : selectedMarket.outcomes.filter( - (outcome) => outcome.status === OPEN_PREDICT_OUTCOME_STATUS, - ); - const matchingOutcome = - selectedMarket.outcomes.find((o) => - o.tokens.some((marketToken) => marketToken.id === token.id), - ) ?? - selectedOpenOutcomes[0] ?? - selectedMarket.outcomes?.[0]; - openBuySheet({ - market: selectedMarket, - outcome: matchingOutcome, - outcomeToken: token, - entryPoint: - entryPoint || PredictEventValues.ENTRY_POINT.PREDICT_MARKET_DETAILS, - ...(predictFeedTab && { predictFeedTab }), - ...(predictScreen && { predictScreen }), - ...(transactionActiveAbTests?.length && { transactionActiveAbTests }), - }); - }, - { - attemptedAction: PredictEventValues.ATTEMPTED_ACTION.PREDICT, - }, - ); - }; + const handleBuyPress = useCallback( + (token: PredictOutcomeToken, selectedMarket: typeof market = market) => { + if (!selectedMarket) { + return; + } + executeGuardedAction( + () => { + const selectedOpenOutcomes = + selectedMarket.id === market?.id + ? openOutcomes + : selectedMarket.outcomes.filter( + (outcome) => outcome.status === OPEN_PREDICT_OUTCOME_STATUS, + ); + const matchingOutcome = + selectedMarket.outcomes.find((o) => + o.tokens.some((marketToken) => marketToken.id === token.id), + ) ?? + selectedOpenOutcomes[0] ?? + selectedMarket.outcomes?.[0]; + openBuySheet({ + market: selectedMarket, + outcome: matchingOutcome, + outcomeToken: token, + entryPoint: + entryPoint || + PredictEventValues.ENTRY_POINT.PREDICT_MARKET_DETAILS, + ...(predictFeedTab && { predictFeedTab }), + ...(predictScreen && { predictScreen }), + ...(transactionActiveAbTests?.length && { + transactionActiveAbTests, + }), + }); + }, + { + attemptedAction: PredictEventValues.ATTEMPTED_ACTION.PREDICT, + }, + ); + }, + [ + executeGuardedAction, + openOutcomes, + market, + openBuySheet, + entryPoint, + predictFeedTab, + predictScreen, + transactionActiveAbTests, + ], + ); - const handleClaimPress = async () => { + const handleClaimPress = useCallback(async () => { await executeGuardedAction( async () => { await claim(); }, { attemptedAction: PredictEventValues.ATTEMPTED_ACTION.CLAIM }, ); - }; + }, [executeGuardedAction, claim]); const handleTabPress = (tabIndex: number) => { if (!tabsReady) return; diff --git a/app/components/UI/Predict/views/PredictMarketDetails/hooks/useOpenOutcomes.ts b/app/components/UI/Predict/views/PredictMarketDetails/hooks/useOpenOutcomes.ts index 2a2f9369a7a..d54a9f6ff47 100644 --- a/app/components/UI/Predict/views/PredictMarketDetails/hooks/useOpenOutcomes.ts +++ b/app/components/UI/Predict/views/PredictMarketDetails/hooks/useOpenOutcomes.ts @@ -1,4 +1,4 @@ -import { useMemo } from 'react'; +import { useMemo, useRef } from 'react'; import { usePredictPrices } from '../../../hooks/usePredictPrices'; import { useLiveMarketPrices } from '../../../hooks/useLiveMarketPrices'; import { getPredictBuyPrice } from '../../../utils/prices'; @@ -56,34 +56,74 @@ export const useOpenOutcomes = ({ ? priceQueries : EMPTY_PRICE_QUERIES; - const { prices } = usePredictPrices({ - queries: activePriceQueries, - enabled: shouldFetchPrices, - pollingInterval: shouldFetchPrices ? 2000 : undefined, - }); - const tokenIds = useMemo( () => activePriceQueries.map((q) => q.outcomeTokenId), [activePriceQueries], ); - const { getPrice: getLivePrice } = useLiveMarketPrices(tokenIds, { + const { getPrice: getLivePrice, isConnected: isLiveConnected } = + useLiveMarketPrices(tokenIds, { + enabled: shouldFetchPrices, + }); + + // The live WebSocket feed is the primary source of truth for prices. When it + // is connected we only keep a slow REST poll as a freshness fallback; this + // avoids both sources driving full re-renders at the same time. + const { prices } = usePredictPrices({ + queries: activePriceQueries, enabled: shouldFetchPrices, + pollingInterval: shouldFetchPrices + ? isLiveConnected + ? 10000 + : 2000 + : undefined, }); + const previousOpenOutcomesRef = useRef([]); + const previousOpenOutcomesBaseRef = useRef(null); + // Price precedence: live WebSocket bestAsk > REST buy price > base market price. - const openOutcomes = useMemo( - () => - openOutcomesBase.map((outcome) => ({ - ...outcome, - tokens: outcome.tokens.map((token) => ({ - ...token, - price: - getPredictBuyPrice(token, getLivePrice(token.id), prices) ?? - token.price, - })), - })), - [openOutcomesBase, prices, getLivePrice], - ); + // + // Identity preservation: rebuilding every outcome/token object on each price + // tick gives all of them new references, which forces every (memoized) row to + // re-render even when only one token's price changed. Here we reuse the + // previous token/outcome object whenever the computed price is unchanged, so + // only the rows that actually changed get a new reference. When the base + // market data changes (different array identity), we rebuild from scratch. + const openOutcomes = useMemo(() => { + const baseUnchanged = + previousOpenOutcomesBaseRef.current === openOutcomesBase; + const previousById = baseUnchanged + ? new Map(previousOpenOutcomesRef.current.map((o) => [o.id, o])) + : undefined; + + const next = openOutcomesBase.map((outcome) => { + const previousOutcome = previousById?.get(outcome.id); + let changed = !previousOutcome; + + const tokens = outcome.tokens.map((token) => { + const price = + getPredictBuyPrice(token, getLivePrice(token.id), prices) ?? + token.price; + const previousToken = previousOutcome?.tokens.find( + (t) => t.id === token.id, + ); + if (previousToken && previousToken.price === price) { + return previousToken; + } + changed = true; + return { ...token, price }; + }); + + if (previousOutcome && !changed) { + return previousOutcome; + } + return { ...outcome, tokens }; + }); + + previousOpenOutcomesRef.current = next; + previousOpenOutcomesBaseRef.current = openOutcomesBase; + return next; + }, [openOutcomesBase, prices, getLivePrice]); const yesPercentage = useMemo((): number => { // Use real-time price if available from open outcomes From 6563eacbe6d8f7eb6201b0b79cbe351a3f343e30 Mon Sep 17 00:00:00 2001 From: Bruno Nascimento Date: Tue, 16 Jun 2026 09:16:38 -0300 Subject: [PATCH 04/23] feat(card): block Money Account -> card linking in restricted residency regions (#31763) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Cardholders whose residency falls in a geo-restricted region must not be able to link their Money Account to the MetaMask Card. Previously the linkage flow had no residency gating, so users in blocked countries/states could attempt (and surface UI for) Money Account card linkage. This PR adds residency-based blocking for Money Account ↔ card linkage: - **Residency capture**: `BaanxProvider` now maps `countryOfResidence` and `usState` from the `/v1/user` KYC payload onto `CardAccountStatus` (normalized to uppercase), and these fields are added to the `CardAccountStatus` type. - **Residency utils** (`app/components/UI/Card/util/residency.ts`): `buildCardResidencyRegion` derives a region code, using the `US-{STATE}` pattern (e.g. `US-CA`) for US residents so blocked lists can target specific states. `isCardResidencyInBlockedRegions` matches a region against a blocked list and **fails open** when residency is unknown. - **Selectors** (`app/selectors/cardController.ts`): adds `selectCardCountryOfResidence`, `selectCardUsState`, `selectCardResidencyRegion`, and `selectIsCardResidencyBlocked`, reusing the existing mUSD conversion blocked-region flag (`selectMusdConversionBlockedCountries`). `selectCardAvailableTokens` now suppresses Money Account placeholder funding entries when residency is blocked (active funding rows are preserved). - **Linkage hook** (`useMoneyAccountCardLinkage`): exposes `isResidencyBlocked`, forces `canLink=false`, and fails closed across `openLinkCardSheet`, `startLinkFlow`, the post-auth pending-link effect, and `confirmLinkInBackground`. Each blocked path tracks `CARD_MONEY_ACCOUNT_LINKING_FAILED` with the new `RESIDENCY_BLOCKED` reason. - **UI**: `MoneyHomeView` hides the card section (link/upsell) when residency is blocked while still showing `manage` mode for already-linked cards. `MoneyOnboardingCard` auto-completes/skips the card step when residency is blocked and the card is not already linked. ## **Changelog** CHANGELOG entry: Blocked Money Account to MetaMask Card linkage for cardholders in geo-restricted residency regions. ## **Related issues** Fixes: CARD-413 ## **Manual testing steps** ```gherkin Feature: Money Account card linkage residency blocking Scenario: Cardholder in a blocked region cannot link their Money Account Given a cardholder whose KYC residency is in a blocked region (e.g. country "GB" or state "US-CA") And the blocked region is present in the mUSD conversion blocked-region list When the user opens the Money home screen Then the MetaMask Card link/upsell section is hidden And the Money Account funding placeholder is not shown in the card funding list Scenario: Blocked cardholder attempting to link fails closed Given a cardholder whose residency is blocked When the user triggers the link card flow Then no navigation or delegation occurs And an error toast is shown And a CARD_MONEY_ACCOUNT_LINKING_FAILED event is tracked with reason "RESIDENCY_BLOCKED" Scenario: Already-linked card remains manageable in a blocked region Given a cardholder whose residency is blocked And the card is already linked to the Money Account When the user opens the Money home screen Then the card section is shown in "manage" mode Scenario: Cardholder in an allowed region can link normally Given a cardholder whose residency is not in any blocked region When the user opens the Money home screen and starts the link flow Then the link flow proceeds as before ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- .../hooks/useMoneyAccountCardLinkage.test.tsx | 105 +++++++ .../Card/hooks/useMoneyAccountCardLinkage.tsx | 62 ++++- app/components/UI/Card/util/metrics.ts | 1 + app/components/UI/Card/util/residency.test.ts | 52 ++++ app/components/UI/Card/util/residency.ts | 41 +++ .../MoneyHomeView/MoneyHomeView.test.tsx | 55 ++++ .../Views/MoneyHomeView/MoneyHomeView.tsx | 3 + .../MoneyOnboardingCard.test.tsx | 36 +++ .../MoneyOnboardingCard.tsx | 13 +- .../card-controller/provider-types.ts | 2 + .../providers/BaanxProvider.test.ts | 44 +++ .../providers/BaanxProvider.ts | 4 + app/selectors/cardController.test.ts | 263 +++++++++++++++++- app/selectors/cardController.ts | 47 +++- 14 files changed, 718 insertions(+), 10 deletions(-) create mode 100644 app/components/UI/Card/util/residency.test.ts create mode 100644 app/components/UI/Card/util/residency.ts diff --git a/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.test.tsx b/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.test.tsx index 5aab04e3b2b..8a8b9655343 100644 --- a/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.test.tsx +++ b/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.test.tsx @@ -15,6 +15,7 @@ import { selectIsCardholder, selectIsMoneyAccountCardLinkInProgress, selectIsMoneyAccountDelegatedForCard, + selectIsCardResidencyBlocked, selectMoneyAccountVedaTokenConfig, } from '../../../../selectors/cardController'; import { @@ -169,6 +170,7 @@ const buildSelectors = ( moneyAccountCardLinkInProgress?: boolean; cardFeatureFlag?: unknown; vedaConfig?: unknown; + isResidencyBlocked?: boolean; } = {}, ) => ({ primaryMoneyAccount: { address: MONEY_ACCOUNT_ADDRESS }, @@ -205,6 +207,7 @@ const buildSelectors = ( decimals: 6, delegationContract: '0xdelegation', }, + isResidencyBlocked: false, ...overrides, }); @@ -232,6 +235,8 @@ const applySelectorMocks = (state: ReturnType) => { return (_chainId: string) => state.isMonadSponsorshipEnabled; if (selector === selectCardFeatureFlag) return state.cardFeatureFlag; if (selector === selectMoneyAccountVedaTokenConfig) return state.vedaConfig; + if (selector === selectIsCardResidencyBlocked) + return state.isResidencyBlocked; return undefined; }); }; @@ -423,6 +428,19 @@ describe('useMoneyAccountCardLinkage', () => { expect(result.current.canLink).toBe(false); }); + it('reports canLink=false when card residency is blocked', () => { + applySelectorMocks(buildSelectors({ isResidencyBlocked: true })); + const { result } = renderLinkageHook(); + expect(result.current.canLink).toBe(false); + expect(result.current.isResidencyBlocked).toBe(true); + }); + + it('reports isResidencyBlocked=false when residency is not blocked', () => { + applySelectorMocks(buildSelectors({ isResidencyBlocked: false })); + const { result } = renderLinkageHook(); + expect(result.current.isResidencyBlocked).toBe(false); + }); + it('reports isLinking=true when controller linkage is in progress', () => { applySelectorMocks( buildSelectors({ moneyAccountCardLinkInProgress: true }), @@ -537,6 +555,28 @@ describe('useMoneyAccountCardLinkage', () => { expect(mockLinkMoneyAccountCard).not.toHaveBeenCalled(); expect(mockShowToast).toHaveBeenCalledTimes(1); }); + + it('tracks RESIDENCY_BLOCKED and fails closed when residency is blocked', () => { + applySelectorMocks(buildSelectors({ isResidencyBlocked: true })); + const { result } = renderLinkageHook(); + + act(() => { + result.current.openLinkCardSheet(CardEntryPoint.MONEY_LINK_CARD_SHEET); + }); + + expect(mockNavigate).not.toHaveBeenCalled(); + expect(mockShowToast).toHaveBeenCalledTimes(1); + expect(mockTrackEvent).toHaveBeenCalledWith( + expect.objectContaining({ name: 'built-event' }), + ); + expect(mockAddProperties).toHaveBeenCalledWith( + expect.objectContaining({ + flow: CardFlow.MONEY_ACCOUNT_LINKAGE, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + entrypoint: CardEntryPoint.MONEY_LINK_CARD_SHEET, + }), + ); + }); }); describe('startLinkFlow (entrypoint branching)', () => { @@ -599,6 +639,29 @@ describe('useMoneyAccountCardLinkage', () => { expect(mockShowToast).toHaveBeenCalledTimes(1); }); + it('tracks RESIDENCY_BLOCKED and fails closed when residency is blocked', () => { + applySelectorMocks(buildSelectors({ isResidencyBlocked: true })); + const { result } = renderLinkageHook(); + + act(() => { + result.current.startLinkFlow({ + ...ORIGIN, + entrypoint: CardEntryPoint.MONEY_HOME_METAMASK_CARD, + }); + }); + + expect(mockNavigate).not.toHaveBeenCalled(); + expect(mockDispatch).not.toHaveBeenCalled(); + expect(mockShowToast).toHaveBeenCalledTimes(1); + expect(mockAddProperties).toHaveBeenCalledWith( + expect.objectContaining({ + flow: CardFlow.MONEY_ACCOUNT_LINKAGE, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + entrypoint: CardEntryPoint.MONEY_HOME_METAMASK_CARD, + }), + ); + }); + it('shows the error toast when Monad USDC cannot be resolved AND the user is authenticated', () => { mockResolveMoneyAccountCardToken.mockReturnValueOnce(null); const { result } = renderLinkageHook(); @@ -811,6 +874,29 @@ describe('useMoneyAccountCardLinkage', () => { expect(mockShowToast).not.toHaveBeenCalled(); }); + it('tracks RESIDENCY_BLOCKED, shows error toast, and clears the flag when residency is blocked after auth', () => { + applySelectorMocks( + buildSelectors({ + pendingMoneyAccountCardLink: CardEntryPoint.MONEY_LINK_CARD_SHEET, + isResidencyBlocked: true, + }), + ); + renderLinkageHook(); + + expect(mockDispatch).toHaveBeenCalledWith( + setPendingMoneyAccountCardLink(null), + ); + expect(mockNavigate).not.toHaveBeenCalled(); + expect(mockShowToast).toHaveBeenCalledTimes(1); + expect(mockAddProperties).toHaveBeenCalledWith( + expect.objectContaining({ + flow: CardFlow.MONEY_ACCOUNT_LINKAGE, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + entrypoint: CardEntryPoint.MONEY_LINK_CARD_SHEET, + }), + ); + }); + it('clears the flag silently when authenticated but requirements are missing', () => { applySelectorMocks( buildSelectors({ @@ -1139,6 +1225,25 @@ describe('useMoneyAccountCardLinkage', () => { }); }); + it('tracks RESIDENCY_BLOCKED when residency is blocked and user is not already delegated', async () => { + applySelectorMocks(buildSelectors({ isResidencyBlocked: true })); + const { result } = renderLinkageHook(); + + let returned: boolean | undefined; + await act(async () => { + returned = await result.current.confirmLinkInBackground(); + }); + + expect(returned).toBe(false); + expect(mockLinkMoneyAccountCard).not.toHaveBeenCalled(); + expect(mockAddProperties).toHaveBeenCalledWith({ + flow: CardFlow.MONEY_ACCOUNT_LINKAGE, + entrypoint: CardEntryPoint.MONEY_LINK_CARD_SHEET, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + is_revoke: false, + }); + }); + it('still submits the delegation when already delegated (Manage Limit update / revoke path)', async () => { applySelectorMocks(buildSelectors({ isAlreadyDelegated: true })); const { result } = renderLinkageHook(); diff --git a/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.tsx b/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.tsx index b806bd4f316..579b21614d0 100644 --- a/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.tsx +++ b/app/components/UI/Card/hooks/useMoneyAccountCardLinkage.tsx @@ -37,6 +37,7 @@ import { selectIsCardholder, selectIsMoneyAccountCardLinkInProgress, selectIsMoneyAccountDelegatedForCard, + selectIsCardResidencyBlocked, selectMoneyAccountVedaTokenConfig, } from '../../../../selectors/cardController'; import { @@ -85,6 +86,7 @@ export interface UseMoneyAccountCardLinkageReturn { primaryMoneyAccount: MoneyAccount | undefined; moneyAccountCardToken: CardFundingToken | null; canLink: boolean; + isResidencyBlocked: boolean; status: LinkageStatus; isLinking: boolean; @@ -134,6 +136,7 @@ export const useMoneyAccountCardLinkage = selectPendingMoneyAccountCardLink, ); const linkInProgress = useSelector(selectIsMoneyAccountCardLinkInProgress); + const isResidencyBlocked = useSelector(selectIsCardResidencyBlocked); const isMonadSponsorshipEnabled = useSelector( getGasFeesSponsoredNetworkEnabled, )(vaultConfig?.chainId ?? ''); @@ -170,7 +173,9 @@ export const useMoneyAccountCardLinkage = moneyAccountCardToken && isMonadSponsorshipEnabled, ); - const canLink = Boolean(canSubmitDelegation && !isAlreadyDelegated); + const canLink = Boolean( + canSubmitDelegation && !isAlreadyDelegated && !isResidencyBlocked, + ); const showPendingToast = useCallback( (isRevoke: boolean = false) => { @@ -283,6 +288,15 @@ export const useMoneyAccountCardLinkage = return; } if (!canLink || !primaryMoneyAccount?.address) { + if (isResidencyBlocked) { + trackMoneyAccountLinkingEvent( + MetaMetricsEvents.CARD_MONEY_ACCOUNT_LINKING_FAILED, + { + entrypoint: entrypoint ?? CardEntryPoint.MONEY_LINK_CARD_SHEET, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + }, + ); + } showErrorToast(); return; } @@ -299,6 +313,8 @@ export const useMoneyAccountCardLinkage = primaryMoneyAccount?.address, navigation, showErrorToast, + isResidencyBlocked, + trackMoneyAccountLinkingEvent, ], ); @@ -312,6 +328,18 @@ export const useMoneyAccountCardLinkage = return; } + if (isResidencyBlocked) { + trackMoneyAccountLinkingEvent( + MetaMetricsEvents.CARD_MONEY_ACCOUNT_LINKING_FAILED, + { + entrypoint: origin.entrypoint, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + }, + ); + showErrorToast(); + return; + } + if (isCardAuthenticated) { if (!isCardVerified) { return; @@ -363,10 +391,12 @@ export const useMoneyAccountCardLinkage = isCardVerified, isAlreadyDelegated, isCardholder, + isResidencyBlocked, openLinkCardSheet, showErrorToast, navigation, dispatch, + trackMoneyAccountLinkingEvent, ], ); @@ -389,6 +419,19 @@ export const useMoneyAccountCardLinkage = return; } + if (isResidencyBlocked) { + trackMoneyAccountLinkingEvent( + MetaMetricsEvents.CARD_MONEY_ACCOUNT_LINKING_FAILED, + { + entrypoint: pendingMoneyAccountCardLinkEntryPoint, + reason: CardLinkingFailureReason.RESIDENCY_BLOCKED, + }, + ); + dispatch(setPendingMoneyAccountCardLink(null)); + showErrorToast(); + return; + } + if (isAlreadyDelegated) { dispatch(setPendingMoneyAccountCardLink(null)); return; @@ -415,9 +458,12 @@ export const useMoneyAccountCardLinkage = moneyAccountCardToken, primaryMoneyAccount?.address, isAlreadyDelegated, + isResidencyBlocked, cardHomeDataStatus, openLinkCardSheet, dispatch, + showErrorToast, + trackMoneyAccountLinkingEvent, ]); const confirmLinkInBackground = useCallback( @@ -430,13 +476,20 @@ export const useMoneyAccountCardLinkage = const isRevoke = options?.delegationAmountHuman !== undefined && parseFloat(options.delegationAmountHuman) === 0; + const isBlockedByResidency = isResidencyBlocked && !isAlreadyDelegated; - if (!canSubmitDelegation || !primaryMoneyAccount?.address) { + if ( + !canSubmitDelegation || + !primaryMoneyAccount?.address || + isBlockedByResidency + ) { trackMoneyAccountLinkingEvent( MetaMetricsEvents.CARD_MONEY_ACCOUNT_LINKING_FAILED, { entrypoint, - reason: CardLinkingFailureReason.PRECONDITION_FAILED, + reason: isBlockedByResidency + ? CardLinkingFailureReason.RESIDENCY_BLOCKED + : CardLinkingFailureReason.PRECONDITION_FAILED, is_revoke: isRevoke, }, ); @@ -533,6 +586,8 @@ export const useMoneyAccountCardLinkage = showPendingToast, showSuccessToast, trackMoneyAccountLinkingEvent, + isResidencyBlocked, + isAlreadyDelegated, ], ); @@ -549,6 +604,7 @@ export const useMoneyAccountCardLinkage = primaryMoneyAccount, moneyAccountCardToken, canLink, + isResidencyBlocked, status, isLinking: linkInProgress, diff --git a/app/components/UI/Card/util/metrics.ts b/app/components/UI/Card/util/metrics.ts index be47f0305fb..c411fe0f5ae 100644 --- a/app/components/UI/Card/util/metrics.ts +++ b/app/components/UI/Card/util/metrics.ts @@ -93,6 +93,7 @@ enum CardFlow { enum CardLinkingFailureReason { PRECONDITION_FAILED = 'PRECONDITION_FAILED', + RESIDENCY_BLOCKED = 'RESIDENCY_BLOCKED', USER_CANCELLED = 'USER_CANCELLED', CONTROLLER_FAILED = 'CONTROLLER_FAILED', UNKNOWN = 'UNKNOWN', diff --git a/app/components/UI/Card/util/residency.test.ts b/app/components/UI/Card/util/residency.test.ts new file mode 100644 index 00000000000..ae24d5e88f8 --- /dev/null +++ b/app/components/UI/Card/util/residency.test.ts @@ -0,0 +1,52 @@ +import { + buildCardResidencyRegion, + isCardResidencyInBlockedRegions, +} from './residency'; + +describe('buildCardResidencyRegion', () => { + it('returns null when countryOfResidence is null', () => { + expect(buildCardResidencyRegion(null, 'CA')).toBeNull(); + }); + + it('returns the country code for non-US residents', () => { + expect(buildCardResidencyRegion('gb', null)).toBe('GB'); + }); + + it('returns US-{STATE} for US residents with a known state', () => { + expect(buildCardResidencyRegion('US', 'ca')).toBe('US-CA'); + }); + + it('returns US when state is unknown for a US resident', () => { + expect(buildCardResidencyRegion('US', null)).toBe('US'); + }); +}); + +describe('isCardResidencyInBlockedRegions', () => { + it('fail-opens when residency is unknown', () => { + expect(isCardResidencyInBlockedRegions(null, ['GB'])).toBe(false); + }); + + it('returns false when blocked regions is empty', () => { + expect(isCardResidencyInBlockedRegions('GB', [])).toBe(false); + }); + + it('blocks GB residents when GB is blocked', () => { + expect(isCardResidencyInBlockedRegions('GB', ['GB'])).toBe(true); + }); + + it('blocks all US residents when US is blocked', () => { + expect(isCardResidencyInBlockedRegions('US-CA', ['US'])).toBe(true); + }); + + it('blocks a specific US state when US-CA is blocked', () => { + expect(isCardResidencyInBlockedRegions('US-CA', ['US-CA'])).toBe(true); + }); + + it('does not block other US states when only US-CA is blocked', () => { + expect(isCardResidencyInBlockedRegions('US-NY', ['US-CA'])).toBe(false); + }); + + it('does not block US residents without state when only US-CA is blocked', () => { + expect(isCardResidencyInBlockedRegions('US', ['US-CA'])).toBe(false); + }); +}); diff --git a/app/components/UI/Card/util/residency.ts b/app/components/UI/Card/util/residency.ts new file mode 100644 index 00000000000..2077566dbaf --- /dev/null +++ b/app/components/UI/Card/util/residency.ts @@ -0,0 +1,41 @@ +/** + * Builds a residency region code from authenticated card KYC data. + * US cardholders with a known state use the `US-{STATE}` pattern (e.g. US-CA) + * so blocked-region lists can target specific states via + * `selectMusdConversionBlockedCountries`. + */ +export const buildCardResidencyRegion = ( + countryOfResidence: string | null, + usState: string | null, +): string | null => { + if (!countryOfResidence) { + return null; + } + + const country = countryOfResidence.toUpperCase(); + + if (country === 'US' && usState) { + return `US-${usState.toUpperCase()}`; + } + + return country; +}; + +/** + * Returns true when the residency region matches any blocked region entry. + * Fail-open when residency is unknown (null). + */ +export const isCardResidencyInBlockedRegions = ( + residencyRegion: string | null, + blockedRegions: string[], +): boolean => { + if (!residencyRegion || blockedRegions.length === 0) { + return false; + } + + const normalized = residencyRegion.toUpperCase(); + + return blockedRegions.some((region) => + normalized.startsWith(region.toUpperCase()), + ); +}; diff --git a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.test.tsx b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.test.tsx index 78cf71d8cb7..240fd847d49 100644 --- a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.test.tsx +++ b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.test.tsx @@ -1942,6 +1942,61 @@ describe('MoneyHomeView', () => { ).not.toBeOnTheScreen(); }); + it('hides the card section when residency is blocked', () => { + mockSelectIsCardholder.mockReturnValue(true); + mockUseMoneyAccountCardLinkage.mockReturnValue({ + hasMoneyAccountRequirements: true, + isCardAuthenticated: true, + isCardVerified: true, + isCardLinkedToMoneyAccount: false, + isResidencyBlocked: true, + primaryMoneyAccount: { address: '0xabc' }, + moneyAccountCardToken: { symbol: 'veda' }, + canLink: false, + status: 'idle', + isLinking: false, + error: null, + startLinkFlow: mockStartLinkFlow, + openLinkCardSheet: mockOpenLinkCardSheet, + reset: jest.fn(), + } as unknown as ReturnType); + + const { queryByTestId } = renderWithProvider(); + + expect( + queryByTestId(MoneyMetaMaskCardTestIds.LINK_CONTAINER), + ).not.toBeOnTheScreen(); + expect( + queryByTestId(MoneyMetaMaskCardTestIds.CONTAINER), + ).not.toBeOnTheScreen(); + }); + + it('still shows manage mode when residency is blocked but card is already linked', () => { + mockSelectIsCardholder.mockReturnValue(true); + mockUseMoneyAccountCardLinkage.mockReturnValue({ + hasMoneyAccountRequirements: true, + isCardAuthenticated: true, + isCardVerified: true, + isCardLinkedToMoneyAccount: true, + isResidencyBlocked: true, + primaryMoneyAccount: { address: '0xabc' }, + moneyAccountCardToken: { symbol: 'veda' }, + canLink: false, + status: 'idle', + isLinking: false, + error: null, + startLinkFlow: mockStartLinkFlow, + openLinkCardSheet: mockOpenLinkCardSheet, + reset: jest.fn(), + } as unknown as ReturnType); + + const { getByTestId } = renderWithProvider(); + + expect( + getByTestId(MoneyMetaMaskCardTestIds.MANAGE_CONTAINER), + ).toBeOnTheScreen(); + }); + it('selects mode="link" for cardholder even with zero transactions', () => { mockSelectIsCardholder.mockReturnValue(true); mockUseMoneyAccountCardLinkage.mockReturnValue({ diff --git a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx index 4102ef46de4..d23fd9dcc8e 100644 --- a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx +++ b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx @@ -166,6 +166,7 @@ const MoneyHomeView = () => { isCardLinkedToMoneyAccount, isLinking, hasMoneyAccountRequirements, + isResidencyBlocked, } = useMoneyAccountCardLinkage(); let displayState: MoneyBalanceDisplayState; @@ -581,6 +582,8 @@ const MoneyHomeView = () => { let metamaskCardMode: 'upsell' | 'link' | 'manage' | null; if (isCardLinkedToMoneyAccount) { metamaskCardMode = 'manage'; + } else if (isResidencyBlocked) { + metamaskCardMode = null; } else if (isCardholder || (isCardAuthenticated && isCardVerified)) { metamaskCardMode = hasMoneyAccountRequirements ? 'link' : null; } else if (isCardAuthenticated) { diff --git a/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.test.tsx b/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.test.tsx index ac60fc214a9..f6213406720 100644 --- a/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.test.tsx +++ b/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.test.tsx @@ -103,6 +103,8 @@ interface SetupOptions { isCardAuthenticated?: boolean; isCardVerified?: boolean; isCardLinkedToMoneyAccount?: boolean; + isResidencyBlocked?: boolean; + isAggregatedBalanceLoading?: boolean; isBalanceLoading?: boolean; tokenTotal?: BigNumber; } @@ -113,6 +115,8 @@ const setupDefaultMocks = ({ isCardAuthenticated = false, isCardVerified = false, isCardLinkedToMoneyAccount = false, + isResidencyBlocked = false, + isAggregatedBalanceLoading = false, isBalanceLoading = false, tokenTotal = new BigNumber(0), }: SetupOptions = {}) => { @@ -133,6 +137,7 @@ const setupDefaultMocks = ({ isCardAuthenticated, isCardVerified, isCardLinkedToMoneyAccount, + isResidencyBlocked, isLinking: false, }); mockIsCardholder.mockReturnValue(isCardholder); @@ -712,4 +717,35 @@ describe('MoneyOnboardingCard', () => { ); }); }); + + describe('residency blocking', () => { + it('auto-skips step 2 when residency is blocked and account is funded', () => { + setupDefaultMocks({ + currentStep: 0, + isCardholder: true, + isCardAuthenticated: true, + isCardVerified: true, + isResidencyBlocked: true, + tokenTotal: new BigNumber(100), + }); + + const { toJSON } = render(); + + expect(toJSON()).toBeNull(); + }); + + it('shows get-card step 2 when residency is not blocked', () => { + setupDefaultMocks({ + currentStep: 1, + isCardAuthenticated: false, + isResidencyBlocked: false, + }); + + const { getByText } = render(); + + expect( + getByText(strings('money.onboarding.step_2.no_card_account.title')), + ).toBeOnTheScreen(); + }); + }); }); diff --git a/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.tsx b/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.tsx index 69ad4fda0f4..d96496e3ddd 100644 --- a/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.tsx +++ b/app/components/UI/Money/components/MoneyOnboardingCard/MoneyOnboardingCard.tsx @@ -60,6 +60,7 @@ const MoneyOnboardingCard = () => { isCardVerified, isCardLinkedToMoneyAccount, isLinking, + isResidencyBlocked, } = useMoneyAccountCardLinkage(); const isCardholder = useSelector(selectIsCardholder); const cardHomeDataStatus = useSelector(selectCardHomeDataStatus); @@ -76,9 +77,12 @@ const MoneyOnboardingCard = () => { isCardLinkedToMoneyAccount, }); + const isCardStepBlocked = isResidencyBlocked && !isCardLinkedToMoneyAccount; + const shouldShowLinkCardAction = - isCardholder || - (isCardAuthenticated && isCardVerified && !isCardLinkedToMoneyAccount); + !isCardStepBlocked && + (isCardholder || + (isCardAuthenticated && isCardVerified && !isCardLinkedToMoneyAccount)); const handleRedirectToCryptoDeposit = useCallback(async () => { await initiateDeposit().catch(() => undefined); @@ -173,7 +177,9 @@ const MoneyOnboardingCard = () => { // - step 1 is complete right now (immediately advance funded users). const canEvaluateStep2 = currentStep >= 1 || isStep1Complete; const isStep2Complete = - canEvaluateStep2 && isCardAuthenticated && isCardLinkedToMoneyAccount; + canEvaluateStep2 && + ((isCardAuthenticated && isCardLinkedToMoneyAccount) || + isCardStepBlocked); if (isStep2Complete) return 2; if (isStep1Complete) return 1; @@ -183,6 +189,7 @@ const MoneyOnboardingCard = () => { isMoneyAccountFunded, isCardAuthenticated, isCardLinkedToMoneyAccount, + isCardStepBlocked, ]); // Prevent a flash of earlier steps by rendering the computed step immediately, diff --git a/app/core/Engine/controllers/card-controller/provider-types.ts b/app/core/Engine/controllers/card-controller/provider-types.ts index cb5aa939212..1512b844b5c 100644 --- a/app/core/Engine/controllers/card-controller/provider-types.ts +++ b/app/core/Engine/controllers/card-controller/provider-types.ts @@ -184,6 +184,8 @@ export interface CardAccountStatus { provisioningEligible: boolean; holderName: string | null; shippingAddress: CardShippingAddress | null; + countryOfResidence: string | null; + usState: string | null; } // -- Alerts & Actions -- diff --git a/app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts b/app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts index ae110944931..168a6600252 100644 --- a/app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts +++ b/app/core/Engine/controllers/card-controller/providers/BaanxProvider.test.ts @@ -309,8 +309,10 @@ describe('BaanxProvider', () => { const account: CardAccountStatus = { verificationStatus: 'VERIFIED', provisioningEligible: true, + countryOfResidence: 'US', holderName: 'Test User', shippingAddress: null, + usState: 'CA', }; const card: CardDetails = { @@ -663,6 +665,48 @@ describe('BaanxProvider', () => { expect(result.card).toBeNull(); }); + it('maps countryOfResidence from the user payload onto account status', async () => { + const get = jest.fn().mockImplementation((path: string) => { + if (path === '/v1/user') { + return Promise.resolve({ + verificationState: 'VERIFIED', + firstName: 'Jane', + countryOfResidence: 'gb', + }); + } + return Promise.resolve(null); + }); + + const result = await buildProvider(get).getCardHomeData('0xabc', tokens); + + expect(result.account).toMatchObject({ + countryOfResidence: 'GB', + usState: null, + verificationStatus: 'VERIFIED', + holderName: 'Jane', + } satisfies Partial); + }); + + it('maps usState from the user payload onto account status', async () => { + const get = jest.fn().mockImplementation((path: string) => { + if (path === '/v1/user') { + return Promise.resolve({ + verificationState: 'VERIFIED', + countryOfResidence: 'US', + usState: 'ca', + }); + } + return Promise.resolve(null); + }); + + const result = await buildProvider(get).getCardHomeData('0xabc', tokens); + + expect(result.account).toMatchObject({ + countryOfResidence: 'US', + usState: 'CA', + } satisfies Partial); + }); + it('propagates a 401 from the wallet details fetch', async () => { const get = jest.fn().mockImplementation((path: string) => { if (path === '/v1/delegation/chain/config') { diff --git a/app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts b/app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts index 8ab64624bb7..de34451cf29 100644 --- a/app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts +++ b/app/core/Engine/controllers/card-controller/providers/BaanxProvider.ts @@ -1480,6 +1480,10 @@ export class BaanxProvider implements ICardProvider { country: user.countryOfResidence ?? '', } : null, + countryOfResidence: user.countryOfResidence + ? user.countryOfResidence.toUpperCase() + : null, + usState: user.usState ? user.usState.toUpperCase() : null, }; } diff --git a/app/selectors/cardController.test.ts b/app/selectors/cardController.test.ts index f2b2113b357..dbaae6a6d22 100644 --- a/app/selectors/cardController.test.ts +++ b/app/selectors/cardController.test.ts @@ -20,6 +20,9 @@ import { selectCardHasApprovedLineaFunding, selectCardLineaUsdcToken, selectIsMoneyAccountDelegatedForCard, + selectCardCountryOfResidence, + selectCardResidencyRegion, + selectIsCardResidencyBlocked, } from './cardController'; import { selectPrimaryMoneyAccount } from './moneyAccountController'; import type { CardControllerState } from '../core/Engine/controllers/card-controller/types'; @@ -91,6 +94,7 @@ const MONAD_VEDA_FEATURE_FLAG = { const createMockRootState = ( overrides: Partial = {}, cardFeatureFlag?: unknown, + extraRemoteFlags?: Record, ): RootState => ({ engine: { @@ -106,10 +110,15 @@ const createMockRootState = ( moneyAccountCardLinkInProgress: false, ...overrides, }, - ...(cardFeatureFlag !== undefined + ...(cardFeatureFlag !== undefined || extraRemoteFlags !== undefined ? { RemoteFeatureFlagController: { - remoteFeatureFlags: { cardFeature: cardFeatureFlag }, + remoteFeatureFlags: { + ...(cardFeatureFlag !== undefined + ? { cardFeature: cardFeatureFlag } + : {}), + ...extraRemoteFlags, + }, }, } : {}), @@ -1436,3 +1445,253 @@ describe('selectIsMoneyAccountDelegatedForCard', () => { expect(selectIsMoneyAccountDelegatedForCard(state)).toBe(true); }); }); + +describe('selectCardCountryOfResidence', () => { + it('returns null when cardHomeData is null', () => { + const state = createMockRootState({ cardHomeData: null }); + expect(selectCardCountryOfResidence(state)).toBeNull(); + }); + + it('returns null when account is null', () => { + const state = createMockRootState({ + cardHomeData: + mockCardHomeData as unknown as CardControllerState['cardHomeData'], + }); + expect(selectCardCountryOfResidence(state)).toBeNull(); + }); + + it('returns countryOfResidence from account', () => { + const state = createMockRootState({ + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'GB', + usState: null, + }, + } as unknown as CardControllerState['cardHomeData'], + }); + expect(selectCardCountryOfResidence(state)).toBe('GB'); + }); +}); + +describe('selectCardResidencyRegion', () => { + it('returns US-{STATE} for US cardholders with a known state', () => { + const state = createMockRootState({ + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'US', + usState: 'CA', + }, + } as unknown as CardControllerState['cardHomeData'], + }); + expect(selectCardResidencyRegion(state)).toBe('US-CA'); + }); +}); + +describe('selectIsCardResidencyBlocked', () => { + const musdBlockedFlags = (blockedRegions: string[]) => ({ + earnMusdConversionGeoBlockedCountries: { blockedRegions }, + }); + + it('returns false when countryOfResidence is null (fail-open)', () => { + const state = createMockRootState({ + cardHomeData: + mockCardHomeData as unknown as CardControllerState['cardHomeData'], + }); + expect(selectIsCardResidencyBlocked(state)).toBe(false); + }); + + it('returns true when countryOfResidence is GB and GB is blocked', () => { + const state = createMockRootState( + { + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'GB', + usState: null, + }, + } as unknown as CardControllerState['cardHomeData'], + }, + undefined, + musdBlockedFlags(['GB']), + ); + expect(selectIsCardResidencyBlocked(state)).toBe(true); + }); + + it('returns false when countryOfResidence is not in blocked set', () => { + const state = createMockRootState( + { + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'US', + usState: 'NY', + }, + } as unknown as CardControllerState['cardHomeData'], + }, + undefined, + musdBlockedFlags(['GB']), + ); + expect(selectIsCardResidencyBlocked(state)).toBe(false); + }); + + it('returns true when US-CA is blocked and cardholder is in California', () => { + const state = createMockRootState( + { + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'US', + usState: 'CA', + }, + } as unknown as CardControllerState['cardHomeData'], + }, + undefined, + musdBlockedFlags(['US-CA']), + ); + expect(selectIsCardResidencyBlocked(state)).toBe(true); + }); + + it('returns false when only US-CA is blocked and cardholder is in New York', () => { + const state = createMockRootState( + { + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'US', + usState: 'NY', + }, + } as unknown as CardControllerState['cardHomeData'], + }, + undefined, + musdBlockedFlags(['US-CA']), + ); + expect(selectIsCardResidencyBlocked(state)).toBe(false); + }); + + it('returns true when entire US is blocked', () => { + const state = createMockRootState( + { + cardHomeData: { + ...mockCardHomeData, + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'US', + usState: 'NY', + }, + } as unknown as CardControllerState['cardHomeData'], + }, + undefined, + musdBlockedFlags(['US']), + ); + expect(selectIsCardResidencyBlocked(state)).toBe(true); + }); +}); + +describe('selectCardAvailableTokens residency blocking', () => { + const WALLET_A = '0xwalletA000000000000000000000000000000001'; + const musdBlockedFlags = (blockedRegions: string[]) => ({ + earnMusdConversionGeoBlockedCountries: { blockedRegions }, + }); + + it('suppresses Money Account placeholder entries when residency is blocked', () => { + mockSelectSelectedInternalAccountByScope.mockReturnValue( + jest.fn().mockReturnValue({ address: WALLET_A }), + ); + const homeData = { + ...mockCardHomeData, + fundingAssets: [], + delegationSettings: makeVedaDelegationSettings(), + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'GB', + usState: null, + }, + } as unknown as CardHomeData; + const state = createMockRootState( + { + cardHomeData: + homeData as unknown as CardControllerState['cardHomeData'], + }, + MONAD_VEDA_FEATURE_FLAG, + musdBlockedFlags(['GB']), + ); + expect(selectCardAvailableTokens(state)).toStrictEqual([]); + }); + + it('keeps active Money Account funding rows when residency is blocked', () => { + mockSelectSelectedInternalAccountByScope.mockReturnValue( + jest.fn().mockReturnValue({ address: WALLET_A }), + ); + const homeData = { + ...mockCardHomeData, + fundingAssets: [ + { + symbol: 'veda', + name: 'Veda', + address: VEDA_ADDRESS, + walletAddress: WALLET_A, + decimals: 6, + chainId: VEDA_CAIP, + spendableBalance: '10', + spendingCap: '100', + priority: 1, + status: FundingAssetStatus.Active, + delegationContract: VEDA_DELEGATION_CONTRACT, + }, + ], + delegationSettings: makeVedaDelegationSettings(), + account: { + verificationStatus: 'VERIFIED', + provisioningEligible: false, + holderName: 'Test User', + shippingAddress: null, + countryOfResidence: 'GB', + usState: null, + }, + } as unknown as CardHomeData; + const state = createMockRootState( + { + cardHomeData: + homeData as unknown as CardControllerState['cardHomeData'], + }, + MONAD_VEDA_FEATURE_FLAG, + musdBlockedFlags(['GB']), + ); + const tokens = selectCardAvailableTokens(state); + expect(tokens).toHaveLength(1); + expect(tokens[0].isMoneyAccountEntry).toBe(true); + expect(tokens[0].fundingStatus).toBe(FundingStatus.Enabled); + }); +}); diff --git a/app/selectors/cardController.ts b/app/selectors/cardController.ts index ecfcbb1a5c9..a5f3074458c 100644 --- a/app/selectors/cardController.ts +++ b/app/selectors/cardController.ts @@ -30,6 +30,11 @@ import { isEthAccount } from '../core/Multichain/utils'; import { isMoneyAccountDelegatedForCard } from '../core/Engine/controllers/card-controller/utils/moneyAccountCardToken'; import { selectPrimaryMoneyAccount } from './moneyAccountController'; import { selectCardFeatureFlag } from './featureFlagController/card'; +import { selectMusdConversionBlockedCountries } from '../components/UI/Earn/selectors/featureFlags'; +import { + buildCardResidencyRegion, + isCardResidencyInBlockedRegions, +} from '../components/UI/Card/util/residency'; const LINEA_MAINNET_CAIP_CHAIN_ID = 'eip155:59144'; const CASHBACK_FUNDING_SYMBOL = 'USDC'; @@ -159,6 +164,33 @@ export const selectMoneyAccountVedaTokenConfig = createSelector( getVedaTokenConfig(data?.delegationSettings), ); +export const selectCardCountryOfResidence = createSelector( + selectCardHomeData, + (data): string | null => data?.account?.countryOfResidence ?? null, +); + +export const selectCardUsState = createSelector( + selectCardHomeData, + (data): string | null => data?.account?.usState ?? null, +); + +export const selectCardResidencyRegion = createSelector( + selectCardCountryOfResidence, + selectCardUsState, + (countryOfResidence, usState): string | null => + buildCardResidencyRegion(countryOfResidence, usState), +); + +const selectCardResidencyBlockedRegions = (state: RootState): string[] => + selectMusdConversionBlockedCountries(state); + +export const selectIsCardResidencyBlocked = createSelector( + selectCardResidencyRegion, + selectCardResidencyBlockedRegions, + (residencyRegion, blockedRegions): boolean => + isCardResidencyInBlockedRegions(residencyRegion, blockedRegions), +); + const toFundingTokenWithVedaContext = ( asset: Parameters[0], vedaConfig: VedaTokenConfig | null, @@ -203,7 +235,14 @@ export const selectCardAvailableTokens = createSelector( selectSelectedEvmAccount, selectCardFeatureFlag, selectMoneyAccountVedaTokenConfig, - (data, selectedAccount, cardFeatureFlag, vedaConfig): CardFundingToken[] => { + selectIsCardResidencyBlocked, + ( + data, + selectedAccount, + cardFeatureFlag, + vedaConfig, + isResidencyBlocked, + ): CardFundingToken[] => { const currentAddress = selectedAccount?.address; const currentAddressLower = currentAddress?.toLowerCase(); const fundingAssets = data?.fundingAssets ?? []; @@ -255,7 +294,11 @@ export const selectCardAvailableTokens = createSelector( ...placeholder, walletAddress: currentAddress, isMoneyAccountEntry: isMoneyAccountEntry(placeholder, vedaConfig), - })); + })) + .filter( + (placeholder) => + !isResidencyBlocked || !placeholder.isMoneyAccountEntry, + ); return sortCardFundingTokens([...realEntries, ...placeholders]); }, From 04cf9e16130acd37bbd4f3bd17577b8ebdaa4145 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Tue, 16 Jun 2026 15:23:09 +0200 Subject: [PATCH 05/23] fix(money): always show Add CTA on Money balance card (MUSD-987) (#31743) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The Money balance card on the wallet home screen used to alternate its CTA between **Earn** (when the money-account balance was 0) and **Add** (when funded). Because the balance is resolved asynchronously from cache on startup, the button visibly flipped from "Earn" to "Add" as the cached balance loaded. Per the accepted solution in MUSD-987, this collapses the CTA to a single, stable **Add** button regardless of balance state. `buttonLabelKey`/`buttonTestId` are now constants and the state branches only decide the button variant and container testID (error/unavailable/empty/new-user/funded are unchanged). Dead code left behind by the change is removed: the `EARN_BUTTON` testID and the unreferenced `homepage.sections.money_empty_state` / `money_filled_state` locale blocks (`en.json` only — other locales flow from the localization pipeline). ## **Changelog** CHANGELOG entry: Fixed the Money balance card CTA flipping from "Earn" to "Add" on startup by always showing a single "Add" button. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-987 ## **Manual testing steps** ```gherkin Feature: Money balance card CTA Scenario: user with no money balance opens the wallet home Given the user has a money account with a 0 balance When the wallet home screen loads Then the Money balance card shows a single "Add" button And the button does not change from "Earn" to "Add" as the balance resolves Scenario: user with a money balance opens the wallet home Given the user has a money account with a balance greater than 0 When the wallet home screen loads Then the Money balance card shows the "Add" button And pressing it starts the deposit flow ``` ## **Screenshots/Recordings** ### **Before** The CTA rendered "Earn" for a 0 balance and flipped to "Add" once the cached balance resolved (see attached recording on MUSD-987). ### **After** image The CTA always renders "Add". ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. --- .../MoneyBalanceCard.test.tsx | 95 ++++++++----------- .../MoneyBalanceCard.testIds.ts | 1 - .../MoneyBalanceCard/MoneyBalanceCard.tsx | 13 +-- locales/languages/en.json | 9 -- 4 files changed, 40 insertions(+), 78 deletions(-) diff --git a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.test.tsx b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.test.tsx index 14c0d53d360..ee940525d8d 100644 --- a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.test.tsx +++ b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.test.tsx @@ -189,17 +189,12 @@ describe('MoneyBalanceCard', () => { expect(queryByText('$0.00')).not.toBeOnTheScreen(); }); - it('renders the Add button (not the Earn upsell)', () => { - const { getByTestId, queryByTestId } = renderWithProvider( - , - ); + it('renders the Add button', () => { + const { getByTestId } = renderWithProvider(); expect(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)).toHaveTextContent( strings('money.balance_card.add'), ); - expect( - queryByTestId(MoneyBalanceCardTestIds.EARN_BUTTON), - ).not.toBeOnTheScreen(); }); it('does not render the empty or new-user container', () => { @@ -295,23 +290,18 @@ describe('MoneyBalanceCard', () => { ); }); - it('renders the Earn button (not the Add button)', () => { - const { getByTestId, queryByTestId } = renderWithProvider( - , - ); + it('renders the Add button', () => { + const { getByTestId } = renderWithProvider(); - expect( - getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON), - ).toHaveTextContent(strings('homepage.sections.money_empty_state.earn')); - expect( - queryByTestId(MoneyBalanceCardTestIds.ADD_BUTTON), - ).not.toBeOnTheScreen(); + expect(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)).toHaveTextContent( + strings('money.balance_card.add'), + ); }); - it('routes add money when Earn is pressed', () => { + it('routes add money when Add is pressed', () => { const { getByTestId } = renderWithProvider(); - fireEvent.press(getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON)); + fireEvent.press(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)); expect(mockInitiateDeposit).toHaveBeenCalled(); expect(mockNavigate).not.toHaveBeenCalledWith(Routes.MONEY.MODALS.ROOT, { @@ -319,15 +309,15 @@ describe('MoneyBalanceCard', () => { }); }); - it('tracks the Earn click with the empty-state label key', () => { + it('tracks the Add click with the deposit redirect target', () => { const { getByTestId } = renderWithProvider(); - fireEvent.press(getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON)); + fireEvent.press(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)); expect(mockTrackButtonClicked).toHaveBeenCalledWith({ button_type: MONEY_BUTTON_TYPES.TEXT, button_intent: MONEY_BUTTON_INTENTS.ADD_MONEY, - label_key: 'homepage.sections.money_empty_state.earn', + label_key: 'money.balance_card.add', redirect_target: SCREEN_NAMES.MONEY_DEPOSIT, }); }); @@ -352,12 +342,10 @@ describe('MoneyBalanceCard', () => { ).toBeOnTheScreen(); }); - it('does not render the Add button', () => { - const { queryByTestId } = renderWithProvider(); + it('renders the Add button', () => { + const { getByTestId } = renderWithProvider(); - expect( - queryByTestId(MoneyBalanceCardTestIds.ADD_BUTTON), - ).not.toBeOnTheScreen(); + expect(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)).toBeOnTheScreen(); }); describe('when the wallet-home onboarding stepper is not displayed', () => { @@ -365,16 +353,14 @@ describe('MoneyBalanceCard', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(false); }); - it('renders the Earn button with the earn label', () => { + it('renders the Add button with the add label', () => { const { getByTestId, queryByTestId } = renderWithProvider( , ); expect( - getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON), - ).toHaveTextContent( - strings('homepage.sections.money_empty_state.earn'), - ); + getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON), + ).toHaveTextContent(strings('money.balance_card.add')); expect( queryByTestId(MoneyBalanceCardTestIds.GET_STARTED_BUTTON), ).not.toBeOnTheScreen(); @@ -388,10 +374,10 @@ describe('MoneyBalanceCard', () => { ).toBeOnTheScreen(); }); - it('routes add money when Earn is pressed', () => { + it('routes add money when Add is pressed', () => { const { getByTestId } = renderWithProvider(); - fireEvent.press(getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON)); + fireEvent.press(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)); expect(mockInitiateDeposit).toHaveBeenCalled(); expect(mockNavigateToMoneyHome).not.toHaveBeenCalled(); @@ -403,16 +389,14 @@ describe('MoneyBalanceCard', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(true); }); - it('renders the Earn button (never Get started) when the stepper is visible', () => { + it('renders the Add button (never Get started) when the stepper is visible', () => { const { getByTestId, queryByTestId } = renderWithProvider( , ); expect( - getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON), - ).toHaveTextContent( - strings('homepage.sections.money_empty_state.earn'), - ); + getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON), + ).toHaveTextContent(strings('money.balance_card.add')); expect( queryByTestId(MoneyBalanceCardTestIds.GET_STARTED_BUTTON), ).not.toBeOnTheScreen(); @@ -426,10 +410,10 @@ describe('MoneyBalanceCard', () => { ).toBeOnTheScreen(); }); - it('routes add money when Earn is pressed', () => { + it('routes add money when Add is pressed', () => { const { getByTestId } = renderWithProvider(); - fireEvent.press(getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON)); + fireEvent.press(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)); expect(mockInitiateDeposit).toHaveBeenCalled(); }); @@ -453,17 +437,12 @@ describe('MoneyBalanceCard', () => { ); }); - it('renders the Add button with the add label and not the Earn button', () => { - const { getByTestId, queryByTestId } = renderWithProvider( - , - ); + it('renders the Add button with the add label', () => { + const { getByTestId } = renderWithProvider(); expect(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)).toHaveTextContent( strings('money.balance_card.add'), ); - expect( - queryByTestId(MoneyBalanceCardTestIds.EARN_BUTTON), - ).not.toBeOnTheScreen(); }); it('renders the APY tag', () => { @@ -510,7 +489,7 @@ describe('MoneyBalanceCard', () => { }); }); - it('routes add money (and not the Money home) when Earn is pressed in empty state', () => { + it('routes add money (and not the Money home) when Add is pressed in empty state', () => { mockUseMoneyAccountBalance.mockReturnValue( createBalanceMock({ totalFiatRaw: '0', @@ -520,7 +499,7 @@ describe('MoneyBalanceCard', () => { const { getByTestId } = renderWithProvider(); - fireEvent.press(getByTestId(MoneyBalanceCardTestIds.EARN_BUTTON)); + fireEvent.press(getByTestId(MoneyBalanceCardTestIds.ADD_BUTTON)); expect(mockInitiateDeposit).toHaveBeenCalled(); expect(mockNavigateToMoneyHome).not.toHaveBeenCalled(); @@ -633,23 +612,23 @@ describe('MoneyBalanceCard', () => { mockSelectMoneyOnboardingSeen.mockReturnValue(true); }); - it('renders Earn as Secondary when the onboarding stepper is visible', () => { + it('renders Add as Secondary when the onboarding stepper is visible', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(true); const { UNSAFE_getByProps } = renderWithProvider(); expect( - getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.EARN_BUTTON), + getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.ADD_BUTTON), ).toBe(ButtonVariant.Secondary); }); - it('renders Earn as Primary when no other primary CTA is on Home', () => { + it('renders Add as Primary when no other primary CTA is on Home', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(false); const { UNSAFE_getByProps } = renderWithProvider(); expect( - getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.EARN_BUTTON), + getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.ADD_BUTTON), ).toBe(ButtonVariant.Primary); }); }); @@ -687,23 +666,23 @@ describe('MoneyBalanceCard', () => { mockSelectMoneyOnboardingSeen.mockReturnValue(false); }); - it('renders Earn as Primary when no other primary CTA is on Home', () => { + it('renders Add as Primary when no other primary CTA is on Home', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(false); const { UNSAFE_getByProps } = renderWithProvider(); expect( - getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.EARN_BUTTON), + getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.ADD_BUTTON), ).toBe(ButtonVariant.Primary); }); - it('renders Earn as Secondary when the onboarding stepper is visible', () => { + it('renders Add as Secondary when the onboarding stepper is visible', () => { mockSelectWalletHomeOnboardingFlowVisible.mockReturnValue(true); const { UNSAFE_getByProps } = renderWithProvider(); expect( - getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.EARN_BUTTON), + getVariant(UNSAFE_getByProps, MoneyBalanceCardTestIds.ADD_BUTTON), ).toBe(ButtonVariant.Secondary); }); }); diff --git a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.testIds.ts b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.testIds.ts index 333c9aced67..3ee4f1242a5 100644 --- a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.testIds.ts +++ b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.testIds.ts @@ -16,5 +16,4 @@ export const MoneyBalanceCardTestIds = { APY_TAG_SKELETON: 'money-balance-card-apy-tag-skeleton', ADD_BUTTON: 'money-balance-card-add-button', GET_STARTED_BUTTON: 'money-balance-card-get-started-button', - EARN_BUTTON: 'money-balance-card-earn-button', } as const; diff --git a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.tsx b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.tsx index e0b4a2fcb9e..4bd7d01ed42 100644 --- a/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.tsx +++ b/app/components/UI/Money/components/MoneyBalanceCard/MoneyBalanceCard.tsx @@ -100,27 +100,22 @@ const MoneyBalanceCard = () => { const balanceText = totalFiatFormatted ?? ''; + const buttonLabelKey = 'money.balance_card.add'; + const buttonTestId = MoneyBalanceCardTestIds.ADD_BUTTON; + let buttonVariant: ButtonVariant; - let buttonLabelKey: string; - let buttonTestId: string; let containerTestId: string; if (!hasMoneyAccount || isError || isRetrying) { buttonVariant = ButtonVariant.Secondary; - buttonLabelKey = 'money.balance_card.add'; - buttonTestId = MoneyBalanceCardTestIds.ADD_BUTTON; containerTestId = MoneyBalanceCardTestIds.ERROR_CONTAINER; } else if (isUnavailable) { buttonVariant = ButtonVariant.Secondary; - buttonLabelKey = 'money.balance_card.add'; - buttonTestId = MoneyBalanceCardTestIds.ADD_BUTTON; containerTestId = MoneyBalanceCardTestIds.UNAVAILABLE_CONTAINER; } else if (isEmpty) { buttonVariant = hasOtherPrimaryCtaOnHome ? ButtonVariant.Secondary : ButtonVariant.Primary; - buttonLabelKey = 'homepage.sections.money_empty_state.earn'; - buttonTestId = MoneyBalanceCardTestIds.EARN_BUTTON; containerTestId = isNewUser ? MoneyBalanceCardTestIds.NEW_USER_CONTAINER : MoneyBalanceCardTestIds.EMPTY_CONTAINER; @@ -128,8 +123,6 @@ const MoneyBalanceCard = () => { buttonVariant = hasOtherPrimaryCtaOnHome ? ButtonVariant.Secondary : ButtonVariant.Primary; - buttonLabelKey = 'money.balance_card.add'; - buttonTestId = MoneyBalanceCardTestIds.ADD_BUTTON; containerTestId = MoneyBalanceCardTestIds.FUNDED_CONTAINER; } diff --git a/locales/languages/en.json b/locales/languages/en.json index e630ce4e7a7..1ee08df66ca 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -9742,15 +9742,6 @@ "money": "Money", "money_empty_description": "You don't have any mUSD yet. Convert stablecoins to mUSD from the Money section on the homepage.", "money_empty_description_network_filter": "No mUSD on this network. Switch network to see your mUSD.", - "money_empty_state": { - "get_started": "Get started", - "earn": "Earn", - "earn_apy": "Earn {{percentage}}% APY" - }, - "money_filled_state": { - "add": "Add", - "apy": "{{percentage}}% APY" - }, "tokens": "Tokens", "perps": "Perps", "related_assets": "Related Assets", From 8e324b136b8dbc333542bfafbd766cd84df00a46 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Tue, 16 Jun 2026 16:04:36 +0200 Subject: [PATCH 06/23] fix(money): align balance, APY, and action buttons between Home and Money pages (MUSD-968) (#31735) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Balances, the percentage/APY value, and the primary action button row sat at different vertical positions on the **Home** page and the **Money account** page, producing a visible layout shift ("jumping") when navigating between the two screens. This aligns the Money account page's content rhythm to the Home page (Home left untouched as the source of truth): - `MoneyBalanceSummary`: normalized the top offset and tightened the balance→APY gap to match Home's balance block. - `MoneyActionButtonRow`: content-size the action buttons by removing the `ButtonBase` `min-height`/`h-full`/stretch hack, so **Add / Send / Card** share the same height and top position as Home's **Buy / Swap / Send / Receive** buttons. The balance, APY/percentage value, and action-button row now hold their vertical position across both screens. ## **Changelog** CHANGELOG entry: Fixed inconsistent vertical alignment of the balance, APY/percentage, and action buttons between the Home and Money account pages. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-968 ## **Manual testing steps** ```gherkin Feature: Consistent alignment between Home and Money account pages Scenario: Balance, APY and action buttons stay in place when switching pages Given I am on the Home page And I note the vertical position of the balance, the percentage value, and the action button row When I navigate to the Money account page Then the balance, the APY value, and the action button row are at the same vertical positions And the action buttons are the same height as on the Home page And there is no visible vertical jump when switching between the pages ``` ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/8cec1f1e-21c2-4701-a833-ec6cfec5f783 ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. --- .../MoneyActionButtonRow.tsx | 79 +++++-------------- .../MoneyBalanceSummary.tsx | 24 +++--- .../MoneyEarnings/MoneyEarnings.tsx | 2 +- .../MoneyOnboardingCard.tsx | 2 +- 4 files changed, 31 insertions(+), 76 deletions(-) diff --git a/app/components/UI/Money/components/MoneyActionButtonRow/MoneyActionButtonRow.tsx b/app/components/UI/Money/components/MoneyActionButtonRow/MoneyActionButtonRow.tsx index 04a22bea22b..7c7692a7a70 100644 --- a/app/components/UI/Money/components/MoneyActionButtonRow/MoneyActionButtonRow.tsx +++ b/app/components/UI/Money/components/MoneyActionButtonRow/MoneyActionButtonRow.tsx @@ -1,18 +1,10 @@ import React from 'react'; +import { StyleSheet } from 'react-native'; import { Box, - BoxAlignItems, BoxFlexDirection, - BoxJustifyContent, - ButtonBase, - FontWeight, - Icon, - IconColor, IconName, - IconSize, - Text, - TextColor, - TextVariant, + MainActionButton, } from '@metamask/design-system-react-native'; import { strings } from '../../../../../../locales/i18n'; import { MoneyActionButtonRowTestIds } from './MoneyActionButtonRow.testIds'; @@ -28,49 +20,12 @@ interface MoneyActionButtonRowProps { card: ActionButtonConfig; } -const ActionButton = ({ - iconName, - label, - onPress, - testID, - disabled, -}: { - iconName: IconName; - label: string; - onPress: () => void; - testID: string; - disabled?: boolean; -}) => ( - - - - - {label} - - - -); +const styles = StyleSheet.create({ + buttonContainer: { + flex: 1, + overflow: 'hidden', + }, +}); const MoneyActionButtonRow = ({ add, @@ -79,30 +34,32 @@ const MoneyActionButtonRow = ({ }: MoneyActionButtonRowProps) => ( - - - ); diff --git a/app/components/UI/Money/components/MoneyBalanceSummary/MoneyBalanceSummary.tsx b/app/components/UI/Money/components/MoneyBalanceSummary/MoneyBalanceSummary.tsx index 99d0d4baf58..2afe2ed0d98 100644 --- a/app/components/UI/Money/components/MoneyBalanceSummary/MoneyBalanceSummary.tsx +++ b/app/components/UI/Money/components/MoneyBalanceSummary/MoneyBalanceSummary.tsx @@ -83,7 +83,6 @@ const MoneyBalanceSummary = ({ variant={TextVariant.DisplayLg} fontWeight={FontWeight.Bold} testID={MoneyBalanceSummaryTestIds.BALANCE} - twClassName="mb-2" > {displayState.value} @@ -94,7 +93,6 @@ const MoneyBalanceSummary = ({ variant={TextVariant.BodyMd} color={TextColor.TextAlternative} testID={MoneyBalanceSummaryTestIds.BALANCE_NO_ACCOUNT} - twClassName="mb-2" > {strings('money.balance_no_account')} @@ -108,7 +106,6 @@ const MoneyBalanceSummary = ({ fontWeight={FontWeight.Bold} color={TextColor.TextAlternative} testID={MoneyBalanceSummaryTestIds.BALANCE_UNAVAILABLE} - twClassName="mb-2" > {displayState.lastKnownValue ?? strings('money.balance_unavailable_value')} @@ -120,16 +117,17 @@ const MoneyBalanceSummary = ({ }; return ( - - - {renderBalanceSlot()} - - {renderApySlot()} - + + {renderBalanceSlot()} + + {renderApySlot()} ); diff --git a/app/components/UI/Money/components/MoneyEarnings/MoneyEarnings.tsx b/app/components/UI/Money/components/MoneyEarnings/MoneyEarnings.tsx index 9ba67b680af..0dc725f9f24 100644 --- a/app/components/UI/Money/components/MoneyEarnings/MoneyEarnings.tsx +++ b/app/components/UI/Money/components/MoneyEarnings/MoneyEarnings.tsx @@ -62,7 +62,7 @@ const MoneyEarnings = ({ isLoading = false, onInfoPress, }: MoneyEarningsProps) => ( - + { } return ( - + Date: Tue, 16 Jun 2026 16:58:16 +0200 Subject: [PATCH 07/23] feat: add ActivityListItemRow component and associated tests (#31016) ## **Description** This PR integrates the Extension Activity adapter prototype into Mobile using a temporary vendored implementation, while preparing the code for a future shared `@metamask/activity-adapters` package. The change normalizes Mobile activity data sources into a common `ActivityListItem` shape: - Accounts API EVM transactions are mapped with `mapApiEvmTransactions` - Local EVM transactions are mapped with `mapLocalTransaction` - Non-EVM keyring transactions are mapped with `mapKeyringTransaction` Mobile then renders normalized activity rows with `ActivityListItemRow`, while preserving Mobile-specific behavior such as Figma-specific row copy/styling, legacy transaction-details navigation, pending local EVM speed up/cancel handling, account/network filtering, token-poisoning protection, and bridge/token enrichment. A key part of this PR is the `ActivityAdapterEnvironment` boundary. Adapter internals no longer directly depend on hidden Mobile/Extension shims for host-specific utilities. Instead, dependencies such as `toAssetId`, native asset lookup, token metadata, calldata parsing, wrapped-token configuration, status constants, and ERC-20 transfer log topics are passed through an explicit environment object. This makes the current vendored implementation closer to the shape needed for externalization. This PR also includes the scaffold for the redesigned Activity screen from TMCU-854. The redesigned screen is fully gated behind the remote feature flag `tmcuActivityRedesignEnabled`, which defaults to `false` in E2E feature-flag mocks. When the flag is disabled, `ActivityView` renders the existing legacy Activity implementation. When the flag is explicitly enabled, `ActivityView` lazy-loads and renders the new `ActivityScreen`. The feature-flag boundary was hardened so that only `tmcuActivityRedesignEnabled === true` enables the redesigned screen. The redesigned screen is lazy-loaded, so its component tree and dependencies are not evaluated on the flag-off path. To preserve existing Activity E2E behavior while the flag is off, the adapter-backed legacy Activity path keeps the existing row test contract: - Activity rows expose `transaction-item-${index}` - Activity statuses expose `transaction-status-${index}` - Swap and bridge rows use the richer legacy Activity titles where bridge history is available, e.g. `Swap ETH to - USDC` and `Bridge to Optimism` Follow-up externalization work should move `app/util/activity-adapters` into a shared package, keep `ActivityAdapterEnvironment` as the host dependency contract, provide Mobile and Extension environment implementations, move parity fixtures into the package test suite, and replace Mobile vendored imports with package imports once published. Follow-up redesign work should keep new Activity UI/data wiring scoped under `app/components/Views/ActivityScreen/**` or redesign-only hooks until the feature flag is intentionally enabled for rollout. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: Refs: - https://consensyssoftware.atlassian.net/browse/TMCU-797 - https://consensyssoftware.atlassian.net/browse/TMCU-854 ## **Manual testing steps** ```gherkin Feature: Activity adapters and Activity redesign feature flag isolation Scenario: legacy Activity remains active when redesign flag is disabled Given tmcuActivityRedesignEnabled is disabled or missing When the user opens the Activity tab Then the legacy Activity view is rendered And existing transaction rows expose transaction-item-* test IDs And existing transaction statuses expose transaction-status-* test IDs Scenario: redesigned Activity screen renders when redesign flag is enabled Given tmcuActivityRedesignEnabled is true When the user opens the Activity tab Then the redesigned Activity screen is rendered And the legacy Activity transaction tab UI is not rendered Scenario: adapter-backed Activity rows preserve legacy swap and bridge titles Given the user has swap or bridge activity with bridge history available When the user opens the Activity tab with tmcuActivityRedesignEnabled disabled Then swap rows show the rich swap title And bridge rows show the rich bridge destination title ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [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** - [ ] 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. --- > [!NOTE] > **Medium Risk** > Touches transaction list merging, deduplication, and navigation/speed-up-cancel flows where regressions could hide or mislabel activity; mitigated by heavy test coverage and flag-gated redesign entry (per PR description). > > **Overview** > Introduces a **unified Activity stack** on top of shared `ActivityListItem` adapters: **`ActivityList`** merges paginated Accounts API EVM history, enriched local EVM txs, and non-EVM keyring activity (chain enablement, hash/nonce dedup, malicious-token filtering, bridge rows), then renders most rows via new **`ActivityListItemRow`** (localized titles/statuses, token + fiat amounts, network badge, legacy swap/bridge title overrides). Pending locals still use **`TransactionElement`**; non-EVM bridges use **`MultichainBridgeTransactionListItem`**, with **`useUnifiedTxActions`** for speed-up/cancel (incl. Ledger/QR). > > Adds **`ActivityScreen`** scaffold (animated header, search placeholder, type/network filter chips + sheets, **`ActivityEmptyState`** CTAs) wired to **`ActivityList`**, plus supporting hooks (`useTransactionsQuery`, `useLocalActivityItems`, `useTransactionAutoScroll`) and API **`normalizeTransaction`** / transformation helpers, with broad unit tests. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 7510782e0fc27b62c8bbe257a3bed3cc0e88761e. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --------- Co-authored-by: vinnyhoward Co-authored-by: Ramon Acitores Co-authored-by: Cursor Co-authored-by: Ramon AC <36987446+racitores@users.noreply.github.com> --- .../ActivityListItemRow.test.tsx | 462 ++++++++++ .../ActivityListItemRow.tsx | 544 +++++++++++ .../Views/ActivityList/ActivityList.styles.ts | 28 + .../Views/ActivityList/ActivityList.test.tsx | 564 ++++++++++++ .../ActivityList/ActivityList.testIds.ts | 9 + .../Views/ActivityList/ActivityList.tsx | 862 ++++++++++++++++++ .../ActivityList/ActivityList.view.test.tsx | 84 ++ .../ActivityList/helpers/adapters.test.ts | 150 +++ .../Views/ActivityList/helpers/adapters.ts | 138 +++ .../helpers/transformations.test.ts | 240 +++++ .../ActivityList/helpers/transformations.ts | 192 ++++ .../hooks/useLocalActivityItems.test.ts | 205 +++++ .../hooks/useLocalActivityItems.ts | 273 ++++++ app/components/Views/ActivityList/index.ts | 1 + app/components/Views/ActivityList/types.ts | 10 + .../useTransactionAutoScroll.test.ts | 137 +++ .../ActivityList/useTransactionAutoScroll.ts | 155 ++++ .../ActivityList/useTransactionsQuery.test.ts | 113 +++ .../ActivityList/useTransactionsQuery.ts | 46 + .../ActivityList/useUnifiedTxActions.test.ts | 267 ++++++ .../Views/ActivityList/useUnifiedTxActions.ts | 420 +++++++++ .../ActivityScreen/ActivityScreen.testIds.ts | 12 + .../Views/ActivityScreen/ActivityScreen.tsx | 220 +++++ .../ActivityScreen.view.test.tsx | 81 ++ .../ActivityEmptyState.test.tsx | 127 +++ .../ActivityEmptyState/ActivityEmptyState.tsx | 104 +++ .../ActivityEmptyState/empty-states.test.ts | 169 ++++ .../ActivityEmptyState/empty-states.ts | 120 +++ .../components/ActivityEmptyState/index.ts | 7 + .../ActivityTypeFilterSheet.test.tsx | 138 +++ .../ActivityTypeFilterSheet.tsx | 101 ++ .../ActivityTypeFilterSheet/index.ts | 5 + .../AssetListControlBar.tsx | 82 ++ .../components/AssetListControlBar/index.ts | 2 + app/components/Views/ActivityScreen/index.ts | 1 + app/components/Views/ActivityScreen/types.ts | 109 +++ .../Views/ActivityView/ActivityView.styles.js | 39 + .../ActivityView/ActivityView.view.test.tsx | 60 ++ app/components/Views/ActivityView/index.js | 65 +- .../Views/ActivityView/index.test.tsx | 2 +- .../selectors/featureFlags/index.ts | 8 + app/images/activity-empty-dark.svg | 42 + app/images/activity-empty-light.svg | 42 + .../activity-list-helpers.test.ts | 96 ++ .../activity-list-helpers.ts | 97 ++ .../adapters/api-evm-transactions.test.ts | 703 ++++++++++++++ .../adapters/api-evm-transactions.ts | 388 ++++++++ .../activity-adapters/adapters/constants.ts | 15 + .../activity-adapters/adapters/dedup.test.ts | 38 + app/util/activity-adapters/adapters/dedup.ts | 55 ++ .../activity-adapters/adapters/environment.ts | 81 ++ .../adapters/helpers.test.ts | 143 +++ .../activity-adapters/adapters/helpers.ts | 243 +++++ .../adapters/keyring-transaction.test.ts | 168 ++++ .../adapters/keyring-transaction.ts | 195 ++++ .../adapters/local-transaction.test.ts | 753 +++++++++++++++ .../adapters/local-transaction.ts | 628 +++++++++++++ app/util/activity-adapters/adapters/shims.ts | 246 +++++ .../adapters/transaction-group.ts | 28 + app/util/activity-adapters/fiat.test.ts | 106 +++ app/util/activity-adapters/fiat.ts | 143 +++ app/util/activity-adapters/index.ts | 33 + app/util/activity-adapters/label-keys.test.ts | 19 + app/util/activity-adapters/label-keys.ts | 27 + app/util/activity-adapters/types.ts | 189 ++++ app/util/test/testSetupView.js | 29 + locales/languages/en.json | 84 +- tests/component-view/mocks.ts | 1 + tests/component-view/presets/activity.ts | 143 +++ tests/component-view/renderers/activity.ts | 168 ++++ tests/feature-flags/feature-flag-registry.ts | 8 + 71 files changed, 11223 insertions(+), 40 deletions(-) create mode 100644 app/components/UI/ActivityListItemRow/ActivityListItemRow.test.tsx create mode 100644 app/components/UI/ActivityListItemRow/ActivityListItemRow.tsx create mode 100644 app/components/Views/ActivityList/ActivityList.styles.ts create mode 100644 app/components/Views/ActivityList/ActivityList.test.tsx create mode 100644 app/components/Views/ActivityList/ActivityList.testIds.ts create mode 100644 app/components/Views/ActivityList/ActivityList.tsx create mode 100644 app/components/Views/ActivityList/ActivityList.view.test.tsx create mode 100644 app/components/Views/ActivityList/helpers/adapters.test.ts create mode 100644 app/components/Views/ActivityList/helpers/adapters.ts create mode 100644 app/components/Views/ActivityList/helpers/transformations.test.ts create mode 100644 app/components/Views/ActivityList/helpers/transformations.ts create mode 100644 app/components/Views/ActivityList/hooks/useLocalActivityItems.test.ts create mode 100644 app/components/Views/ActivityList/hooks/useLocalActivityItems.ts create mode 100644 app/components/Views/ActivityList/index.ts create mode 100644 app/components/Views/ActivityList/types.ts create mode 100644 app/components/Views/ActivityList/useTransactionAutoScroll.test.ts create mode 100644 app/components/Views/ActivityList/useTransactionAutoScroll.ts create mode 100644 app/components/Views/ActivityList/useTransactionsQuery.test.ts create mode 100644 app/components/Views/ActivityList/useTransactionsQuery.ts create mode 100644 app/components/Views/ActivityList/useUnifiedTxActions.test.ts create mode 100644 app/components/Views/ActivityList/useUnifiedTxActions.ts create mode 100644 app/components/Views/ActivityScreen/ActivityScreen.testIds.ts create mode 100644 app/components/Views/ActivityScreen/ActivityScreen.tsx create mode 100644 app/components/Views/ActivityScreen/ActivityScreen.view.test.tsx create mode 100644 app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.test.tsx create mode 100644 app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.tsx create mode 100644 app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.test.ts create mode 100644 app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.ts create mode 100644 app/components/Views/ActivityScreen/components/ActivityEmptyState/index.ts create mode 100644 app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.test.tsx create mode 100644 app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.tsx create mode 100644 app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/index.ts create mode 100644 app/components/Views/ActivityScreen/components/AssetListControlBar/AssetListControlBar.tsx create mode 100644 app/components/Views/ActivityScreen/components/AssetListControlBar/index.ts create mode 100644 app/components/Views/ActivityScreen/index.ts create mode 100644 app/components/Views/ActivityScreen/types.ts create mode 100644 app/components/Views/ActivityView/ActivityView.styles.js create mode 100644 app/components/Views/ActivityView/ActivityView.view.test.tsx create mode 100644 app/components/Views/ActivityView/selectors/featureFlags/index.ts create mode 100644 app/images/activity-empty-dark.svg create mode 100644 app/images/activity-empty-light.svg create mode 100644 app/util/activity-adapters/activity-list-helpers.test.ts create mode 100644 app/util/activity-adapters/activity-list-helpers.ts create mode 100644 app/util/activity-adapters/adapters/api-evm-transactions.test.ts create mode 100644 app/util/activity-adapters/adapters/api-evm-transactions.ts create mode 100644 app/util/activity-adapters/adapters/constants.ts create mode 100644 app/util/activity-adapters/adapters/dedup.test.ts create mode 100644 app/util/activity-adapters/adapters/dedup.ts create mode 100644 app/util/activity-adapters/adapters/environment.ts create mode 100644 app/util/activity-adapters/adapters/helpers.test.ts create mode 100644 app/util/activity-adapters/adapters/helpers.ts create mode 100644 app/util/activity-adapters/adapters/keyring-transaction.test.ts create mode 100644 app/util/activity-adapters/adapters/keyring-transaction.ts create mode 100644 app/util/activity-adapters/adapters/local-transaction.test.ts create mode 100644 app/util/activity-adapters/adapters/local-transaction.ts create mode 100644 app/util/activity-adapters/adapters/shims.ts create mode 100644 app/util/activity-adapters/adapters/transaction-group.ts create mode 100644 app/util/activity-adapters/fiat.test.ts create mode 100644 app/util/activity-adapters/fiat.ts create mode 100644 app/util/activity-adapters/index.ts create mode 100644 app/util/activity-adapters/label-keys.test.ts create mode 100644 app/util/activity-adapters/label-keys.ts create mode 100644 app/util/activity-adapters/types.ts create mode 100644 tests/component-view/presets/activity.ts create mode 100644 tests/component-view/renderers/activity.ts diff --git a/app/components/UI/ActivityListItemRow/ActivityListItemRow.test.tsx b/app/components/UI/ActivityListItemRow/ActivityListItemRow.test.tsx new file mode 100644 index 00000000000..708adb62474 --- /dev/null +++ b/app/components/UI/ActivityListItemRow/ActivityListItemRow.test.tsx @@ -0,0 +1,462 @@ +/** + * Tests for ActivityListItemRow — exhaustive status and type mapping. + */ +import React from 'react'; +import { render } from '@testing-library/react-native'; +import type { ActivityListItem, Status } from '../../../util/activity-adapters'; +import { ActivityListItemRow } from './ActivityListItemRow'; +import { strings } from '../../../../locales/i18n'; +import { getNetworkImageSource } from '../../../util/networks'; + +const LINEA_MUSD_ADDRESS = '0xaca92e438df0b2401ff60da7e4337b687a2435da'; +const LINEA_MUSD_CHECKSUM_ADDRESS = + '0xacA92E438df0B2401fF60dA7E4337B687a2435DA'; + +const mockState = { + user: { + appTheme: 'light', + }, + settings: { + showFiatOnTestnets: true, + }, + engine: { + backgroundState: { + CurrencyRateController: { + currentCurrency: 'usd', + currencyRates: { + ETH: { + conversionRate: 2500, + usdConversionRate: 2500, + }, + }, + }, + NetworkController: { + networkConfigurationsByChainId: { + '0x1': { + nativeCurrency: 'ETH', + }, + }, + }, + TokenRatesController: { + marketData: { + '0x1': { + [LINEA_MUSD_CHECKSUM_ADDRESS]: { + price: 0.0004, + }, + }, + }, + }, + }, + }, +}; + +// Minimal required mocks +jest.mock('../../../util/theme', () => { + const { mockTheme } = jest.requireActual('../../../util/theme'); + return { + useTheme: jest.fn(() => mockTheme), + }; +}); + +jest.mock('react-redux', () => ({ + useSelector: jest.fn((selector) => { + try { + return selector(mockState); + } catch { + return undefined; + } + }), +})); + +jest.mock('../../../selectors/currencyRateController', () => ({ + selectCurrentCurrency: jest.fn( + (state) => + state.engine.backgroundState.CurrencyRateController.currentCurrency, + ), + selectCurrencyRateForChainId: jest.fn(() => 2500), +})); + +jest.mock('../../../selectors/tokenRatesController', () => ({ + selectTokenMarketData: jest.fn( + (state) => state.engine.backgroundState.TokenRatesController.marketData, + ), +})); + +jest.mock('react-native', () => { + const rn = jest.requireActual('react-native'); + return { + ...rn, + useColorScheme: jest.fn(() => 'light'), + }; +}); + +jest.mock('../../../util/transaction-icons', () => ({ + getTransactionIcon: jest.fn(() => 1), +})); + +jest.mock('../../../util/date', () => ({ + toDateFormat: jest.fn(() => 'Jan 1'), +})); + +jest.mock('../../../util/networks', () => ({ + getNetworkImageSource: jest.fn(() => ({ uri: 'mock-network-image' })), +})); + +jest.mock('../../../component-library/components/Badges/BadgeWrapper', () => { + const ReactActual = jest.requireActual('react'); + const { View } = jest.requireActual('react-native'); + return ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); +}); + +jest.mock('../../../component-library/components/Badges/Badge', () => { + const ReactActual = jest.requireActual('react'); + const { View } = jest.requireActual('react-native'); + const Badge = () => ReactActual.createElement(View, null); + Badge.displayName = 'Badge'; + return { + __esModule: true, + default: Badge, + BadgeVariant: { Network: 'Network' }, + }; +}); + +jest.mock('../../../component-library/components/Avatars/Avatar', () => ({ + AvatarSize: { Xs: 'xs' }, +})); + +jest.mock('../../../component-library/components/Texts/Text', () => ({ + getFontFamily: jest.fn(() => 'Inter'), + TextVariant: { + BodyLGMedium: 'bodyLGMedium', + BodyMDBold: 'bodyMDBold', + BodyMD: 'bodyMD', + }, +})); + +jest.mock('../../Base/ListItem', () => { + const ReactActual = jest.requireActual('react'); + const { Text: TextActual, View } = jest.requireActual('react-native'); + + const ListItem = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); + + ListItem.Date = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(TextActual, null, children); + ListItem.Content = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); + ListItem.Icon = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); + ListItem.Body = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); + ListItem.Title = ({ + children, + ...rest + }: { + children: React.ReactNode; + numberOfLines?: number; + style?: object; + }) => ReactActual.createElement(TextActual, rest, children); + ListItem.Amount = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(TextActual, null, children); + ListItem.Amounts = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(View, null, children); + ListItem.FiatAmount = ({ children }: { children: React.ReactNode }) => + ReactActual.createElement(TextActual, null, children); + + return ListItem; +}); + +// --------------------------------------------------------------------------- +// Helper to build minimal ActivityListItem +// --------------------------------------------------------------------------- + +const makeItem = ( + overrides: Partial<{ + type: ActivityListItem['type']; + status: Status; + isEarliestNonce: boolean; + hash: string; + from: string; + to: string; + token?: object; + }>, +): ActivityListItem => { + const type = overrides.type ?? 'send'; + const status = overrides.status ?? 'success'; + const base = { + type, + chainId: 'eip155:1' as const, + status, + timestamp: 1_700_000_000_000, + isEarliestNonce: overrides.isEarliestNonce, + }; + + if (type === 'send' || type === 'receive') { + return { + ...base, + type, + data: { + hash: overrides.hash ?? '0xabc', + from: overrides.from ?? '0xfrom', + to: overrides.to ?? '0xto', + token: overrides.token as never, + }, + } as unknown as ActivityListItem; + } + + return { + ...base, + type, + data: { + hash: overrides.hash ?? '0xabc', + from: overrides.from ?? '0xfrom', + to: overrides.to ?? '0xto', + }, + } as unknown as ActivityListItem; +}; + +// --------------------------------------------------------------------------- +// Status mapping tests — prove all Status values map to explicit display labels +// --------------------------------------------------------------------------- + +describe('ActivityListItemRow — status display', () => { + const allStatuses: Status[] = ['pending', 'success', 'failed', 'cancelled']; + + it.each(allStatuses)( + 'renders an explicit non-empty status label for status=%s', + (status) => { + const item = makeItem({ status }); + const { getByTestId } = render( + , + ); + const el = getByTestId('transaction-status-0'); + expect(el.props.children).toBeTruthy(); + }, + ); + + it('shows "Confirmed" for success status', () => { + const item = makeItem({ status: 'success' }); + const { getByTestId } = render( + , + ); + const el = getByTestId('transaction-status-0'); + expect(el.props.children).toBe(strings('transaction.confirmed')); + }); + + it('shows "Failed" for failed status', () => { + const item = makeItem({ status: 'failed' }); + const { getByTestId } = render( + , + ); + const el = getByTestId('transaction-status-0'); + expect(el.props.children).toBe(strings('transaction.failed')); + }); + + it('shows "Cancelled" for cancelled status', () => { + const item = makeItem({ status: 'cancelled' }); + const { getByTestId } = render( + , + ); + const el = getByTestId('transaction-status-0'); + expect(el.props.children).toBe(strings('transaction.cancelled')); + }); + + it('shows "Submitted" for pending status (earliest nonce)', () => { + const item = makeItem({ status: 'pending', isEarliestNonce: true }); + const { getByTestId } = render( + , + ); + const el = getByTestId('transaction-status-0'); + expect(el.props.children).toBe(strings('transaction.submitted')); + }); +}); + +describe('ActivityListItemRow — network badge', () => { + it('uses the row item chainId for the network badge', () => { + const item = makeItem({ status: 'success' }); + render(); + + expect(getNetworkImageSource).toHaveBeenCalledWith({ + chainId: item.chainId, + }); + }); +}); + +describe('ActivityListItemRow — amount display', () => { + it('formats raw token base units and renders fiat when rates are available', () => { + const item = makeItem({ + status: 'success', + token: { + amount: '1000000', + decimals: 6, + symbol: 'mUSD', + assetId: `eip155:1/erc20:${LINEA_MUSD_ADDRESS}`, + direction: 'in', + }, + }); + + const { getByText } = render(); + + expect(getByText('+1 mUSD')).toBeOnTheScreen(); + expect(getByText('+$1')).toBeOnTheScreen(); + }); + + it('does not render fiat when token market data is unavailable', () => { + const item = makeItem({ + status: 'success', + token: { + amount: '1000000', + decimals: 6, + symbol: 'UNKNOWN', + assetId: 'eip155:1/erc20:0x0000000000000000000000000000000000000001', + direction: 'in', + }, + }); + + const { getByText, queryByText } = render( + , + ); + + expect(getByText('+1 UNKNOWN')).toBeOnTheScreen(); + expect(queryByText('+$1')).toBeNull(); + }); +}); + +// --------------------------------------------------------------------------- +// Type mapping tests — prove all ActivityKind values produce a non-empty title +// --------------------------------------------------------------------------- + +const ALL_KINDS: ActivityListItem['type'][] = [ + 'send', + 'receive', + 'swap', + 'swapIncomplete', + 'bridge', + 'buy', + 'sell', + 'claim', + 'claimMusdBonus', + 'deposit', + 'convert', + 'wrap', + 'unwrap', + 'approveSpendingCap', + 'revokeSpendingCap', + 'increaseSpendingCap', + 'lendingDeposit', + 'lendingWithdrawal', + 'nftMint', + 'contractInteraction', + 'contractDeployment', + 'smartAccountUpgrade', + 'predictionsAddFunds', + 'predictionsWithdrawFunds', + 'predictionClaimWinnings', + 'predictionCashedOut', + 'predictionPlaced', + 'perpsAddFunds', + 'perpsWithdrawFunds', + 'perpsOpenLong', + 'perpsCloseLong', + 'perpsCloseLongLiquidated', + 'perpsCloseLongStopLoss', + 'perpsOpenShort', + 'perpsCloseShort', + 'perpsCloseShortLiquidated', + 'perpsCloseShortStopLoss', + 'perpsPaidFundingFees', + 'perpsReceivedFundingFees', + 'perpsCloseShortTakeProfit', + 'perpsCloseLongTakeProfit', + 'marketShort', + 'stopMarketCloseShort', + 'marketCloseShort', +]; + +const EXPECTED_TITLES = { + send: strings('transactions.sent'), + receive: strings('transactions.received'), + swap: strings('transactions.swaps_transaction'), + swapIncomplete: strings('transactions.swaps_transaction'), + bridge: strings('transactions.bridge_transaction'), + buy: strings('transactions.activity_buy'), + sell: strings('transactions.activity_sell'), + claim: strings('transactions.claim'), + claimMusdBonus: strings('transactions.activity_claim_musd_bonus'), + deposit: strings('transactions.tx_review_staking_deposit'), + convert: strings('transactions.tx_review_musd_conversion'), + wrap: strings('transactions.activity_wrap'), + unwrap: strings('transactions.activity_unwrap'), + approveSpendingCap: strings('transactions.tx_review_approve'), + revokeSpendingCap: strings('transactions.activity_revoke_spending_cap'), + increaseSpendingCap: strings('transactions.tx_review_increase_allowance'), + lendingDeposit: strings('transactions.tx_review_lending_deposit'), + lendingWithdrawal: strings('transactions.tx_review_lending_withdraw'), + nftMint: strings('transactions.activity_nft_mint'), + contractInteraction: strings('transactions.smart_contract_interaction'), + contractDeployment: strings('transactions.tx_review_contract_deployment'), + smartAccountUpgrade: strings('transactions.activity_smart_account_upgrade'), + predictionsAddFunds: strings('transactions.tx_review_predict_deposit'), + predictionsWithdrawFunds: strings('transactions.tx_review_predict_withdraw'), + predictionClaimWinnings: strings('transactions.tx_review_predict_claim'), + predictionCashedOut: strings('transactions.activity_prediction_cashed_out'), + predictionPlaced: strings('transactions.activity_prediction_placed'), + perpsAddFunds: strings('transactions.tx_review_perps_deposit'), + perpsWithdrawFunds: strings('transactions.tx_review_perps_withdraw'), + perpsOpenLong: strings('transactions.activity_perps_open_long'), + perpsCloseLong: strings('transactions.activity_perps_close_long'), + perpsCloseLongLiquidated: strings( + 'transactions.activity_perps_close_long_liquidated', + ), + perpsCloseLongStopLoss: strings( + 'transactions.activity_perps_close_long_stop_loss', + ), + perpsOpenShort: strings('transactions.activity_perps_open_short'), + perpsCloseShort: strings('transactions.activity_perps_close_short'), + perpsCloseShortLiquidated: strings( + 'transactions.activity_perps_close_short_liquidated', + ), + perpsCloseShortStopLoss: strings( + 'transactions.activity_perps_close_short_stop_loss', + ), + perpsPaidFundingFees: strings( + 'transactions.activity_perps_paid_funding_fees', + ), + perpsReceivedFundingFees: strings( + 'transactions.activity_perps_received_funding_fees', + ), + perpsCloseShortTakeProfit: strings( + 'transactions.activity_perps_close_short_take_profit', + ), + perpsCloseLongTakeProfit: strings( + 'transactions.activity_perps_close_long_take_profit', + ), + marketShort: strings('transactions.activity_market_short'), + stopMarketCloseShort: strings( + 'transactions.activity_stop_market_close_short', + ), + marketCloseShort: strings('transactions.activity_market_close_short'), +} satisfies Record; + +describe('ActivityListItemRow — title display for all ActivityKind values', () => { + it.each(ALL_KINDS)('renders the explicit title for type=%s', (type) => { + const item = makeItem({ type, status: 'success' }); + const { getByText, queryByText } = render( + , + ); + + expect(getByText(EXPECTED_TITLES[type])).toBeOnTheScreen(); + expect(queryByText(strings('transactions.interaction'))).toBeNull(); + }); + + it('prefers the title override when provided (legacy swap/bridge contract)', () => { + const item = makeItem({ type: 'swap', status: 'success' }); + const { getByText, queryByText } = render( + , + ); + + expect(getByText('Swap ETH to USDC')).toBeOnTheScreen(); + expect(queryByText(strings('transactions.swaps_transaction'))).toBeNull(); + }); +}); diff --git a/app/components/UI/ActivityListItemRow/ActivityListItemRow.tsx b/app/components/UI/ActivityListItemRow/ActivityListItemRow.tsx new file mode 100644 index 00000000000..77dbb437ef6 --- /dev/null +++ b/app/components/UI/ActivityListItemRow/ActivityListItemRow.tsx @@ -0,0 +1,544 @@ +/** + * Row component that renders a single ActivityListItem from the shared adapter shape. + * All styling and localization are Mobile-specific; data comes from the shared adapters. + */ +import React, { useCallback } from 'react'; +import { + Image, + Text, + TextStyle, + TouchableHighlight, + useColorScheme, + StyleSheet, +} from 'react-native'; +import { useSelector } from 'react-redux'; +import type { Hex } from '@metamask/utils'; +import { useTheme } from '../../../util/theme'; +import { getTransactionIcon } from '../../../util/transaction-icons'; +import { toDateFormat } from '../../../util/date'; +import { strings } from '../../../../locales/i18n'; +import ListItem from '../../Base/ListItem'; +import BadgeWrapper from '../../../component-library/components/Badges/BadgeWrapper'; +import Badge, { + BadgeVariant, +} from '../../../component-library/components/Badges/Badge'; +import { AvatarSize } from '../../../component-library/components/Avatars/Avatar'; +import { getNetworkImageSource } from '../../../util/networks'; +import { RootState } from '../../../reducers'; +import { AppThemeKey } from '../../../util/theme/models'; +import { + getFontFamily, + TextVariant, +} from '../../../component-library/components/Texts/Text'; +import { + applyDisplaySign, + getDisplaySignPrefix, + getHumanReadableTokenAmount, + toMarketRateLookupToken, + type ActivityListItem, + type ActivityKind, + type Status, + type TokenAmount, +} from '../../../util/activity-adapters'; +import { + selectCurrencyRateForChainId, + selectCurrentCurrency, +} from '../../../selectors/currencyRateController'; +import { selectTokenMarketData } from '../../../selectors/tokenRatesController'; +import { NATIVE_TOKEN_ADDRESS } from '../../../util/activity-adapters/adapters/shims'; +import { balanceToFiatNumber, renderFiat } from '../../../util/number/bigint'; + +type TokenMarketData = ReturnType; + +type FiatCurrencyCode = Parameters[1]; + +// --------------------------------------------------------------------------- +// Chain/token helpers +// --------------------------------------------------------------------------- + +function resolveDisplayToken(item: ActivityListItem): TokenAmount | undefined { + const { data } = item; + + if ('destinationToken' in data && data.destinationToken?.symbol) { + return data.destinationToken; + } + + if ('sourceToken' in data && data.sourceToken?.symbol) { + return data.sourceToken; + } + + if ('token' in data && data.token?.symbol) { + return data.token; + } + + return undefined; +} + +const getHexChainId = (chainId: string): Hex | undefined => { + const decimalChainId = chainId.split(':')[1]; + if (!decimalChainId) { + return undefined; + } + + return `0x${Number.parseInt(decimalChainId, 10).toString(16)}` as Hex; +}; + +function getTokenPrice({ + token, + hexChainId, + marketData, +}: { + token: TokenAmount; + hexChainId: Hex; + marketData: TokenMarketData; +}): number | undefined { + const marketRateToken = toMarketRateLookupToken(token, hexChainId); + + if (!marketRateToken) { + return undefined; + } + + const tokenAddress = marketRateToken.address as Hex; + + if (tokenAddress === NATIVE_TOKEN_ADDRESS) { + return 1; + } + + const chainMarketData = marketData?.[hexChainId]; + if (!chainMarketData) { + return undefined; + } + + const exactPrice = chainMarketData[tokenAddress]?.price; + if (exactPrice !== undefined) { + return exactPrice; + } + + const normalizedTokenAddress = tokenAddress.toLowerCase(); + const marketDataAddress = Object.keys(chainMarketData).find( + (address) => address.toLowerCase() === normalizedTokenAddress, + ); + + return marketDataAddress + ? chainMarketData[marketDataAddress as Hex]?.price + : undefined; +} + +function resolveFiatAmount({ + token, + hexChainId, + marketData, + nativeConversionRate, + currentCurrency, +}: { + token: TokenAmount | undefined; + hexChainId: Hex | undefined; + marketData: TokenMarketData; + nativeConversionRate: number | undefined; + currentCurrency: string | undefined; +}): string | undefined { + if ( + !token || + !hexChainId || + !nativeConversionRate || + !currentCurrency || + token.amount === undefined + ) { + return undefined; + } + + const amount = getHumanReadableTokenAmount(token); + const tokenPrice = getTokenPrice({ token, hexChainId, marketData }); + + if (!amount || tokenPrice === undefined) { + return undefined; + } + + const fiatNumber = balanceToFiatNumber( + amount, + nativeConversionRate, + tokenPrice, + ); + const fiatAmount = renderFiat( + fiatNumber, + currentCurrency as FiatCurrencyCode, + 2, + ); + const signPrefix = getDisplaySignPrefix(token.direction, { showPlus: true }); + + return applyDisplaySign(fiatAmount, signPrefix); +} + +// --------------------------------------------------------------------------- +// Status → display +// --------------------------------------------------------------------------- + +interface StatusDisplay { + label: string; + colorKey: 'success' | 'warning' | 'error' | 'muted'; +} + +const STATUS_DISPLAY = { + success: { label: strings('transaction.confirmed'), colorKey: 'success' }, + failed: { label: strings('transaction.failed'), colorKey: 'error' }, + cancelled: { label: strings('transaction.cancelled'), colorKey: 'error' }, + pending: { + label: strings('transaction.submitted'), + colorKey: 'warning', + }, +} satisfies Record; + +/** Maps all adapter Status values to display labels and colors. */ +function resolveStatus(status: Status): StatusDisplay { + return STATUS_DISPLAY[status]; +} + +// --------------------------------------------------------------------------- +// ActivityKind → title +// --------------------------------------------------------------------------- + +type ActivityTitleResolver = (token?: TokenAmount) => string; + +const withSymbol = ( + token: TokenAmount | undefined, + symbolKey: string, + fallbackKey: string, +) => { + const symbol = token?.symbol ?? ''; + return symbol ? strings(symbolKey, { unit: symbol }) : strings(fallbackKey); +}; + +const ACTIVITY_TITLE_RESOLVERS = { + send: (token) => + withSymbol(token, 'transactions.sent_unit', 'transactions.sent'), + receive: (token) => + withSymbol(token, 'transactions.received_unit', 'transactions.received'), + swap: () => strings('transactions.swaps_transaction'), + swapIncomplete: () => strings('transactions.swaps_transaction'), + bridge: () => strings('transactions.bridge_transaction'), + buy: () => strings('transactions.activity_buy'), + sell: () => strings('transactions.activity_sell'), + claim: () => strings('transactions.claim'), + claimMusdBonus: () => strings('transactions.activity_claim_musd_bonus'), + deposit: () => strings('transactions.tx_review_staking_deposit'), + convert: () => strings('transactions.tx_review_musd_conversion'), + wrap: () => strings('transactions.activity_wrap'), + unwrap: () => strings('transactions.activity_unwrap'), + approveSpendingCap: () => strings('transactions.tx_review_approve'), + revokeSpendingCap: () => strings('transactions.activity_revoke_spending_cap'), + increaseSpendingCap: () => + strings('transactions.tx_review_increase_allowance'), + lendingDeposit: () => strings('transactions.tx_review_lending_deposit'), + lendingWithdrawal: () => strings('transactions.tx_review_lending_withdraw'), + nftMint: () => strings('transactions.activity_nft_mint'), + contractInteraction: () => strings('transactions.smart_contract_interaction'), + contractDeployment: () => + strings('transactions.tx_review_contract_deployment'), + smartAccountUpgrade: () => + strings('transactions.activity_smart_account_upgrade'), + predictionsAddFunds: () => strings('transactions.tx_review_predict_deposit'), + predictionsWithdrawFunds: () => + strings('transactions.tx_review_predict_withdraw'), + predictionClaimWinnings: () => + strings('transactions.tx_review_predict_claim'), + predictionCashedOut: () => + strings('transactions.activity_prediction_cashed_out'), + predictionPlaced: () => strings('transactions.activity_prediction_placed'), + perpsAddFunds: () => strings('transactions.tx_review_perps_deposit'), + perpsWithdrawFunds: () => strings('transactions.tx_review_perps_withdraw'), + perpsOpenLong: () => strings('transactions.activity_perps_open_long'), + perpsCloseLong: () => strings('transactions.activity_perps_close_long'), + perpsCloseLongLiquidated: () => + strings('transactions.activity_perps_close_long_liquidated'), + perpsCloseLongStopLoss: () => + strings('transactions.activity_perps_close_long_stop_loss'), + perpsOpenShort: () => strings('transactions.activity_perps_open_short'), + perpsCloseShort: () => strings('transactions.activity_perps_close_short'), + perpsCloseShortLiquidated: () => + strings('transactions.activity_perps_close_short_liquidated'), + perpsCloseShortStopLoss: () => + strings('transactions.activity_perps_close_short_stop_loss'), + perpsPaidFundingFees: () => + strings('transactions.activity_perps_paid_funding_fees'), + perpsReceivedFundingFees: () => + strings('transactions.activity_perps_received_funding_fees'), + perpsCloseShortTakeProfit: () => + strings('transactions.activity_perps_close_short_take_profit'), + perpsCloseLongTakeProfit: () => + strings('transactions.activity_perps_close_long_take_profit'), + marketShort: () => strings('transactions.activity_market_short'), + stopMarketCloseShort: () => + strings('transactions.activity_stop_market_close_short'), + marketCloseShort: () => strings('transactions.activity_market_close_short'), +} satisfies Record; + +/** Returns a display title for each ActivityKind. */ +function resolveTitle(type: ActivityKind, token?: TokenAmount): string { + return ACTIVITY_TITLE_RESOLVERS[type](token); +} + +export function resolveActivityListItemTitle( + item: ActivityListItem, + titleOverride?: string, +): string { + if (titleOverride) { + return titleOverride; + } + + const primaryToken = + 'token' in item.data + ? (item.data as { token?: TokenAmount }).token + : 'sourceToken' in item.data + ? (item.data as { sourceToken?: TokenAmount }).sourceToken + : undefined; + + return resolveTitle(item.type, primaryToken); +} + +// --------------------------------------------------------------------------- +// ActivityKind → icon type string (matches getTransactionIcon switch cases) +// --------------------------------------------------------------------------- + +function resolveIconType(type: ActivityKind): string { + switch (type) { + case 'send': + case 'sell': + case 'lendingDeposit': + case 'deposit': + case 'wrap': + case 'perpsAddFunds': + case 'predictionsAddFunds': + return 'send'; + case 'receive': + case 'buy': + case 'claim': + case 'claimMusdBonus': + case 'lendingWithdrawal': + case 'unwrap': + case 'nftMint': + case 'perpsWithdrawFunds': + case 'predictionsWithdrawFunds': + case 'predictionClaimWinnings': + case 'predictionCashedOut': + case 'predictionPlaced': + case 'perpsReceivedFundingFees': + return 'receive'; + case 'swap': + case 'swapIncomplete': + case 'bridge': + case 'convert': + return 'swap'; + case 'approveSpendingCap': + case 'revokeSpendingCap': + case 'increaseSpendingCap': + case 'contractInteraction': + case 'contractDeployment': + case 'smartAccountUpgrade': + case 'perpsOpenLong': + case 'perpsCloseLong': + case 'perpsCloseLongLiquidated': + case 'perpsCloseLongStopLoss': + case 'perpsOpenShort': + case 'perpsCloseShort': + case 'perpsCloseShortLiquidated': + case 'perpsCloseShortStopLoss': + case 'perpsPaidFundingFees': + case 'perpsCloseShortTakeProfit': + case 'perpsCloseLongTakeProfit': + case 'marketShort': + case 'stopMarketCloseShort': + case 'marketCloseShort': + return 'interaction'; + } +} + +// --------------------------------------------------------------------------- +// Amount display +// --------------------------------------------------------------------------- + +function resolveAmount(token: TokenAmount | undefined): string { + if (!token?.symbol) { + return ''; + } + + const amount = getHumanReadableTokenAmount(token); + const signPrefix = getDisplaySignPrefix(token.direction, { showPlus: true }); + const value = amount ? `${amount} ${token.symbol}` : token.symbol; + + return applyDisplaySign(value, signPrefix); +} + +// --------------------------------------------------------------------------- +// Styles +// --------------------------------------------------------------------------- + +const createStyles = ( + colors: ReturnType['colors'], + typography: ReturnType['typography'], +) => + StyleSheet.create({ + row: { + backgroundColor: colors.background.default, + flex: 1, + borderBottomWidth: 1, + borderBottomColor: colors.border.muted, + }, + icon: { + width: 32, + height: 32, + }, + listItemDate: { + marginBottom: 10, + paddingBottom: 0, + }, + listItemContent: { + alignItems: 'flex-start', + marginTop: 0, + paddingTop: 0, + }, + listItemTitle: { + ...typography.sBodyLGMedium, + fontFamily: getFontFamily(TextVariant.BodyLGMedium), + marginTop: 0, + color: colors.text.default, + } as TextStyle, + statusText: { + ...typography.sBodyMDBold, + fontFamily: getFontFamily(TextVariant.BodyMDBold), + marginTop: 4, + fontSize: 12, + letterSpacing: 0.5, + } as TextStyle, + listItemAmount: { + ...typography.sBodyMD, + fontFamily: getFontFamily(TextVariant.BodyMD), + color: colors.text.alternative, + } as TextStyle, + }); + +// --------------------------------------------------------------------------- +// Props +// --------------------------------------------------------------------------- + +interface ActivityListItemRowProps { + item: ActivityListItem; + index?: number; + onPress?: (item: ActivityListItem) => void; + /** + * Optional pre-resolved title. Used to preserve the legacy Activity contract + * for swap/bridge rows (e.g. "Swap ETH to USDC", "Bridge to Optimism"), which + * the parent derives from bridge history. Falls back to the kind-based title. + */ + title?: string; +} + +export function ActivityListItemRow({ + item, + index, + onPress, + title: titleOverride, +}: ActivityListItemRowProps) { + const { colors, typography } = useTheme(); + const osColorScheme = useColorScheme(); + const appTheme = useSelector( + (state: RootState) => state.user.appTheme as AppThemeKey, + ); + + const styles = createStyles(colors, typography); + const isFailed = item.status === 'failed' || item.status === 'cancelled'; + const iconType = resolveIconType(item.type); + const icon = getTransactionIcon(iconType, isFailed, appTheme, osColorScheme); + + const statusDisplay = resolveStatus(item.status); + const statusColor = + statusDisplay.colorKey === 'success' + ? colors.success.default + : statusDisplay.colorKey === 'error' + ? colors.error.default + : statusDisplay.colorKey === 'warning' + ? colors.warning.default + : colors.text.muted; + + const title = resolveActivityListItemTitle(item, titleOverride); + const displayToken = resolveDisplayToken(item); + const amount = resolveAmount(displayToken); + const marketData = useSelector(selectTokenMarketData); + const currentCurrency = useSelector(selectCurrentCurrency); + const hexChainId = getHexChainId(item.chainId); + const nativeConversionRate = useSelector((state: RootState) => + hexChainId ? selectCurrencyRateForChainId(state, hexChainId) : undefined, + ); + const fiatAmount = resolveFiatAmount({ + token: displayToken, + hexChainId, + marketData, + nativeConversionRate, + currentCurrency, + }); + + const networkImageSource = getNetworkImageSource({ + chainId: item.chainId, + }); + + const handlePress = useCallback(() => { + onPress?.(item); + }, [onPress, item]); + + return ( + + + + {toDateFormat(new Date(item.timestamp))} + + + + + } + > + + + + + + {title} + + + {statusDisplay.label} + + + {Boolean(amount) && ( + + {Boolean(fiatAmount) && ( + + {fiatAmount} + + )} + + {amount} + + + )} + + + + ); +} + +export default ActivityListItemRow; diff --git a/app/components/Views/ActivityList/ActivityList.styles.ts b/app/components/Views/ActivityList/ActivityList.styles.ts new file mode 100644 index 00000000000..480f2829808 --- /dev/null +++ b/app/components/Views/ActivityList/ActivityList.styles.ts @@ -0,0 +1,28 @@ +import { StyleSheet } from 'react-native'; +import { Theme } from '../../../util/theme/models'; + +const styleSheet = (params: { theme: Theme }) => { + const { colors } = params.theme; + return StyleSheet.create({ + container: { + flex: 1, + backgroundColor: colors.background.default, + }, + emptyList: { + width: '100%', + justifyContent: 'center', + alignItems: 'center', + paddingVertical: 40, + }, + modal: { + justifyContent: 'flex-end', + margin: 0, + }, + scrollViewContent: { + flex: 1, + justifyContent: 'flex-end', + }, + }); +}; + +export default styleSheet; diff --git a/app/components/Views/ActivityList/ActivityList.test.tsx b/app/components/Views/ActivityList/ActivityList.test.tsx new file mode 100644 index 00000000000..a3724af5968 --- /dev/null +++ b/app/components/Views/ActivityList/ActivityList.test.tsx @@ -0,0 +1,564 @@ +import React from 'react'; +import { + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react-native'; +import { useNavigation } from '@react-navigation/native'; +import { useSelector } from 'react-redux'; +import ActivityList from './ActivityList'; +import { ActivityListSelectorsIDs } from './ActivityList.testIds'; +import { useTransactionsQuery } from './useTransactionsQuery'; +import { useLocalActivityItems } from './hooks/useLocalActivityItems'; +import { useUnifiedTxActions } from './useUnifiedTxActions'; +import Engine from '../../../core/Engine'; + +jest.mock('@react-navigation/native', () => ({ + useNavigation: jest.fn(), +})); + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(), +})); + +jest.mock('../../../selectors/accountsController', () => ({ + selectSelectedInternalAccount: jest.fn((state) => state.selectedAccount), +})); + +jest.mock('../../../selectors/currencyRateController', () => ({ + selectCurrentCurrency: jest.fn((state) => state.currentCurrency), +})); + +jest.mock('../../../selectors/multichain/multichain', () => ({ + selectNonEvmTransactionsForSelectedAccountGroup: jest.fn( + (state) => state.nonEvmState, + ), +})); + +jest.mock( + '../../../selectors/multichainAccounts/accountTreeController', + () => ({ + selectSelectedAccountGroupInternalAccounts: jest.fn( + (state) => state.selectedGroupAccounts, + ), + }), +); + +jest.mock('../../../selectors/networkController', () => ({ + selectEvmNetworkConfigurationsByChainId: jest.fn((state) => state.evmConfigs), + selectProviderType: jest.fn((state) => state.providerType), +})); + +jest.mock('../../../selectors/networkEnablementController', () => ({ + selectEVMEnabledNetworks: jest.fn((state) => state.enabledEvm), + selectNonEVMEnabledNetworks: jest.fn((state) => state.enabledNonEvm), +})); + +jest.mock('../../../selectors/transactionController', () => ({ + selectRelatedChainIdsByTransactionId: jest.fn((state) => state.related), +})); + +jest.mock('../../../selectors/bridgeStatusController', () => ({ + selectBridgeHistoryForAccount: jest.fn((state) => state.bridgeHistory), +})); + +jest.mock('@metamask/design-system-twrnc-preset', () => ({ + useTailwind: () => ({ style: () => ({}) }), +})); + +jest.mock('@shopify/flash-list', () => { + const ReactActual = jest.requireActual('react'); + const { Text, TouchableOpacity, View } = jest.requireActual('react-native'); + return { + FlashList: ReactActual.forwardRef( + ( + { + data, + keyExtractor, + ListEmptyComponent, + ListFooterComponent, + ListHeaderComponent, + onScroll, + onViewableItemsChanged, + refreshControl, + renderItem, + testID, + }: { + data: unknown[]; + keyExtractor: (item: unknown) => string; + ListEmptyComponent?: React.ReactElement | (() => React.ReactElement); + ListFooterComponent?: React.ReactElement | null; + ListHeaderComponent?: React.ReactElement; + onScroll?: (event: object) => void; + onViewableItemsChanged?: (args: object) => void; + refreshControl?: React.ReactElement; + renderItem: (args: { + item: unknown; + index: number; + }) => React.ReactNode; + testID?: string; + }, + ref: React.Ref<{ scrollToOffset: jest.Mock }>, + ) => { + ReactActual.useImperativeHandle(ref, () => ({ + scrollToOffset: jest.fn(), + })); + const empty = + typeof ListEmptyComponent === 'function' ? ( + + ) : ( + ListEmptyComponent + ); + return ( + + {ListHeaderComponent} + {data.length + ? data.map((item, index) => ( + + {renderItem({ item, index })} + + )) + : empty} + {ListFooterComponent} + + ( + refreshControl as + | React.ReactElement<{ onRefresh: () => void }> + | undefined + )?.props.onRefresh() + } + /> + + onScroll?.({ nativeEvent: { contentOffset: { y: 12 } } }) + } + /> + + onViewableItemsChanged?.({ viewableItems: [{ index: 0 }] }) + } + > + viewable + + + ); + }, + ), + }; +}); + +jest.mock('../../../util/theme', () => ({ + useTheme: () => ({ + colors: { + background: { default: 'white' }, + icon: { default: 'black' }, + primary: { default: 'blue' }, + }, + }), +})); + +jest.mock('../../hooks/useStyles', () => ({ + useStyles: () => ({ + styles: { + container: {}, + emptyList: {}, + }, + }), +})); + +jest.mock('../../UI/AssetOverview/PriceChart/PriceChart.context', () => { + const ReactActual = jest.requireActual('react'); + const PriceChartContext = { + Consumer: ({ + children, + }: { + children: (value: object) => React.ReactNode; + }) => children({ isChartBeingTouched: false }), + }; + return { + __esModule: true, + default: PriceChartContext, + PriceChartProvider: ({ children }: { children?: React.ReactNode }) => ( + <>{children} + ), + }; +}); + +jest.mock('./useTransactionsQuery', () => ({ + useTransactionsQuery: jest.fn(), +})); + +jest.mock('./hooks/useLocalActivityItems', () => ({ + useLocalActivityItems: jest.fn(), +})); + +jest.mock('./useUnifiedTxActions', () => ({ + useUnifiedTxActions: jest.fn(), +})); + +jest.mock('../../../core/Engine', () => ({ + context: { + TransactionController: { + updateIncomingTransactions: jest.fn(() => Promise.resolve()), + }, + }, +})); + +const updateIncomingTransactions = ( + Engine.context.TransactionController as unknown as { + updateIncomingTransactions: jest.Mock; + } +).updateIncomingTransactions; + +jest.mock('../../UI/ActivityListItemRow/ActivityListItemRow', () => ({ + ActivityListItemRow: ({ + item, + onPress, + title, + }: { + item: { data: { hash?: string } }; + onPress: (item: unknown) => void; + title?: string; + }) => { + const { Text, TouchableOpacity } = jest.requireActual('react-native'); + return ( + onPress(item)} + > + {title ?? item.data.hash} + + ); + }, + resolveActivityListItemTitle: jest.fn(() => 'Activity title'), +})); + +jest.mock('../../UI/TransactionElement', () => { + const { Text, View } = jest.requireActual('react-native'); + return { + __esModule: true, + default: ({ tx }: { tx: { id: string } }) => ( + + Pending tx + + ), + }; +}); + +jest.mock('../../UI/MultichainBridgeTransactionListItem', () => { + const { Text, View } = jest.requireActual('react-native'); + return { + __esModule: true, + default: ({ transaction }: { transaction: { id: string } }) => ( + + Bridge tx + + ), + }; +}); + +jest.mock('../../UI/Transactions/TransactionsFooter', () => { + const { Text, TouchableOpacity } = jest.requireActual('react-native'); + return { + __esModule: true, + default: ({ onViewBlockExplorer }: { onViewBlockExplorer: () => void }) => ( + + EVM footer + + ), + }; +}); + +jest.mock('../MultichainTransactionsView/MultichainTransactionsFooter', () => { + const { Text, TouchableOpacity } = jest.requireActual('react-native'); + return { + __esModule: true, + default: ({ onViewMore }: { onViewMore: () => void }) => ( + + Non-EVM footer + + ), + }; +}); + +jest.mock('../confirmations/components/modals/cancel-speedup-modal', () => { + const { View } = jest.requireActual('react-native'); + return { + CancelSpeedupModal: ({ isVisible }: { isVisible: boolean }) => + isVisible ? : null, + }; +}); + +jest.mock('../../hooks/useBlockExplorer', () => ({ + __esModule: true, + default: () => ({ + getBlockExplorerName: jest.fn(() => 'Explorer'), + getBlockExplorerUrl: jest.fn(() => 'https://explorer.test/address/0xevm'), + }), +})); + +jest.mock('../../UI/Bridge/hooks/useBridgeHistoryItemBySrcTxHash', () => ({ + useBridgeHistoryItemBySrcTxHash: jest.fn(() => ({ + bridgeHistoryItemsBySrcTxHash: { + '0xconfirmed': { title: 'bridge-history' }, + solanaBridge: { title: 'solana-bridge' }, + }, + })), +})); + +jest.mock('../../UI/Bridge/utils/transaction-history', () => ({ + getSwapBridgeTxActivityTitle: jest.fn(() => 'Bridge title'), + handleUnifiedSwapsTxHistoryItemClick: jest.fn(), +})); + +jest.mock('../../../util/multichain/multichainTransactionTokenScan', () => ({ + filterMultichainTransactionsExcludingMaliciousTokenActivity: jest.fn( + (txs) => txs, + ), +})); + +jest.mock( + '../../hooks/useMultichainActivityMaliciousTokenKeys/useMultichainActivityMaliciousTokenKeys', + () => ({ + useMultichainActivityMaliciousTokenKeys: jest.fn(() => ({ + maliciousTokenKeys: new Set(), + })), + }), +); + +jest.mock('../../../core/Multichain/utils', () => ({ + getAddressUrl: jest.fn(() => 'https://solana.explorer/address/sol'), +})); + +jest.mock('../../../util/networks', () => ({ + getBlockExplorerAddressUrl: jest.fn(() => ({ + title: 'Configured Explorer', + url: 'https://configured.explorer/address/0xevm', + })), +})); + +jest.mock('./helpers/adapters', () => ({ + normalizeTransaction: jest.fn(() => ({ + chainId: '0x1', + id: 'normalized', + txParams: { from: '0xevm', to: '0xto' }, + })), +})); + +jest.mock('./helpers/transformations', () => { + const actual = jest.requireActual('./helpers/transformations'); + return { + ...actual, + mapNonEvmTransactions: jest.fn((txs) => + txs.map((tx: { id: string; chain: string }) => ({ + type: 'send', + chainId: tx.chain, + status: 'success', + timestamp: 2, + data: { hash: tx.id }, + raw: { type: 'keyringTransaction', data: tx }, + })), + ), + mergeTransactionsByTime: jest.fn((local, confirmed, nonEvm) => [ + ...local, + ...confirmed, + ...nonEvm, + ]), + }; +}); + +const mockNavigate = jest.fn(); +const mockFetchNextPage = jest.fn(); +const mockRefetch = jest.fn(() => Promise.resolve()); +const mockOnScroll = jest.fn(); + +const selectorValues = { + bridgeHistory: { + solanaBridge: { status: { srcChain: { txHash: 'solanaBridge' } } }, + }, + currentCurrency: 'usd', + enabledEvm: ['0x1'], + enabledNonEvm: [] as string[], + evmConfigs: { + '0x1': { + blockExplorerUrls: ['https://configured.explorer'], + defaultBlockExplorerUrlIndex: 0, + }, + }, + nonEvmState: { transactions: [] as unknown[] }, + providerType: 'mainnet', + related: new Map(), + selectedAccount: { address: '0xselected' }, + selectedGroupAccounts: [{ address: '0xevm', type: 'eip155:eoa' }], +}; + +const confirmedItem = { + type: 'send', + chainId: 'eip155:1', + status: 'success', + timestamp: 3, + data: { + hash: '0xconfirmed', + from: '0xevm', + to: '0xto', + token: { symbol: 'ETH' }, + }, + raw: { + type: 'apiEvmTransaction', + data: { chainId: 1, from: '0xevm', hash: '0xconfirmed', nonce: 7 }, + }, +}; + +const localPendingItem = { + type: 'send', + chainId: 'eip155:1', + status: 'pending', + timestamp: 4, + data: { hash: '0xlocal' }, + raw: { + type: 'localTransaction', + data: { + primaryTransaction: { + chainId: '0x1', + hash: '0xlocal', + id: 'local-id', + txParams: { from: '0xevm', nonce: '0x8' }, + }, + }, + }, +}; + +describe('ActivityList', () => { + beforeEach(() => { + jest.clearAllMocks(); + selectorValues.enabledEvm = ['0x1']; + selectorValues.enabledNonEvm = []; + selectorValues.nonEvmState = { transactions: [] }; + selectorValues.selectedGroupAccounts = [ + { address: '0xevm', type: 'eip155:eoa' }, + ]; + (useNavigation as jest.Mock).mockReturnValue({ navigate: mockNavigate }); + (useTransactionsQuery as jest.Mock).mockReturnValue({ + data: { pages: [{ data: [confirmedItem] }] }, + fetchNextPage: mockFetchNextPage, + hasNextPage: true, + isFetchingNextPage: false, + isInitialLoading: false, + refetch: mockRefetch, + }); + (useLocalActivityItems as jest.Mock).mockReturnValue([localPendingItem]); + (useUnifiedTxActions as jest.Mock).mockReturnValue({ + cancelIsOpen: false, + cancelTransaction: jest.fn(), + cancelUnsignedQRTransaction: jest.fn(), + confirmDisabled: false, + existingTx: null, + onCancelAction: jest.fn(), + onSpeedUpAction: jest.fn(), + onSpeedUpCancelCompleted: jest.fn(), + signLedgerTransaction: jest.fn(), + signQRTransaction: jest.fn(), + speedUpIsOpen: false, + speedUpTransaction: jest.fn(), + }); + (useSelector as unknown as jest.Mock).mockImplementation((selector) => + selector(selectorValues), + ); + }); + + it('renders local pending and confirmed transaction rows', () => { + render(} onScroll={mockOnScroll} />); + + expect( + screen.getByTestId(ActivityListSelectorsIDs.CONTAINER), + ).toBeOnTheScreen(); + expect(screen.getByTestId('pending-local-id')).toBeOnTheScreen(); + expect(screen.getByTestId('row-0xconfirmed')).toBeOnTheScreen(); + }); + + it('refreshes incoming transactions and refetches the list on pull-to-refresh', async () => { + render(} onScroll={mockOnScroll} />); + + fireEvent.press(screen.getByTestId('mock-refresh')); + + await waitFor(() => expect(updateIncomingTransactions).toHaveBeenCalled()); + expect(mockRefetch).toHaveBeenCalledTimes(1); + }); + + it('forwards scroll events to onScroll', () => { + render(} onScroll={mockOnScroll} />); + + fireEvent.press(screen.getByTestId('mock-scroll')); + + expect(mockOnScroll).toHaveBeenCalledTimes(1); + }); + + it('fetches the next page when viewable items change', () => { + render(} onScroll={mockOnScroll} />); + + fireEvent.press(screen.getByTestId('mock-viewable')); + + expect(mockFetchNextPage).toHaveBeenCalledTimes(1); + }); + + it('opens the EVM block explorer from the footer', () => { + render(} onScroll={mockOnScroll} />); + + fireEvent.press(screen.getByTestId('evm-footer')); + + expect(mockNavigate).toHaveBeenCalledWith('Webview', { + params: { + title: 'Configured Explorer', + url: 'https://configured.explorer/address/0xevm', + }, + screen: 'SimpleWebview', + }); + }); + + it('navigates to transaction details when a confirmed row is pressed', () => { + render(} onScroll={mockOnScroll} />); + + fireEvent.press(screen.getByTestId('row-0xconfirmed')); + + expect(mockNavigate).toHaveBeenCalledWith( + expect.any(String), + expect.objectContaining({ + screen: expect.any(String), + }), + ); + }); + + it('renders non-EVM bridge rows and footer when only non-EVM chains are enabled', () => { + selectorValues.enabledEvm = []; + selectorValues.enabledNonEvm = ['solana:mainnet']; + selectorValues.nonEvmState = { + transactions: [{ chain: 'solana:mainnet', id: 'solanaBridge' }], + }; + selectorValues.selectedGroupAccounts = [ + { address: 'solana-address', type: 'solana:data-account' }, + ]; + (useTransactionsQuery as jest.Mock).mockReturnValue({ + data: { pages: [{ data: [] }] }, + fetchNextPage: mockFetchNextPage, + hasNextPage: false, + isFetchingNextPage: false, + isInitialLoading: false, + refetch: mockRefetch, + }); + (useLocalActivityItems as jest.Mock).mockReturnValue([]); + + render(); + + expect(screen.getByTestId('bridge-solanaBridge')).toBeOnTheScreen(); + fireEvent.press(screen.getByTestId('non-evm-footer')); + expect(mockNavigate).toHaveBeenCalledWith('Webview', { + params: { url: 'https://solana.explorer/address/sol' }, + screen: 'SimpleWebview', + }); + }); +}); diff --git a/app/components/Views/ActivityList/ActivityList.testIds.ts b/app/components/Views/ActivityList/ActivityList.testIds.ts new file mode 100644 index 00000000000..aa281b4b8fb --- /dev/null +++ b/app/components/Views/ActivityList/ActivityList.testIds.ts @@ -0,0 +1,9 @@ +export const ActivityListSelectorsIDs = { + CONTAINER: 'activity-list', +} as const; + +export const activityListRowItemTestId = (index: number): string => + `transaction-item-${index}`; + +export const activityListRowStatusTestId = (index: number): string => + `transaction-status-${index}`; diff --git a/app/components/Views/ActivityList/ActivityList.tsx b/app/components/Views/ActivityList/ActivityList.tsx new file mode 100644 index 00000000000..8e3ad8ed813 --- /dev/null +++ b/app/components/Views/ActivityList/ActivityList.tsx @@ -0,0 +1,862 @@ +import { SupportedCaipChainId } from '@metamask/multichain-network-controller'; +import { TransactionType } from '@metamask/transaction-controller'; +import { numberToHex } from '@metamask/utils'; +import { useNavigation } from '@react-navigation/native'; +import { + FlashList, + type FlashListRef, + type ViewToken, +} from '@shopify/flash-list'; +import React, { useCallback, useMemo, useRef, useState } from 'react'; +import { + ActivityIndicator, + type NativeScrollEvent, + type NativeSyntheticEvent, + RefreshControl, + View, +} from 'react-native'; +import { useSelector } from 'react-redux'; +import { useTailwind } from '@metamask/design-system-twrnc-preset'; +import { strings } from '../../../../locales/i18n'; +import ExtendedKeyringTypes from '../../../constants/keyringTypes'; +import Routes from '../../../constants/navigation/Routes'; +import { RPC } from '../../../constants/network'; +import { selectSelectedInternalAccount } from '../../../selectors/accountsController'; +import { selectCurrentCurrency } from '../../../selectors/currencyRateController'; +import { selectNonEvmTransactionsForSelectedAccountGroup } from '../../../selectors/multichain/multichain'; +import { selectSelectedAccountGroupInternalAccounts } from '../../../selectors/multichainAccounts/accountTreeController'; +import { + selectEvmNetworkConfigurationsByChainId, + selectProviderType, +} from '../../../selectors/networkController'; +import { + selectEVMEnabledNetworks, + selectNonEVMEnabledNetworks, +} from '../../../selectors/networkEnablementController'; +import { selectRelatedChainIdsByTransactionId } from '../../../selectors/transactionController'; +import { baseStyles } from '../../../styles/common'; +import { isHardwareAccount } from '../../../util/address'; +import { getBlockExplorerAddressUrl } from '../../../util/networks'; +import { useTheme } from '../../../util/theme'; +import Engine from '../../../core/Engine'; +import { useStyles } from '../../hooks/useStyles'; +import PriceChartContext, { + PriceChartProvider, +} from '../../UI/AssetOverview/PriceChart/PriceChart.context'; +import { useBridgeHistoryItemBySrcTxHash } from '../../UI/Bridge/hooks/useBridgeHistoryItemBySrcTxHash'; +import { + getSwapBridgeTxActivityTitle, + handleUnifiedSwapsTxHistoryItemClick, +} from '../../UI/Bridge/utils/transaction-history'; +import MultichainBridgeTransactionListItem from '../../UI/MultichainBridgeTransactionListItem'; +import TransactionElement from '../../UI/TransactionElement'; +import TransactionsFooter from '../../UI/Transactions/TransactionsFooter'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import MultichainTransactionsFooter from '../MultichainTransactionsView/MultichainTransactionsFooter'; +import { getAddressUrl } from '../../../core/Multichain/utils'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { CancelSpeedupModal } from '../confirmations/components/modals/cancel-speedup-modal'; +import styleSheet from './ActivityList.styles'; +import { useUnifiedTxActions } from './useUnifiedTxActions'; +import { TransactionDetailLocation } from '../../../core/Analytics/events/transactions'; +import { useTransactionAutoScroll } from './useTransactionAutoScroll'; +import useBlockExplorer from '../../hooks/useBlockExplorer'; +import { selectBridgeHistoryForAccount } from '../../../selectors/bridgeStatusController'; +import { TabEmptyState } from '../../../component-library/components-temp/TabEmptyState'; +import { ActivityListSelectorsIDs } from './ActivityList.testIds'; +import { useMultichainActivityMaliciousTokenKeys } from '../../hooks/useMultichainActivityMaliciousTokenKeys/useMultichainActivityMaliciousTokenKeys'; +import { filterMultichainTransactionsExcludingMaliciousTokenActivity } from '../../../util/multichain/multichainTransactionTokenScan'; +import { useTransactionsQuery } from './useTransactionsQuery'; +import { type ActivityListItem } from './types'; +import { + isBridgeHistoryForEvmTransaction, + mergeTransactionsByTime, + mapNonEvmTransactions, +} from './helpers/transformations'; +import { normalizeTransaction } from './helpers/adapters'; +import { useLocalActivityItems } from './hooks/useLocalActivityItems'; +import { + ActivityListItemRow, + resolveActivityListItemTitle, +} from '../../UI/ActivityListItemRow/ActivityListItemRow'; + +const confirmedEvmOverscan = 5; +const visibilityConfig = { itemVisiblePercentThreshold: 1 }; + +const updateIncomingTransactions = () => + ( + Engine.context.TransactionController as unknown as { + updateIncomingTransactions: () => Promise; + } + ).updateIncomingTransactions(); + +const generateKey = (item: ActivityListItem): string => { + const hash = item.data.hash; + if (hash) { + return `${item.chainId}:${hash}`; + } + return `${item.chainId}:${item.timestamp}:${item.type}`; +}; + +const noop = () => undefined; + +const getActivityValue = (item: ActivityListItem) => { + const { data } = item; + + if ('token' in data && data.token?.symbol) { + return `${data.token.amount ?? ''} ${data.token.symbol}`.trim(); + } + + if ('destinationToken' in data && data.destinationToken?.symbol) { + return `${data.destinationToken.amount ?? ''} ${ + data.destinationToken.symbol + }`.trim(); + } + + if ('sourceToken' in data && data.sourceToken?.symbol) { + return `${data.sourceToken.amount ?? ''} ${data.sourceToken.symbol}`.trim(); + } + + return undefined; +}; + +const getActivityFromTo = (item: ActivityListItem) => { + const { data } = item; + return { + from: 'from' in data && typeof data.from === 'string' ? data.from : '', + to: 'to' in data && typeof data.to === 'string' ? data.to : '', + }; +}; + +interface ActivityListProps { + header?: React.ReactElement; + tabLabel?: string; + chainId?: string; // used by non-EVM list items for explorer links + location?: TransactionDetailLocation; + onScroll?: (event: NativeSyntheticEvent) => void; +} + +const ActivityList = ({ + header, + chainId, + location, + onScroll, +}: ActivityListProps) => { + const navigation = useNavigation(); + const { colors } = useTheme(); + const tw = useTailwind(); + const { styles } = useStyles(styleSheet, {}); + const { bridgeHistoryItemsBySrcTxHash } = useBridgeHistoryItemBySrcTxHash(); + + const getBridgeHistoryItemByHash = useCallback( + (hash?: string) => { + if (!hash) { + return undefined; + } + + const normalizedHash = hash.toLowerCase(); + return ( + bridgeHistoryItemsBySrcTxHash[hash] ?? + Object.entries(bridgeHistoryItemsBySrcTxHash).find( + ([key]) => key.toLowerCase() === normalizedHash, + )?.[1] + ); + }, + [bridgeHistoryItemsBySrcTxHash], + ); + + const { + data: evmTransactions, + fetchNextPage, + hasNextPage, + isInitialLoading, + isFetchingNextPage, + refetch, + } = useTransactionsQuery(); + + const allConfirmedFiltered = useMemo( + () => evmTransactions?.pages.flatMap((page) => page.data) ?? [], + [evmTransactions], + ); + + // Local EVM transactions mapped through the shared adapter + const localActivityItems = useLocalActivityItems(); + + const nonEvmState = useSelector( + selectNonEvmTransactionsForSelectedAccountGroup, + ); + const nonEvmTransactions = useMemo( + () => nonEvmState?.transactions ?? [], + [nonEvmState?.transactions], + ); + + const currentCurrency = useSelector(selectCurrentCurrency); + + const selectedInternalAccount = useSelector(selectSelectedInternalAccount); + const selectedAccountGroupInternalAccounts = useSelector( + selectSelectedAccountGroupInternalAccounts, + ); + const selectedAccountGroupEvmAddress = useMemo(() => { + const evmAccount = selectedAccountGroupInternalAccounts.find( + (account) => + account.type === 'eip155:eoa' || account.type === 'eip155:erc4337', + ); + return evmAccount?.address ?? ''; + }, [selectedAccountGroupInternalAccounts]); + + const selectedAccountGroupSolanaAddress = useMemo(() => { + const solanaAccount = selectedAccountGroupInternalAccounts.find( + (account) => account.type === 'solana:data-account', + ); + return solanaAccount?.address ?? ''; + }, [selectedAccountGroupInternalAccounts]); + + const enabledEVMNetworks = useSelector(selectEVMEnabledNetworks); + const enabledEVMChainIds = useMemo( + () => enabledEVMNetworks ?? [], + [enabledEVMNetworks], + ); + const enabledNonEVMNetworks = useSelector(selectNonEVMEnabledNetworks); + const enabledNonEVMChainIds = useMemo( + () => enabledNonEVMNetworks ?? [], + [enabledNonEVMNetworks], + ); + + const relatedChainIdsByTransactionId = useSelector( + selectRelatedChainIdsByTransactionId, + ); + + const bridgeHistory = useSelector(selectBridgeHistoryForAccount); + + /** Drop confirmed EVM rows not on currently enabled chains (guards stale query pages). */ + const allConfirmedForEnabledChains = useMemo(() => { + const chains = enabledEVMChainIds ?? []; + if (chains.length === 0) return []; + const allowed = new Set(chains.map((c) => c.toLowerCase())); + return allConfirmedFiltered.filter((item) => { + // chainId is a CaipChainId like eip155:1 — extract hex part + const hexChainId = item.chainId.split(':')[1]; + if (!hexChainId) return false; + const hexFormatted = `0x${parseInt(hexChainId, 10).toString(16)}`; + return allowed.has(hexFormatted.toLowerCase()); + }); + }, [allConfirmedFiltered, enabledEVMChainIds]); + + const { maliciousTokenKeys } = + useMultichainActivityMaliciousTokenKeys(nonEvmTransactions); + + const providerType = useSelector(selectProviderType); + const evmNetworkConfigurationsByChainId = useSelector( + selectEvmNetworkConfigurationsByChainId, + ); + + const unifiedTransactionSource = useMemo<{ + localItems: ActivityListItem[]; + confirmedEvmItems: ActivityListItem[]; + nonEvmItems: ActivityListItem[]; + }>(() => { + const bridgeHistoryValues = Object.values(bridgeHistory ?? {}); + const enabledEvmSet = new Set( + (enabledEVMChainIds ?? []).map((id) => id.toLowerCase()), + ); + + // Filter local items to enabled EVM chains only, also deduplicate against confirmed + const confirmedHashes = new Set( + allConfirmedForEnabledChains + .map((item) => item.data.hash?.toLowerCase()) + .filter(Boolean) as string[], + ); + + // localActivityItems are already mapped from TransactionMeta via the adapter; + // here we apply the same chain-filter and EVM-confirmed dedup that existed before. + const filteredLocalItems = localActivityItems.filter((item) => { + const raw = item.raw; + if (raw?.type !== 'localTransaction') return true; + const tx = raw.data.primaryTransaction; + + const txChainId = tx.chainId?.toLowerCase() ?? ''; + const relatedChainIds = relatedChainIdsByTransactionId.get(tx.id) ?? [ + txChainId, + ]; + + if (!relatedChainIds.some((id) => enabledEvmSet.has(id))) { + return false; + } + + // Dedup against confirmed by hash — bridge txns are exempt from nonce dedup + const hash = tx.hash?.toLowerCase(); + if (hash && confirmedHashes.has(hash)) return false; + + // Nonce dedup: skip local if a confirmed tx has the same nonce+from+chain + // (bridge txns exempt, as they may have same nonce as their approval) + const isBridgeTx = isBridgeHistoryForEvmTransaction( + tx, + bridgeHistoryValues, + ); + if (!isBridgeTx) { + const nonce = tx.txParams?.nonce; + const from = tx.txParams?.from?.toLowerCase(); + if (nonce !== undefined && nonce !== null && from) { + const matchedByNonce = allConfirmedForEnabledChains.some( + (confirmed) => { + // parse nonce from confirmed item if available + const confirmedRaw = confirmed.raw; + if (confirmedRaw?.type !== 'apiEvmTransaction') return false; + const confirmedApiTx = confirmedRaw.data; + // hexChainId from caip: eip155:1 → 0x1 + const hexChainId = confirmed.chainId.split(':')[1] + ? `0x${parseInt(confirmed.chainId.split(':')[1], 10).toString(16)}` + : ''; + return ( + confirmedApiTx.nonce === parseInt(String(nonce), 16) && + hexChainId.toLowerCase() === txChainId && + confirmedApiTx.from?.toLowerCase() === from + ); + }, + ); + if (matchedByNonce) return false; + } + } + + return true; + }); + + // Non-EVM: filter by enabled chains, include bridge txns whose dest chain is enabled + const filteredNonEvmTransactions = nonEvmTransactions + .filter((tx) => { + if (enabledNonEVMChainIds.includes(tx.chain)) return true; + const bridge = Object.values(bridgeHistory ?? {}).find( + (item) => item.status?.srcChain?.txHash === tx.id, + ); + return ( + bridge?.quote?.destChainId !== undefined && + enabledEVMChainIds.includes(numberToHex(bridge.quote.destChainId)) + ); + }) + .filter( + (tx, index, self) => index === self.findIndex((t) => t.id === tx.id), + ); + + const filteredNonEvmForMalicious = + filterMultichainTransactionsExcludingMaliciousTokenActivity( + filteredNonEvmTransactions, + maliciousTokenKeys, + ); + + const nonEvmItems = mapNonEvmTransactions(filteredNonEvmForMalicious); + + return { + localItems: filteredLocalItems, + confirmedEvmItems: allConfirmedForEnabledChains, + nonEvmItems, + }; + }, [ + allConfirmedForEnabledChains, + localActivityItems, + nonEvmTransactions, + enabledEVMChainIds, + enabledNonEVMChainIds, + bridgeHistory, + relatedChainIdsByTransactionId, + maliciousTokenKeys, + ]); + + const data = useMemo(() => { + const { localItems, confirmedEvmItems, nonEvmItems } = + unifiedTransactionSource; + return mergeTransactionsByTime(localItems, confirmedEvmItems, nonEvmItems); + }, [unifiedTransactionSource]); + + const hasEvmChainsEnabled = enabledEVMChainIds.length > 0; + const popularListBlockExplorer = useBlockExplorer( + hasEvmChainsEnabled ? enabledEVMChainIds[0] : undefined, + ); + + const configBlockExplorerUrl = useMemo(() => { + if (!enabledEVMChainIds?.length || enabledEVMChainIds.length !== 1) { + return undefined; + } + const selectedChainId = enabledEVMChainIds[0]; + const config = evmNetworkConfigurationsByChainId?.[selectedChainId]; + if (!config) return undefined; + const index = config.defaultBlockExplorerUrlIndex ?? 0; + return config.blockExplorerUrls?.[index]; + }, [enabledEVMChainIds, evmNetworkConfigurationsByChainId]); + + const blockExplorerUrl = useMemo(() => { + if (configBlockExplorerUrl) { + return configBlockExplorerUrl; + } + return hasEvmChainsEnabled + ? popularListBlockExplorer.getBlockExplorerUrl( + selectedAccountGroupEvmAddress, + ) || undefined + : undefined; + }, [ + configBlockExplorerUrl, + popularListBlockExplorer, + selectedAccountGroupEvmAddress, + hasEvmChainsEnabled, + ]); + + const hasNonEvmChainsEnabled = enabledNonEVMChainIds.length > 0; + + const showEvmFooter = hasEvmChainsEnabled && !hasNonEvmChainsEnabled; + const showNonEvmFooter = hasNonEvmChainsEnabled && !hasEvmChainsEnabled; + + const onViewBlockExplorer = useCallback(() => { + if (!selectedAccountGroupEvmAddress) { + return; + } + + let url; + let title; + if (configBlockExplorerUrl) { + const result = getBlockExplorerAddressUrl( + RPC, + selectedAccountGroupEvmAddress, + blockExplorerUrl, + ); + url = result.url; + title = result.title; + if (!url) return; + } else { + url = blockExplorerUrl; + title = hasEvmChainsEnabled + ? popularListBlockExplorer.getBlockExplorerName(enabledEVMChainIds[0]) + : undefined; + } + + navigation.navigate('Webview', { + screen: 'SimpleWebview', + params: { url, title }, + }); + }, [ + navigation, + blockExplorerUrl, + selectedAccountGroupEvmAddress, + popularListBlockExplorer, + enabledEVMChainIds, + configBlockExplorerUrl, + hasEvmChainsEnabled, + ]); + + const allNonEvmChainsAreSolana = useMemo( + () => + enabledNonEVMChainIds.every((chain) => + chain.toLowerCase().startsWith('solana:'), + ), + [enabledNonEVMChainIds], + ); + + const nonEvmExplorerChainId = useMemo(() => { + if (enabledNonEVMChainIds.length) return enabledNonEVMChainIds[0]; + if (chainId?.includes(':')) return chainId; + return undefined; + }, [enabledNonEVMChainIds, chainId]); + + const nonEvmExplorerUrl = useMemo(() => { + if (!selectedAccountGroupSolanaAddress || !nonEvmExplorerChainId) return ''; + return getAddressUrl( + selectedAccountGroupSolanaAddress, + nonEvmExplorerChainId as SupportedCaipChainId, + ); + }, [nonEvmExplorerChainId, selectedAccountGroupSolanaAddress]); + + const showNonEvmExplorerLink = + showNonEvmFooter && allNonEvmChainsAreSolana && Boolean(nonEvmExplorerUrl); + + const onViewNonEvmExplorer = useCallback(() => { + if (!nonEvmExplorerUrl) return; + navigation.navigate('Webview', { + screen: 'SimpleWebview', + params: { url: nonEvmExplorerUrl }, + }); + }, [navigation, nonEvmExplorerUrl]); + + const footerComponent = useMemo(() => { + if (isFetchingNextPage) { + return ( + + + + ); + } + + if (showEvmFooter) { + return ( + + ); + } + + if (showNonEvmFooter) { + return ( + 0 + } + showDisclaimer + showExplorerLink={showNonEvmExplorerLink} + onViewMore={onViewNonEvmExplorer} + /> + ); + } + + return null; + }, [ + enabledEVMChainIds, + unifiedTransactionSource.nonEvmItems?.length, + onViewBlockExplorer, + onViewNonEvmExplorer, + providerType, + blockExplorerUrl, + nonEvmExplorerUrl, + showEvmFooter, + isFetchingNextPage, + showNonEvmExplorerLink, + showNonEvmFooter, + configBlockExplorerUrl, + tw, + ]); + + const [refreshing, setRefreshing] = useState(false); + const { + speedUpIsOpen, + cancelIsOpen, + confirmDisabled, + existingTx, + onSpeedUpAction, + onCancelAction, + onSpeedUpCancelCompleted, + speedUpTransaction, + cancelTransaction, + signQRTransaction, + signLedgerTransaction, + cancelUnsignedQRTransaction, + } = useUnifiedTxActions(); + + const onRefresh = useCallback(async () => { + setRefreshing(true); + try { + await Promise.all([updateIncomingTransactions(), refetch()]); + } finally { + setRefreshing(false); + } + }, [refetch]); + + const handleActivityItemPress = useCallback( + (item: ActivityListItem) => { + const { raw } = item; + if (!raw) return; + + const itemBridgeHistoryItem = getBridgeHistoryItemByHash(item.data.hash); + const actionKey = resolveActivityListItemTitle( + item, + itemBridgeHistoryItem + ? getSwapBridgeTxActivityTitle(itemBridgeHistoryItem) + : undefined, + ); + + const selectedEvmAddress = + selectedAccountGroupEvmAddress || + selectedInternalAccount?.address || + ''; + + if (raw.type === 'keyringTransaction') { + const { from, to } = getActivityFromTo(item); + const value = getActivityValue(item); + navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.SHEET.MULTICHAIN_TRANSACTION_DETAILS, + params: { + transaction: raw.data, + displayData: { + title: actionKey, + from: from + ? { address: from, amount: value ?? '', unit: '' } + : undefined, + to: to + ? { address: to, amount: value ?? '', unit: '' } + : undefined, + isRedeposit: false, + }, + }, + }); + return; + } + + const tx = + raw.type === 'apiEvmTransaction' + ? selectedEvmAddress + ? normalizeTransaction(selectedEvmAddress, raw.data) + : undefined + : raw.data.primaryTransaction; + + if (!tx) return; + + if ( + raw.type === 'localTransaction' && + tx.type === TransactionType.bridge + ) { + const bridgeTxHistoryItem = + bridgeHistory[tx.id] ?? + (tx.actionId ? bridgeHistory[tx.actionId] : undefined) ?? + Object.values(bridgeHistory).find( + (itemValue) => + (itemValue as unknown as { originalTransactionId?: string }) + .originalTransactionId === tx.id, + ); + + handleUnifiedSwapsTxHistoryItemClick({ + navigation, + evmTxMeta: tx, + bridgeTxHistoryItem, + }); + return; + } + + const { from, to } = getActivityFromTo(item); + const value = getActivityValue(item); + + navigation.navigate(Routes.MODAL.ROOT_MODAL_FLOW, { + screen: Routes.SHEET.TRANSACTION_DETAILS, + params: { + tx, + transactionElement: { + actionKey, + value, + }, + transactionDetails: { + hash: item.data.hash, + renderFrom: from, + renderTo: to, + renderValue: value, + transactionType: item.type, + txChainId: tx.chainId, + }, + showSpeedUpModal: noop, + showCancelModal: noop, + }, + }); + }, + [ + bridgeHistory, + getBridgeHistoryItemByHash, + navigation, + selectedAccountGroupEvmAddress, + selectedInternalAccount?.address, + ], + ); + + // Index of the last API-confirmed EVM item — used to trigger pagination. + const lastConfirmedEvmIndex = useMemo(() => { + for (let index = data.length - 1; index >= 0; index -= 1) { + const item = data[index]; + if (item.raw?.type === 'apiEvmTransaction') { + return index; + } + } + return -1; + }, [data]); + + const lastConfirmedEvmKey = + lastConfirmedEvmIndex >= 0 + ? generateKey(data[lastConfirmedEvmIndex]) + : undefined; + + const onViewableItemsChanged = useCallback( + ({ viewableItems }: { viewableItems: ViewToken[] }) => { + if ( + !hasNextPage || + isFetchingNextPage || + !lastConfirmedEvmKey || + lastConfirmedEvmIndex < 0 + ) { + return; + } + + const prefetchIndex = Math.max( + lastConfirmedEvmIndex - confirmedEvmOverscan, + 0, + ); + const isNearPrefetchThreshold = viewableItems.some( + ({ index }) => typeof index === 'number' && index >= prefetchIndex, + ); + + if (!isNearPrefetchThreshold) return; + fetchNextPage(); + }, + [ + fetchNextPage, + hasNextPage, + isFetchingNextPage, + lastConfirmedEvmIndex, + lastConfirmedEvmKey, + ], + ); + + const listRef = useRef>(null); + + const { handleScroll } = useTransactionAutoScroll(data, listRef, { + keyExtractor: (item: ActivityListItem) => generateKey(item), + }); + + const handleListScroll = useCallback( + (event: NativeSyntheticEvent) => { + handleScroll(); + onScroll?.(event); + }, + [handleScroll, onScroll], + ); + + const renderEmptyList = () => ( + + + + ); + + const renderInitialLoading = () => ( + + + + ); + + const shouldShowTransactionList = !isInitialLoading && data.length > 0; + const items = shouldShowTransactionList ? data : []; + + const renderItem = ({ + item, + index, + }: { + item: ActivityListItem; + index: number; + }) => { + const raw = item.raw; + + // Pending local EVM transactions: route to TransactionElement for speed-up/cancel UI. + if (raw?.type === 'localTransaction' && item.status === 'pending') { + const tx = raw.data.primaryTransaction; + return ( + + ); + } + + // Non-EVM bridge transactions: route to MultichainBridgeTransactionListItem. + if (raw?.type === 'keyringTransaction') { + const srcTxHash = raw.data.id; + const bridgeHistoryItem = getBridgeHistoryItemByHash(srcTxHash); + if (bridgeHistoryItem) { + return ( + + ); + } + } + + // All other items (API EVM confirmed, completed local EVM, non-EVM non-bridge): + // render from the shared ActivityListItem shape. + // + // Preserve the legacy Activity title for swap/bridge rows (e.g. + // "Swap ETH to USDC", "Bridge to Optimism") by deriving it from bridge + // history, mirroring TransactionElement. Falls back to the kind-based title. + const bridgeHistoryItem = getBridgeHistoryItemByHash(item.data.hash); + const title = bridgeHistoryItem + ? getSwapBridgeTxActivityTitle(bridgeHistoryItem) + : undefined; + + return ( + + ); + }; + + return ( + + + + {({ isChartBeingTouched }) => ( + + } + onScroll={handleListScroll} + onViewableItemsChanged={onViewableItemsChanged} + viewabilityConfig={visibilityConfig} + scrollEventThrottle={16} + scrollEnabled={!isChartBeingTouched} + /> + )} + + {/* Speed up / Cancel modals */} + + + + ); +}; + +export default ActivityList; diff --git a/app/components/Views/ActivityList/ActivityList.view.test.tsx b/app/components/Views/ActivityList/ActivityList.view.test.tsx new file mode 100644 index 00000000000..db9cbacdb69 --- /dev/null +++ b/app/components/Views/ActivityList/ActivityList.view.test.tsx @@ -0,0 +1,84 @@ +import '../../../../tests/component-view/mocks'; +import { fireEvent, waitFor, within } from '@testing-library/react-native'; +import { RefreshControl } from 'react-native'; +import Engine from '../../../core/Engine'; +import Routes from '../../../constants/navigation/Routes'; +import { strings } from '../../../../locales/i18n'; +import { describeForPlatforms } from '../../../../tests/component-view/platform'; +import { + buildConfirmedLocalSendTransaction, + buildPendingLocalSendTransaction, + initialStateActivityWithLocalTransactions, +} from '../../../../tests/component-view/presets/activity'; +import { + renderActivityListView, + renderActivityListViewWithRoutes, +} from '../../../../tests/component-view/renderers/activity'; +import { getRouteProbeTestId } from '../../../../tests/component-view/render'; +import { + activityListRowItemTestId, + activityListRowStatusTestId, +} from './ActivityList.testIds'; + +const transactionControllerWithIncomingSync = Engine.context + .TransactionController as unknown as { + updateIncomingTransactions: jest.MockedFunction<() => Promise>; +}; + +describeForPlatforms('ActivityList', () => { + it('shows pending and confirmed local rows then opens transaction details from a confirmed row', async () => { + const state = initialStateActivityWithLocalTransactions([ + buildConfirmedLocalSendTransaction(), + buildPendingLocalSendTransaction(), + ]).build(); + + const { findByTestId } = renderActivityListViewWithRoutes({ + state, + extraRoutes: [{ name: Routes.MODAL.ROOT_MODAL_FLOW }], + }); + + const pendingStatus = await findByTestId(activityListRowStatusTestId(0)); + + expect(pendingStatus).toHaveTextContent(strings('transaction.submitted')); + + const confirmedRow = await findByTestId(activityListRowItemTestId(1)); + const confirmedScope = within(confirmedRow); + + expect(confirmedScope.getByText('Sent ETH')).toBeOnTheScreen(); + expect( + confirmedScope.getByTestId(activityListRowStatusTestId(1)), + ).toHaveTextContent(strings('transaction.confirmed')); + expect(confirmedScope.getByText('-1 ETH')).toBeOnTheScreen(); + + fireEvent.press(confirmedRow); + + expect( + await findByTestId(getRouteProbeTestId(Routes.MODAL.ROOT_MODAL_FLOW)), + ).toBeOnTheScreen(); + }); + + it('pull to refresh on an empty list syncs incoming transactions through Engine', async () => { + const updateIncomingSpy = jest + .spyOn( + transactionControllerWithIncomingSync, + 'updateIncomingTransactions', + ) + .mockResolvedValue(undefined); + + const { UNSAFE_getByType } = renderActivityListView({ + overrides: { + settings: { + basicFunctionalityEnabled: true, + }, + }, + }); + + fireEvent(UNSAFE_getByType(RefreshControl), 'refresh'); + + await waitFor(() => { + expect(updateIncomingSpy).toHaveBeenCalledTimes(1); + }); + + updateIncomingSpy.mockRestore(); + }); +}); diff --git a/app/components/Views/ActivityList/helpers/adapters.test.ts b/app/components/Views/ActivityList/helpers/adapters.test.ts new file mode 100644 index 00000000000..d4ef537547a --- /dev/null +++ b/app/components/Views/ActivityList/helpers/adapters.test.ts @@ -0,0 +1,150 @@ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import { + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import { normalizeTransaction } from './adapters'; + +const address = '0x9bed78535d6a03a955f1504aadba974d9a29e292'; +const recipient = '0x80181d3ba89220cdb80234fc7aa19d5cc56229cc'; +const token = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; + +const makeTx = ( + overrides: Partial = {}, +): V1TransactionByHashResponse => + ({ + blockNumber: 10, + chainId: 8453, + from: address, + gas: '21000', + gasPrice: '1', + gasUsed: '21000', + hash: '0xhash', + isError: false, + methodId: '0x', + nonce: 7, + timestamp: '2026-01-01T00:00:00.000Z', + to: recipient, + value: '1', + valueTransfers: [], + ...overrides, + }) as unknown as V1TransactionByHashResponse; + +describe('normalizeTransaction', () => { + it('normalizes a simple send into TransactionMeta', () => { + const meta = normalizeTransaction(address, makeTx()); + + expect(meta).toMatchObject({ + chainId: '0x2105', + hash: '0xhash', + id: '0xhash-8453', + status: TransactionStatus.confirmed, + time: 1767225600000, + type: TransactionType.simpleSend, + txParams: { + chainId: '0x2105', + from: address, + to: recipient, + value: '0x1', + }, + }); + }); + + it('marks errored transactions as failed and maps known calldata method ids', () => { + expect( + normalizeTransaction( + address, + makeTx({ + isError: true, + methodId: '0x095ea7b3', + to: token, + value: '0', + }), + ), + ).toMatchObject({ + error: expect.any(Error), + status: TransactionStatus.failed, + type: TransactionType.tokenMethodApprove, + }); + + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0xa9059cbb', to: token, value: '0' }), + ).type, + ).toBe(TransactionType.tokenMethodTransfer); + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0x23b872dd', to: token, value: '0' }), + ).type, + ).toBe(TransactionType.tokenMethodTransferFrom); + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0xf242432a', to: token, value: '0' }), + ).type, + ).toBe(TransactionType.tokenMethodSafeTransferFrom); + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0x39509351', to: token, value: '0' }), + ).type, + ).toBe(TransactionType.tokenMethodIncreaseAllowance); + }); + + it('normalizes incoming token transfers using transfer information and recipient address', () => { + const sender = '0x1111111111111111111111111111111111111111'; + const meta = normalizeTransaction( + address, + makeTx({ + from: sender, + to: token, + value: '0', + valueTransfers: [ + { + amount: '1000000', + contractAddress: token, + decimal: 6, + from: sender, + name: 'USD Coin', + symbol: 'USDC', + to: address, + transferType: 'ERC20', + }, + ], + }), + ); + + expect(meta).toMatchObject({ + isTransfer: true, + transferInformation: { + amount: '1000000', + contractAddress: token, + decimals: 6, + symbol: 'USDC', + }, + type: TransactionType.incoming, + txParams: { + to: address, + value: '0xf4240', + }, + }); + }); + + it('classifies contract deployments and value-bearing contract interactions', () => { + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0xabcdef12', to: undefined, value: '0' }), + ).type, + ).toBe(TransactionType.deployContract); + + expect( + normalizeTransaction( + address, + makeTx({ methodId: '0xabcdef12', to: recipient, value: '1' }), + ).type, + ).toBe(TransactionType.contractInteraction); + }); +}); diff --git a/app/components/Views/ActivityList/helpers/adapters.ts b/app/components/Views/ActivityList/helpers/adapters.ts new file mode 100644 index 00000000000..865a58c2361 --- /dev/null +++ b/app/components/Views/ActivityList/helpers/adapters.ts @@ -0,0 +1,138 @@ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import { + type TransactionMeta, + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import { + APPROVE_FUNCTION_SIGNATURE, + INCREASE_ALLOWANCE_SIGNATURE, + NFT_SAFE_TRANSFER_FROM_FUNCTION_SIGNATURE, + SET_APPROVAL_FOR_ALL_SIGNATURE, + TRANSFER_FROM_FUNCTION_SIGNATURE, + TRANSFER_FUNCTION_SIGNATURE, +} from '../../../../util/transactions'; +import { Hex } from 'viem'; +import { toHex } from '@metamask/controller-utils'; + +// Ported from transaction-controller +// - AccountsApiRemoteTransactionSource +// - determineTransactionType +function resolveTransactionMetaType( + transaction: V1TransactionByHashResponse, + isOutgoing: boolean, +) { + if (!isOutgoing) { + return TransactionType.incoming; + } + + const rawData = transaction.methodId?.toLowerCase(); + // Treat '0x' (empty calldata) the same as no methodId, since the API + // returns '0x' for simple ETH sends. + const data = rawData && rawData !== '0x' ? rawData : undefined; + + if (data && !transaction.to) { + return TransactionType.deployContract; + } + + const isContractAddress = Boolean(data?.length); + + if (!isContractAddress) { + return TransactionType.simpleSend; + } + + const hasValue = BigInt(transaction.value ?? '0') !== BigInt(0); + + if (hasValue) { + return TransactionType.contractInteraction; + } + + if (!data) { + return TransactionType.contractInteraction; + } + + switch (data) { + case APPROVE_FUNCTION_SIGNATURE: + return TransactionType.tokenMethodApprove; + case SET_APPROVAL_FOR_ALL_SIGNATURE: + return TransactionType.tokenMethodSetApprovalForAll; + case TRANSFER_FUNCTION_SIGNATURE: + return TransactionType.tokenMethodTransfer; + case TRANSFER_FROM_FUNCTION_SIGNATURE: + return TransactionType.tokenMethodTransferFrom; + case NFT_SAFE_TRANSFER_FROM_FUNCTION_SIGNATURE: + return TransactionType.tokenMethodSafeTransferFrom; + case INCREASE_ALLOWANCE_SIGNATURE: + return TransactionType.tokenMethodIncreaseAllowance; + default: + return TransactionType.contractInteraction; + } +} + +// Ported from transaction-controller normalizeTransaction +export function normalizeTransaction( + address: string, + transaction: V1TransactionByHashResponse, +) { + const { from, hash, methodId } = transaction; + const normalizedAddress = address.toLowerCase(); + + const status = transaction.isError + ? TransactionStatus.failed + : TransactionStatus.confirmed; + + // Find token transfer that involves the current address + const valueTransfer = transaction.valueTransfers?.find( + (vt) => + (vt.to?.toLowerCase() === normalizedAddress || + vt.from?.toLowerCase() === normalizedAddress) && + vt.contractAddress, + ); + + const isIncomingTokenTransfer = + valueTransfer?.to?.toLowerCase() === normalizedAddress && + from.toLowerCase() !== normalizedAddress; + const isOutgoing = from.toLowerCase() === normalizedAddress; + + const transferInformation = valueTransfer + ? { + amount: valueTransfer.amount, + contractAddress: valueTransfer.contractAddress, + decimals: valueTransfer.decimal, + symbol: valueTransfer.symbol, + } + : undefined; + + const meta: TransactionMeta = { + blockNumber: String(transaction.blockNumber), + chainId: toHex(transaction.chainId), + error: transaction.isError ? new Error('Transaction failed') : undefined, + hash, + id: `${hash}-${transaction.chainId}`, + isTransfer: isIncomingTokenTransfer, + networkClientId: '', + status, + time: Date.parse(transaction.timestamp) || 0, + toSmartContract: false, + transferInformation, + txParams: { + chainId: toHex(transaction.chainId), + data: methodId as Hex, + from: from as Hex, + gas: toHex(transaction.gas), + gasPrice: toHex(transaction.gasPrice), + gasUsed: toHex(transaction.gasUsed), + nonce: toHex(transaction.nonce), + to: isIncomingTokenTransfer ? address : transaction.to, + value: toHex( + isIncomingTokenTransfer + ? (valueTransfer?.amount ?? transaction.value) + : transaction.value, + ), + }, + type: resolveTransactionMetaType(transaction, isOutgoing), + verifiedOnBlockchain: false, + }; + + return meta; +} diff --git a/app/components/Views/ActivityList/helpers/transformations.test.ts b/app/components/Views/ActivityList/helpers/transformations.test.ts new file mode 100644 index 00000000000..e2e3ece9e5a --- /dev/null +++ b/app/components/Views/ActivityList/helpers/transformations.test.ts @@ -0,0 +1,240 @@ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import { + isBridgeHistoryForEvmTransaction, + mapNonEvmTransactions, + mergeTransactionsByTime, + selectApiEvmTransactions, + shouldSkipTransaction, +} from './transformations'; +import { + mapApiEvmTransactions, + mapKeyringTransaction, +} from '../../../../util/activity-adapters'; + +jest.mock('../../../../util/activity-adapters', () => ({ + mapApiEvmTransactions: jest.fn(({ transaction }) => ({ + type: 'send', + chainId: `eip155:${transaction.chainId}`, + status: 'success', + timestamp: Date.parse(transaction.timestamp), + data: { hash: transaction.hash }, + raw: { type: 'apiEvmTransaction', data: transaction }, + })), + mapKeyringTransaction: jest.fn(({ transaction }) => ({ + type: 'send', + chainId: transaction.chain, + status: 'success', + timestamp: 1, + data: { hash: transaction.id }, + raw: { type: 'keyringTransaction', data: transaction }, + })), +})); + +const address = '0x9bed78535d6a03a955f1504aadba974d9a29e292'; +const otherAddress = '0x80181d3ba89220cdb80234fc7aa19d5cc56229cc'; + +const makeTx = ( + overrides: Partial = {}, +): V1TransactionByHashResponse => + ({ + chainId: 1, + from: address, + hash: '0xhash', + methodId: '0x', + timestamp: '2026-01-01T00:00:00.000Z', + to: otherAddress, + value: '1', + valueTransfers: [], + ...overrides, + }) as unknown as V1TransactionByHashResponse; + +describe('ActivityList transformations', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('shouldSkipTransaction', () => { + it('skips excluded hashes, unrelated transactions, spam, and empty self transfers', () => { + expect( + shouldSkipTransaction(address, makeTx(), new Set(['0xhash'])), + ).toBe(true); + expect( + shouldSkipTransaction( + address, + makeTx({ from: otherAddress, to: otherAddress }), + ), + ).toBe(true); + expect( + shouldSkipTransaction( + address, + makeTx({ transactionType: 'SPAM_TOKEN_TRANSFER' }), + ), + ).toBe(true); + expect( + shouldSkipTransaction( + address, + makeTx({ + from: address, + methodId: '0x', + to: address, + value: '0', + valueTransfers: [], + }), + ), + ).toBe(true); + }); + + it('skips incoming transfers already handled by local sources and keeps normal outgoing transactions', () => { + expect( + shouldSkipTransaction( + address, + makeTx({ + from: otherAddress, + to: address, + valueTransfers: [ + { + amount: '1000000', + contractAddress: '0xtoken', + decimal: 6, + from: otherAddress, + name: 'Mock Token', + symbol: 'MOCK', + to: address, + transferType: 'ERC20', + }, + ], + }), + ), + ).toBe(true); + expect( + shouldSkipTransaction( + address, + makeTx({ + from: otherAddress, + to: address, + valueTransfers: [ + { + amount: '1', + contractAddress: '', + decimal: 18, + from: otherAddress, + name: 'Ether', + symbol: 'ETH', + to: address, + transferType: 'NATIVE', + }, + ], + }), + ), + ).toBe(true); + expect(shouldSkipTransaction(address, makeTx())).toBe(false); + }); + }); + + it('matches bridge history by tx ids, original id, and source hash', () => { + const bridgeHistoryValues = [ + { + txMetaId: 'meta-id', + originalTransactionId: 'original-id', + status: { srcChain: { txHash: '0xBridgeHash' } }, + }, + ]; + + expect( + isBridgeHistoryForEvmTransaction( + { id: 'meta-id' }, + bridgeHistoryValues as never, + ), + ).toBe(true); + expect( + isBridgeHistoryForEvmTransaction( + { actionId: 'original-id' }, + bridgeHistoryValues as never, + ), + ).toBe(true); + expect( + isBridgeHistoryForEvmTransaction( + { hash: '0xbridgehash' }, + bridgeHistoryValues as never, + ), + ).toBe(true); + expect( + isBridgeHistoryForEvmTransaction( + { hash: '0xother' }, + bridgeHistoryValues as never, + ), + ).toBe(false); + }); + + it('selects and maps API EVM transactions while preserving the infinite-query shape', () => { + const tx = makeTx({ hash: '0xkept' }); + const skipped = makeTx({ hash: '0xskipped' }); + const select = selectApiEvmTransactions({ + address, + excludedTxHashes: new Set(['0xskipped']), + }); + + const result = select({ + pageParams: [undefined], + pages: [ + { + data: [tx, skipped], + pageInfo: { + count: 2, + endCursor: 'next', + hasNextPage: true, + }, + unprocessedNetworks: [], + }, + ], + } as never); + + expect(result.pages[0].pageInfo.endCursor).toBe('next'); + expect(result.pages[0].data).toHaveLength(1); + expect(mapApiEvmTransactions).toHaveBeenCalledWith({ + subjectAddress: address.toLowerCase(), + transaction: tx, + environment: undefined, + }); + }); + + it('maps non-EVM transactions and merges by descending timestamp', () => { + const nonEvmItems = mapNonEvmTransactions([ + { id: 'solana-tx', chain: 'solana:mainnet' }, + ] as never); + + expect(mapKeyringTransaction).toHaveBeenCalledWith({ + transaction: { id: 'solana-tx', chain: 'solana:mainnet' }, + }); + expect(nonEvmItems[0].data.hash).toBe('solana-tx'); + + const merged = mergeTransactionsByTime( + [ + { + ...nonEvmItems[0], + timestamp: 1, + }, + ], + [ + { + type: 'receive', + chainId: 'eip155:1', + status: 'success', + timestamp: 3, + data: { from: otherAddress, hash: '0xconfirmed', to: address }, + }, + ], + [ + { + type: 'send', + chainId: 'solana:mainnet', + status: 'success', + timestamp: 2, + data: { from: otherAddress, hash: '0xnon-evm', to: address }, + }, + ], + ); + + expect(merged.map((item) => item.timestamp)).toEqual([3, 2, 1]); + }); +}); diff --git a/app/components/Views/ActivityList/helpers/transformations.ts b/app/components/Views/ActivityList/helpers/transformations.ts new file mode 100644 index 00000000000..9464761ac01 --- /dev/null +++ b/app/components/Views/ActivityList/helpers/transformations.ts @@ -0,0 +1,192 @@ +/** + * Transformation helpers for the UnifiedTransactionsView. + * Produces ActivityListItem[] from API EVM and non-EVM transaction sources. + * Local EVM transactions are handled separately by useLocalActivityItems. + */ +import { + type V1TransactionByHashResponse, + type V4MultiAccountTransactionsResponse, +} from '@metamask/core-backend'; +import type { BridgeHistoryItem } from '@metamask/bridge-status-controller'; +import type { Transaction as NonEvmTransaction } from '@metamask/keyring-api'; +import type { InfiniteData } from '@tanstack/react-query'; +import { + mapApiEvmTransactions, + mapKeyringTransaction, + type ActivityListItem, + type ActivityAdapterEnvironment, +} from '../../../../util/activity-adapters'; +import { mergeActivityItems } from '../../../../util/activity-adapters/adapters/dedup'; +import { equalsIgnoreCase } from '../../../../util/string'; + +export type { ActivityListItem }; + +const excludedTransactionTypes = ['SPAM_TOKEN_TRANSFER']; + +const getOriginalTransactionId = (bridgeHistoryItem: BridgeHistoryItem) => + (bridgeHistoryItem as unknown as { originalTransactionId?: string }) + .originalTransactionId; + +export const isBridgeHistoryForEvmTransaction = ( + tx: { id?: string; actionId?: string; hash?: string }, + bridgeHistoryValues: BridgeHistoryItem[], +) => + bridgeHistoryValues.some((bridgeHistoryItem) => { + const originalTransactionId = getOriginalTransactionId(bridgeHistoryItem); + return ( + bridgeHistoryItem.txMetaId === tx.id || + bridgeHistoryItem.txMetaId === tx.actionId || + originalTransactionId === tx.id || + originalTransactionId === tx.actionId || + equalsIgnoreCase(bridgeHistoryItem.status?.srcChain?.txHash, tx.hash) + ); + }); + +function isIncomingTokenTransfer( + address: string, + transaction: V1TransactionByHashResponse, +) { + const normalizedAddress = address.toLowerCase(); + return ( + transaction.valueTransfers?.some( + (transfer) => + Boolean(transfer.contractAddress) && + transfer.to?.toLowerCase() === normalizedAddress && + transfer.from?.toLowerCase() !== normalizedAddress, + ) ?? false + ); +} + +function isIncomingNativeTransfer( + address: string, + transaction: V1TransactionByHashResponse, +) { + const normalizedAddress = address.toLowerCase(); + let hasOutgoingTransfer = false; + let hasIncomingNativeTransfer = false; + + for (const transfer of transaction.valueTransfers ?? []) { + if ( + !hasOutgoingTransfer && + transfer.from?.toLowerCase() === normalizedAddress + ) { + hasOutgoingTransfer = true; + } + + if ( + !hasIncomingNativeTransfer && + transfer.to?.toLowerCase() === normalizedAddress && + !transfer.contractAddress + ) { + hasIncomingNativeTransfer = true; + } + + if (hasOutgoingTransfer && hasIncomingNativeTransfer) { + break; + } + } + + return hasIncomingNativeTransfer && !hasOutgoingTransfer; +} + +export function shouldSkipTransaction( + address: string, + transaction: V1TransactionByHashResponse, + excludedTxHashes?: Set, +) { + const rawFrom = transaction.from?.toLowerCase(); + const rawTo = transaction.to?.toLowerCase(); + const hash = transaction.hash?.toLowerCase(); + + if (hash && excludedTxHashes?.has(hash)) { + return true; + } + + if (rawFrom !== address && rawTo !== address) { + return true; + } + + if (excludedTransactionTypes.includes(transaction.transactionType ?? '')) { + return true; + } + + if ( + rawFrom === address && + rawTo === address && + transaction.value === '0' && + !transaction.valueTransfers?.length && + (!transaction.methodId || transaction.methodId === '0x') + ) { + return true; + } + + if (isIncomingTokenTransfer(address, transaction)) { + return true; + } + + return rawFrom !== address && isIncomingNativeTransfer(address, transaction); +} + +function transformApiTransactions( + address: string, + transactions: V1TransactionByHashResponse[], + excludedTxHashes?: Set, + environment?: ActivityAdapterEnvironment, +): ActivityListItem[] { + const items: ActivityListItem[] = []; + const subjectAddress = address.toLowerCase(); + + for (const tx of transactions) { + if (shouldSkipTransaction(subjectAddress, tx, excludedTxHashes)) { + continue; + } + items.push( + mapApiEvmTransactions({ subjectAddress, transaction: tx, environment }), + ); + } + + return items; +} + +export function selectApiEvmTransactions({ + address, + excludedTxHashes, + environment, +}: { + address: string; + excludedTxHashes?: Set; + environment?: ActivityAdapterEnvironment; +}) { + return (data: InfiniteData) => ({ + ...data, + pages: data.pages.map((page) => ({ + ...page, + data: transformApiTransactions( + address, + page.data, + excludedTxHashes, + environment, + ), + })), + }); +} + +export function mapNonEvmTransactions( + transactions: NonEvmTransaction[], +): ActivityListItem[] { + return transactions.map((transaction) => + mapKeyringTransaction({ transaction }), + ); +} + +/** + * Merges and sorts all three transaction sources into a single ActivityListItem list. + * API-confirmed EVM items win deduplication by hash over local items. + */ +export function mergeTransactionsByTime( + localItems: ActivityListItem[], + confirmedEvmItems: ActivityListItem[], + nonEvmItems: ActivityListItem[], +): ActivityListItem[] { + return mergeActivityItems(localItems, confirmedEvmItems, nonEvmItems); +} diff --git a/app/components/Views/ActivityList/hooks/useLocalActivityItems.test.ts b/app/components/Views/ActivityList/hooks/useLocalActivityItems.test.ts new file mode 100644 index 00000000000..4cbc00772f3 --- /dev/null +++ b/app/components/Views/ActivityList/hooks/useLocalActivityItems.test.ts @@ -0,0 +1,205 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { + TransactionStatus, + TransactionType, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { useSelector } from 'react-redux'; +import { useLocalActivityItems } from './useLocalActivityItems'; +import { selectLocalTransactions } from '../../../../selectors/transactionController'; +import { selectBridgeHistoryForAccount } from '../../../../selectors/bridgeStatusController'; +import { selectEvmNetworkConfigurationsByChainId } from '../../../../selectors/networkController'; +import { selectAllTokens } from '../../../../selectors/tokensController'; +import { selectSelectedAccountGroupEvmInternalAccount } from '../../../../selectors/multichainAccounts/accountTreeController'; + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(), +})); + +jest.mock('../../../../selectors/transactionController', () => ({ + selectLocalTransactions: jest.fn(), +})); + +jest.mock('../../../../selectors/bridgeStatusController', () => ({ + selectBridgeHistoryForAccount: jest.fn(), +})); + +jest.mock('../../../../selectors/networkController', () => ({ + selectEvmNetworkConfigurationsByChainId: jest.fn(), +})); + +jest.mock('../../../../selectors/tokensController', () => ({ + selectAllTokens: jest.fn(), +})); + +jest.mock( + '../../../../selectors/multichainAccounts/accountTreeController', + () => ({ + selectSelectedAccountGroupEvmInternalAccount: jest.fn(), + }), +); + +const from = '0x9bed78535d6a03a955f1504aadba974d9a29e292'; +const recipient = '0x80181d3ba89220cdb80234fc7aa19d5cc56229cc'; +const usdc = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; + +const makeTx = (overrides: Partial = {}): TransactionMeta => + ({ + chainId: '0x2105', + hash: '0xhash', + id: 'tx-id', + status: TransactionStatus.submitted, + time: 1, + type: TransactionType.simpleSend, + txParams: { + from, + nonce: '0x1', + to: recipient, + value: '0x1', + }, + ...overrides, + }) as TransactionMeta; + +const selectorState = { + allTokens: { + '0x2105': { + [from.toLowerCase()]: [{ address: usdc, decimals: 6, symbol: 'USDC' }], + }, + }, + bridgeHistory: {}, + groupAccount: { address: from }, + localTransactions: [] as unknown[], + networks: { + '0x2105': { nativeCurrency: 'ETH' }, + }, +}; + +describe('useLocalActivityItems', () => { + beforeEach(() => { + jest.clearAllMocks(); + selectorState.localTransactions = []; + selectorState.bridgeHistory = {}; + (useSelector as unknown as jest.Mock).mockImplementation((selector) => { + switch (selector) { + case selectLocalTransactions: + return selectorState.localTransactions; + case selectBridgeHistoryForAccount: + return selectorState.bridgeHistory; + case selectEvmNetworkConfigurationsByChainId: + return selectorState.networks; + case selectAllTokens: + return selectorState.allTokens; + case selectSelectedAccountGroupEvmInternalAccount: + return selectorState.groupAccount; + default: + return undefined; + } + }); + }); + + it('groups retried transactions by nonce and marks only the lowest nonce as earliest', () => { + selectorState.localTransactions = [ + makeTx({ + id: 'nonce-1', + hash: '0xnonce1', + time: 1, + txParams: { from, nonce: '0x1', to: recipient, value: '0x1' }, + }), + makeTx({ + id: 'nonce-2', + hash: '0xnonce2', + time: 2, + txParams: { from, nonce: '0x2', to: recipient, value: '0x1' }, + }), + makeTx({ + id: 'nonce-2-retry', + hash: '0xnonce2retry', + time: 3, + type: TransactionType.retry, + txParams: { from, nonce: '0x2', to: recipient, value: '0x2' }, + }), + { id: 'smart-tx-without-params' }, + ]; + + const { result } = renderHook(() => useLocalActivityItems()); + + expect(result.current).toHaveLength(2); + expect(result.current[0]).toMatchObject({ + data: { hash: '0xnonce1' }, + isEarliestNonce: true, + }); + expect(result.current[1]).toMatchObject({ + data: { hash: '0xnonce2retry' }, + isEarliestNonce: false, + }); + }); + + it('enriches contract-token metadata from the selected account token list', () => { + selectorState.localTransactions = [ + makeTx({ + hash: '0xtoken', + type: TransactionType.tokenMethodTransfer, + txParams: { + data: '0xa9059cbb00000000000000000000000080181d3ba89220cdb80234fc7aa19d5cc56229cc00000000000000000000000000000000000000000000000000000000000f4240', + from, + nonce: '0x1', + to: usdc, + value: '0x0', + }, + }), + ]; + + const { result } = renderHook(() => useLocalActivityItems()); + + expect(result.current[0]).toMatchObject({ + data: { + token: { + amount: '1000000', + assetId: + 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + decimals: 6, + symbol: 'USDC', + }, + }, + }); + }); + + it('uses bridge history status and swap metadata enrichment', () => { + selectorState.bridgeHistory = { + bridgeTx: { + status: { destChain: { txHash: '0xdestination' } }, + }, + }; + selectorState.localTransactions = [ + makeTx({ + actionId: 'bridgeTx', + hash: '0xbridge', + id: 'bridge-id', + status: TransactionStatus.submitted, + type: TransactionType.bridge, + } as Partial), + makeTx({ + destinationTokenAddress: usdc, + destinationTokenSymbol: 'USDC', + hash: '0xswap', + id: 'swap-id', + sourceTokenSymbol: 'ETH', + type: TransactionType.swap, + txParams: { from, nonce: '0x2', to: usdc, value: '0x1' }, + } as Partial), + ]; + + const { result } = renderHook(() => useLocalActivityItems()); + + expect(result.current[0]).toMatchObject({ + data: { hash: '0xbridge' }, + status: 'success', + }); + expect(result.current[1]).toMatchObject({ + data: { + destinationToken: { direction: 'in', symbol: 'USDC' }, + sourceToken: { direction: 'out', symbol: 'ETH' }, + }, + }); + }); +}); diff --git a/app/components/Views/ActivityList/hooks/useLocalActivityItems.ts b/app/components/Views/ActivityList/hooks/useLocalActivityItems.ts new file mode 100644 index 00000000000..e1042b93784 --- /dev/null +++ b/app/components/Views/ActivityList/hooks/useLocalActivityItems.ts @@ -0,0 +1,273 @@ +/** + * Builds enriched TransactionGroups from Mobile's local transactions and maps them + * to ActivityListItem[] using the shared mapLocalTransaction adapter. + */ +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { + TransactionMeta, + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import type { Hex } from '@metamask/utils'; +import { selectLocalTransactions } from '../../../../selectors/transactionController'; +import { selectBridgeHistoryForAccount } from '../../../../selectors/bridgeStatusController'; +import { selectEvmNetworkConfigurationsByChainId } from '../../../../selectors/networkController'; +import { selectAllTokens } from '../../../../selectors/tokensController'; +import { selectSelectedAccountGroupEvmInternalAccount } from '../../../../selectors/multichainAccounts/accountTreeController'; +import { + mapLocalTransaction, + mobileActivityAdapterEnvironment, + type TransactionGroup, + type ActivityListItem, + type Status, + type TokenAmount, +} from '../../../../util/activity-adapters'; + +const BRIDGE_FAIL_STATUSES = [ + TransactionStatus.failed, + TransactionStatus.dropped, + TransactionStatus.rejected, +] as string[]; + +/** + * Checks whether a transaction is a TransactionMeta (vs SmartTransaction). + * SmartTransaction objects have chainId on the object when returned from the Mobile selector. + */ +function isTransactionMetaLike( + tx: unknown, +): tx is TransactionMeta & { isSmartTransaction?: boolean } { + return Boolean( + tx && + typeof tx === 'object' && + 'txParams' in tx && + (tx as { txParams?: unknown }).txParams !== undefined, + ); +} + +/** + * Returns whether the pending transaction has the lowest nonce among all pending + * transactions for the same sender+chain, which determines if it is "earliest". + */ +function computeIsEarliestNonce( + tx: TransactionMeta, + allLocalTxs: TransactionMeta[], +): boolean { + const { txParams } = tx; + if ( + !txParams?.from || + txParams.nonce === undefined || + txParams.nonce === null + ) { + return true; + } + const ownNonce = Number(txParams.nonce); + const from = txParams.from.toLowerCase(); + const chain = tx.chainId?.toLowerCase(); + + return !allLocalTxs.some((other) => { + if (other.id === tx.id) return false; + const otherNonce = Number(other.txParams?.nonce); + return ( + other.txParams?.from?.toLowerCase() === from && + other.chainId?.toLowerCase() === chain && + otherNonce < ownNonce + ); + }); +} + +function getTransactionGroupKey(tx: TransactionMeta): string { + const chainId = tx.chainId?.toLowerCase() ?? 'unknown-chain'; + const from = tx.txParams?.from?.toLowerCase() ?? 'unknown-from'; + const nonce = tx.txParams?.nonce; + + if (nonce !== undefined && nonce !== null) { + return `${chainId}:${from}:${nonce}`; + } + + return `${chainId}:${from}:${tx.id}`; +} + +function buildTransactionGroups( + transactions: (TransactionMeta & { isSmartTransaction?: boolean })[], +): TransactionGroup[] { + const groupsByKey = new Map< + string, + (TransactionMeta & { isSmartTransaction?: boolean })[] + >(); + + for (const tx of transactions) { + const key = getTransactionGroupKey(tx); + const group = groupsByKey.get(key) ?? []; + group.push(tx); + groupsByKey.set(key, group); + } + + return [...groupsByKey.values()].map((groupTransactions) => { + const sorted = [...groupTransactions].sort( + (a, b) => (a.time ?? 0) - (b.time ?? 0), + ); + const initialTransaction = sorted[0]; + const primaryTransaction = sorted[sorted.length - 1]; + const nonce = initialTransaction.txParams?.nonce; + + return { + hasCancelled: sorted.some((tx) => tx.type === TransactionType.cancel), + hasRetried: sorted.some((tx) => tx.type === TransactionType.retry), + initialTransaction, + nonce: nonce === undefined || nonce === null ? undefined : String(nonce), + primaryTransaction, + transactions: sorted, + }; + }); +} + +/** + * Returns bridge activity status override for a local bridge transaction. + */ +function getBridgeActivityStatus( + tx: TransactionMeta, + bridgeHistory: ReturnType, +): Status | undefined { + if (tx.type !== TransactionType.bridge) return undefined; + const historyItem = + bridgeHistory[tx.id] ?? + (tx.actionId ? bridgeHistory[tx.actionId] : undefined) ?? + Object.values(bridgeHistory).find( + (item) => + (item as unknown as { originalTransactionId?: string }) + .originalTransactionId === tx.id, + ); + + if (!historyItem) return undefined; + + if (historyItem.status?.destChain?.txHash) { + return 'success'; + } + + if (BRIDGE_FAIL_STATUSES.includes(tx.status)) { + return 'failed'; + } + + return undefined; +} + +/** + * Derives source+destination token enrichment from swap metadata stored on TransactionMeta. + */ +function getSwapTokenEnrichment( + tx: TransactionMeta, + nativeSymbol: string | undefined, +): { sourceToken?: TokenAmount; destinationToken?: TokenAmount } { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const meta = tx as any; + const srcSymbol: string | undefined = + meta.sourceTokenSymbol ?? meta.swapMetaData?.token_from; + const dstSymbol: string | undefined = + meta.destinationTokenSymbol ?? meta.swapMetaData?.token_to; + + // For swaps where source is native, fallback to nativeSymbol if no explicit srcSymbol + const effectiveSrcSymbol = + srcSymbol ?? + (meta.destinationTokenAddress && nativeSymbol ? nativeSymbol : undefined); + + if (!effectiveSrcSymbol && !dstSymbol) return {}; + + const sourceToken: TokenAmount | undefined = effectiveSrcSymbol + ? { direction: 'out', symbol: effectiveSrcSymbol } + : undefined; + const destinationToken: TokenAmount | undefined = dstSymbol + ? { direction: 'in', symbol: dstSymbol } + : undefined; + + return { sourceToken, destinationToken }; +} + +export function useLocalActivityItems(): ActivityListItem[] { + // Outgoing / user-initiated txs only — excludes incoming spam from TransactionController. + const localTransactions = useSelector(selectLocalTransactions); + const bridgeHistory = useSelector(selectBridgeHistoryForAccount); + const networkConfigurations = useSelector( + selectEvmNetworkConfigurationsByChainId, + ); + const groupEvmAccount = useSelector( + selectSelectedAccountGroupEvmInternalAccount, + ); + // allTokens: Record> + const allTokens = useSelector(selectAllTokens) as Record< + string, + Record + >; + + const transactionMetaList = useMemo( + () => localTransactions.filter(isTransactionMetaLike), + [localTransactions], + ); + + return useMemo(() => { + const items: ActivityListItem[] = []; + const accountAddress = groupEvmAccount?.address?.toLowerCase(); + const groupedTransactions = buildTransactionGroups(transactionMetaList); + + for (const baseGroup of groupedTransactions) { + const { primaryTransaction: tx } = baseGroup; + const txChainId = tx.chainId as Hex | undefined; + + // Native symbol from network configuration + const chainConfig = txChainId + ? networkConfigurations?.[txChainId] + : undefined; + const nativeAssetSymbol = chainConfig?.nativeCurrency; + + // Token metadata for contract interactions (ERC-20 transfers, approvals) + const contractAddress = tx.txParams?.to?.toLowerCase(); + let contractTokenMetadata: + | { symbol?: string; decimals?: number } + | undefined; + + if (accountAddress && txChainId && contractAddress) { + const chainTokens = allTokens[txChainId]?.[accountAddress as Hex] ?? []; + const matchingToken = chainTokens.find( + (t) => t.address?.toLowerCase() === contractAddress, + ); + if (matchingToken) { + contractTokenMetadata = { + symbol: matchingToken.symbol, + decimals: matchingToken.decimals, + }; + } + } + + // Bridge activity status override + const activityStatus = getBridgeActivityStatus(tx, bridgeHistory); + + // Swap token enrichment + const { sourceToken, destinationToken } = getSwapTokenEnrichment( + tx, + nativeAssetSymbol, + ); + + const isEarliestNonce = computeIsEarliestNonce(tx, transactionMetaList); + + const group: TransactionGroup = { + ...baseGroup, + activityStatus, + sourceToken, + destinationToken, + nativeAssetSymbol, + contractTokenMetadata, + }; + + const item = mapLocalTransaction(group, mobileActivityAdapterEnvironment); + items.push({ ...item, isEarliestNonce }); + } + + return items; + }, [ + transactionMetaList, + bridgeHistory, + networkConfigurations, + allTokens, + groupEvmAccount?.address, + ]); +} diff --git a/app/components/Views/ActivityList/index.ts b/app/components/Views/ActivityList/index.ts new file mode 100644 index 00000000000..a25d2aef78f --- /dev/null +++ b/app/components/Views/ActivityList/index.ts @@ -0,0 +1 @@ +export { default } from './ActivityList'; diff --git a/app/components/Views/ActivityList/types.ts b/app/components/Views/ActivityList/types.ts new file mode 100644 index 00000000000..0139a47e160 --- /dev/null +++ b/app/components/Views/ActivityList/types.ts @@ -0,0 +1,10 @@ +/** + * Unified Activity list item type - re-exported from the shared activity adapters. + * All three transaction sources (API EVM, local EVM, non-EVM) produce this shape. + */ +export type { + ActivityListItem, + ActivityKind, + Status, + TokenAmount, +} from '../../../util/activity-adapters'; diff --git a/app/components/Views/ActivityList/useTransactionAutoScroll.test.ts b/app/components/Views/ActivityList/useTransactionAutoScroll.test.ts new file mode 100644 index 00000000000..91314482271 --- /dev/null +++ b/app/components/Views/ActivityList/useTransactionAutoScroll.test.ts @@ -0,0 +1,137 @@ +import { act, renderHook } from '@testing-library/react-hooks'; +import { useTransactionAutoScroll } from './useTransactionAutoScroll'; +import Logger from '../../../util/Logger'; + +jest.mock('../../../util/Logger', () => ({ + error: jest.fn(), +})); + +describe('useTransactionAutoScroll', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + const keyExtractor = (item: { id: string }) => item.id; + + it('does not scroll on initial render, then scrolls when a new first item appears', () => { + const listRef = { + current: { + scrollToOffset: jest.fn(), + }, + }; + const { rerender } = renderHook( + ({ data }) => + useTransactionAutoScroll(data, listRef as never, { + delay: 50, + keyExtractor, + }), + { + initialProps: { data: [{ id: 'old' }] }, + }, + ); + + act(() => { + jest.runOnlyPendingTimers(); + }); + expect(listRef.current.scrollToOffset).not.toHaveBeenCalled(); + + rerender({ data: [{ id: 'new' }, { id: 'old' }] }); + + act(() => { + jest.advanceTimersByTime(50); + }); + + expect(listRef.current.scrollToOffset).toHaveBeenCalledWith({ + animated: true, + offset: 0, + }); + }); + + it('clears pending auto-scroll when disabled and ignores new items while user is scrolling', () => { + const listRef = { + current: { + scrollToOffset: jest.fn(), + }, + }; + const { rerender, result } = renderHook( + ({ data, enabled }) => + useTransactionAutoScroll(data, listRef as never, { + delay: 50, + enabled, + keyExtractor, + }), + { + initialProps: { data: [{ id: 'old' }], enabled: true }, + }, + ); + + act(() => { + result.current.handleScroll(); + }); + rerender({ data: [{ id: 'new' }, { id: 'old' }], enabled: true }); + + act(() => { + jest.advanceTimersByTime(50); + }); + expect(listRef.current.scrollToOffset).not.toHaveBeenCalled(); + + act(() => { + jest.advanceTimersByTime(1000); + }); + rerender({ + data: [{ id: 'newer' }, { id: 'new' }, { id: 'old' }], + enabled: false, + }); + act(() => { + jest.runOnlyPendingTimers(); + }); + + expect(listRef.current.scrollToOffset).not.toHaveBeenCalled(); + }); + + it('logs extractor and scroll errors without throwing', () => { + const listRef = { + current: { + scrollToOffset: jest.fn(() => { + throw new Error('scroll failed'); + }), + }, + }; + const { rerender } = renderHook( + ({ data }) => + useTransactionAutoScroll(data, listRef as never, { + delay: 50, + keyExtractor: (item: { id: string }) => { + if (item.id === 'bad') { + throw new Error('bad item'); + } + return item.id; + }, + }), + { + initialProps: { data: [{ id: 'old' }] }, + }, + ); + + rerender({ data: [{ id: 'bad' }, { id: 'old' }] }); + expect(Logger.error).toHaveBeenCalledWith( + expect.any(Error), + 'useTransactionAutoScroll: Failed to extract item ID', + ); + + rerender({ data: [{ id: 'new' }, { id: 'bad' }, { id: 'old' }] }); + act(() => { + jest.advanceTimersByTime(50); + }); + + expect(Logger.error).toHaveBeenCalledWith( + expect.any(Error), + 'useTransactionAutoScroll: Auto-scroll failed', + ); + }); +}); diff --git a/app/components/Views/ActivityList/useTransactionAutoScroll.ts b/app/components/Views/ActivityList/useTransactionAutoScroll.ts new file mode 100644 index 00000000000..ad814e19bdb --- /dev/null +++ b/app/components/Views/ActivityList/useTransactionAutoScroll.ts @@ -0,0 +1,155 @@ +import { useRef, useEffect, useCallback, RefObject } from 'react'; +import { FlashListRef } from '@shopify/flash-list'; +import Logger from '../../../util/Logger'; + +interface UseTransactionAutoScrollOptions { + /** + * Whether auto-scroll is enabled + */ + enabled?: boolean; + /** + * Delay in milliseconds before scrolling (to ensure list has updated) + */ + delay?: number; + /** + * Function to extract a unique ID from an item + */ + keyExtractor: (item: T) => string | null; +} + +/** + * Custom hook to handle automatic scrolling to top when new transactions are added + * + * @param data - Array of items to monitor for changes + * @param listRef - Reference to the FlashList component + * @param options - Configuration options + * @returns Object containing the scroll handler + */ +export function useTransactionAutoScroll( + data: T[], + listRef: RefObject | null>, + options: UseTransactionAutoScrollOptions, +) { + const { enabled = true, delay = 150, keyExtractor } = options; + + const scrollTimeoutRef = useRef(null); + const isUserScrollingRef = useRef(false); + const userScrollTimeoutRef = useRef(null); + const isInitialRenderRef = useRef(true); + + // Track the first item ID to detect when a new item is added to the top + const previousFirstItemIdRef = useRef(null); + const previousDataLengthRef = useRef(0); + + /** + * Track user scrolling to prevent disruptive auto-scrolls + */ + const handleScroll = useCallback(() => { + isUserScrollingRef.current = true; + if (userScrollTimeoutRef.current) { + clearTimeout(userScrollTimeoutRef.current); + } + userScrollTimeoutRef.current = setTimeout(() => { + isUserScrollingRef.current = false; + }, 1000); + }, []); + + /** + * Scroll to top when a new item is added + */ + useEffect(() => { + // Clear any pending scroll when disabled + if (!enabled) { + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + scrollTimeoutRef.current = null; + } + return; + } + + // Safely extract the first item ID with error handling + const getCurrentFirstItemId = (): string | null => { + try { + if (data.length === 0) return null; + const firstItem = data[0]; + if (!firstItem) return null; + return keyExtractor(firstItem); + } catch (error) { + // Gracefully handle any unexpected item structure + Logger.error( + error as Error, + 'useTransactionAutoScroll: Failed to extract item ID', + ); + return null; + } + }; + + const currentFirstItemId = getCurrentFirstItemId(); + + // Skip auto-scroll on initial mount + if (isInitialRenderRef.current) { + isInitialRenderRef.current = false; + previousFirstItemIdRef.current = currentFirstItemId; + previousDataLengthRef.current = data.length; + return; + } + + // Detect if a new item was added + const listGrew = data.length > previousDataLengthRef.current; + const firstItemChanged = + previousFirstItemIdRef.current !== null && + currentFirstItemId !== null && + currentFirstItemId !== previousFirstItemIdRef.current; + + // Only scroll if we have valid item data and a change occurred + const hasNewItem = + data.length > 0 && + currentFirstItemId !== null && + (listGrew || firstItemChanged); + + if (hasNewItem && listRef.current) { + // Clear any pending scroll + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + + // Small delay to ensure list has updated before scrolling + scrollTimeoutRef.current = setTimeout(() => { + // Check user scrolling state when timeout fires, not when scheduled + if (isUserScrollingRef.current) { + return; + } + + try { + listRef.current?.scrollToOffset({ offset: 0, animated: true }); + } catch (error) { + // Silently handle scroll errors (e.g., list not ready) + Logger.error( + error as Error, + 'useTransactionAutoScroll: Auto-scroll failed', + ); + } + }, delay); + } + + previousFirstItemIdRef.current = currentFirstItemId; + previousDataLengthRef.current = data.length; + }, [data, enabled, delay, keyExtractor, listRef]); + + /** + * Cleanup timeouts on unmount + */ + useEffect( + () => () => { + if (scrollTimeoutRef.current) { + clearTimeout(scrollTimeoutRef.current); + } + if (userScrollTimeoutRef.current) { + clearTimeout(userScrollTimeoutRef.current); + } + }, + [], + ); + + return { handleScroll }; +} diff --git a/app/components/Views/ActivityList/useTransactionsQuery.test.ts b/app/components/Views/ActivityList/useTransactionsQuery.test.ts new file mode 100644 index 00000000000..b6349b9ac34 --- /dev/null +++ b/app/components/Views/ActivityList/useTransactionsQuery.test.ts @@ -0,0 +1,113 @@ +import { renderHook } from '@testing-library/react-hooks'; +import { useInfiniteQuery } from '@tanstack/react-query'; +import { useSelector } from 'react-redux'; +import { apiClient } from '../../../core/apiClient'; +import { useTransactionsQuery } from './useTransactionsQuery'; + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(), +})); + +jest.mock('@tanstack/react-query', () => ({ + useInfiniteQuery: jest.fn((options) => options), +})); + +jest.mock('../../../core/apiClient', () => ({ + apiClient: { + accounts: { + getV4MultiAccountTransactionsInfiniteQueryOptions: jest.fn(() => ({ + queryKey: ['transactions'], + queryFn: jest.fn(), + })), + }, + }, +})); + +jest.mock('./helpers/transformations', () => ({ + selectApiEvmTransactions: jest.fn((args) => ({ selectorArgs: args })), +})); + +const mockUseSelector = useSelector as unknown as jest.Mock; + +describe('useTransactionsQuery', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('uses the selected account-group EVM address and enabled networks', () => { + const excludedTxHashes = new Set(['0xskip']); + mockUseSelector + .mockReturnValueOnce({ address: '0xGroupAddress' }) + .mockReturnValueOnce('0xGlobalAddress') + .mockReturnValueOnce(['eip155:1']) + .mockReturnValueOnce(excludedTxHashes); + + renderHook(() => useTransactionsQuery()); + + expect( + apiClient.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions, + ).toHaveBeenCalledWith({ + accountAddresses: ['eip155:0:0xGroupAddress'], + networks: ['eip155:1'], + includeTxMetadata: true, + }); + expect(useInfiniteQuery).toHaveBeenCalledWith( + expect.objectContaining({ + enabled: true, + retry: false, + select: { + selectorArgs: { + address: '0xGroupAddress', + excludedTxHashes, + }, + }, + }), + ); + }); + + it('falls back to the global EVM address and disables the query without networks', () => { + mockUseSelector + .mockReturnValueOnce(undefined) + .mockReturnValueOnce('0xGlobalAddress') + .mockReturnValueOnce([]) + .mockReturnValueOnce(new Set()); + + renderHook(() => useTransactionsQuery()); + + expect( + apiClient.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions, + ).toHaveBeenCalledWith({ + accountAddresses: ['eip155:0:0xGlobalAddress'], + networks: [], + includeTxMetadata: true, + }); + expect(useInfiniteQuery).toHaveBeenCalledWith( + expect.objectContaining({ + enabled: false, + }), + ); + }); + + it('does not request account addresses when no EVM address exists', () => { + mockUseSelector + .mockReturnValueOnce(undefined) + .mockReturnValueOnce(undefined) + .mockReturnValueOnce(['eip155:1']) + .mockReturnValueOnce(new Set()); + + renderHook(() => useTransactionsQuery()); + + expect( + apiClient.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions, + ).toHaveBeenCalledWith({ + accountAddresses: [], + networks: ['eip155:1'], + includeTxMetadata: true, + }); + expect(useInfiniteQuery).toHaveBeenCalledWith( + expect.objectContaining({ + enabled: false, + }), + ); + }); +}); diff --git a/app/components/Views/ActivityList/useTransactionsQuery.ts b/app/components/Views/ActivityList/useTransactionsQuery.ts new file mode 100644 index 00000000000..6c6ba30a6ae --- /dev/null +++ b/app/components/Views/ActivityList/useTransactionsQuery.ts @@ -0,0 +1,46 @@ +import { useInfiniteQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; +import { useSelector } from 'react-redux'; +import { KnownCaipNamespace, toCaipAccountId } from '@metamask/utils'; +import { apiClient } from '../../../core/apiClient'; +import { selectEvmAddress } from '../../../selectors/accountsController'; +import { selectSelectedAccountGroupEvmInternalAccount } from '../../../selectors/multichainAccounts/accountTreeController'; +import { selectEvmEnabledCaipNetworks } from '../../../selectors/networkEnablementController'; +import { selectApiEvmTransactions } from './helpers/transformations'; +import { MINUTE } from '../../../constants/time'; +import { selectRequiredTransactionHashes } from '../../../selectors/transactionController'; + +export const useTransactionsQuery = () => { + const groupEvmAccount = useSelector( + selectSelectedAccountGroupEvmInternalAccount, + ); + const globalEvmAddress = useSelector(selectEvmAddress); + /** Activity must load EVM history for the group's EVM account when e.g. Bitcoin is selected. */ + const evmAddress = (groupEvmAccount?.address ?? globalEvmAddress ?? '') || ''; + const networks = useSelector(selectEvmEnabledCaipNetworks); + const excludedTxHashes = useSelector(selectRequiredTransactionHashes); + const accountAddresses = evmAddress + ? [toCaipAccountId(KnownCaipNamespace.Eip155, '0', evmAddress)] + : []; + + const queryOptions = + apiClient.accounts.getV4MultiAccountTransactionsInfiniteQueryOptions({ + accountAddresses, + networks, + includeTxMetadata: true, + }); + + const selectFn = useMemo( + () => selectApiEvmTransactions({ address: evmAddress, excludedTxHashes }), + [evmAddress, excludedTxHashes], + ); + + // @ts-expect-error apiClient returns v5 types, repo still in v4 + return useInfiniteQuery({ + ...queryOptions, + select: selectFn, + enabled: accountAddresses.length > 0 && networks.length > 0, + staleTime: 5 * MINUTE, + retry: false, + }); +}; diff --git a/app/components/Views/ActivityList/useUnifiedTxActions.test.ts b/app/components/Views/ActivityList/useUnifiedTxActions.test.ts new file mode 100644 index 00000000000..872e5db2253 --- /dev/null +++ b/app/components/Views/ActivityList/useUnifiedTxActions.test.ts @@ -0,0 +1,267 @@ +import { act, renderHook } from '@testing-library/react-hooks'; +import { + TransactionType, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { useNavigation } from '@react-navigation/native'; +import { useSelector } from 'react-redux'; +import Engine from '../../../core/Engine'; +import { useUnifiedTxActions } from './useUnifiedTxActions'; +import { + executeHardwareWalletOperation, + useHardwareWallet, +} from '../../../core/HardwareWallet'; +import { + speedUpTransaction, + getPreviousGasFromController, +} from '../../../util/transaction-controller'; +import { validateTransactionActionBalance } from '../../../util/transactions'; +import { isHardwareAccount } from '../../../util/address'; + +jest.mock('@react-navigation/native', () => ({ + useNavigation: jest.fn(), +})); + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(), +})); + +jest.mock('../../../component-library/components/Toast', () => { + const ReactActual = jest.requireActual('react'); + return { + ToastContext: ReactActual.createContext({ + toastRef: { current: { showToast: jest.fn() } }, + }), + }; +}); + +jest.mock('../../../core/Engine', () => ({ + __esModule: true, + default: { + context: { + ApprovalController: { + acceptRequest: jest.fn(), + rejectRequest: jest.fn(), + }, + TransactionController: { + stopTransaction: jest.fn(), + }, + }, + }, +})); + +jest.mock('../../../core/HardwareWallet', () => ({ + executeHardwareWalletOperation: jest.fn(async ({ execute }) => { + await execute(); + return true; + }), + useHardwareWallet: jest.fn(() => ({ + ensureDeviceReady: jest.fn(), + hideAwaitingConfirmation: jest.fn(), + setPendingOperationAddress: jest.fn(), + showAwaitingConfirmation: jest.fn(), + showHardwareWalletError: jest.fn(), + })), +})); + +jest.mock('../../../util/address', () => ({ + isHardwareAccount: jest.fn(() => false), +})); + +jest.mock('../../../util/confirmation/gas', () => ({ + getGasValuesForReplacement: jest.fn( + (params) => params ?? { gasPrice: '0x2' }, + ), + getMediumGasPriceHex: jest.fn(() => '0x2'), + normalizeReplacementGasFeeParams: jest.fn((params) => params), +})); + +jest.mock('../../../util/transaction-controller', () => ({ + getPreviousGasFromController: jest.fn(() => ({ gasPrice: '0x1' })), + speedUpTransaction: jest.fn(), +})); + +jest.mock('../../../util/transactions', () => ({ + validateTransactionActionBalance: jest.fn(() => false), +})); + +jest.mock('../../../util/confirmation/transactions', () => ({ + getTransactionUpdateErrorToastOptions: jest.fn((error) => ({ error })), +})); + +jest.mock('../../UI/QRHardware/QRSigningTransactionModal', () => ({ + QRSignMode: { Cancel: 'Cancel', SpeedUp: 'SpeedUp' }, + createQRSigningTransactionModalNavDetails: jest.fn((params) => [ + 'QRModal', + params, + ]), +})); + +const mockNavigate = jest.fn(); +const mockUseSelector = useSelector as unknown as jest.Mock; +const mockIsHardwareAccount = isHardwareAccount as unknown as jest.Mock; +let hardwareAccountType: 'ledger' | 'qr' | undefined; + +const tx = { + chainId: '0x1', + id: 'tx-id', + networkClientId: 'mainnet', + status: 'submitted', + time: 1, + type: TransactionType.simpleSend, + txParams: { + from: '0xselected', + gasPrice: '0x0', + to: '0xrecipient', + value: '0x1', + }, +} as unknown as TransactionMeta; + +describe('useUnifiedTxActions', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useNavigation as jest.Mock).mockReturnValue({ navigate: mockNavigate }); + hardwareAccountType = undefined; + mockIsHardwareAccount.mockImplementation( + (_address: string, keyringTypes: string[]) => + keyringTypes.includes( + hardwareAccountType === 'ledger' + ? 'Ledger Hardware' + : hardwareAccountType === 'qr' + ? 'QR Hardware Wallet Device' + : 'none', + ), + ); + mockUseSelector + .mockReturnValueOnce({ medium: { suggestedMaxFeePerGas: '2' } }) + .mockReturnValueOnce({}) + .mockReturnValueOnce('0xselected'); + }); + + it('opens and closes speed-up/cancel modal state and sets disabled from balance validation', () => { + (validateTransactionActionBalance as jest.Mock).mockReturnValueOnce(true); + const { result } = renderHook(() => useUnifiedTxActions()); + + act(() => { + result.current.onSpeedUpAction(true, tx); + }); + + expect(result.current.speedUpIsOpen).toBe(true); + expect(result.current.speedUpTxId).toBe('tx-id'); + expect(result.current.confirmDisabled).toBe(true); + + act(() => { + result.current.onSpeedUpCancelCompleted(); + }); + + expect(result.current.speedUpIsOpen).toBe(false); + expect(result.current.speedUpTxId).toBeNull(); + + act(() => { + result.current.onCancelAction(true, tx); + }); + + expect(result.current.cancelIsOpen).toBe(true); + expect(result.current.cancelTxId).toBe('tx-id'); + }); + + it('executes software speed-up and cancel actions', async () => { + const { result } = renderHook(() => useUnifiedTxActions()); + + act(() => { + result.current.onSpeedUpAction(true, tx); + }); + await act(async () => { + await result.current.speedUpTransaction({ gasPrice: '0x0' }); + }); + + expect(getPreviousGasFromController).toHaveBeenCalledWith('tx-id'); + expect(speedUpTransaction).toHaveBeenCalledWith('tx-id', { + gasPrice: '0x2', + }); + expect(result.current.speedUpIsOpen).toBe(false); + + act(() => { + result.current.onCancelAction(true, tx); + }); + await act(async () => { + await result.current.cancelTransaction({ gasPrice: '0x3' }); + }); + + expect( + Engine.context.TransactionController.stopTransaction, + ).toHaveBeenCalledWith('tx-id', { gasPrice: '0x3' }); + }); + + it('routes QR hardware replacement transactions through the QR modal', async () => { + hardwareAccountType = 'qr'; + const { result } = renderHook(() => useUnifiedTxActions()); + + act(() => { + result.current.onSpeedUpAction(true, tx); + }); + await act(async () => { + await result.current.speedUpTransaction({ gasPrice: '0x3' }); + }); + + expect(mockNavigate).toHaveBeenCalledWith( + 'QRModal', + expect.objectContaining({ + transactionId: 'tx-id', + signMode: 'SpeedUp', + }), + ); + }); + + it('executes Ledger signing and direct QR/unsigned helpers', async () => { + mockIsHardwareAccount.mockImplementation(() => true); + const { result } = renderHook(() => useUnifiedTxActions()); + + await act(async () => { + await result.current.signLedgerTransaction({ + id: 'tx-id', + replacementParams: { + maxFeePerGas: '0x4', + type: 'cancel', + } as never, + }); + }); + + expect(executeHardwareWalletOperation).toHaveBeenCalled(); + expect( + Engine.context.TransactionController.stopTransaction, + ).toHaveBeenCalledWith( + 'tx-id', + expect.objectContaining({ maxFeePerGas: '0x4' }), + ); + + await act(async () => { + await result.current.signQRTransaction(tx); + }); + expect(mockNavigate).toHaveBeenCalledWith( + 'QRModal', + expect.objectContaining({ transactionId: 'tx-id' }), + ); + + await act(async () => { + await result.current.cancelUnsignedQRTransaction(tx); + }); + expect( + Engine.context.ApprovalController.rejectRequest, + ).toHaveBeenCalledWith('tx-id', expect.objectContaining({ code: 4001 })); + }); + + it('throws from Ledger signing when no selected address exists', async () => { + mockUseSelector.mockReset(); + mockUseSelector + .mockReturnValueOnce({}) + .mockReturnValueOnce({}) + .mockReturnValueOnce(undefined); + const { result } = renderHook(() => useUnifiedTxActions()); + + await expect( + result.current.signLedgerTransaction({ id: 'ledger-tx' }), + ).rejects.toThrow('Missing selected address'); + expect(useHardwareWallet).toHaveBeenCalled(); + }); +}); diff --git a/app/components/Views/ActivityList/useUnifiedTxActions.ts b/app/components/Views/ActivityList/useUnifiedTxActions.ts new file mode 100644 index 00000000000..854a7a4227e --- /dev/null +++ b/app/components/Views/ActivityList/useUnifiedTxActions.ts @@ -0,0 +1,420 @@ +import { providerErrors } from '@metamask/rpc-errors'; +import { + CANCEL_RATE, + SPEED_UP_RATE, + type FeeMarketEIP1559Values, + type GasPriceValue, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { useNavigation } from '@react-navigation/native'; +import { useCallback, useContext, useState } from 'react'; +import { useSelector } from 'react-redux'; +import { ToastContext } from '../../../component-library/components/Toast'; +import ExtendedKeyringTypes from '../../../constants/keyringTypes'; +import Engine from '../../../core/Engine'; +import { selectAccounts } from '../../../selectors/accountTrackerController'; +import { selectSelectedInternalAccountFormattedAddress } from '../../../selectors/accountsController'; +import { selectGasFeeEstimates } from '../../../selectors/confirmTransaction'; +import { isHardwareAccount } from '../../../util/address'; +import { + getGasValuesForReplacement, + getMediumGasPriceHex, + normalizeReplacementGasFeeParams, +} from '../../../util/confirmation/gas'; +import { + getPreviousGasFromController, + speedUpTransaction as speedUpTx, +} from '../../../util/transaction-controller'; +import { validateTransactionActionBalance } from '../../../util/transactions'; +import { LedgerReplacementTxTypes } from '../../UI/LedgerModals/LedgerTransactionModal'; +import { type ReplacementTxParams } from '../../../core/HardwareWallet/transactionReplacementParams'; +import { + createQRSigningTransactionModalNavDetails, + QRSignMode, +} from '../../UI/QRHardware/QRSigningTransactionModal'; +import { + useHardwareWallet, + executeHardwareWalletOperation, +} from '../../../core/HardwareWallet'; +import { getTransactionUpdateErrorToastOptions } from '../../../util/confirmation/transactions'; + +type Maybe = T | null | undefined; + +export interface LegacyExistingGas { + isEIP1559Transaction?: false; + gasPrice?: string | number; +} + +export interface Eip1559ExistingGas { + isEIP1559Transaction: true; + maxFeePerGas?: string; + maxPriorityFeePerGas?: string; +} + +export type ExistingGas = LegacyExistingGas | Eip1559ExistingGas; + +/** Params for speed-up/cancel: controller shape only; optional error for UI flow */ +export type SpeedUpCancelParams = (GasPriceValue | FeeMarketEIP1559Values) & { + error?: string; +}; + +interface LedgerSignRequest { + id: string; + replacementParams?: ReplacementTxParams; + speedUpParams?: { + type?: string; + }; +} + +export const SpeedUpCancelModalState = { + Closed: 'closed', + SpeedUp: 'speedUp', + Cancel: 'cancel', +} as const; + +export type SpeedUpCancelModalState = + (typeof SpeedUpCancelModalState)[keyof typeof SpeedUpCancelModalState]; + +export function useUnifiedTxActions() { + const navigation = useNavigation(); + const { + ensureDeviceReady, + setPendingOperationAddress, + showAwaitingConfirmation, + hideAwaitingConfirmation, + showHardwareWalletError, + } = useHardwareWallet(); + const toastContext = useContext(ToastContext); + const toastRef = toastContext?.toastRef; + + const gasFeeEstimates = useSelector(selectGasFeeEstimates); + const accounts = useSelector(selectAccounts); + const selectedAddress = useSelector( + selectSelectedInternalAccountFormattedAddress, + ); + + const [speedUpCancelModalState, setSpeedUpCancelModalState] = + useState(SpeedUpCancelModalState.Closed); + const [confirmDisabled, setConfirmDisabled] = useState(false); + const [existingTx, setExistingTx] = useState(null); + const [speedUpTxId, setSpeedUpTxId] = useState>(null); + const [cancelTxId, setCancelTxId] = useState>(null); + + const isLedgerAccount = isHardwareAccount(selectedAddress ?? '', [ + ExtendedKeyringTypes.ledger, + ]); + + const isQRHardwareAccount = isHardwareAccount(selectedAddress ?? '', [ + ExtendedKeyringTypes.qr, + ]); + + const showTransactionUpdateErrorToast = useCallback( + (error: unknown) => { + toastRef?.current?.showToast( + getTransactionUpdateErrorToastOptions(error), + ); + }, + [toastRef], + ); + + const closeSpeedUpCancelModal = useCallback(() => { + setSpeedUpCancelModalState(SpeedUpCancelModalState.Closed); + setSpeedUpTxId(null); + setCancelTxId(null); + setExistingTx(null); + }, []); + + const onSpeedUpCancelCompleted = useCallback(() => { + closeSpeedUpCancelModal(); + }, [closeSpeedUpCancelModal]); + + const signLedgerTransaction = useCallback( + async (transaction: LedgerSignRequest) => { + if (!selectedAddress) { + throw new Error( + 'Missing selected address for hardware wallet operation', + ); + } + + const gasFeeParams = normalizeReplacementGasFeeParams( + transaction?.replacementParams, + ); + + const didComplete = await executeHardwareWalletOperation({ + address: selectedAddress, + operationType: 'transaction', + ensureDeviceReady, + setPendingOperationAddress, + showAwaitingConfirmation, + hideAwaitingConfirmation, + showHardwareWalletError, + execute: async () => { + if ( + transaction?.replacementParams?.type === + LedgerReplacementTxTypes.SPEED_UP + ) { + await speedUpTx(transaction.id, gasFeeParams); + return; + } + + if ( + transaction?.replacementParams?.type === + LedgerReplacementTxTypes.CANCEL + ) { + await Engine.context.TransactionController.stopTransaction( + transaction.id, + gasFeeParams, + ); + return; + } + + await Engine.context.ApprovalController.acceptRequest( + transaction.id, + undefined, + { + waitForResult: true, + }, + ); + }, + onRejected: onSpeedUpCancelCompleted, + }); + + if (didComplete) { + onSpeedUpCancelCompleted(); + } + }, + [ + selectedAddress, + ensureDeviceReady, + setPendingOperationAddress, + showAwaitingConfirmation, + hideAwaitingConfirmation, + showHardwareWalletError, + onSpeedUpCancelCompleted, + ], + ); + + const getGasPriceEstimate = () => getMediumGasPriceHex(gasFeeEstimates); + + const getCancelOrSpeedupValues = (): + | GasPriceValue + | FeeMarketEIP1559Values + | undefined => { + const txParams = existingTx?.txParams; + const existingGasPriceHex = txParams?.gasPrice; + if (existingGasPriceHex !== undefined && existingGasPriceHex !== '0x0') { + const existingGasPriceDecimal = parseInt(String(existingGasPriceHex), 16); + if (existingGasPriceDecimal !== 0) { + return undefined; + } + } + return { gasPrice: getGasPriceEstimate() }; + }; + + const onSpeedUpAction = (open: boolean, tx?: TransactionMeta) => { + if (!open) { + setSpeedUpCancelModalState(SpeedUpCancelModalState.Closed); + return; + } + if (!tx) { + return; + } + setExistingTx(tx); + setSpeedUpTxId(tx.id ?? null); + setConfirmDisabled( + Boolean( + validateTransactionActionBalance( + tx, + SPEED_UP_RATE.toString(), + accounts, + ), + ), + ); + setSpeedUpCancelModalState(SpeedUpCancelModalState.SpeedUp); + }; + + const onCancelAction = (open: boolean, tx?: TransactionMeta) => { + if (!open) { + setSpeedUpCancelModalState(SpeedUpCancelModalState.Closed); + return; + } + if (!tx) { + return; + } + setExistingTx(tx); + setCancelTxId(tx.id ?? null); + setConfirmDisabled( + Boolean( + validateTransactionActionBalance(tx, CANCEL_RATE.toString(), accounts), + ), + ); + setSpeedUpCancelModalState(SpeedUpCancelModalState.Cancel); + }; + + const getParamsToSend = ( + params?: SpeedUpCancelParams, + ): GasPriceValue | FeeMarketEIP1559Values | undefined => { + if (params?.error) { + return undefined; + } + if ( + params && + 'gasPrice' in params && + (params.gasPrice === '0x0' || parseInt(String(params.gasPrice), 16) === 0) + ) { + return getCancelOrSpeedupValues(); + } + if (params && ('maxFeePerGas' in params || 'gasPrice' in params)) { + return params; + } + return getCancelOrSpeedupValues(); + }; + + const speedUpTransaction = async (params?: SpeedUpCancelParams) => { + try { + if (params && 'error' in params && params.error) { + throw new Error(params.error); + } + if (!speedUpTxId) { + throw new Error('Missing transaction id for speed up'); + } + + const rawGasValues = getParamsToSend(params); + const gasValues = getGasValuesForReplacement( + rawGasValues, + getPreviousGasFromController(speedUpTxId), + SPEED_UP_RATE, + ); + + if (isLedgerAccount) { + const isEip1559 = gasValues && 'maxFeePerGas' in gasValues; + + await signLedgerTransaction({ + id: speedUpTxId, + speedUpParams: { type: 'SpeedUp' }, + replacementParams: { + type: LedgerReplacementTxTypes.SPEED_UP, + ...(isEip1559 + ? { eip1559GasFee: gasValues } + : { legacyGasFee: gasValues }), + }, + }); + return; + } + + if (isQRHardwareAccount) { + const transactionId = speedUpTxId; + navigation.navigate( + ...createQRSigningTransactionModalNavDetails({ + transactionId, + signMode: QRSignMode.SpeedUp, + gasValues, + onConfirmationComplete: () => undefined, + }), + ); + onSpeedUpCancelCompleted(); + return; + } + + await speedUpTx(speedUpTxId, gasValues); + onSpeedUpCancelCompleted(); + } catch (error: unknown) { + showTransactionUpdateErrorToast(error); + setSpeedUpCancelModalState(SpeedUpCancelModalState.Closed); + } + }; + + const cancelTransaction = async (params?: SpeedUpCancelParams) => { + try { + if (params && 'error' in params && params.error) { + throw new Error(params.error); + } + if (!cancelTxId) { + throw new Error('Missing transaction id for cancel'); + } + + const rawGasValues = getParamsToSend(params); + const gasValues = getGasValuesForReplacement( + rawGasValues, + getPreviousGasFromController(cancelTxId), + CANCEL_RATE, + ); + + if (isLedgerAccount) { + const isEip1559 = gasValues && 'maxFeePerGas' in gasValues; + + await signLedgerTransaction({ + id: cancelTxId, + replacementParams: { + type: LedgerReplacementTxTypes.CANCEL, + ...(isEip1559 + ? { eip1559GasFee: gasValues } + : { legacyGasFee: gasValues }), + }, + }); + return; + } + + if (isQRHardwareAccount) { + const transactionId = cancelTxId; + navigation.navigate( + ...createQRSigningTransactionModalNavDetails({ + transactionId, + signMode: QRSignMode.Cancel, + gasValues, + onConfirmationComplete: () => undefined, + }), + ); + onSpeedUpCancelCompleted(); + return; + } + + await Engine.context.TransactionController.stopTransaction( + cancelTxId, + gasValues, + ); + onSpeedUpCancelCompleted(); + } catch (error: unknown) { + showTransactionUpdateErrorToast(error); + setSpeedUpCancelModalState(SpeedUpCancelModalState.Closed); + } + }; + + const signQRTransaction = useCallback( + async (transactionMeta: TransactionMeta) => { + navigation.navigate( + ...createQRSigningTransactionModalNavDetails({ + transactionId: transactionMeta.id, + onConfirmationComplete: () => { + // Modal handles confirmation/rejection internally + }, + }), + ); + }, + [navigation], + ); + + const cancelUnsignedQRTransaction = async (tx: TransactionMeta) => { + await Engine.context.ApprovalController.rejectRequest( + tx.id, + providerErrors.userRejectedRequest(), + ); + }; + + return { + speedUpIsOpen: speedUpCancelModalState === SpeedUpCancelModalState.SpeedUp, + cancelIsOpen: speedUpCancelModalState === SpeedUpCancelModalState.Cancel, + confirmDisabled, + existingTx, + speedUpTxId, + cancelTxId, + onSpeedUpAction, + onCancelAction, + onSpeedUpCancelCompleted, + speedUpTransaction, + cancelTransaction, + signQRTransaction, + signLedgerTransaction, + cancelUnsignedQRTransaction, + } as const; +} diff --git a/app/components/Views/ActivityScreen/ActivityScreen.testIds.ts b/app/components/Views/ActivityScreen/ActivityScreen.testIds.ts new file mode 100644 index 00000000000..d28010f36ee --- /dev/null +++ b/app/components/Views/ActivityScreen/ActivityScreen.testIds.ts @@ -0,0 +1,12 @@ +export const ActivityScreenSelectorsIDs = { + SAFE_AREA_VIEW: 'activity-screen-safe-area-view', + HEADER: 'activity-screen-header', + BACK_BUTTON: 'activity-screen-back-button', + SEARCH_INPUT: 'activity-screen-search-input', + NETWORK_FILTER_CHIP: 'activity-screen-network-filter-chip', + TYPE_FILTER_CHIP: 'activity-screen-type-filter-chip', + TYPE_FILTER_SHEET: 'activity-screen-type-filter-sheet', + TYPE_FILTER_OPTION_PREFIX: 'activity-screen-type-filter-option-', + LIST: 'activity-screen-list', + EMPTY_STATE: 'activity-screen-empty-state', +}; diff --git a/app/components/Views/ActivityScreen/ActivityScreen.tsx b/app/components/Views/ActivityScreen/ActivityScreen.tsx new file mode 100644 index 00000000000..20f29d44bc0 --- /dev/null +++ b/app/components/Views/ActivityScreen/ActivityScreen.tsx @@ -0,0 +1,220 @@ +import React, { useCallback, useMemo, useState } from 'react'; +import { + LayoutChangeEvent, + type NativeScrollEvent, + type NativeSyntheticEvent, +} from 'react-native'; +import { type SharedValue, useSharedValue } from 'react-native-reanimated'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useNavigation } from '@react-navigation/native'; +import { useTailwind } from '@metamask/design-system-twrnc-preset'; +import { + Box, + HeaderStandardAnimated, + Text, + TextFieldSearch, + TextVariant, +} from '@metamask/design-system-react-native'; +import { strings } from '../../../../locales/i18n'; +import Routes from '../../../constants/navigation/Routes'; +import { ActivityScreenSelectorsIDs } from './ActivityScreen.testIds'; +import ActivityTypeFilterSheet, { + ACTIVITY_TYPE_FILTER_LABEL_KEY, +} from './components/ActivityTypeFilterSheet'; +import AssetListControlBar from './components/AssetListControlBar'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import ActivityList from '../ActivityList'; +import { TrendingTokenNetworkBottomSheet } from '../../UI/Trending/components/TrendingTokensBottomSheet/TrendingTokenNetworkBottomSheet'; +import { TRENDING_NETWORKS_LIST } from '../../UI/Trending/utils/trendingNetworksList'; +import type { CaipChainId } from '@metamask/utils'; +import { ActivityTypeFilter } from './types'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import ErrorBoundary from '../ErrorBoundary'; + +const updateScrollY = ( + scrollY: SharedValue, + event: NativeSyntheticEvent, +) => { + scrollY.value = event.nativeEvent.contentOffset.y; +}; + +const ActivityScreen = () => { + const tw = useTailwind(); + const navigation = useNavigation(); + + const scrollY = useSharedValue(0); + const titleSectionHeight = useSharedValue(0); + + const handleTitleLayout = useCallback( + (event: LayoutChangeEvent) => { + titleSectionHeight.value = event.nativeEvent.layout.height; + }, + [titleSectionHeight], + ); + + const [searchQuery, setSearchQuery] = useState(''); + // TODO: restore `ActivityTypeFilter.All` as the default once data-source + // unification lands. See `ACTIVITY_TYPE_FILTER_ORDER` in ./types.ts. + const [typeFilter, setTypeFilter] = useState( + ActivityTypeFilter.Transactions, + ); + const [isTypeSheetOpen, setIsTypeSheetOpen] = useState(false); + const [networkFilter, setNetworkFilter] = useState( + null, + ); + const [isNetworkSheetOpen, setIsNetworkSheetOpen] = useState(false); + + const handleClearSearch = useCallback(() => { + setSearchQuery(''); + }, []); + + const handleOpenTypeSheet = useCallback(() => { + setIsTypeSheetOpen(true); + }, []); + + const handleCloseTypeSheet = useCallback(() => { + setIsTypeSheetOpen(false); + }, []); + + const handleSelectTypeFilter = useCallback((filter: ActivityTypeFilter) => { + setTypeFilter(filter); + }, []); + + const isTypeFilterActive = typeFilter !== ActivityTypeFilter.All; + const typeFilterLabel = isTypeFilterActive + ? strings('activity_view.filter_types_selected', { + label: strings(ACTIVITY_TYPE_FILTER_LABEL_KEY[typeFilter]), + }) + : strings('activity_view.filter_all_types'); + + const isNetworkFilterActive = + Array.isArray(networkFilter) && networkFilter.length > 0; + const selectedNetworkName = isNetworkFilterActive + ? TRENDING_NETWORKS_LIST.find((n) => n.caipChainId === networkFilter[0]) + ?.name + : undefined; + const networkFilterLabel = + isNetworkFilterActive && selectedNetworkName + ? strings('activity_view.filter_network_selected', { + label: selectedNetworkName, + }) + : strings('activity_view.filter_all_networks'); + + const handleOpenNetworkSheet = useCallback(() => { + setIsNetworkSheetOpen(true); + }, []); + + const handleCloseNetworkSheet = useCallback(() => { + setIsNetworkSheetOpen(false); + }, []); + + const handleSelectNetwork = useCallback((chainIds: CaipChainId[] | null) => { + setNetworkFilter(chainIds); + }, []); + + const handleBackPress = useCallback(() => { + if (navigation.canGoBack()) { + navigation.goBack(); + return; + } + navigation.navigate(Routes.HOME_TABS); + }, [navigation]); + + const handleActivityListScroll = useCallback( + (event: NativeSyntheticEvent) => { + updateScrollY(scrollY, event); + }, + [scrollY], + ); + + const activityListHeader = useMemo( + () => ( + <> + + + {strings('activity_view.title')} + + + + + {/* No functionality yet, just a placeholder for the search input */} + + + + + + + + ), + [ + handleClearSearch, + handleOpenNetworkSheet, + handleOpenTypeSheet, + handleTitleLayout, + isNetworkFilterActive, + isTypeFilterActive, + networkFilterLabel, + searchQuery, + typeFilterLabel, + ], + ); + + return ( + + + + + + + + + {isTypeSheetOpen ? ( + + ) : null} + + {/* This is a stub for the network filter bottom sheet. We may actually use this version depending on the feedback/requirements */} + + + + ); +}; + +export default ActivityScreen; diff --git a/app/components/Views/ActivityScreen/ActivityScreen.view.test.tsx b/app/components/Views/ActivityScreen/ActivityScreen.view.test.tsx new file mode 100644 index 00000000000..e07f1558a73 --- /dev/null +++ b/app/components/Views/ActivityScreen/ActivityScreen.view.test.tsx @@ -0,0 +1,81 @@ +import '../../../../tests/component-view/mocks'; +import { fireEvent, waitFor } from '@testing-library/react-native'; + +import Routes from '../../../constants/navigation/Routes'; +import { getRouteProbeTestId } from '../../../../tests/component-view/render'; +import { describeForPlatforms } from '../../../../tests/component-view/platform'; +import { + renderActivityScreenView, + renderActivityScreenViewWithRoutes, +} from '../../../../tests/component-view/renderers/activity'; +import { strings } from '../../../../locales/i18n'; +import { ActivityScreenSelectorsIDs } from './ActivityScreen.testIds'; +import { ACTIVITY_TYPE_FILTER_LABEL_KEY } from './components/ActivityTypeFilterSheet'; +import { ActivityTypeFilter } from './types'; + +const optionTestId = (filter: ActivityTypeFilter) => + `${ActivityScreenSelectorsIDs.TYPE_FILTER_OPTION_PREFIX}${filter}`; + +const selectedTypeFilterLabel = (filter: ActivityTypeFilter) => + strings('activity_view.filter_types_selected', { + label: strings(ACTIVITY_TYPE_FILTER_LABEL_KEY[filter]), + }); + +describeForPlatforms('ActivityScreen', () => { + it('updates search text and selected type filter through the real screen controls', async () => { + const { getByPlaceholderText, getByTestId, getByText, findByTestId } = + renderActivityScreenView(); + + const searchInput = getByPlaceholderText( + strings('activity_view.search_placeholder'), + ); + fireEvent.changeText(searchInput, 'swap'); + + expect(searchInput).toHaveProp('value', 'swap'); + + fireEvent.press(getByTestId(ActivityScreenSelectorsIDs.TYPE_FILTER_CHIP)); + + expect( + await findByTestId(ActivityScreenSelectorsIDs.TYPE_FILTER_SHEET), + ).toBeOnTheScreen(); + + fireEvent.press(await findByTestId(optionTestId(ActivityTypeFilter.Money))); + + await waitFor(() => { + expect( + getByText(selectedTypeFilterLabel(ActivityTypeFilter.Money)), + ).toBeOnTheScreen(); + }); + }); + + it('updates the selected network filter through the real network sheet', async () => { + const { getByTestId, getByText, findByText } = renderActivityScreenView(); + + fireEvent.press( + getByTestId(ActivityScreenSelectorsIDs.NETWORK_FILTER_CHIP), + ); + fireEvent.press(await findByText('Linea')); + + await waitFor(() => { + expect( + getByText( + strings('activity_view.filter_network_selected', { + label: 'Linea', + }), + ), + ).toBeOnTheScreen(); + }); + }); + + it('navigates back to home tabs when opened as the root activity route', async () => { + const { getByTestId, findByTestId } = renderActivityScreenViewWithRoutes({ + extraRoutes: [{ name: Routes.HOME_TABS }], + }); + + fireEvent.press(getByTestId(ActivityScreenSelectorsIDs.BACK_BUTTON)); + + expect( + await findByTestId(getRouteProbeTestId(Routes.HOME_TABS)), + ).toBeOnTheScreen(); + }); +}); diff --git a/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.test.tsx b/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.test.tsx new file mode 100644 index 00000000000..bbb99c24756 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.test.tsx @@ -0,0 +1,127 @@ +import React from 'react'; +import { + cleanup, + fireEvent, + render, + screen, + waitFor, +} from '@testing-library/react-native'; +import { useNavigation } from '@react-navigation/native'; +import ActivityEmptyState from './ActivityEmptyState'; +import { ActivityTypeFilter } from '../../types'; +import Routes from '../../../../../constants/navigation/Routes'; +import { ActivityScreenSelectorsIDs } from '../../ActivityScreen.testIds'; +import { useRampNavigation } from '../../../../UI/Ramp/hooks/useRampNavigation'; +import { useMoneyAccountDeposit } from '../../../../UI/Money/hooks/useMoneyAccount'; + +jest.mock('@react-navigation/native', () => ({ + useNavigation: jest.fn(), +})); + +jest.mock('react-redux', () => ({ + useSelector: jest.fn(() => true), +})); + +jest.mock('@metamask/design-system-twrnc-preset', () => ({ + Theme: { Dark: 'dark', Light: 'light' }, + useTheme: jest.fn(() => 'light'), +})); + +jest.mock('@metamask/design-system-react-native', () => { + const ReactActual = jest.requireActual('react'); + const { Text, TouchableOpacity, View } = jest.requireActual('react-native'); + + return { + Box: ({ + children, + testID, + }: { + children?: React.ReactNode; + testID?: string; + }) => {children}, + TabEmptyState: ({ + actionButtonText, + description, + onAction, + testID, + }: { + actionButtonText: string; + description: string; + onAction: () => void; + testID?: string; + }) => ( + + {ReactActual.createElement(Text, null, description)} + {ReactActual.createElement(Text, null, actionButtonText)} + + ), + }; +}); + +jest.mock('../../../../../images/activity-empty-dark.svg', () => 'DarkIcon'); +jest.mock('../../../../../images/activity-empty-light.svg', () => 'LightIcon'); + +jest.mock('../../../../UI/Ramp/hooks/useRampNavigation', () => ({ + useRampNavigation: jest.fn(), +})); + +jest.mock('../../../../UI/Money/hooks/useMoneyAccount', () => ({ + useMoneyAccountDeposit: jest.fn(), +})); + +const mockNavigate = jest.fn(); +const mockGoToBuy = jest.fn(); +const mockInitiateDeposit = jest.fn(() => Promise.resolve()); + +describe('ActivityEmptyState', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useNavigation as jest.Mock).mockReturnValue({ navigate: mockNavigate }); + (useRampNavigation as jest.Mock).mockReturnValue({ goToBuy: mockGoToBuy }); + (useMoneyAccountDeposit as jest.Mock).mockReturnValue({ + initiateDeposit: mockInitiateDeposit, + }); + }); + + it('renders the empty state container and action copy', () => { + render(); + + expect( + screen.getByTestId(ActivityScreenSelectorsIDs.LIST), + ).toBeOnTheScreen(); + expect( + screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE), + ).toBeOnTheScreen(); + expect(screen.getByText('Swap tokens')).toBeOnTheScreen(); + }); + + it('routes each CTA to the expected destination', async () => { + render(); + fireEvent.press(screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE)); + expect(mockNavigate).toHaveBeenCalledWith(Routes.PREDICT.ROOT, { + screen: Routes.PREDICT.MARKET_LIST, + }); + + cleanup(); + render(); + fireEvent.press(screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE)); + expect(mockNavigate).toHaveBeenCalledWith(Routes.PERPS.ROOT, { + screen: Routes.PERPS.MARKET_LIST, + }); + + cleanup(); + render(); + fireEvent.press(screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE)); + expect(mockGoToBuy).toHaveBeenCalledTimes(1); + + cleanup(); + render(); + fireEvent.press(screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE)); + await waitFor(() => expect(mockInitiateDeposit).toHaveBeenCalledTimes(1)); + + cleanup(); + render(); + fireEvent.press(screen.getByTestId(ActivityScreenSelectorsIDs.EMPTY_STATE)); + expect(mockNavigate).toHaveBeenCalledWith(Routes.CARD.ROOT); + }); +}); diff --git a/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.tsx b/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.tsx new file mode 100644 index 00000000000..27aaa02fea5 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityEmptyState/ActivityEmptyState.tsx @@ -0,0 +1,104 @@ +import React, { useCallback } from 'react'; +import { useNavigation } from '@react-navigation/native'; +import { useSelector } from 'react-redux'; +import { + Theme, + useTheme as useDesignSystemTheme, +} from '@metamask/design-system-twrnc-preset'; +import { Box, TabEmptyState } from '@metamask/design-system-react-native'; +import { strings } from '../../../../../../locales/i18n'; +import Routes from '../../../../../constants/navigation/Routes'; +import Logger from '../../../../../util/Logger'; +import { selectAddressHasTokenBalances } from '../../../../../selectors/tokenBalancesController'; +import ActivityEmptyDarkIcon from '../../../../../images/activity-empty-dark.svg'; +import ActivityEmptyLightIcon from '../../../../../images/activity-empty-light.svg'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { useRampNavigation } from '../../../../UI/Ramp/hooks/useRampNavigation'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { useMoneyAccountDeposit } from '../../../../UI/Money/hooks/useMoneyAccount'; +import { ActivityScreenSelectorsIDs } from '../../ActivityScreen.testIds'; +import { ActivityTypeFilter } from '../../types'; +import { + ActivityEmptyStateAction, + getActivityEmptyState, +} from './empty-states'; + +export interface ActivityEmptyStateProps { + /** Currently selected type filter — drives copy + CTA. */ + typeFilter: ActivityTypeFilter; +} + +/** + * Filter-aware empty state for the Activity screen. Resolves the right copy, + * illustration, and CTA based on the active type filter and whether the + * account has any token balances. + */ +const ActivityEmptyState: React.FC = ({ + typeFilter, +}) => { + const designSystemTheme = useDesignSystemTheme(); + const navigation = useNavigation(); + const { goToBuy } = useRampNavigation(); + const { initiateDeposit } = useMoneyAccountDeposit(); + const hasFunds = useSelector(selectAddressHasTokenBalances); + + const Icon = + designSystemTheme === Theme.Dark + ? ActivityEmptyDarkIcon + : ActivityEmptyLightIcon; + + const emptyState = getActivityEmptyState({ filter: typeFilter, hasFunds }); + + const handleAction = useCallback(() => { + switch (emptyState.action) { + case ActivityEmptyStateAction.Swap: + navigation.navigate(Routes.BRIDGE.ROOT, { + screen: Routes.BRIDGE.BRIDGE_VIEW, + }); + return; + case ActivityEmptyStateAction.AddFunds: + goToBuy(); + return; + case ActivityEmptyStateAction.MakePrediction: + navigation.navigate(Routes.PREDICT.ROOT, { + screen: Routes.PREDICT.MARKET_LIST, + }); + return; + case ActivityEmptyStateAction.BrowsePerpsMarkets: + navigation.navigate(Routes.PERPS.ROOT, { + screen: Routes.PERPS.MARKET_LIST, + }); + return; + case ActivityEmptyStateAction.TransferToMoney: + initiateDeposit().catch((error) => { + Logger.error(error as Error, { + message: + '[ActivityEmptyState] Money deposit failed to initiate from empty state', + }); + }); + return; + case ActivityEmptyStateAction.OpenMetamaskCard: + navigation.navigate(Routes.CARD.ROOT); + return; + default: + return; + } + }, [emptyState.action, navigation, goToBuy, initiateDeposit]); + + return ( + + } + description={strings(emptyState.descriptionKey)} + actionButtonText={strings(emptyState.actionLabelKey)} + onAction={handleAction} + /> + + ); +}; + +export default ActivityEmptyState; diff --git a/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.test.ts b/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.test.ts new file mode 100644 index 00000000000..556d566ee61 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.test.ts @@ -0,0 +1,169 @@ +import { + ActivityEmptyStateAction, + getActivityEmptyState, +} from './empty-states'; +import { ActivityTypeFilter } from '../../types'; + +describe('getActivityEmptyState', () => { + describe('All filter', () => { + it('returns funded default copy + Swap action when hasFunds is true', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.All, + hasFunds: true, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.default_funded.description', + actionLabelKey: 'activity_view.empty_state.default_funded.action', + action: ActivityEmptyStateAction.Swap, + }); + }); + + it('returns unfunded default copy + AddFunds action when hasFunds is false', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.All, + hasFunds: false, + }), + ).toEqual({ + descriptionKey: + 'activity_view.empty_state.default_unfunded.description', + actionLabelKey: 'activity_view.empty_state.default_unfunded.action', + action: ActivityEmptyStateAction.AddFunds, + }); + }); + }); + + describe('Transactions filter', () => { + it('returns funded copy + Swap when hasFunds is true', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Transactions, + hasFunds: true, + }), + ).toEqual({ + descriptionKey: + 'activity_view.empty_state.transactions_funded.description', + actionLabelKey: 'activity_view.empty_state.transactions_funded.action', + action: ActivityEmptyStateAction.Swap, + }); + }); + + it('returns unfunded copy + AddFunds when hasFunds is false', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Transactions, + hasFunds: false, + }), + ).toEqual({ + descriptionKey: + 'activity_view.empty_state.transactions_unfunded.description', + actionLabelKey: + 'activity_view.empty_state.transactions_unfunded.action', + action: ActivityEmptyStateAction.AddFunds, + }); + }); + }); + + describe('Money filter', () => { + it('returns funded copy + TransferToMoney when hasFunds is true', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Money, + hasFunds: true, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.money_funded.description', + actionLabelKey: 'activity_view.empty_state.money_funded.action', + action: ActivityEmptyStateAction.TransferToMoney, + }); + }); + + it('returns unfunded copy + TransferToMoney when hasFunds is false', () => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Money, + hasFunds: false, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.money_unfunded.description', + actionLabelKey: 'activity_view.empty_state.money_unfunded.action', + action: ActivityEmptyStateAction.TransferToMoney, + }); + }); + }); + + describe('Filters that override hasFunds (themed copy regardless of balance)', () => { + it.each([true, false])( + 'Predictions returns themed copy + MakePrediction (hasFunds=%s)', + (hasFunds) => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Predictions, + hasFunds, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.predictions.description', + actionLabelKey: 'activity_view.empty_state.predictions.action', + action: ActivityEmptyStateAction.MakePrediction, + }); + }, + ); + + it.each([true, false])( + 'Perps returns themed copy + BrowsePerpsMarkets (hasFunds=%s)', + (hasFunds) => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.Perps, + hasFunds, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.perps.description', + actionLabelKey: 'activity_view.empty_state.perps.action', + action: ActivityEmptyStateAction.BrowsePerpsMarkets, + }); + }, + ); + + it.each([true, false])( + 'BuySell returns themed copy + AddFunds (hasFunds=%s)', + (hasFunds) => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.BuySell, + hasFunds, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.buy_sell.description', + actionLabelKey: 'activity_view.empty_state.buy_sell.action', + action: ActivityEmptyStateAction.AddFunds, + }); + }, + ); + + it.each([true, false])( + 'MetamaskCard returns themed copy + OpenMetamaskCard (hasFunds=%s)', + (hasFunds) => { + expect( + getActivityEmptyState({ + filter: ActivityTypeFilter.MetamaskCard, + hasFunds, + }), + ).toEqual({ + descriptionKey: 'activity_view.empty_state.metamask_card.description', + actionLabelKey: 'activity_view.empty_state.metamask_card.action', + action: ActivityEmptyStateAction.OpenMetamaskCard, + }); + }, + ); + }); + + it('falls back to the All branch for an unknown filter value', () => { + const result = getActivityEmptyState({ + filter: 'something-unknown' as ActivityTypeFilter, + hasFunds: true, + }); + expect(result.action).toBe(ActivityEmptyStateAction.Swap); + }); +}); diff --git a/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.ts b/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.ts new file mode 100644 index 00000000000..fad62ef3e09 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityEmptyState/empty-states.ts @@ -0,0 +1,120 @@ +import { ActivityTypeFilter } from '../../types'; + +/** + * Discrete CTA actions used by the Activity screen's empty states. The + * `ActivityEmptyState` component resolves each action to its real navigation + * handler — this enum keeps the config table free of navigation imports. + */ +export enum ActivityEmptyStateAction { + Swap = 'swap', + AddFunds = 'addFunds', + MakePrediction = 'makePrediction', + BrowsePerpsMarkets = 'browsePerpsMarkets', + TransferToMoney = 'transferToMoney', + OpenMetamaskCard = 'openMetamaskCard', +} + +export interface ActivityEmptyStateConfig { + /** i18n key for the empty-state description. */ + descriptionKey: string; + /** i18n key for the CTA button label. */ + actionLabelKey: string; + /** Which CTA the screen should dispatch. */ + action: ActivityEmptyStateAction; +} + +interface GetEmptyStateArgs { + filter: ActivityTypeFilter; + hasFunds: boolean; +} + +/** + * Returns the empty-state config for the given filter + funds state. + * + * Filter empty states override the no-funds default so a user filtering by + * Predictions still sees "your first prediction could be your best" even if + * their wallet is empty. + */ +export function getActivityEmptyState({ + filter, + hasFunds, +}: GetEmptyStateArgs): ActivityEmptyStateConfig { + switch (filter) { + case ActivityTypeFilter.Predictions: + return { + descriptionKey: 'activity_view.empty_state.predictions.description', + actionLabelKey: 'activity_view.empty_state.predictions.action', + action: ActivityEmptyStateAction.MakePrediction, + }; + + case ActivityTypeFilter.Perps: + return { + descriptionKey: 'activity_view.empty_state.perps.description', + actionLabelKey: 'activity_view.empty_state.perps.action', + action: ActivityEmptyStateAction.BrowsePerpsMarkets, + }; + + case ActivityTypeFilter.Transactions: + return hasFunds + ? { + descriptionKey: + 'activity_view.empty_state.transactions_funded.description', + actionLabelKey: + 'activity_view.empty_state.transactions_funded.action', + action: ActivityEmptyStateAction.Swap, + } + : { + descriptionKey: + 'activity_view.empty_state.transactions_unfunded.description', + actionLabelKey: + 'activity_view.empty_state.transactions_unfunded.action', + action: ActivityEmptyStateAction.AddFunds, + }; + + case ActivityTypeFilter.BuySell: + return { + descriptionKey: 'activity_view.empty_state.buy_sell.description', + actionLabelKey: 'activity_view.empty_state.buy_sell.action', + action: ActivityEmptyStateAction.AddFunds, + }; + + case ActivityTypeFilter.Money: + return hasFunds + ? { + descriptionKey: + 'activity_view.empty_state.money_funded.description', + actionLabelKey: 'activity_view.empty_state.money_funded.action', + action: ActivityEmptyStateAction.TransferToMoney, + } + : { + descriptionKey: + 'activity_view.empty_state.money_unfunded.description', + actionLabelKey: 'activity_view.empty_state.money_unfunded.action', + action: ActivityEmptyStateAction.TransferToMoney, + }; + + case ActivityTypeFilter.MetamaskCard: + // TODO: confirm card empty state copy with product + return { + descriptionKey: 'activity_view.empty_state.metamask_card.description', + actionLabelKey: 'activity_view.empty_state.metamask_card.action', + action: ActivityEmptyStateAction.OpenMetamaskCard, + }; + + case ActivityTypeFilter.All: + default: + return hasFunds + ? { + descriptionKey: + 'activity_view.empty_state.default_funded.description', + actionLabelKey: 'activity_view.empty_state.default_funded.action', + action: ActivityEmptyStateAction.Swap, + } + : { + descriptionKey: + 'activity_view.empty_state.default_unfunded.description', + actionLabelKey: 'activity_view.empty_state.default_unfunded.action', + action: ActivityEmptyStateAction.AddFunds, + }; + } +} diff --git a/app/components/Views/ActivityScreen/components/ActivityEmptyState/index.ts b/app/components/Views/ActivityScreen/components/ActivityEmptyState/index.ts new file mode 100644 index 00000000000..8b451bbd753 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityEmptyState/index.ts @@ -0,0 +1,7 @@ +export { default } from './ActivityEmptyState'; +export type { ActivityEmptyStateProps } from './ActivityEmptyState'; +export { + ActivityEmptyStateAction, + getActivityEmptyState, + type ActivityEmptyStateConfig, +} from './empty-states'; diff --git a/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.test.tsx b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.test.tsx new file mode 100644 index 00000000000..c5d250cd2ea --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.test.tsx @@ -0,0 +1,138 @@ +import React from 'react'; +import { fireEvent, render, screen } from '@testing-library/react-native'; +import ActivityTypeFilterSheet, { + ACTIVITY_TYPE_FILTER_LABEL_KEY, +} from './ActivityTypeFilterSheet'; +import { ActivityScreenSelectorsIDs } from '../../ActivityScreen.testIds'; +import { ACTIVITY_TYPE_FILTER_ORDER, ActivityTypeFilter } from '../../types'; + +// Capture the latest BottomSheet ref's close call so we can assert the sheet +// closes itself after a selection. +const mockOnCloseBottomSheet = jest.fn(); + +jest.mock('@metamask/design-system-react-native', () => { + const ReactNative = jest.requireActual('react-native'); + const React = jest.requireActual('react'); + + return { + IconColor: { IconDefault: 'IconDefault' }, + IconName: { Check: 'Check' }, + IconSize: { Md: 'Md' }, + TextVariant: { BodyMd: 'BodyMd' }, + Box: ({ + children, + testID, + }: { + children?: React.ReactNode; + testID?: string; + }) => {children}, + Text: ({ children }: { children?: React.ReactNode }) => ( + {children} + ), + Icon: ({ name, testID }: { name?: string; testID?: string }) => ( + + ), + BottomSheet: React.forwardRef( + ( + { + children, + onClose, + testID, + }: { + children?: React.ReactNode; + onClose?: () => void; + testID?: string; + }, + ref: React.Ref<{ onCloseBottomSheet: () => void }>, + ) => { + React.useImperativeHandle(ref, () => ({ + onCloseBottomSheet: mockOnCloseBottomSheet, + })); + return ( + + {children} + + + ); + }, + ), + BottomSheetHeader: ({ children }: { children?: React.ReactNode }) => ( + + {children} + + ), + }; +}); + +jest.mock('@metamask/design-system-twrnc-preset', () => ({ + useTailwind: () => ({ + style: (..._args: unknown[]) => ({}), + }), +})); + +const renderSheet = ( + overrides: Partial> = {}, +) => + render( + , + ); + +const optionTestId = (filter: ActivityTypeFilter) => + `${ActivityScreenSelectorsIDs.TYPE_FILTER_OPTION_PREFIX}${filter}`; + +describe('ActivityTypeFilterSheet', () => { + beforeEach(() => { + mockOnCloseBottomSheet.mockClear(); + }); + + it('shows a check icon only on the selected row', () => { + renderSheet({ selected: ActivityTypeFilter.Perps }); + + const selectedRow = screen.getByTestId( + optionTestId(ActivityTypeFilter.Perps), + ); + expect(selectedRow).toHaveProp('accessibilityState', { selected: true }); + + const unselectedRow = screen.getByTestId( + optionTestId(ActivityTypeFilter.Transactions), + ); + expect(unselectedRow).toHaveProp('accessibilityState', { selected: false }); + }); + + it('calls onSelect, closes the sheet, and forwards onClose so the parent can re-open it', () => { + const onSelect = jest.fn(); + const onClose = jest.fn(); + renderSheet({ onSelect, onClose }); + + fireEvent.press(screen.getByTestId(optionTestId(ActivityTypeFilter.Money))); + + expect(onSelect).toHaveBeenCalledWith(ActivityTypeFilter.Money); + expect(mockOnCloseBottomSheet).toHaveBeenCalledTimes(1); + expect(mockOnCloseBottomSheet).toHaveBeenCalledWith(onClose); + }); + + it('invokes onClose when the sheet dispatches its close event', () => { + const onClose = jest.fn(); + renderSheet({ onClose }); + + fireEvent.press(screen.getByTestId('mock-bottom-sheet-close')); + + expect(onClose).toHaveBeenCalledTimes(1); + }); + + it('exports an i18n label key for every filter', () => { + for (const filter of ACTIVITY_TYPE_FILTER_ORDER) { + expect(ACTIVITY_TYPE_FILTER_LABEL_KEY[filter]).toMatch( + /^activity_view\.type_filter\./, + ); + } + }); +}); diff --git a/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.tsx b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.tsx new file mode 100644 index 00000000000..abf7177dd5f --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/ActivityTypeFilterSheet.tsx @@ -0,0 +1,101 @@ +import React, { useCallback, useRef } from 'react'; +import { Pressable } from 'react-native'; +import { useTailwind } from '@metamask/design-system-twrnc-preset'; +import { + BottomSheet, + BottomSheetHeader, + type BottomSheetRef, + Box, + Icon, + IconColor, + IconName, + IconSize, + Text, + TextVariant, +} from '@metamask/design-system-react-native'; +import { strings } from '../../../../../../locales/i18n'; +import { ACTIVITY_TYPE_FILTER_ORDER, ActivityTypeFilter } from '../../types'; +import { ActivityScreenSelectorsIDs } from '../../ActivityScreen.testIds'; + +export const ACTIVITY_TYPE_FILTER_LABEL_KEY: Record< + ActivityTypeFilter, + string +> = { + // `All` is not currently selectable from the sheet — see the TODO above + // `ACTIVITY_TYPE_FILTER_ORDER` in ../../types.ts. Kept for type completeness + // and so chip labels keep resolving if the flag is re-enabled. + [ActivityTypeFilter.All]: 'activity_view.type_filter.all', + [ActivityTypeFilter.Transactions]: 'activity_view.type_filter.transactions', + [ActivityTypeFilter.BuySell]: 'activity_view.type_filter.buy_sell', + [ActivityTypeFilter.Perps]: 'activity_view.type_filter.perps', + [ActivityTypeFilter.Predictions]: 'activity_view.type_filter.predictions', + [ActivityTypeFilter.MetamaskCard]: 'activity_view.type_filter.metamask_card', + [ActivityTypeFilter.Money]: 'activity_view.type_filter.money', +}; + +export interface ActivityTypeFilterSheetProps { + selected: ActivityTypeFilter; + onSelect: (filter: ActivityTypeFilter) => void; + onClose: () => void; +} + +const ActivityTypeFilterSheet: React.FC = ({ + selected, + onSelect, + onClose, +}) => { + const tw = useTailwind(); + const sheetRef = useRef(null); + + const handleSelect = useCallback( + (filter: ActivityTypeFilter) => { + onSelect(filter); + sheetRef.current?.onCloseBottomSheet(onClose); + }, + [onSelect, onClose], + ); + + return ( + + + {strings('activity_view.type_filter.title')} + + + + {ACTIVITY_TYPE_FILTER_ORDER.map((filter) => { + const isSelected = filter === selected; + return ( + handleSelect(filter)} + style={tw.style( + 'flex-row items-center justify-between px-4 py-4', + isSelected && 'bg-muted', + )} + testID={`${ActivityScreenSelectorsIDs.TYPE_FILTER_OPTION_PREFIX}${filter}`} + accessibilityRole="button" + accessibilityState={{ selected: isSelected }} + > + + {strings(ACTIVITY_TYPE_FILTER_LABEL_KEY[filter])} + + {isSelected ? ( + + ) : null} + + ); + })} + + + ); +}; + +export default ActivityTypeFilterSheet; diff --git a/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/index.ts b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/index.ts new file mode 100644 index 00000000000..0687597fb40 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/ActivityTypeFilterSheet/index.ts @@ -0,0 +1,5 @@ +export { default } from './ActivityTypeFilterSheet'; +export { + ACTIVITY_TYPE_FILTER_LABEL_KEY, + type ActivityTypeFilterSheetProps, +} from './ActivityTypeFilterSheet'; diff --git a/app/components/Views/ActivityScreen/components/AssetListControlBar/AssetListControlBar.tsx b/app/components/Views/ActivityScreen/components/AssetListControlBar/AssetListControlBar.tsx new file mode 100644 index 00000000000..effb006fb81 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/AssetListControlBar/AssetListControlBar.tsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { ScrollView } from 'react-native'; +import { useTailwind } from '@metamask/design-system-twrnc-preset'; +import { + ButtonBase, + ButtonBaseSize, + IconColor, + IconName, + TextColor, +} from '@metamask/design-system-react-native'; +import { ActivityScreenSelectorsIDs } from '../../ActivityScreen.testIds'; + +export interface AssetListControlBarProps { + networkLabel: string; + isNetworkFilterActive: boolean; + onNetworkPress: () => void; + typeLabel: string; + isTypeFilterActive: boolean; + onTypePress: () => void; +} + +/** + * Horizontally-scrollable filter chip row for the Activity screen — mirrors + * the extension's `AssetListControlBar` pattern. Pure presentational: the + * parent screen owns filter state, label resolution, and sheet rendering. + * + * Sheets must remain siblings of the scroll content (not nested inside it), + * since the underlying `component-library` `BottomSheet` does not portal. + */ +const AssetListControlBar: React.FC = ({ + networkLabel, + isNetworkFilterActive, + onNetworkPress, + typeLabel, + isTypeFilterActive, + onTypePress, +}) => { + const tw = useTailwind(); + + return ( + + + {networkLabel} + + + {typeLabel} + + + ); +}; + +export default AssetListControlBar; diff --git a/app/components/Views/ActivityScreen/components/AssetListControlBar/index.ts b/app/components/Views/ActivityScreen/components/AssetListControlBar/index.ts new file mode 100644 index 00000000000..2f3178a8d80 --- /dev/null +++ b/app/components/Views/ActivityScreen/components/AssetListControlBar/index.ts @@ -0,0 +1,2 @@ +export { default } from './AssetListControlBar'; +export type { AssetListControlBarProps } from './AssetListControlBar'; diff --git a/app/components/Views/ActivityScreen/index.ts b/app/components/Views/ActivityScreen/index.ts new file mode 100644 index 00000000000..b2c08074921 --- /dev/null +++ b/app/components/Views/ActivityScreen/index.ts @@ -0,0 +1 @@ +export { default } from './ActivityScreen'; diff --git a/app/components/Views/ActivityScreen/types.ts b/app/components/Views/ActivityScreen/types.ts new file mode 100644 index 00000000000..488de295694 --- /dev/null +++ b/app/components/Views/ActivityScreen/types.ts @@ -0,0 +1,109 @@ +import type { ActivityKind } from '../../../util/activity-adapters'; + +export type { ActivityKind }; + +/** + * Top-level "Types" filter buckets shown in the Activity screen filter sheet. + * Each bucket maps to a set of `ActivityKind`s via `ACTIVITY_TYPE_FILTER_KINDS`. + */ +export enum ActivityTypeFilter { + All = 'all', + Transactions = 'transactions', + BuySell = 'buySell', + Perps = 'perps', + Predictions = 'predictions', + MetamaskCard = 'metamaskCard', + Money = 'money', +} + +/** + * Bucket → kinds mapping. `null` means "no filtering" (matches everything). + * + * TODO: refine bucket membership with product/design once adapters land — + * Money/MetaMask Card definitions are best-guess based on the Figma options. + */ +export const ACTIVITY_TYPE_FILTER_KINDS: Record< + ActivityTypeFilter, + ReadonlySet | null +> = { + [ActivityTypeFilter.All]: null, + [ActivityTypeFilter.Transactions]: new Set([ + 'send', + 'receive', + 'swap', + 'swapIncomplete', + 'bridge', + 'wrap', + 'unwrap', + 'convert', + 'approveSpendingCap', + 'increaseSpendingCap', + 'revokeSpendingCap', + 'contractInteraction', + 'contractDeployment', + 'smartAccountUpgrade', + 'nftMint', + ]), + [ActivityTypeFilter.BuySell]: new Set([ + 'buy', + 'sell', + 'deposit', + ]), + [ActivityTypeFilter.Perps]: new Set([ + 'perpsAddFunds', + 'perpsWithdrawFunds', + 'perpsOpenLong', + 'perpsCloseLong', + 'perpsCloseLongLiquidated', + 'perpsCloseLongStopLoss', + 'perpsCloseLongTakeProfit', + 'perpsOpenShort', + 'perpsCloseShort', + 'perpsCloseShortLiquidated', + 'perpsCloseShortStopLoss', + 'perpsCloseShortTakeProfit', + 'perpsPaidFundingFees', + 'perpsReceivedFundingFees', + 'marketShort', + 'stopMarketCloseShort', + 'marketCloseShort', + ]), + [ActivityTypeFilter.Predictions]: new Set([ + 'predictionsAddFunds', + 'predictionsWithdrawFunds', + 'predictionClaimWinnings', + 'predictionCashedOut', + 'predictionPlaced', + ]), + [ActivityTypeFilter.MetamaskCard]: new Set([]), + [ActivityTypeFilter.Money]: new Set([ + 'claim', + 'claimMusdBonus', + 'lendingDeposit', + 'lendingWithdrawal', + ]), +}; + +// TODO: re-enable `ActivityTypeFilter.All` once the data sources are unified +// (deduped, time-sorted across EVM tx controller, non-EVM keyrings, perps, +// predict, etc.). Until then we ship type-only filtering — see TMCU thread. +export const ACTIVITY_TYPE_FILTER_ORDER: ActivityTypeFilter[] = [ + // ActivityTypeFilter.All, + ActivityTypeFilter.Transactions, + ActivityTypeFilter.BuySell, + ActivityTypeFilter.Perps, + ActivityTypeFilter.Predictions, + ActivityTypeFilter.MetamaskCard, + ActivityTypeFilter.Money, +]; + +export function activityKindMatchesTypeFilter( + kind: ActivityKind, + filter: ActivityTypeFilter, +): boolean { + const allowed = ACTIVITY_TYPE_FILTER_KINDS[filter]; + if (allowed === null) { + return true; + } + return allowed.has(kind); +} diff --git a/app/components/Views/ActivityView/ActivityView.styles.js b/app/components/Views/ActivityView/ActivityView.styles.js new file mode 100644 index 00000000000..179886a5a96 --- /dev/null +++ b/app/components/Views/ActivityView/ActivityView.styles.js @@ -0,0 +1,39 @@ +import { StyleSheet } from 'react-native'; + +const styleSheet = ({ theme }) => { + const { colors } = theme; + + return StyleSheet.create({ + tabWrapper: { + flex: 1, + backgroundColor: colors.background.default, + }, + controlButtonOuterWrapper: { + flexDirection: 'row', + width: '100%', + justifyContent: 'space-between', + alignItems: 'center', + marginVertical: 8, + paddingHorizontal: 16, + }, + controlButton: { + backgroundColor: colors.background.default, + borderColor: colors.border.muted, + borderWidth: 1, + borderRadius: 8, + maxWidth: '80%', + paddingHorizontal: 12, + }, + networkManagerWrapper: { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + gap: 4, + }, + titleText: { + color: colors.text.default, + }, + }); +}; + +export default styleSheet; diff --git a/app/components/Views/ActivityView/ActivityView.view.test.tsx b/app/components/Views/ActivityView/ActivityView.view.test.tsx new file mode 100644 index 00000000000..0ad3e038840 --- /dev/null +++ b/app/components/Views/ActivityView/ActivityView.view.test.tsx @@ -0,0 +1,60 @@ +import '../../../../tests/component-view/mocks'; +import { fireEvent, waitFor } from '@testing-library/react-native'; +import { strings } from '../../../../locales/i18n'; +import type { DeepPartial } from '../../../util/test/renderWithProvider'; +import type { RootState } from '../../../reducers'; +import Routes from '../../../constants/navigation/Routes'; +import { describeForPlatforms } from '../../../../tests/component-view/platform'; +import { + renderActivityView, + renderActivityViewWithRoutes, +} from '../../../../tests/component-view/renderers/activity'; +import { getRouteProbeTestId } from '../../../../tests/component-view/render'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { WalletViewSelectorsIDs } from '../Wallet/WalletView.testIds'; + +const legacyActivityViewState = { + engine: { + backgroundState: { + NetworkEnablementController: { + enabledNetworkMap: { + eip155: { '0x1': true }, + solana: {}, + }, + }, + }, + }, +} as unknown as DeepPartial; + +describeForPlatforms('ActivityView', () => { + it('opens network manager when the legacy network filter is pressed', async () => { + const { getByTestId, findByTestId } = renderActivityViewWithRoutes({ + overrides: legacyActivityViewState, + extraRoutes: [{ name: Routes.MODAL.ROOT_MODAL_FLOW }], + }); + + const networkFilter = await waitFor(() => + getByTestId(WalletViewSelectorsIDs.TOKEN_NETWORK_FILTER), + ); + + fireEvent.press(networkFilter); + + expect( + await findByTestId(getRouteProbeTestId(Routes.MODAL.ROOT_MODAL_FLOW)), + ).toBeOnTheScreen(); + }); + + it('types in search after the redesigned screen lazy-loads', async () => { + const { findByPlaceholderText } = renderActivityView({ + redesignEnabled: true, + }); + + const searchInput = await waitFor(() => + findByPlaceholderText(strings('activity_view.search_placeholder')), + ); + + fireEvent.changeText(searchInput, 'swap'); + + expect(searchInput).toHaveProp('value', 'swap'); + }); +}); diff --git a/app/components/Views/ActivityView/index.js b/app/components/Views/ActivityView/index.js index fc607753aa7..a3a06deff43 100644 --- a/app/components/Views/ActivityView/index.js +++ b/app/components/Views/ActivityView/index.js @@ -1,6 +1,6 @@ import { useFocusEffect, useNavigation } from '@react-navigation/native'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; -import { BackHandler, StyleSheet, View } from 'react-native'; +import { BackHandler, View } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useSelector } from 'react-redux'; // eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog @@ -47,48 +47,23 @@ import { useStyles } from '../../hooks/useStyles'; import ErrorBoundary from '../ErrorBoundary'; // eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog import UnifiedTransactionsView from '../UnifiedTransactionsView/UnifiedTransactionsView'; +import styleSheet from './ActivityView.styles'; +import { selectIsActivityRedesignEnabled } from './selectors/featureFlags'; -const createStyles = (params) => { - const { theme } = params; - const { colors } = theme; - return StyleSheet.create({ - tabWrapper: { - flex: 1, - backgroundColor: colors.background.default, - }, - controlButtonOuterWrapper: { - flexDirection: 'row', - width: '100%', - justifyContent: 'space-between', - alignItems: 'center', - marginVertical: 8, - paddingHorizontal: 16, - }, - controlButton: { - backgroundColor: colors.background.default, - borderColor: colors.border.muted, - borderWidth: 1, - borderRadius: 8, - maxWidth: '80%', - paddingHorizontal: 12, - }, - networkManagerWrapper: { - display: 'flex', - flexDirection: 'row', - alignItems: 'center', - gap: 4, - }, - titleText: { - color: colors.text.default, - }, - }); -}; +// Lazily loaded so the redesigned Activity screen and its dependencies are not +// evaluated when `tmcuActivityRedesignEnabled` is off, keeping the legacy path +// fully isolated. +const ActivityScreen = React.lazy( + () => + // eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog + import('../ActivityScreen/ActivityScreen'), +); -const ActivityView = () => { +const LegacyActivityView = () => { const { colors } = useTheme(); const tw = useTailwind(); - const { styles } = useStyles(createStyles); + const { styles } = useStyles(styleSheet, {}); const navigation = useNavigation(); @@ -325,4 +300,18 @@ const ActivityView = () => { ); }; +const ActivityView = () => { + const isActivityRedesignEnabled = useSelector( + selectIsActivityRedesignEnabled, + ); + + return isActivityRedesignEnabled ? ( + + + + ) : ( + + ); +}; + export default ActivityView; diff --git a/app/components/Views/ActivityView/index.test.tsx b/app/components/Views/ActivityView/index.test.tsx index 0925538bf3a..5b68eb3456c 100644 --- a/app/components/Views/ActivityView/index.test.tsx +++ b/app/components/Views/ActivityView/index.test.tsx @@ -4,7 +4,7 @@ import { BackHandler } from 'react-native'; import { backgroundState } from '../../../util/test/initial-root-state'; import renderWithProvider from '../../../util/test/renderWithProvider'; import { createStackNavigator } from '@react-navigation/stack'; -import { cleanup, fireEvent } from '@testing-library/react-native'; +import { cleanup, fireEvent, waitFor } from '@testing-library/react-native'; // eslint-disable-next-line import-x/no-namespace import * as networkManagerUtils from '../../UI/NetworkManager'; import { useCurrentNetworkInfo } from '../../hooks/useCurrentNetworkInfo'; diff --git a/app/components/Views/ActivityView/selectors/featureFlags/index.ts b/app/components/Views/ActivityView/selectors/featureFlags/index.ts new file mode 100644 index 00000000000..f0f1cfee92f --- /dev/null +++ b/app/components/Views/ActivityView/selectors/featureFlags/index.ts @@ -0,0 +1,8 @@ +import { createSelector } from 'reselect'; +import { selectRemoteFeatureFlags } from '../../../../../selectors/featureFlagController'; + +export const selectIsActivityRedesignEnabled = createSelector( + selectRemoteFeatureFlags, + (remoteFeatureFlags): boolean => + remoteFeatureFlags.tmcuActivityRedesignEnabled === true, +); diff --git a/app/images/activity-empty-dark.svg b/app/images/activity-empty-dark.svg new file mode 100644 index 00000000000..499c6841b99 --- /dev/null +++ b/app/images/activity-empty-dark.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/activity-empty-light.svg b/app/images/activity-empty-light.svg new file mode 100644 index 00000000000..c4288134855 --- /dev/null +++ b/app/images/activity-empty-light.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/util/activity-adapters/activity-list-helpers.test.ts b/app/util/activity-adapters/activity-list-helpers.test.ts new file mode 100644 index 00000000000..76cdc3051a5 --- /dev/null +++ b/app/util/activity-adapters/activity-list-helpers.test.ts @@ -0,0 +1,96 @@ +import type { ActivityListItem } from './types'; +import { + activityMatchesAssetId, + groupActivityListItems, + shouldShowPlusSign, +} from './activity-list-helpers'; + +function makeItem(overrides: Partial = {}): ActivityListItem { + return { + chainId: 'eip155:1', + data: { + hash: '0xhash', + token: { + amount: '1', + assetId: 'eip155:1/slip44:60', + direction: 'out', + symbol: 'ETH', + }, + }, + isEarliestNonce: true, + status: 'success', + timestamp: 1, + type: 'send', + ...overrides, + } as unknown as ActivityListItem; +} + +function localDay(timestamp: number) { + const date = new Date(timestamp); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} + +describe('activity list helpers', () => { + it('hides plus signs for spending-cap activity types', () => { + expect(shouldShowPlusSign('approveSpendingCap')).toBe(false); + expect(shouldShowPlusSign('increaseSpendingCap')).toBe(false); + expect(shouldShowPlusSign('revokeSpendingCap')).toBe(false); + expect(shouldShowPlusSign('receive')).toBe(true); + }); + + it('matches token, source token, and destination token asset ids case-insensitively', () => { + const item = makeItem({ + data: { + hash: '0xhash', + sourceToken: { + assetId: 'eip155:1/erc20:0xA0B86991C6218B36C1D19D4A2E9EB0CE3606EB48', + direction: 'out', + symbol: 'USDC', + }, + destinationToken: { + assetId: 'eip155:1/slip44:60', + direction: 'in', + symbol: 'ETH', + }, + }, + type: 'swap', + }); + + expect( + activityMatchesAssetId( + item, + 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + ), + ).toBe(true); + expect(activityMatchesAssetId(item, 'eip155:1/slip44:60')).toBe(true); + expect(activityMatchesAssetId(item, 'eip155:137/slip44:60')).toBe(false); + }); + + it('groups pending items before date-grouped historical items', () => { + const pending = makeItem({ + data: { hash: '0xpending' }, + status: 'pending', + timestamp: Date.UTC(2026, 0, 2, 12), + }); + const firstHistorical = makeItem({ + data: { hash: '0xfirst' }, + timestamp: Date.UTC(2026, 0, 2, 11), + }); + const secondHistorical = makeItem({ + data: { hash: '0xsecond' }, + timestamp: Date.UTC(2026, 0, 1, 11), + }); + + expect( + groupActivityListItems([pending, firstHistorical, secondHistorical]), + ).toStrictEqual([ + { type: 'pending-header' }, + { type: 'item', item: pending }, + { type: 'date-header', date: localDay(firstHistorical.timestamp) }, + { type: 'item', item: firstHistorical }, + { type: 'date-header', date: localDay(secondHistorical.timestamp) }, + { type: 'item', item: secondHistorical }, + ]); + }); +}); diff --git a/app/util/activity-adapters/activity-list-helpers.ts b/app/util/activity-adapters/activity-list-helpers.ts new file mode 100644 index 00000000000..9744fde1311 --- /dev/null +++ b/app/util/activity-adapters/activity-list-helpers.ts @@ -0,0 +1,97 @@ +import type { CaipAssetType } from '@metamask/utils'; +import { + mobileActivityAdapterEnvironment, + type ActivityAdapterEnvironment, +} from './adapters/environment'; +import type { ActivityListItem } from './types'; + +const hidePlusSignActivityTypes = new Set([ + 'approveSpendingCap', + 'increaseSpendingCap', + 'revokeSpendingCap', +]); + +export type ActivityListFilter = + | { assetId: CaipAssetType } + | { networks: string[] }; + +export type GroupedActivityListItem = + | { type: 'pending-header' } + | { type: 'date-header'; date: number } + | { type: 'item'; item: ActivityListItem }; + +export function shouldShowPlusSign(activityType: ActivityListItem['type']) { + return !hidePlusSignActivityTypes.has(activityType); +} + +export function activityMatchesAssetId( + item: ActivityListItem, + assetId: CaipAssetType, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +) { + const { data } = item; + const tokenAssetIds = [ + 'token' in data ? data.token?.assetId : undefined, + 'sourceToken' in data ? data.sourceToken?.assetId : undefined, + 'destinationToken' in data ? data.destinationToken?.assetId : undefined, + ]; + + return tokenAssetIds.some( + (tokenAssetId) => + tokenAssetId !== undefined && + environment.equalsIgnoreCase(tokenAssetId, assetId), + ); +} + +function parseDate(timestamp: number) { + const date = new Date(timestamp); + date.setHours(0, 0, 0, 0); + return date.getTime(); +} + +function groupItemsByDate( + items: ActivityListItem[], +): GroupedActivityListItem[] { + let currentDate: number | null = null; + + return items.flatMap((item): GroupedActivityListItem[] => { + const date = parseDate(item.timestamp); + + if (date === currentDate) { + return [{ type: 'item', item }]; + } + + currentDate = date; + return [ + { type: 'date-header', date }, + { type: 'item', item }, + ]; + }); +} + +export function groupActivityListItems( + items: ActivityListItem[], +): GroupedActivityListItem[] { + const pending: ActivityListItem[] = []; + const historical: ActivityListItem[] = []; + + for (const item of items) { + if (item.status === 'pending') { + pending.push(item); + } else { + historical.push(item); + } + } + + const grouped: GroupedActivityListItem[] = []; + + if (pending.length > 0) { + grouped.push({ type: 'pending-header' }); + for (const item of pending) { + grouped.push({ type: 'item', item }); + } + } + + grouped.push(...groupItemsByDate(historical)); + return grouped; +} diff --git a/app/util/activity-adapters/adapters/api-evm-transactions.test.ts b/app/util/activity-adapters/adapters/api-evm-transactions.test.ts new file mode 100644 index 00000000000..c47f699d027 --- /dev/null +++ b/app/util/activity-adapters/adapters/api-evm-transactions.test.ts @@ -0,0 +1,703 @@ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import { mapApiEvmTransactions } from './api-evm-transactions'; +import { NATIVE_TOKEN_ADDRESS, toAssetId } from './shims'; + +const subjectAddress = '0x9bed78535d6a03a955f1504aadba974d9a29e292'; +const baseUsdc = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; +const baseAaveUsdc = '0x4e65fe4dba92790696d040ac24aa414708f5c0ab'; +const baseAavePool = '0xa238dd80c259a72e81d7e4664a9801593f98d1c5'; +const baseRecipientAddress = '0x6fdb1e9d93c1279177b00baaf44524055455e92e'; +const bscContractCallerAddress = '0xf70da97812cb96acdf810712aa562db8dfa3dbef'; +const bscRecipientAddress = '0xb92fe925dc43a0ecde6c8b1a2709c170ec4fff4f'; +const bscUniversalRouter = '0xca11bde05977b3631167028862be2a173976ca11'; +const exchangeRecipient = '0x3913a8aca88c946284abbe7ab2ed671c6603de20'; +const lineaMusd = '0xaca92e438df0b2401ff60da7e4337b687a2435da'; +const lineaSenderAddress = '0xf70da97812cb96acdf810712aa562db8dfa3dbef'; +const metamaskBonusContract = '0x3ef3d8ba38ebe18db133cec108f4d14ce00dd9ae'; +const polygonRecipientAddress = '0x2cd071562a1688b3e9f31be39c92aa140a1acc94'; +const wethContractAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; +const zeroAddress = '0x0000000000000000000000000000000000000000'; + +const withoutRaw = (item: ReturnType) => { + const activity = { ...item }; + delete activity.raw; + return activity; +}; + +describe('mapApiEvmTransactions', () => { + it('maps an ERC-20 transfer sent by the account to a Send activity', () => { + const transaction = { + timestamp: '2026-05-12T13:37:47.000Z', + chainId: 8453, + from: subjectAddress, + to: baseUsdc, + transactionCategory: 'TRANSFER', + valueTransfers: [ + { + from: subjectAddress, + to: baseRecipientAddress, + symbol: 'USDC', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1778593067000, + data: { + from: subjectAddress, + hash: undefined, + to: baseRecipientAddress, + token: { + direction: 'out', + symbol: 'USDC', + assetId: toAssetId(baseUsdc, 'eip155:8453'), + }, + }, + }); + }); + + it('maps an approval without value transfers using known bridge token metadata', () => { + const transaction = { + hash: '0x91f89897197afcc09ad98ec4282366fd7938d8a9609e4fc2a0aa2d070664bc27', + timestamp: '2026-05-27T13:20:27.000Z', + chainId: 8453, + accountId: `eip155:8453:${subjectAddress}`, + methodId: '0x095ea7b3', + value: '0', + to: baseUsdc, + from: subjectAddress, + isError: false, + valueTransfers: [], + logs: [], + transactionProtocol: 'ERC_20', + transactionCategory: 'APPROVE', + transactionType: 'ERC_20_APPROVE', + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'approveSpendingCap', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1779888027000, + data: { + hash: '0x91f89897197afcc09ad98ec4282366fd7938d8a9609e4fc2a0aa2d070664bc27', + token: { + direction: 'out', + symbol: 'USDC', + decimals: 6, + assetId: toAssetId(baseUsdc, 'eip155:8453'), + }, + }, + }); + }); + + it('maps a native value contract call without method data to a Send activity', () => { + const transaction = { + hash: '0x64d2f26c261178252fcad9dbb665cf40337b827a582066553dd6634eaeea9f0a', + timestamp: '2026-05-19T19:27:12.000Z', + chainId: 137, + from: subjectAddress, + to: polygonRecipientAddress, + methodId: null, + transactionCategory: 'CONTRACT_CALL', + transactionType: 'GENERIC_CONTRACT_CALL', + value: '100000000000000000', + valueTransfers: [ + { + from: subjectAddress, + to: polygonRecipientAddress, + amount: '100000000000000000', + decimal: 18, + symbol: 'MATIC', + transferType: 'normal', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:137', + status: 'success', + timestamp: 1779218832000, + data: { + from: subjectAddress, + hash: '0x64d2f26c261178252fcad9dbb665cf40337b827a582066553dd6634eaeea9f0a', + to: polygonRecipientAddress, + token: { + amount: '100000000000000000', + assetId: toAssetId(NATIVE_TOKEN_ADDRESS, 'eip155:137'), + decimals: 18, + direction: 'out', + symbol: 'MATIC', + }, + }, + }); + }); + + it('maps an ERC-20 transfer received by the account to a Receive activity', () => { + const transaction = { + timestamp: '2026-05-05T12:15:27.000Z', + chainId: 59144, + from: lineaSenderAddress, + to: lineaMusd, + transactionCategory: 'TRANSFER', + valueTransfers: [ + { + from: lineaSenderAddress, + to: subjectAddress, + symbol: 'mUSD', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'receive', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1777983327000, + data: { + from: lineaSenderAddress, + hash: undefined, + to: subjectAddress, + token: { + direction: 'in', + symbol: 'mUSD', + assetId: toAssetId(lineaMusd, 'eip155:59144'), + }, + }, + }); + }); + + it('maps an exchange transaction without a received token to an incomplete Swap activity', () => { + const transaction = { + timestamp: '2026-05-05T17:57:53.000Z', + chainId: 59144, + from: subjectAddress, + to: subjectAddress, + transactionCategory: 'EXCHANGE', + valueTransfers: [ + { + from: subjectAddress, + to: exchangeRecipient, + symbol: 'mUSD', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'swapIncomplete', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1778003873000, + data: { + hash: undefined, + sourceToken: { + direction: 'out', + symbol: 'mUSD', + }, + }, + }); + }); + + it('maps an exchange transaction with an internal ETH receive transfer to a Swap activity with native destination assetId', () => { + const aggregatorAddress = '0x0a2854fbbd9b3ef66f17d47284e7f899b9509330'; + const transaction = { + hash: '0x80b974d5834e1047a78332369de3d4b988f0237ff8a418c9464217e55c542f2f', + timestamp: '2026-05-28T01:03:49.000Z', + chainId: 59144, + methodId: '0xe9ae5c53', + value: '0', + to: subjectAddress, + from: subjectAddress, + isError: false, + transactionCategory: 'EXCHANGE', + valueTransfers: [ + { + from: aggregatorAddress, + to: subjectAddress, + amount: '4894004361763', + decimal: 18, + symbol: 'ETH', + name: 'Ether', + transferType: 'internal', + }, + { + from: subjectAddress, + to: aggregatorAddress, + amount: '10000', + decimal: 6, + contractAddress: lineaMusd, + symbol: 'mUSD', + name: 'MetaMask USD', + transferType: 'erc20', + }, + ], + logs: [], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'swap', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1779930229000, + data: { + hash: '0x80b974d5834e1047a78332369de3d4b988f0237ff8a418c9464217e55c542f2f', + sourceToken: { + amount: '10000', + decimals: 6, + direction: 'out', + assetId: toAssetId(lineaMusd, 'eip155:59144'), + symbol: 'mUSD', + }, + destinationToken: { + amount: '4894004361763', + decimals: 18, + direction: 'in', + assetId: toAssetId(NATIVE_TOKEN_ADDRESS, 'eip155:59144'), + symbol: 'ETH', + }, + }, + }); + }); + + it('maps an NFT sale with received native value to a Send activity', () => { + const nftRecipientAddress = '0x4f5243ceea96cee1da0fdb89c756d0e999439424'; + const nftBuyerAddress = '0x78c87da124bb36a914ff1c0f2d642f47870c997c'; + const transaction = { + timestamp: '2026-02-23T22:04:23.000Z', + chainId: 1, + from: nftBuyerAddress, + to: subjectAddress, + transactionCategory: 'TRANSFER', + valueTransfers: [ + { + from: subjectAddress, + to: nftRecipientAddress, + amount: 1, + tokenId: '984', + symbol: 'BAE', + transferType: 'erc1155', + }, + { + from: nftBuyerAddress, + to: subjectAddress, + amount: '1000000000000000', + decimal: 18, + symbol: 'ETH', + transferType: 'normal', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:1', + status: 'success', + timestamp: 1771884263000, + data: { + from: subjectAddress, + hash: undefined, + to: nftRecipientAddress, + token: { + amount: '1', + direction: 'out', + symbol: 'BAE', + }, + }, + }); + }); + + it('maps an NFT mint transfer to an nftMint activity without assetId', () => { + const nftContractAddress = '0x239fd4b0c4db49fa8660e65b97619d43d0e0a79d'; + const transaction = { + hash: '0x25805d4ae16935e6fa92add9dcee97db0127749d4244032a79489098a880210c', + timestamp: '2026-05-13T14:34:23.000Z', + chainId: 59144, + from: zeroAddress, + to: subjectAddress, + transactionCategory: 'TRANSFER', + valueTransfers: [ + { + from: zeroAddress, + to: subjectAddress, + contractAddress: nftContractAddress, + tokenId: '1', + symbol: 'TDN', + transferType: 'erc721', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'nftMint', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1778682863000, + data: { + hash: '0x25805d4ae16935e6fa92add9dcee97db0127749d4244032a79489098a880210c', + from: zeroAddress, + to: subjectAddress, + token: { + direction: 'in', + symbol: 'TDN', + }, + }, + }); + }); + + it('maps an Aave supply contract call to a Lending deposit activity', () => { + const transaction = { + hash: '0x08d14578168f22001e95503469c63613bd9f3d3f60e81dbbf204fbd21f484bd9', + timestamp: '2026-05-13T03:31:29.000Z', + chainId: 8453, + from: subjectAddress, + to: baseAavePool, + methodId: '0x617ba037', + transactionCategory: 'CONTRACT_CALL', + transactionType: 'GENERIC_CONTRACT_CALL', + valueTransfers: [ + { + from: zeroAddress, + to: subjectAddress, + amount: '99999', + decimal: 6, + contractAddress: baseAaveUsdc, + symbol: 'aBasUSDC', + }, + { + from: subjectAddress, + to: baseAaveUsdc, + amount: '100000', + decimal: 6, + contractAddress: baseUsdc, + symbol: 'USDC', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'lendingDeposit', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1778643089000, + data: { + hash: '0x08d14578168f22001e95503469c63613bd9f3d3f60e81dbbf204fbd21f484bd9', + sourceToken: { + amount: '100000', + decimals: 6, + direction: 'out', + symbol: 'USDC', + assetId: toAssetId(baseUsdc, 'eip155:8453'), + }, + destinationToken: { + amount: '99999', + decimals: 6, + direction: 'in', + symbol: 'aBasUSDC', + assetId: toAssetId(baseAaveUsdc, 'eip155:8453'), + }, + }, + }); + }); + + it('maps a DEPOSIT without an inbound transfer to a deposit activity', () => { + const stakingContractAddress = '0x00000000219ab540356cbb839cbe05303d7705fa'; + const transaction = { + hash: '0xabc123deposit00000000000000000000000000000000000000000000000001', + timestamp: '2026-05-12T13:37:47.000Z', + chainId: 1, + from: subjectAddress, + to: stakingContractAddress, + transactionCategory: 'DEPOSIT', + valueTransfers: [ + { + from: subjectAddress, + to: stakingContractAddress, + amount: '1000000000000000000', + decimal: 18, + symbol: 'ETH', + transferType: 'normal', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'deposit', + chainId: 'eip155:1', + status: 'success', + timestamp: 1778593067000, + data: { + hash: '0xabc123deposit00000000000000000000000000000000000000000000000001', + token: { + amount: '1000000000000000000', + decimals: 18, + direction: 'in', + symbol: 'ETH', + assetId: toAssetId(NATIVE_TOKEN_ADDRESS, 'eip155:1'), + }, + }, + }); + }); + + it('maps a MetaMask mUSD bonus claim to a Claim mUSD bonus activity', () => { + const transaction = { + hash: '0x875ded271a40278391fca5d71892231afd0cb9592f31bdf3b7c949906cb982c4', + timestamp: '2026-05-13T00:48:45.000Z', + chainId: 59144, + from: subjectAddress, + to: metamaskBonusContract, + transactionCategory: 'CLAIM_BONUS', + valueTransfers: [ + { + from: metamaskBonusContract, + to: subjectAddress, + contractAddress: lineaMusd, + symbol: 'mUSD', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'claimMusdBonus', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1778633325000, + data: { + hash: '0x875ded271a40278391fca5d71892231afd0cb9592f31bdf3b7c949906cb982c4', + token: { + direction: 'in', + symbol: 'mUSD', + assetId: toAssetId(lineaMusd, 'eip155:59144'), + }, + }, + }); + }); + + it('maps a WETH deposit to a Wrap activity', () => { + const transaction = { + hash: '0x6e448f5b8cf55534507770c1cb90ba14e723d03b4a46b4919a5847eb8d13b7b5', + timestamp: '2026-05-28T13:42:23.000Z', + chainId: 1, + from: subjectAddress, + to: wethContractAddress, + methodId: '0xd0e30db0', + transactionCategory: 'DEPOSIT', + transactionProtocol: 'WETH', + transactionType: 'WETH_DEPOSIT', + valueTransfers: [ + { + from: NATIVE_TOKEN_ADDRESS, + to: subjectAddress, + amount: '1000000000000', + decimal: 18, + contractAddress: wethContractAddress, + symbol: 'WETH', + transferType: 'erc20', + }, + { + from: subjectAddress, + to: wethContractAddress, + amount: '1000000000000', + decimal: 18, + symbol: 'ETH', + transferType: 'normal', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'wrap', + chainId: 'eip155:1', + status: 'success', + timestamp: 1779975743000, + data: { + hash: '0x6e448f5b8cf55534507770c1cb90ba14e723d03b4a46b4919a5847eb8d13b7b5', + sourceToken: { + amount: '1000000000000', + decimals: 18, + direction: 'out', + symbol: 'ETH', + assetId: toAssetId(NATIVE_TOKEN_ADDRESS, 'eip155:1'), + }, + destinationToken: { + amount: '1000000000000', + decimals: 18, + direction: 'in', + symbol: 'WETH', + assetId: toAssetId(wethContractAddress, 'eip155:1'), + }, + }, + }); + }); + + it('maps a WETH withdrawal to an Unwrap activity', () => { + const transaction = { + hash: '0x8f2a1c9e4b7d30651234567890abcdef1234567890abcdef1234567890abcdef', + timestamp: '2026-05-28T14:15:00.000Z', + chainId: 1, + from: subjectAddress, + to: wethContractAddress, + methodId: '0x2e1a7d4d', + transactionCategory: 'UNWRAP', + transactionProtocol: 'WETH', + transactionType: 'WETH_WITHDRAW', + valueTransfers: [ + { + from: subjectAddress, + to: wethContractAddress, + amount: '1000000000000', + decimal: 18, + contractAddress: wethContractAddress, + symbol: 'WETH', + transferType: 'erc20', + }, + { + from: wethContractAddress, + to: subjectAddress, + amount: '1000000000000', + decimal: 18, + symbol: 'ETH', + transferType: 'normal', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'unwrap', + chainId: 'eip155:1', + status: 'success', + timestamp: 1779977700000, + data: { + hash: '0x8f2a1c9e4b7d30651234567890abcdef1234567890abcdef1234567890abcdef', + sourceToken: { + amount: '1000000000000', + decimals: 18, + direction: 'out', + symbol: 'WETH', + assetId: toAssetId(wethContractAddress, 'eip155:1'), + }, + destinationToken: { + amount: '1000000000000', + decimals: 18, + direction: 'in', + symbol: 'ETH', + assetId: toAssetId(NATIVE_TOKEN_ADDRESS, 'eip155:1'), + }, + }, + }); + }); + + it('maps a bridge withdraw to a Bridge activity', () => { + const transaction = { + hash: '0x9f81163d00374094411f44732738c6dea194551e4500bde9fd7ee60319aac766', + timestamp: '2026-05-28T04:13:31.000Z', + chainId: 8453, + methodId: '0xe9ae5c53', + value: '0', + to: subjectAddress, + from: subjectAddress, + isError: false, + valueTransfers: [ + { + from: subjectAddress, + to: '0xa5c1ce365ddb5a91ff466774ec4bdf8f97cb9f55', + amount: '100000', + decimal: 6, + contractAddress: baseUsdc, + symbol: 'USDC', + transferType: 'erc20', + }, + ], + logs: [], + transactionCategory: 'BRIDGE_WITHDRAW', + transactionProtocol: 'ACROSS', + transactionType: 'ACROSS_BRIDGE_WITHDRAW', + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'bridge', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1779941611000, + data: { + hash: '0x9f81163d00374094411f44732738c6dea194551e4500bde9fd7ee60319aac766', + sourceToken: { + amount: '100000', + decimals: 6, + direction: 'out', + symbol: 'USDC', + assetId: toAssetId(baseUsdc, 'eip155:8453'), + }, + }, + }); + }); + + it('maps an unrecognized transaction category to a contract interaction activity', () => { + const transaction = { + timestamp: '2026-05-12T16:04:40.000Z', + chainId: 56, + from: bscContractCallerAddress, + to: bscUniversalRouter, + methodId: '0x174dea71', + transactionCategory: 'CONTRACT_CALL', + transactionProtocol: 'GENERIC', + transactionType: 'GENERIC_CONTRACT_CALL', + valueTransfers: [ + { + from: subjectAddress, + to: bscRecipientAddress, + symbol: 'BNB', + }, + ], + } as unknown as V1TransactionByHashResponse; + + expect( + withoutRaw(mapApiEvmTransactions({ subjectAddress, transaction })), + ).toStrictEqual({ + type: 'contractInteraction', + chainId: 'eip155:56', + status: 'success', + timestamp: 1778601880000, + data: { + from: bscContractCallerAddress, + hash: undefined, + methodId: '0x174dea71', + to: bscUniversalRouter, + transactionCategory: 'CONTRACT_CALL', + transactionProtocol: 'GENERIC', + transactionType: 'GENERIC_CONTRACT_CALL', + }, + }); + }); +}); diff --git a/app/util/activity-adapters/adapters/api-evm-transactions.ts b/app/util/activity-adapters/adapters/api-evm-transactions.ts new file mode 100644 index 00000000000..0841367c152 --- /dev/null +++ b/app/util/activity-adapters/adapters/api-evm-transactions.ts @@ -0,0 +1,388 @@ +/* + * Vendored from metamask-extension shared/lib/activity/adapters/api-evm-transactions.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + * + * Extension dependencies are provided via ActivityAdapterEnvironment. + */ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import { KnownCaipNamespace, toCaipChainId } from '@metamask/utils'; +import type { ActivityListItem, Status, TokenAmount } from '../types'; +import { supplyMethodIds } from './constants'; +import { + getTokenMetadataFromKnownToken, + getTokenAmountFromTransfer, + withFallbackTokenAssetId, + type ValueTransfer, +} from './helpers'; +import { + mobileActivityAdapterEnvironment, + type ActivityAdapterEnvironment, +} from './environment'; + +// Converts indexed API transactions into the shared activity item shape +export function mapApiEvmTransactions({ + subjectAddress, + transaction, + environment = mobileActivityAdapterEnvironment, +}: { + subjectAddress: string; + transaction: V1TransactionByHashResponse; + environment?: ActivityAdapterEnvironment; +}): ActivityListItem { + const { hash, transactionCategory, valueTransfers } = transaction; + const status: Status = transaction.isError ? 'failed' : 'success'; + const timestamp = new Date(transaction.timestamp).getTime(); + const chainId = toCaipChainId( + KnownCaipNamespace.Eip155, + transaction.chainId.toString(), + ); + const getToken = ( + transfer: ValueTransfer | undefined, + direction: TokenAmount['direction'], + ) => getTokenAmountFromTransfer(transfer, direction, chainId, environment); + + const sentTransfer = valueTransfers?.find(({ from }) => + environment.equalsIgnoreCase(from, subjectAddress), + ); + const receivedTransfer = valueTransfers?.find(({ to }) => + environment.equalsIgnoreCase(to, subjectAddress), + ); + const sentNftTransfer = valueTransfers?.find( + ({ from, transferType }) => + environment.equalsIgnoreCase(from, subjectAddress) && + (transferType === 'erc721' || transferType === 'erc1155'), + ); + const receivedNftTransfer = valueTransfers?.find( + ({ to, transferType }) => + environment.equalsIgnoreCase(to, subjectAddress) && + (transferType === 'erc721' || transferType === 'erc1155'), + ); + const sentNativeTransfer = valueTransfers?.find( + ({ from, transferType }) => + environment.equalsIgnoreCase(from, subjectAddress) && + transferType === 'normal', + ); + const hasNativeTransferWithoutMethod = + transactionCategory === 'CONTRACT_CALL' && + !transaction.methodId && + valueTransfers?.some(({ transferType }) => transferType === 'normal'); + const hasSupplyMethodId = + transaction.methodId && supplyMethodIds.has(transaction.methodId); + + if (transactionCategory === 'SWAP' || transactionCategory === 'EXCHANGE') { + if (!receivedTransfer?.symbol) { + return { + type: 'swapIncomplete', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + sourceToken: getToken(sentTransfer, 'out'), + hash, + }, + }; + } + + return { + type: 'swap', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + hash, + }, + }; + } + + if (transactionCategory === 'APPROVE') { + // TODO: Categorize REVOKE in the backend + const approveTransfer = sentTransfer ?? receivedTransfer; + const approveDirection = receivedTransfer && !sentTransfer ? 'in' : 'out'; + const approveToken = + getToken(approveTransfer, approveDirection) ?? + getTokenMetadataFromKnownToken( + transaction.to, + approveDirection, + chainId, + environment, + ); + + return { + type: 'approveSpendingCap', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + token: approveToken, + }, + }; + } + + // TODO: Categorize NFT in the backend, sometimes TRANSFER or CONTRACT_CALL + if (sentNftTransfer || receivedNftTransfer) { + if (receivedNftTransfer) { + if (receivedNftTransfer.from === environment.nativeTokenAddress) { + return { + type: 'nftMint', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + from: receivedNftTransfer.from, + to: receivedNftTransfer.to, + token: getToken(receivedNftTransfer, 'in'), + }, + }; + } + + if (sentNativeTransfer) { + return { + type: 'buy', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + token: getToken(receivedNftTransfer, 'in'), + }, + }; + } + + return { + type: 'receive', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + from: receivedNftTransfer.from, + to: receivedNftTransfer.to, + token: getToken(receivedNftTransfer, 'in'), + }, + }; + } + + if (sentNftTransfer) { + return { + type: 'send', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + from: sentNftTransfer.from, + to: sentNftTransfer.to, + token: getToken(sentNftTransfer, 'out'), + }, + }; + } + } + + if ( + transactionCategory === 'TRANSFER' || + transactionCategory === 'STANDARD' || + hasNativeTransferWithoutMethod + ) { + const isReceive = + Boolean(receivedTransfer) || + (environment.equalsIgnoreCase(transaction.to, subjectAddress) && + !environment.equalsIgnoreCase(transaction.from, subjectAddress)); + + const transfer = isReceive ? receivedTransfer : sentTransfer; + + return { + type: isReceive ? 'receive' : 'send', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + from: transfer?.from ?? transaction.from, + to: transfer?.to ?? transaction.to, + token: withFallbackTokenAssetId( + getToken(transfer, isReceive ? 'in' : 'out'), + transaction.to, + transfer?.transferType, + chainId, + environment, + ), + hash, + }, + }; + } + + if (transactionCategory === 'CLAIM_BONUS') { + return { + type: 'claimMusdBonus', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + token: getToken(receivedTransfer, 'in'), + }, + }; + } + + if (transactionCategory === 'CLAIM') { + return { + type: 'claim', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + token: getToken( + receivedTransfer ?? sentTransfer, + receivedTransfer ? 'in' : 'out', + ), + }, + }; + } + + if (transactionCategory === 'WITHDRAW') { + return { + type: 'lendingWithdrawal', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + }, + }; + } + + if (transactionCategory === 'BRIDGE_WITHDRAW') { + return { + type: 'bridge', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + sourceToken: getToken(sentTransfer, 'out'), + }, + }; + } + + // TODO: Categorize Deposit/Stake in the backend + if (sentTransfer && hasSupplyMethodId) { + return { + type: 'lendingDeposit', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + }, + }; + } + + // TODO: Categorize these Swaps in the backend + if ( + transactionCategory === 'CONTRACT_CALL' && + sentTransfer?.symbol && + receivedTransfer?.symbol && + sentTransfer.symbol !== receivedTransfer.symbol + ) { + return { + type: 'swap', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + hash, + }, + }; + } + + // TODO: Not sure if this is specific enough, may need separate category in backend + if ( + transactionCategory === 'DEPOSIT' && + receivedTransfer && + !hasSupplyMethodId + ) { + return { + type: 'wrap', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + }, + }; + } + + if (transactionCategory === 'UNWRAP') { + return { + type: 'unwrap', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + sourceToken: getToken(sentTransfer, 'out'), + destinationToken: getToken(receivedTransfer, 'in'), + }, + }; + } + + if (transactionCategory === 'DEPOSIT') { + return { + type: 'deposit', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + token: getToken(sentTransfer, 'in'), + }, + }; + } + + return { + type: 'contractInteraction', + chainId, + status, + timestamp, + raw: { type: 'apiEvmTransaction', data: transaction }, + data: { + hash, + methodId: transaction.methodId, + from: transaction.from, + to: transaction.to, + transactionCategory, + transactionProtocol: transaction.transactionProtocol, + transactionType: transaction.transactionType, + }, + }; +} diff --git a/app/util/activity-adapters/adapters/constants.ts b/app/util/activity-adapters/adapters/constants.ts new file mode 100644 index 00000000000..08652893717 --- /dev/null +++ b/app/util/activity-adapters/adapters/constants.ts @@ -0,0 +1,15 @@ +/** + * Vendored from metamask-extension shared/lib/activity/adapters/constants.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ + +// Known method IDs for supply/deposit calls +export const supplyMethodIds = new Set(['0x617ba037', '0xa1903eab']); + +// Known method IDs for withdraw calls +export const withdrawMethodIds = new Set(['0x69328dec']); + +// WETH9-style wrap / unwrap (deposit / withdraw) +export const wrapMethodIds = new Set(['0xd0e30db0']); +export const unwrapMethodIds = new Set(['0x2e1a7d4d']); diff --git a/app/util/activity-adapters/adapters/dedup.test.ts b/app/util/activity-adapters/adapters/dedup.test.ts new file mode 100644 index 00000000000..675dbd516df --- /dev/null +++ b/app/util/activity-adapters/adapters/dedup.test.ts @@ -0,0 +1,38 @@ +import type { ActivityListItem } from '../types'; +import { mergeActivityItems } from './dedup'; + +const makeItem = ( + source: string, + timestamp: number, + hash?: string, +): ActivityListItem => + ({ + type: 'send', + chainId: 'eip155:1', + status: 'success', + timestamp, + data: { hash }, + raw: { type: source, data: {} }, + }) as unknown as ActivityListItem; + +describe('mergeActivityItems', () => { + it('lets confirmed EVM items win over local duplicates and sorts newest first', () => { + const localDuplicate = makeItem('localTransaction', 1, '0xABC'); + const confirmed = makeItem('apiEvmTransaction', 2, '0xabc'); + const nonEvm = makeItem('keyringTransaction', 3, 'solana-hash'); + + expect(mergeActivityItems([localDuplicate], [confirmed], [nonEvm])).toEqual( + [nonEvm, confirmed], + ); + }); + + it('keeps hashless items because there is no stable dedup key', () => { + const local = makeItem('localTransaction', 1); + const confirmed = makeItem('apiEvmTransaction', 2); + + expect(mergeActivityItems([local], [confirmed], [])).toEqual([ + confirmed, + local, + ]); + }); +}); diff --git a/app/util/activity-adapters/adapters/dedup.ts b/app/util/activity-adapters/adapters/dedup.ts new file mode 100644 index 00000000000..6afe47fa776 --- /dev/null +++ b/app/util/activity-adapters/adapters/dedup.ts @@ -0,0 +1,55 @@ +/** + * Deduplication and merge helpers for ActivityListItem lists. + * Mirrors the Extension's helpers.ts#dedupeItems + groupActivityListItems, + * adapted for Mobile's three-source merge pattern. + */ +import type { ActivityListItem } from '../types'; + +function getItemHash(item: ActivityListItem): string | undefined { + return item.data.hash?.toLowerCase(); +} + +/** + * Merges local-EVM, API-confirmed-EVM, and non-EVM ActivityListItem arrays into + * a single list sorted newest-first. API-confirmed items win deduplication over + * local items with the same hash. + * + * Order of precedence: local first, then confirmed, then non-EVM — matching the + * original Mobile behavior where confirmed beats local by hash. + */ +export function mergeActivityItems( + localItems: ActivityListItem[], + confirmedEvmItems: ActivityListItem[], + nonEvmItems: ActivityListItem[], +): ActivityListItem[] { + const seenHashes = new Set(); + const result: ActivityListItem[] = []; + + // Confirmed EVM items are authoritative — add them first to seed seen hashes. + for (const item of confirmedEvmItems) { + const hash = getItemHash(item); + if (hash) { + if (seenHashes.has(hash)) continue; + seenHashes.add(hash); + } + result.push(item); + } + + // Local items: include unless a confirmed item with the same hash exists. + for (const item of localItems) { + const hash = getItemHash(item); + if (hash && seenHashes.has(hash)) continue; + if (hash) seenHashes.add(hash); + result.push(item); + } + + // Non-EVM: deduplicate by hash. + for (const item of nonEvmItems) { + const hash = getItemHash(item); + if (hash && seenHashes.has(hash)) continue; + if (hash) seenHashes.add(hash); + result.push(item); + } + + return result.sort((a, b) => b.timestamp - a.timestamp); +} diff --git a/app/util/activity-adapters/adapters/environment.ts b/app/util/activity-adapters/adapters/environment.ts new file mode 100644 index 00000000000..e52213144ce --- /dev/null +++ b/app/util/activity-adapters/adapters/environment.ts @@ -0,0 +1,81 @@ +/** + * Host dependency boundary for the vendored activity adapters. + * TODO: Move this contract into @metamask/activity-adapters when published. + */ +import { + BRIDGE_CHAINID_COMMON_TOKEN_PAIR, + IN_PROGRESS_TRANSACTION_STATUSES, + NATIVE_TOKEN_ADDRESS, + STATIC_MAINNET_TOKEN_LIST, + SWAPS_WRAPPED_TOKENS_ADDRESSES, + SmartTransactionStatus, + TOKEN_TRANSFER_LOG_TOPIC_HASH, + TransactionGroupStatus, + equalsIgnoreCase, + parseStandardTokenTransactionData, + toAssetId, +} from './shims'; +import { getNativeAssetForChainId } from '@metamask/bridge-controller'; + +export interface ActivityTokenMetadata { + symbol?: string; + decimals?: number; + assetId?: string; +} + +export interface ParsedStandardTokenTransactionData { + args?: Record; +} + +export interface ActivityAdapterEnvironment { + bridgeChainIdCommonTokenPair: Record< + string, + ActivityTokenMetadata | undefined + >; + equalsIgnoreCase: (value?: string, other?: string) => boolean; + getNativeAssetForChainId: ( + chainId: string, + ) => ActivityTokenMetadata | undefined; + inProgressTransactionStatuses: readonly string[]; + nativeTokenAddress: string; + parseStandardTokenTransactionData: ( + data: string, + ) => ParsedStandardTokenTransactionData | undefined; + smartTransactionStatus: { + cancelled: string; + pending: string; + success: string; + }; + staticMainnetTokenList: Record; + tokenTransferLogTopicHash: string; + toAssetId: ( + address: string, + chainId: string | undefined, + ) => string | undefined; + transactionGroupStatus: { + cancelled: string; + pending: string; + }; + wrappedTokenAddresses: Record; +} + +export const mobileActivityAdapterEnvironment: ActivityAdapterEnvironment = { + bridgeChainIdCommonTokenPair: BRIDGE_CHAINID_COMMON_TOKEN_PAIR, + equalsIgnoreCase, + getNativeAssetForChainId: (chainId) => { + try { + return getNativeAssetForChainId(chainId); + } catch { + return undefined; + } + }, + inProgressTransactionStatuses: IN_PROGRESS_TRANSACTION_STATUSES, + nativeTokenAddress: NATIVE_TOKEN_ADDRESS, + parseStandardTokenTransactionData, + smartTransactionStatus: SmartTransactionStatus, + staticMainnetTokenList: STATIC_MAINNET_TOKEN_LIST, + tokenTransferLogTopicHash: TOKEN_TRANSFER_LOG_TOPIC_HASH, + toAssetId, + transactionGroupStatus: TransactionGroupStatus, + wrappedTokenAddresses: SWAPS_WRAPPED_TOKENS_ADDRESSES, +}; diff --git a/app/util/activity-adapters/adapters/helpers.test.ts b/app/util/activity-adapters/adapters/helpers.test.ts new file mode 100644 index 00000000000..ee3bee8b6e5 --- /dev/null +++ b/app/util/activity-adapters/adapters/helpers.test.ts @@ -0,0 +1,143 @@ +import { + TransactionStatus, + TransactionType, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { getLocalTransactionStatus } from './helpers'; + +type LocalTransactionStatusInput = Parameters< + typeof getLocalTransactionStatus +>[0]; + +const baseTransactionMeta = { + chainId: '0x1', + id: 'activity-helpers-test-tx', + networkClientId: 'mainnet', + time: 0, + txParams: {}, +} as const; + +const makeGroup = ( + overrides: Partial = {}, +): LocalTransactionStatusInput => ({ + primaryTransaction: { + ...baseTransactionMeta, + txReceipt: {}, + type: 'simpleSend', + status: TransactionStatus.submitted, + ...overrides, + } as TransactionMeta, + initialTransaction: { + ...baseTransactionMeta, + isSmartTransaction: false, + txParams: {}, + ...overrides, + } as TransactionMeta & { isSmartTransaction?: boolean }, +}); + +describe('getLocalTransactionStatus', () => { + it('maps confirmed → success', () => { + const group = makeGroup({ status: TransactionStatus.confirmed }); + + expect(getLocalTransactionStatus(group)).toBe('success'); + }); + + it('maps failed → failed', () => { + const group = makeGroup({ status: TransactionStatus.failed }); + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); + + it('maps dropped → failed', () => { + const group = makeGroup({ status: TransactionStatus.dropped }); + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); + + it('maps rejected → failed', () => { + const group = makeGroup({ status: TransactionStatus.rejected }); + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); + + it('maps cancelled (cancel-type tx) → failed', () => { + const group = makeGroup({ + status: TransactionStatus.confirmed, + type: TransactionType.cancel, + }); + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); + + it('maps submitted → pending', () => { + const group = makeGroup({ status: TransactionStatus.submitted }); + + expect(getLocalTransactionStatus(group)).toBe('pending'); + }); + + it('maps approved → pending', () => { + const group = makeGroup({ status: TransactionStatus.approved }); + + expect(getLocalTransactionStatus(group)).toBe('pending'); + }); + + it('maps unapproved → pending', () => { + const group = makeGroup({ status: TransactionStatus.unapproved }); + + expect(getLocalTransactionStatus(group)).toBe('pending'); + }); + + it('maps signed → pending', () => { + const group = makeGroup({ status: TransactionStatus.signed }); + + expect(getLocalTransactionStatus(group)).toBe('pending'); + }); + + it('maps receipt status 0x0 (revert) → failed', () => { + const group = makeGroup({ + status: TransactionStatus.confirmed, + txReceipt: { status: '0x0' }, + }); + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); + + it('maps smart tx pending → pending', () => { + const group: LocalTransactionStatusInput = { + primaryTransaction: makeGroup({}).primaryTransaction, + initialTransaction: { + ...baseTransactionMeta, + isSmartTransaction: true, + status: 'pending', + } as unknown as TransactionMeta & { isSmartTransaction?: boolean }, + }; + + expect(getLocalTransactionStatus(group)).toBe('pending'); + }); + + it('maps smart tx success → success', () => { + const group: LocalTransactionStatusInput = { + primaryTransaction: makeGroup({}).primaryTransaction, + initialTransaction: { + ...baseTransactionMeta, + isSmartTransaction: true, + status: 'success', + } as unknown as TransactionMeta & { isSmartTransaction?: boolean }, + }; + + expect(getLocalTransactionStatus(group)).toBe('success'); + }); + + it('maps smart tx cancelled → failed', () => { + const group: LocalTransactionStatusInput = { + primaryTransaction: makeGroup({}).primaryTransaction, + initialTransaction: { + ...baseTransactionMeta, + isSmartTransaction: true, + status: 'cancelled', + } as unknown as TransactionMeta & { isSmartTransaction?: boolean }, + }; + + expect(getLocalTransactionStatus(group)).toBe('failed'); + }); +}); diff --git a/app/util/activity-adapters/adapters/helpers.ts b/app/util/activity-adapters/adapters/helpers.ts new file mode 100644 index 00000000000..4316da84d6d --- /dev/null +++ b/app/util/activity-adapters/adapters/helpers.ts @@ -0,0 +1,243 @@ +/* + * Vendored from metamask-extension shared/lib/activity/adapters/helpers.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + * + * Extension dependencies are provided via ActivityAdapterEnvironment. + */ +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import type { CaipChainId, Hex } from '@metamask/utils'; +import { + TransactionStatus, + TransactionType, +} from '@metamask/transaction-controller'; +import type { TransactionGroup } from './transaction-group'; +import type { Status, TokenAmount } from '../types'; +import { + mobileActivityAdapterEnvironment, + type ActivityAdapterEnvironment, +} from './environment'; + +const MAINNET_HEX_CHAIN_ID = '0x1'; + +export type ValueTransfer = NonNullable< + V1TransactionByHashResponse['valueTransfers'] +>[number]; + +const resolveAssetId = ( + chainId: CaipChainId, + { + contractAddress, + transferType, + }: { + contractAddress?: string; + transferType?: string; + }, + environment: ActivityAdapterEnvironment, +): string | undefined => { + if (contractAddress) { + return environment.toAssetId(contractAddress, chainId); + } + + if (transferType === 'normal' || transferType === 'internal') { + return environment.toAssetId(environment.nativeTokenAddress, chainId); + } + + return undefined; +}; + +function getTransactionStatusKey( + transaction: TransactionGroup['primaryTransaction'], + environment: ActivityAdapterEnvironment, +): string { + const { + txReceipt: { status: receiptStatus } = {}, + type, + status, + } = transaction; + + if (receiptStatus === '0x0') { + return TransactionStatus.failed; + } + + if ( + status === TransactionStatus.confirmed && + type === TransactionType.cancel + ) { + return environment.transactionGroupStatus.cancelled; + } + + return transaction.status; +} + +export function getLocalTransactionStatus( + { + primaryTransaction, + initialTransaction, + }: { + primaryTransaction: TransactionGroup['primaryTransaction']; + initialTransaction: TransactionGroup['initialTransaction']; + }, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +): Status { + if (initialTransaction.isSmartTransaction) { + const smartStatus = initialTransaction.status as string | undefined; + + if (smartStatus === environment.smartTransactionStatus.pending) { + return 'pending'; + } + + if (smartStatus === environment.smartTransactionStatus.success) { + return 'success'; + } + + if (smartStatus === environment.smartTransactionStatus.cancelled) { + return 'failed'; + } + + return 'pending'; + } + + const statusKey = getTransactionStatusKey(primaryTransaction, environment); + + if (statusKey === TransactionStatus.confirmed) { + return 'success'; + } + + if ( + statusKey === TransactionStatus.cancelled || + statusKey === environment.transactionGroupStatus.cancelled || + statusKey === TransactionStatus.dropped || + statusKey === TransactionStatus.failed || + statusKey === TransactionStatus.rejected + ) { + return 'failed'; + } + + if (environment.inProgressTransactionStatuses.includes(statusKey)) { + return 'pending'; + } + + return 'pending'; +} + +export function getKnownTokenMetadata( + chainId: CaipChainId | Hex, + contractAddress?: string, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +) { + if (contractAddress === undefined) { + return undefined; + } + + const assetId = environment.toAssetId(contractAddress, chainId); + const tokenMetadata = + (chainId === MAINNET_HEX_CHAIN_ID || assetId?.startsWith('eip155:1/') + ? environment.staticMainnetTokenList[contractAddress.toLowerCase()] + : undefined) ?? + Object.values(environment.bridgeChainIdCommonTokenPair).find( + (token) => + token?.assetId !== undefined && + assetId !== undefined && + environment.equalsIgnoreCase(token.assetId, assetId), + ); + + return tokenMetadata + ? { ...tokenMetadata, ...(assetId ? { assetId } : {}) } + : undefined; +} + +export function getTokenMetadataFromKnownToken( + contractAddress: string | undefined, + direction: TokenAmount['direction'], + chainId: CaipChainId | Hex, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +) { + const tokenMetadata = getKnownTokenMetadata( + chainId, + contractAddress, + environment, + ); + + if (!tokenMetadata) { + return undefined; + } + + return { + direction, + ...(tokenMetadata.symbol ? { symbol: tokenMetadata.symbol } : {}), + ...(tokenMetadata.decimals === undefined + ? {} + : { decimals: tokenMetadata.decimals }), + ...(tokenMetadata.assetId ? { assetId: tokenMetadata.assetId } : {}), + }; +} + +export function getTokenAmountFromTransfer( + transfer: ValueTransfer | undefined, + direction: TokenAmount['direction'], + chainId: CaipChainId, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +) { + if (!transfer?.symbol && transfer?.amount === undefined) { + return undefined; + } + + const isNftTransfer = + transfer?.transferType === 'erc721' || transfer?.transferType === 'erc1155'; + + const assetId = + transfer && !isNftTransfer + ? resolveAssetId( + chainId, + { + contractAddress: transfer.contractAddress, + transferType: transfer.transferType, + }, + environment, + ) + : undefined; + + return { + direction, + ...(transfer.amount === null || transfer.amount === undefined + ? {} + : { amount: String(transfer.amount) }), + ...(transfer.decimal === undefined ? {} : { decimals: transfer.decimal }), + ...(transfer.symbol ? { symbol: transfer.symbol } : {}), + ...(assetId ? { assetId } : {}), + }; +} + +/** + * When the transfer omits contractAddress, fall back to the indexed tx `to` field. + * + * @param token - Parsed token amount from the value transfer. + * @param fallbackContractAddress - Indexed transaction `to` address used as ERC-20 fallback. + * @param transferType - Value transfer type; native (`normal`) transfers skip the fallback. + * @param chainId - CAIP-2 chain id for asset id encoding. + * @returns Token amount with `assetId` set when a fallback address applies. + */ +export function withFallbackTokenAssetId( + token: TokenAmount | undefined, + fallbackContractAddress: string | undefined, + transferType: string | undefined, + chainId: CaipChainId, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +): TokenAmount | undefined { + if ( + !token || + token.assetId || + transferType === 'normal' || + !fallbackContractAddress + ) { + return token; + } + + const assetId = environment.toAssetId(fallbackContractAddress, chainId); + if (!assetId) { + return token; + } + + return { ...token, assetId }; +} diff --git a/app/util/activity-adapters/adapters/keyring-transaction.test.ts b/app/util/activity-adapters/adapters/keyring-transaction.test.ts new file mode 100644 index 00000000000..75e784fc7e5 --- /dev/null +++ b/app/util/activity-adapters/adapters/keyring-transaction.test.ts @@ -0,0 +1,168 @@ +import { + TransactionStatus, + TransactionType, + type Transaction, +} from '@metamask/keyring-api'; +import { mapKeyringTransaction } from './keyring-transaction'; + +const SOLANA_CHAIN_ID = + 'solana:4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ' as Transaction['chain']; +const BITCOIN_CHAIN_ID = + 'bip122:000000000019d6689c085ae165831e93' as Transaction['chain']; + +describe('mapKeyringTransaction', () => { + it('maps keyring send transactions with token amount data', () => { + const item = mapKeyringTransaction({ + transaction: { + id: 'send-id', + chain: SOLANA_CHAIN_ID, + account: '00000000-0000-4000-8000-000000000000', + status: TransactionStatus.Confirmed, + timestamp: 1716367781, + type: TransactionType.Send, + from: [ + { + address: 'from-address', + asset: { + fungible: true, + type: `${SOLANA_CHAIN_ID}/token:usdc`, + unit: 'USDC', + amount: '2.5', + }, + }, + ], + to: [{ address: 'to-address', asset: null }], + fees: [], + events: [], + } as Transaction, + }); + + expect(item).toStrictEqual( + expect.objectContaining({ + type: 'send', + chainId: SOLANA_CHAIN_ID, + status: 'success', + timestamp: 1716367781000, + data: { + hash: 'send-id', + from: 'from-address', + to: 'to-address', + token: { + amount: '2.5', + assetId: `${SOLANA_CHAIN_ID}/token:usdc`, + direction: 'out', + symbol: 'USDC', + }, + }, + }), + ); + }); + + it('maps keyring swap transactions with source and destination token amounts', () => { + const item = mapKeyringTransaction({ + transaction: { + id: 'swap-id', + chain: SOLANA_CHAIN_ID, + account: '00000000-0000-4000-8000-000000000000', + status: TransactionStatus.Submitted, + timestamp: 1716367781, + type: TransactionType.Swap, + from: [ + { + address: 'from-address', + asset: { + fungible: true, + type: `${SOLANA_CHAIN_ID}/slip44:501`, + unit: 'SOL', + amount: '1', + }, + }, + ], + to: [ + { + address: 'to-address', + asset: { + fungible: true, + type: `${SOLANA_CHAIN_ID}/token:usdc`, + unit: 'USDC', + amount: '100', + }, + }, + ], + fees: [], + events: [], + } as Transaction, + }); + + expect(item).toStrictEqual( + expect.objectContaining({ + type: 'swap', + chainId: SOLANA_CHAIN_ID, + status: 'pending', + timestamp: 1716367781000, + data: { + hash: 'swap-id', + sourceToken: { + amount: '1', + assetId: `${SOLANA_CHAIN_ID}/slip44:501`, + direction: 'out', + symbol: 'SOL', + }, + destinationToken: { + amount: '100', + assetId: `${SOLANA_CHAIN_ID}/token:usdc`, + direction: 'in', + symbol: 'USDC', + }, + }, + }), + ); + }); + + it('maps bitcoin send token from to-movement when from is empty', () => { + const item = mapKeyringTransaction({ + transaction: { + id: 'btc-send-output-id', + chain: BITCOIN_CHAIN_ID, + account: '00000000-0000-4000-8000-000000000000', + status: TransactionStatus.Confirmed, + timestamp: 1716367781, + type: TransactionType.Send, + from: [{ address: 'bc1from', asset: null }], + to: [ + { + address: 'bc1to', + asset: { + fungible: true, + type: `${BITCOIN_CHAIN_ID}/slip44:0`, + unit: 'BTC', + amount: '0.1', + }, + }, + ], + fees: [], + events: [], + } as Transaction, + }); + + expect(item).toStrictEqual( + expect.objectContaining({ + type: 'send', + chainId: BITCOIN_CHAIN_ID, + status: 'success', + timestamp: 1716367781000, + data: { + hash: 'btc-send-output-id', + from: 'bc1from', + to: 'bc1to', + token: { + amount: '0.1', + assetId: `${BITCOIN_CHAIN_ID}/slip44:0`, + direction: 'out', + symbol: 'BTC', + }, + }, + }), + ); + }); +}); diff --git a/app/util/activity-adapters/adapters/keyring-transaction.ts b/app/util/activity-adapters/adapters/keyring-transaction.ts new file mode 100644 index 00000000000..e3df7726bd1 --- /dev/null +++ b/app/util/activity-adapters/adapters/keyring-transaction.ts @@ -0,0 +1,195 @@ +/** + * Vendored from metamask-extension shared/lib/activity/adapters/keyring-transaction.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ +import { + type Transaction, + TransactionStatus as KeyringTransactionStatus, + TransactionType as KeyringTransactionType, +} from '@metamask/keyring-api'; +import type { ActivityListItem, Status, TokenAmount } from '../types'; + +type Movement = Transaction['from'][number]; +type FungibleAsset = Extract< + NonNullable, + { fungible: true } +>; + +function mapStatus(status: Transaction['status']): Status { + switch (status) { + case KeyringTransactionStatus.Confirmed: + return 'success'; + case KeyringTransactionStatus.Failed: + return 'failed'; + case KeyringTransactionStatus.Submitted: + case KeyringTransactionStatus.Unconfirmed: + default: + return 'pending'; + } +} + +function mapTimestamp(timestamp: Transaction['timestamp']) { + return timestamp ? timestamp * 1000 : 0; +} + +function getAddress(movements: Movement[]) { + return movements[0]?.address ?? ''; +} + +function hasFungibleAsset( + movement: Movement, +): movement is Movement & { asset: FungibleAsset } { + return movement.asset?.fungible === true; +} + +function getToken( + movements: Movement[], + direction: TokenAmount['direction'], +): TokenAmount | undefined { + const movement = movements.find(hasFungibleAsset); + + if (!movement) { + return undefined; + } + + return { + amount: movement.asset.amount, + symbol: movement.asset.unit, + assetId: movement.asset.type, + direction, + }; +} + +function aggregateMovementAmount(movements: Movement[]) { + const amountByAssetType: Record< + string, + { + amount: number; + unit: string; + } + > = {}; + + for (const movement of movements) { + if (!hasFungibleAsset(movement)) { + continue; + } + + const { type: assetType, unit } = movement.asset; + const parsedAmount = Number.parseFloat(movement.asset.amount); + const normalizedAmount = Number.isFinite(parsedAmount) ? parsedAmount : 0; + + if (!amountByAssetType[assetType]) { + amountByAssetType[assetType] = { + amount: normalizedAmount, + unit, + }; + continue; + } + + amountByAssetType[assetType].amount += normalizedAmount; + } + + const entries = Object.entries(amountByAssetType); + if (entries.length !== 1) { + return undefined; + } + + const [assetType, aggregate] = entries[0]; + return { + assetType, + amount: String(aggregate.amount), + unit: aggregate.unit, + }; +} + +// Converts keyring API transactions into the shared activity item shape +export function mapKeyringTransaction({ + transaction, +}: { + transaction: Transaction; +}): ActivityListItem { + const status = mapStatus(transaction.status); + const timestamp = mapTimestamp(transaction.timestamp); + const chainId = transaction.chain; + const from = getAddress(transaction.from); + const to = getAddress(transaction.to); + + if (transaction.type === KeyringTransactionType.Send) { + const fromToken = getToken(transaction.from, 'out'); + let token = fromToken; + + // Bitcoin transaction.from can be empty, resulting in no token avatar or send amount displayed. + // Workaround: use the same aggregated to-asset fallback strategy as tx details modal. + if (!fromToken && chainId.startsWith('bip122:')) { + const aggregatedToAsset = aggregateMovementAmount(transaction.to); + if (aggregatedToAsset) { + token = { + direction: 'out', + assetId: aggregatedToAsset.assetType, + symbol: aggregatedToAsset.unit, + amount: aggregatedToAsset.amount, + }; + } + } + + return { + type: 'send', + chainId, + status, + timestamp, + raw: { type: 'keyringTransaction', data: transaction }, + data: { + hash: transaction.id, + from, + to, + token, + }, + }; + } + + if (transaction.type === KeyringTransactionType.Receive) { + return { + type: 'receive', + chainId, + status, + timestamp, + raw: { type: 'keyringTransaction', data: transaction }, + data: { + hash: transaction.id, + from, + to, + token: getToken(transaction.to, 'in'), + }, + }; + } + + if (transaction.type === KeyringTransactionType.Swap) { + return { + type: 'swap', + chainId, + status, + timestamp, + raw: { type: 'keyringTransaction', data: transaction }, + data: { + hash: transaction.id, + destinationToken: getToken(transaction.to, 'in'), + sourceToken: getToken(transaction.from, 'out'), + }, + }; + } + + return { + type: 'contractInteraction', + chainId, + status, + timestamp, + raw: { type: 'keyringTransaction', data: transaction }, + data: { + hash: transaction.id, + from, + to, + transactionType: transaction.type, + }, + }; +} diff --git a/app/util/activity-adapters/adapters/local-transaction.test.ts b/app/util/activity-adapters/adapters/local-transaction.test.ts new file mode 100644 index 00000000000..01c6f7884f2 --- /dev/null +++ b/app/util/activity-adapters/adapters/local-transaction.test.ts @@ -0,0 +1,753 @@ +import { + TransactionStatus, + TransactionType, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { mapLocalTransaction } from './local-transaction'; +import type { TransactionGroup } from './transaction-group'; +import { toAssetId } from './shims'; +import { MERKL_DISTRIBUTOR_ADDRESS } from '../../../components/UI/Earn/components/MerklRewards/constants'; + +const from = '0x9bed78535d6a03a955f1504aadba974d9a29e292'; +const to = '0x80181d3ba89220cdb80234fc7aa19d5cc56229cc'; +const mainnet = '0x1'; +const base = '0x2105'; +const linea = '0xe708'; +const baseUsdc = '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'; +const baseAavePool = '0xa238dd80c259a72e81d7e4664a9801593f98d1c5'; +const lineaDai = '0x4af15ec2a0bd43db75dd04e62faa3b8ef36b00d5'; +const lineaMusd = '0xaca92e438df0b2401ff60da7e4337b687a2435da'; +const wethContractAddress = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2'; +const erc20TransferTopic = + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; + +const withoutRaw = (item: ReturnType) => { + const activity = { ...item }; + delete activity.raw; + return activity; +}; + +const makeGroup = ( + transaction: Partial, + overrides: Partial = {}, +): TransactionGroup => + ({ + initialTransaction: transaction, + primaryTransaction: transaction, + nativeAssetSymbol: 'ETH', + ...overrides, + }) as TransactionGroup; + +const addressTopic = (address: string) => + `0x${address.toLowerCase().replace('0x', '').padStart(64, '0')}`; + +describe('mapLocalTransaction', () => { + it('maps a pending native send to a Send activity', () => { + const transaction = { + chainId: mainnet, + id: 'send-id', + hash: '0xsend', + status: TransactionStatus.submitted, + time: 1716367781000, + type: TransactionType.simpleSend, + txParams: { + from, + to, + value: '0x1', + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:1', + status: 'pending', + timestamp: 1716367781000, + data: { + hash: '0xsend', + from, + to, + token: { + amount: '0x1', + assetId: 'eip155:1/slip44:60', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + }, + }); + }); + + it('maps an ERC-20 transfer without transferInformation from known token metadata', () => { + const tokenContractAddress = '0xdac17f958d2ee523a2206206994597c13d831ec7'; + const recipient = '0xa6372EDD08c857870f9c245A17eE6895307957d5'; + const transaction = { + chainId: mainnet, + id: 'usdt-send-id', + hash: '0x41f675c4a384e5064b1d9620934b0ff5e8a84f5c84530a25d025e27fb784d303', + status: TransactionStatus.confirmed, + time: 1779392463306, + type: TransactionType.tokenMethodTransfer, + txParams: { + from, + to: tokenContractAddress, + value: '0x0', + data: '0xa9059cbb000000000000000000000000a6372edd08c857870f9c245a17ee6895307957d500000000000000000000000000000000000000000000000000000000000186a0', + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:1', + status: 'success', + timestamp: 1779392463306, + data: { + hash: '0x41f675c4a384e5064b1d9620934b0ff5e8a84f5c84530a25d025e27fb784d303', + from, + to: recipient, + token: { + amount: '100000', + assetId: toAssetId(tokenContractAddress, 'eip155:1'), + decimals: 6, + direction: 'out', + symbol: 'USDT', + }, + }, + }); + }); + + it('maps a custom network native send without bridge native asset metadata', () => { + const customChainId = '0x53a'; + const transaction = { + chainId: customChainId, + id: 'custom-send-id', + hash: '0xcustomsend', + status: TransactionStatus.confirmed, + time: 1779392463306, + type: TransactionType.simpleSend, + txParams: { + from, + to, + value: '0xde0b6b3a7640000', + }, + } as unknown as Partial; + + expect( + withoutRaw( + mapLocalTransaction( + makeGroup(transaction, { + nativeAssetSymbol: 'ETH', + nonce: '0x1', + transactions: [transaction as TransactionMeta], + }), + ), + ), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:1338', + status: 'success', + timestamp: 1779392463306, + data: { + hash: '0xcustomsend', + from, + to, + token: { + amount: '0xde0b6b3a7640000', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + }, + }); + }); + + it('maps a USDC transfer with transferInformation', () => { + const tokenContractAddress = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; + const recipient = '0x50A9D56C2B8BA9A5c7f2C08C3d26E0499F23a706'; + const transaction = { + chainId: mainnet, + id: 'token-send-id', + hash: '0xtokensend', + status: TransactionStatus.submitted, + time: 1716367781000, + transferInformation: { + amount: '20000', + contractAddress: tokenContractAddress, + decimals: 6, + symbol: 'USDC', + }, + type: TransactionType.tokenMethodTransfer, + txParams: { + from, + to: tokenContractAddress, + data: '0xa9059cbb00000000000000000000000050a9d56c2b8ba9a5c7f2c08c3d26e0499f23a7060000000000000000000000000000000000000000000000000000000000004e20', + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'send', + chainId: 'eip155:1', + status: 'pending', + timestamp: 1716367781000, + data: { + hash: '0xtokensend', + from, + to: recipient, + token: { + amount: '20000', + assetId: toAssetId(tokenContractAddress, 'eip155:1'), + decimals: 6, + direction: 'out', + symbol: 'USDC', + }, + }, + }); + }); + + it('leaves unknown token transfer symbols blank', () => { + const tokenContractAddress = '0x1111111111111111111111111111111111111111'; + const transaction = { + chainId: mainnet, + id: 'unknown-token-send-id', + hash: '0xunknown', + status: TransactionStatus.confirmed, + time: 1779392463306, + type: TransactionType.tokenMethodTransfer, + txParams: { + from, + to: tokenContractAddress, + value: '0x0', + data: '0xa9059cbb000000000000000000000000a6372edd08c857870f9c245a17ee6895307957d500000000000000000000000000000000000000000000000000000000000186a0', + }, + } as unknown as Partial; + + const item = mapLocalTransaction(makeGroup(transaction)); + + expect(item.type).toBe('send'); + if (item.type !== 'send') { + throw new Error(`Expected send item, got ${item.type}`); + } + + expect(item.data.token).toStrictEqual({ + amount: '100000', + assetId: toAssetId(tokenContractAddress, 'eip155:1'), + direction: 'out', + }); + }); + + it('uses the original transaction type and primary transaction status', () => { + const initialTransaction = { + chainId: linea, + id: 'approve-id', + hash: '0xapprove', + status: TransactionStatus.submitted, + time: 1716367781000, + transferInformation: { + contractAddress: '0x239fd4b0c4db49fa8660e65b97619d43d0e0a79d', + decimals: 0, + symbol: 'TDN', + }, + type: TransactionType.tokenMethodApprove, + txParams: { + from, + to: '0x239fd4b0c4db49fa8660e65b97619d43d0e0a79d', + data: '0xa22cb465', + }, + } as Partial; + const primaryTransaction = { + ...initialTransaction, + id: 'retry-id', + hash: '0xretry', + status: TransactionStatus.approved, + time: 1716367881000, + type: TransactionType.retry, + } as Partial; + + expect( + withoutRaw( + mapLocalTransaction( + makeGroup(initialTransaction, { + hasRetried: true, + nonce: '0x2', + primaryTransaction: primaryTransaction as TransactionMeta, + transactions: [ + initialTransaction as TransactionMeta, + primaryTransaction as TransactionMeta, + ], + }), + ), + ), + ).toStrictEqual({ + type: 'approveSpendingCap', + chainId: 'eip155:59144', + status: 'pending', + timestamp: 1716367881000, + data: { + hash: '0xretry', + token: { + assetId: toAssetId( + '0x239fd4b0c4db49fa8660e65b97619d43d0e0a79d', + 'eip155:59144', + ), + direction: 'out', + symbol: 'TDN', + }, + }, + }); + }); + + it('uses bridge history token data to map a local swap', () => { + const transaction = { + chainId: base, + id: 'bridge-swap-id', + hash: '0xbridgeswap', + status: TransactionStatus.confirmed, + time: 1779392463306, + type: TransactionType.swap, + txParams: { + from, + to, + value: '0x0', + }, + } as Partial; + + expect( + withoutRaw( + mapLocalTransaction( + makeGroup(transaction, { + sourceToken: { + amount: '10000000000000', + assetId: 'eip155:8453/slip44:60', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + destinationToken: { + amount: '19546', + assetId: + 'eip155:8453/erc20:0xACa92e438df0B2401fF60Da7E4337B687a2435dA', + decimals: 6, + direction: 'in', + symbol: 'MUSD', + }, + }), + ), + ), + ).toStrictEqual({ + type: 'swap', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1779392463306, + data: { + hash: '0xbridgeswap', + sourceToken: { + amount: '10000000000000', + assetId: 'eip155:8453/slip44:60', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + destinationToken: { + amount: '19546', + assetId: + 'eip155:8453/erc20:0xACa92e438df0B2401fF60Da7E4337B687a2435dA', + decimals: 6, + direction: 'in', + symbol: 'MUSD', + }, + }, + }); + }); + + it('maps an mUSD conversion to a Convert activity', () => { + const transaction = { + chainId: linea, + id: 'musd-conversion-id', + hash: '0xmusdconversion', + status: TransactionStatus.confirmed, + time: 1779805800000, + type: TransactionType.musdConversion, + txParams: { + from, + to: lineaMusd, + value: '0x0', + data: '0xa9059cbb0000000000000000000000009bed78535d6a03a955f1504aadba974d9a29e2920000000000000000000000000000000000000000000000000000000000018703', + }, + } as Partial; + + expect( + withoutRaw( + mapLocalTransaction( + makeGroup(transaction, { + sourceToken: { + assetId: toAssetId(lineaDai, 'eip155:59144'), + decimals: 18, + direction: 'out', + symbol: 'DAI', + }, + }), + ), + ), + ).toStrictEqual({ + type: 'convert', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1779805800000, + data: { + hash: '0xmusdconversion', + sourceToken: { + assetId: toAssetId(lineaDai, 'eip155:59144'), + decimals: 18, + direction: 'out', + symbol: 'DAI', + }, + destinationToken: { + amount: '100099', + assetId: toAssetId(lineaMusd, 'eip155:59144'), + decimals: 6, + direction: 'in', + symbol: 'mUSD', + }, + }, + }); + }); + + it('maps an mUSD claim receipt payout to a Claim mUSD bonus activity with token amount', () => { + const transaction = { + chainId: linea, + id: 'musd-claim-id', + hash: '0xmusdclaim', + status: TransactionStatus.confirmed, + time: 1779805800000, + type: TransactionType.musdClaim, + txParams: { + from, + to: MERKL_DISTRIBUTOR_ADDRESS, + value: '0x0', + }, + txReceipt: { + logs: [ + { + address: lineaMusd, + data: '0x0f4240', + topics: [ + erc20TransferTopic, + addressTopic(MERKL_DISTRIBUTOR_ADDRESS), + addressTopic(from), + ], + }, + ], + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'claimMusdBonus', + chainId: 'eip155:59144', + status: 'success', + timestamp: 1779805800000, + data: { + hash: '0xmusdclaim', + token: { + amount: '1000000', + assetId: toAssetId(lineaMusd, 'eip155:59144'), + decimals: 6, + direction: 'in', + symbol: 'mUSD', + }, + }, + }); + }); + + it('maps an Aave supply contract interaction to a Lending deposit activity', () => { + const transaction = { + chainId: base, + id: 'aave-supply-id', + hash: '0x093844dd6200984f0e27d3c3a76b7a63b360bfb2136213237d693afd2cd69740', + status: TransactionStatus.confirmed, + time: 1779892154611, + type: TransactionType.contractInteraction, + txParams: { + from, + to: baseAavePool, + value: '0x0', + data: '0x617ba037000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000186a00000000000000000000000009bed78535d6a03a955f1504aadba974d9a29e2920000000000000000000000000000000000000000000000000000000000000000', + }, + simulationData: { + tokenBalanceChanges: [ + { + address: baseUsdc, + difference: '0x186a0', + isDecrease: true, + standard: 'erc20', + }, + ], + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'lendingDeposit', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1779892154611, + data: { + hash: '0x093844dd6200984f0e27d3c3a76b7a63b360bfb2136213237d693afd2cd69740', + sourceToken: { + amount: '100000', + assetId: toAssetId(baseUsdc, 'eip155:8453'), + decimals: 6, + direction: 'out', + symbol: 'USDC', + }, + }, + }); + }); + + it('maps a withdraw contract interaction from the received token transfer', () => { + const transaction = { + chainId: base, + hash: '0x26f4911467b538702c0945e4ec5e303de44c0c1c174897141d1b548ea3161795', + status: TransactionStatus.confirmed, + time: 1779912434153, + type: TransactionType.contractInteraction, + txParams: { + from, + to: baseAavePool, + data: '0x69328dec000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda029130000000000000000000000000000000000000000000000000000000000030d400000000000000000000000009bed78535d6a03a955f1504aadba974d9a29e292', + }, + txReceipt: { + logs: [ + { + address: baseUsdc, + data: '0x0000000000000000000000000000000000000000000000000000000000030d40', + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + '0x0000000000000000000000004e65fe4dba92790696d040ac24aa414708f5c0ab', + '0x0000000000000000000000009bed78535d6a03a955f1504aadba974d9a29e292', + ], + }, + ], + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'lendingWithdrawal', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1779912434153, + data: { + hash: '0x26f4911467b538702c0945e4ec5e303de44c0c1c174897141d1b548ea3161795', + destinationToken: { + amount: '200000', + assetId: toAssetId(baseUsdc, 'eip155:8453'), + decimals: 6, + direction: 'in', + symbol: 'USDC', + }, + }, + }); + }); + + it('uses a bridge history activity status override', () => { + const transaction = { + chainId: mainnet, + id: 'bridge-id', + hash: '0xbridge', + status: TransactionStatus.confirmed, + time: 1779392463306, + type: TransactionType.bridge, + txParams: { + from, + to, + value: '0x0', + }, + } as Partial; + + expect( + mapLocalTransaction( + makeGroup(transaction, { + activityStatus: 'failed', + }), + ).status, + ).toBe('failed'); + }); + + it('maps swap metadata token symbols to a Swap activity', () => { + const transaction = { + chainId: base, + id: 'swap-id', + hash: '0xswap', + status: TransactionStatus.confirmed, + time: 1716367781000, + swapMetaData: { + token_from: 'ETH', + token_to: 'USDC', + }, + type: TransactionType.swap, + txParams: { + from, + to: '0x9dda6ef3d919c9bc8885d5560999a3640431e8e6', + value: '0x246139ca8000', + }, + } as unknown as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'swap', + chainId: 'eip155:8453', + status: 'success', + timestamp: 1716367781000, + data: { + hash: '0xswap', + sourceToken: { + assetId: 'eip155:8453/slip44:60', + direction: 'out', + symbol: 'ETH', + }, + destinationToken: { + direction: 'in', + symbol: 'USDC', + }, + }, + }); + }); + + it('maps a WETH9 deposit contract interaction to a Wrap activity', () => { + const transaction = { + chainId: mainnet, + id: 'wrap-id', + hash: '0xwrap', + status: TransactionStatus.confirmed, + time: 1716367781000, + type: TransactionType.contractInteraction, + txParams: { + from, + to: wethContractAddress, + value: '0x3782dace9d900000', + data: '0xd0e30db0', + }, + } as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'wrap', + chainId: 'eip155:1', + status: 'success', + timestamp: 1716367781000, + data: { + hash: '0xwrap', + sourceToken: { + amount: '0x3782dace9d900000', + assetId: 'eip155:1/slip44:60', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + destinationToken: { + amount: '0x3782dace9d900000', + assetId: toAssetId(wethContractAddress, 'eip155:1'), + decimals: 18, + direction: 'in', + symbol: 'WETH', + }, + }, + }); + }); + + it('maps a WETH9 withdraw contract interaction to an Unwrap activity', () => { + const unwrapAmount = '1000000000000000000'; + const unwrapAmountHex = BigInt(unwrapAmount).toString(16).padStart(64, '0'); + const transaction = { + chainId: mainnet, + id: 'unwrap-id', + hash: '0xunwrap', + status: TransactionStatus.confirmed, + time: 1716367781000, + type: TransactionType.contractInteraction, + txParams: { + from, + to: wethContractAddress, + value: '0x0', + data: `0x2e1a7d4d${unwrapAmountHex}`, + }, + } as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'unwrap', + chainId: 'eip155:1', + status: 'success', + timestamp: 1716367781000, + data: { + hash: '0xunwrap', + sourceToken: { + amount: unwrapAmount, + assetId: toAssetId(wethContractAddress, 'eip155:1'), + decimals: 18, + direction: 'out', + symbol: 'WETH', + }, + destinationToken: { + amount: unwrapAmount, + assetId: 'eip155:1/slip44:60', + decimals: 18, + direction: 'in', + symbol: 'ETH', + }, + }, + }); + }); + + it('maps a native value contract interaction with an outgoing token', () => { + const transaction = { + chainId: mainnet, + id: 'contract-interaction-id', + hash: '0xcontract', + status: TransactionStatus.confirmed, + time: 1716367781000, + type: TransactionType.contractInteraction, + txParams: { + from, + to, + value: '0x3782dace9d900000', + data: '0xd0e30db0', + }, + } as Partial; + + expect( + withoutRaw(mapLocalTransaction(makeGroup(transaction))), + ).toStrictEqual({ + type: 'contractInteraction', + chainId: 'eip155:1', + status: 'success', + timestamp: 1716367781000, + data: { + hash: '0xcontract', + from, + to, + token: { + amount: '0x3782dace9d900000', + assetId: 'eip155:1/slip44:60', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }, + methodId: '0xd0e30db0', + transactionType: TransactionType.contractInteraction, + }, + }); + }); +}); diff --git a/app/util/activity-adapters/adapters/local-transaction.ts b/app/util/activity-adapters/adapters/local-transaction.ts new file mode 100644 index 00000000000..a2a1537a109 --- /dev/null +++ b/app/util/activity-adapters/adapters/local-transaction.ts @@ -0,0 +1,628 @@ +/* + * Vendored from metamask-extension shared/lib/activity/adapters/local-transaction.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + * + * Extension dependencies are provided via ActivityAdapterEnvironment. + */ +import { TransactionType } from '@metamask/transaction-controller'; +import { KnownCaipNamespace, toCaipChainId, type Hex } from '@metamask/utils'; +import { getClaimPayoutFromReceipt } from '../../../components/UI/Earn/utils/musd'; +import { + MUSD_DECIMALS, + MUSD_TOKEN, + MUSD_TOKEN_ADDRESS, + MUSD_TOKEN_ASSET_ID_BY_CHAIN, +} from '../../../components/UI/Earn/constants/musd'; +import type { ActivityListItem, TokenAmount } from '../types'; +import type { TransactionGroup } from './transaction-group'; +import { + supplyMethodIds, + unwrapMethodIds, + withdrawMethodIds, + wrapMethodIds, +} from './constants'; +import { getKnownTokenMetadata, getLocalTransactionStatus } from './helpers'; +import { + mobileActivityAdapterEnvironment, + type ActivityAdapterEnvironment, +} from './environment'; + +const EVM_NATIVE_DECIMALS = 18; + +// Converts local TransactionController groups into activity items +export function mapLocalTransaction( + transactionGroup: TransactionGroup, + environment: ActivityAdapterEnvironment = mobileActivityAdapterEnvironment, +): ActivityListItem { + const { initialTransaction, primaryTransaction } = transactionGroup; + const chainId = toCaipChainId( + KnownCaipNamespace.Eip155, + Number.parseInt(initialTransaction.chainId, 16).toString(), + ); + const nativeAsset = environment.getNativeAssetForChainId( + initialTransaction.chainId, + ); + // Prefer the network-configured ticker (resolved by the selector from + // NetworkController state) over the bridge-controller swaps registry, + // which hard-codes synthetic symbols like `TESTETH` for chains such as + // Localhost (0x539) regardless of how the user configured the network. + const nativeSymbol = + transactionGroup.nativeAssetSymbol ?? nativeAsset?.symbol; + + const getNativeToken = ( + transaction: TransactionGroup['initialTransaction'], + direction: TokenAmount['direction'], + ) => { + if (nativeSymbol === undefined) { + return undefined; + } + + return { + direction, + symbol: nativeSymbol, + ...(transaction.txParams.value + ? { amount: transaction.txParams.value } + : {}), + ...(nativeAsset?.assetId ? { assetId: nativeAsset.assetId } : {}), + decimals: nativeAsset?.decimals ?? EVM_NATIVE_DECIMALS, + }; + }; + + const getContractToken = ({ + amount, + contractAddress, + direction, + transaction, + }: { + amount?: string; + contractAddress?: string; + direction: TokenAmount['direction']; + transaction: TransactionGroup['initialTransaction']; + }) => { + if (contractAddress === undefined) { + return undefined; + } + + const tokenMetadata = getKnownTokenMetadata( + chainId, + contractAddress, + environment, + ); + const decimals = + transaction.transferInformation?.amount === undefined + ? (tokenMetadata?.decimals ?? + transactionGroup.contractTokenMetadata?.decimals) + : transaction.transferInformation.decimals; + const tokenAmount = transaction.transferInformation?.amount ?? amount; + const symbol = + transaction.transferInformation?.symbol ?? + tokenMetadata?.symbol ?? + transactionGroup.contractTokenMetadata?.symbol; + const assetId = environment.toAssetId(contractAddress, chainId); + + return { + direction, + ...(symbol ? { symbol } : {}), + ...(assetId ? { assetId } : {}), + ...(tokenAmount ? { amount: tokenAmount } : {}), + ...(decimals === undefined ? {} : { decimals }), + }; + }; + + const getLegacySwapToken = (direction: TokenAmount['direction']) => { + const { value } = initialTransaction.txParams; + let hasNativeValue = false; + + if (value !== undefined && value !== '') { + try { + hasNativeValue = BigInt(value) > 0n; + } catch { + hasNativeValue = false; + } + } + + let symbol: string | undefined; + + if (direction === 'out') { + symbol = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (initialTransaction as any).sourceTokenSymbol ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (primaryTransaction as any).sourceTokenSymbol ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (initialTransaction as any).swapMetaData?.token_from ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (primaryTransaction as any).swapMetaData?.token_from ?? + (hasNativeValue ? nativeSymbol : undefined); + } else { + symbol = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (initialTransaction as any).destinationTokenSymbol ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (primaryTransaction as any).destinationTokenSymbol ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (initialTransaction as any).swapMetaData?.token_to ?? + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (primaryTransaction as any).swapMetaData?.token_to; + } + + if (symbol === undefined) { + return undefined; + } + + return { + direction, + symbol, + ...(symbol === nativeSymbol && nativeAsset?.assetId + ? { assetId: nativeAsset.assetId } + : {}), + }; + }; + + const status = + transactionGroup.activityStatus ?? + getLocalTransactionStatus( + { + primaryTransaction, + initialTransaction, + }, + environment, + ); + const timestamp = primaryTransaction.time ?? initialTransaction.time; + const hash = + primaryTransaction.hash ?? initialTransaction.hash ?? primaryTransaction.id; + const from = initialTransaction.txParams.from ?? ''; + const to = initialTransaction.txParams.to ?? ''; + const methodId = initialTransaction.txParams.data?.slice(0, 10); + + switch (initialTransaction.type) { + case TransactionType.simpleSend: { + return { + type: 'send', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + from, + to, + token: getNativeToken(initialTransaction, 'out'), + }, + }; + } + + case TransactionType.tokenMethodSafeTransferFrom: + case TransactionType.tokenMethodTransfer: + case TransactionType.tokenMethodTransferFrom: { + const transactionData = initialTransaction.txParams.data + ? environment.parseStandardTokenTransactionData( + initialTransaction.txParams.data, + ) + : undefined; + const recipient = transactionData?.args?._to ?? transactionData?.args?.to; + const amount = + transactionData?.args?._value ?? transactionData?.args?.value; + + return { + type: 'send', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + from, + to: typeof recipient === 'string' ? recipient : to, + token: getContractToken({ + amount: amount?.toString(), + transaction: initialTransaction, + direction: 'out', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + } + + case TransactionType.incoming: { + return { + type: 'receive', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + from, + to, + token: initialTransaction.transferInformation?.contractAddress + ? getContractToken({ + transaction: initialTransaction, + direction: 'in', + contractAddress: + initialTransaction.transferInformation.contractAddress, + }) + : getNativeToken(initialTransaction, 'in'), + }, + }; + } + + case TransactionType.swap: + case TransactionType.swapAndSend: { + const { + sourceToken: enrichedSourceToken, + destinationToken: enrichedDestinationToken, + } = transactionGroup; + const sourceToken = enrichedSourceToken ?? getLegacySwapToken('out'); + const destinationToken = + enrichedDestinationToken ?? getLegacySwapToken('in'); + + if (destinationToken?.symbol === undefined) { + return { + type: 'swapIncomplete', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken, + }, + }; + } + + return { + type: 'swap', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken, + destinationToken, + }, + }; + } + + case TransactionType.bridge: { + const { + sourceToken: enrichedSourceToken, + destinationToken: enrichedDestinationToken, + } = transactionGroup; + return { + type: 'bridge', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken: enrichedSourceToken, + destinationToken: enrichedDestinationToken, + }, + }; + } + + case TransactionType.musdConversion: { + const transactionData = initialTransaction.txParams.data + ? environment.parseStandardTokenTransactionData( + initialTransaction.txParams.data, + ) + : undefined; + const amount = + transactionData?.args?._value ?? transactionData?.args?.value; + + return { + type: 'convert', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken: transactionGroup.sourceToken, + destinationToken: getContractToken({ + amount: amount?.toString(), + transaction: initialTransaction, + direction: 'in', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + } + + case TransactionType.bridgeApproval: + case TransactionType.shieldSubscriptionApprove: + case TransactionType.swapApproval: + case TransactionType.tokenMethodApprove: + case TransactionType.tokenMethodSetApprovalForAll: + return { + type: 'approveSpendingCap', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + token: getContractToken({ + transaction: initialTransaction, + direction: 'out', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + + case TransactionType.tokenMethodIncreaseAllowance: + return { + type: 'increaseSpendingCap', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + token: getContractToken({ + transaction: initialTransaction, + direction: 'out', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + + case TransactionType.lendingDeposit: + return { + type: 'lendingDeposit', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken: getContractToken({ + transaction: initialTransaction, + direction: 'out', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + + case TransactionType.stakingDeposit: + return { + type: 'deposit', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + token: getContractToken({ + transaction: initialTransaction, + direction: 'out', + contractAddress: initialTransaction.txParams.to, + }), + }, + }; + + case TransactionType.musdClaim: { + const claimAmountRaw = getClaimPayoutFromReceipt( + primaryTransaction.txReceipt?.logs, + from, + ); + + return { + type: 'claimMusdBonus', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + ...(claimAmountRaw + ? { + token: { + amount: claimAmountRaw, + assetId: + MUSD_TOKEN_ASSET_ID_BY_CHAIN[ + initialTransaction.chainId as Hex + ] ?? environment.toAssetId(MUSD_TOKEN_ADDRESS, chainId), + decimals: MUSD_DECIMALS, + direction: 'in', + symbol: MUSD_TOKEN.symbol, + }, + } + : {}), + }, + }; + } + + default: { + const isSupplyContractInteraction = + initialTransaction.type === TransactionType.contractInteraction && + methodId && + supplyMethodIds.has(methodId.toLowerCase()); + const isWithdrawContractInteraction = + initialTransaction.type === TransactionType.contractInteraction && + methodId && + withdrawMethodIds.has(methodId.toLowerCase()); + + const suppliedTokenBalanceChange = + isSupplyContractInteraction && + initialTransaction.simulationData?.tokenBalanceChanges?.find( + ({ isDecrease, standard }) => isDecrease && standard === 'erc20', + ); + + if (suppliedTokenBalanceChange) { + return { + type: 'lendingDeposit', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + sourceToken: getContractToken({ + amount: BigInt(suppliedTokenBalanceChange.difference).toString(), + transaction: initialTransaction, + direction: 'out', + contractAddress: suppliedTokenBalanceChange.address, + }), + }, + }; + } + + if (isWithdrawContractInteraction) { + const fromAddress = from.toLowerCase(); + const receivedTokenLog = ( + initialTransaction.txReceipt?.logs ?? [] + ).find(({ topics: [eventTopic, , logTo] = [] }) => { + const toAddress = logTo + ? `0x${logTo.slice(-40)}`.toLowerCase() + : undefined; + + return ( + eventTopic?.toLowerCase() === + environment.tokenTransferLogTopicHash && toAddress === fromAddress + ); + }); + const destinationToken = receivedTokenLog + ? getContractToken({ + amount: BigInt(String(receivedTokenLog.data)).toString(), + transaction: initialTransaction, + direction: 'in', + contractAddress: receivedTokenLog.address, + }) + : undefined; + + return { + type: 'lendingWithdrawal', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + destinationToken, + }, + }; + } + + // wrap and unwrap + if ( + initialTransaction.type === TransactionType.contractInteraction && + methodId + ) { + const wrappedTokenAddress = + environment.wrappedTokenAddresses[initialTransaction.chainId]; + + if ( + wrappedTokenAddress && + environment.equalsIgnoreCase(to, wrappedTokenAddress) + ) { + const normalizedMethodId = methodId.toLowerCase(); + const activityRaw = { + type: 'localTransaction' as const, + data: transactionGroup, + }; + + if (wrapMethodIds.has(normalizedMethodId)) { + const { value: wrapAmount } = initialTransaction.txParams; + + try { + if (wrapAmount && BigInt(wrapAmount) > 0n) { + return { + type: 'wrap', + chainId, + status, + timestamp, + raw: activityRaw, + data: { + hash, + sourceToken: getNativeToken(initialTransaction, 'out'), + destinationToken: getContractToken({ + amount: wrapAmount, + transaction: initialTransaction, + direction: 'in', + contractAddress: wrappedTokenAddress, + }), + }, + }; + } + } catch { + // Invalid native value — fall through. + } + } + + if (unwrapMethodIds.has(normalizedMethodId)) { + const { data } = initialTransaction.txParams; + let unwrapAmount: string | undefined; + + if (data && data.length >= 74) { + try { + unwrapAmount = BigInt(`0x${data.slice(10, 74)}`).toString(); + } catch { + unwrapAmount = undefined; + } + } + + const nativeToken = getNativeToken(initialTransaction, 'in'); + + return { + type: 'unwrap', + chainId, + status, + timestamp, + raw: activityRaw, + data: { + hash, + sourceToken: getContractToken({ + amount: unwrapAmount, + transaction: initialTransaction, + direction: 'out', + contractAddress: wrappedTokenAddress, + }), + destinationToken: + nativeToken && unwrapAmount + ? { ...nativeToken, amount: unwrapAmount } + : nativeToken, + }, + }; + } + } + } + + const token = (() => { + const { value } = initialTransaction.txParams; + + if (value === undefined || value === '') { + return undefined; + } + + try { + return BigInt(value) > 0n + ? getNativeToken(initialTransaction, 'out') + : undefined; + } catch { + return undefined; + } + })(); + + return { + type: 'contractInteraction', + chainId, + status, + timestamp, + raw: { type: 'localTransaction', data: transactionGroup }, + data: { + hash, + from, + to, + ...(token ? { token } : {}), + methodId, + transactionType: initialTransaction.type, + }, + }; + } + } +} diff --git a/app/util/activity-adapters/adapters/shims.ts b/app/util/activity-adapters/adapters/shims.ts new file mode 100644 index 00000000000..6a4961bd60d --- /dev/null +++ b/app/util/activity-adapters/adapters/shims.ts @@ -0,0 +1,246 @@ +/** + * Mobile shims for Extension-only constants used by the vendored adapters. + * Each shim maps to the equivalent Mobile constant or provides a minimal inline definition. + * TODO: Remove when shared @metamask/activity-adapters package is published. + */ +import { TransactionStatus } from '@metamask/transaction-controller'; +import { + KnownCaipNamespace, + toCaipChainId, + type CaipChainId, + type CaipAssetType, + isCaipAssetType, +} from '@metamask/utils'; +import { + getNativeAssetForChainId, + isNativeAddress, +} from '@metamask/bridge-controller'; +import { toChecksumHexAddress } from '@metamask/controller-utils'; +import { equalsIgnoreCase as mobileEqualsIgnoreCase } from '../../string'; +import { parseStandardTokenTransactionData as mobileParseStandardTokenTransactionData } from '../../../components/Views/confirmations/utils/transaction'; + +// --------------------------------------------------------------------------- +// Transaction status constants (Extension: shared/constants/transaction.ts) +// --------------------------------------------------------------------------- + +export const IN_PROGRESS_TRANSACTION_STATUSES = [ + TransactionStatus.unapproved, + TransactionStatus.approved, + TransactionStatus.signed, + TransactionStatus.submitted, +] as const; + +/** Matches Extension's SmartTransactionStatus enum values (lowercase). */ +export const SmartTransactionStatus = { + cancelled: 'cancelled', + pending: 'pending', + success: 'success', +} as const; + +/** Matches Extension's TransactionGroupStatus enum. */ +export const TransactionGroupStatus = { + cancelled: 'cancelled', + pending: 'pending', +} as const; + +/** Zero address used as the "native token" sentinel (matches Extension). */ +export const NATIVE_TOKEN_ADDRESS = '0x0'.padEnd(42, '0'); + +// --------------------------------------------------------------------------- +// ERC-20 Transfer log topic hash (Extension: shared/lib/transactions-controller-utils.ts) +// --------------------------------------------------------------------------- + +export const TOKEN_TRANSFER_LOG_TOPIC_HASH = + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'; + +// --------------------------------------------------------------------------- +// Small dependency shims for Extension shared utilities. +// Keep Mobile-specific imports centralized here so adapter files remain close to +// the future shared package surface. +// --------------------------------------------------------------------------- + +export const equalsIgnoreCase = mobileEqualsIgnoreCase; +export const parseStandardTokenTransactionData = + mobileParseStandardTokenTransactionData; + +// --------------------------------------------------------------------------- +// Wrapped-token addresses per EVM chain (Extension: shared/constants/swaps.ts) +// Only chains where wrap/unwrap detection is needed. +// --------------------------------------------------------------------------- + +export const SWAPS_WRAPPED_TOKENS_ADDRESSES: Record = { + '0x1': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH (mainnet) + '0x38': '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c', // WBNB (BSC) + '0x89': '0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270', // WMATIC (Polygon) + '0xa': '0x4200000000000000000000000000000000000006', // WETH (Optimism) + '0xa4b1': '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1', // WETH (Arbitrum) + '0x2105': '0x4200000000000000000000000000000000000006', // WETH (Base) + '0xe708': '0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34', // WETH (Linea) + '0xa86a': '0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7', // WAVAX (Avalanche) + '0x144': '0x5AEa5775959fBC2557Cc8789bC1bf90A239D9a91', // WETH (zkSync Era) +}; + +// --------------------------------------------------------------------------- +// Known token metadata (Extension: shared/constants/tokens.ts STATIC_MAINNET_TOKEN_LIST) +// Minimal known-token fallback used by Extension adapter tests and common +// mainnet approvals/transfers where transaction metadata omits token details. +// TODO: Replace with Mobile's TokensController/token-list data once the +// adapters move to a shared package. +// --------------------------------------------------------------------------- + +export const STATIC_MAINNET_TOKEN_LIST: Record< + string, + { symbol: string; decimals: number; assetId?: string } +> = { + '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': { + symbol: 'USDC', + decimals: 6, + assetId: 'eip155:1/erc20:0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', + }, + '0xdac17f958d2ee523a2206206994597c13d831ec7': { + symbol: 'USDT', + decimals: 6, + assetId: 'eip155:1/erc20:0xdAC17F958D2ee523a2206206994597C13D831ec7', + }, + '0x6b175474e89094c44da98b954eedeac495271d0f': { + symbol: 'DAI', + decimals: 18, + assetId: 'eip155:1/erc20:0x6B175474E89094C44Da98b954EedeAC495271d0F', + }, + '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2': { + symbol: 'WETH', + decimals: 18, + assetId: 'eip155:1/erc20:0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', + }, +}; + +// --------------------------------------------------------------------------- +// Bridge chain common token pairs (Extension: shared/constants/bridge.ts) +// Common bridge output tokens used as fallback metadata by the Extension +// adapters for approvals without value-transfer metadata. +// --------------------------------------------------------------------------- + +export const BRIDGE_CHAINID_COMMON_TOKEN_PAIR: Record< + string, + { symbol: string; decimals: number; assetId?: string } | undefined +> = { + 'eip155:1': { + symbol: 'mUSD', + decimals: 6, + assetId: 'eip155:1/erc20:0xACa92e438df0B2401fF60Da7E4337B687a2435dA', + }, + 'eip155:10': { + symbol: 'USDC', + decimals: 6, + assetId: 'eip155:10/erc20:0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', + }, + 'eip155:56': { + symbol: 'USDT', + decimals: 18, + assetId: 'eip155:56/erc20:0x55d398326f99059fF775485246999027B3197955', + }, + 'eip155:137': { + symbol: 'USDT', + decimals: 6, + assetId: 'eip155:137/erc20:0xc2132D05D31c914a87C6611C10748AEb04B58e8F', + }, + 'eip155:8453': { + symbol: 'USDC', + decimals: 6, + assetId: 'eip155:8453/erc20:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', + }, + 'eip155:42161': { + symbol: 'USDC', + decimals: 6, + assetId: 'eip155:42161/erc20:0xaf88d065e77c8cC2239327C5EDb3A432268e5831', + }, + 'eip155:43114': { + symbol: 'USDC', + decimals: 6, + assetId: 'eip155:43114/erc20:0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E', + }, + 'eip155:59144': { + symbol: 'mUSD', + decimals: 6, + assetId: 'eip155:59144/erc20:0xACa92e438df0B2401fF60Da7E4337B687a2435dA', + }, + 'eip155:324': { + symbol: 'USDT', + decimals: 6, + assetId: 'eip155:324/erc20:0x493257fD37EDB34451f62EDf8D2a0C418852bA4C', + }, +}; + +// --------------------------------------------------------------------------- +// toAssetId — simplified EVM implementation of Extension shared/lib/asset-utils.ts +// Handles the EVM ERC-20 and native-token cases used by the adapters. +// --------------------------------------------------------------------------- + +export function toAssetId( + address: string, + chainId: string | undefined, +): CaipAssetType | undefined { + if (!chainId || !address) { + return undefined; + } + + // Already CAIP-19 — pass through. + if (isCaipAssetType(address)) { + return address as CaipAssetType; + } + + // Resolve hex chainId → CAIP-2 + let caipChainId: CaipChainId; + try { + caipChainId = chainId.includes(':') + ? (chainId as CaipChainId) + : toCaipChainId( + KnownCaipNamespace.Eip155, + parseInt(chainId, 16).toString(), + ); + } catch { + return undefined; + } + + const lowerAddress = address.toLowerCase(); + + // Native token (zero address) → use bridge-controller's native asset registry. + if (isNativeAddress(lowerAddress)) { + try { + return getNativeAssetForChainId(caipChainId)?.assetId as + | CaipAssetType + | undefined; + } catch { + return undefined; + } + } + + // EVM ERC-20 (strict hex address). + if (/^0x[0-9a-f]{40}$/i.test(address)) { + const checksummed = toChecksumHexAddress(address) ?? address; + return `${caipChainId}/erc20:${checksummed}` as CaipAssetType; + } + + return undefined; +} + +// --------------------------------------------------------------------------- +// formatUnits — pure bigint implementation matching Extension shared/lib/unit.ts +// --------------------------------------------------------------------------- + +export function formatUnits(value: bigint, decimals: number): string { + let display = value.toString(); + const negative = display.startsWith('-'); + + if (negative) { + display = display.slice(1); + } + + display = display.padStart(decimals, '0'); + + const integer = display.slice(0, display.length - decimals); + const rawFraction = display.slice(display.length - decimals); + const fraction = rawFraction.replace(/(0+)$/u, ''); + + return `${negative ? '-' : ''}${integer || '0'}${fraction ? `.${fraction}` : ''}`; +} diff --git a/app/util/activity-adapters/adapters/transaction-group.ts b/app/util/activity-adapters/adapters/transaction-group.ts new file mode 100644 index 00000000000..dfb7e6b502d --- /dev/null +++ b/app/util/activity-adapters/adapters/transaction-group.ts @@ -0,0 +1,28 @@ +/** + * Mobile-specific TransactionGroup type for the local activity adapter. + * Derived from metamask-extension shared/lib/multichain/types.ts#TransactionGroup. + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ +import type { TransactionMeta } from '@metamask/transaction-controller'; +import type { Status, TokenAmount } from '../types'; + +export interface TransactionGroup { + hasCancelled?: boolean; + hasRetried?: boolean; + /** The earliest transaction in the group (determines type/category). */ + initialTransaction: TransactionMeta & { isSmartTransaction?: boolean }; + nonce?: string; + /** The most recent transaction (determines status). */ + primaryTransaction: TransactionMeta; + transactions?: TransactionMeta[]; + /** Optional status override from bridge history or other enrichment. */ + activityStatus?: Status; + /** Enriched source token (swaps, bridges, converts). */ + sourceToken?: TokenAmount; + /** Enriched destination token (swaps, bridges). */ + destinationToken?: TokenAmount; + /** Native asset ticker from NetworkController, overrides bridge-controller symbol. */ + nativeAssetSymbol?: string; + /** Token metadata from TokensController for contract interactions. */ + contractTokenMetadata?: { symbol?: string; decimals?: number }; +} diff --git a/app/util/activity-adapters/fiat.test.ts b/app/util/activity-adapters/fiat.test.ts new file mode 100644 index 00000000000..e0275f71a5e --- /dev/null +++ b/app/util/activity-adapters/fiat.test.ts @@ -0,0 +1,106 @@ +import { + applyDisplaySign, + calculateFiatFromMarketRates, + getDisplaySignPrefix, + getHumanReadableTokenAmount, + getTokenAddressForMarketRates, + type MarketRateLookupToken, + toMarketRateLookupToken, +} from './fiat'; +import { NATIVE_TOKEN_ADDRESS } from './adapters/shims'; + +const ethToken: MarketRateLookupToken = { + address: NATIVE_TOKEN_ADDRESS, + symbol: 'ETH', + decimals: 18, + chainId: '0x1', +}; + +describe('activity adapter fiat helpers', () => { + describe('calculateFiatFromMarketRates', () => { + const marketRates = { + 1: { [NATIVE_TOKEN_ADDRESS]: 2500 }, + }; + + it('returns fiat amount for a valid token and amount', () => { + expect(calculateFiatFromMarketRates('1.5', ethToken, marketRates)).toBe( + 3750, + ); + }); + + it('preserves sign for negative amounts', () => { + expect(calculateFiatFromMarketRates('-1', ethToken, marketRates)).toBe( + -2500, + ); + }); + + it('parses leading plus amounts', () => { + expect(calculateFiatFromMarketRates('+1.5', ethToken, marketRates)).toBe( + 3750, + ); + }); + + it('returns undefined when amount, token, or rate is missing', () => { + expect( + calculateFiatFromMarketRates(undefined, ethToken, marketRates), + ).toBeUndefined(); + expect(calculateFiatFromMarketRates('1', undefined, marketRates)).toBe( + undefined, + ); + expect( + calculateFiatFromMarketRates('1', ethToken, { 1: {} }), + ).toBeUndefined(); + }); + }); + + it('returns an unsigned human-readable token amount', () => { + expect( + getHumanReadableTokenAmount({ + amount: '1000000000000000000', + decimals: 18, + direction: 'out', + symbol: 'ETH', + }), + ).toBe('1'); + }); + + it('returns no prefix for incoming amounts when plus is disabled', () => { + expect(getDisplaySignPrefix('in', { showPlus: false })).toBe(''); + }); + + it('applies display signs without duplicating existing signs', () => { + expect(applyDisplaySign('$2,500.00', '+')).toBe('+$2,500.00'); + expect(applyDisplaySign('+$2,500.00', '+')).toBe('+$2,500.00'); + expect(applyDisplaySign('-$2,500.00', '+')).toBe('-$2,500.00'); + expect(applyDisplaySign('1.5 ETH', '-')).toBe('-1.5 ETH'); + expect(applyDisplaySign('-$2,500.00', '-')).toBe('-$2,500.00'); + expect(applyDisplaySign('+$2,500.00', '-')).toBe('+$2,500.00'); + expect(applyDisplaySign('1.5 ETH', '')).toBe('1.5 ETH'); + }); + + it('maps CAIP asset ids to market-rate token addresses', () => { + expect(getTokenAddressForMarketRates('eip155:1/slip44:60')).toBe( + NATIVE_TOKEN_ADDRESS, + ); + expect( + getTokenAddressForMarketRates( + 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + ), + ).toBe('0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'); + }); + + it('builds a market-rate lookup token from an activity token amount', () => { + expect( + toMarketRateLookupToken( + { + amount: '1', + decimals: 18, + direction: 'out', + symbol: 'ETH', + assetId: 'eip155:1/slip44:60', + }, + '0x1', + ), + ).toStrictEqual(ethToken); + }); +}); diff --git a/app/util/activity-adapters/fiat.ts b/app/util/activity-adapters/fiat.ts new file mode 100644 index 00000000000..fd394d73203 --- /dev/null +++ b/app/util/activity-adapters/fiat.ts @@ -0,0 +1,143 @@ +/* + * Vendored from metamask-extension shared/lib/activity/fiat.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + * + * Extension imports replaced with Mobile equivalents: + * - shared/lib/unit#formatUnits → shims#formatUnits (inline pure bigint impl) + * - shared/constants/transaction#NATIVE_TOKEN_ADDRESS → shims + */ +import { + isCaipAssetType, + parseCaipAssetType, + type CaipAssetType, + type Hex, +} from '@metamask/utils'; +import { NATIVE_TOKEN_ADDRESS, formatUnits } from './adapters/shims'; +import type { TokenAmount } from './types'; + +/** Minimal token descriptor used for market-rate lookups. */ +export interface MarketRateLookupToken { + address: string; + symbol: string; + decimals: number; + chainId: Hex; +} + +export function calculateFiatFromMarketRates( + amount: string | undefined, + token: MarketRateLookupToken | undefined, + marketRates: Record>, +) { + if (amount === undefined || !token) { + return undefined; + } + + const parsed = Number.parseFloat(amount); + const rate = marketRates[Number.parseInt(token.chainId, 16)]?.[token.address]; + return rate === undefined ? undefined : parsed * rate; +} + +export function getDisplaySignPrefix( + direction: TokenAmount['direction'], + { showPlus }: { showPlus: boolean }, +): string { + if (direction === 'out') { + return '-'; + } + + if (direction === 'in' && showPlus) { + return '+'; + } + + return ''; +} + +// Converts TokenAmount to unsigned human-readable numeric string (e.g. "1", "1.5") +export function getHumanReadableTokenAmount( + token: TokenAmount, +): string | undefined { + if (!token.amount) { + return undefined; + } + + let value: string; + try { + value = formatUnits(BigInt(token.amount), token.decimals ?? 0); + } catch { + value = token.amount; + } + + return value.startsWith('-') ? value.slice(1) : value; +} + +// Applies display + or - sign to a formatted display value +export function applyDisplaySign( + formattedDisplay: string, + signPrefix: string, +): string { + if ( + signPrefix === '+' && + !formattedDisplay.startsWith('+') && + !formattedDisplay.startsWith('-') + ) { + return `+${formattedDisplay}`; + } + + if ( + signPrefix === '-' && + !formattedDisplay.startsWith('-') && + !formattedDisplay.startsWith('+') + ) { + return `-${formattedDisplay}`; + } + + return formattedDisplay; +} + +export function getTokenAddressForMarketRates( + assetId: CaipAssetType | undefined, +): string | undefined { + if (!assetId) { + return undefined; + } + + if (assetId.includes('/slip44:') || assetId.includes('/native:')) { + return NATIVE_TOKEN_ADDRESS; + } + + try { + const { assetNamespace, assetReference } = parseCaipAssetType(assetId); + + if (assetNamespace === 'erc20' && typeof assetReference === 'string') { + return assetReference.toLowerCase(); + } + + if (assetNamespace === 'slip44' || assetNamespace === 'native') { + return NATIVE_TOKEN_ADDRESS; + } + } catch { + return undefined; + } + + return undefined; +} + +export function toMarketRateLookupToken( + token: TokenAmount, + hexChainId: Hex, +): MarketRateLookupToken | undefined { + const assetId = isCaipAssetType(token.assetId) ? token.assetId : undefined; + const address = getTokenAddressForMarketRates(assetId); + + if (!address) { + return undefined; + } + + return { + address, + symbol: token.symbol ?? '', + decimals: token.decimals ?? 0, + chainId: hexChainId, + }; +} diff --git a/app/util/activity-adapters/index.ts b/app/util/activity-adapters/index.ts new file mode 100644 index 00000000000..b2efcbfbd54 --- /dev/null +++ b/app/util/activity-adapters/index.ts @@ -0,0 +1,33 @@ +/** + * Vendored Activity adapters from metamask-extension shared/lib/activity/ + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ +export type { + ActivityListItem, + ActivityKind, + Status, + TokenAmount, +} from './types'; +export { mapApiEvmTransactions } from './adapters/api-evm-transactions'; +export { mapKeyringTransaction } from './adapters/keyring-transaction'; +export { mapLocalTransaction } from './adapters/local-transaction'; +export { + mobileActivityAdapterEnvironment, + type ActivityAdapterEnvironment, +} from './adapters/environment'; +export type { TransactionGroup } from './adapters/transaction-group'; +export { getLabelKeys } from './label-keys'; +export { + calculateFiatFromMarketRates, + getHumanReadableTokenAmount, + getDisplaySignPrefix, + applyDisplaySign, + toMarketRateLookupToken, +} from './fiat'; +export { + activityMatchesAssetId, + groupActivityListItems, + shouldShowPlusSign, + type GroupedActivityListItem, +} from './activity-list-helpers'; diff --git a/app/util/activity-adapters/label-keys.test.ts b/app/util/activity-adapters/label-keys.test.ts new file mode 100644 index 00000000000..017acc0d9cd --- /dev/null +++ b/app/util/activity-adapters/label-keys.test.ts @@ -0,0 +1,19 @@ +import { getLabelKeys } from './label-keys'; + +describe('getLabelKeys', () => { + it('returns title and description keys', () => { + expect( + getLabelKeys({ + type: 'swap', + status: 'pending', + }), + ).toStrictEqual({ + title: { + key: 'activity_swap_pending_title', + }, + description: { + key: 'activity_swap_pending_description', + }, + }); + }); +}); diff --git a/app/util/activity-adapters/label-keys.ts b/app/util/activity-adapters/label-keys.ts new file mode 100644 index 00000000000..3727af2f1bd --- /dev/null +++ b/app/util/activity-adapters/label-keys.ts @@ -0,0 +1,27 @@ +/** + * Vendored from metamask-extension shared/lib/activity/label-keys.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ +import type { ActivityKind, Status } from './types'; + +const fallbackLabelKey = 'activity_fallback'; + +export function getLabelKeys({ + type, + status, +}: { + type: ActivityKind; + status: Status; +}) { + const key = type && status ? `activity_${type}_${status}` : fallbackLabelKey; + + return { + title: { + key: `${key}_title`, + }, + description: { + key: `${key}_description`, + }, + }; +} diff --git a/app/util/activity-adapters/types.ts b/app/util/activity-adapters/types.ts new file mode 100644 index 00000000000..00efeb619d5 --- /dev/null +++ b/app/util/activity-adapters/types.ts @@ -0,0 +1,189 @@ +/** + * Vendored from metamask-extension shared/lib/activity/types.ts + * Branch: origin/n3ps/activity-v3-prototype + * TODO: Replace with shared @metamask/activity-adapters package when published. + */ +import type { Transaction } from '@metamask/keyring-api'; +import type { V1TransactionByHashResponse } from '@metamask/core-backend'; +import type { CaipChainId } from '@metamask/utils'; +import type { TransactionGroup } from './adapters/transaction-group'; + +export type Status = 'pending' | 'success' | 'failed' | 'cancelled'; + +export type ActivityKind = + | 'receive' + | 'sell' + | 'buy' + | 'deposit' + | 'swap' + | 'swapIncomplete' + | 'claim' + | 'claimMusdBonus' + | 'send' + | 'wrap' + | 'unwrap' + | 'approveSpendingCap' + | 'revokeSpendingCap' + | 'increaseSpendingCap' + | 'contractInteraction' + | 'contractDeployment' + | 'bridge' + | 'convert' + | 'smartAccountUpgrade' + | 'lendingDeposit' + | 'lendingWithdrawal' + | 'predictionsAddFunds' + | 'predictionsWithdrawFunds' + | 'predictionClaimWinnings' + | 'predictionCashedOut' + | 'predictionPlaced' + | 'perpsAddFunds' + | 'perpsWithdrawFunds' + | 'perpsOpenLong' + | 'perpsCloseLong' + | 'perpsCloseLongLiquidated' + | 'perpsCloseLongStopLoss' + | 'perpsOpenShort' + | 'perpsCloseShort' + | 'perpsCloseShortLiquidated' + | 'perpsCloseShortStopLoss' + | 'perpsPaidFundingFees' + | 'perpsReceivedFundingFees' + | 'perpsCloseShortTakeProfit' + | 'perpsCloseLongTakeProfit' + | 'marketShort' + | 'stopMarketCloseShort' + | 'marketCloseShort' + | 'nftMint'; + +export interface TokenAmount { + amount?: string; + decimals?: number; + symbol?: string; + // CAIP-19 asset id (from adapters) + assetId?: string; + direction: 'in' | 'out'; +} + +interface ActivityData { + type: Type; + chainId: CaipChainId; + status: Status; + timestamp: number; + isEarliestNonce?: boolean; + /* Used by legacy details modals. Interim until redesigned details are implemented */ + raw?: + | { type: 'apiEvmTransaction'; data: V1TransactionByHashResponse } + | { type: 'keyringTransaction'; data: Transaction } + | { type: 'localTransaction'; data: TransactionGroup }; + data: Data & { + hash?: string; + }; +} + +export type ActivityListItem = + | ActivityData< + 'send' | 'receive', + { + from: string; + to: string; + token?: TokenAmount; + } + > + | ActivityData< + | 'swap' + | 'convert' + | 'lendingDeposit' + | 'lendingWithdrawal' + | 'wrap' + | 'unwrap', + { + sourceToken?: TokenAmount; + destinationToken?: TokenAmount; + } + > + | ActivityData< + 'swapIncomplete', + { + sourceToken?: TokenAmount; + } + > + | ActivityData< + 'bridge', + { + sourceToken?: TokenAmount; + destinationToken?: TokenAmount; + } + > + | ActivityData< + 'buy' | 'claim' | 'deposit', + { + token?: TokenAmount; + } + > + | ActivityData< + 'claimMusdBonus', + { + token?: TokenAmount; + } + > + | ActivityData< + 'approveSpendingCap' | 'revokeSpendingCap' | 'increaseSpendingCap', + { + token?: TokenAmount; + } + > + | ActivityData< + 'nftMint', + { + from: string; + to: string; + token?: TokenAmount; + } + > + | ActivityData< + 'contractInteraction', + { + from: string; + to: string; + token?: TokenAmount; + methodId?: string; + transactionCategory?: string; + transactionProtocol?: string; + transactionType?: string; + } + > + | ActivityData< + | 'sell' + | 'contractDeployment' + | 'smartAccountUpgrade' + | 'predictionsAddFunds' + | 'predictionsWithdrawFunds' + | 'predictionClaimWinnings' + | 'predictionCashedOut' + | 'predictionPlaced' + | 'perpsAddFunds' + | 'perpsWithdrawFunds' + | 'perpsOpenLong' + | 'perpsCloseLong' + | 'perpsCloseLongLiquidated' + | 'perpsCloseLongStopLoss' + | 'perpsOpenShort' + | 'perpsCloseShort' + | 'perpsCloseShortLiquidated' + | 'perpsCloseShortStopLoss' + | 'perpsPaidFundingFees' + | 'perpsReceivedFundingFees' + | 'perpsCloseShortTakeProfit' + | 'perpsCloseLongTakeProfit' + | 'marketShort' + | 'stopMarketCloseShort' + | 'marketCloseShort', + { + from?: string; + to?: string; + token?: TokenAmount; + sourceToken?: TokenAmount; + destinationToken?: TokenAmount; + } + >; diff --git a/app/util/test/testSetupView.js b/app/util/test/testSetupView.js index b84b4be6409..ab31f27bff9 100644 --- a/app/util/test/testSetupView.js +++ b/app/util/test/testSetupView.js @@ -114,6 +114,35 @@ jest.mock('expo/fetch', () => ({ fetch, })); +// @metamask/perps-controller no longer exports MarketCategory / MARKET_CATEGORIES on +// this branch, but Perps UI (pulled in via TransactionElement → Balance) still reads +// them at module load. Stub the enum so component-view tests can import Activity views. +jest.mock('@metamask/perps-controller', () => { + const actual = jest.requireActual('@metamask/perps-controller'); + + return { + ...actual, + MarketCategory: { + CryptoCurrency: 'crypto', + Stock: 'stock', + PreIpo: 'pre-ipo', + Index: 'index', + Etf: 'etf', + Forex: 'forex', + Commodity: 'commodity', + }, + MARKET_CATEGORIES: [ + 'crypto', + 'stock', + 'pre-ipo', + 'forex', + 'commodity', + 'index', + 'etf', + ], + }; +}); + // Reanimated setup is usually required for navigation/animations try { require('react-native-reanimated').setUpTests(); diff --git a/locales/languages/en.json b/locales/languages/en.json index 1ee08df66ca..58885e94cc7 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -3017,7 +3017,64 @@ "disclaimer": "Disclaimer: MetaMask pulls the media file from the source URL. This URL is sometimes changed by the marketplace the NFT was minted on." }, "activity_view": { - "title": "Activity" + "title": "Activity", + "search_placeholder": "Search tokens, transaction types...", + "filter_all_networks": "All networks", + "filter_all_types": "All types", + "filter_types_selected": "Types: {{label}}", + "filter_network_selected": "Network: {{label}}", + "type_filter": { + "title": "Types", + "all": "All types", + "transactions": "Transactions", + "buy_sell": "Buy/Sell", + "perps": "Perps", + "predictions": "Predictions", + "metamask_card": "MetaMask Card", + "money": "Money" + }, + "empty_state": { + "default_funded": { + "description": "Nothing to see yet. Swap your first token today.", + "action": "Swap tokens" + }, + "default_unfunded": { + "description": "Nothing to see yet. Add funds to your wallet to get started.", + "action": "Add funds" + }, + "predictions": { + "description": "Your first prediction could be your best.", + "action": "Make a prediction" + }, + "perps": { + "description": "Your first perps trade could be your best.", + "action": "Browse markets" + }, + "transactions_funded": { + "description": "Swap your first token today.", + "action": "Swap tokens" + }, + "transactions_unfunded": { + "description": "Add funds to your wallet to get started.", + "action": "Add funds" + }, + "buy_sell": { + "description": "Add funds to your wallet to get started.", + "action": "Add funds" + }, + "money_funded": { + "description": "You've got funds—put them to work in MetaMask Money.", + "action": "Transfer funds" + }, + "money_unfunded": { + "description": "Transfer to MetaMask Money and unlock all it has to offer.", + "action": "Transfer funds" + }, + "metamask_card": { + "description": "Manage your MetaMask Card and spend crypto anywhere.", + "action": "Open MetaMask Card" + } + } }, "transactions_view": { "title": "Transactions" @@ -4656,6 +4713,31 @@ "tx_review_predict_withdraw": "Predictions withdraw", "tx_review_perps_withdraw": "Perps withdraw", "tx_review_musd_conversion": "mUSD conversion", + "activity_buy": "Bought", + "activity_sell": "Sold", + "activity_claim_musd_bonus": "Claimed mUSD bonus", + "activity_wrap": "Wrapped", + "activity_unwrap": "Unwrapped", + "activity_revoke_spending_cap": "Revoked spending cap", + "activity_nft_mint": "NFT mint", + "activity_smart_account_upgrade": "Smart account upgrade", + "activity_prediction_cashed_out": "Prediction cashed out", + "activity_prediction_placed": "Prediction placed", + "activity_perps_open_long": "Opened long", + "activity_perps_close_long": "Closed long", + "activity_perps_close_long_liquidated": "Closed long - liquidated", + "activity_perps_close_long_stop_loss": "Closed long - stop loss", + "activity_perps_open_short": "Opened short", + "activity_perps_close_short": "Closed short", + "activity_perps_close_short_liquidated": "Closed short - liquidated", + "activity_perps_close_short_stop_loss": "Closed short - stop loss", + "activity_perps_paid_funding_fees": "Paid funding fees", + "activity_perps_received_funding_fees": "Received funding fees", + "activity_perps_close_short_take_profit": "Closed short - take profit", + "activity_perps_close_long_take_profit": "Closed long - take profit", + "activity_market_short": "Market short", + "activity_stop_market_close_short": "Stop market - close short", + "activity_market_close_short": "Market - close short", "claim": "Claim", "sent_ether": "Sent ETH", "self_sent_ether": "Sent yourself ETH", diff --git a/tests/component-view/mocks.ts b/tests/component-view/mocks.ts index 0cfc00a1b27..38e8ba4f931 100644 --- a/tests/component-view/mocks.ts +++ b/tests/component-view/mocks.ts @@ -268,6 +268,7 @@ jest.mock('../../app/core/Engine', () => { addTransaction: jest.fn().mockResolvedValue({}), getTransactions: jest.fn().mockReturnValue([]), updateEditableParams: jest.fn(), + updateIncomingTransactions: jest.fn().mockResolvedValue(undefined), getNonceLock: jest .fn() .mockResolvedValue({ nextNonce: 0, releaseLock: jest.fn() }), diff --git a/tests/component-view/presets/activity.ts b/tests/component-view/presets/activity.ts new file mode 100644 index 00000000000..3da38adc92b --- /dev/null +++ b/tests/component-view/presets/activity.ts @@ -0,0 +1,143 @@ +import { + TransactionStatus, + TransactionType, + type TransactionMeta, +} from '@metamask/transaction-controller'; +import { createStateFixture } from '../stateFixture'; +import type { DeepPartial } from '../../../app/util/test/renderWithProvider'; +import type { RootState } from '../../../app/reducers'; + +export const ACTIVITY_CV_ACCOUNT = '0x0000000000000000000000000000000000000001'; + +const ACTIVITY_CV_RECIPIENT = '0x80181d3ba89220cdb80234fc7aa19d5cc56229cc'; + +export const buildConfirmedLocalSendTransaction = (): TransactionMeta => + ({ + id: 'activity-cv-confirmed-send', + hash: '0xactivitycvconfirmedsend', + chainId: '0x1', + status: TransactionStatus.confirmed, + time: 1_716_367_781_000, + type: TransactionType.simpleSend, + txParams: { + from: ACTIVITY_CV_ACCOUNT, + to: ACTIVITY_CV_RECIPIENT, + value: '0xde0b6b3a7640000', + nonce: '0x0', + }, + txReceipt: { status: '0x1' }, + }) as unknown as TransactionMeta; + +export const buildPendingLocalSendTransaction = (): TransactionMeta => + ({ + id: 'activity-cv-pending-send', + hash: '0xactivitycvpendingsend', + chainId: '0x1', + status: TransactionStatus.submitted, + time: 1_716_367_782_000, + type: TransactionType.simpleSend, + txParams: { + from: ACTIVITY_CV_ACCOUNT, + to: ACTIVITY_CV_RECIPIENT, + value: '0xde0b6b3a7640000', + nonce: '0x1', + }, + }) as unknown as TransactionMeta; + +const enabledMainnetNetworkMap = { + eip155: { + '0x1': true, + }, + solana: {}, +} as const; + +/** + * Minimal Activity state. EVM networks are intentionally disabled by default so + * ActivityList renders through Redux without kicking off the external tx API. + */ +export const initialStateActivity = () => + createStateFixture() + .withMinimalAccounts(ACTIVITY_CV_ACCOUNT) + .withMinimalMainnetNetwork() + .withMinimalMultichainNetwork(true) + .withMinimalTransactionController() + .withMinimalKeyringController() + .withMinimalBridgeController() + .withMinimalTokenRates() + .withMinimalMultichainTransactions() + .withAccountTreeForSelectedAccount() + .withRemoteFeatureFlags({}) + .withOverrides({ + settings: { + showFiatOnTestnets: true, + }, + engine: { + backgroundState: { + AccountTrackerController: { + accounts: {}, + accountsByChainId: {}, + }, + CurrencyRateController: { + currentCurrency: 'USD', + currencyRates: { + ETH: { + conversionRate: 2500, + usdConversionRate: 2500, + }, + }, + }, + GasFeeController: { + gasFeeEstimates: {}, + }, + NetworkEnablementController: { + enabledNetworkMap: { + eip155: {}, + solana: {}, + }, + }, + PreferencesController: { + showTestNetworks: false, + tokenNetworkFilter: {}, + }, + SmartTransactionsController: { + smartTransactionsState: { + smartTransactions: {}, + }, + }, + TokenBalancesController: { + tokenBalances: {}, + }, + TokensController: { + allTokens: { + '0x1': { + [ACTIVITY_CV_ACCOUNT]: [], + }, + }, + allDetectedTokens: {}, + allIgnoredTokens: {}, + }, + }, + }, + } as unknown as DeepPartial); + +export const initialStateActivityWithLocalTransactions = ( + transactions: TransactionMeta[], +) => + initialStateActivity().withOverrides({ + engine: { + backgroundState: { + NetworkEnablementController: { + enabledNetworkMap: enabledMainnetNetworkMap, + }, + TransactionController: { + transactions, + swapsTransactions: {}, + }, + }, + }, + } as unknown as DeepPartial); + +export const initialStateActivityWithRedesignEnabled = () => + initialStateActivity().withRemoteFeatureFlags({ + tmcuActivityRedesignEnabled: true, + }); diff --git a/tests/component-view/renderers/activity.ts b/tests/component-view/renderers/activity.ts new file mode 100644 index 00000000000..e9022a94439 --- /dev/null +++ b/tests/component-view/renderers/activity.ts @@ -0,0 +1,168 @@ +import '../mocks'; +import React from 'react'; +import type { DeepPartial } from '../../../app/util/test/renderWithProvider'; +import type { RootState } from '../../../app/reducers'; +import Routes from '../../../app/constants/navigation/Routes'; +import ActivityScreen from '../../../app/components/Views/ActivityScreen/ActivityScreen'; +import ActivityList from '../../../app/components/Views/ActivityList'; +import ActivityView from '../../../app/components/Views/ActivityView'; +import { HardwareWalletProvider } from '../../../app/core/HardwareWallet/HardwareWalletProvider'; +import { renderComponentViewScreen, renderScreenWithRoutes } from '../render'; +import { + initialStateActivity, + initialStateActivityWithRedesignEnabled, +} from '../presets/activity'; + +interface RenderActivityScreenViewOptions { + overrides?: DeepPartial; + state?: DeepPartial; +} + +interface RenderActivityScreenViewWithRoutesOptions + extends RenderActivityScreenViewOptions { + extraRoutes: { name: string; Component?: React.ComponentType }[]; +} + +interface RenderActivityListViewOptions { + overrides?: DeepPartial; + state?: DeepPartial; +} + +interface RenderActivityListViewWithRoutesOptions + extends RenderActivityListViewOptions { + extraRoutes: { name: string; Component?: React.ComponentType }[]; +} + +interface RenderActivityViewOptions { + overrides?: DeepPartial; + redesignEnabled?: boolean; +} + +interface RenderActivityViewWithRoutesOptions + extends RenderActivityViewOptions { + extraRoutes: { name: string; Component?: React.ComponentType }[]; +} + +function ActivityViewWithProviders() { + return React.createElement( + HardwareWalletProvider, + null, + React.createElement(ActivityView as unknown as React.ComponentType), + ); +} + +function ActivityScreenWithProviders() { + return React.createElement( + HardwareWalletProvider, + null, + React.createElement(ActivityScreen), + ); +} + +function ActivityListWithProviders() { + return React.createElement( + HardwareWalletProvider, + null, + React.createElement(ActivityList), + ); +} + +function buildActivityState(options: { + overrides?: DeepPartial; + state?: DeepPartial; + redesignEnabled?: boolean; +}) { + if (options.state) { + return options.state; + } + + const builder = options.redesignEnabled + ? initialStateActivityWithRedesignEnabled() + : initialStateActivity(); + if (options.overrides) { + builder.withOverrides(options.overrides); + } + + return builder.build(); +} + +export function renderActivityScreenView( + options: RenderActivityScreenViewOptions = {}, +): ReturnType { + const state = buildActivityState(options); + + return renderComponentViewScreen( + ActivityScreenWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + { state }, + ); +} + +export function renderActivityScreenViewWithRoutes( + options: RenderActivityScreenViewWithRoutesOptions, +): ReturnType { + const state = buildActivityState(options); + + return renderScreenWithRoutes( + ActivityScreenWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + options.extraRoutes, + { state }, + ); +} + +export function renderActivityListView( + options: RenderActivityListViewOptions = {}, +): ReturnType { + const state = buildActivityState(options); + + return renderComponentViewScreen( + ActivityListWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + { state }, + ); +} + +export function renderActivityListViewWithRoutes( + options: RenderActivityListViewWithRoutesOptions, +): ReturnType { + const state = buildActivityState(options); + + return renderScreenWithRoutes( + ActivityListWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + options.extraRoutes, + { state }, + ); +} + +export function renderActivityView( + options: RenderActivityViewOptions = {}, +): ReturnType { + const state = buildActivityState({ + overrides: options.overrides, + redesignEnabled: options.redesignEnabled, + }); + + return renderComponentViewScreen( + ActivityViewWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + { state }, + ); +} + +export function renderActivityViewWithRoutes( + options: RenderActivityViewWithRoutesOptions, +): ReturnType { + const state = buildActivityState({ + overrides: options.overrides, + redesignEnabled: options.redesignEnabled, + }); + + return renderScreenWithRoutes( + ActivityViewWithProviders, + { name: Routes.TRANSACTIONS_VIEW }, + options.extraRoutes, + { state }, + ); +} diff --git a/tests/feature-flags/feature-flag-registry.ts b/tests/feature-flags/feature-flag-registry.ts index 05d5aa50cdb..9d1a643e0c4 100644 --- a/tests/feature-flags/feature-flag-registry.ts +++ b/tests/feature-flags/feature-flag-registry.ts @@ -4347,6 +4347,14 @@ export const FEATURE_FLAG_REGISTRY: Record = { status: FeatureFlagStatus.Active, }, + tmcuActivityRedesignEnabled: { + name: 'tmcuActivityRedesignEnabled', + type: FeatureFlagType.Remote, + inProd: false, + productionDefault: false, + status: FeatureFlagStatus.Active, + }, + trendingTokens: { name: 'trendingTokens', type: FeatureFlagType.Remote, From 11a6eb0a653f8d96f17b21336fe5867f3ed9d79d Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Tue, 16 Jun 2026 16:59:11 +0200 Subject: [PATCH 08/23] fix(money): design review polishes (MUSD-993) (#31813) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Addresses the design-review polishes for the Money account screens (MUSD-993): 1. **Add funds sheet** — renamed the fiat row to **Debit card or Apple Pay** (Card icon) and added a coming-soon **Bank account** row, matching the design. The Debit card or Apple Pay row is always active and opens the MM Pay deposit flow. 2. **APY tooltip** — updated the variability copy (Veda / Steakhouse Financial) and added "Money account is powered by Monad." 3. **How it works FAQ** — the supported no-fee deposit tokens are now derived from the `earnMoneyDepositNoFeeTokens` remote flag (with a bundled per-chain fallback so the list is never empty) instead of a hard-coded list. Chain ids resolve to friendly network names; mUSD shows in the per-chain "which tokens can I deposit" list but is excluded from the inline "converts to mUSD" sentence. 4. **Yield FAQ** — appended the APY-variability / Veda–Steakhouse disclaimer. 5. **Deposit FAQ** — limited the funding-methods sentence to "debit card, credit card, or Apple Pay". 6. **Money home layout** — the "Add funds" CTA now renders once at the bottom (previously a misplaced mid-list instance in the empty state), and a divider separates every content section. 7. **What you get** — "Send" instead of "Transfer". ## **Changelog** CHANGELOG entry: Polished the Money account screens — refreshed the Add funds payment options, APY and FAQ copy, made the supported-token list dynamic, and fixed the home layout spacing and Add funds button placement. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-993 ## **Manual testing steps** ```gherkin Feature: Money account design review polishes Scenario: Add funds sheet payment options Given I am on the Money account home screen When I tap "Add" Then I see "Convert crypto", "Debit card or Apple Pay", the mUSD amount, "Bank account" (Coming soon) and "External address" (Coming soon) And tapping "Debit card or Apple Pay" opens the MM Pay deposit flow Scenario: How it works FAQ tokens are dynamic Given I open the "How it works" page When I expand "Which tokens can I deposit into the Money Account?" Then the per-chain token list reflects the no-fee remote config with friendly network names Scenario: Money home layout Given I am on the Money account home screen Then the "Add funds" button appears once at the bottom And each content section is separated by a divider ``` ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/663f7d86-1858-4384-809c-1bae4111f24e image image image image _Screenshots to be attached during review — UI polish; reference designs are in the Figma links on the MUSD-993 ticket._ ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. --- .../Views/MoneyHomeView/MoneyHomeView.tsx | 265 ++++++++++-------- .../MoneyHowItWorksView.tsx | 13 + ...yAddMoneySheet.pendingTransaction.test.tsx | 5 - .../MoneyAddMoneySheet.test.tsx | 63 ++--- .../MoneyAddMoneySheet.testIds.ts | 1 + .../MoneyAddMoneySheet/MoneyAddMoneySheet.tsx | 13 +- .../MoneyApyInfoSheet.test.tsx | 14 + .../MoneyApyInfoSheet/MoneyApyInfoSheet.tsx | 3 + .../MoneyWhatYouGet/MoneyWhatYouGet.test.tsx | 2 +- .../UI/Money/utils/depositFaqTokens.test.ts | 72 +++++ .../UI/Money/utils/depositFaqTokens.ts | 84 ++++++ locales/languages/en.json | 14 +- 12 files changed, 378 insertions(+), 171 deletions(-) create mode 100644 app/components/UI/Money/utils/depositFaqTokens.test.ts create mode 100644 app/components/UI/Money/utils/depositFaqTokens.ts diff --git a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx index d23fd9dcc8e..366f37823bc 100644 --- a/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx +++ b/app/components/UI/Money/Views/MoneyHomeView/MoneyHomeView.tsx @@ -83,7 +83,7 @@ import { } from '../../constants/moneyEvents'; import { TransactionMeta } from '@metamask/transaction-controller'; -const Divider = () => ; +const Divider = () => ; const ACTION_BUTTON_ROW_BUTTON_COUNT = 3; @@ -602,6 +602,147 @@ const MoneyHomeView = () => { const isCardAnalyticsReady = cardHomeDataStatus === 'success' || cardHomeDataStatus === 'error'; + const contentSections: { key: string; node: React.ReactNode }[] = []; + + if (hasBalanceValue && isFunded) { + contentSections.push({ + key: 'earnings', + node: ( + + ), + }); + } + + if (isEmptyState) { + contentSections.push({ + key: 'how-it-works', + node: ( + + handleHowItWorksPress({ + componentName: COMPONENT_NAMES.MONEY_HOW_IT_WORKS_SECTION_HEADER, + }) + } + isLoading={vaultApyQuery.isLoading} + /> + ), + }); + contentSections.push({ + key: 'musd-row', + node: ( + + handleMusdRowPress({ + componentName: COMPONENT_NAMES.MONEY_MUSD_TOKEN_SECTION, + }) + } + onAddPress={handleMusdRowAddPress} + balance={musdFiatFormatted} + /> + ), + }); + } + + if (showCardActivityLoading || activityItems.length >= 1) { + contentSections.push({ + key: 'activity', + node: showCardActivityLoading ? ( + + ) : ( + + ), + }); + } + + if (depositTokens.length > 0) { + contentSections.push({ + key: 'potential-earnings', + node: ( + + ), + }); + } + + if (metamaskCardMode) { + contentSections.push({ + key: 'metamask-card', + node: ( + + ), + }); + } + + if (isFunded) { + contentSections.push({ + key: 'condensed-info', + node: ( + + handleHowItWorksPress({ + componentName: + COMPONENT_NAMES.MONEY_CONDENSED_INFO_CARDS_HOW_IT_WORKS, + }) + } + onMusdPress={() => + handleMusdRowPress({ + componentName: COMPONENT_NAMES.MONEY_CONDENSED_INFO_CARDS_MUSD, + }) + } + onWhatYouGetPress={handleWhatYouGetPress} + /> + ), + }); + } + + if (isEmptyState) { + contentSections.push({ + key: 'what-you-get', + node: ( + + ), + }); + } + return ( { card={{ onPress: handleActionButtonCardPress }} /> - {hasBalanceValue && isFunded && ( - <> - - - - )} - {isEmptyState && ( - <> - - handleHowItWorksPress({ - componentName: - COMPONENT_NAMES.MONEY_HOW_IT_WORKS_SECTION_HEADER, - }) - } - isLoading={vaultApyQuery.isLoading} - /> - - handleMusdRowPress({ - componentName: COMPONENT_NAMES.MONEY_MUSD_TOKEN_SECTION, - }) - } - onAddPress={handleMusdRowAddPress} - balance={musdFiatFormatted} - /> - - - )} - {(showCardActivityLoading || activityItems.length >= 1) && ( - <> - {showCardActivityLoading ? ( - - ) : ( - - )} - - - )} - {depositTokens.length > 0 && ( - <> - - - - )} - {metamaskCardMode && ( - <> - - - - )} - {isFunded && ( - - handleHowItWorksPress({ - componentName: - COMPONENT_NAMES.MONEY_CONDENSED_INFO_CARDS_HOW_IT_WORKS, - }) - } - onMusdPress={() => - handleMusdRowPress({ - componentName: COMPONENT_NAMES.MONEY_CONDENSED_INFO_CARDS_MUSD, - }) - } - onWhatYouGetPress={handleWhatYouGetPress} - /> - )} - {isEmptyState && ( - - )} - {!isEmptyState && ( - - )} + {contentSections.map((section, index) => ( + + {index > 0 && } + {section.node} + + ))} + ); diff --git a/app/components/UI/Money/Views/MoneyHowItWorksView/MoneyHowItWorksView.tsx b/app/components/UI/Money/Views/MoneyHowItWorksView/MoneyHowItWorksView.tsx index 0c71e1b66f3..a1447fd167c 100644 --- a/app/components/UI/Money/Views/MoneyHowItWorksView/MoneyHowItWorksView.tsx +++ b/app/components/UI/Money/Views/MoneyHowItWorksView/MoneyHowItWorksView.tsx @@ -24,9 +24,16 @@ import Animated, { withTiming, Easing, } from 'react-native-reanimated'; +import { useSelector } from 'react-redux'; import { strings } from '../../../../../../locales/i18n'; import { useTheme } from '../../../../../util/theme'; import useMoneyAccountBalance from '../../hooks/useMoneyAccountBalance'; +import { selectMoneyNoFeeTokens } from '../../selectors/featureFlags'; +import { + resolveNoFeeTokens, + formatNoFeeTokenBullets, + formatBaseStablecoins, +} from '../../utils/depositFaqTokens'; import { MoneyHowItWorksViewTestIds } from './MoneyHowItWorksView.testIds'; import useMountEffect from '../../hooks/useMountEffect'; import { COMPONENT_NAMES, SCREEN_NAMES } from '../../constants/moneyEvents'; @@ -126,6 +133,10 @@ const MoneyHowItWorksView = () => { const { apyPercent } = useMoneyAccountBalance(); const percentage = apyPercent ?? FALLBACK_APY; + const noFeeTokens = resolveNoFeeTokens(useSelector(selectMoneyNoFeeTokens)); + const tokenBullets = formatNoFeeTokenBullets(noFeeTokens); + const stablecoins = formatBaseStablecoins(noFeeTokens); + const { trackScreenViewed } = useMoneyAnalytics({ screen_name: SCREEN_NAMES.MONEY_HOW_IT_WORKS, }); @@ -224,6 +235,8 @@ const MoneyHowItWorksView = () => { })} answer={strings(`money.how_it_works_page.faq_a${index + 1}`, { percentage, + tokenBullets, + stablecoins, })} testID={MoneyHowItWorksViewTestIds.FAQ_ITEM(index + 1)} /> diff --git a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.pendingTransaction.test.tsx b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.pendingTransaction.test.tsx index b20f277d254..b859047ca13 100644 --- a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.pendingTransaction.test.tsx +++ b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.pendingTransaction.test.tsx @@ -15,7 +15,6 @@ import { addTransactionBatch } from '../../../../../util/transaction-controller' import { useMusdBalance } from '../../../Earn/hooks/useMusdBalance'; import { useMMPayFiatConfig } from '../../../../Views/confirmations/hooks/pay/useMMPayFiatConfig'; import { selectHasAnyNonZeroTokenBalance } from '../../../../../selectors/tokenBalancesController'; -import { useHasNativeFiatProvider } from '../../../Ramp/hooks/useHasNativeFiatProvider'; import { useMoneyAnalytics } from '../../hooks/useMoneyAnalytics'; const PENDING_TX_ID = 'pending-tx-from-elsewhere'; @@ -154,9 +153,6 @@ jest.mock('../../../../../selectors/tokenBalancesController', () => ({ ...jest.requireActual('../../../../../selectors/tokenBalancesController'), selectHasAnyNonZeroTokenBalance: jest.fn(), })); -jest.mock('../../../Ramp/hooks/useHasNativeFiatProvider', () => ({ - useHasNativeFiatProvider: jest.fn(), -})); jest.mock('../../hooks/useMoneyAnalytics', () => ({ useMoneyAnalytics: jest.fn(), })); @@ -214,7 +210,6 @@ describe('MoneyAddMoneySheet — Add funds with a pending transaction', () => { (selectHasAnyNonZeroTokenBalance as unknown as jest.Mock).mockReturnValue( true, ); - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(true); (useMoneyAnalytics as jest.Mock).mockReturnValue({ trackBottomSheetViewed: jest.fn(), trackSurfaceClicked: jest.fn(), diff --git a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.test.tsx b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.test.tsx index 60ea836f0ba..a9fcfe70cdd 100644 --- a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.test.tsx +++ b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.test.tsx @@ -8,7 +8,6 @@ import { useMusdBalance } from '../../../Earn/hooks/useMusdBalance'; import { useMoneyAccountDeposit } from '../../hooks/useMoneyAccount'; import { useMMPayFiatConfig } from '../../../../Views/confirmations/hooks/pay/useMMPayFiatConfig'; import { selectHasAnyNonZeroTokenBalance } from '../../../../../selectors/tokenBalancesController'; -import { useHasNativeFiatProvider } from '../../../Ramp/hooks/useHasNativeFiatProvider'; import { MUSD_CONVERSION_DEFAULT_CHAIN_ID, MUSD_TOKEN_ADDRESS_BY_CHAIN, @@ -63,10 +62,6 @@ jest.mock('../../../../../selectors/tokenBalancesController', () => ({ selectHasAnyNonZeroTokenBalance: jest.fn(), })); -jest.mock('../../../Ramp/hooks/useHasNativeFiatProvider', () => ({ - useHasNativeFiatProvider: jest.fn(), -})); - jest.mock('../../../../../selectors/transactionController', () => ({ ...jest.requireActual('../../../../../selectors/transactionController'), selectTransactions: jest.fn(() => []), @@ -125,24 +120,35 @@ describe('MoneyAddMoneySheet', () => { (selectHasAnyNonZeroTokenBalance as unknown as jest.Mock).mockReturnValue( true, ); - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(true); }); - it('renders all four options', () => { - const { getByText, getByTestId } = renderWithProvider( + it('renders all options', () => { + const { getByText, getAllByText, getByTestId } = renderWithProvider( , ); expect(getByText('Convert crypto')).toBeOnTheScreen(); - expect(getByText('Debit card or bank account')).toBeOnTheScreen(); + expect(getByText('Debit card or Apple Pay')).toBeOnTheScreen(); expect(getByText('$1,203.89 mUSD')).toBeOnTheScreen(); + expect(getByText('Bank account')).toBeOnTheScreen(); expect(getByText('External address')).toBeOnTheScreen(); - expect(getByText('Coming soon')).toBeOnTheScreen(); + // Bank account and External address are both coming soon. + expect(getAllByText('Coming soon')).toHaveLength(2); expect( getByTestId(MoneyAddMoneySheetTestIds.RECEIVE_EXTERNAL_ROW), ).toBeOnTheScreen(); }); + it('renders the Bank account row as a coming-soon, non-pressable option', () => { + const { getByTestId } = renderWithProvider(); + + const bankRow = getByTestId(MoneyAddMoneySheetTestIds.BANK_ACCOUNT_ROW); + expect(bankRow).toBeOnTheScreen(); + + fireEvent.press(bankRow); + expect(mockInitiateDeposit).not.toHaveBeenCalled(); + }); + it('renders the "Add funds" title', () => { const { getByText } = renderWithProvider(); @@ -345,9 +351,7 @@ describe('MoneyAddMoneySheet', () => { ).toBeNull(); }); - it('shows the Deposit funds option enabled when a native provider is available', () => { - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(true); - + it('navigates to MM Pay with autoSelectFiatPayment when Debit card or Apple Pay is pressed', () => { const { getByTestId } = renderWithProvider(); fireEvent.press( @@ -359,21 +363,20 @@ describe('MoneyAddMoneySheet', () => { }); }); - it('shows the Deposit funds option disabled with "Coming soon" when no native provider serves the region', () => { - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(false); - + it('keeps Debit card or Apple Pay active, with only Bank account and External address coming soon', () => { const { getByTestId, getAllByText } = renderWithProvider( , ); + expect(getAllByText('Coming soon')).toHaveLength(2); + fireEvent.press( getByTestId(MoneyAddMoneySheetTestIds.DEPOSIT_FUNDS_OPTION), ); - // Two "Coming soon" tags now: the disabled Deposit row + Receive external. - expect(getAllByText('Coming soon')).toHaveLength(2); - expect(mockOnCloseBottomSheet).not.toHaveBeenCalled(); - expect(mockInitiateDeposit).not.toHaveBeenCalled(); + expect(mockInitiateDeposit).toHaveBeenCalledWith({ + autoSelectFiatPayment: true, + }); }); // Returns the option-row testIDs in rendered order. Each row carries its @@ -401,8 +404,6 @@ describe('MoneyAddMoneySheet', () => { }; it('keeps the original order when all options are enabled', () => { - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(true); - const { UNSAFE_root } = renderWithProvider(); const order = getOptionOrder(UNSAFE_root); @@ -413,32 +414,18 @@ describe('MoneyAddMoneySheet', () => { ]); }); - it('moves the disabled Deposit funds (Coming soon) row to the bottom of the options', () => { - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(false); - - const { UNSAFE_root } = renderWithProvider(); - const order = getOptionOrder(UNSAFE_root); - - expect(order).toEqual([ - MoneyAddMoneySheetTestIds.CONVERT_CRYPTO_OPTION, - MoneyAddMoneySheetTestIds.MOVE_MUSD_OPTION, - MoneyAddMoneySheetTestIds.DEPOSIT_FUNDS_OPTION, - ]); - }); - - it('groups multiple disabled options at the bottom preserving their relative order', () => { + it('moves a disabled option (Convert crypto) to the bottom of the order', () => { (selectHasAnyNonZeroTokenBalance as unknown as jest.Mock).mockReturnValue( false, ); - (useHasNativeFiatProvider as jest.Mock).mockReturnValue(false); const { UNSAFE_root } = renderWithProvider(); const order = getOptionOrder(UNSAFE_root); expect(order).toEqual([ + MoneyAddMoneySheetTestIds.DEPOSIT_FUNDS_OPTION, MoneyAddMoneySheetTestIds.MOVE_MUSD_OPTION, MoneyAddMoneySheetTestIds.CONVERT_CRYPTO_OPTION, - MoneyAddMoneySheetTestIds.DEPOSIT_FUNDS_OPTION, ]); }); diff --git a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.testIds.ts b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.testIds.ts index cee9159c36a..1bccd213abc 100644 --- a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.testIds.ts +++ b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.testIds.ts @@ -3,5 +3,6 @@ export const MoneyAddMoneySheetTestIds = { CONVERT_CRYPTO_OPTION: 'money-add-money-sheet-convert-crypto', DEPOSIT_FUNDS_OPTION: 'money-add-money-sheet-deposit-funds', MOVE_MUSD_OPTION: 'money-add-money-sheet-move-musd', + BANK_ACCOUNT_ROW: 'money-add-money-sheet-bank-account', RECEIVE_EXTERNAL_ROW: 'money-add-money-sheet-receive-external', }; diff --git a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.tsx b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.tsx index f53ca7a6e81..87641fb823c 100644 --- a/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.tsx +++ b/app/components/UI/Money/components/MoneyAddMoneySheet/MoneyAddMoneySheet.tsx @@ -40,7 +40,6 @@ import { useMMPayFiatConfig } from '../../../../Views/confirmations/hooks/pay/us import { useElevatedSurface } from '../../../../../util/theme/themeUtils'; import { selectTransactions } from '../../../../../selectors/transactionController'; import { selectHasAnyNonZeroTokenBalance } from '../../../../../selectors/tokenBalancesController'; -import { useHasNativeFiatProvider } from '../../../Ramp/hooks/useHasNativeFiatProvider'; import MoneySheetOptionsList, { type MoneySheetOption, } from '../MoneySheetOptionsList'; @@ -72,7 +71,6 @@ const MoneyAddMoneySheet: React.FC = () => { const { initiateDeposit } = useMoneyAccountDeposit(); const { enabledTransactionTypes } = useMMPayFiatConfig(); const hasAnyCryptoBalance = useSelector(selectHasAnyNonZeroTokenBalance); - const hasNativeFiatProvider = useHasNativeFiatProvider(); const transactions = useSelector(selectTransactions); const isFiatDepositEnabled = useMemo( () => enabledTransactionTypes.includes(TransactionType.moneyAccountDeposit), @@ -214,11 +212,9 @@ const MoneyAddMoneySheet: React.FC = () => { ? [ { label: strings('money.add_money_sheet.deposit_funds'), - icon: IconName.Bank, + icon: IconName.Card, onPress: handleDepositFunds, testID: MoneyAddMoneySheetTestIds.DEPOSIT_FUNDS_OPTION, - disabled: !hasNativeFiatProvider, - comingSoon: !hasNativeFiatProvider, }, ] : []), @@ -233,6 +229,13 @@ const MoneyAddMoneySheet: React.FC = () => { testID: MoneyAddMoneySheetTestIds.MOVE_MUSD_OPTION, disabled: !hasMusdBalance, }, + { + label: strings('money.add_money_sheet.bank_account'), + icon: IconName.Bank, + testID: MoneyAddMoneySheetTestIds.BANK_ACCOUNT_ROW, + disabled: true, + comingSoon: true, + }, { label: strings('money.add_money_sheet.receive_external'), icon: IconName.QrCode, diff --git a/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.test.tsx b/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.test.tsx index f7360ac462c..5aaf5dea160 100644 --- a/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.test.tsx +++ b/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.test.tsx @@ -125,6 +125,14 @@ describe('MoneyApyInfoSheet', () => { ).toBeOnTheScreen(); }); + it('renders paragraph_4', () => { + const { getByText } = renderWithProvider(); + + expect( + getByText(strings('money.apy_tooltip.paragraph_4')), + ).toBeOnTheScreen(); + }); + it('does not render a Learn More footer button', () => { const { queryByTestId } = renderWithProvider(); @@ -174,6 +182,12 @@ describe('MoneyApyInfoSheet', () => { expect(queryByText(strings('money.apy_tooltip.paragraph_3'))).toBeNull(); }); + it('does not render paragraph_4', () => { + const { queryByText } = renderWithProvider(); + + expect(queryByText(strings('money.apy_tooltip.paragraph_4'))).toBeNull(); + }); + it('renders the sheet title', () => { const { getByText } = renderWithProvider(); diff --git a/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.tsx b/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.tsx index 1a38e305d99..09e86ece11c 100644 --- a/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.tsx +++ b/app/components/UI/Money/components/MoneyApyInfoSheet/MoneyApyInfoSheet.tsx @@ -62,6 +62,9 @@ const MoneyApyInfoSheet = () => { {strings('money.apy_tooltip.paragraph_3')} + + {strings('money.apy_tooltip.paragraph_4')} + ); diff --git a/app/components/UI/Money/components/MoneyWhatYouGet/MoneyWhatYouGet.test.tsx b/app/components/UI/Money/components/MoneyWhatYouGet/MoneyWhatYouGet.test.tsx index 05cbb6ce535..6e6e88ea8a0 100644 --- a/app/components/UI/Money/components/MoneyWhatYouGet/MoneyWhatYouGet.test.tsx +++ b/app/components/UI/Money/components/MoneyWhatYouGet/MoneyWhatYouGet.test.tsx @@ -28,7 +28,7 @@ describe('MoneyWhatYouGet', () => { expect(container).toHaveTextContent(/dollar-backed stablecoin/); expect(container).toHaveTextContent(/Get full liquidity/); expect(container).toHaveTextContent(/1-3% mUSD back/); - expect(container).toHaveTextContent(/Transfer to any of your wallets/); + expect(container).toHaveTextContent(/Send to any of your wallets/); expect(container).toHaveTextContent(/Send and receive funds globally/); }); diff --git a/app/components/UI/Money/utils/depositFaqTokens.test.ts b/app/components/UI/Money/utils/depositFaqTokens.test.ts new file mode 100644 index 00000000000..de1a230cf9a --- /dev/null +++ b/app/components/UI/Money/utils/depositFaqTokens.test.ts @@ -0,0 +1,72 @@ +import { + MONEY_NO_FEE_TOKENS_FALLBACK, + resolveNoFeeTokens, + formatNoFeeTokenBullets, + formatBaseStablecoins, +} from './depositFaqTokens'; + +describe('depositFaqTokens', () => { + describe('resolveNoFeeTokens', () => { + it('returns the remote list when it is populated', () => { + const remote = { '0x1': ['USDC'] }; + + expect(resolveNoFeeTokens(remote)).toBe(remote); + }); + + it('falls back to the bundled list when remote is empty', () => { + expect(resolveNoFeeTokens({})).toBe(MONEY_NO_FEE_TOKENS_FALLBACK); + }); + }); + + describe('formatNoFeeTokenBullets', () => { + it('formats each chain as a bullet line with a friendly network name', () => { + expect(formatNoFeeTokenBullets(MONEY_NO_FEE_TOKENS_FALLBACK)).toBe( + [ + '• Ethereum: USDC, USDT, DAI, aUSDC, aUSDT, aDAI', + '• Arbitrum: USDC', + '• Base: USDC', + '• BNB Chain: USDC, USDT', + ].join('\n'), + ); + }); + + it('omits chains without a known network name', () => { + expect( + formatNoFeeTokenBullets({ '0x1': ['USDC'], '0x999999': ['USDC'] }), + ).toBe('• Ethereum: USDC'); + }); + + it('includes mUSD in the per-chain deposit list', () => { + expect( + formatNoFeeTokenBullets({ + '0x1': ['USDC', 'mUSD'], + '0xe708': ['mUSD'], + }), + ).toBe('• Ethereum: USDC, mUSD\n• Linea: mUSD'); + }); + }); + + describe('formatBaseStablecoins', () => { + it('returns the unique base stablecoins excluding aTokens, with an "or" list', () => { + expect(formatBaseStablecoins(MONEY_NO_FEE_TOKENS_FALLBACK)).toBe( + 'USDC, USDT, or DAI', + ); + }); + + it('joins two stablecoins with "or"', () => { + expect(formatBaseStablecoins({ '0x1': ['USDC', 'DAI'] })).toBe( + 'USDC or DAI', + ); + }); + + it('returns a single stablecoin without a connector', () => { + expect(formatBaseStablecoins({ '0x1': ['USDC', 'aUSDC'] })).toBe('USDC'); + }); + + it('excludes mUSD from the inline stablecoin list', () => { + expect(formatBaseStablecoins({ '0x1': ['USDC', 'mUSD', 'DAI'] })).toBe( + 'USDC or DAI', + ); + }); + }); +}); diff --git a/app/components/UI/Money/utils/depositFaqTokens.ts b/app/components/UI/Money/utils/depositFaqTokens.ts new file mode 100644 index 00000000000..0d70a257f1d --- /dev/null +++ b/app/components/UI/Money/utils/depositFaqTokens.ts @@ -0,0 +1,84 @@ +import { CHAIN_IDS } from '@metamask/transaction-controller'; +import { NETWORK_TO_NAME_MAP } from '../../../../core/Engine/constants'; +import { WildcardTokenList } from '../../Earn/utils/wildcardTokenList'; + +const NETWORK_NAMES = NETWORK_TO_NAME_MAP as Record; + +/** + * Symbols excluded from the inline faq_a1 sentence only. That sentence describes + * depositing a stablecoin that "converts to mUSD", so listing mUSD itself reads + * as circular. mUSD is still shown in the per-chain deposit list (faq_a7) since + * it is a valid no-fee deposit. + */ +const INLINE_EXCLUDED_SYMBOLS = new Set(['MUSD']); + +const isInlineExcludedSymbol = (symbol: string): boolean => + INLINE_EXCLUDED_SYMBOLS.has(symbol.toUpperCase()); + +/** + * Default no-fee deposit tokens per chain, used when the remote + * `earnMoneyDepositNoFeeTokens` flag is not configured so the FAQ never renders + * an empty list. Mirrors the wildcard list shape: chain id -> token symbols. + */ +export const MONEY_NO_FEE_TOKENS_FALLBACK: WildcardTokenList = { + [CHAIN_IDS.MAINNET]: ['USDC', 'USDT', 'DAI', 'aUSDC', 'aUSDT', 'aDAI'], + [CHAIN_IDS.ARBITRUM]: ['USDC'], + [CHAIN_IDS.BASE]: ['USDC'], + [CHAIN_IDS.BSC]: ['USDC', 'USDT'], +}; + +/** + * Returns the remote no-fee token list when populated, otherwise the bundled + * fallback. + */ +export const resolveNoFeeTokens = ( + remote: WildcardTokenList, +): WildcardTokenList => + Object.keys(remote).length > 0 ? remote : MONEY_NO_FEE_TOKENS_FALLBACK; + +/** + * Formats the per-chain no-fee token list as bullet lines, e.g. + * "• Ethereum: USDC, USDT, DAI". Chains without a known network name are + * omitted so the user-facing FAQ never shows a raw chain id. + */ +export const formatNoFeeTokenBullets = (list: WildcardTokenList): string => + Object.entries(list) + .map(([chainId, symbols]) => { + const name = NETWORK_NAMES[chainId]; + return name ? `• ${name}: ${symbols.join(', ')}` : null; + }) + .filter((line): line is string => line !== null) + .join('\n'); + +/** + * Returns the unique base stablecoin symbols (excluding aave-wrapped aTokens) + * across all chains, formatted as an "or" list, e.g. "USDC, USDT, or DAI". + */ +export const formatBaseStablecoins = (list: WildcardTokenList): string => { + const seen = new Set(); + const stablecoins: string[] = []; + for (const symbols of Object.values(list)) { + for (const symbol of symbols) { + // aTokens (aUSDC, aUSDT, aDAI) are wrapped variants; the inline FAQ + // sentence lists only the base stablecoins, and excludes mUSD. + if ( + /^a[A-Z]/.test(symbol) || + isInlineExcludedSymbol(symbol) || + seen.has(symbol) + ) { + continue; + } + seen.add(symbol); + stablecoins.push(symbol); + } + } + + if (stablecoins.length <= 1) { + return stablecoins.join(''); + } + if (stablecoins.length === 2) { + return `${stablecoins[0]} or ${stablecoins[1]}`; + } + const last = stablecoins[stablecoins.length - 1]; + return `${stablecoins.slice(0, -1).join(', ')}, or ${last}`; +}; diff --git a/locales/languages/en.json b/locales/languages/en.json index 58885e94cc7..45002d0ec3c 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -7104,7 +7104,7 @@ "benefit_liquidity": "Get full liquidity with no lockups, so you can trade or withdraw anytime", "benefit_spend_prefix": "Spend at 150M+ merchants with MetaMask Card and earn ", "benefit_spend_cashback": "1-3% mUSD back", - "benefit_transfer": "Transfer to any of your wallets across MetaMask", + "benefit_transfer": "Send to any of your wallets across MetaMask", "benefit_global": "Send and receive funds globally", "learn_more": "Learn more" }, @@ -7114,7 +7114,8 @@ "add_money_sheet": { "title": "Add funds", "convert_crypto": "Convert crypto", - "deposit_funds": "Debit card or bank account", + "deposit_funds": "Debit card or Apple Pay", + "bank_account": "Bank account", "move_musd": "{{amount}} mUSD", "add_musd": "Add mUSD", "receive_external": "External address", @@ -7159,8 +7160,9 @@ "apy_tooltip": { "title": "Annual Percentage Yield (APY)", "paragraph_1": "Your Money account earns up to {{percentage}}% automatically.", - "paragraph_2": "The rate shown is an estimated Annual Percentage Yield (APY) based on current market conditions. APY is variable and may change due to various factors. The rate is generated by third-party DeFi platforms that deploy funds in blockchain protocols.", + "paragraph_2": "The rate shown is an estimated Annual Percentage Yield (APY) based on current market conditions. APY is variable and is not guaranteed. Funds go into a DeFi vault, administered by Veda with risk oversight by Steakhouse Financial, that generates returns across established lending markets.", "paragraph_3": "When you link your MetaMask Card, purchases will be deducted from this balance.", + "paragraph_4": "Money account is powered by Monad.", "deposit_body": "The rate shown is an estimated Annual Percentage Yield (APY) based on current market conditions. APY is variable and is not guaranteed." }, "earnings_tooltip": { @@ -7234,7 +7236,7 @@ "description_3": "Money account is powered by Monad.", "faq_title": "FAQs", "faq_q1": "What is a MetaMask Money Account?", - "faq_a1": "MetaMask Money Account is a self-custodial account built into MetaMask that earns up to {{percentage}}% variable APY on deposited funds—with no lockups, no withdrawal penalties, and no account fees. When you deposit a supported stablecoin (USDC, USDT, or DAI) or aTokens into a Money Account, it converts to mUSD, MetaMask's dollar-backed stablecoin, with no conversion fees. You can also deposit any token into a Money Account, with a conversion fee. Your Money Account balance (mUSD) stays available to trade, send, and earn—or spend anytime via MetaMask Card, across 150+ million Mastercard merchants worldwide.", + "faq_a1": "MetaMask Money Account is a self-custodial account built into MetaMask that earns up to {{percentage}}% variable APY on deposited funds—with no lockups, no withdrawal penalties, and no account fees. When you deposit a supported stablecoin ({{stablecoins}}) or aTokens into a Money Account, it converts to mUSD, MetaMask's dollar-backed stablecoin, with no conversion fees. You can also deposit any token into a Money Account, with a conversion fee. Your Money Account balance (mUSD) stays available to trade, send, and earn—or spend anytime via MetaMask Card, across 150+ million Mastercard merchants worldwide.", "faq_q2": "Is MetaMask Money Account safe?", "faq_a2": "MetaMask is a self-custodial wallet—only you control your private keys and funds. MetaMask cannot access, freeze, or move your balance. mUSD itself is backed 1:1 by US dollars and short-term US Treasury bills held in regulated custody by Bridge (a Stripe company). However, like all DeFi-based products, Money Account carries risks, including smart-contract failures, protocol exploits, liquidity shortages, third-party failures and legal or regulatory restrictions. The APY is variable and not guaranteed, and there is a risk of loss. The Money balance (mUSD) is not insured by the FDIC or any government agency.", "faq_q3": "Who controls my MetaMask Money Account?", @@ -7244,9 +7246,9 @@ "faq_q5": "How much can I earn with a MetaMask Money Account?", "faq_a5": "MetaMask Money Account earns up to {{percentage}}% APY. The rate is variable and fluctuates with market conditions. The current rate is always visible inside the Money Account.", "faq_q6": "Where does the yield come from?", - "faq_a6": "When funds are deposited into a Money Account, these assets go into a third-party smart contract vault. The vault interacts with established DeFi protocols—for example, lending markets like Aave and Morpho—where they earn returns from real economic activity, primarily interest paid by borrowers. Any resulting returns, after applicable protocol costs and product fees, show up as APY. Earnings are not interest paid by MetaMask or by the issuer of mUSD. They are the onchain returns generated by the vault's positions in third-party DeFi protocols.", + "faq_a6": "When funds are deposited into a Money Account, these assets go into a third-party smart contract vault. The vault interacts with established DeFi protocols—for example, lending markets like Aave and Morpho—where they earn returns from real economic activity, primarily interest paid by borrowers. Any resulting returns, after applicable protocol costs and product fees, show up as APY. Earnings are not interest paid by MetaMask or by the issuer of mUSD. They are the onchain returns generated by the vault's positions in third-party DeFi protocols.\n\nThe rate shown is an estimated Annual Percentage Yield (APY) based on current market conditions. APY is variable and is not guaranteed. The DeFi vault is administered by Veda with risk oversight by Steakhouse Financial.", "faq_q7": "Which tokens can I deposit into the Money Account?", - "faq_a7": "You can deposit the following stablecoins and aTokens into your Money Account with no conversion fees:\n\n• Ethereum: USDC, USDT, DAI, aUSDC, aUSDT, aDAI\n• Arbitrum: USDC\n• Base: USDC\n• BNB Chain: USDC, USDT\n\nAll other EVM tokens can also be deposited into the Money Account, but standard exchange fees may apply. You can also fund your Money Account using a debit card, credit card, bank account, PayPal, Apple Pay, or Google Pay.\n\nNote: There is an initial max deposit of $100,000 per token to ensure liquidity.", + "faq_a7": "You can deposit the following stablecoins and aTokens into your Money Account with no conversion fees:\n\n{{tokenBullets}}\n\nAll other EVM tokens can also be deposited into the Money Account, but standard exchange fees may apply. You can also fund your Money Account using a debit card, credit card, or Apple Pay.\n\nNote: There is an initial max deposit of $100,000 per token to ensure liquidity.", "faq_q8": "Can I withdraw from the MetaMask Money Account anytime?", "faq_a8": "Yes. Your mUSD is never locked. You can trade, send, spend, or withdraw your full balance at any time with no notice periods, no penalties, and no withdrawal fees from MetaMask. Withdrawals process immediately, subject to standard network confirmation times on the relevant blockchain. If liquidity is tight, there may be temporary delays.", "faq_q9": "Do I need to complete KYC to use MetaMask Money Account?", From 988652f637608d7855f15baf248152994bfb4278 Mon Sep 17 00:00:00 2001 From: Devin Stewart <49423028+Bigshmow@users.noreply.github.com> Date: Tue, 16 Jun 2026 09:11:26 -0600 Subject: [PATCH 09/23] feat: top traders unified pnl abbreviation (#31777) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Unifies PnL abbreviation across the three Social Leaderboard surfaces (homepage carousel, leaderboard list, trader profile headline) so the same value renders identically everywhere. The trader profile's 30D Return previously showed un-abbreviated values (e.g. `+$117,166.82`); the leaderboard rows used a K-only formatter that produced `+$1,200K` for million-dollar values. Now all three use one shared formatter: - **Sub-$1K** renders the actual value with 2 decimal places (e.g. `+$500.24`, `+$0.50`) - **≥$1K** abbreviates with K/M/B/T tier suffixes and 1 decimal trimmed (e.g. `+$5.1K`, `+$117.2K`, `+$1.2M`, `+$1M`) - Zero renders as `$0.00` with no sign - Tier-boundary rounding promotes correctly: `999_999` → `+$1M` (not `+$1000K`) **What changed** - New `formatSignedAbbreviatedUsd` in `SocialLeaderboard/utils/formatters.ts` is the single source of truth. Co-located helpers (`shortenAbsCurrency`, `renderBucket`, `CURRENCY_BUCKETS`) live in the same file. - `StatsRow` (profile 30D Return) drops its local `formatPnlWithCents` + `formatWithThreshold` import in favor of the shared formatter. - `TopTraderCard` + `TraderRow` (homepage carousel and leaderboard list) import the shared formatter directly via the existing cross-route `eslint-disable` pattern. - The thin `formatPnl` wrapper in `Homepage/Sections/TopTraders/utils/formatPnl.ts` and its test file are deleted. Two consumers updated. - Tests in `formatters.test.ts`, `StatsRow.test.tsx`, `TraderProfileView.test.tsx`, `TopTraderCard.test.tsx`, and `TraderRow.test.tsx` updated to assert the new format. **Visible behavior changes** - Trader profile 30D Return: `+$117,166.82` → `+$117.2K`. The PM-driven request that started this work. - Homepage carousel + leaderboard list PnL: rows over `$1M` now correctly promote to M (`+$1.2M`) instead of staying in K (`+$1,200K`). Sub-$1M rows gain one decimal of precision (`+$963K` → `+$963.1K`). - Zero PnL: no longer shows a `+` sign (was `+$0` in old `formatPnl`, now `$0.00`). Consistent with how the profile view renders zero. ## **Changelog** CHANGELOG entry: Unified the PnL number formatting on the social leaderboard so the same value renders the same way everywhere (trader profile, leaderboard list, homepage carousel). Large values now abbreviate to K/M/B/T with one decimal (e.g. $1.2M); sub-$1K values keep two decimal places. ## **Related issues** Refs: N/A — surfaced during TSA-628 / social leaderboard polish work. PM-driven request: trader profile 30D Return needed to abbreviate ($1.2M) for parity with the rest of the surfaces. Filing as a follow-up to the perps rollout work. ## **Manual testing steps** ```gherkin Feature: Unified PnL abbreviation across the social leaderboard Scenario: Trader profile 30D Return shows abbreviated value for large numbers Given the user opens a trader profile whose 30D return is $1,170,000 Then the headline reads "+$1.2M" (not "+$1,170,000.00" or "+$1,170K") Scenario: Leaderboard list row abbreviates million-dollar PnL correctly Given a leaderboard trader with $1,200,000 PnL When the leaderboard list renders Then the row reads "+$1.2M" (not "+$1,200K") Scenario: Homepage Top Traders carousel matches the leaderboard format Given the same trader appears in the homepage Top Traders carousel Then the carousel card renders the same "+$1.2M" string as the leaderboard list Scenario: Sub-$1K values keep two decimal places Given a trader profile with a 30D return of $500.236 Then the headline reads "+$500.24" (not "+$500" or "+$500K") Scenario: Zero PnL renders neutrally with no sign Given a trader profile with a 30D return of exactly $0 Then the headline reads "$0.00" (no leading + or -) ``` ## **Screenshots/Recordings** ### **Before** Screenshot 2026-06-15 at 10 14 43 PM Screenshot 2026-06-15 at 10 14 33 PM ### **After** Screenshot 2026-06-15 at 10 12 41 PM Screenshot 2026-06-15 at 10 12 27 PM ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- .../components/TopTraderCard.test.tsx | 4 +- .../TopTraders/components/TopTraderCard.tsx | 5 +- .../TopTraders/components/TraderRow.test.tsx | 4 +- .../TopTraders/components/TraderRow.tsx | 5 +- .../TopTraders/utils/formatPnl.test.ts | 70 ------------------- .../Sections/TopTraders/utils/formatPnl.ts | 21 ------ .../TraderProfileView.test.tsx | 8 +-- .../components/StatsRow.test.tsx | 18 +++-- .../TraderProfileView/components/StatsRow.tsx | 19 +---- .../utils/formatters.test.ts | 39 +++++++++++ .../SocialLeaderboard/utils/formatters.ts | 44 ++++++++++++ 11 files changed, 112 insertions(+), 125 deletions(-) delete mode 100644 app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.test.ts delete mode 100644 app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.ts diff --git a/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.test.tsx b/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.test.tsx index a7aa8048a36..1c95d28c156 100644 --- a/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.test.tsx +++ b/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.test.tsx @@ -30,7 +30,7 @@ describe('TopTraderCard', () => { , ); expect(screen.getByText('sniperliquid')).toBeOnTheScreen(); - expect(screen.getByText('+$963K')).toBeOnTheScreen(); + expect(screen.getByText('+$963.1K')).toBeOnTheScreen(); expect(screen.getByText(/30D/)).toBeOnTheScreen(); }); @@ -186,6 +186,6 @@ describe('TopTraderCard', () => { onFollowPress={mockOnFollowPress} />, ); - expect(screen.getByText('-$500')).toBeOnTheScreen(); + expect(screen.getByText('-$500.00')).toBeOnTheScreen(); }); }); diff --git a/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.tsx b/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.tsx index 149820ea666..3b1e9d67c3a 100644 --- a/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.tsx +++ b/app/components/Views/Homepage/Sections/TopTraders/components/TopTraderCard.tsx @@ -17,7 +17,8 @@ import React from 'react'; import { Image, TouchableOpacity } from 'react-native'; import { strings } from '../../../../../../../locales/i18n'; import type { TopTrader } from '../types'; -import { formatPnl } from '../utils/formatPnl'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { formatSignedAbbreviatedUsd } from '../../../../SocialLeaderboard/utils/formatters'; import { hasRealAvatar } from '../utils/avatarFallback'; export interface TopTraderCardProps { @@ -55,7 +56,7 @@ const TopTraderCard: React.FC = ({ }) => { const tw = useTailwind(); - const pnlText = formatPnl(trader.pnlValue); + const pnlText = formatSignedAbbreviatedUsd(trader.pnlValue); const isPnlPositive = trader.pnlValue >= 0; return ( diff --git a/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.test.tsx b/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.test.tsx index af7c54d01d6..ee347a5a618 100644 --- a/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.test.tsx +++ b/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.test.tsx @@ -34,7 +34,7 @@ describe('TraderRow', () => { expect(screen.getByText('1')).toBeOnTheScreen(); expect(screen.getByText('sniperliquid')).toBeOnTheScreen(); expect(screen.getByText('+43.0%')).toBeOnTheScreen(); - expect(screen.getByText('+$963K')).toBeOnTheScreen(); + expect(screen.getByText('+$963.1K')).toBeOnTheScreen(); }); it('renders avatar image when avatarUri is present', () => { @@ -132,7 +132,7 @@ describe('TraderRow', () => { , ); expect(screen.getByText('-15.3%')).toBeOnTheScreen(); - expect(screen.getByText('-$500')).toBeOnTheScreen(); + expect(screen.getByText('-$500.00')).toBeOnTheScreen(); }); it('uses custom testID when provided', () => { diff --git a/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.tsx b/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.tsx index a1796934001..293b87af262 100644 --- a/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.tsx +++ b/app/components/Views/Homepage/Sections/TopTraders/components/TraderRow.tsx @@ -20,7 +20,8 @@ import { Image, TouchableOpacity } from 'react-native'; import { strings } from '../../../../../../../locales/i18n'; import { TopRankAvatar, TopRankIndicator } from '../topRank'; import type { TopTrader } from '../types'; -import { formatPnl } from '../utils/formatPnl'; +// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog +import { formatSignedAbbreviatedUsd } from '../../../../SocialLeaderboard/utils/formatters'; import { hasRealAvatar } from '../utils/avatarFallback'; const AVATAR_SIZE = 40; @@ -56,7 +57,7 @@ const TraderRow: React.FC = ({ const roiSign = trader.percentageChange >= 0 ? '+' : ''; const roiText = `${roiSign}${trader.percentageChange.toFixed(1)}%`; - const pnlText = formatPnl(trader.pnlValue); + const pnlText = formatSignedAbbreviatedUsd(trader.pnlValue); const isPnlPositive = trader.pnlValue >= 0; const isRoiPositive = trader.percentageChange >= 0; diff --git a/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.test.ts b/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.test.ts deleted file mode 100644 index 1fdb5f7498d..00000000000 --- a/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { formatPnl } from './formatPnl'; - -describe('formatPnl', () => { - describe('positive values', () => { - it('formats a sub-thousand value with no comma', () => { - expect(formatPnl(500)).toBe('+$500'); - }); - - it('formats a sub-thousand value with rounding', () => { - expect(formatPnl(499.7)).toBe('+$500'); - }); - - it('formats a thousands value with K suffix', () => { - expect(formatPnl(963_000)).toBe('+$963K'); - }); - - it('formats a thousands value that needs a comma with K suffix', () => { - expect(formatPnl(1_200_000)).toBe('+$1,200K'); - }); - - it('formats a millions value with K suffix and comma', () => { - expect(formatPnl(1_500_000)).toBe('+$1,500K'); - }); - - it('formats zero as positive', () => { - expect(formatPnl(0)).toBe('+$0'); - }); - }); - - describe('negative values', () => { - it('formats a sub-thousand negative value', () => { - expect(formatPnl(-500)).toBe('-$500'); - }); - - it('formats a negative thousands value with K suffix', () => { - expect(formatPnl(-963_000)).toBe('-$963K'); - }); - - it('formats a negative value that needs a comma', () => { - expect(formatPnl(-1_200_000)).toBe('-$1,200K'); - }); - }); - - describe('boundary values', () => { - it('formats exactly 1,000', () => { - expect(formatPnl(1_000)).toBe('+$1K'); - }); - - it('formats just below 1,000', () => { - expect(formatPnl(999)).toBe('+$999'); - }); - - it('formats 999.5 as +$1K (rounds up to 1000 before branching)', () => { - expect(formatPnl(999.5)).toBe('+$1K'); - }); - - it('formats -999.7 as -$1K (rounds up to 1000 before branching)', () => { - expect(formatPnl(-999.7)).toBe('-$1K'); - }); - - it('formats exactly 1,000,000', () => { - expect(formatPnl(1_000_000)).toBe('+$1,000K'); - }); - - it('rounds fractional values correctly', () => { - expect(formatPnl(1_499)).toBe('+$1K'); - expect(formatPnl(1_500)).toBe('+$2K'); - }); - }); -}); diff --git a/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.ts b/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.ts deleted file mode 100644 index 683545e5602..00000000000 --- a/app/components/Views/Homepage/Sections/TopTraders/utils/formatPnl.ts +++ /dev/null @@ -1,21 +0,0 @@ -// eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog -import { addThousandsSeparator } from '../../../../SocialLeaderboard/utils/numberFormatting'; - -/** - * Format a raw PnL number into a compact display string. - * - * Uses manual rounding instead of `toLocaleString` options because - * React Native's Hermes engine does not honour `maximumFractionDigits`. - * - * @param value - Raw USD PnL value. - * @returns Formatted string like "+$963K" or "-$1,200". - */ -export function formatPnl(value: number): string { - const rounded = Math.round(Math.abs(value)); - const sign = value >= 0 ? '+' : '-'; - - if (rounded >= 1_000) { - return `${sign}$${addThousandsSeparator(String(Math.round(rounded / 1_000)))}K`; - } - return `${sign}$${addThousandsSeparator(String(rounded))}`; -} diff --git a/app/components/Views/SocialLeaderboard/TraderProfileView/TraderProfileView.test.tsx b/app/components/Views/SocialLeaderboard/TraderProfileView/TraderProfileView.test.tsx index 1b3cef22b69..c74672bc743 100644 --- a/app/components/Views/SocialLeaderboard/TraderProfileView/TraderProfileView.test.tsx +++ b/app/components/Views/SocialLeaderboard/TraderProfileView/TraderProfileView.test.tsx @@ -816,7 +816,7 @@ describe('TraderProfileView', () => { renderWithProvider(); // Sum is 100,000 — hyperliquid contribution ignored - expect(screen.getByText('+$100,000.00')).toBeOnTheScreen(); + expect(screen.getByText('+$100K')).toBeOnTheScreen(); // And the trader's global pnl30d (999,999) is NOT what we display expect(screen.queryByText('+$999,999.00')).not.toBeOnTheScreen(); }); @@ -840,7 +840,7 @@ describe('TraderProfileView', () => { renderWithProvider(); // -1000 + -2500 + 500 = -3000 - expect(screen.getByText('-$3,000.00')).toBeOnTheScreen(); + expect(screen.getByText('-$3K')).toBeOnTheScreen(); }); it('treats a missing chain entry as 0', () => { @@ -856,7 +856,7 @@ describe('TraderProfileView', () => { renderWithProvider(); - expect(screen.getByText('+$7,500.00')).toBeOnTheScreen(); + expect(screen.getByText('+$7.5K')).toBeOnTheScreen(); }); it('falls back to the global stats.pnl30d when perChainPnl is empty', () => { @@ -872,7 +872,7 @@ describe('TraderProfileView', () => { renderWithProvider(); - expect(screen.getByText('+$20,610.00')).toBeOnTheScreen(); + expect(screen.getByText('+$20.6K')).toBeOnTheScreen(); }); }); }); diff --git a/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.test.tsx b/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.test.tsx index 0171ffea66b..e5f54464e0e 100644 --- a/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.test.tsx +++ b/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.test.tsx @@ -39,9 +39,15 @@ describe('StatsRow', () => { expect(screen.getByText('0%')).toBeOnTheScreen(); }); - it('renders formatted PnL when pnl30d is non-null and positive', () => { + it('abbreviates positive PnL with K suffix', () => { renderWithProvider(); - expect(screen.getByText('+$20,610.00')).toBeOnTheScreen(); + expect(screen.getByText('+$20.6K')).toBeOnTheScreen(); + }); + + it('abbreviates large positive PnL with M suffix', () => { + const stats = { ...baseStats, pnl30d: 1_170_000 }; + renderWithProvider(); + expect(screen.getByText('+$1.2M')).toBeOnTheScreen(); }); it('renders dash when pnl30d is null', () => { @@ -51,19 +57,19 @@ describe('StatsRow', () => { expect(dashes.length).toBeGreaterThanOrEqual(2); }); - it('renders negative PnL correctly', () => { + it('abbreviates negative PnL with K suffix', () => { const stats = { ...baseStats, pnl30d: -5000 }; renderWithProvider(); - expect(screen.getByText('-$5,000.00')).toBeOnTheScreen(); + expect(screen.getByText('-$5K')).toBeOnTheScreen(); }); - it('renders PnL for small values without K suffix', () => { + it('renders sub-$1K PnL with two decimal places (no abbreviation)', () => { const stats = { ...baseStats, pnl30d: 500 }; renderWithProvider(); expect(screen.getByText('+$500.00')).toBeOnTheScreen(); }); - it('rounds decimal PnL values to two places', () => { + it('rounds sub-$1K PnL to two decimal places', () => { const stats = { ...baseStats, pnl30d: 500.236 }; renderWithProvider(); expect(screen.getByText('+$500.24')).toBeOnTheScreen(); diff --git a/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.tsx b/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.tsx index 3918fbb0456..9cdb532ddea 100644 --- a/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.tsx +++ b/app/components/Views/SocialLeaderboard/TraderProfileView/components/StatsRow.tsx @@ -10,9 +10,9 @@ import { BoxAlignItems, BoxJustifyContent, } from '@metamask/design-system-react-native'; -import I18n, { strings } from '../../../../../../locales/i18n'; +import { strings } from '../../../../../../locales/i18n'; import type { TraderStats } from '@metamask/social-controllers'; -import { formatWithThreshold } from '../../../../../util/assets'; +import { formatSignedAbbreviatedUsd } from '../../utils/formatters'; import { TraderProfileViewSelectorsIDs } from '../TraderProfileView.testIds'; export interface StatsRowProps { @@ -42,18 +42,6 @@ function formatHoldTime(minutes: number): string { }); } -function formatPnlWithCents(value: number): string { - const sign = value >= 0 ? '+' : '-'; - const formatted = formatWithThreshold(Math.abs(value), 0, I18n.locale, { - style: 'currency', - currency: 'USD', - minimumFractionDigits: 2, - maximumFractionDigits: 2, - }); - - return `${sign}${formatted}`; -} - const StatsRow: React.FC = ({ stats, holdTimeMinutes }) => { const winRate = stats.winRate30d != null @@ -62,8 +50,7 @@ const StatsRow: React.FC = ({ stats, holdTimeMinutes }) => { const isWinRatePositive = (stats.winRate30d ?? 0) > 0; const hasPnl = stats.pnl30d != null; - const pnl = - stats.pnl30d != null ? formatPnlWithCents(stats.pnl30d) : '\u2014'; + const pnl = formatSignedAbbreviatedUsd(stats.pnl30d); const isPnlPositive = stats.pnl30d != null && stats.pnl30d >= 0; return ( diff --git a/app/components/Views/SocialLeaderboard/utils/formatters.test.ts b/app/components/Views/SocialLeaderboard/utils/formatters.test.ts index 3f62f32d03f..af2e656642f 100644 --- a/app/components/Views/SocialLeaderboard/utils/formatters.test.ts +++ b/app/components/Views/SocialLeaderboard/utils/formatters.test.ts @@ -1,6 +1,7 @@ import { formatUsd, formatSignedUsd, + formatSignedAbbreviatedUsd, formatTokenAmount, formatPercent, formatTradeDate, @@ -51,6 +52,44 @@ describe('formatSignedUsd', () => { }); }); +describe('formatSignedAbbreviatedUsd', () => { + it.each([ + [123, '+$123.00'], + [999, '+$999.00'], + [1_000, '+$1K'], + [5_123, '+$5.1K'], + [5_000, '+$5K'], + [20_610, '+$20.6K'], + [117_166, '+$117.2K'], + [999_999, '+$1M'], + [1_170_000, '+$1.2M'], + [3_200_000_000, '+$3.2B'], + [1.5e12, '+$1.5T'], + ])('formats %d as %s', (input, expected) => { + expect(formatSignedAbbreviatedUsd(input)).toBe(expected); + }); + + it('prefixes negative values with -', () => { + expect(formatSignedAbbreviatedUsd(-5_000)).toBe('-$5K'); + expect(formatSignedAbbreviatedUsd(-1_170_000)).toBe('-$1.2M'); + expect(formatSignedAbbreviatedUsd(-500.24)).toBe('-$500.24'); + }); + + it('renders zero without a sign', () => { + expect(formatSignedAbbreviatedUsd(0)).toBe('$0.00'); + }); + + it('shows two decimal places for sub-$1K values', () => { + expect(formatSignedAbbreviatedUsd(500.236)).toBe('+$500.24'); + expect(formatSignedAbbreviatedUsd(0.5)).toBe('+$0.50'); + }); + + it('returns an em dash for null and undefined', () => { + expect(formatSignedAbbreviatedUsd(null)).toBe('\u2014'); + expect(formatSignedAbbreviatedUsd(undefined)).toBe('\u2014'); + }); +}); + describe('formatTokenAmount', () => { it('abbreviates billions (e.g. 1.5B)', () => { expect(formatTokenAmount(1500000000)).toBe('1.50B'); diff --git a/app/components/Views/SocialLeaderboard/utils/formatters.ts b/app/components/Views/SocialLeaderboard/utils/formatters.ts index d71fc727d8d..75b6d297872 100644 --- a/app/components/Views/SocialLeaderboard/utils/formatters.ts +++ b/app/components/Views/SocialLeaderboard/utils/formatters.ts @@ -33,6 +33,50 @@ export function formatSignedUsd(value: number | null | undefined): string { return sign + formatPerpsFiat(Math.abs(value), { stripTrailingZeros: false }); } +// Ordered largest → smallest. Walk down and promote when rounding pushes a +// value past the bucket boundary (e.g. `999_999` rounds to `1000K`, which +// we want as `$1M`, not `$1000K`). +const CURRENCY_BUCKETS: readonly (readonly [number, string])[] = [ + [1e12, 'T'], + [1e9, 'B'], + [1e6, 'M'], + [1e3, 'K'], +]; + +function renderBucket(value: number, suffix: string): string { + const str = value % 1 === 0 ? value.toFixed(0) : value.toFixed(1); + return `$${str}${suffix}`; +} + +function shortenAbsCurrency(abs: number): string { + if (abs < 1e3) return `$${abs.toFixed(2)}`; + for (let i = 0; i < CURRENCY_BUCKETS.length; i++) { + const [divisor, suffix] = CURRENCY_BUCKETS[i]; + if (abs < divisor) continue; + const value = Math.round((abs / divisor) * 10) / 10; + if (value >= 1_000 && i > 0) { + const [nextDivisor, nextSuffix] = CURRENCY_BUCKETS[i - 1]; + const promoted = Math.round((abs / nextDivisor) * 10) / 10; + return renderBucket(promoted, nextSuffix); + } + return renderBucket(value, suffix); + } + return `$${abs.toFixed(2)}`; +} + +/** + * Signed USD with K/M/B/T abbreviation for ≥$1K values. Used for compact + * PnL displays like the 30D Return headline (`+$117.2K`, `+$1.2M`, `-$500`). + */ +export function formatSignedAbbreviatedUsd( + value: number | null | undefined, +): string { + if (value == null) return EM_DASH; + if (value === 0) return shortenAbsCurrency(0); + const sign = value > 0 ? '+' : '-'; + return sign + shortenAbsCurrency(Math.abs(value)); +} + /** * Formats a raw token quantity for display in list rows. * - Values >= 1,000 are abbreviated with K/M/B/T suffixes (e.g. 216.65M). From 58b724130ac1bead192b0a4e356512d5d606bab4 Mon Sep 17 00:00:00 2001 From: Ulisses Ferreira Date: Tue, 16 Jun 2026 16:17:15 +0100 Subject: [PATCH 10/23] chore: bump `@metamask/tron-wallet-snap` to `^1.26.0` (#31794) ## **Description** Bringing the following changes to the client: ```markdown ## [1.26.0] ### Added - Add `signProofOfOwnership` client request method ([#327](https://github.com/MetaMask/snap-tron-wallet/pull/327)) - This method silently signs `metamask:proof-of-ownership::
` messages with the account's secp256k1 key via TronWeb's `signMessageV2` - Add support for `keyring_createAccounts` method to enable batch account creation ([#308](https://github.com/MetaMask/snap-tron-wallet/pull/308)). ``` ## **Changelog** CHANGELOG entry: null ## **Related issues** n/a ## **Manual testing steps** n/a ## **Screenshots/Recordings** ### **Before** n/a ### **After** n/a ## **Pre-merge author checklist** - [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** - [ ] 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. --- package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 1b8f571e1db..cfb3e90fb94 100644 --- a/package.json +++ b/package.json @@ -348,7 +348,7 @@ "@metamask/swappable-obj-proxy": "^2.1.0", "@metamask/transaction-controller": "^68.0.0", "@metamask/transaction-pay-controller": "^23.7.0", - "@metamask/tron-wallet-snap": "^1.25.6", + "@metamask/tron-wallet-snap": "^1.26.0", "@metamask/utils": "^11.11.0", "@metamask/wallet": "^3.0.0", "@myx-trade/sdk": "^0.1.265", diff --git a/yarn.lock b/yarn.lock index 4cd367aedf2..1a652a447ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10423,10 +10423,10 @@ __metadata: languageName: node linkType: hard -"@metamask/tron-wallet-snap@npm:^1.25.6": - version: 1.25.8 - resolution: "@metamask/tron-wallet-snap@npm:1.25.8" - checksum: 10/c533b566360b1587865b2e8f74125a301c348e6baa5a721e5629080b03fc47067b0275bec26183863ab5575a812bac8946c4fa1ac5c3daa645faec16b7ab3368 +"@metamask/tron-wallet-snap@npm:^1.26.0": + version: 1.26.0 + resolution: "@metamask/tron-wallet-snap@npm:1.26.0" + checksum: 10/ba7dc5d4bdae9f0a5c346744ea5eda311a1301a390c8ba3eedee4c99bf29d7d4937c65607198dcedda760223f07363638026e2649912123c4f89460de10906b4 languageName: node linkType: hard @@ -35432,7 +35432,7 @@ __metadata: "@metamask/test-dapp-solana": "npm:^0.3.0" "@metamask/transaction-controller": "npm:^68.0.0" "@metamask/transaction-pay-controller": "npm:^23.7.0" - "@metamask/tron-wallet-snap": "npm:^1.25.6" + "@metamask/tron-wallet-snap": "npm:^1.26.0" "@metamask/utils": "npm:^11.11.0" "@metamask/wallet": "npm:^3.0.0" "@myx-trade/sdk": "npm:^0.1.265" From 4f74e16cf35d2c80031e6f0f82969145c7f30a3f Mon Sep 17 00:00:00 2001 From: cmd-ob Date: Tue, 16 Jun 2026 16:27:47 +0100 Subject: [PATCH 11/23] test: migrate import-srp and delete-account smoke tests to Appium (#31803) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Migrates `import-srp` and `delete-account` from Detox (`SmokeWalletPlatform`) to Appium (`SmokeAccounts`) as part of the ongoing smoke-test framework migration. Changes include: - New Appium specs under `tests/smoke-appium/accounts/` - Removal of the Detox counterparts from `tests/smoke/wallet/` and `tests/smoke/multichain-accounts/` - Cross-framework fixes in `ImportSrpView` (replaces `device.getPlatform()` with `PlatformDetector`, adds Appium iOS seed-phrase input handling) - New `iosAppiumXPath` selector variant in `resolve()` for platform-specific iOS locators ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: Detox-to-Appium SmokeAccounts migration — test infrastructure only ## **Manual testing steps** ```gherkin Feature: SmokeAccounts Appium account flows Scenario: import SRP account on Android Given a device with the Appium smoke test runner When I run the import-srp Appium spec on Android Then the test imports an SRP and verifies Account 1 is selected Scenario: delete account on iOS Given a device with the Appium smoke test runner When I run the delete-account Appium spec on iOS Then the test deletes the imported account and verifies it is removed from the account list ``` ## **Screenshots/Recordings** ### **Before** N/A — E2E test migration only; no user-facing UI changes. ### **After** N/A — E2E test migration only; no user-facing UI changes. ## **Pre-merge author checklist** - [x] I've followed [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Style](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/coding-style.md) - [x] I've completed the PR template and read the [Ready for review](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/ready-for-review.md) guide - [x] I've included tests if applicable and/or updated snapshots - [x] I've documented my code with [JSDoc](https://jsdoc.app/) if applicable - [x] I've applied the right labels for this PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)) #### Performance checks (if applicable) - [x] I tested on an Android device or emulator and timing performance was acceptable - [x] I tested this change with the `power user` performance scenario and timing performance was acceptable - [x] I instrumented this change with Sentry traces if applicable ## **Pre-merge reviewer checklist** - [ ] I've followed the [MetaMask Contributor Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile Coding Style](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/coding-style.md) - [ ] I've read the [How to review a MetaMask Mobile PR](https://github.com/MetaMask/metamask-mobile/blob/main/docs/readme/reviewing.md) guide - [ ] I've checked what automated tests report, and I've considered whether this change should have caused any failures to resolve differently - [ ] I've manually tested the change, following the manual testing steps in the pull request description, and that what's being tested reflects the user's perspective, not the presence of the change itself - [ ] I've checked that any documentation linked from this PR, or that I expect to update from this change, is accurate and up to date Made with [Cursor](https://cursor.com) --- tests/framework/EncapsulatedElement.test.ts | 25 +++++ tests/framework/Selector.ts | 23 +++- tests/page-objects/importSrp/ImportSrpView.ts | 100 ++++++++++++++---- .../accounts/delete-account.spec.ts | 93 ++++++++++++++++ .../smoke-appium/accounts/import-srp.spec.ts | 44 ++++++++ .../delete-account.spec.ts | 68 ------------ tests/smoke/wallet/import-srp.spec.ts | 39 ------- 7 files changed, 262 insertions(+), 130 deletions(-) create mode 100644 tests/smoke-appium/accounts/delete-account.spec.ts create mode 100644 tests/smoke-appium/accounts/import-srp.spec.ts delete mode 100644 tests/smoke/multichain-accounts/delete-account.spec.ts delete mode 100644 tests/smoke/wallet/import-srp.spec.ts diff --git a/tests/framework/EncapsulatedElement.test.ts b/tests/framework/EncapsulatedElement.test.ts index 7c943090886..898d0f06345 100644 --- a/tests/framework/EncapsulatedElement.test.ts +++ b/tests/framework/EncapsulatedElement.test.ts @@ -781,6 +781,31 @@ describe('EncapsulatedElement', () => { }); }); + describe('{ detoxTestID, androidAppiumTestID, iosAppiumXPath }', () => { + it('calls EncapsulatedElement.create with ios xpath config', () => { + FrameworkDetector.setFramework(TestFramework.DETOX); + const spy = createSpyOnEncapsulatedCreate(); + spy.mockReturnValue(createMockDetoxElement()); + + resolve({ + detoxTestID: 'seed-phrase-input', + androidAppiumTestID: 'seed-phrase-input', + iosAppiumXPath: '//XCUIElementTypeOther[@name="textfield"]', + }); + + expect(spy).toHaveBeenCalledTimes(1); + const config = spy.mock.calls[0][0] as LocatorConfig; + expect(typeof config.detox).toBe('function'); + expect( + typeof (config.appium as { android: unknown; ios: unknown }).android, + ).toBe('function'); + expect( + typeof (config.appium as { android: unknown; ios: unknown }).ios, + ).toBe('function'); + spy.mockRestore(); + }); + }); + describe('{ testID, iosAppiumTestID }', () => { it('calls EncapsulatedElement.create with ios-override config', () => { FrameworkDetector.setFramework(TestFramework.DETOX); diff --git a/tests/framework/Selector.ts b/tests/framework/Selector.ts index 70da4248156..e2bed033395 100644 --- a/tests/framework/Selector.ts +++ b/tests/framework/Selector.ts @@ -14,6 +14,11 @@ export type Selector = androidAppiumTestID: string; iosAppiumTestID: string; } + | { + detoxTestID: string; + androidAppiumTestID: string; + iosAppiumXPath: string; + } | { testID: string; iosAppiumTestID: string; index?: number }; /** @@ -21,6 +26,21 @@ export type Selector = * This can also be used in the original Matchers, Assertions, and Gestures methods that currently return DetoxElements to make them cross-framework compatible without page-object changes. */ export function resolve(selector: Selector): EncapsulatedElementType { + if ('iosAppiumXPath' in selector) { + return encapsulated({ + detox: () => + element(by.id(selector.detoxTestID)) as unknown as DetoxElement, + appium: { + android: () => + PlaywrightMatchers.getElementById(selector.androidAppiumTestID, { + exact: true, + }), + ios: () => + PlaywrightMatchers.getElementByXPath(selector.iosAppiumXPath), + }, + }); + } + if ('androidAppiumTestID' in selector) { return encapsulated({ detox: () => @@ -149,6 +169,7 @@ export function isSelector(value: unknown): value is Selector { 'text' in v || 'detoxTestID' in v || 'androidAppiumTestID' in v || - 'iosAppiumTestID' in v + 'iosAppiumTestID' in v || + 'iosAppiumXPath' in v ); } diff --git a/tests/page-objects/importSrp/ImportSrpView.ts b/tests/page-objects/importSrp/ImportSrpView.ts index 1695e45f80b..2c009babfd7 100644 --- a/tests/page-objects/importSrp/ImportSrpView.ts +++ b/tests/page-objects/importSrp/ImportSrpView.ts @@ -1,6 +1,14 @@ import Matchers from '../../framework/Matchers'; import Gestures from '../../framework/Gestures'; -import { EncapsulatedElementType } from '../../framework/EncapsulatedElement'; +import { + asDetoxElement, + EncapsulatedElementType, +} from '../../framework/EncapsulatedElement'; +import { PlatformDetector } from '../../framework/PlatformLocator'; +import { encapsulatedAction } from '../../framework/encapsulatedAction'; +import { resolve } from '../../framework/Selector'; +import UnifiedGestures from '../../framework/UnifiedGestures'; +import PlaywrightGestures from '../../framework/PlaywrightGestures'; import { ImportSRPIDs } from '../../../app/components/Views/ImportNewSecretRecoveryPhrase/SRPImport.testIds'; class ImportSrpView { @@ -20,13 +28,25 @@ class ImportSrpView { return Matchers.getElementByID(ImportSRPIDs.SEED_PHRASE_INPUT_ID); } - seedPhraseInput(index: number): EncapsulatedElementType { - if (index !== 0) { - return Matchers.getElementByID( - `${ImportSRPIDs.SEED_PHRASE_INPUT_ID}_${index}`, - ); + private getAppiumIosSeedPhraseXPath(index: number): string { + if (index === 0) { + return '//XCUIElementTypeOther[@name="textfield"]'; } - return Matchers.getElementByID(ImportSRPIDs.SEED_PHRASE_INPUT_ID); + + return `//XCUIElementTypeOther[@name="textfield" and @label="${index + 1}."]`; + } + + seedPhraseInput(index: number): EncapsulatedElementType { + const testID = + index === 0 + ? ImportSRPIDs.SEED_PHRASE_INPUT_ID + : `${ImportSRPIDs.SEED_PHRASE_INPUT_ID}_${index}`; + + return resolve({ + detoxTestID: testID, + androidAppiumTestID: testID, + iosAppiumXPath: this.getAppiumIosSeedPhraseXPath(index), + }); } async tapTitle() { @@ -42,21 +62,57 @@ class ImportSrpView { } async enterSrp(mnemonic: string): Promise { - if (device.getPlatform() === 'ios') { - const srpArray = mnemonic.split(' '); - for (const [i, word] of srpArray.entries()) { - await Gestures.typeText(this.seedPhraseInput(i), `${word} `, { - elemDescription: 'Import SRP Secret Recovery Phrase Input Box', - hideKeyboard: i === srpArray.length - 1, - }); - } - await this.tapTitle(); - } else { - await Gestures.replaceText(this.textareaInput, mnemonic, { - elemDescription: 'SRP textarea input', - checkVisibility: false, - }); - } + const srpArray = mnemonic.split(' '); + + await encapsulatedAction({ + detox: async () => { + if (PlatformDetector.isIOS()) { + for (const [i, word] of srpArray.entries()) { + await Gestures.typeText( + asDetoxElement(this.seedPhraseInput(i)), + `${word} `, + { + elemDescription: 'Import SRP Secret Recovery Phrase Input Box', + hideKeyboard: i === srpArray.length - 1, + }, + ); + } + await this.tapTitle(); + return; + } + + await Gestures.replaceText( + asDetoxElement(this.textareaInput), + mnemonic, + { + elemDescription: 'SRP textarea input', + checkVisibility: false, + }, + ); + }, + appium: async () => { + if (PlatformDetector.isAndroid()) { + await UnifiedGestures.replaceText(this.seedPhraseInput(0), mnemonic, { + description: 'Import SRP Secret Recovery Phrase Input Box', + }); + return; + } + + for (const [i, word] of srpArray.entries()) { + const suffix = i === srpArray.length - 1 ? '' : ' '; + await UnifiedGestures.typeText( + this.seedPhraseInput(i), + `${word}${suffix}`, + { + description: 'Import SRP Secret Recovery Phrase Input Box', + waitForInteractive: true, + postEnabledSettleMs: 500, + }, + ); + } + await PlaywrightGestures.hideKeyboard(); + }, + }); } } diff --git a/tests/smoke-appium/accounts/delete-account.spec.ts b/tests/smoke-appium/accounts/delete-account.spec.ts new file mode 100644 index 00000000000..8e4800e45fc --- /dev/null +++ b/tests/smoke-appium/accounts/delete-account.spec.ts @@ -0,0 +1,93 @@ +import { test as appiumTest } from '../../framework/fixtures/playwright/index.js'; +import { SmokeAccounts } from '../../tags.js'; +import { + SIMPLE_KEYPAIR_ACCOUNT, + goToAccountDetailsV2, +} from '../../helpers/multichain-accounts/common.js'; +import AccountDetails from '../../page-objects/MultichainAccounts/AccountDetails.js'; +import DeleteAccount from '../../page-objects/MultichainAccounts/DeleteAccount.js'; +import Assertions from '../../framework/Assertions.js'; +import Matchers from '../../framework/Matchers.js'; +import WalletView from '../../page-objects/wallet/WalletView.js'; +import AccountListBottomSheet from '../../page-objects/wallet/AccountListBottomSheet.js'; +import FixtureBuilder from '../../framework/fixtures/FixtureBuilder.js'; +import { withFixtures } from '../../framework/fixtures/FixtureHelper.js'; +import { loginToAppPlaywright } from '../../flows/wallet.flow.js'; +import { Mockttp } from 'mockttp'; +import { setupMockRequest } from '../../api-mocking/helpers/mockHelpers.js'; +import { Utilities } from '../../framework/index.js'; + +const deleteAccount = async () => { + await AccountDetails.tapDeleteAccountLink(); + await Assertions.expectElementToBeVisible(DeleteAccount.container); + await DeleteAccount.tapDeleteAccount(); +}; + +const assertAccountCount = async ( + accountName: string, + expectedCount: number, +): Promise => { + await Utilities.executeWithRetry( + async () => { + const accountElements = + await AccountListBottomSheet.getAccountElementsByAccountNameV2( + accountName, + ); + return accountElements.length === expectedCount; + }, + { + description: `Count accounts with name "${accountName}" in the account list`, + timeout: 5000, + interval: 500, + }, + ); +}; + +appiumTest.describe( + SmokeAccounts('Multichain Accounts: Account Details'), + () => { + appiumTest( + 'deletes the account', + async ({ driver: _driver, currentDeviceDetails }) => { + await withFixtures( + { + fixture: new FixtureBuilder() + .withImportedHdKeyringAndTwoDefaultAccountsSimpleKeyPairAccount() + .build(), + restartDevice: true, + currentDeviceDetails, + testSpecificMock: async (mockServer: Mockttp) => { + await setupMockRequest(mockServer, { + requestMethod: 'GET', + url: /^https:\/\/api\.merkl\.xyz\/v4\/users\/[a-zA-Z0-9]+\/rewards(\?|$)/, + response: [], + responseCode: 200, + }); + }, + }, + async () => { + await loginToAppPlaywright({ scenarioType: 'e2e' }); + await WalletView.tapIdenticon(); + + await Assertions.expectElementToBeVisible( + AccountListBottomSheet.accountList, + ); + + await assertAccountCount('Imported Account 1', 1); + + await goToAccountDetailsV2({ + ...SIMPLE_KEYPAIR_ACCOUNT, + index: 2, + }); + await deleteAccount(); + // Go back to account list + await WalletView.tapIdenticon(); + + // Assert that the account is no longer present in the account list + await assertAccountCount('Imported Account 1', 0); + }, + ); + }, + ); + }, +); diff --git a/tests/smoke-appium/accounts/import-srp.spec.ts b/tests/smoke-appium/accounts/import-srp.spec.ts new file mode 100644 index 00000000000..f2b3aff7ac1 --- /dev/null +++ b/tests/smoke-appium/accounts/import-srp.spec.ts @@ -0,0 +1,44 @@ +import { test as appiumTest } from '../../framework/fixtures/playwright/index.js'; +import { SmokeAccounts } from '../../tags.js'; +import { loginToAppPlaywright } from '../../flows/wallet.flow.js'; +import FixtureBuilder from '../../framework/fixtures/FixtureBuilder.js'; +import { withFixtures } from '../../framework/fixtures/FixtureHelper.js'; +import WalletView from '../../page-objects/wallet/WalletView.js'; +import Assertions from '../../framework/Assertions.js'; +import ImportSrpView from '../../page-objects/importSrp/ImportSrpView.js'; +import { goToImportSrp, inputSrp } from '../../flows/accounts.flow.js'; +import { IDENTITY_TEAM_SEED_PHRASE } from '../../smoke/identity/utils/constants.js'; + +// We now have account indexes "per wallets", thus the new account for that new SRP (wallet), will +// be: "Account 1". +const IMPORTED_ACCOUNT_NAME = 'Account 1'; + +appiumTest.describe(SmokeAccounts('Multichain import SRP account'), () => { + appiumTest( + 'should import account with SRP', + async ({ driver: _driver, currentDeviceDetails }) => { + await withFixtures( + { + fixture: new FixtureBuilder() + .withImportedHdKeyringAndTwoDefaultAccountsOneImportedHdAccountKeyringController() + .build(), + restartDevice: true, + currentDeviceDetails, + }, + async () => { + await loginToAppPlaywright({ scenarioType: 'e2e' }); + await goToImportSrp(); + await inputSrp(IDENTITY_TEAM_SEED_PHRASE); + await ImportSrpView.tapImportButton(); + await Assertions.expectElementToHaveText( + WalletView.accountName, + IMPORTED_ACCOUNT_NAME, + { + description: `Expect selected account to be ${IMPORTED_ACCOUNT_NAME}`, + }, + ); + }, + ); + }, + ); +}); diff --git a/tests/smoke/multichain-accounts/delete-account.spec.ts b/tests/smoke/multichain-accounts/delete-account.spec.ts deleted file mode 100644 index 7296750b710..00000000000 --- a/tests/smoke/multichain-accounts/delete-account.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { SmokeWalletPlatform } from '../../tags'; -import { - SIMPLE_KEYPAIR_ACCOUNT, - goToAccountDetailsV2, -} from '../../helpers/multichain-accounts/common'; -import AccountDetails from '../../page-objects/MultichainAccounts/AccountDetails'; -import DeleteAccount from '../../page-objects/MultichainAccounts/DeleteAccount'; -import Assertions from '../../framework/Assertions'; -import Matchers from '../../framework/Matchers'; -import WalletView from '../../page-objects/wallet/WalletView'; -import TestHelpers from '../../helpers'; -import AccountListBottomSheet from '../../page-objects/wallet/AccountListBottomSheet'; -import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; -import { withFixtures } from '../../framework/fixtures/FixtureHelper'; -import { loginToApp } from '../../flows/wallet.flow'; -import { Mockttp } from 'mockttp'; -import { setupMockRequest } from '../../api-mocking/helpers/mockHelpers'; - -const deleteAccount = async () => { - await AccountDetails.tapDeleteAccountLink(); - await Assertions.expectElementToBeVisible(DeleteAccount.container); - await DeleteAccount.tapDeleteAccount(); -}; - -describe(SmokeWalletPlatform('Multichain Accounts: Account Details'), () => { - beforeEach(async () => { - await TestHelpers.reverseServerPort(); - }); - - it('deletes the account', async () => { - await withFixtures( - { - fixture: new FixtureBuilder() - .withImportedHdKeyringAndTwoDefaultAccountsSimpleKeyPairAccount() - .build(), - restartDevice: true, - testSpecificMock: async (mockServer: Mockttp) => { - await setupMockRequest(mockServer, { - requestMethod: 'GET', - url: /^https:\/\/api\.merkl\.xyz\/v4\/users\/[a-zA-Z0-9]+\/rewards(\?|$)/, - response: [], - responseCode: 200, - }); - }, - }, - async () => { - await loginToApp(); - await WalletView.tapIdenticon(); - - await Assertions.expectElementToBeVisible( - AccountListBottomSheet.accountList, - ); - - await goToAccountDetailsV2({ - ...SIMPLE_KEYPAIR_ACCOUNT, - index: 2, - }); - await deleteAccount(); - // Go back to account list - await WalletView.tapIdenticon(); - - const importedAccountsSection = - Matchers.getElementByText('Imported Accounts'); - await Assertions.expectElementToNotBeVisible(importedAccountsSection); - }, - ); - }); -}); diff --git a/tests/smoke/wallet/import-srp.spec.ts b/tests/smoke/wallet/import-srp.spec.ts deleted file mode 100644 index 9e765d4cc75..00000000000 --- a/tests/smoke/wallet/import-srp.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { SmokeWalletPlatform } from '../../tags'; -import FixtureBuilder from '../../framework/fixtures/FixtureBuilder'; -import { withFixtures } from '../../framework/fixtures/FixtureHelper'; -import WalletView from '../../page-objects/wallet/WalletView'; -import { loginToApp } from '../../flows/wallet.flow'; -import Assertions from '../../framework/Assertions'; -import ImportSrpView from '../../page-objects/importSrp/ImportSrpView'; -import { goToImportSrp, inputSrp } from '../../flows/accounts.flow'; -import { IDENTITY_TEAM_SEED_PHRASE } from '../identity/utils/constants'; - -// We now have account indexes "per wallets", thus the new account for that new SRP (wallet), will -// be: "Account 1". -const IMPORTED_ACCOUNT_NAME = 'Account 1'; - -describe(SmokeWalletPlatform('Multichain import SRP account'), () => { - it('should import account with SRP', async () => { - await withFixtures( - { - fixture: new FixtureBuilder() - .withImportedHdKeyringAndTwoDefaultAccountsOneImportedHdAccountKeyringController() - .build(), - restartDevice: true, - }, - async () => { - await loginToApp(); - await goToImportSrp(); - await inputSrp(IDENTITY_TEAM_SEED_PHRASE); - await ImportSrpView.tapImportButton(); - await Assertions.expectElementToHaveText( - WalletView.accountName, - IMPORTED_ACCOUNT_NAME, - { - description: `Expect selected account to be ${IMPORTED_ACCOUNT_NAME}`, - }, - ); - }, - ); - }); -}); From 8e744129b16ed73224fb9a3cc54bcfbea391e312 Mon Sep 17 00:00:00 2001 From: sahar-fehri Date: Tue, 16 Jun 2026 16:27:56 +0100 Subject: [PATCH 12/23] fix: percentage calculation token details page (#31129) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The price change percentage shown on the Token Details page frequently diverges from the Trending page percentage, sometimes dramatically. This PR addresses the client-side root causes. ### Fix 1 — Defensive sort for historical prices (`useTokenHistoricalPrices.ts`) The historical-prices API occasionally returns data in reverse chronological order (newest-first). Since the client uses `prices[0]` as the 24h-ago baseline, reverse-sorted data makes the baseline equal the *current* price, yielding 0% or near-0% change. A defensive sort ensures `prices[0]` is always the oldest entry. ### Fix 2 — Use spot-prices percentage for legacy chart instead of deriving from historical prices (`useTokenPrice.ts`, `exchange-rates.ts`) The legacy chart derived its percentage from `currentPrice - historicalPrices[0]`. For newly-listed or volatile tokens, the `historical-prices` API can return incomplete data (e.g. only 10 hours of data when 24 hours is requested), causing inaccurate percentages. The spot-prices API (`v3/spot-prices`) already returns pre-computed percentage changes (`pricePercentChange1d`, `pricePercentChange7d`, `pricePercentChange30d`, `pricePercentChange1y`); the same values the Trending page displays. However, these fields were being discarded: - **EVM path**: The core `fetchTokenContractExchangeRates` function fetched full market data but stripped everything except `.price` in its final reduce - **Non-EVM path**: `fetchTokenExchangeRates` called the same API but only extracted `.price`, discarding percentage fields **What changed:** - **Core (`@metamask/assets-controllers`)**: Added optional `includeMarketData` parameter to `fetchTokenContractExchangeRates`. When `true`, returns full `MarketDataDetails` (including percentage changes) instead of price-only. Defaults to `false` for backward compatibility. ([core PR #9042](https://github.com/MetaMask/core/pull/9042)) - **Mobile (`exchange-rates.ts`)**: Added `includeMarketData` flag to `fetchTokenExchangeRates` and `getTokenExchangeRate`. Non-EVM branch now preserves the full API response when the flag is set. Removed the redundant `getTokenSpotPriceWithMarketData` function. - **Mobile (`useTokenPrice.ts`)**: Single `useEffect` now calls `getTokenExchangeRate({ includeMarketData: true })` to get both the price and percentage data in one API call. For supported time ranges (1D, 1W, 1M, 1Y), the spot-prices percentage overrides the historical-prices-derived one. For imported tokens, reads percentage from Redux (already available via `TokenRatesController`). Unsupported ranges (3M, 3Y, All) fall back to the historical-prices derivation. ### Fix 3 — Tighten "no data" overlay for legacy chart with insufficient time coverage (`useTokenHistoricalPrices.ts`, `PriceChart.tsx`) Previously the chart only checked if the API returned at least 5 data points before rendering. This meant a 1D request that returned only 10 hours of data (many data points but covering less than half the requested period) would still render a misleading chart. **What changed:** - **`useTokenHistoricalPrices.ts`**: Added a `hasInsufficientTimeCoverage()` check that compares the actual time span of returned data against the expected duration for each time period (1D = 24h, 1W = 7d, etc.). If the data covers less than **95%** of the expected duration, the hook sets `hasInsufficientCoverage: true`. HTTP 204 (no content) responses also set the flag. - **`PriceChart.tsx`**: The "no data" overlay now also shows when `hasInsufficientCoverage` is true, even if there are 5+ data points. - The flag is threaded through `useTokenPrice` → `TokenDetails` → `AssetOverviewContent` → `Price` → `PriceLegacy`/`PriceAdvanced` → `PriceChart`. ## Example SpaceX on Base — Reverse-sorted historical data (Fix 1) + Incomplete historical data (Fix 2) **Trending page shows:** `+98,964%` **Token Details (legacy chart) before fix:** `-80%` (or `-0.00%` with reverse-sorted data) The `historical-prices` API returned only ~10 hours of data for this newly-listed token, starting after the major pump. Using `historicalPrices[0]` as the baseline gave a post-pump price, making the percentage wildly incorrect. **After fix:** Uses `pricePercentChange1d` from the spot-prices API (same source as Trending page) → `+98,720%` ✅ ## **Changelog** CHANGELOG entry: Fixed percentage mismatch between Trending page and Token Details page caused by reverse-sorted historical price data, discarded spot-prices percentage fields for both EVM and non-EVM tokens, and added 95% time-coverage check to show "no data" overlay for incomplete historical data ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3288 ## **Manual testing steps** ```gherkin Feature: Token Details percentage accuracy Scenario: Legacy chart percentage matches trending page for newly-listed tokens Given user is on the Trending page and sees a newly listed token (e.g. on Base chain) When user taps into Token Details and the legacy chart loads Then the displayed percentage should closely match the trending percentage And the amount change should be consistent with the percentage Scenario: Non-EVM token percentage matches trending page Given user is on the Trending page filtered to Solana When user taps a trending Solana token into Token Details Then the displayed 1D percentage should match the trending percentage Scenario: Switching time ranges works correctly Given user is on Token Details for any token When user switches between 1D, 1W, 1M, 1Y time ranges Then each range should show the spot-prices-derived percentage And 3M, 3Y, All should fall back to historical-prices-derived percentage Scenario: Insufficient time coverage shows no-data overlay Given the historical-prices API returns less than 95% of the requested time period When user is on Token Details for a newly-listed token on 1D Then the chart should show the "No chart data" overlay instead of a partial chart Scenario: Stable tokens remain unaffected Given user is on the Trending page and sees a major token (e.g. SOL, ETH) When user taps into Token Details Then the percentage should remain within 0-2% of the trending percentage (unchanged behavior) ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- > [!NOTE] > **Medium Risk** > Touches token pricing UX across legacy/advanced charts and exchange-rate fetching; incorrect coverage or spot-% override could still mislead users, but behavior is guarded by tests and falls back to historical derivation for unsupported ranges. > > **Overview** > Aligns Token Details price-change % and legacy chart behavior with Trending by fixing historical-price handling and using spot-prices market data. > > **Historical prices:** `useTokenHistoricalPrices` now sorts API results chronologically, exports `hasInsufficientTimeCoverage()` (95% of the requested period), sets `hasInsufficientCoverage` on short spans and HTTP 204, and threads that flag through `useTokenPrice` → `PriceChart`, which shows the insufficient-data overlay even when there are enough points. > > **Spot-prices %:** `fetchTokenExchangeRates` / `getTokenExchangeRate` gain optional `includeMarketData`; `useTokenPrice` fetches full market data for non-imported tokens (with a fetch-id guard on token switch) and overrides `priceDiff` / `comparePrice` from Redux or API fields (`pricePercentChange1d`, etc.) for 1D/1W/1M/1Y. Bridge Redux only stores numeric rates when the payload is a number. `@metamask/assets-controllers` bumps to **^109.1.0**. > > **Tests:** Coverage for coverage math, chart overlay, exchange-rate call signatures, stale fetch clearing, and advanced-chart OHLCV mocks aligned to **prevBar** baseline. > > Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit f1665a5d60c23e94881e5ef9f071db67beb9e20f. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot). --- .../Price/Price.advanced.test.tsx | 42 ++++-- .../UI/AssetOverview/Price/Price.advanced.tsx | 3 + .../UI/AssetOverview/Price/Price.legacy.tsx | 3 + .../UI/AssetOverview/Price/Price.tsx | 1 + .../PriceChart/PriceChart.test.tsx | 27 ++++ .../AssetOverview/PriceChart/PriceChart.tsx | 13 +- .../UI/Bridge/utils/exchange-rates.test.tsx | 11 +- .../UI/Bridge/utils/exchange-rates.ts | 67 ++++++--- .../UI/TokenDetails/Views/TokenDetails.tsx | 2 + .../components/AssetOverviewContent.tsx | 3 + .../TokenDetails/hooks/useTokenPrice.test.ts | 85 +++++++++++- .../UI/TokenDetails/hooks/useTokenPrice.ts | 127 +++++++++++++++--- .../hooks/useTokenHistoricalPrices.test.ts | 106 +++++++++++++++ .../hooks/useTokenHistoricalPrices.ts | 63 ++++++++- app/core/redux/slices/bridge/index.ts | 8 +- docs/readme/e2e-testing.md | 1 + package.json | 2 +- .../mock-responses/defaults/price-apis.ts | 66 ++++++++- yarn.lock | 2 +- 19 files changed, 564 insertions(+), 68 deletions(-) create mode 100644 app/components/hooks/useTokenHistoricalPrices.test.ts diff --git a/app/components/UI/AssetOverview/Price/Price.advanced.test.tsx b/app/components/UI/AssetOverview/Price/Price.advanced.test.tsx index c622c906f53..81ed4511ad8 100644 --- a/app/components/UI/AssetOverview/Price/Price.advanced.test.tsx +++ b/app/components/UI/AssetOverview/Price/Price.advanced.test.tsx @@ -372,7 +372,7 @@ describe('PriceAdvanced', () => { }); it('calculates percentage from OHLCV close price of the reference candle', () => { - // Reference candle close = 100, current price = 105 + // prevBar close = 100, current price = 105 // Expected: (105 - 100) / 100 * 100 = 5.00% const now = Date.now(); const oneDayAgo = now - 24 * 60 * 60 * 1000; @@ -398,7 +398,7 @@ describe('PriceAdvanced', () => { open: 1, high: 1, low: 1, - close: 1, + close: 100, volume: 1, }, ]; @@ -455,7 +455,7 @@ describe('PriceAdvanced', () => { }); it('updates percentage when time range changes and new OHLCV data loads', () => { - // Initial: reference candle close = 100, current price = 105 + // Initial: prevBar close = 100, current price = 105 // Expected: (105 - 100) / 100 * 100 = 5.00% const now = Date.now(); const oneDayAgo = now - 24 * 60 * 60 * 1000; @@ -481,7 +481,7 @@ describe('PriceAdvanced', () => { open: 1, high: 1, low: 1, - close: 1, + close: 100, volume: 1, }, ]; @@ -519,11 +519,12 @@ describe('PriceAdvanced', () => { expect(getByText(/5\.00%/)).toBeOnTheScreen(); - // After time range change: reference candle close = 103, current = 105 + // After time range change: prevBar close = 103, current = 105 // Expected: (105 - 103) / 103 * 100 = 1.94% mockUseOHLCVChart.mockReturnValueOnce({ ohlcvData: [ - ...ohlcvPadBefore, + ...ohlcvPadBefore.slice(0, -1), + { ...ohlcvPadBefore[2], close: 103 }, { time: oneDayAgo, open: 102, @@ -554,7 +555,7 @@ describe('PriceAdvanced', () => { }); it('displays price diff when dynamicComparePrice is 0', () => { - // Edge case: reference candle close is 0 — should still render, not hide + // Edge case: prevBar close is 0 — should still render, not hide const now = Date.now(); const oneDayAgo = now - 24 * 60 * 60 * 1000; const ohlcvPadBefore = [ @@ -579,7 +580,7 @@ describe('PriceAdvanced', () => { open: 1, high: 1, low: 1, - close: 1, + close: 0, volume: 1, }, ]; @@ -648,13 +649,13 @@ describe('PriceAdvanced', () => { close: 200, volume: 1, }, - // 2 days ago — still before visible range, should be skipped + // 2 days ago — prevBar (last candle before visible range) { time: lastBarTime - 2 * oneDayMs, open: 190, high: 195, low: 185, - close: 190, + close: 100, volume: 1, }, // ~24h ago — first candle in visible range (close = 100) @@ -1047,12 +1048,19 @@ describe('PriceAdvanced', () => { // lastBarTime = 100000000, visibleFromMs = 13600000 // First visible candle at time 20000000 has close=100 // Last candle has close=95 - // displayDiff = 95 - 100 = -5 (negative) + // prevBar.close = 100, displayPrice = 95, diff = -5 (negative) mockUseOHLCVChart.mockReturnValueOnce({ ohlcvData: [ { time: 1000000, open: 90, high: 91, low: 89, close: 90, volume: 1 }, { time: 2000000, open: 90, high: 91, low: 89, close: 91, volume: 1 }, - { time: 3000000, open: 91, high: 92, low: 90, close: 92, volume: 1 }, + { + time: 3000000, + open: 91, + high: 101, + low: 90, + close: 100, + volume: 1, + }, { time: 20000000, open: 100, @@ -1108,11 +1116,19 @@ describe('PriceAdvanced', () => { const mockOnPriceDirectionChange = jest.fn(); // Mock OHLCV data with negative price movement + // prevBar.close = 100, lastBar.close = 95 → negative diff mockUseOHLCVChart.mockReturnValueOnce({ ohlcvData: [ { time: 1000000, open: 90, high: 91, low: 89, close: 90, volume: 1 }, { time: 2000000, open: 90, high: 91, low: 89, close: 91, volume: 1 }, - { time: 3000000, open: 91, high: 92, low: 90, close: 92, volume: 1 }, + { + time: 3000000, + open: 91, + high: 101, + low: 90, + close: 100, + volume: 1, + }, { time: 20000000, open: 100, diff --git a/app/components/UI/AssetOverview/Price/Price.advanced.tsx b/app/components/UI/AssetOverview/Price/Price.advanced.tsx index 75482775c59..7bb681c43d0 100644 --- a/app/components/UI/AssetOverview/Price/Price.advanced.tsx +++ b/app/components/UI/AssetOverview/Price/Price.advanced.tsx @@ -135,6 +135,7 @@ export interface PriceAdvancedProps { setTimePeriod?: (period: TimePeriod) => void; onPriceDirectionChange?: (isPositive: boolean) => void; useAmbientColor?: boolean; + hasInsufficientCoverage?: boolean; } const PriceAdvanced = ({ @@ -150,6 +151,7 @@ const PriceAdvanced = ({ setTimePeriod, onPriceDirectionChange, useAmbientColor = false, + hasInsufficientCoverage = false, }: PriceAdvancedProps) => { const dispatch = useDispatch(); const { trackEvent, createEventBuilder } = useAnalytics(); @@ -559,6 +561,7 @@ const PriceAdvanced = ({ isLoading={isLoading} onPriceDirectionChange={onPriceDirectionChange} useAmbientColor={useAmbientColor} + hasInsufficientCoverage={hasInsufficientCoverage} /> ); } diff --git a/app/components/UI/AssetOverview/Price/Price.legacy.tsx b/app/components/UI/AssetOverview/Price/Price.legacy.tsx index 0797416f29e..7f66a3c5b00 100644 --- a/app/components/UI/AssetOverview/Price/Price.legacy.tsx +++ b/app/components/UI/AssetOverview/Price/Price.legacy.tsx @@ -39,6 +39,7 @@ export interface PriceLegacyProps { onTimePeriodChange?: (period: TimePeriod) => void; onPriceDirectionChange?: (isPositive: boolean) => void; useAmbientColor?: boolean; + hasInsufficientCoverage?: boolean; } const PriceLegacy = ({ @@ -53,6 +54,7 @@ const PriceLegacy = ({ onTimePeriodChange, onPriceDirectionChange, useAmbientColor = false, + hasInsufficientCoverage = false, }: PriceLegacyProps) => { const [activeChartIndex, setActiveChartIndex] = useState(-1); @@ -223,6 +225,7 @@ const PriceLegacy = ({ isLoading={isLoading} onChartIndexChange={handleChartInteraction} chartColorOverride={initialAmbientColor} + hasInsufficientCoverage={hasInsufficientCoverage} /> {chartNavigationButtons.length > 0 && onTimePeriodChange && ( diff --git a/app/components/UI/AssetOverview/Price/Price.tsx b/app/components/UI/AssetOverview/Price/Price.tsx index 1f6524ccd97..6da2fa2553f 100644 --- a/app/components/UI/AssetOverview/Price/Price.tsx +++ b/app/components/UI/AssetOverview/Price/Price.tsx @@ -15,6 +15,7 @@ interface PriceSharedProps { currentCurrency: string; comparePrice: number; isLoading: boolean; + hasInsufficientCoverage?: boolean; } /** diff --git a/app/components/UI/AssetOverview/PriceChart/PriceChart.test.tsx b/app/components/UI/AssetOverview/PriceChart/PriceChart.test.tsx index a7889094150..8fbd2d1db88 100644 --- a/app/components/UI/AssetOverview/PriceChart/PriceChart.test.tsx +++ b/app/components/UI/AssetOverview/PriceChart/PriceChart.test.tsx @@ -118,6 +118,33 @@ describe('PriceChart', () => { queryByText('Data is not available for this time period'), ).not.toBeOnTheScreen(); }); + + it('shows overlay when hasInsufficientCoverage is true despite having enough points', () => { + const { getByTestId } = render( + , + ); + + expect(getByTestId('price-chart-insufficient-data')).toBeOnTheScreen(); + }); + + it('does not show overlay when hasInsufficientCoverage is false', () => { + const { queryByTestId } = render( + , + ); + + expect( + queryByTestId('price-chart-insufficient-data'), + ).not.toBeOnTheScreen(); + expect(queryByTestId('price-chart-no-data')).not.toBeOnTheScreen(); + }); }); describe('Loading state', () => { diff --git a/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx b/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx index 07d4553cf5d..f7c5610984f 100644 --- a/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx +++ b/app/components/UI/AssetOverview/PriceChart/PriceChart.tsx @@ -50,6 +50,12 @@ interface PriceChartProps { chartHeight?: number; /** Override line color (A/B test). */ chartColorOverride?: string; + /** + * When true, the historical-prices API returned data covering less than + * 75% of the requested time period. The chart shows a "no data" overlay + * instead of rendering a misleading partial chart. + */ + hasInsufficientCoverage?: boolean; } const PriceChart = ({ @@ -59,6 +65,7 @@ const PriceChart = ({ onChartIndexChange, chartHeight = TOKEN_OVERVIEW_CHART_HEIGHT, chartColorOverride, + hasInsufficientCoverage = false, }: PriceChartProps) => { const { trackEvent, createEventBuilder } = useAnalytics(); const emptyDisplayTrackedRef = useRef(false); @@ -128,9 +135,11 @@ const PriceChart = ({ }; }, [priceList]); - const chartHasData = priceList.length >= CHART_DATA_THRESHOLD; + const chartHasData = + priceList.length >= CHART_DATA_THRESHOLD && !hasInsufficientCoverage; const hasInsufficientData = - priceList.length > 0 && priceList.length < CHART_DATA_THRESHOLD; + (priceList.length > 0 && priceList.length < CHART_DATA_THRESHOLD) || + hasInsufficientCoverage; useEffect(() => { if (chartHasData || isLoading) { diff --git a/app/components/UI/Bridge/utils/exchange-rates.test.tsx b/app/components/UI/Bridge/utils/exchange-rates.test.tsx index fedb9fb257b..5a5fe712f1e 100644 --- a/app/components/UI/Bridge/utils/exchange-rates.test.tsx +++ b/app/components/UI/Bridge/utils/exchange-rates.test.tsx @@ -753,6 +753,7 @@ describe('exchange-rates', () => { const result = await fetchTokenExchangeRates( solanaChainId, currency, + undefined, ...tokenAddresses, ); @@ -771,6 +772,7 @@ describe('exchange-rates', () => { const result = await fetchTokenExchangeRates( solanaChainId, currency, + undefined, ...tokenAddresses, ); @@ -795,6 +797,7 @@ describe('exchange-rates', () => { const result = await fetchTokenExchangeRates( evmChainId, currency, + undefined, ...tokenAddresses, ); @@ -810,6 +813,7 @@ describe('exchange-rates', () => { const result = await fetchTokenExchangeRates( evmChainId, currency, + undefined, ...tokenAddresses, ); @@ -823,7 +827,12 @@ describe('exchange-rates', () => { new Error('API error'), ); - const result = await fetchTokenExchangeRates('0x1', 'USD', '0x123'); + const result = await fetchTokenExchangeRates( + '0x1', + 'USD', + undefined, + '0x123', + ); expect(result).toEqual({}); }); diff --git a/app/components/UI/Bridge/utils/exchange-rates.ts b/app/components/UI/Bridge/utils/exchange-rates.ts index 35ce83e6618..4ae5693a8d5 100644 --- a/app/components/UI/Bridge/utils/exchange-rates.ts +++ b/app/components/UI/Bridge/utils/exchange-rates.ts @@ -19,6 +19,7 @@ import { CodefiTokenPricesServiceV2, ContractMarketData, fetchTokenContractExchangeRates, + type MarketDataDetails, } from '@metamask/assets-controllers'; import { safeToChecksumAddress } from '../../../../util/address'; import { toAssetId } from '../hooks/useAssetMetadata/utils'; @@ -259,20 +260,24 @@ export const getDisplayCurrencyValue = ({ }; /** - * Fetches the exchange rates for the tokens against the current currency + * Fetches the exchange rates for the tokens against the current currency. * @param chainId - The chainId of the tokens * @param currency - The currency to fetch the exchange rates in + * @param options - Optional settings + * @param options.includeMarketData - When true, returns full MarketDataDetails + * per token instead of just the price number. * @param tokenAddresses - The addresses of the tokens to fetch the exchange rates for - * @returns Exchange rate for the tokens against the current currency + * @returns Exchange rates (or full market data) for the tokens */ export const fetchTokenExchangeRates = async ( chainId: Hex | CaipChainId, currency: string, + options?: { includeMarketData?: boolean }, ...tokenAddresses: string[] ) => { - try { - let exchangeRates: Record = {}; + const withMarketData = options?.includeMarketData === true; + try { // Non-EVM if (isNonEvmChainId(chainId) && isCaipChainId(chainId)) { const queryParams = new URLSearchParams({ @@ -285,17 +290,20 @@ export const fetchTokenExchangeRates = async ( const url = `https://price.api.cx.metamask.io/v3/spot-prices?${queryParams}`; const tokenV3PriceResponse = (await handleFetch(url)) as Record< string, - { price: number } + MarketDataDetails >; - exchangeRates = Object.entries(tokenV3PriceResponse).reduce( + if (withMarketData) { + return tokenV3PriceResponse; + } + + return Object.entries(tokenV3PriceResponse).reduce( (acc, [k, curr]) => { acc[k] = curr.price; return acc; }, {} as Record, ); - return exchangeRates; } // EVM chains @@ -306,12 +314,23 @@ export const fetchTokenExchangeRates = async ( return {}; } - exchangeRates = await fetchTokenContractExchangeRates({ + if (withMarketData) { + const marketData = await fetchTokenContractExchangeRates({ + tokenPricesService: new CodefiTokenPricesServiceV2(), + nativeCurrency: currency, + tokenAddresses: checksumAddresses as Hex[], + chainId: formatChainIdToHex(chainId), + includeMarketData: true, + }); + return marketData; + } + + const exchangeRates = (await fetchTokenContractExchangeRates({ tokenPricesService: new CodefiTokenPricesServiceV2(), nativeCurrency: currency, tokenAddresses: checksumAddresses as Hex[], chainId: formatChainIdToHex(chainId), - }); + })) as Record; return Object.keys(exchangeRates).reduce( (acc: Record, address) => { @@ -325,29 +344,35 @@ export const fetchTokenExchangeRates = async ( } }; -// This fetches the exchange rate for a token in a given currency. This is only called when the exchange -// rate is not available in the TokenRatesController, which happens when the selected token has not been -// imported into the wallet +/** + * Fetches the exchange rate for a single token. Only called when the rate is + * not available in the TokenRatesController (i.e. token is not imported). + * When includeMarketData is true, returns full MarketDataDetails instead of + * just the price number. + */ export const getTokenExchangeRate = async (request: { chainId: Hex | CaipChainId; tokenAddress: string; currency: string; + includeMarketData?: boolean; }) => { - const { chainId, tokenAddress, currency } = request; - const exchangeRates = await fetchTokenExchangeRates( + const { chainId, tokenAddress, currency, includeMarketData } = request; + + const result = (await fetchTokenExchangeRates( chainId, currency, + { includeMarketData }, tokenAddress, - ); + )) as Record; + const assetId = toAssetId(tokenAddress, formatChainIdToCaip(chainId)); if (isNonEvmChainId(chainId) && assetId) { - return exchangeRates?.[assetId]; + return result?.[assetId]; } - // The exchange rate can be checksummed or not, so we need to check both - const exchangeRate = - exchangeRates?.[toChecksumHexAddress(tokenAddress)] ?? - exchangeRates?.[tokenAddress.toLowerCase()]; - return exchangeRate; + return ( + result?.[toChecksumHexAddress(tokenAddress)] ?? + result?.[tokenAddress.toLowerCase()] + ); }; /** diff --git a/app/components/UI/TokenDetails/Views/TokenDetails.tsx b/app/components/UI/TokenDetails/Views/TokenDetails.tsx index 2f743dfefa2..24636ff4582 100644 --- a/app/components/UI/TokenDetails/Views/TokenDetails.tsx +++ b/app/components/UI/TokenDetails/Views/TokenDetails.tsx @@ -216,6 +216,7 @@ const TokenDetails: React.FC<{ timePeriod, setTimePeriod, chartNavigationButtons, + hasInsufficientCoverage, } = useTokenPrice({ token }); const [chartPricePositive, setChartPricePositive] = useState( @@ -316,6 +317,7 @@ const TokenDetails: React.FC<{ comparePrice={comparePrice} prices={prices} isLoading={isLoading} + hasInsufficientCoverage={hasInsufficientCoverage} timePeriod={timePeriod} setTimePeriod={setTimePeriod} chartNavigationButtons={chartNavigationButtons} diff --git a/app/components/UI/TokenDetails/components/AssetOverviewContent.tsx b/app/components/UI/TokenDetails/components/AssetOverviewContent.tsx index eea482074db..31404348232 100644 --- a/app/components/UI/TokenDetails/components/AssetOverviewContent.tsx +++ b/app/components/UI/TokenDetails/components/AssetOverviewContent.tsx @@ -164,6 +164,7 @@ export interface AssetOverviewContentProps { comparePrice: number; prices: TokenPrice[]; isLoading: boolean; + hasInsufficientCoverage?: boolean; timePeriod: TimePeriod; setTimePeriod: (period: TimePeriod) => void; @@ -234,6 +235,7 @@ const AssetOverviewContent: React.FC = ({ comparePrice, prices, isLoading, + hasInsufficientCoverage, timePeriod, setTimePeriod, chartNavigationButtons, @@ -752,6 +754,7 @@ const AssetOverviewContent: React.FC = ({ currentPrice={currentPrice} comparePrice={comparePrice} isLoading={isLoading} + hasInsufficientCoverage={hasInsufficientCoverage} onPriceDirectionChange={onPriceDirectionChange} useAmbientColor={useAmbientColor} /> diff --git a/app/components/UI/TokenDetails/hooks/useTokenPrice.test.ts b/app/components/UI/TokenDetails/hooks/useTokenPrice.test.ts index c511a7ea468..ae97562cb30 100644 --- a/app/components/UI/TokenDetails/hooks/useTokenPrice.test.ts +++ b/app/components/UI/TokenDetails/hooks/useTokenPrice.test.ts @@ -1,4 +1,4 @@ -import { renderHook, waitFor } from '@testing-library/react-native'; +import { renderHook, waitFor, act } from '@testing-library/react-native'; import { useSelector } from 'react-redux'; import { useTokenPrice } from './useTokenPrice'; import { TokenI } from '../../Tokens/types'; @@ -10,6 +10,7 @@ import { import { isAssetFromSearch } from '../../../../selectors/tokenSearchDiscoveryDataController'; import { selectTokenMarketData } from '../../../../selectors/tokenRatesController'; import useTokenHistoricalPrices from '../../../hooks/useTokenHistoricalPrices'; +import { getTokenExchangeRate } from '../../Bridge/utils/exchange-rates'; jest.mock('react-redux', () => ({ useSelector: jest.fn(), @@ -43,6 +44,7 @@ jest.mock('../../Bridge/utils/exchange-rates', () => ({ const mockUseSelector = jest.mocked(useSelector); const mockIsAssetFromSearch = jest.mocked(isAssetFromSearch); const mockUseTokenHistoricalPrices = jest.mocked(useTokenHistoricalPrices); +const mockGetTokenExchangeRate = jest.mocked(getTokenExchangeRate); describe('useTokenPrice', () => { const defaultCurrencyRates = { @@ -85,6 +87,7 @@ describe('useTokenPrice', () => { data: [], isLoading: false, error: undefined, + hasInsufficientCoverage: false, }); setupDefaultMocks(); }); @@ -103,6 +106,7 @@ describe('useTokenPrice', () => { isLoading: true, data: undefined, error: undefined, + hasInsufficientCoverage: false, }); const { result } = renderHook(() => useTokenPrice({ token })); @@ -135,6 +139,7 @@ describe('useTokenPrice', () => { ], isLoading: false, error: undefined, + hasInsufficientCoverage: false, }); const { result } = renderHook(() => useTokenPrice({ token })); @@ -209,6 +214,7 @@ describe('useTokenPrice', () => { data: [['1700000000', 145.0]], isLoading: false, error: undefined, + hasInsufficientCoverage: false, }); const { result } = renderHook(() => @@ -221,4 +227,81 @@ describe('useTokenPrice', () => { expect(result.current.comparePrice).toBe(145.0); expect(result.current.priceDiff).toBe(5.5); }); + + it('forwards hasInsufficientCoverage from the historical prices hook', async () => { + const token = { + address: '0x6b175474e89094c44da98b954eedeac495271d0f', + chainId: '0x1', + } as TokenI; + + mockUseTokenHistoricalPrices.mockReturnValue({ + data: [['1700000000', 1.0]], + isLoading: false, + error: undefined, + hasInsufficientCoverage: true, + }); + + const { result } = renderHook(() => useTokenPrice({ token })); + + await waitFor(() => { + expect(result.current.hasInsufficientCoverage).toBe(true); + }); + }); + + it('clears stale fetchedMarketData when token changes', async () => { + const tokenA = { + address: '0xaaaa', + chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', + } as TokenI; + const tokenB = { + address: '0xbbbb', + chainId: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', + } as TokenI; + + setupDefaultMocks(); + mockUseTokenHistoricalPrices.mockReturnValue({ + data: [], + isLoading: false, + error: undefined, + hasInsufficientCoverage: false, + }); + + let resolveA!: (v: unknown) => void; + let resolveB!: (v: unknown) => void; + + mockGetTokenExchangeRate + .mockImplementationOnce( + () => + new Promise((r) => { + resolveA = r as (v: unknown) => void; + }), + ) + .mockImplementationOnce( + () => + new Promise((r) => { + resolveB = r as (v: unknown) => void; + }), + ); + + const { rerender, result } = renderHook( + ({ token }: { token: TokenI }) => useTokenPrice({ token }), + { initialProps: { token: tokenA } }, + ); + + rerender({ token: tokenB }); + + await act(async () => { + resolveA({ price: 999, pricePercentChange1d: 50 }); + }); + + expect(result.current.currentPrice).toBe(0); + + await act(async () => { + resolveB({ price: 42, pricePercentChange1d: 5 }); + }); + + await waitFor(() => { + expect(result.current.currentPrice).toBe(42); + }); + }); }); diff --git a/app/components/UI/TokenDetails/hooks/useTokenPrice.ts b/app/components/UI/TokenDetails/hooks/useTokenPrice.ts index 04b46efd9ad..71e69cc3b22 100644 --- a/app/components/UI/TokenDetails/hooks/useTokenPrice.ts +++ b/app/components/UI/TokenDetails/hooks/useTokenPrice.ts @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useSelector } from 'react-redux'; import { Hex } from '@metamask/utils'; import { selectNativeCurrencyByChainId } from '../../../../selectors/networkController'; @@ -19,10 +19,27 @@ import { import { calculateAssetPrice } from '../../AssetOverview/utils/calculateAssetPrice'; import { formatChainIdToCaip } from '@metamask/bridge-controller'; import { selectTokenMarketData } from '../../../../selectors/tokenRatesController'; +import { type MarketDataDetails } from '@metamask/assets-controllers'; import { getTokenExchangeRate } from '../../Bridge/utils/exchange-rates'; import { isNonEvmChainId } from '../../../../core/Multichain/utils'; import { safeToChecksumAddress } from '../../../../util/address'; +/** + * Time ranges where the spot-prices API provides a reliable pre-computed + * percentage, mapped to the corresponding MarketDataDetails field. + * Ranges not covered here (3m, 3y, all) have no matching API field and + * will fall back to the historical-prices-derived percentage. + */ +const SPOT_PRICE_PCT_BY_TIME_PERIOD: Partial< + Record +> = { + '1d': 'pricePercentChange1d', + '1w': 'pricePercentChange7d', + '7d': 'pricePercentChange7d', + '1m': 'pricePercentChange30d', + '1y': 'pricePercentChange1y', +}; + export interface UseTokenPriceResult { currentPrice: number; priceDiff: number; @@ -33,6 +50,7 @@ export interface UseTokenPriceResult { setTimePeriod: (period: TimePeriod) => void; chartNavigationButtons: TimePeriod[]; currentCurrency: string; + hasInsufficientCoverage: boolean; } export interface UseTokenPriceParams { @@ -72,7 +90,11 @@ export const useTokenPrice = ({ ? safeToChecksumAddress(token.address) : token.address; - const { data: prices = [], isLoading } = useTokenHistoricalPrices({ + const { + data: prices = [], + isLoading, + hasInsufficientCoverage, + } = useTokenHistoricalPrices({ asset: token, address: token.address as Hex, chainId, @@ -88,13 +110,29 @@ export const useTokenPrice = ({ [isNonEvmToken], ); - const marketDataRate = - allTokenMarketData?.[chainId]?.[itemAddress as Hex]?.price; + const tokenMarketEntry = allTokenMarketData?.[chainId]?.[itemAddress as Hex]; + const marketDataRate = tokenMarketEntry?.price; const [fetchedRate, setFetchedRate] = useState(); + const [fetchedMarketData, setFetchedMarketData] = useState< + MarketDataDetails | undefined + >(); + const fetchIdRef = useRef(0); + // Stable token key to prevent unnecessary re-fetches + const tokenKey = `${chainId}-${itemAddress}-${currentCurrency}`; + + // For non-imported tokens (not in Redux), fetch price + market data in a + // single call. This gives us both the exchange rate and the pre-computed + // percentage changes from the spot-prices API, avoiding the historical-prices + // endpoint's incomplete-data problem for newly-listed tokens. useEffect(() => { + setFetchedRate(undefined); + setFetchedMarketData(undefined); + if (marketDataRate !== undefined || !itemAddress) { + // Token data already available in Redux or no address - mark fetch as "not needed" + setFetchedMarketData({} as MarketDataDetails); return; } @@ -104,42 +142,63 @@ export const useTokenPrice = ({ conversionRateByTicker?.[nativeCurrency]?.conversionRate; if (!isNonEvm && !nativeTokenConversionRate) { + // Can't fetch without conversion rate - mark fetch as "not possible" + setFetchedMarketData({} as MarketDataDetails); return; } - const fetchRate = async () => { + const id = ++fetchIdRef.current; + + const fetchData = async () => { try { - const tokenFiatPrice = await getTokenExchangeRate({ + const data = (await getTokenExchangeRate({ chainId, tokenAddress: itemAddress, currency: currentCurrency, - }); + includeMarketData: true, + })) as MarketDataDetails | undefined; + + if (id !== fetchIdRef.current) return; - if (!tokenFiatPrice) { + if (!data?.price) { setFetchedRate(undefined); + // Set empty object to indicate "fetch completed but no data available" + // This prevents infinite loading when API returns incomplete data + setFetchedMarketData({} as MarketDataDetails); return; } + setFetchedMarketData(data); + if (isNonEvm) { - setFetchedRate(tokenFiatPrice); + setFetchedRate(data.price); } else if (nativeTokenConversionRate) { - setFetchedRate(tokenFiatPrice / nativeTokenConversionRate); + setFetchedRate(data.price / nativeTokenConversionRate); } - } catch (error) { - console.error('Failed to fetch token exchange rate:', error); + } catch { + if (id !== fetchIdRef.current) return; setFetchedRate(undefined); + // Set empty object to indicate "fetch attempted but failed" + // This prevents infinite loading when API request fails + setFetchedMarketData({} as MarketDataDetails); } }; - fetchRate(); - }, [ - chainId, - itemAddress, - currentCurrency, - marketDataRate, - nativeCurrency, - conversionRateByTicker, - ]); + fetchData(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tokenKey, marketDataRate]); + + // For time periods that use spot-prices percentage (1d, 1w, 1m, 1y), + // wait for spot-prices to load before showing data to avoid flicker. + // For other periods (3m, 3y, all), we must rely on historical prices. + const spotPctField = SPOT_PRICE_PCT_BY_TIME_PERIOD[timePeriod]; + const needsSpotPriceFetch = marketDataRate === undefined && !!itemAddress; + // Wait for spot-prices data when: token not in Redux, time period uses spot %, + // and we haven't fetched yet (fetchedMarketData is still undefined). + const isWaitingForSpotPrice = + needsSpotPriceFetch && + spotPctField !== undefined && + fetchedMarketData === undefined; const exchangeRate = marketDataRate ?? fetchedRate; @@ -169,16 +228,40 @@ export const useTokenPrice = ({ comparePrice = calculatedComparePrice; } + // When the spot-prices API has a pre-computed percentage for the active + // time range, prefer it over the percentage derived from historical-prices. + // The historical-prices endpoint can return incomplete data for newly-listed + // tokens (e.g., only 6h of data when 24h is requested), causing wildly + // incorrect percentages. + // For imported tokens, read from Redux (tokenMarketEntry); for non-imported + // tokens, fall back to the fetched market data. + const spotPct = spotPctField + ? ((tokenMarketEntry?.[spotPctField] as number | undefined) ?? + (fetchedMarketData?.[spotPctField] as number | undefined) ?? + null) + : null; + + if (spotPct != null && currentPrice > 0) { + const derivedComparePrice = currentPrice / (1 + spotPct / 100); + comparePrice = derivedComparePrice; + priceDiff = currentPrice - derivedComparePrice; + } + + // Combine loading states: wait for both historical prices AND spot-prices + // (when needed for the current time period) to avoid percentage flicker. + const combinedIsLoading = isLoading || isWaitingForSpotPrice; + return { currentPrice, priceDiff, comparePrice, prices, - isLoading, + isLoading: combinedIsLoading, timePeriod, setTimePeriod, chartNavigationButtons, currentCurrency, + hasInsufficientCoverage, }; }; diff --git a/app/components/hooks/useTokenHistoricalPrices.test.ts b/app/components/hooks/useTokenHistoricalPrices.test.ts new file mode 100644 index 00000000000..6af5a92ab72 --- /dev/null +++ b/app/components/hooks/useTokenHistoricalPrices.test.ts @@ -0,0 +1,106 @@ +import { + hasInsufficientTimeCoverage, + type TimePeriod, + type TokenPrice, +} from './useTokenHistoricalPrices'; + +const HOUR_MS = 3_600_000; + +function makeTimeSeries( + startMs: number, + count: number, + intervalMs: number, +): TokenPrice[] { + return Array.from({ length: count }, (_, i) => [ + String(startMs + i * intervalMs), + 100 + i, + ]) as TokenPrice[]; +} + +describe('hasInsufficientTimeCoverage', () => { + const now = Date.now(); + + it('returns false for "all" time period (no expected duration)', () => { + const prices = makeTimeSeries(now, 10, HOUR_MS); + expect(hasInsufficientTimeCoverage(prices, 'all')).toBe(false); + }); + + it('returns false when data has fewer than 2 points', () => { + const single: TokenPrice[] = [[String(now), 100]]; + expect(hasInsufficientTimeCoverage(single, '1d')).toBe(false); + expect(hasInsufficientTimeCoverage([], '1d')).toBe(false); + }); + + it('returns false when 1d data covers 24 hours', () => { + const prices = makeTimeSeries(now, 289, 5 * 60_000); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(false); + }); + + it('returns true when 1d data covers only 10 hours', () => { + const tenHours = 10 * HOUR_MS; + const prices = makeTimeSeries(now, 120, tenHours / 119); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(true); + }); + + it('returns true when 1d data covers exactly 50% of expected duration', () => { + const halfDay = 12 * HOUR_MS; + const prices = makeTimeSeries(now, 50, halfDay / 49); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(true); + }); + + it('returns true when 1d data covers 80% of expected duration', () => { + const eightyPct = 0.8 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 50, eightyPct / 49); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(true); + }); + + it('returns true when 1d data covers 22 hours (~91.7%)', () => { + const twentyTwoHours = 22 * HOUR_MS; + const prices = makeTimeSeries(now, 50, twentyTwoHours / 49); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(true); + }); + + it('returns false when 1d data covers 23 hours (~95.8%)', () => { + const twentyThreeHours = 23 * HOUR_MS; + const prices = makeTimeSeries(now, 50, twentyThreeHours / 49); + expect(hasInsufficientTimeCoverage(prices, '1d')).toBe(false); + }); + + it('returns false when 1w data covers 7 days', () => { + const sevenDays = 7 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 100, sevenDays / 99); + expect(hasInsufficientTimeCoverage(prices, '1w')).toBe(false); + }); + + it('returns true when 1w data covers only 3 days', () => { + const threeDays = 3 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 100, threeDays / 99); + expect(hasInsufficientTimeCoverage(prices, '1w')).toBe(true); + }); + + it('handles 7d alias the same as 1w', () => { + const threeDays = 3 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 100, threeDays / 99); + expect(hasInsufficientTimeCoverage(prices, '7d')).toBe(true); + }); + + it('returns false for 1m with sufficient coverage', () => { + const thirtyDays = 30 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 100, thirtyDays / 99); + expect(hasInsufficientTimeCoverage(prices, '1m')).toBe(false); + }); + + it('returns true for 1m with only 10 days of data', () => { + const tenDays = 10 * 24 * HOUR_MS; + const prices = makeTimeSeries(now, 100, tenDays / 99); + expect(hasInsufficientTimeCoverage(prices, '1m')).toBe(true); + }); + + it.each(['3m', '1y', '3y'])( + 'validates coverage for %s time period', + (period) => { + const prices = makeTimeSeries(now, 10, HOUR_MS); + expect(hasInsufficientTimeCoverage(prices, period)).toBe(true); + }, + ); +}); diff --git a/app/components/hooks/useTokenHistoricalPrices.ts b/app/components/hooks/useTokenHistoricalPrices.ts index d74e5e7a850..e1ca6d64956 100644 --- a/app/components/hooks/useTokenHistoricalPrices.ts +++ b/app/components/hooks/useTokenHistoricalPrices.ts @@ -11,6 +11,50 @@ export type TokenPrice = [string, number]; const placeholderPrices = Array(289).fill(['0', 0] as TokenPrice); +const HOURS = 3_600_000; +const DAYS = 24 * HOURS; + +/** + * Expected durations (in ms) for each time period. + * `null` means no coverage check (e.g. "all" has no fixed expected span). + */ +const EXPECTED_DURATION_MS: Record = { + '1d': 1 * DAYS, + '1w': 7 * DAYS, + '7d': 7 * DAYS, + '1m': 30 * DAYS, + '3m': 90 * DAYS, + '1y': 365 * DAYS, + '3y': 3 * 365 * DAYS, + all: null, +}; + +/** + * Minimum fraction of the requested time period that the returned data must + * cover. Below this threshold we show the "no data" overlay instead of + * rendering a misleading chart. 0.95 = data must span at least 95% of the + * expected duration (e.g. ~22.8 h for a 1D request). + */ +const MIN_COVERAGE_RATIO = 0.95; + +/** + * Returns true when the historical-prices data covers less than + * {@link MIN_COVERAGE_RATIO} of the requested time period. + */ +export function hasInsufficientTimeCoverage( + prices: TokenPrice[], + timePeriod: TimePeriod, +): boolean { + const expectedMs = EXPECTED_DURATION_MS[timePeriod]; + if (expectedMs === null || prices.length < 2) return false; + + const firstTs = Number(prices[0][0]); + const lastTs = Number(prices[prices.length - 1][0]); + const actualSpanMs = Math.abs(lastTs - firstTs); + + return actualSpanMs < expectedMs * MIN_COVERAGE_RATIO; +} + const useTokenHistoricalPrices = ({ asset, address, @@ -31,16 +75,19 @@ const useTokenHistoricalPrices = ({ data: TokenPrice[] | undefined; isLoading: boolean; error: Error | undefined; + hasInsufficientCoverage: boolean; } => { const resultChainId = formatChainIdToCaip(asset.chainId as Hex); const isNonEvmAsset = resultChainId === asset.chainId; const [prices, setPrices] = useState(placeholderPrices); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(); + const [insufficientCoverage, setInsufficientCoverage] = useState(false); useEffect(() => { const fetchPrices = async () => { setIsLoading(true); + setInsufficientCoverage(false); try { const baseUri = 'https://price.api.cx.metamask.io/v3'; @@ -91,10 +138,17 @@ const useTokenHistoricalPrices = ({ endTrace({ name: TraceName.FetchHistoricalPrices }); if (response.status === 204) { setPrices([]); + setInsufficientCoverage(true); return; } const data: { prices: TokenPrice[] } = await response.json(); - setPrices(data.prices as TokenPrice[]); + const sortedPrices = [...data.prices].sort( + (a, b) => Number(a[0]) - Number(b[0]), + ); + setPrices(sortedPrices as TokenPrice[]); + setInsufficientCoverage( + hasInsufficientTimeCoverage(sortedPrices, timePeriod), + ); } catch (e: unknown) { setError(e as Error); } finally { @@ -114,7 +168,12 @@ const useTokenHistoricalPrices = ({ asset.chainId, ]); - return { data: prices, isLoading, error }; + return { + data: prices, + isLoading, + error, + hasInsufficientCoverage: insufficientCoverage, + }; }; export default useTokenHistoricalPrices; diff --git a/app/core/redux/slices/bridge/index.ts b/app/core/redux/slices/bridge/index.ts index 9f7c9f2b148..4869a402c85 100644 --- a/app/core/redux/slices/bridge/index.ts +++ b/app/core/redux/slices/bridge/index.ts @@ -353,7 +353,9 @@ const slice = createSlice({ action.meta.arg.chainId === state.sourceToken.chainId && action.meta.arg.tokenAddress === state.sourceToken.address ) { - state.sourceToken.currencyExchangeRate = action.payload ?? undefined; + const rate = action.payload; + state.sourceToken.currencyExchangeRate = + typeof rate === 'number' ? rate : undefined; } }); builder.addCase(setDestTokenExchangeRate.fulfilled, (state, action) => { @@ -363,7 +365,9 @@ const slice = createSlice({ action.meta.arg.chainId === state.destToken.chainId && action.meta.arg.tokenAddress === state.destToken.address ) { - state.destToken.currencyExchangeRate = action.payload ?? undefined; + const rate = action.payload; + state.destToken.currencyExchangeRate = + typeof rate === 'number' ? rate : undefined; } }); }, diff --git a/docs/readme/e2e-testing.md b/docs/readme/e2e-testing.md index c14a13d3e88..2d518a38d6d 100644 --- a/docs/readme/e2e-testing.md +++ b/docs/readme/e2e-testing.md @@ -124,6 +124,7 @@ First, ensure the build watcher is running in a dedicated terminal for logs: ```bash export METAMASK_ENVIRONMENT='e2e' export METAMASK_BUILD_TYPE='main' +export HAS_TEST_OVERRIDES="true" yarn setup:expo yarn watch:clean # First time or after dependency changes yarn watch # Subsequent runs diff --git a/package.json b/package.json index cfb3e90fb94..d8328b53bd7 100644 --- a/package.json +++ b/package.json @@ -242,7 +242,7 @@ "@metamask/app-metadata-controller": "^2.0.0", "@metamask/approval-controller": "^9.0.0", "@metamask/assets-controller": "^8.3.1", - "@metamask/assets-controllers": "^109.0.0", + "@metamask/assets-controllers": "^109.1.0", "@metamask/authenticated-user-storage": "^2.0.0", "@metamask/base-controller": "^9.0.1", "@metamask/bitcoin-wallet-snap": "^1.12.0", diff --git a/tests/api-mocking/mock-responses/defaults/price-apis.ts b/tests/api-mocking/mock-responses/defaults/price-apis.ts index 94c11818172..eb4002aed7a 100644 --- a/tests/api-mocking/mock-responses/defaults/price-apis.ts +++ b/tests/api-mocking/mock-responses/defaults/price-apis.ts @@ -145,26 +145,88 @@ export const PRICE_API_MOCKS: MockEventsObject = { responseCode: 200, response: { 'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f': { + id: 'eip155:1/erc20:0x6b175474e89094c44da98b954eedeac495271d0f', + price: 0.999588, usd: 0.999588, eth: 0.000233, + marketCap: 5000000000, + pricePercentChange1h: 0.01, + pricePercentChange1d: 0.1, + pricePercentChange7d: 0.5, + pricePercentChange14d: 0.8, + pricePercentChange30d: 1.0, + pricePercentChange200d: 2.0, + pricePercentChange1y: 5.0, }, 'eip155:1/slip44:60': { + id: 'eip155:1/slip44:60', + price: 4280.15, usd: 4280.15, eth: 1.0, + marketCap: 500000000000, + pricePercentChange1h: 0.5, + pricePercentChange1d: 2.5, + pricePercentChange7d: 5.0, + pricePercentChange14d: 8.0, + pricePercentChange30d: 10.0, + pricePercentChange200d: 20.0, + pricePercentChange1y: 50.0, }, 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48': { + id: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + price: 1.0, usd: 1.0, eth: 0.000233, + marketCap: 35000000000, + pricePercentChange1h: 0.01, + pricePercentChange1d: 0.1, + pricePercentChange7d: 0.2, + pricePercentChange14d: 0.3, + pricePercentChange30d: 0.5, + pricePercentChange200d: 1.0, + pricePercentChange1y: 2.0, + }, + 'eip155:1/erc20:0x96f6ef951840721adbf46ac996b59e0235cb985c': { + id: 'eip155:1/erc20:0x96f6ef951840721adbf46ac996b59e0235cb985c', + price: 1.02, + usd: 1.02, + eth: 0.000238, + marketCap: 500000000, + pricePercentChange1h: 0.01, + pricePercentChange1d: 0.05, + pricePercentChange7d: 0.15, + pricePercentChange14d: 0.25, + pricePercentChange30d: 0.4, + pricePercentChange200d: 0.8, + pricePercentChange1y: 1.5, }, 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174': { + id: 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + price: 1.0, usd: 1.0, eth: 0.000344, - price: 1.0, + marketCap: 1000000000, + pricePercentChange1h: 0.01, + pricePercentChange1d: 0.1, + pricePercentChange7d: 0.2, + pricePercentChange14d: 0.3, + pricePercentChange30d: 0.5, + pricePercentChange200d: 1.0, + pricePercentChange1y: 2.0, }, 'eip155:137/slip44:966': { - usd: 1.0, + id: 'eip155:137/slip44:966', price: 1.0, + usd: 1.0, eth: 0.000344, + marketCap: 50000000, + pricePercentChange1h: 0.5, + pricePercentChange1d: 1.0, + pricePercentChange7d: 3.0, + pricePercentChange14d: 5.0, + pricePercentChange30d: 8.0, + pricePercentChange200d: 15.0, + pricePercentChange1y: 20.0, }, }, }, diff --git a/yarn.lock b/yarn.lock index 1a652a447ed..6bf2b864768 100644 --- a/yarn.lock +++ b/yarn.lock @@ -35312,7 +35312,7 @@ __metadata: "@metamask/app-metadata-controller": "npm:^2.0.0" "@metamask/approval-controller": "npm:^9.0.0" "@metamask/assets-controller": "npm:^8.3.1" - "@metamask/assets-controllers": "npm:^109.0.0" + "@metamask/assets-controllers": "npm:^109.1.0" "@metamask/authenticated-user-storage": "npm:^2.0.0" "@metamask/auto-changelog": "npm:^5.3.0" "@metamask/base-controller": "npm:^9.0.1" From 07df4e7feadfdf17f9deb19a4c9380666bc4ecee Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 16 Jun 2026 21:04:57 +0530 Subject: [PATCH 13/23] fix: percentage buttons on predict withdraw into money account (#31795) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fix percentage buttons when withdrawing from predict into money account. ## **Changelog** CHANGELOG entry: ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1559 ## **Manual testing steps** NA ## **Screenshots/Recordings** NA ## **Pre-merge author checklist** - [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) - [X] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [X] 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 - [X] 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** - [ ] 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. --- .../useTransactionCustomAmount.test.ts | 72 +++++++++++++++++++ .../useTransactionCustomAmount.ts | 8 ++- 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.test.ts b/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.test.ts index 552bdf991c9..6c984b023a6 100644 --- a/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.test.ts +++ b/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.test.ts @@ -544,6 +544,78 @@ describe('useTransactionCustomAmount', () => { expect(result.current.amountFiat).toBe('8642.46'); }); + it('uses predict balance for predictWithdraw even when payment override is MoneyAccount', async () => { + usePredictBalanceMock.mockReturnValue({ data: 4321.23 } as never); + useMoneyAccountBalanceMock.mockReturnValue({ + totalFiatRaw: '750.50', + } as ReturnType); + + const { result } = runHook({ + transactionMeta: { + type: TransactionType.predictWithdraw, + id: transactionIdMock, + chainId: '0x1' as Hex, + txParams: { from: '0xabc' }, + } as unknown as Partial, + stateOverrides: { + engine: { + backgroundState: { + TransactionPayController: { + transactionData: { + [transactionIdMock]: { + paymentOverride: PaymentOverride.MoneyAccount, + }, + }, + }, + }, + }, + }, + }); + + await act(async () => { + result.current.updatePendingAmountPercentage(50); + }); + + // 4321.23 (predict balance) × 2 (fiat rate) × 0.50 = 4321.23 + expect(result.current.amountFiat).toBe('4321.23'); + }); + + it('uses full predict balance for predictWithdraw max even when payment override is MoneyAccount', async () => { + usePredictBalanceMock.mockReturnValue({ data: 4321.23 } as never); + useMoneyAccountBalanceMock.mockReturnValue({ + totalFiatRaw: '750.50', + } as ReturnType); + + const { result } = runHook({ + transactionMeta: { + type: TransactionType.predictWithdraw, + id: transactionIdMock, + chainId: '0x1' as Hex, + txParams: { from: '0xabc' }, + } as unknown as Partial, + stateOverrides: { + engine: { + backgroundState: { + TransactionPayController: { + transactionData: { + [transactionIdMock]: { + paymentOverride: PaymentOverride.MoneyAccount, + }, + }, + }, + }, + }, + }, + }); + + await act(async () => { + result.current.updatePendingAmountPercentage(100); + }); + + // 4321.23 (predict balance) × 2 (fiat rate) = 8642.46 + expect(result.current.amountFiat).toBe('8642.46'); + }); + it('to percentage of perps available balance', async () => { (Engine.context as Record).PerpsController = { state: { diff --git a/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.ts b/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.ts index 6c9888ce39c..fc12b75f5f6 100644 --- a/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.ts +++ b/app/components/Views/confirmations/hooks/transactions/useTransactionCustomAmount.ts @@ -300,11 +300,13 @@ function useTokenBalance(tokenUsdRate: number) { return withdrawableMusd.multipliedBy(tokenUsdRate).toNumber(); } + if (hasTransactionType(transactionMeta, [TransactionType.predictWithdraw])) { + return predictBalanceUsd; + } + if (paymentOverride === PaymentOverride.MoneyAccount) { return totalFiatRaw ? parseFloat(totalFiatRaw) : 0; } - return hasTransactionType(transactionMeta, [TransactionType.predictWithdraw]) - ? predictBalanceUsd - : payTokenBalanceUsd; + return payTokenBalanceUsd; } From b73672503becc40d96075991b2e35b5da68f268e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Tue, 16 Jun 2026 16:48:38 +0100 Subject: [PATCH 14/23] chore: make QuickBuy flow user-currency-native (#31786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** QuickBuy treated USD as the canonical fiat unit, with inconsistent/mislabeled conversions (a `€` symbol rendered on a USD number, `currencyExchangeRate` meaning different things on EVM vs non-EVM, hardcoded `$` headlines). This makes the user's display currency the single canonical fiat unit across state, slider, balances, and totals. Deriving USD only at the analytics boundary, where the schema contractually requires `amount_usd`. https://github.com/user-attachments/assets/05701682-8392-4f63-8304-2420a488a061 Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 06 26 Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 13 52 Simulator Screenshot - iPhone 17 Pro - 2026-06-16
at 10 06 59 ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TSA-633 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** ### **Before** NA ### **After** NA ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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** - [ ] 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. --------- Co-authored-by: Xavier Brochard Co-authored-by: Cursor --- .../components/QuickBuy/QuickBuyAmount.tsx | 4 +- .../QuickBuy/QuickBuyContext.test.tsx | 7 +- .../components/QuickBuy/QuickBuyRoot.test.tsx | 7 +- .../QuickBuy/QuickBuySheet.test.tsx | 7 +- .../components/QuickBuyAmountSection.test.tsx | 25 +- .../components/QuickBuyAmountSection.tsx | 6 +- .../QuickBuy/hooks/enrichTokenBalance.test.ts | 112 +++----- .../QuickBuy/hooks/enrichTokenBalance.ts | 214 +++++++-------- .../QuickBuy/hooks/usePayWithTokens.test.ts | 1 + .../QuickBuy/hooks/usePayWithTokens.ts | 8 +- .../hooks/usePositionTokenBalance.test.ts | 85 +++++- .../QuickBuy/hooks/usePositionTokenBalance.ts | 115 ++++---- .../QuickBuy/hooks/useQuickBuyController.ts | 256 +++++++++++------- .../QuickBuy/hooks/useReceiveTokens.test.ts | 1 + .../QuickBuy/hooks/useReceiveTokens.ts | 8 +- .../QuickBuy/useQuickBuyController.test.ts | 104 ++++++- 16 files changed, 582 insertions(+), 378 deletions(-) diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/QuickBuyAmount.tsx b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/QuickBuyAmount.tsx index 05bc4c63590..9267cd7fc2d 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/QuickBuyAmount.tsx +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/QuickBuyAmount.tsx @@ -8,7 +8,7 @@ import { useQuickBuyContext } from './useQuickBuyContext'; const QuickBuyAmount: React.FC = () => { const { amountDisplayMode, - usdAmount, + fiatAmountLabel, target, tradeMode, hasSourcePrice, @@ -39,7 +39,7 @@ const QuickBuyAmount: React.FC = () => { return ( { , ); expect(screen.getByText('$50')).toBeOnTheScreen(); }); - it('shows $0 placeholder when usdAmount is empty', () => { - render(); + it('renders a non-USD preformatted fiat label as primary in fiat mode', () => { + render( + , + ); + expect(screen.getByText('50 €')).toBeOnTheScreen(); + }); + + it('shows the zero placeholder label when no amount is entered', () => { + render(); expect(screen.getByText('$0')).toBeOnTheScreen(); }); @@ -72,7 +83,11 @@ describe('QuickBuyAmountSection', () => { it('replaces the secondary label with an ActivityIndicator when isQuoteLoading', () => { render( - , + , ); expect(screen.getByTestId('quick-buy-amount-area')).toBeOnTheScreen(); // Secondary label is replaced by spinner — crypto label should NOT be present diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/components/QuickBuyAmountSection.tsx b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/components/QuickBuyAmountSection.tsx index 650325299d7..69dbf955db8 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/components/QuickBuyAmountSection.tsx +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/components/QuickBuyAmountSection.tsx @@ -18,7 +18,8 @@ const styles = StyleSheet.create({ interface QuickBuyAmountSectionProps { amountDisplayMode: QuickBuyAmountDisplayMode; - usdAmount: string; + /** Entered amount preformatted in the user's display currency (e.g. "$20", "20 €"). */ + fiatAmountLabel: string; destSymbol: string; /** Estimated amount received in the dest token from the quote. */ estimatedReceiveAmount: string | undefined; @@ -44,7 +45,7 @@ interface QuickBuyAmountSectionProps { const QuickBuyAmountSection: React.FC = ({ amountDisplayMode, - usdAmount, + fiatAmountLabel, destSymbol, estimatedReceiveAmount, isQuoteLoading, @@ -52,7 +53,6 @@ const QuickBuyAmountSection: React.FC = ({ sourceCryptoAmount, sourceSymbol, }) => { - const fiatAmountLabel = usdAmount ? `$${usdAmount}` : '$0'; const cryptoAmountLabel = estimatedReceiveAmount ? `${formatTokenAmount(parseFloat(estimatedReceiveAmount))} ${destSymbol}` : `0 ${destSymbol}`; diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.test.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.test.ts index 532ee9c4c23..b7a56796249 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.test.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.test.ts @@ -27,7 +27,10 @@ const baseDeps = (overrides: Record = {}): TokenBalanceDeps => accountsByChainId: {}, tokenBalances: {}, tokenMarketData: {}, - currencyRates: { ETH: { usdConversionRate: 2000 } }, + // `conversionRate` is the native-token -> user-currency rate that the + // canonical `calcTokenFiatRate` reads. + currencyRates: { ETH: { conversionRate: 2000, usdConversionRate: 2000 } }, + currentCurrency: 'USD', allNetworkConfigs: { '0x1': { nativeCurrency: 'ETH' } }, ...overrides, }) as unknown as TokenBalanceDeps; @@ -50,7 +53,7 @@ describe('enrichTokenBalance', () => { expect(result).toEqual({ balance: '1.0', - balanceFiat: '$2000.00', + balanceFiat: '$2,000.00', tokenFiatAmount: 2000, currencyExchangeRate: 2000, }); @@ -79,7 +82,7 @@ describe('enrichTokenBalance', () => { ...extra, }); - it('prices an ERC-20 from market data times the usd conversion rate', () => { + it('prices an ERC-20 from market data times the native conversion rate', () => { const deps = withUsdcBalance({ tokenMarketData: { '0x1': { [toChecksumAddress(USDC)]: { price: 0.0005 } }, @@ -87,12 +90,43 @@ describe('enrichTokenBalance', () => { }); const result = enrichTokenBalance( - token({ address: USDC, chainId: '0x1', symbol: 'USDC', decimals: 6 }), + token({ + address: toChecksumAddress(USDC), + chainId: '0x1', + symbol: 'USDC', + decimals: 6, + }), + deps, + ); + + expect(result).toMatchObject({ + balance: '250.0', + balanceFiat: '$250.00', + currencyExchangeRate: 1, + tokenFiatAmount: 250, + }); + }); + + it('prices a lowercase-address ERC-20 against checksum-keyed market data', () => { + const deps = withUsdcBalance({ + tokenMarketData: { + '0x1': { [toChecksumAddress(USDC)]: { price: 0.0005 } }, + }, + }); + + const result = enrichTokenBalance( + token({ + address: USDC.toLowerCase(), + chainId: '0x1', + symbol: 'USDC', + decimals: 6, + }), deps, ); expect(result).toMatchObject({ balance: '250.0', + balanceFiat: '$250.00', currencyExchangeRate: 1, tokenFiatAmount: 250, }); @@ -177,7 +211,7 @@ describe('enrichTokenBalance', () => { expect(result).toEqual({ balance: '12.5', - balanceFiat: '$2500.00', + balanceFiat: '$2,500.00', tokenFiatAmount: 2500, currencyExchangeRate: 200, }); @@ -279,7 +313,7 @@ describe('enrichTokenBalance', () => { expect(result).toEqual({ balance: '0.5', - balanceFiat: '$50000.00', + balanceFiat: '$50,000.00', tokenFiatAmount: 50000, currencyExchangeRate: 100000, }); @@ -327,70 +361,4 @@ describe('enrichTokenBalance', () => { expect(result).toBeNull(); }); }); - - describe('fiatCurrency', () => { - const solAssetId = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501'; - const solanaScope = 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp'; - const solanaAccount = { id: 'solana-account-id' }; - - it('formats the fiat string with the provided currency symbol (numeric value stays USD)', () => { - const deps = baseDeps({ - fiatCurrency: 'eur', - solanaAccount, - multichainBalances: { - [solanaAccount.id]: { [solAssetId]: { amount: '12.5' } }, - }, - multichainRates: { [solAssetId]: { rate: '200' } }, - }); - - const result = enrichTokenBalance( - token({ - address: solAssetId, - chainId: solanaScope, - symbol: 'SOL', - decimals: 9, - }), - deps, - ); - - expect(result).toEqual({ - balance: '12.5', - balanceFiat: '€2500', - tokenFiatAmount: 2500, - currencyExchangeRate: 200, - }); - }); - - it('defaults to USD when no fiatCurrency is provided', () => { - const deps = baseDeps({ - solanaAccount, - multichainBalances: { - [solanaAccount.id]: { [solAssetId]: { amount: '12.5' } }, - }, - multichainRates: { [solAssetId]: { rate: '200' } }, - }); - - const result = enrichTokenBalance( - token({ address: solAssetId, chainId: solanaScope, symbol: 'SOL' }), - deps, - ); - - expect(result?.balanceFiat).toBe('$2500.00'); - }); - - it('uses the provided currency symbol for a lenient zero enrichment', () => { - const result = enrichTokenBalance( - token({ address: solAssetId, chainId: solanaScope, symbol: 'SOL' }), - baseDeps({ fiatCurrency: 'eur' }), - { includeZeroBalance: true }, - ); - - expect(result).toEqual({ - balance: '0', - balanceFiat: '€0', - tokenFiatAmount: 0, - currencyExchangeRate: undefined, - }); - }); - }); }); diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.ts index 0ec57510b61..65f1f8a034c 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/enrichTokenBalance.ts @@ -2,29 +2,31 @@ import type { Hex } from '@metamask/utils'; import { formatUnits } from 'ethers/lib/utils'; import { isNonEvmChainId, - isSolanaChainId, isNativeAddress, + isSolanaChainId, } from '@metamask/bridge-controller'; import { BtcScope, TrxScope } from '@metamask/keyring-api'; import type { BridgeToken } from '../../../../../../UI/Bridge/types'; -import { addCurrencySymbol } from '../../../../../../../util/number/bigint'; +import { formatCurrency } from '../../../../../../UI/Bridge/utils/currencyUtils'; +import { calcTokenFiatRate } from '../../../../../../UI/Bridge/utils/exchange-rates'; +import { safeToChecksumAddress } from '../../../../../../../util/address'; import type { selectTokenMarketData } from '../../../../../../../selectors/tokenRatesController'; import type { selectCurrencyRates } from '../../../../../../../selectors/currencyRateController'; import { hasNonZeroHexBalance, getCachedNativeBalance, getCachedErc20Balance, - getTokenPrice, type TokenBalances, type AccountsByChainId, } from './tokenBalanceUtils'; /** * The priced balance fields shared by every QuickBuy token row. `balance` is a - * non-truncated decimal amount, `balanceFiat` the formatted fiat string (left - * `undefined` when the token's USD price can't be resolved, so the row renders - * a dash), and `currencyExchangeRate` the USD-per-token rate the controller - * uses to convert the entered USD amount into a token amount. + * non-truncated decimal amount, `balanceFiat` the formatted fiat string in the + * user's display currency (left `undefined` when the token's price can't be + * resolved, so the row renders a dash), and `currencyExchangeRate` the + * user-currency-per-token rate the controller uses to convert the entered fiat + * amount into a token amount. */ export interface TokenBalanceEnrichment { balance: string; @@ -44,12 +46,9 @@ export interface TokenBalanceDeps { tokenBalances: TokenBalances; tokenMarketData: ReturnType; currencyRates: ReturnType; + /** The user's selected display currency (e.g. "usd", "eur"). */ + currentCurrency: string; allNetworkConfigs?: Record; - /** - * Currency code used to format the fiat display string (e.g. `'usd'`, - * `'eur'`). Defaults to USD when omitted. - */ - fiatCurrency?: Parameters[1]; solanaAccount?: { id: string }; tronAccount?: { id: string }; bitcoinAccount?: { id: string }; @@ -63,7 +62,7 @@ export interface TokenBalanceDeps { export interface EnrichTokenBalanceOptions { /** * When `true`, tokens are still returned instead of being dropped: unheld - * tokens come back as balance "0" / $0.00 fiat, and held-but-unpriceable + * tokens come back as balance "0" / zero fiat, and held-but-unpriceable * tokens keep their real balance with an undefined fiat (rendered as a dash). * Used by the "Receive" picker, which lists every stable regardless of * whether the user holds it. @@ -71,29 +70,18 @@ export interface EnrichTokenBalanceOptions { includeZeroBalance?: boolean; } -/** - * QuickBuy prices everything in USD: `currencyExchangeRate` is a USD-per-token - * rate and the amount-entry flow is USD-first (see `QuickBuyAmountSection`). - * The fiat fields are therefore always USD-denominated, so they must be - * formatted as USD — formatting a USD value with the user's selected currency - * (e.g. "€2000.00" for a $2000 value) would be wrong. - */ -const USD_CURRENCY = 'usd' as Parameters[1]; - -const zeroEnrichment = ( - fiatCurrency: Parameters[1] = USD_CURRENCY, -): TokenBalanceEnrichment => ({ +const zeroEnrichment = (currentCurrency: string): TokenBalanceEnrichment => ({ balance: '0', - balanceFiat: addCurrencySymbol('0.00', fiatCurrency), + balanceFiat: formatCurrency(0, currentCurrency), tokenFiatAmount: 0, currencyExchangeRate: undefined, }); /** - * Lenient result for a token the user *does* hold but whose USD price can't be + * Lenient result for a token the user *does* hold but whose price can't be * resolved: keeps the real on-chain `balance` so the Receive picker still shows * the holding, while leaving fiat `undefined` (the row renders a dash rather - * than a misleading $0.00) and the rate undefined. + * than a misleading zero) and the rate undefined. */ const unpricedEnrichment = (balance: string): TokenBalanceEnrichment => ({ balance, @@ -106,37 +94,29 @@ const priced = ( balance: string, exchangeRate: number, balanceNum: number, - fiatCurrency: Parameters[1] = USD_CURRENCY, + currentCurrency: string, ): TokenBalanceEnrichment => { const tokenFiatAmount = balanceNum * exchangeRate; return { balance, - balanceFiat: addCurrencySymbol(tokenFiatAmount.toFixed(2), fiatCurrency), + balanceFiat: formatCurrency(tokenFiatAmount, currentCurrency), tokenFiatAmount, currencyExchangeRate: exchangeRate, }; }; -const enrichEvmTokenBalance = ( +/** + * Reads the user's cached on-chain balance of an EVM token, returning a + * non-truncated decimal string, or `null` when the user holds none (or the + * balance can't be parsed). Pricing is handled separately by the canonical + * `calcTokenFiatRate`. + */ +const readEvmBalance = ( candidate: BridgeToken, deps: TokenBalanceDeps, - options: EnrichTokenBalanceOptions, -): TokenBalanceEnrichment | null => { - const { includeZeroBalance } = options; - const { - accountAddress, - accountsByChainId, - tokenBalances, - tokenMarketData, - currencyRates, - allNetworkConfigs, - fiatCurrency, - } = deps; - - const dropOrZero = () => - includeZeroBalance ? zeroEnrichment(fiatCurrency) : null; - - if (!accountAddress) return dropOrZero(); +): string | null => { + const { accountAddress, accountsByChainId, tokenBalances } = deps; + if (!accountAddress) return null; const chainId = candidate.chainId as Hex; const isNative = isNativeAddress(candidate.address); @@ -149,45 +129,13 @@ const enrichEvmTokenBalance = ( candidate.address, ); - if (!hasNonZeroHexBalance(rawBalance)) return dropOrZero(); + if (!hasNonZeroHexBalance(rawBalance)) return null; - let displayBalance: string; try { - displayBalance = formatUnits(rawBalance, candidate.decimals); + return formatUnits(rawBalance, candidate.decimals); } catch { - return dropOrZero(); - } - - const balanceNum = parseFloat(displayBalance); - if (isNaN(balanceNum) || balanceNum <= 0) return dropOrZero(); - - const nativeTicker = allNetworkConfigs?.[chainId]?.nativeCurrency; - const nativeConversionRate = nativeTicker - ? (currencyRates?.[nativeTicker]?.usdConversionRate ?? 0) - : 0; - - let exchangeRate: number; - if (isNative) { - exchangeRate = nativeConversionRate; - } else { - const tokenPrice = getTokenPrice( - tokenMarketData, - chainId, - candidate.address, - ); - exchangeRate = - tokenPrice !== undefined ? tokenPrice * nativeConversionRate : 0; + return null; } - - if (!(exchangeRate > 0)) { - // No resolvable USD price. Strict callers (Pay with) drop the token because - // the fiat-first amount entry needs a real price; lenient callers (Receive) - // keep the real held balance with a zero fiat value so the holding still - // shows up. - return includeZeroBalance ? unpricedEnrichment(displayBalance) : null; - } - - return priced(displayBalance, exchangeRate, balanceNum, fiatCurrency); }; /** @@ -205,51 +153,89 @@ const getNonEvmAccount = ( return undefined; }; -const enrichNonEvmTokenBalance = ( +/** + * Reads the user's non-EVM (Solana, Tron, Bitcoin) balance of a token from the + * multichain balances controller, returning a decimal string or `null`. + */ +const readNonEvmBalance = ( candidate: BridgeToken, deps: TokenBalanceDeps, - options: EnrichTokenBalanceOptions, -): TokenBalanceEnrichment | null => { - const { includeZeroBalance } = options; - const { multichainBalances, multichainRates, fiatCurrency } = deps; - - const dropOrZero = () => - includeZeroBalance ? zeroEnrichment(fiatCurrency) : null; - +): string | null => { const nonEvmAccount = getNonEvmAccount(candidate.chainId, deps); - if (!nonEvmAccount) return dropOrZero(); + if (!nonEvmAccount) return null; const amountStr = - multichainBalances?.[nonEvmAccount.id]?.[candidate.address]?.amount; - if (!amountStr) return dropOrZero(); - - const balanceNum = parseFloat(amountStr); - if (isNaN(balanceNum) || balanceNum <= 0) return dropOrZero(); - - const rateStr = multichainRates?.[candidate.address]?.rate; - const rateNum = rateStr ? parseFloat(rateStr) : NaN; + deps.multichainBalances?.[nonEvmAccount.id]?.[candidate.address]?.amount; + return amountStr ?? null; +}; - if (isNaN(rateNum) || rateNum <= 0) { - // Held but no resolvable rate: keep the real balance when lenient (Receive), - // drop it when strict (Pay with). - return includeZeroBalance ? unpricedEnrichment(amountStr) : null; +/** + * Returns a copy of the candidate whose EVM ERC-20 address is checksummed so it + * matches the keys `calcTokenFiatRate` uses to look up `tokenMarketData` (which + * is keyed by checksummed addresses). Pay-with candidates carry lowercase + * addresses, so without this normalization held ERC-20s with valid prices + * resolve to no rate and get dropped from the strict (Pay with) picker. + * Non-EVM (CAIP asset id) and native addresses are left untouched. + */ +const toPricedCandidate = (candidate: BridgeToken): BridgeToken => { + if ( + isNonEvmChainId(candidate.chainId) || + isNativeAddress(candidate.address) + ) { + return candidate; } - return priced(amountStr, rateNum, balanceNum, fiatCurrency); + const checksummedAddress = safeToChecksumAddress(candidate.address); + return checksummedAddress + ? { ...candidate, address: checksummedAddress } + : candidate; }; /** * Prices a single token candidate from cached Redux balances, returning the - * shared balance fields (or `null` when the token should be omitted). Handles - * EVM natives, EVM ERC-20s, and non-EVM assets (Solana, Tron, Bitcoin) via the - * multichain balance/rate controllers, keeping the USD exchange-rate semantics - * QuickBuy's amount math depends on. + * shared balance fields (or `null` when the token should be omitted). Balance + * reading is QuickBuy-specific (EVM natives / ERC-20s via cached balances, + * non-EVM assets via the multichain controllers); the fiat rate is delegated to + * the canonical `calcTokenFiatRate` so QuickBuy shares the wallet-wide + * user-currency exchange-rate semantics (no bespoke USD math). */ export const enrichTokenBalance = ( candidate: BridgeToken, deps: TokenBalanceDeps, options: EnrichTokenBalanceOptions = {}, -): TokenBalanceEnrichment | null => - isNonEvmChainId(candidate.chainId) - ? enrichNonEvmTokenBalance(candidate, deps, options) - : enrichEvmTokenBalance(candidate, deps, options); +): TokenBalanceEnrichment | null => { + const { includeZeroBalance } = options; + const dropOrZero = () => + includeZeroBalance ? zeroEnrichment(deps.currentCurrency) : null; + + const balance = isNonEvmChainId(candidate.chainId) + ? readNonEvmBalance(candidate, deps) + : readEvmBalance(candidate, deps); + + if (balance === null) return dropOrZero(); + + const balanceNum = parseFloat(balance); + if (isNaN(balanceNum) || balanceNum <= 0) return dropOrZero(); + + const exchangeRate = calcTokenFiatRate({ + token: toPricedCandidate(candidate), + evmMultiChainMarketData: deps.tokenMarketData, + networkConfigurationsByChainId: (deps.allNetworkConfigs ?? {}) as Record< + Hex, + { nativeCurrency: string } + >, + evmMultiChainCurrencyRates: deps.currencyRates, + nonEvmMultichainAssetRates: deps.multichainRates as Parameters< + typeof calcTokenFiatRate + >[0]['nonEvmMultichainAssetRates'], + }); + + if (!exchangeRate || exchangeRate <= 0) { + // No resolvable price. Strict callers (Pay with) drop the token because the + // fiat-first amount entry needs a real price; lenient callers (Receive) + // keep the real held balance with an undefined fiat so the holding shows up. + return includeZeroBalance ? unpricedEnrichment(balance) : null; + } + + return priced(balance, exchangeRate, balanceNum, deps.currentCurrency); +}; diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.test.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.test.ts index 643f7abb0ea..a526061ad4f 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.test.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.test.ts @@ -47,6 +47,7 @@ jest.mock('../../../../../../../selectors/tokenRatesController', () => ({ jest.mock('../../../../../../../selectors/currencyRateController', () => ({ selectCurrencyRates: jest.fn(), + selectCurrentCurrency: jest.fn(() => 'USD'), })); jest.mock('../../../../../../../core/redux/slices/bridge', () => ({ diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.ts index bbcfe1d858d..97e31b312d5 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePayWithTokens.ts @@ -10,7 +10,10 @@ import { selectAccountsByChainId } from '../../../../../../../selectors/accountT import { selectSelectedInternalAccountByScope } from '../../../../../../../selectors/multichainAccounts/accounts'; import { selectTokensBalances } from '../../../../../../../selectors/tokenBalancesController'; import { selectTokenMarketData } from '../../../../../../../selectors/tokenRatesController'; -import { selectCurrencyRates } from '../../../../../../../selectors/currencyRateController'; +import { + selectCurrencyRates, + selectCurrentCurrency, +} from '../../../../../../../selectors/currencyRateController'; import { selectMultichainBalances, selectMultichainAssetsRates, @@ -47,6 +50,7 @@ export const usePayWithTokens = (): { const tokenBalances = useSelector(selectTokensBalances); const tokenMarketData = useSelector(selectTokenMarketData); const currencyRates = useSelector(selectCurrencyRates); + const currentCurrency = useSelector(selectCurrentCurrency); const solanaAccount = accountByScope(SolScope.Mainnet); const tronAccount = accountByScope(TrxScope.Mainnet); @@ -74,6 +78,7 @@ export const usePayWithTokens = (): { tokenBalances, tokenMarketData, currencyRates, + currentCurrency, allNetworkConfigs, solanaAccount: solanaAccount ?? undefined, tronAccount: tronAccount ?? undefined, @@ -116,6 +121,7 @@ export const usePayWithTokens = (): { tokenBalances, tokenMarketData, currencyRates, + currentCurrency, allNetworkConfigs, solanaAccount, tronAccount, diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.test.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.test.ts index e40ae252d96..0c40eda7c23 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.test.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.test.ts @@ -64,13 +64,16 @@ const solanaAccount = { id: 'solana-account-id' }; const tronAccount = { id: 'tron-account-id' }; const bitcoinAccount = { id: 'bitcoin-account-id' }; -const FAKE_STATE = { - engine: { - backgroundState: { - NetworkController: { networkConfigurationsByChainId: {} }, +const makeState = ( + networkConfigs: Record = {}, +) => + ({ + engine: { + backgroundState: { + NetworkController: { networkConfigurationsByChainId: networkConfigs }, + }, }, - }, -} as never; + }) as never; const token = (address: string, chainId: string, symbol: string): BridgeToken => ({ @@ -99,6 +102,11 @@ const setup = ({ accounts = {}, multichainBalances = {}, multichainRates = {}, + accountsByChainId = {}, + tokenBalances = {}, + tokenMarketData = {}, + currencyRates = {}, + networkConfigs = {}, }: { currency?: string; accounts?: Record; @@ -107,11 +115,20 @@ const setup = ({ Record | undefined >; multichainRates?: Record; + accountsByChainId?: Record; + tokenBalances?: Record; + tokenMarketData?: Record; + currencyRates?: Record; + networkConfigs?: Record; }) => { - (selectAccountsByChainId as unknown as jest.Mock).mockReturnValue({}); - (selectTokensBalances as unknown as jest.Mock).mockReturnValue({}); - (selectTokenMarketData as unknown as jest.Mock).mockReturnValue({}); - (selectCurrencyRates as unknown as jest.Mock).mockReturnValue({}); + (selectAccountsByChainId as unknown as jest.Mock).mockReturnValue( + accountsByChainId, + ); + (selectTokensBalances as unknown as jest.Mock).mockReturnValue(tokenBalances); + (selectTokenMarketData as unknown as jest.Mock).mockReturnValue( + tokenMarketData, + ); + (selectCurrencyRates as unknown as jest.Mock).mockReturnValue(currencyRates); (selectCurrentCurrency as unknown as jest.Mock).mockReturnValue(currency); (selectMultichainBalances as unknown as jest.Mock).mockReturnValue( multichainBalances, @@ -123,7 +140,7 @@ const setup = ({ (scope: string) => accounts[scope] ?? undefined, ); mockUseSelector.mockImplementation((selector: (state: never) => unknown) => - selector(FAKE_STATE), + selector(makeState(networkConfigs)), ); }; @@ -141,9 +158,9 @@ describe('usePositionTokenBalance', () => { }); describe('Solana', () => { - it('prices the held balance and formats fiat with the user currency symbol', () => { + it('prices the held balance and formats fiat in the user display currency', () => { setup({ - currency: 'eur', + currency: 'usd', accounts: { [SOL_SCOPE]: solanaAccount }, multichainBalances: { [solanaAccount.id]: { [SOL_ASSET]: { amount: '12.5' } }, @@ -160,7 +177,7 @@ describe('usePositionTokenBalance', () => { expect(result.current).toMatchObject({ balance: '12.5', - balanceFiat: '€2500', + balanceFiat: '$2,500.00', tokenFiatAmount: 2500, currencyExchangeRate: 200, }); @@ -296,7 +313,7 @@ describe('usePositionTokenBalance', () => { expect(result.current).toMatchObject({ balance: '0.5', - balanceFiat: '$50000.00', + balanceFiat: '$50,000.00', tokenFiatAmount: 50000, currencyExchangeRate: 100000, }); @@ -335,4 +352,42 @@ describe('usePositionTokenBalance', () => { // No on-chain balance configured for the EVM account -> undefined. expect(result.current).toBeUndefined(); }); + + it('prices a held EVM ERC-20 with a lowercase address via checksum-keyed market data', () => { + // `tokenMarketData` is keyed by checksummed address, but position tokens can + // arrive lowercase; without normalization the price lookup misses and the + // token drops to the unpriced path (regression guard). + const lowercaseUsdc = '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48'; + const checksumUsdc = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'; + setup({ + accounts: { [EVM_SCOPE]: { id: 'evm', address: '0xAccount' } }, + // 1 token (1e18) held, keyed by the lowercase token address. + tokenBalances: { + '0xAccount': { '0x1': { [lowercaseUsdc]: '0xde0b6b3a7640000' } }, + }, + // Price is only resolvable under the checksummed key. + tokenMarketData: { '0x1': { [checksumUsdc]: { price: 0.5 } } }, + currencyRates: { ETH: { conversionRate: 2000 } }, + networkConfigs: { '0x1': { nativeCurrency: 'ETH' } }, + }); + + const evmToken = { + address: lowercaseUsdc, + chainId: '0x1', + symbol: 'USDC', + name: 'USDC', + decimals: 18, + } as BridgeToken; + + const { result } = renderHook(() => + usePositionTokenBalance(targetOn('0x1', lowercaseUsdc), evmToken), + ); + + expect(result.current).toMatchObject({ + balance: '1.0', + balanceFiat: '$1,000.00', + tokenFiatAmount: 1000, + currencyExchangeRate: 1000, + }); + }); }); diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.ts index 9eb73037771..2e97e609edb 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/usePositionTokenBalance.ts @@ -22,7 +22,9 @@ import { selectMultichainBalances, selectMultichainAssetsRates, } from '../../../../../../../selectors/multichain/multichain'; -import { addCurrencySymbol } from '../../../../../../../util/number/bigint'; +import { safeToChecksumAddress } from '../../../../../../../util/address'; +import { formatCurrency } from '../../../../../../UI/Bridge/utils/currencyUtils'; +import { calcTokenFiatRate } from '../../../../../../UI/Bridge/utils/exchange-rates'; import { EVM_SCOPE } from '../../../../../../UI/Earn/constants/networks'; import type { QuickBuyTarget } from '../types'; import { enrichTokenBalance } from './enrichTokenBalance'; @@ -30,7 +32,6 @@ import { hasNonZeroHexBalance, getCachedNativeBalance, getCachedErc20Balance, - getTokenPrice, } from './tokenBalanceUtils'; /** @@ -44,8 +45,10 @@ import { * * Mirrors the behaviour of the Bridge's `useTokensWithBalance` / * `calculateEvmBalances`: a held-but-unpriceable token is still surfaced (with - * `$0.00` fiat and an undefined `currencyExchangeRate`), so downstream flows - * can let the user act on the token amount instead of hiding it entirely. + * a zero fiat value in the user's display currency and an undefined + * `currencyExchangeRate`), so downstream flows can let the user act on the + * token amount instead of hiding it entirely. `currencyExchangeRate` is a + * user-currency-per-token rate (consistent across EVM and non-EVM). */ export const usePositionTokenBalance = ( target: QuickBuyTarget | null, @@ -88,24 +91,72 @@ export const usePositionTokenBalance = ( // the entire hook for production users. const caipChainId = target.chain as CaipChainId; - const fiatCurrency = currentCurrency as Parameters< - typeof addCurrencySymbol - >[1]; - const zeroFiat = addCurrencySymbol('0.00', fiatCurrency); + const zeroFiat = formatCurrency(0, currentCurrency); + + // `calcTokenFiatRate` looks up `tokenMarketData` by the raw `token.address` + // (keyed by checksummed addresses). + const pricedDestToken = + isNonEvmChainId(destToken.chainId) || isNativeAddress(destToken.address) + ? destToken + : { + ...destToken, + address: + safeToChecksumAddress(destToken.address) ?? destToken.address, + }; + + // The fiat rate is delegated to the canonical `calcTokenFiatRate`, so the + // position token shares the wallet-wide user-currency exchange-rate + // semantics (EVM native/ERC-20 and non-EVM are all handled there). It + // returns a user-currency-per-token rate, or `undefined` when no price is + // resolvable — in which case we still surface the held balance with a zero + // fiat value, matching the wallet-wide behaviour (see `calculateEvmBalances`). + const exchangeRate = calcTokenFiatRate({ + token: pricedDestToken, + evmMultiChainMarketData: tokenMarketData, + networkConfigurationsByChainId: (allNetworkConfigs ?? {}) as Record< + Hex, + { nativeCurrency: string } + >, + evmMultiChainCurrencyRates: currencyRates, + nonEvmMultichainAssetRates: multichainRates as Parameters< + typeof calcTokenFiatRate + >[0]['nonEvmMultichainAssetRates'], + }); + const hasRate = exchangeRate !== undefined && exchangeRate > 0; + + const buildResult = ( + balanceStr: string, + balanceNum: number, + ): BridgeToken => { + const fiatValue = hasRate ? balanceNum * (exchangeRate as number) : 0; + return { + ...destToken, + balance: balanceStr, + balanceFiat: hasRate + ? formatCurrency(fiatValue, currentCurrency) + : zeroFiat, + tokenFiatAmount: fiatValue, + currencyExchangeRate: hasRate ? exchangeRate : undefined, + }; + }; // ─── Non-EVM branch (Solana, Tron, Bitcoin) ─────────────────────── // `enrichTokenBalance` prices all non-EVM assets generically from the // chain-agnostic multichain balance/rate controllers, so it replaces the // bespoke per-chain handling here and keeps the EVM branch's // `formatChainIdToHex` (which throws for non-EVM CAIP ids) out of reach. + // It prices via the canonical `calcTokenFiatRate` in the user's display + // currency (`currentCurrency`), so Tron/Bitcoin positions are sellable and + // shown in the same currency as the EVM branch. // // Lenient mode (`includeZeroBalance`) so a held-but-unpriceable token // (real balance, no resolvable rate) stays sellable — matching the EVM // branch below and the wallet-wide `calculateEvmBalances` behaviour. The // lenient path also returns a zero-balance enrichment for tokens the user // doesn't hold, so we drop those (balance ≤ 0) to preserve the strict - // "no balance → not sellable" contract. Unpriced holdings render `$0.00` - // (via `zeroFiat`) rather than a dash, consistent with the EVM branch. + // "no balance → not sellable" contract. Unpriced holdings render the + // user-currency zero (via `zeroFiat`) rather than a dash, consistent with + // the EVM branch. if (isNonEvmChainId(caipChainId)) { const enrichment = enrichTokenBalance( destToken, @@ -115,8 +166,8 @@ export const usePositionTokenBalance = ( tokenBalances, tokenMarketData, currencyRates, + currentCurrency, allNetworkConfigs, - fiatCurrency, solanaAccount: solanaAccount ?? undefined, tronAccount: tronAccount ?? undefined, bitcoinAccount: bitcoinAccount ?? undefined, @@ -170,47 +221,7 @@ export const usePositionTokenBalance = ( const balanceNum = parseFloat(displayBalance); if (isNaN(balanceNum) || balanceNum <= 0) return undefined; - const networkConfig = allNetworkConfigs?.[hexChainId]; - const nativeTicker = networkConfig?.nativeCurrency; - const nativeConversionRate = nativeTicker - ? (currencyRates?.[nativeTicker]?.usdConversionRate ?? 0) - : 0; - - // Resolve the source token's price in user fiat. If anything's missing we - // still return the token with its real balance — downstream flows will - // operate on token amounts and render $0.00 for fiat, matching the - // wallet-wide behaviour (see `calculateEvmBalances`). - let exchangeRate: number | undefined; - if (nativeConversionRate > 0) { - if (isNativeAddress(target.tokenAddress)) { - exchangeRate = nativeConversionRate; - } else { - const tokenPrice = getTokenPrice( - tokenMarketData, - hexChainId, - target.tokenAddress, - ); - if (tokenPrice !== undefined) { - exchangeRate = tokenPrice * nativeConversionRate; - } - } - } - if (exchangeRate !== undefined && exchangeRate <= 0) { - exchangeRate = undefined; - } - - const fiatValue = - exchangeRate !== undefined ? balanceNum * exchangeRate : 0; - return { - ...destToken, - balance: displayBalance, - balanceFiat: - exchangeRate !== undefined - ? addCurrencySymbol(fiatValue.toFixed(2), fiatCurrency) - : zeroFiat, - tokenFiatAmount: fiatValue, - currencyExchangeRate: exchangeRate, - }; + return buildResult(displayBalance, balanceNum); }, [ target, destToken, diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useQuickBuyController.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useQuickBuyController.ts index 56abf6a43e5..1bbe609093b 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useQuickBuyController.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useQuickBuyController.ts @@ -10,7 +10,11 @@ import { } from 'react'; import { TextInput } from 'react-native'; import { useDispatch, useSelector } from 'react-redux'; -import { selectCurrentCurrency } from '../../../../../../../selectors/currencyRateController'; +import { + selectCurrencyRates, + selectCurrentCurrency, +} from '../../../../../../../selectors/currencyRateController'; +import { selectNetworkConfigurations } from '../../../../../../../selectors/networkController'; import { ImpactMoment, playErrorNotification, @@ -27,7 +31,9 @@ import { formatCurrency, formatMinimumReceived, } from '../../../../../../UI/Bridge/utils/currencyUtils'; +import { FIAT_INPUT_DECIMALS } from '../../../../../../UI/Bridge/utils/sourceAmountInputMode'; import { isGaslessQuote } from '../../../../../../UI/Bridge/utils/isGaslessQuote'; +import { calcUsdAmountFromFiat } from '../../../../../../UI/Bridge/utils/exchange-rates'; import { isSameAsset, selectDefaultSourceToken, @@ -149,16 +155,19 @@ export interface UseQuickBuyControllerResult { currentCurrency: string; // amount amountDisplayMode: QuickBuyAmountDisplayMode; - usdAmount: string; + /** Raw entered amount in the user's display currency (unformatted, e.g. "20"). */ + fiatAmount: string; + /** Entered amount preformatted in the user's display currency (e.g. "$20", "20 €"). */ + fiatAmountLabel: string; /** Token-units amount entered in the unpriced sell path (otherwise ''). */ sourceAmountTokens: string; - /** Source token amount in token units (derived from USD for priced, or directly entered for unpriced). */ + /** Source token amount in token units (derived from the fiat amount for priced, or directly entered for unpriced). */ sourceTokenAmount: string | undefined; /** True when the source token has a usable fiat exchange rate. */ hasSourcePrice: boolean; sliderPercent: number; - maxSpendUsd: number; - /** True when neither USD nor token-balance gates allow slider interaction. */ + maxSpendFiat: number; + /** True when neither fiat nor token-balance gates allow slider interaction. */ isSliderDisabled: boolean; formattedExchangeRate: string | undefined; metamaskFeePercent: number; @@ -177,7 +186,7 @@ export interface UseQuickBuyControllerResult { formattedMinimumReceivedFiat: string | undefined; formattedPriceImpact: string; formattedRate: string | undefined; - totalAmountUsd: string; + totalAmountFiat: string; // quote state isQuoteLoading: boolean; /** @@ -246,7 +255,7 @@ export function useQuickBuyController( } = useQuickBuyAnalytics(traderAddress, caip19, analyticsContext); const [tradeMode, setTradeMode] = useState('buy'); - const [usdAmount, setUsdAmount] = useState(''); + const [fiatAmount, setFiatAmount] = useState(''); const [sourceAmountTokens, setSourceAmountTokens] = useState(''); // True when the user has committed the slider to 100% ("sell all"). In this // mode `sourceTokenAmount` spends the exact on-chain balance rather than a @@ -257,22 +266,24 @@ export function useQuickBuyController( // Drives quote re-fetching. Updated only when the user commits a value // (slider drag end, tap, or text input) — NOT on every drag tick. This // prevents spamming quote requests while the thumb is moving. - const [quotedUsdAmount, setQuotedUsdAmount] = useState(''); + const [quotedFiatAmount, setQuotedFiatAmount] = useState(''); // Bumped whenever the user commits an amount in a single discrete gesture // (slider release) so the quotes hook fetches immediately instead of waiting // out the typing debounce. Typed input intentionally does NOT bump this — it // stays debounced to avoid a request per keystroke. const [immediateFetchToken, setImmediateFetchToken] = useState(0); // Fiat-first: every input path (slider, hidden TextInput, amount-area press) - // edits the USD amount, so the primary label must default to fiat as well. - // The user can swap to crypto display via the toggle once a quote is available. + // edits the user-currency amount, so the primary label must default to fiat + // as well. The user can swap to crypto display via the toggle once a quote is + // available. const [amountDisplayMode, setAmountDisplayMode] = useState('fiat'); const [sliderPercent, setSliderPercent] = useState(0); const lastSliderPercentRef = useRef(0); - // Deduplicates consecutive handleSliderDragEnd calls with the same USD amount - // (can happen when Tap + Pan both fire onEnd for a pure tap gesture). - const lastCommittedUsdRef = useRef(''); + // Deduplicates consecutive handleSliderDragEnd calls with the same + // user-currency amount (can happen when Tap + Pan both fire onEnd for a pure + // tap gesture). + const lastCommittedFiatRef = useRef(''); const [selectedQuoteRequestId, setSelectedQuoteRequestId] = useState< string | undefined >(undefined); @@ -287,6 +298,8 @@ export function useQuickBuyController( const isNonEvmSourced = useSelector(selectIsNonEvmSourced); const bridgeFeatureFlags = useSelector(selectBridgeFeatureFlags); const currentCurrency = useSelector(selectCurrentCurrency); + const currencyRates = useSelector(selectCurrencyRates); + const networkConfigurations = useSelector(selectNetworkConfigurations); const selectedAddress = useSelector( selectSelectedInternalAccountFormattedAddress, ); @@ -448,6 +461,26 @@ export function useQuickBuyController( tradeMode === 'buy' ? positionTokenFromSetup : selectedDestStable; const sourceChainId = sourceToken?.chainId as Hex | undefined; + // The entered amount is in the user's display currency, but the + // `amount_usd` analytics property is contractually USD. Convert via the + // pure fiat->USD ratio (usdConversionRate / conversionRate) derived from the + // source chain's native-currency rates. Returns 0 when rates are unavailable + // so analytics never reports a user-currency value as USD. + const toAmountUsd = useCallback( + (fiat: number): number => { + if (!Number.isFinite(fiat) || fiat <= 0) return 0; + return ( + calcUsdAmountFromFiat({ + tokenFiatValue: fiat, + chainId: sourceToken?.chainId, + networkConfigurationsByChainId: networkConfigurations, + evmMultiChainCurrencyRates: currencyRates, + }) ?? 0 + ); + }, + [sourceToken?.chainId, networkConfigurations, currencyRates], + ); + // BridgeController.fetchQuotes does not start gas fee polling, so estimates // for the source chain may be missing when selectBridgeQuotesBase enriches // the quote — producing a $0 network fee. Poll explicitly for the source @@ -556,12 +589,14 @@ export function useQuickBuyController( return latestSourceBalance.displayBalance; } if (hasSourcePrice) { - if (!quotedUsdAmount || !sourceToken?.currencyExchangeRate) { + if (!quotedFiatAmount || !sourceToken?.currencyExchangeRate) { return undefined; } - const usd = parseFloat(quotedUsdAmount); - if (isNaN(usd) || usd <= 0) return undefined; - return (usd / sourceToken.currencyExchangeRate).toString(); + // `currencyExchangeRate` is user-currency-per-token and `quotedFiatAmount` + // is in the user's display currency, so fiat / rate yields token units. + const fiat = parseFloat(quotedFiatAmount); + if (isNaN(fiat) || fiat <= 0) return undefined; + return (fiat / sourceToken.currencyExchangeRate).toString(); } // Unpriced path: source amount is entered directly in token units. if (!sourceAmountTokens) return undefined; @@ -572,7 +607,7 @@ export function useQuickBuyController( hasSourcePrice, isMaxSourceAmount, latestSourceBalance?.displayBalance, - quotedUsdAmount, + quotedFiatAmount, sourceAmountTokens, sourceToken?.currencyExchangeRate, ]); @@ -586,28 +621,34 @@ export function useQuickBuyController( }, [sourceTokenAmount, dispatch]); // Used for analytics passed to useQuickBuyQuotes. Must derive from - // quotedUsdAmount (not usdAmount) so that mid-drag display updates don't + // quotedFiatAmount (not fiatAmount) so that mid-drag display updates don't // recreate quotesAnalyticsContext and trigger spurious quote re-fetches. - const quotedUsdAmountNumber = useMemo(() => { - const v = Number(quotedUsdAmount); + const quotedFiatAmountNumber = useMemo(() => { + const v = Number(quotedFiatAmount); return Number.isFinite(v) ? v : 0; - }, [quotedUsdAmount]); - // Derives from usdAmount for handleConfirm (the confirm button is disabled - // when usdAmount !== quotedUsdAmount, so by the time confirm is pressed they + }, [quotedFiatAmount]); + // Derives from fiatAmount for handleConfirm (the confirm button is disabled + // when fiatAmount !== quotedFiatAmount, so by the time confirm is pressed they // are always equal — keeping separate avoids recreating handleConfirm on // every drag tick). - const usdAmountNumber = useMemo(() => { - const v = Number(usdAmount); + const fiatAmountNumber = useMemo(() => { + const v = Number(fiatAmount); return Number.isFinite(v) ? v : 0; - }, [usdAmount]); + }, [fiatAmount]); + // `amount_usd` analytics is contractually USD; the committed amount is in the + // user's display currency, so convert before it leaves for analytics. + const quotedAmountUsd = useMemo( + () => toAmountUsd(quotedFiatAmountNumber), + [toAmountUsd, quotedFiatAmountNumber], + ); const quotesAnalyticsContext = useMemo( () => ({ traderAddress, caip19, - amountUsd: quotedUsdAmountNumber, + amountUsd: quotedAmountUsd, source: analyticsContext?.source, }), - [traderAddress, caip19, quotedUsdAmountNumber, analyticsContext?.source], + [traderAddress, caip19, quotedAmountUsd, analyticsContext?.source], ); const { @@ -653,7 +694,7 @@ export function useQuickBuyController( const formattedNetworkFee = useFormattedNetworkFee(activeQuote ?? null); - const networkFeeRawUsd = useMemo(() => { + const networkFeeFiat = useMemo(() => { if (!activeQuote) return null; if (isGaslessQuote(activeQuote.quote)) { const v = activeQuote.includedTxFees?.valueInCurrency; @@ -732,14 +773,17 @@ export function useQuickBuyController( [activeQuote, bridgeFeatureFlags], ); - const totalAmountUsd = useMemo(() => { - const inputNum = parseFloat(usdAmount); - if (!usdAmount || isNaN(inputNum)) return '$0'; - if (activeQuote && networkFeeRawUsd !== null) { - return `$${(inputNum + networkFeeRawUsd).toFixed(2)}`; + const totalAmountFiat = useMemo(() => { + const inputNum = parseFloat(fiatAmount); + const zero = formatCurrency(0, currentCurrency); + if (!fiatAmount || isNaN(inputNum)) return zero; + // Both the entered amount and the quote's network fee (`valueInCurrency`) + // are already in the user's display currency. + if (activeQuote && networkFeeFiat !== null) { + return formatCurrency(inputNum + networkFeeFiat, currentCurrency); } - return '$0'; - }, [usdAmount, activeQuote, networkFeeRawUsd]); + return zero; + }, [fiatAmount, activeQuote, networkFeeFiat, currentCurrency]); const hasInsufficientBalance = useIsInsufficientBalance({ amount: sourceTokenAmount, @@ -757,7 +801,7 @@ export function useQuickBuyController( const hasDestinationPicker = isEvmNonEvmBridge || isNonEvmNonEvmBridge; const isDestinationAddressMissing = hasDestinationPicker && !destAddress; - const sourceBalanceFiatUsd = useMemo(() => { + const sourceBalanceFiatValue = useMemo(() => { if ( !latestSourceBalance?.displayBalance || !liveSourceCurrencyExchangeRate @@ -771,8 +815,8 @@ export function useQuickBuyController( }, [latestSourceBalance?.displayBalance, liveSourceCurrencyExchangeRate]); const sourceBalanceFiat = useMemo( - () => formatCurrency(sourceBalanceFiatUsd, currentCurrency), - [sourceBalanceFiatUsd, currentCurrency], + () => formatCurrency(sourceBalanceFiatValue, currentCurrency), + [sourceBalanceFiatValue, currentCurrency], ); const sourceBalanceDisplay = useMemo(() => { @@ -794,7 +838,7 @@ export function useQuickBuyController( // pass it straight through rather than re-deriving it from a token amount. const destBalanceFiat = liveSelectedDestBalance?.balanceFiat; - const maxSpendUsd = sourceBalanceFiatUsd; + const maxSpendFiat = sourceBalanceFiatValue; // Token-amount-based gate: used for sources we can't price. Mirrors how the // Bridge / asset list keep unpriceable tokens usable as long as the user @@ -807,7 +851,7 @@ export function useQuickBuyController( }, [latestSourceBalance?.displayBalance]); const isSliderDisabled = hasSourcePrice - ? maxSpendUsd <= 0 + ? maxSpendFiat <= 0 : maxSpendTokens <= 0; // For the toolbar rate pill in buy mode the dest token from `useQuickBuySetup` @@ -841,7 +885,7 @@ export function useQuickBuyController( }, [onClose]); // Updates the display state (thumb position + fiat label) on every 1% tick - // during a drag. Does NOT commit to quotedUsdAmount or fire analytics — that + // during a drag. Does NOT commit to quotedFiatAmount or fire analytics — that // is deferred to handleSliderDragEnd so we only re-fetch quotes once per // gesture, not on every pixel of movement. const handleSliderChange = useCallback( @@ -871,31 +915,33 @@ export function useQuickBuyController( } // ── Priced path: update display state only (quote commits on drag end). ── - if (maxSpendUsd <= 0) { - setUsdAmount(''); + if (maxSpendFiat <= 0) { + setFiatAmount(''); return; } - const nextUsd = - rounded === 0 ? '' : ((maxSpendUsd * rounded) / 100).toFixed(2); - setUsdAmount(nextUsd); + const nextFiat = + rounded === 0 + ? '' + : ((maxSpendFiat * rounded) / 100).toFixed(FIAT_INPUT_DECIMALS); + setFiatAmount(nextFiat); lastInputMethodRef.current = SocialLeaderboardEventValues.AMOUNT_SELECTION_METHOD.SLIDER; }, - [hasSourcePrice, maxSpendTokens, maxSpendUsd, lastInputMethodRef], + [hasSourcePrice, maxSpendTokens, maxSpendFiat, lastInputMethodRef], ); // Called once when the user lifts their finger (pan end) or taps the track. - // Commits the final value to quotedUsdAmount (triggering a quote re-fetch) + // Commits the final value to quotedFiatAmount (triggering a quote re-fetch) // and fires analytics exactly once per interaction. const handleSliderDragEnd = useCallback( (percent: number) => { const rounded = Math.round(percent); - const nextUsd = - rounded === 0 || maxSpendUsd <= 0 + const nextFiat = + rounded === 0 || maxSpendFiat <= 0 ? '' - : ((maxSpendUsd * rounded) / 100).toFixed(2); + : ((maxSpendFiat * rounded) / 100).toFixed(FIAT_INPUT_DECIMALS); - // Flag max BEFORE the dedup guard. lastCommittedUsdRef is also written by + // Flag max BEFORE the dedup guard. lastCommittedFiatRef is also written by // typed input and the price-migration effect, so releasing the slider at // 100% can match the ref and return early (e.g. user typed the exact max, // then slid to 100% to "sell all"). If setIsMaxSourceAmount ran after the @@ -905,28 +951,28 @@ export function useQuickBuyController( setIsMaxSourceAmount(rounded >= 100); // Deduplicate: Tap + Pan can both fire onEnd for a pure tap gesture. - if (nextUsd === lastCommittedUsdRef.current) { + if (nextFiat === lastCommittedFiatRef.current) { return; } - lastCommittedUsdRef.current = nextUsd; + lastCommittedFiatRef.current = nextFiat; // Guarantee display state matches the committed value. The last onUpdate // tick during a Pan may have landed on a different % than where the - // finger actually lifted — if so, usdAmount would be stale relative to - // quotedUsdAmount, keeping isAmountUncommitted true and the Buy button + // finger actually lifted — if so, fiatAmount would be stale relative to + // quotedFiatAmount, keeping isAmountUncommitted true and the Buy button // permanently disabled. Syncing both states here is the authoritative fix. setSliderPercent(rounded); lastSliderPercentRef.current = rounded; - setUsdAmount(nextUsd); + setFiatAmount(nextFiat); - setQuotedUsdAmount(nextUsd); - const numericUsd = Number(nextUsd); - if (rounded > 0 && Number.isFinite(numericUsd) && numericUsd > 0) { + setQuotedFiatAmount(nextFiat); + const numericFiat = Number(nextFiat); + if (rounded > 0 && Number.isFinite(numericFiat) && numericFiat > 0) { // Slider release is a single committed value — fetch the quote // immediately rather than waiting out the typing debounce. setImmediateFetchToken((token) => token + 1); trackAmountSelected( - numericUsd, + toAmountUsd(numericFiat), SocialLeaderboardEventValues.AMOUNT_SELECTION_METHOD.SLIDER, tradeMode === 'buy' ? sourceToken?.symbol : undefined, rounded, @@ -935,10 +981,11 @@ export function useQuickBuyController( } }, [ - maxSpendUsd, + maxSpendFiat, sourceToken?.symbol, destToken?.symbol, tradeMode, + toAmountUsd, trackAmountSelected, ], ); @@ -960,13 +1007,13 @@ export function useQuickBuyController( }, []); const resetAmountState = useCallback(() => { - setUsdAmount(''); - setQuotedUsdAmount(''); + setFiatAmount(''); + setQuotedFiatAmount(''); setSourceAmountTokens(''); setIsMaxSourceAmount(false); setSliderPercent(0); lastSliderPercentRef.current = 0; - lastCommittedUsdRef.current = ''; + lastCommittedFiatRef.current = ''; lastTrackedAmountRef.current = ''; lastInputMethodRef.current = SocialLeaderboardEventValues.AMOUNT_SELECTION_METHOD.SLIDER; @@ -988,8 +1035,8 @@ export function useQuickBuyController( // If the source token's price becomes available (or disappears) while the // sheet is open — e.g. a new market-data fetch lands — re-align the display // mode so the headline reflects what we can honestly show. If price arrives - // after the user already entered a token amount, convert it to USD so the - // amount is not lost. + // after the user already entered a token amount, convert it to the user's + // display currency so the amount is not lost. const prevHasSourcePriceRef = useRef(hasSourcePrice); useEffect(() => { if (prevHasSourcePriceRef.current === hasSourcePrice) return; @@ -998,7 +1045,8 @@ export function useQuickBuyController( if (!hasSourcePrice) { setAmountDisplayMode('crypto'); } else if (!prev) { - // Price just became available — migrate any entered token amount to USD. + // Price just became available — migrate any entered token amount to the + // user's display currency (`currencyExchangeRate` is user-currency-per-token). setAmountDisplayMode('fiat'); const tokens = parseFloat(sourceAmountTokens); if ( @@ -1006,10 +1054,12 @@ export function useQuickBuyController( tokens > 0 && liveSourceCurrencyExchangeRate ) { - const usd = (tokens * liveSourceCurrencyExchangeRate).toFixed(2); - setUsdAmount(usd); - setQuotedUsdAmount(usd); - lastCommittedUsdRef.current = usd; + const fiat = (tokens * liveSourceCurrencyExchangeRate).toFixed( + FIAT_INPUT_DECIMALS, + ); + setFiatAmount(fiat); + setQuotedFiatAmount(fiat); + lastCommittedFiatRef.current = fiat; } } }, [hasSourcePrice, sourceAmountTokens, liveSourceCurrencyExchangeRate]); @@ -1039,16 +1089,17 @@ export function useQuickBuyController( const normalized = cleaned.startsWith('.') ? `0${cleaned}` : cleaned; const parts = normalized.split('.'); if (parts.length > 2) return; - // Priced (fiat) input: cap to 2 decimals. Unpriced (token) input: allow - // up to the token's decimals so the user can spend small balances. + // Priced (fiat) input: cap to two decimals, matching Bridge fiat mode + // (`FIAT_INPUT_DECIMALS`). Unpriced (token) input: allow up to the token's + // decimals so the user can spend small balances. const maxFractionDigits = hasSourcePrice - ? 2 + ? FIAT_INPUT_DECIMALS : (sourceToken?.decimals ?? 18); if (parts.length === 2 && parts[1].length > maxFractionDigits) return; if (hasSourcePrice) { - setUsdAmount(normalized); - setQuotedUsdAmount(normalized); - lastCommittedUsdRef.current = normalized; + setFiatAmount(normalized); + setQuotedFiatAmount(normalized); + lastCommittedFiatRef.current = normalized; } else { setSourceAmountTokens(normalized); } @@ -1063,13 +1114,16 @@ export function useQuickBuyController( // stops typing for 500ms, so we don't emit on every keystroke. useEffect(() => { if (lastInputMethodRef.current !== 'custom_input') return; - if (!usdAmount) return; - const numeric = Number(usdAmount); - if (!Number.isFinite(numeric) || numeric <= 0) return; - if (lastTrackedAmountRef.current === String(numeric)) return; + if (!fiatAmount) return; + const numericFiat = Number(fiatAmount); + if (!Number.isFinite(numericFiat) || numericFiat <= 0) return; + // `amount_usd` is contractually USD; convert the entered display-currency + // amount and dedupe against the same USD value the tracker records. + const amountUsd = toAmountUsd(numericFiat); + if (lastTrackedAmountRef.current === String(amountUsd)) return; const handle = setTimeout(() => { trackAmountSelected( - numeric, + amountUsd, SocialLeaderboardEventValues.AMOUNT_SELECTION_METHOD.CUSTOM_INPUT, tradeMode === 'buy' ? sourceToken?.symbol : undefined, undefined, @@ -1078,10 +1132,11 @@ export function useQuickBuyController( }, 500); return () => clearTimeout(handle); }, [ - usdAmount, + fiatAmount, sourceToken?.symbol, destToken?.symbol, tradeMode, + toAmountUsd, trackAmountSelected, lastInputMethodRef, lastTrackedAmountRef, @@ -1090,7 +1145,10 @@ export function useQuickBuyController( const handleConfirm = useCallback(async () => { if (!activeQuote || !walletAddress) return; - const amountUsd = usdAmountNumber > 0 ? usdAmountNumber : undefined; + // `amount_usd` is contractually USD; the entered amount is in the user's + // display currency, so convert it here. + const amountUsdValue = toAmountUsd(fiatAmountNumber); + const amountUsd = amountUsdValue > 0 ? amountUsdValue : undefined; const amountTokenRaw = activeQuote.toTokenAmount?.amount; const amountToken = amountTokenRaw != null && isNumberValue(amountTokenRaw) @@ -1155,7 +1213,7 @@ export function useQuickBuyController( tokenSymbol: target.tokenSymbol, counterTokenSymbol: (tradeMode === 'buy' ? sourceToken?.symbol : destToken?.symbol) ?? '', - fiatAmountLabel: formatCurrency(usdAmountNumber, currentCurrency), + fiatAmountLabel: formatCurrency(fiatAmountNumber, currentCurrency), rate: formattedRate, isNonEvmSwap, }; @@ -1271,7 +1329,8 @@ export function useQuickBuyController( isNonEvmNonEvmBridge, sourceToken?.chainId, destToken?.chainId, - usdAmountNumber, + fiatAmountNumber, + toAmountUsd, currentCurrency, formattedRate, traderAddress, @@ -1286,13 +1345,21 @@ export function useQuickBuyController( submitStartedAtRef, ]); + // Preformatted headline value in the user's display currency (correct symbol + // placement + separators for any locale/currency). The view renders this + // string directly instead of concatenating a hardcoded "$". + const fiatAmountLabel = useMemo( + () => formatCurrency(Number(fiatAmount) || 0, currentCurrency), + [fiatAmount, currentCurrency], + ); + const hasError = Boolean(quoteFetchError || isNoQuotesAvailable); const hasValidAmount = hasSourcePrice - ? Boolean(usdAmount && Number(usdAmount) > 0) + ? Boolean(fiatAmount && Number(fiatAmount) > 0) : Boolean(sourceAmountTokens && Number(sourceAmountTokens) > 0); // True while the slider is mid-drag: the user has moved the thumb but has not // yet committed (released). - const isAmountUncommitted = usdAmount !== quotedUsdAmount; + const isAmountUncommitted = fiatAmount !== quotedFiatAmount; const hasQuoteRequestableAmount = useMemo(() => { const hasNonZeroInputAmount = Boolean( sourceTokenAmount && Number(sourceTokenAmount) !== 0, @@ -1449,12 +1516,13 @@ export function useQuickBuyController( selectedDestStable, currentCurrency, amountDisplayMode, - usdAmount, + fiatAmount, + fiatAmountLabel, sourceAmountTokens, sourceTokenAmount, hasSourcePrice, sliderPercent, - maxSpendUsd, + maxSpendFiat, isSliderDisabled, formattedExchangeRate, metamaskFeePercent, @@ -1468,7 +1536,7 @@ export function useQuickBuyController( formattedMinimumReceivedFiat, formattedPriceImpact, formattedRate, - totalAmountUsd, + totalAmountFiat, isQuoteLoading, isBlockingQuoteLoad, isSubmittingTx, diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.test.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.test.ts index 0c6d80c2444..b19baf3a40f 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.test.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.test.ts @@ -33,6 +33,7 @@ jest.mock('../../../../../../../selectors/tokenRatesController', () => ({ jest.mock('../../../../../../../selectors/currencyRateController', () => ({ selectCurrencyRates: jest.fn(() => ({})), + selectCurrentCurrency: jest.fn(() => 'USD'), })); jest.mock('../../../../../../../selectors/multichain/multichain', () => ({ diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.ts index 54f18fa9c12..dc38830d29f 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/hooks/useReceiveTokens.ts @@ -9,7 +9,10 @@ import { selectAccountsByChainId } from '../../../../../../../selectors/accountT import { selectSelectedInternalAccountByScope } from '../../../../../../../selectors/multichainAccounts/accounts'; import { selectTokensBalances } from '../../../../../../../selectors/tokenBalancesController'; import { selectTokenMarketData } from '../../../../../../../selectors/tokenRatesController'; -import { selectCurrencyRates } from '../../../../../../../selectors/currencyRateController'; +import { + selectCurrencyRates, + selectCurrentCurrency, +} from '../../../../../../../selectors/currencyRateController'; import { selectMultichainBalances, selectMultichainAssetsRates, @@ -168,6 +171,7 @@ export const useReceiveTokens = ( const tokenBalances = useSelector(selectTokensBalances); const tokenMarketData = useSelector(selectTokenMarketData); const currencyRates = useSelector(selectCurrencyRates); + const currentCurrency = useSelector(selectCurrentCurrency); const multichainBalances = useSelector(selectMultichainBalances); const multichainRates = useSelector(selectMultichainAssetsRates); const allNetworkConfigs = useSelector( @@ -187,6 +191,7 @@ export const useReceiveTokens = ( tokenBalances, tokenMarketData, currencyRates, + currentCurrency, allNetworkConfigs, solanaAccount: solanaAccount ?? undefined, tronAccount: tronAccount ?? undefined, @@ -210,6 +215,7 @@ export const useReceiveTokens = ( tokenBalances, tokenMarketData, currencyRates, + currentCurrency, allNetworkConfigs, solanaAccount, tronAccount, diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/useQuickBuyController.test.ts b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/useQuickBuyController.test.ts index 6ca75673243..1557ddf1956 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/useQuickBuyController.test.ts +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/components/QuickBuy/useQuickBuyController.test.ts @@ -16,7 +16,11 @@ import { } from '../../../../../../core/redux/slices/bridge'; import { selectSelectedInternalAccountFormattedAddress } from '../../../../../../selectors/accountsController'; import { selectSourceWalletAddress } from '../../../../../../selectors/bridge'; -import { selectCurrentCurrency } from '../../../../../../selectors/currencyRateController'; +import { + selectCurrentCurrency, + selectCurrencyRates, +} from '../../../../../../selectors/currencyRateController'; +import { selectNetworkConfigurations } from '../../../../../../selectors/networkController'; import { selectShouldUseSmartTransaction } from '../../../../../../selectors/smartTransactionsController'; import { ImpactMoment, @@ -205,6 +209,11 @@ jest.mock('../../../../../../selectors/accountsController', () => ({ jest.mock('../../../../../../selectors/currencyRateController', () => ({ selectCurrentCurrency: jest.fn(), + selectCurrencyRates: jest.fn(), +})); + +jest.mock('../../../../../../selectors/networkController', () => ({ + selectNetworkConfigurations: jest.fn(), })); jest.mock('../../../../../../util/address', () => ({ @@ -360,6 +369,15 @@ const setupDefaultMocks = () => { selectSelectedInternalAccountFormattedAddress as unknown as jest.Mock ).mockReturnValue('0xWALLET'); (selectCurrentCurrency as unknown as jest.Mock).mockReturnValue('USD'); + // Native-currency rates + network configs power the fiat->USD conversion for + // `amount_usd` analytics. conversionRate === usdConversionRate keeps the USD + // case a 1:1 conversion (entered USD amount == amount_usd). + (selectCurrencyRates as unknown as jest.Mock).mockReturnValue({ + ETH: { conversionRate: 2000, usdConversionRate: 2000 }, + }); + (selectNetworkConfigurations as unknown as jest.Mock).mockReturnValue({ + '0x1': { nativeCurrency: 'ETH' }, + }); (usePriceImpactViewData as jest.Mock).mockReturnValue({ textColor: TextColor.TextAlternative, icon: undefined, @@ -442,7 +460,7 @@ describe('useQuickBuyController', () => { result.current.handleAmountChange('20'); }); - expect(result.current.usdAmount).toBe('20'); + expect(result.current.fiatAmount).toBe('20'); }); it('normalizes a leading decimal without digits', () => { @@ -454,7 +472,7 @@ describe('useQuickBuyController', () => { result.current.handleAmountChange('.'); }); - expect(result.current.usdAmount).toBe('0.'); + expect(result.current.fiatAmount).toBe('0.'); expect(result.current.hasValidAmount).toBe(false); }); @@ -467,7 +485,7 @@ describe('useQuickBuyController', () => { result.current.handleAmountChange('.5'); }); - expect(result.current.usdAmount).toBe('0.5'); + expect(result.current.fiatAmount).toBe('0.5'); expect(result.current.hasValidAmount).toBe(true); }); @@ -495,13 +513,13 @@ describe('useQuickBuyController', () => { result.current.handleAmountChange('25'); }); - expect(result.current.usdAmount).toBe('25'); + expect(result.current.fiatAmount).toBe('25'); expect(result.current.sliderPercent).toBe(0); }); }); describe('handleSliderChange', () => { - it('updates display state (sliderPercent, usdAmount) on every 1% tick', () => { + it('updates display state (sliderPercent, fiatAmount) on every 1% tick', () => { (useLatestBalance as jest.Mock).mockReturnValue({ displayBalance: '100', atomicBalance: '100000000', @@ -520,7 +538,7 @@ describe('useQuickBuyController', () => { }); expect(result.current.sliderPercent).toBe(50); - expect(Number(result.current.usdAmount)).toBeGreaterThan(0); + expect(Number(result.current.fiatAmount)).toBeGreaterThan(0); }); it('does not fire analytics during drag — only updates display', () => { @@ -599,6 +617,72 @@ describe('useQuickBuyController', () => { }); }); + describe('user-currency (non-USD)', () => { + it('formats the headline in the user currency while emitting amount_usd in USD', () => { + // EUR display currency; native ETH worth €1,000 / $1,200 → USD = EUR * 1.2. + (selectCurrentCurrency as unknown as jest.Mock).mockReturnValue('EUR'); + (selectCurrencyRates as unknown as jest.Mock).mockReturnValue({ + ETH: { conversionRate: 1000, usdConversionRate: 1200 }, + }); + (useLatestBalance as jest.Mock).mockReturnValue({ + displayBalance: '100', + atomicBalance: '100000000', + }); + const sourceWithRate = createSourceToken({ currencyExchangeRate: 1 }); + (usePayWithTokens as jest.Mock).mockReturnValue({ + options: [sourceWithRate], + }); + + const { result } = renderHook(() => + useQuickBuyController(createTarget(), jest.fn()), + ); + + act(() => { + result.current.handleAmountChange('20'); + }); + + // Headline is localized to the user's display currency, not hardcoded USD. + expect(result.current.fiatAmount).toBe('20'); + expect(result.current.fiatAmountLabel).toBe('€20.00'); + + // Committing via the slider emits analytics in USD (20 EUR * 1.2 = 24 USD). + act(() => { + result.current.handleSliderDragEnd(20); + }); + + expect(mockTrackAmountSelected).toHaveBeenCalledTimes(1); + expect(mockTrackAmountSelected.mock.calls[0][0]).toBeCloseTo(24); + }); + + it('uses two-decimal fiat state for JPY (same as Bridge fiat input)', () => { + (selectCurrentCurrency as unknown as jest.Mock).mockReturnValue('JPY'); + (selectCurrencyRates as unknown as jest.Mock).mockReturnValue({ + ETH: { conversionRate: 1000, usdConversionRate: 1000 }, + }); + (useLatestBalance as jest.Mock).mockReturnValue({ + displayBalance: '100', + atomicBalance: '100000000', + }); + const sourceWithRate = createSourceToken({ currencyExchangeRate: 1 }); + (usePayWithTokens as jest.Mock).mockReturnValue({ + options: [sourceWithRate], + }); + + const { result } = renderHook(() => + useQuickBuyController(createTarget(), jest.fn()), + ); + + act(() => { + result.current.handleSliderChange(33); + }); + + // 33% of a ¥100 cap = ¥33.00 in state (FIAT_INPUT_DECIMALS); headline + // still formats via Intl as whole yen. + expect(result.current.fiatAmount).toBe('33.00'); + expect(result.current.fiatAmountLabel).toBe('¥33'); + }); + }); + describe('max ("sell all") source amount', () => { // A near-$1 stablecoin whose rate is fractionally below 1. The fiat // round-trip (balance → cent-rounded USD → tokens) reconstructs an amount @@ -714,7 +798,7 @@ describe('useQuickBuyController', () => { result.current.handleAmountChange('25'); }); - expect(result.current.usdAmount).toBe('25'); + expect(result.current.fiatAmount).toBe('25'); expect(result.current.sliderPercent).toBe(0); act(() => { @@ -722,7 +806,7 @@ describe('useQuickBuyController', () => { }); expect(result.current.selectedSourceToken).toEqual(usdt); - expect(result.current.usdAmount).toBe(''); + expect(result.current.fiatAmount).toBe(''); expect(result.current.sliderPercent).toBe(0); }); }); @@ -854,7 +938,7 @@ describe('useQuickBuyController', () => { }); describe('isConfirmDisabled', () => { - it('is disabled when usdAmount is empty', () => { + it('is disabled when fiatAmount is empty', () => { const { result } = renderHook(() => useQuickBuyController(createTarget(), jest.fn()), ); From 3e8ed439bec64994df50a69f70303a23b33ccaff Mon Sep 17 00:00:00 2001 From: javiergarciavera <76975121+javiergarciavera@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:51:14 +0200 Subject: [PATCH 15/23] feat(perf): send installed app size to Sentry [MMQA-1974] (#31800) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After BrowserStack session enrichment, extract the installed app size from profiling data and publish it to Sentry as an `app_size_mb` measurement (unit: megabyte), using the same publisher and DSN as the per-test timing metrics. ## **Description** This PR extends the E2E performance reporting pipeline to track installed app size over time in Sentry. After a BrowserStack session is enriched with profiling data, the `app_size` metric (in MB) is extracted from the profiling summary and published to Sentry as an `app_size_mb` measurement with `megabyte` unit. It reuses the existing `publishPerformanceScenarioToSentry` publisher and DSN, so no new infrastructure is needed. Changes: - `types.ts`: add `app_size` to `ProfilingData` metrics; `appSizeMb` to `ProfilingSummary` - `PerformanceTracker.ts`: add optional `appSizeMb` field to `MetricsOutput` - `BrowserStackEnricher.ts`: extract `app_size` into `profilingSummary.appSizeMb` - `PerformanceSentryPublisher.ts`: add `app_size_mb` measurement (megabyte unit); allow publishing when only `appSizeMb` is set and `steps` is empty - `PerformanceReporter.ts`: call `publishAppSizeToSentry()` after enrichment - `PerformanceSentryPublisher.test.ts`: 3 new tests covering `app_size_mb` ## **Changelog** CHANGELOG entry: null ## **Related issues** Refs: https://consensyssoftware.atlassian.net/browse/MMQA-1974 ## **Manual testing steps** This is a CI/test-infrastructure-only change (files under `tests/reporters/`). There is no UI or runtime app behaviour to test manually. To verify: 1. Merge and let a nightly BrowserStack E2E run complete. 2. Open the Sentry project used for E2E performance metrics. 3. In Discover / Performance, query `measurements.app_size_mb` — values should appear for each test session that has profiling data. Unit tests covering the new behaviour can be run locally: ```bash yarn jest tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts ``` ## **Screenshots/Recordings** N/A — no UI changes. Sentry data will only be visible after a CI run with the merged branch. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [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** - [ ] 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. --------- Co-authored-by: Claude Sonnet 4.6 --- tests/reporters/PerformanceReporter.ts | 60 +++++++++++++ tests/reporters/PerformanceTracker.ts | 1 + .../browserstack/BrowserStackEnricher.ts | 3 + .../sentry/PerformanceSentryPublisher.test.ts | 87 +++++++++++++++++++ .../sentry/PerformanceSentryPublisher.ts | 12 ++- tests/reporters/types.ts | 2 + 6 files changed, 164 insertions(+), 1 deletion(-) diff --git a/tests/reporters/PerformanceReporter.ts b/tests/reporters/PerformanceReporter.ts index 429b8e27b45..723f868b74b 100644 --- a/tests/reporters/PerformanceReporter.ts +++ b/tests/reporters/PerformanceReporter.ts @@ -131,6 +131,7 @@ class PerformanceReporter { if (this.sessions.length > 0 && isBrowserStackRun) { await this.enrichSessionsWithProviderData(); + await this.publishAppSizeToSentry(); } // Clean up leftover environment variables @@ -484,6 +485,65 @@ class PerformanceReporter { } } + /** + * After BrowserStack enrichment, publish the installed app size for each + * session that has profiling data to Sentry, following the same pattern + * as the per-test timing measurements sent from the fixture. + */ + private async publishAppSizeToSentry(): Promise { + for (const session of this.sessions) { + const appSizeMb = session.profilingSummary?.appSizeMb; + if (appSizeMb === undefined) { + continue; + } + + const metric = this.metrics.find((m) => m.testName === session.testTitle); + + const deviceInfo: DeviceInfo = session.deviceInfo ?? + metric?.device ?? { + name: 'Unknown', + osVersion: 'Unknown', + provider: 'browserstack', + }; + + const teamInfo = session.team ?? metric?.team ?? null; + + try { + const sentToSentry = await publishPerformanceScenarioToSentry({ + metrics: { + steps: [], + timestamp: session.timestamp ?? new Date().toISOString(), + thresholdMarginPercent: 0, + team: teamInfo, + total: 0, + totalThreshold: null, + hasThresholds: false, + totalValidation: null, + device: deviceInfo, + appSizeMb, + }, + testTitle: session.testTitle, + projectName: session.projectName ?? 'unknown', + testFilePath: session.testFilePath, + videoRecordingUrl: session.videoURL ?? null, + tags: session.tags ?? metric?.tags ?? [], + status: session.testStatus, + }); + + if (sentToSentry) { + logger.info( + `App size (${appSizeMb} MB) for "${session.testTitle}" sent to Sentry`, + ); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + logger.warn( + `Failed to publish app size for "${session.testTitle}" to Sentry: ${message}`, + ); + } + } + } + private async generateReports(summary: ReportSummary): Promise { const testName = (this.metrics[0]?.testName ?? 'Unknown') .replace(/[^a-zA-Z0-9]/g, '_') diff --git a/tests/reporters/PerformanceTracker.ts b/tests/reporters/PerformanceTracker.ts index e0c013784ff..b669ed8d35a 100644 --- a/tests/reporters/PerformanceTracker.ts +++ b/tests/reporters/PerformanceTracker.ts @@ -27,6 +27,7 @@ export interface MetricsOutput { } | null; device: DeviceInfo; sessionCreationDurationMs?: number; + appSizeMb?: number; } /** diff --git a/tests/reporters/providers/browserstack/BrowserStackEnricher.ts b/tests/reporters/providers/browserstack/BrowserStackEnricher.ts index d4ac91a6199..4a8d0d056cc 100644 --- a/tests/reporters/providers/browserstack/BrowserStackEnricher.ts +++ b/tests/reporters/providers/browserstack/BrowserStackEnricher.ts @@ -182,6 +182,9 @@ export class BrowserStackEnricher extends BaseSessionDataEnricher { criticalIssues: appData.detected_issues?.filter((issue) => issue.type === 'error') .length ?? 0, + ...(metrics.app_size !== undefined && { + appSizeMb: metrics.app_size, + }), cpu: { avg: metrics.cpu?.avg ?? 0, max: metrics.cpu?.max ?? 0, diff --git a/tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts b/tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts index 9c8b17f970c..24405efff99 100644 --- a/tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts +++ b/tests/reporters/providers/sentry/PerformanceSentryPublisher.test.ts @@ -370,6 +370,93 @@ describe('PerformanceSentryPublisher', () => { expect(longTimerKeys.every((key: string) => key.length <= 64)).toBe(true); }); + it('sends app_size_mb measurement with megabyte unit when appSizeMb is set', async () => { + process.env.E2E_PERFORMANCE_SENTRY_DSN = + 'https://publicKey@o123.ingest.sentry.io/4567'; + fetchMock.mockResolvedValue({ + ok: true, + status: 200, + } as Response); + + const sent = await publishPerformanceScenarioToSentry({ + metrics: createMetrics({ appSizeMb: 291.62 }), + testTitle: 'Import wallet flow', + projectName: 'browserstack-android', + testFilePath: 'tests/performance/onboarding/import-wallet.spec.js', + tags: ['@PerformanceOnboarding'], + status: 'passed', + retry: 0, + workerIndex: 0, + }); + + expect(sent).toBe(true); + const [, requestInit] = fetchMock.mock.calls[0] ?? []; + expect(requestInit).toBeDefined(); + if (!requestInit) { + throw new Error('Expected request init payload for Sentry request'); + } + + const body = requestInit.body as string; + const [, , payloadLine] = body.split('\n'); + const payload = JSON.parse(payloadLine); + + expect(payload.measurements.app_size_mb).toEqual({ + value: 291.62, + unit: 'megabyte', + }); + }); + + it('sends when only appSizeMb is set and steps is empty', async () => { + process.env.E2E_PERFORMANCE_SENTRY_DSN = + 'https://publicKey@o123.ingest.sentry.io/4567'; + fetchMock.mockResolvedValue({ + ok: true, + status: 200, + } as Response); + + const sent = await publishPerformanceScenarioToSentry({ + metrics: createMetrics({ steps: [], appSizeMb: 289.75 }), + testTitle: 'Send ETH flow', + projectName: 'browserstack-android', + testFilePath: 'tests/performance/login/send-eth.spec.ts', + tags: ['@PerformanceLogin'], + status: 'passed', + retry: 0, + workerIndex: 0, + }); + + expect(sent).toBe(true); + const [, requestInit] = fetchMock.mock.calls[0] ?? []; + const body = requestInit?.body as string; + const [, , payloadLine] = body.split('\n'); + const payload = JSON.parse(payloadLine); + + expect(payload.measurements.app_size_mb).toEqual({ + value: 289.75, + unit: 'megabyte', + }); + expect(payload.spans).toHaveLength(0); + }); + + it('does not send when steps is empty and appSizeMb is not set', async () => { + process.env.E2E_PERFORMANCE_SENTRY_DSN = + 'https://publicKey@o123.ingest.sentry.io/4567'; + + const sent = await publishPerformanceScenarioToSentry({ + metrics: createMetrics({ steps: [] }), + testTitle: 'Import wallet flow', + projectName: 'browserstack-android', + testFilePath: 'tests/performance/onboarding/import-wallet.spec.js', + tags: ['@PerformanceOnboarding'], + status: 'passed', + retry: 0, + workerIndex: 0, + }); + + expect(sent).toBe(false); + expect(fetchMock).not.toHaveBeenCalled(); + }); + it('includes profiling measurements when profilingSummary is provided', async () => { process.env.E2E_PERFORMANCE_SENTRY_DSN = 'https://publicKey@o123.ingest.sentry.io/4567'; diff --git a/tests/reporters/providers/sentry/PerformanceSentryPublisher.ts b/tests/reporters/providers/sentry/PerformanceSentryPublisher.ts index 65c4cf875e6..ce52c35e511 100644 --- a/tests/reporters/providers/sentry/PerformanceSentryPublisher.ts +++ b/tests/reporters/providers/sentry/PerformanceSentryPublisher.ts @@ -227,7 +227,10 @@ function getGithubJobUrl(): string | null { export async function publishPerformanceScenarioToSentry( options: PublishPerformanceScenarioOptions, ): Promise { - if (options.metrics.steps.length === 0) { + if ( + options.metrics.steps.length === 0 && + options.metrics.appSizeMb === undefined + ) { return false; } @@ -308,6 +311,13 @@ export async function publishPerformanceScenarioToSentry( }; } + if (options.metrics.appSizeMb !== undefined) { + measurements.app_size_mb = { + value: options.metrics.appSizeMb, + unit: 'megabyte', + }; + } + if (options.profilingSummary?.uiRendering) { const { slowFrames, frozenFrames, anrs } = options.profilingSummary.uiRendering; diff --git a/tests/reporters/types.ts b/tests/reporters/types.ts index 68a89c378fe..ece88bb58f1 100644 --- a/tests/reporters/types.ts +++ b/tests/reporters/types.ts @@ -90,6 +90,7 @@ export interface ProfilingData { status?: string; detected_issues?: ProfilingIssue[]; metrics: { + app_size?: number; cpu?: { avg?: number; max?: number }; mem?: { avg?: number; max?: number }; batt?: { total_batt_usage?: number; total_batt_usage_pct?: number }; @@ -118,6 +119,7 @@ export interface ProfilingSummary { status?: string; issues?: number; criticalIssues?: number; + appSizeMb?: number; cpu?: { avg: number; max: number; unit?: string }; memory?: { avg: number; max: number; unit?: string }; battery?: { total: number; percentage: number; unit?: string }; From 04c71b27955ec6440f2b6d0636c6e3cf713ab9f7 Mon Sep 17 00:00:00 2001 From: Alexey Kureev Date: Tue, 16 Jun 2026 18:11:39 +0200 Subject: [PATCH 16/23] feat(money): make Earn on Crypto a full-page screen (MUSD-994) (#31816) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** The "Earn on your crypto" screen (`MoneyPotentialEarningsView`) was registered inside the Money tab stack, so it rendered with the bottom tab navigation bar still visible and the CTA sitting above it — it was not a true full-page screen as per the design. This PR promotes `MoneyPotentialEarningsView` from the Money tab stack (`MoneyTabScreenStack`) to a top-level native stack route in `MainNavigator`, mirroring the existing Money confirmations/onboarding pattern. As a result the bottom tab navigation bar is no longer rendered on this screen and the "Convert your crypto" CTA sits at the true bottom edge of the screen with safe-area padding. No changes were needed to the view itself or to the navigation calls (the route name resolves to the new top-level registration). ## **Changelog** CHANGELOG entry: Changed the "Earn on your crypto" screen to a full-page layout, removing the bottom navigation bar. ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-994 ## **Manual testing steps** ```gherkin Feature: Earn on your crypto full-page screen Scenario: user opens Earn on your crypto from the Money home screen Given the user is on the Money home screen And the "Earn on your crypto" section shows eligible tokens When the user taps the section header or "View all" Then the "Earn on your crypto" screen opens as a full page And the bottom tab navigation bar is not visible And the "Convert your crypto" CTA is pinned to the bottom of the screen with padding ``` ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/0dbe0051-1d6c-4c4e-b875-dfa38dd1e8cf ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] 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. --- app/components/Nav/Main/MainNavigator.js | 6 ++++++ app/components/UI/Money/routes/index.test.tsx | 5 +---- app/components/UI/Money/routes/index.tsx | 5 ----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/components/Nav/Main/MainNavigator.js b/app/components/Nav/Main/MainNavigator.js index b9ea67025a7..46bc288e37a 100644 --- a/app/components/Nav/Main/MainNavigator.js +++ b/app/components/Nav/Main/MainNavigator.js @@ -126,6 +126,7 @@ import { MoneyTabScreenStack, } from '../../UI/Money/routes'; import MoneyOnboardingView from '../../UI/Money/Views/MoneyOnboardingView'; +import MoneyPotentialEarningsView from '../../UI/Money/Views/MoneyPotentialEarningsView'; import { selectMoneyEnableMoneyAccountFlag } from '../../UI/Money/selectors/featureFlags'; import { BridgeTransactionDetails } from '../../UI/Bridge/components/TransactionDetails/TransactionDetails'; import { BridgeModalStack, BridgeScreenStack } from '../../UI/Bridge/routes'; @@ -1214,6 +1215,11 @@ const MainNavigator = () => { component={MoneyOnboardingView} options={{ headerShown: false, ...fadeNativeOptions }} /> + { jest.clearAllMocks(); }); - it('registers Money home, activity, how-it-works, and potential-earnings screens', () => { + it('registers Money home, activity, and how-it-works screens', () => { const { getByTestId } = renderWithProvider(, { theme: themeWithCustomBackground, }); @@ -120,9 +120,6 @@ describe('MoneyTabScreenStack', () => { expect(getByTestId('money-screen-MoneyHome')).toBeOnTheScreen(); expect(getByTestId('money-screen-MoneyActivity')).toBeOnTheScreen(); expect(getByTestId('money-screen-MoneyHowItWorks')).toBeOnTheScreen(); - expect( - getByTestId('money-screen-MoneyPotentialEarnings'), - ).toBeOnTheScreen(); }); it('sets stack content background from theme to avoid flash during inner navigation', () => { diff --git a/app/components/UI/Money/routes/index.tsx b/app/components/UI/Money/routes/index.tsx index 6bf63032342..2ce7438e9a1 100644 --- a/app/components/UI/Money/routes/index.tsx +++ b/app/components/UI/Money/routes/index.tsx @@ -9,7 +9,6 @@ import { useTheme } from '../../../../util/theme'; import MoneyHomeView from '../Views/MoneyHomeView'; import MoneyActivityView from '../Views/MoneyActivityView'; import MoneyHowItWorksView from '../Views/MoneyHowItWorksView'; -import MoneyPotentialEarningsView from '../Views/MoneyPotentialEarningsView'; import MoneyAddMoneySheet from '../components/MoneyAddMoneySheet'; import MoneyMoreSheet from '../components/MoneyMoreSheet'; import MoneyTransferSheet from '../components/MoneyTransferSheet'; @@ -49,10 +48,6 @@ const MoneyTabScreenStack = () => { name={Routes.MONEY.HOW_IT_WORKS} component={MoneyHowItWorksView} /> - ); }; From ce9c664b2be2f78e0c4e96df0bf0a669cc2856da Mon Sep 17 00:00:00 2001 From: Xavier Brochard Date: Tue, 16 Jun 2026 18:19:51 +0200 Subject: [PATCH 17/23] fix: apply base currency selection when assetsUnifyState is enabled (#31740) ## **Description** When the `assetsUnifyState` feature flag is enabled, the active fiat currency shown across the UI is read from `AssetsController.selectedCurrency` (via `selectCurrentCurrency` -> `getCurrencyRateControllerCurrentCurrency`). However, the General Settings "Base currency" picker only wrote the selection to `CurrencyRateController.setCurrentCurrency`. Nothing ever wrote `AssetsController.selectedCurrency`, and the controller does not auto-sync from `CurrencyRateController`. As a result, with the flag on, tapping a currency closed the picker but the selection silently no-opped and the displayed currency stayed on `USD`. With the flag off the UI reads `CurrencyRateController.currentCurrency`, so the bug did not reproduce. This PR contains two changes: 1. `selectCurrency` now also calls `AssetsController.setSelectedCurrency(currency)`, so the selection applies regardless of the flag state. `setSelectedCurrency` updates `selectedCurrency` and triggers a price refetch in the new currency. 2. Migration `143` copies `CurrencyRateController.currentCurrency` into `AssetsController.selectedCurrency`. Migration `139` had defaulted `selectedCurrency` to `'usd'` without preserving the user's existing currency, so without this, enabling the flag would silently reset existing non-USD users to USD. ## **Changelog** CHANGELOG entry: Fixed a bug where changing the base currency in General Settings had no effect. ## **Related issues** Fixes: ## **Manual testing steps** ```gherkin Feature: Base currency selection in General Settings Scenario: user changes the base currency with assetsUnifyState enabled Given the assetsUnifyState feature flag is enabled And the user is on Settings > General When the user opens the "Base currency" picker And the user selects "EUR - Euro" Then the selected base currency updates to EUR And fiat values across the app are displayed in EUR Scenario: existing non-USD user upgrades with assetsUnifyState enabled Given a user had previously selected EUR as their base currency When the app upgrades and runs migration 143 And the assetsUnifyState feature flag is enabled Then the user's base currency remains EUR (not reset to USD) ``` ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [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 - [ ] 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. ## **Pre-merge reviewer checklist** - [ ] 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. --------- Co-authored-by: Cursor --- .../Views/Settings/GeneralSettings/index.js | 11 +- .../Settings/GeneralSettings/index.test.tsx | 38 +++++ app/store/migrations/143.test.ts | 139 ++++++++++++++++++ app/store/migrations/143.ts | 52 +++++++ app/store/migrations/index.ts | 2 + 5 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 app/store/migrations/143.test.ts create mode 100644 app/store/migrations/143.ts diff --git a/app/components/Views/Settings/GeneralSettings/index.js b/app/components/Views/Settings/GeneralSettings/index.js index 9b19763994a..1f645ecc3e7 100644 --- a/app/components/Views/Settings/GeneralSettings/index.js +++ b/app/components/Views/Settings/GeneralSettings/index.js @@ -48,6 +48,9 @@ import { colors as staticColors } from '../../../../styles/common'; import { enablePushNotifications } from '../../../../actions/notification/helpers'; import { selectIsMetaMaskPushNotificationsEnabled } from '../../../../selectors/notifications'; +export const GENERAL_SETTINGS_CURRENCY_SELECTOR = + 'general-settings-currency-selector'; + const diameter = 40; const spacing = 8; @@ -228,8 +231,13 @@ class Settings extends PureComponent { }; selectCurrency = async (currency) => { - const { CurrencyRateController } = Engine.context; + const { CurrencyRateController, AssetsController } = Engine.context; CurrencyRateController.setCurrentCurrency(currency); + // When the `assetsUnifyState` flag is enabled, the UI reads the active + // currency from AssetsController.selectedCurrency rather than from + // CurrencyRateController, so it must be updated here too. Otherwise the + // selection silently no-ops and the displayed currency stays unchanged. + AssetsController?.setSelectedCurrency?.(currency); updateUserTraitsWithCurrentCurrency(currency); }; @@ -358,6 +366,7 @@ class Settings extends PureComponent { ({ + context: { + CurrencyRateController: { + setCurrentCurrency: (...args: unknown[]) => + mockSetCurrentCurrency(...args), + }, + AssetsController: { + setSelectedCurrency: (...args: unknown[]) => + mockSetSelectedCurrency(...args), + }, + }, +})); + jest.mock('../../../../core/Analytics'); jest.mock('../../../../util/analytics/analytics', () => ({ @@ -102,6 +119,27 @@ describe('GeneralSettings', () => { }); }); +describe('GeneralSettings currency selection', () => { + beforeEach(() => { + jest.clearAllMocks(); + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('updates both CurrencyRateController and AssetsController when a currency is selected', () => { + const { getByTestId, getByText } = renderComponent(); + + fireEvent.press(getByTestId(GENERAL_SETTINGS_CURRENCY_SELECTOR)); + fireEvent.press(getByText('EUR - Euro')); + + expect(mockSetCurrentCurrency).toHaveBeenCalledWith('eur'); + expect(mockSetSelectedCurrency).toHaveBeenCalledWith('eur'); + }); +}); + describe('updateUserTraitsWithCurrentCurrency', () => { afterEach(() => { jest.clearAllMocks(); diff --git a/app/store/migrations/143.test.ts b/app/store/migrations/143.test.ts new file mode 100644 index 00000000000..d097ffcd8bd --- /dev/null +++ b/app/store/migrations/143.test.ts @@ -0,0 +1,139 @@ +import { cloneDeep } from 'lodash'; + +import { ensureValidState } from './util'; +import migrate from './143'; + +jest.mock('./util', () => ({ + ensureValidState: jest.fn(), +})); + +const mockedEnsureValidState = jest.mocked(ensureValidState); + +const createTestState = ( + selectedCurrency: string, + currentCurrency: string, +) => ({ + engine: { + backgroundState: { + AssetsController: { + selectedCurrency, + }, + CurrencyRateController: { + currentCurrency, + }, + }, + }, +}); + +describe('Migration 143: Carry over selected fiat currency', () => { + beforeEach(() => { + jest.resetAllMocks(); + }); + + it('returns state unchanged if ensureValidState fails', () => { + const state = { some: 'state' }; + mockedEnsureValidState.mockReturnValue(false); + + const migratedState = migrate(state); + + expect(migratedState).toBe(state); + expect(migratedState).toStrictEqual({ some: 'state' }); + }); + + it('copies currentCurrency into selectedCurrency when they differ', () => { + const oldState = createTestState('usd', 'eur'); + mockedEnsureValidState.mockReturnValue(true); + + const migratedState = migrate(oldState) as typeof oldState; + + expect( + migratedState.engine.backgroundState.AssetsController.selectedCurrency, + ).toBe('eur'); + }); + + it('leaves selectedCurrency untouched when it already matches currentCurrency', () => { + const oldState = createTestState('eur', 'eur'); + mockedEnsureValidState.mockReturnValue(true); + + const migratedState = migrate(oldState) as typeof oldState; + + expect( + migratedState.engine.backgroundState.AssetsController.selectedCurrency, + ).toBe('eur'); + }); + + it.each([ + { + currentCurrency: '', + test: 'empty currentCurrency', + }, + { + currentCurrency: 123 as unknown as string, + test: 'non-string currentCurrency', + }, + ])( + 'does not modify selectedCurrency for invalid currentCurrency - $test', + ({ currentCurrency }) => { + const oldState = createTestState('usd', currentCurrency); + mockedEnsureValidState.mockReturnValue(true); + + const migratedState = migrate(oldState) as typeof oldState; + + expect( + migratedState.engine.backgroundState.AssetsController.selectedCurrency, + ).toBe('usd'); + }, + ); + + it.each([ + { + state: { + engine: { + backgroundState: { + CurrencyRateController: { currentCurrency: 'eur' }, + }, + }, + }, + test: 'missing AssetsController', + }, + { + state: { + engine: { + backgroundState: { + AssetsController: 'invalid', + CurrencyRateController: { currentCurrency: 'eur' }, + }, + }, + }, + test: 'invalid AssetsController state', + }, + { + state: { + engine: { + backgroundState: { + AssetsController: { selectedCurrency: 'usd' }, + }, + }, + }, + test: 'missing CurrencyRateController', + }, + { + state: { + engine: { + backgroundState: { + AssetsController: { selectedCurrency: 'usd' }, + CurrencyRateController: 'invalid', + }, + }, + }, + test: 'invalid CurrencyRateController state', + }, + ])('does not modify state if the state is invalid - $test', ({ state }) => { + const orgState = cloneDeep(state); + mockedEnsureValidState.mockReturnValue(true); + + const migratedState = migrate(state); + + expect(migratedState).toStrictEqual(orgState); + }); +}); diff --git a/app/store/migrations/143.ts b/app/store/migrations/143.ts new file mode 100644 index 00000000000..4b8c34d88cd --- /dev/null +++ b/app/store/migrations/143.ts @@ -0,0 +1,52 @@ +import { hasProperty, isObject } from '@metamask/utils'; +import { ensureValidState } from './util'; + +/** + * Migration 143: + * + * Carry over the user's selected fiat currency from + * `CurrencyRateController.currentCurrency` into + * `AssetsController.selectedCurrency`. + * + * Migration 139 initialized `AssetsController.selectedCurrency` to the default + * `'usd'` without copying the user's existing currency. When the + * `assetsUnifyState` feature flag is enabled, the UI reads the active currency + * from `AssetsController.selectedCurrency`, so without this sync existing + * non-USD users would be silently reset to USD. + * + * @param state - The persisted Redux state. + * @returns The migrated state. + */ +const migration = (state: unknown): unknown => { + const migrationVersion = 143; + + if (!ensureValidState(state, migrationVersion)) { + return state; + } + + const { backgroundState } = state.engine; + + if ( + !hasProperty(backgroundState, 'AssetsController') || + !isObject(backgroundState.AssetsController) || + !hasProperty(backgroundState, 'CurrencyRateController') || + !isObject(backgroundState.CurrencyRateController) + ) { + return state; + } + + const { AssetsController, CurrencyRateController } = backgroundState; + const { currentCurrency } = CurrencyRateController; + + if ( + typeof currentCurrency === 'string' && + currentCurrency.length > 0 && + AssetsController.selectedCurrency !== currentCurrency + ) { + AssetsController.selectedCurrency = currentCurrency; + } + + return state; +}; + +export default migration; diff --git a/app/store/migrations/index.ts b/app/store/migrations/index.ts index 200b963fbed..25bcaf25b8c 100644 --- a/app/store/migrations/index.ts +++ b/app/store/migrations/index.ts @@ -143,6 +143,7 @@ import migration139 from './139'; import migration140 from './140'; import migration141 from './141'; import migration142 from './142'; +import migration143 from './143'; // Add migrations above this line import { ControllerStorage } from '../persistConfig'; @@ -305,6 +306,7 @@ export const migrationList: MigrationsList = { 140: migration140, 141: migration141, 142: migration142, + 143: migration143, }; // Enable both synchronous and asynchronous migrations From d9fcd15cc6b8581505d67ae56fd6c3535809aed2 Mon Sep 17 00:00:00 2001 From: Devin Stewart <49423028+Bigshmow@users.noreply.github.com> Date: Tue, 16 Jun 2026 10:20:39 -0600 Subject: [PATCH 18/23] feat: read notification_subtype from deeplink and relay to analytics (#31765) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Mobile half of TSA-702. The deeplink contract change (see paired social-api PR) renames the `notification_event` query param on `social-trader-position` URLs to `notification_subtype` for parity with NAAP. This PR updates the mobile deeplink handler to parse the new name, forwards the value through navigation to `TraderPositionView`, and includes it on the `SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED` analytics event so click-attribution can distinguish spot vs perp opens in analytics. **What changed** - `handleSocialTraderPositionUrl.ts` — parses `notification_subtype` (was `notification_event`), fires the existing `SOCIAL_FOLLOW_TRADING_NOTIFICATION_CLICKED` event with the new property key, and forwards `notificationSubtype` as a navigation param to `TraderPositionView`. - `TraderPositionView.tsx` — reads `notificationSubtype` from route params and includes it on the `SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED` event when present. - `socialLeaderboardEvents.ts` — adds `NOTIFICATION_SUBTYPE: 'notification_subtype'` as an analytics property key. - `NavigationService/types.ts` — adds optional `notificationSubtype` to both `TraderPositionViewParams` union branches. **Backwards compatibility** Missing `notification_subtype` does not break navigation — the analytics property is omitted via a spread guard when absent. Routes that don't originate from a notification tap (in-app row taps, deeplinks without a subtype) work unchanged. **Paired PR** This depends on the social-api rename ([PR #89](https://github.com/consensys-vertical-apps/va-mmcx-social-api/pull/89)) landing for the new param name to appear on real deeplinks. Until both ship, notification-tap analytics will be missing the subtype property — but routing/destination behavior is unchanged. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TSA-702 ## **Manual testing steps** ```gherkin Feature: Notification deeplink forwards subtype through to analytics Scenario: Tap a notification with a spot subtype Given the user taps a social-trader-position deeplink with notification_subtype=follow_newtrade_buy When the deeplink handler runs Then the user lands on TraderPositionView for the given position And the SOCIAL_FOLLOW_TRADING_NOTIFICATION_CLICKED event fires with notification_subtype=follow_newtrade_buy And once the screen renders, SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED fires with notification_subtype=follow_newtrade_buy Scenario: Tap a notification with a perp subtype Given the user taps a social-trader-position deeplink with notification_subtype=follow_newtrade_perp_long When the deeplink handler runs Then navigation and analytics propagate notification_subtype=follow_newtrade_perp_long end-to-end Scenario: Legacy deeplinks without a subtype still work Given the user taps a social-trader-position deeplink with no notification_subtype query param When the deeplink handler runs Then navigation completes normally And the SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED event fires WITHOUT a notification_subtype property ``` ## **Screenshots/Recordings** N/A — analytics-only change, no visible UI. ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- .../TraderPositionView/TraderPositionView.tsx | 12 ++++++- .../analytics/socialLeaderboardEvents.ts | 1 + .../handleSocialTraderPositionUrl.test.ts | 32 +++++++++++++++---- .../__tests__/handleUniversalLink.test.ts | 6 ++-- .../legacy/handleSocialTraderPositionUrl.ts | 18 ++++++----- app/core/NavigationService/types.ts | 8 +++++ 6 files changed, 59 insertions(+), 18 deletions(-) diff --git a/app/components/Views/SocialLeaderboard/TraderPositionView/TraderPositionView.tsx b/app/components/Views/SocialLeaderboard/TraderPositionView/TraderPositionView.tsx index 86459102772..90019a90f12 100644 --- a/app/components/Views/SocialLeaderboard/TraderPositionView/TraderPositionView.tsx +++ b/app/components/Views/SocialLeaderboard/TraderPositionView/TraderPositionView.tsx @@ -72,6 +72,7 @@ const TraderPositionView = () => { position: positionParam, positionId, source: sourceParam, + notificationSubtype, } = route.params; const { track } = useSocialLeaderboardAnalytics(); @@ -217,8 +218,17 @@ const TraderPositionView = () => { track(MetaMetricsEvents.SOCIAL_FOLLOW_TRADING_TOKEN_SCREEN_VIEWED, { ...followTradingTokenContext, [SocialLeaderboardEventProperties.SOURCE]: followTradingTokenSource, + ...(notificationSubtype !== undefined && { + [SocialLeaderboardEventProperties.NOTIFICATION_SUBTYPE]: + notificationSubtype, + }), }); - }, [followTradingTokenContext, followTradingTokenSource, track]); + }, [ + followTradingTokenContext, + followTradingTokenSource, + notificationSubtype, + track, + ]); // Keep a stable ref to the latest context so the dismissed-cleanup effect // can read the current value without listing it as a dependency. diff --git a/app/components/Views/SocialLeaderboard/analytics/socialLeaderboardEvents.ts b/app/components/Views/SocialLeaderboard/analytics/socialLeaderboardEvents.ts index ac684e53028..ccd77bf2b0b 100644 --- a/app/components/Views/SocialLeaderboard/analytics/socialLeaderboardEvents.ts +++ b/app/components/Views/SocialLeaderboard/analytics/socialLeaderboardEvents.ts @@ -23,6 +23,7 @@ export const SocialLeaderboardEventProperties = { LATENCY_MS: 'latency_ms', MARKET_CAP: 'market_cap', NOTIFICATION_TYPE: 'notification_type', + NOTIFICATION_SUBTYPE: 'notification_subtype', PAY_WITH_TOKEN: 'pay_with_token', RECEIVE_TOKEN: 'receive_token', PRESET_VALUE: 'preset_value', diff --git a/app/core/DeeplinkManager/handlers/legacy/__tests__/handleSocialTraderPositionUrl.test.ts b/app/core/DeeplinkManager/handlers/legacy/__tests__/handleSocialTraderPositionUrl.test.ts index fce66259a25..ce841e6c640 100644 --- a/app/core/DeeplinkManager/handlers/legacy/__tests__/handleSocialTraderPositionUrl.test.ts +++ b/app/core/DeeplinkManager/handlers/legacy/__tests__/handleSocialTraderPositionUrl.test.ts @@ -33,10 +33,10 @@ describe('handleSocialTraderPositionUrl', () => { jest.clearAllMocks(); }); - it('navigates to TraderPositionView with positionId', () => { + it('navigates to TraderPositionView with positionId and forwards notificationSubtype', () => { handleSocialTraderPositionUrl({ actionPath: - '?positionId=92d9001b-8b64-4b13-9c1b-ba9292a6099a&traderId=trader-1&deduplication_id=dedup-1¬ification_event=follow_newtrade_buy', + '?positionId=92d9001b-8b64-4b13-9c1b-ba9292a6099a&traderId=trader-1&deduplication_id=dedup-1¬ification_subtype=follow_newtrade_buy', }); expect(mockNavigate).toHaveBeenCalledTimes(1); @@ -46,11 +46,12 @@ describe('handleSocialTraderPositionUrl', () => { positionId: '92d9001b-8b64-4b13-9c1b-ba9292a6099a', traderId: 'trader-1', source: 'notification', + notificationSubtype: 'follow_newtrade_buy', }, ); }); - it('navigates with only positionId and traderId route params', () => { + it('navigates with only positionId and traderId when no subtype is present', () => { handleSocialTraderPositionUrl({ actionPath: '?positionId=position-1&traderId=trader-1', }); @@ -62,14 +63,15 @@ describe('handleSocialTraderPositionUrl', () => { positionId: 'position-1', traderId: 'trader-1', source: 'notification', + notificationSubtype: undefined, }, ); }); - it('decodes encoded positionId and traderId values', () => { + it('decodes encoded positionId, traderId, and subtype values', () => { handleSocialTraderPositionUrl({ actionPath: - '?positionId=position%20id%2Fwith%20reserved%3Fchars&traderId=trader%20id%2Fwith%20reserved%3Fchars&deduplication_id=dedup%20id%2Fwith%20reserved%3Fchars¬ification_event=follow%20newtrade%2Fbuy', + '?positionId=position%20id%2Fwith%20reserved%3Fchars&traderId=trader%20id%2Fwith%20reserved%3Fchars&deduplication_id=dedup%20id%2Fwith%20reserved%3Fchars¬ification_subtype=follow%20newtrade%2Fbuy', }); expect(mockNavigate).toHaveBeenCalledWith( @@ -78,6 +80,7 @@ describe('handleSocialTraderPositionUrl', () => { positionId: 'position id/with reserved?chars', traderId: 'trader id/with reserved?chars', source: 'notification', + notificationSubtype: 'follow newtrade/buy', }, ); expect(DevLogger.log).toHaveBeenCalledWith( @@ -86,11 +89,27 @@ describe('handleSocialTraderPositionUrl', () => { positionId: 'position id/with reserved?chars', traderId: 'trader id/with reserved?chars', deduplicationId: 'dedup id/with reserved?chars', - notificationEvent: 'follow newtrade/buy', + notificationSubtype: 'follow newtrade/buy', }, ); }); + it.each([ + 'follow_newtrade_buy', + 'follow_newtrade_sell', + 'follow_newtrade_perp_long', + 'follow_newtrade_perp_short', + ])('forwards subtype %s through to the destination screen', (subtype) => { + handleSocialTraderPositionUrl({ + actionPath: `?positionId=position-1&traderId=trader-1¬ification_subtype=${subtype}`, + }); + + expect(mockNavigate).toHaveBeenCalledWith( + Routes.SOCIAL_LEADERBOARD.POSITION, + expect.objectContaining({ notificationSubtype: subtype }), + ); + }); + it('falls back to social leaderboard when traderId is missing', () => { handleSocialTraderPositionUrl({ actionPath: '?positionId=92d9001b-8b64-4b13-9c1b-ba9292a6099a', @@ -174,6 +193,7 @@ describe('handleSocialTraderPositionUrl', () => { positionId: 'position-1', traderId: 'trader-1', source: 'notification', + notificationSubtype: undefined, }, ); expect(DevLogger.log).toHaveBeenCalledWith( diff --git a/app/core/DeeplinkManager/handlers/legacy/__tests__/handleUniversalLink.test.ts b/app/core/DeeplinkManager/handlers/legacy/__tests__/handleUniversalLink.test.ts index 87d9d5562c7..62405e04aac 100644 --- a/app/core/DeeplinkManager/handlers/legacy/__tests__/handleUniversalLink.test.ts +++ b/app/core/DeeplinkManager/handlers/legacy/__tests__/handleUniversalLink.test.ts @@ -1258,14 +1258,14 @@ describe('handleUniversalLink', () => { describe('ACTIONS.SOCIAL_TRADER_POSITION', () => { it('calls _handleSocialTraderPosition when action is SOCIAL_TRADER_POSITION', async () => { - const positionUrl = `${PROTOCOLS.HTTPS}://${AppConstants.MM_UNIVERSAL_LINK_HOST}/${ACTIONS.SOCIAL_TRADER_POSITION}?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_event=follow_newtrade_buy`; + const positionUrl = `${PROTOCOLS.HTTPS}://${AppConstants.MM_UNIVERSAL_LINK_HOST}/${ACTIONS.SOCIAL_TRADER_POSITION}?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_subtype=follow_newtrade_buy`; const positionUrlObj = { ...urlObj, hostname: AppConstants.MM_UNIVERSAL_LINK_HOST, href: positionUrl, pathname: `/${ACTIONS.SOCIAL_TRADER_POSITION}`, search: - '?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_event=follow_newtrade_buy', + '?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_subtype=follow_newtrade_buy', }; await handleUniversalLink({ @@ -1280,7 +1280,7 @@ describe('handleUniversalLink', () => { expect(mockHandleDeepLinkModalDisplay).not.toHaveBeenCalled(); expect(handleSocialTraderPositionUrl).toHaveBeenCalledWith({ actionPath: - '?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_event=follow_newtrade_buy', + '?positionId=position-1&traderId=trader-1&deduplication_id=dedup-1¬ification_subtype=follow_newtrade_buy', }); expect(handled).toHaveBeenCalled(); }); diff --git a/app/core/DeeplinkManager/handlers/legacy/handleSocialTraderPositionUrl.ts b/app/core/DeeplinkManager/handlers/legacy/handleSocialTraderPositionUrl.ts index 09142792553..e825dc913ff 100644 --- a/app/core/DeeplinkManager/handlers/legacy/handleSocialTraderPositionUrl.ts +++ b/app/core/DeeplinkManager/handlers/legacy/handleSocialTraderPositionUrl.ts @@ -15,7 +15,7 @@ interface SocialTraderPositionNavigationParams { positionId?: string; traderId?: string; deduplicationId?: string; - notificationEvent?: string; + notificationSubtype?: string; } const parseSocialTraderPositionNavigationParams = ( @@ -29,7 +29,8 @@ const parseSocialTraderPositionNavigationParams = ( positionId: urlParams.get('positionId')?.trim() || undefined, traderId: urlParams.get('traderId')?.trim() || undefined, deduplicationId: urlParams.get('deduplication_id')?.trim() || undefined, - notificationEvent: urlParams.get('notification_event')?.trim() || undefined, + notificationSubtype: + urlParams.get('notification_subtype')?.trim() || undefined, }; }; @@ -41,7 +42,7 @@ const navigateToFallback = () => { * Handles notification-approved TraderPosition deeplinks. * * Supported URL format: - * - https://link.metamask.io/social-trader-position?positionId=&traderId=&deduplication_id=¬ification_event= + * - https://link.metamask.io/social-trader-position?positionId=&traderId=&deduplication_id=¬ification_subtype= */ export const handleSocialTraderPositionUrl = ({ actionPath, @@ -52,11 +53,11 @@ export const handleSocialTraderPositionUrl = ({ ); try { - const { positionId, traderId, deduplicationId, notificationEvent } = + const { positionId, traderId, deduplicationId, notificationSubtype } = parseSocialTraderPositionNavigationParams(actionPath); DevLogger.log( '[handleSocialTraderPositionUrl] Parsed navigation parameters:', - { positionId, traderId, deduplicationId, notificationEvent }, + { positionId, traderId, deduplicationId, notificationSubtype }, ); if (!positionId || !traderId) { @@ -85,13 +86,13 @@ export const handleSocialTraderPositionUrl = ({ ); } - if (notificationEvent !== undefined) { + if (notificationSubtype !== undefined) { const event = AnalyticsEventBuilder.createEventBuilder( MetaMetricsEvents.SOCIAL_FOLLOW_TRADING_NOTIFICATION_CLICKED, ) .addProperties({ - [SocialLeaderboardEventProperties.NOTIFICATION_TYPE]: - notificationEvent, + [SocialLeaderboardEventProperties.NOTIFICATION_SUBTYPE]: + notificationSubtype, }) .build(); analytics.trackEvent(event); @@ -101,6 +102,7 @@ export const handleSocialTraderPositionUrl = ({ positionId, traderId, source: 'notification', + notificationSubtype, }); } catch (error) { DevLogger.log( diff --git a/app/core/NavigationService/types.ts b/app/core/NavigationService/types.ts index 9542b4be5f7..46c66206195 100644 --- a/app/core/NavigationService/types.ts +++ b/app/core/NavigationService/types.ts @@ -246,6 +246,10 @@ type TraderPositionViewParams = /** Analytics entry-point that opened the position view. Narrowed at the * receiver into the QuickBuy / FollowTradingToken source enums. */ source?: string; + /** Notification subtype forwarded from the social-trader-position + * deeplink (e.g. `follow_newtrade_perp_long`). Attached to the + * destination screen's analytics event for click attribution. */ + notificationSubtype?: string; } | { /** Deep-link path: triggers useTraderPosition to fetch by UUID. */ @@ -260,6 +264,10 @@ type TraderPositionViewParams = /** Analytics entry-point that opened the position view. Narrowed at the * receiver into the QuickBuy / FollowTradingToken source enums. */ source?: string; + /** Notification subtype forwarded from the social-trader-position + * deeplink (e.g. `follow_newtrade_perp_long`). Attached to the + * destination screen's analytics event for click attribution. */ + notificationSubtype?: string; }; /** From 2a50c29ae1bebae022a9ac7a5267ee70b2da831f Mon Sep 17 00:00:00 2001 From: Juanmi <95381763+juanmigdr@users.noreply.github.com> Date: Tue, 16 Jun 2026 18:28:53 +0200 Subject: [PATCH 19/23] fix: broken perps section headers in Explore (#31697) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Fix broken perps section headers in Explore ## **Changelog** CHANGELOG entry: fix broken perps section headers in Explore ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/ASSETS-3367 ## **Manual testing steps** ```gherkin Feature: my feature name Scenario: user [verb for user action] Given [describe expected initial app state] When user [verb for user action] Then [describe expected outcome] ``` ## **Screenshots/Recordings** ### **Before** ### **After** https://github.com/user-attachments/assets/ce6366fb-b54e-4c6b-be49-7219327f3250 ## **Pre-merge author checklist** - [ ] 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). - [ ] I've completed the PR template to the best of my ability - [ ] I've included tests if applicable - [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] 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** - [ ] 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. --- .../feeds/perps/PerpsToggleBlock.test.tsx | 99 +++++- .../feeds/perps/PerpsToggleBlock.tsx | 47 ++- .../feeds/perps/perpsNavigation.ts | 3 +- .../Views/TrendingView/tabs/MacroTab.test.tsx | 220 +++++++++++++ .../Views/TrendingView/tabs/MacroTab.tsx | 61 ++-- .../Views/TrendingView/tabs/RwasTab.test.tsx | 306 ++++++++++++++++++ .../Views/TrendingView/tabs/RwasTab.tsx | 66 ++-- locales/languages/en.json | 5 - 8 files changed, 714 insertions(+), 93 deletions(-) create mode 100644 app/components/Views/TrendingView/tabs/MacroTab.test.tsx create mode 100644 app/components/Views/TrendingView/tabs/RwasTab.test.tsx diff --git a/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.test.tsx b/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.test.tsx index df656307e9d..c70337d06f2 100644 --- a/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.test.tsx +++ b/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.test.tsx @@ -90,16 +90,16 @@ const Skeleton = () => sk; const STOCKS_MARKETS = [makeMarket('AAPL'), makeMarket('GOOGL')]; const COMMODITY_MARKETS = [makeMarket('GOLD')]; -const DEFAULT_TABS = [ - { key: 'stocks', name: 'Stocks', items: STOCKS_MARKETS }, - { key: 'commodities', name: 'Commodities', items: COMMODITY_MARKETS }, +const DEFAULT_TABS: PerpsToggleBlockProps['tabs'] = [ + { key: 'stock', name: 'Stocks', items: STOCKS_MARKETS }, + { key: 'commodity', name: 'Commodities', items: COMMODITY_MARKETS }, ]; const DEFAULT_PROPS: PerpsToggleBlockProps = { title: 'Stocks & Commodities', tabs: DEFAULT_TABS, isLoading: false, - defaultPillKey: 'stocks', + defaultPillKey: 'stock', onViewAll: jest.fn(), sortOptionId: 'volume', tabName: 'Macro', @@ -137,8 +137,8 @@ describe('PerpsToggleBlock', () => { it('renders pill buttons for each tab', () => { const { getByTestId } = renderBlock(); - expect(getByTestId('test-toggle-pill-stocks')).toBeTruthy(); - expect(getByTestId('test-toggle-pill-commodities')).toBeTruthy(); + expect(getByTestId('test-toggle-pill-stock')).toBeTruthy(); + expect(getByTestId('test-toggle-pill-commodity')).toBeTruthy(); }); }); @@ -153,25 +153,25 @@ describe('PerpsToggleBlock', () => { }); describe('pill switching', () => { - it('shows the commodities items after selecting the commodities pill', () => { + it('shows the commodity items after selecting the commodity pill', () => { const { getByTestId, queryByTestId } = renderBlock(); act(() => { - fireEvent.press(getByTestId('test-toggle-pill-commodities')); + fireEvent.press(getByTestId('test-toggle-pill-commodity')); }); expect(getByTestId('perps-row-GOLD')).toBeTruthy(); expect(queryByTestId('perps-row-AAPL')).toBeNull(); }); - it('switching back to stocks shows stocks items again', () => { + it('switching back to stock shows stock items again', () => { const { getByTestId } = renderBlock(); act(() => { - fireEvent.press(getByTestId('test-toggle-pill-commodities')); + fireEvent.press(getByTestId('test-toggle-pill-commodity')); }); act(() => { - fireEvent.press(getByTestId('test-toggle-pill-stocks')); + fireEvent.press(getByTestId('test-toggle-pill-stock')); }); expect(getByTestId('perps-row-AAPL')).toBeTruthy(); @@ -186,7 +186,7 @@ describe('PerpsToggleBlock', () => { fireEvent.press(getByTestId('section-header-view-all-test')); expect(onViewAll).toHaveBeenCalledTimes(1); - expect(onViewAll).toHaveBeenCalledWith('stocks', 'volume'); + expect(onViewAll).toHaveBeenCalledWith('stock', 'volume'); }); it('calls onViewAll with the newly active pill key after switching pills', () => { @@ -194,12 +194,12 @@ describe('PerpsToggleBlock', () => { const { getByTestId } = renderBlock({ ...DEFAULT_PROPS, onViewAll }); act(() => { - fireEvent.press(getByTestId('test-toggle-pill-commodities')); + fireEvent.press(getByTestId('test-toggle-pill-commodity')); }); fireEvent.press(getByTestId('section-header-view-all-test')); - expect(onViewAll).toHaveBeenCalledWith('commodities', 'volume'); + expect(onViewAll).toHaveBeenCalledWith('commodity', 'volume'); }); it('forwards the sortOptionId prop unchanged regardless of active pill', () => { @@ -211,11 +211,11 @@ describe('PerpsToggleBlock', () => { }); act(() => { - fireEvent.press(getByTestId('test-toggle-pill-commodities')); + fireEvent.press(getByTestId('test-toggle-pill-commodity')); }); fireEvent.press(getByTestId('section-header-view-all-test')); - expect(onViewAll).toHaveBeenCalledWith('commodities', 'priceChange'); + expect(onViewAll).toHaveBeenCalledWith('commodity', 'priceChange'); }); it('calls onViewAll only once per press', () => { @@ -229,6 +229,73 @@ describe('PerpsToggleBlock', () => { }); }); + describe('empty-tab filtering', () => { + it('hides a pill whose items array is empty once loaded', () => { + const tabs: PerpsToggleBlockProps['tabs'] = [ + { key: 'stock', name: 'Stocks', items: STOCKS_MARKETS }, + { key: 'commodity', name: 'Commodities', items: [] }, + ]; + const { getByTestId, queryByTestId } = renderBlock({ + ...DEFAULT_PROPS, + tabs, + isLoading: false, + }); + + expect(getByTestId('test-toggle-pill-stock')).toBeTruthy(); + expect(queryByTestId('test-toggle-pill-commodity')).toBeNull(); + }); + + it('shows all pills while loading even if items are empty', () => { + const tabs: PerpsToggleBlockProps['tabs'] = [ + { key: 'stock', name: 'Stocks', items: [] }, + { key: 'commodity', name: 'Commodities', items: [] }, + ]; + const { getByTestId } = renderBlock({ + ...DEFAULT_PROPS, + tabs, + isLoading: true, + }); + + expect(getByTestId('test-toggle-pill-stock')).toBeTruthy(); + expect(getByTestId('test-toggle-pill-commodity')).toBeTruthy(); + }); + + it('defaults to the first pill that has items', () => { + const tabs: PerpsToggleBlockProps['tabs'] = [ + { key: 'stock', name: 'Stocks', items: [] }, + { key: 'commodity', name: 'Commodities', items: COMMODITY_MARKETS }, + ]; + const { getByTestId } = renderBlock({ + ...DEFAULT_PROPS, + tabs, + defaultPillKey: 'stock', + isLoading: false, + }); + + // commodity pill is active (stock was empty and hidden) + expect(getByTestId('perps-row-GOLD')).toBeTruthy(); + }); + + it('calls onViewAll with the first visible category when the default pill is empty', () => { + const onViewAll = jest.fn(); + const tabs: PerpsToggleBlockProps['tabs'] = [ + { key: 'stock', name: 'Stocks', items: [] }, + { key: 'commodity', name: 'Commodities', items: COMMODITY_MARKETS }, + ]; + const { getByTestId } = renderBlock({ + ...DEFAULT_PROPS, + tabs, + defaultPillKey: 'stock', + isLoading: false, + onViewAll, + }); + + fireEvent.press(getByTestId('section-header-view-all-test')); + + expect(onViewAll).toHaveBeenCalledWith('commodity', 'volume'); + }); + }); + describe('analytics', () => { it('calls trackExploreInteracted with correct context when a row is pressed', () => { const mockTrack = trackExploreInteracted as jest.Mock; diff --git a/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.tsx b/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.tsx index bed6dd344a3..e221094067c 100644 --- a/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.tsx +++ b/app/components/Views/TrendingView/feeds/perps/PerpsToggleBlock.tsx @@ -1,7 +1,11 @@ -import React, { useCallback, useRef } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { Box } from '@metamask/design-system-react-native'; import type { ListRenderItem } from '@shopify/flash-list'; -import type { PerpsMarketData, SortOptionId } from '@metamask/perps-controller'; +import { + type MarketTypeFilter, + type PerpsMarketData, + type SortOptionId, +} from '@metamask/perps-controller'; import PerpsRowItem from './PerpsRowItem'; import PerpsRowSkeleton from '../../../../UI/Perps/components/PerpsRowSkeleton'; import PillToggleCardList, { @@ -14,14 +18,17 @@ import { trackExploreInteracted, } from '../../search/analytics'; +/** Valid perps category filter keys — all `MarketTypeFilter` values except `'all'`. */ +export type PerpsFilterKey = Exclude; + const PerpsRowSingleSkeleton: React.FC = () => ; export interface PerpsToggleBlockProps { title: string; tabs: PillToggleCardListTab[]; isLoading: boolean; - defaultPillKey: string; - onViewAll: (filter: string, sortOptionId: SortOptionId) => void; + defaultPillKey: PerpsFilterKey; + onViewAll: (filter: PerpsFilterKey, sortOptionId: SortOptionId) => void; sortOptionId: SortOptionId; /** Analytics context */ tabName: ExploreTabName; @@ -51,7 +58,27 @@ const PerpsToggleBlock: React.FC = ({ testIdPrefix, listTestId, }) => { - const activePillKey = useRef(defaultPillKey); + const visibleTabs = useMemo( + () => (isLoading ? tabs : tabs.filter((t) => t.items.length > 0)), + [isLoading, tabs], + ); + + const firstVisibleKey = (visibleTabs[0]?.key ?? + defaultPillKey) as PerpsFilterKey; + const [activePillKey, setActivePillKey] = + useState(firstVisibleKey); + + useEffect(() => { + setActivePillKey((current) => + visibleTabs.some((tab) => tab.key === current) + ? current + : firstVisibleKey, + ); + }, [firstVisibleKey, visibleTabs]); + + const handlePillChange = useCallback((key: string) => { + setActivePillKey(key as PerpsFilterKey); + }, []); const renderItem: ListRenderItem = useCallback( ({ item, index }) => ( @@ -76,20 +103,20 @@ const PerpsToggleBlock: React.FC = ({ onViewAll(activePillKey.current, sortOptionId)} + onViewAll={() => onViewAll(activePillKey, sortOptionId)} testID={headerTestID} tabName={tabName} sectionName={sectionName} /> - tabs={tabs} + key={visibleTabs.map((tab) => tab.key).join(',')} + tabs={visibleTabs} isLoading={isLoading} renderItem={renderItem} Skeleton={PerpsRowSingleSkeleton} idPrefix={idPrefix} - onPillChange={(key) => { - activePillKey.current = key; - }} + defaultPillKey={firstVisibleKey} + onPillChange={handlePillChange} testIdPrefix={testIdPrefix} listTestId={listTestId} /> diff --git a/app/components/Views/TrendingView/feeds/perps/perpsNavigation.ts b/app/components/Views/TrendingView/feeds/perps/perpsNavigation.ts index 9b9d3e60ad9..dccbc81486e 100644 --- a/app/components/Views/TrendingView/feeds/perps/perpsNavigation.ts +++ b/app/components/Views/TrendingView/feeds/perps/perpsNavigation.ts @@ -1,6 +1,7 @@ import { NavigationProp } from '@react-navigation/native'; import { PERPS_EVENT_VALUE, + type MarketTypeFilter, type SortDirection, type SortOptionId, } from '@metamask/perps-controller'; @@ -18,7 +19,7 @@ interface NavigateToPerpsMarketListOptions { /** Navigate to the perps market list, optionally pre-filtering by market type and pre-sorting by a sort option. */ export const navigateToPerpsMarketList = ( navigation: NavigationProp, - filter: string = 'all', + filter: MarketTypeFilter = 'all', sortOptionId?: SortOptionId, { source = PERPS_EVENT_VALUE.SOURCE.EXPLORE, diff --git a/app/components/Views/TrendingView/tabs/MacroTab.test.tsx b/app/components/Views/TrendingView/tabs/MacroTab.test.tsx new file mode 100644 index 00000000000..31725963c6e --- /dev/null +++ b/app/components/Views/TrendingView/tabs/MacroTab.test.tsx @@ -0,0 +1,220 @@ +/** + * MacroTab — unit tests + * + * Covers: + * 1. Renders perps section when data is available. + * 2. Returns null for the perps block when data is empty and not loading. + * 3. Hides the perps section when the perps feature flag is off. + * 4. Calls navigateToPerpsMarketList with the active filter and sort option when "View All" is pressed. + */ + +jest.mock('@shopify/flash-list', () => { + const RN = jest.requireActual('react-native'); + return { FlashList: RN.FlatList }; +}); + +jest.mock('@metamask/design-system-twrnc-preset', () => { + const twFn = () => ({}); + twFn.style = () => ({}); + return { useTailwind: () => twFn }; +}); + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('../../../UI/Perps', () => ({ + selectPerpsEnabledFlag: jest.fn(() => true), + PerpsSectionProvider: ({ children }: { children: React.ReactNode }) => + children, +})); + +jest.mock('../../../UI/Predict', () => ({ + selectPredictEnabledFlag: jest.fn(() => false), +})); + +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigation: jest.fn(), +})); + +jest.mock('../search/analytics', () => ({ + trackExploreInteracted: jest.fn(), + trackExploreSectionSeeAll: jest.fn(), +})); + +jest.mock('../feeds/perps/usePerpsFeed'); +jest.mock('../feeds/predictions/usePredictionsFeed'); + +jest.mock('../feeds/predictions/PredictionsCarouselSection', () => { + const { View } = jest.requireActual('react-native'); + return function MockPredictionsCarouselSection() { + return ; + }; +}); + +jest.mock('../feeds/perps/PerpsSectionProvider', () => { + const { Fragment } = jest.requireActual('react'); + return function MockPerpsSectionProvider({ + children, + }: { + children: React.ReactNode; + }) { + return {children}; + }; +}); + +const mockNavigateToPerpsMarketList = jest.fn(); +jest.mock('../feeds/perps/perpsNavigation', () => ({ + navigateToPerpsMarketList: (...args: unknown[]) => + mockNavigateToPerpsMarketList(...args), +})); + +jest.mock('../feeds/perps/PerpsToggleBlock', () => { + const { TouchableOpacity, Text: RNText } = jest.requireActual('react-native'); + const MockPerpsToggleBlock = ({ + onViewAll, + sortOptionId, + defaultPillKey, + headerTestID, + }: { + title: string; + onViewAll: (filter: string, sort: string) => void; + sortOptionId: string; + defaultPillKey: string; + headerTestID: string; + isLoading: boolean; + }) => ( + onViewAll(defaultPillKey, sortOptionId)} + > + perps-block + + ); + MockPerpsToggleBlock.displayName = 'MockPerpsToggleBlock'; + return MockPerpsToggleBlock; +}); + +import React from 'react'; +import { render, fireEvent, act } from '@testing-library/react-native'; +import { useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; +import type { PerpsMarketData } from '@metamask/perps-controller'; +import { selectPerpsEnabledFlag } from '../../../UI/Perps'; +import { usePerpsFeed } from '../feeds/perps/usePerpsFeed'; +import { usePredictionsFeed } from '../feeds/predictions/usePredictionsFeed'; +import MacroTab from './MacroTab'; + +const mockUsePerpsFeed = jest.mocked(usePerpsFeed); +const mockUsePredictionsFeed = jest.mocked(usePredictionsFeed); + +const mockNavigation = { navigate: jest.fn() }; + +const makeMarket = (symbol: string, type: string): PerpsMarketData => + ({ + symbol, + name: symbol, + marketType: type, + price: '$1.00', + change24h: '+1%', + change24hPercent: '1', + volume: '$100M', + maxLeverage: '10x', + isHip3: false, + }) as PerpsMarketData; + +const makeFeedItem = (market: PerpsMarketData) => ({ + market, + isWatchlisted: false, +}); + +const DEFAULT_PERPS_FEED = { + data: [ + makeFeedItem(makeMarket('AAPL', 'stock')), + makeFeedItem(makeMarket('MSFT', 'pre-ipo')), + makeFeedItem(makeMarket('GOLD', 'commodity')), + ], + isLoading: false, + defaultSortOptionId: 'volume' as const, + refetch: jest.fn(), +}; + +const DEFAULT_REFRESH = { trigger: 0, silentRefresh: false }; + +const renderTab = () => + render( + , + ); + +describe('MacroTab', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useNavigation as jest.Mock).mockReturnValue(mockNavigation); + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === selectPerpsEnabledFlag) return true; + return false; + }); + mockUsePerpsFeed.mockReturnValue(DEFAULT_PERPS_FEED); + mockUsePredictionsFeed.mockReturnValue({ + data: [], + isLoading: false, + refetch: jest.fn(), + }); + }); + + it('renders the perps toggle block when data is available', () => { + const { getByTestId } = renderTab(); + expect(getByTestId('mock-perps-toggle-block')).toBeTruthy(); + }); + + it('does not render the perps block when data is empty and not loading', () => { + mockUsePerpsFeed.mockReturnValue({ + ...DEFAULT_PERPS_FEED, + data: [], + isLoading: false, + }); + + const { queryByTestId } = renderTab(); + expect(queryByTestId('mock-perps-toggle-block')).toBeNull(); + }); + + it('renders the perps block while loading even with no data', () => { + mockUsePerpsFeed.mockReturnValue({ + ...DEFAULT_PERPS_FEED, + data: [], + isLoading: true, + }); + + const { getByTestId } = renderTab(); + expect(getByTestId('mock-perps-toggle-block')).toBeTruthy(); + }); + + it('does not render the perps section when perps feature flag is off', () => { + (useSelector as jest.Mock).mockReturnValue(false); + + const { queryByTestId } = renderTab(); + expect(queryByTestId('mock-perps-toggle-block')).toBeNull(); + }); + + it('calls navigateToPerpsMarketList with correct filter when View All is pressed', () => { + const { getByTestId } = renderTab(); + + act(() => { + fireEvent.press( + getByTestId('section-header-view-all-macro_stocks_commodity_perps'), + ); + }); + + expect(mockNavigateToPerpsMarketList).toHaveBeenCalledWith( + mockNavigation, + 'stock', + 'volume', + ); + }); +}); diff --git a/app/components/Views/TrendingView/tabs/MacroTab.tsx b/app/components/Views/TrendingView/tabs/MacroTab.tsx index f254933b1ce..74e8e957dec 100644 --- a/app/components/Views/TrendingView/tabs/MacroTab.tsx +++ b/app/components/Views/TrendingView/tabs/MacroTab.tsx @@ -1,16 +1,22 @@ import React, { useMemo } from 'react'; import { useNavigation, NavigationProp } from '@react-navigation/native'; import { useSelector } from 'react-redux'; -import type { PerpsMarketData, SortOptionId } from '@metamask/perps-controller'; -import { isEquityAsset } from '../../../UI/Perps/utils/marketHours'; +import { + applyMarketFilters, + type PerpsMarketData, + type SortOptionId, +} from '@metamask/perps-controller'; import type { PerpsNavigationParamList } from '../../../UI/Perps/types/navigation'; import type { AppNavigationProp } from '../../../../core/NavigationService/types'; import { selectPerpsEnabledFlag } from '../../../UI/Perps'; import { selectPredictEnabledFlag } from '../../../UI/Predict'; +import { normalizeFilterKey } from '../../../UI/Perps/utils/marketCategoryMapping'; import { strings } from '../../../../../locales/i18n'; import { usePerpsFeed } from '../feeds/perps/usePerpsFeed'; import PerpsSectionProvider from '../feeds/perps/PerpsSectionProvider'; -import PerpsToggleBlock from '../feeds/perps/PerpsToggleBlock'; +import PerpsToggleBlock, { + type PerpsFilterKey, +} from '../feeds/perps/PerpsToggleBlock'; import { navigateToPerpsMarketList } from '../feeds/perps/perpsNavigation'; import { usePredictionsFeed } from '../feeds/predictions/usePredictionsFeed'; import PredictionsCarouselSection from '../feeds/predictions/PredictionsCarouselSection'; @@ -19,9 +25,18 @@ import ExploreScroll from '../components/ExploreScroll'; import type { PillToggleCardListTab } from '../components/PillToggleCardList'; import type { TabProps } from '../hooks/useExploreRefresh'; +/** Perps category pills for the Macro tab, in perps display order. */ +const MACRO_PERPS_CATEGORIES: PerpsFilterKey[] = [ + 'stock', + 'pre-ipo', + 'commodity', + 'index', + 'etf', +]; + interface MacroPerpsBlockProps { refresh: TabProps['refresh']; - onViewAll: (filter: string, sortOptionId: SortOptionId) => void; + onViewAll: (filter: PerpsFilterKey, sortOptionId: SortOptionId) => void; } const MacroPerpsBlock: React.FC = ({ @@ -29,30 +44,20 @@ const MacroPerpsBlock: React.FC = ({ onViewAll, }) => { const perps = usePerpsFeed({ variant: 'macro', refresh }); + const markets = useMemo(() => perps.data.map((d) => d.market), [perps.data]); - const tabs = useMemo[]>(() => { - const byType = (type: PerpsMarketData['marketType']) => - perps.data - .filter((d) => d.market.marketType === type) - .slice(0, 3) - .map((d) => d.market); - const stockLikeItems = perps.data - .filter((d) => isEquityAsset(d.market.marketType)) - .slice(0, 3) - .map((d) => d.market); - return [ - { - key: 'stocks', - name: strings('trending.macro_pill_stocks'), - items: stockLikeItems, - }, - { - key: 'commodities', - name: strings('trending.macro_pill_commodities'), - items: byType('commodity'), - }, - ]; - }, [perps.data]); + const tabs = useMemo[]>( + () => + MACRO_PERPS_CATEGORIES.map((category) => ({ + key: category, + name: strings(`perps.home.tabs.${normalizeFilterKey(category)}`), + items: applyMarketFilters(markets, { + categories: [category], + limit: 3, + }), + })), + [markets], + ); if (!perps.isLoading && perps.data.length === 0) return null; @@ -61,7 +66,7 @@ const MacroPerpsBlock: React.FC = ({ title={strings('trending.macro_stocks_commodity_perps')} tabs={tabs} isLoading={perps.isLoading} - defaultPillKey="stocks" + defaultPillKey={MACRO_PERPS_CATEGORIES[0]} onViewAll={onViewAll} sortOptionId={perps.defaultSortOptionId} tabName="Macro" diff --git a/app/components/Views/TrendingView/tabs/RwasTab.test.tsx b/app/components/Views/TrendingView/tabs/RwasTab.test.tsx new file mode 100644 index 00000000000..bc942d9447b --- /dev/null +++ b/app/components/Views/TrendingView/tabs/RwasTab.test.tsx @@ -0,0 +1,306 @@ +/** + * RwasTab — unit tests + * + * Covers: + * 1. Renders the perps toggle block when data is available. + * 2. Returns null for the perps block when data is empty and not loading. + * 3. Hides the perps section when the perps feature flag is off. + * 4. Calls navigateToPerpsMarketList with the correct filter when "View All" is pressed. + * 5. Renders the stocks section when stocks data is available. + */ + +jest.mock('@shopify/flash-list', () => { + const RN = jest.requireActual('react-native'); + return { FlashList: RN.FlatList }; +}); + +jest.mock('@metamask/design-system-twrnc-preset', () => { + const twFn = () => ({}); + twFn.style = () => ({}); + return { useTailwind: () => twFn }; +}); + +jest.mock('react-redux', () => ({ + ...jest.requireActual('react-redux'), + useSelector: jest.fn(), +})); + +jest.mock('@react-navigation/native', () => ({ + ...jest.requireActual('@react-navigation/native'), + useNavigation: jest.fn(), +})); + +jest.mock('../search/analytics', () => ({ + trackExploreInteracted: jest.fn(), + trackExploreSectionSeeAll: jest.fn(), +})); + +jest.mock('../../../UI/Perps', () => ({ + selectPerpsEnabledFlag: jest.fn(() => true), +})); + +jest.mock('../../../UI/Predict', () => ({ + selectPredictEnabledFlag: jest.fn(() => false), +})); + +jest.mock('../feeds/perps/usePerpsFeed'); +jest.mock('../feeds/stocks/useStocksFeed', () => ({ + useStocksFeed: jest.fn(), + STOCKS_FEED_PREVIEW_PAGE_SIZE: 3, +})); +jest.mock('../feeds/predictions/usePredictionsFeed'); + +jest.mock('../feeds/predictions/PredictionsCarouselSection', () => { + const { View } = jest.requireActual('react-native'); + return function MockPredictionsCarouselSection() { + return ; + }; +}); + +jest.mock('../feeds/perps/PerpsSectionProvider', () => { + const { Fragment } = jest.requireActual('react'); + return function MockPerpsSectionProvider({ + children, + }: { + children: React.ReactNode; + }) { + return {children}; + }; +}); + +const mockNavigateToPerpsMarketList = jest.fn(); +jest.mock('../feeds/perps/perpsNavigation', () => ({ + navigateToPerpsMarketList: (...args: unknown[]) => + mockNavigateToPerpsMarketList(...args), +})); + +jest.mock('../feeds/tokens/TokenRowItem', () => { + const { View } = jest.requireActual('react-native'); + return { + TokenRowItem: function MockTokenRowItem() { + return ; + }, + }; +}); + +jest.mock( + '../../../UI/Trending/components/TrendingTokenSkeleton/TrendingTokensSkeleton', + () => { + const { View } = jest.requireActual('react-native'); + return function MockTrendingTokensSkeleton() { + return ; + }; + }, +); + +jest.mock('../../../UI/Trending/components/TrendingTokenRowItem/utils', () => ({ + getCaipChainIdFromAssetId: jest.fn(() => 'eip155:1'), +})); + +jest.mock('../feeds/perps/PerpsToggleBlock', () => { + const { TouchableOpacity, Text: RNText } = jest.requireActual('react-native'); + const MockPerpsToggleBlock = ({ + onViewAll, + sortOptionId, + defaultPillKey, + headerTestID, + }: { + title: string; + onViewAll: (filter: string, sort: string) => void; + sortOptionId: string; + defaultPillKey: string; + headerTestID: string; + isLoading: boolean; + }) => ( + onViewAll(defaultPillKey, sortOptionId)} + > + perps-block + + ); + MockPerpsToggleBlock.displayName = 'MockPerpsToggleBlock'; + return MockPerpsToggleBlock; +}); + +import React from 'react'; +import { render, fireEvent, act } from '@testing-library/react-native'; +import { useSelector } from 'react-redux'; +import { useNavigation } from '@react-navigation/native'; +import type { PerpsMarketData } from '@metamask/perps-controller'; +import { selectPerpsEnabledFlag } from '../../../UI/Perps'; +import { usePerpsFeed } from '../feeds/perps/usePerpsFeed'; +import { useStocksFeed } from '../feeds/stocks/useStocksFeed'; +import { usePredictionsFeed } from '../feeds/predictions/usePredictionsFeed'; +import RwasTab from './RwasTab'; + +const mockUsePerpsFeed = jest.mocked(usePerpsFeed); +const mockUseStocksFeed = jest.mocked(useStocksFeed); +const mockUsePredictionsFeed = jest.mocked(usePredictionsFeed); + +const mockNavigation = { navigate: jest.fn() }; + +const makeMarket = (symbol: string, type: string): PerpsMarketData => + ({ + symbol, + name: symbol, + marketType: type, + price: '$1.00', + change24h: '+1%', + change24hPercent: '1', + volume: '$100M', + maxLeverage: '10x', + isHip3: false, + }) as PerpsMarketData; + +const makeFeedItem = (market: PerpsMarketData) => ({ + market, + isWatchlisted: false, +}); + +const DEFAULT_PERPS_FEED = { + data: [ + makeFeedItem(makeMarket('GOLD', 'commodity')), + makeFeedItem(makeMarket('AAPL', 'stock')), + makeFeedItem(makeMarket('EURUSD', 'forex')), + ], + isLoading: false, + defaultSortOptionId: 'priceChange' as const, + refetch: jest.fn(), +}; + +const DEFAULT_REFRESH = { trigger: 0, silentRefresh: false }; + +const renderTab = () => + render( + , + ); + +describe('RwasTab', () => { + beforeEach(() => { + jest.clearAllMocks(); + (useNavigation as jest.Mock).mockReturnValue(mockNavigation); + (useSelector as jest.Mock).mockImplementation((selector) => { + if (selector === selectPerpsEnabledFlag) return true; + return false; + }); + mockUsePerpsFeed.mockReturnValue(DEFAULT_PERPS_FEED); + mockUseStocksFeed.mockReturnValue({ + data: [], + isLoading: false, + refetch: jest.fn(), + }); + mockUsePredictionsFeed.mockReturnValue({ + data: [], + isLoading: false, + refetch: jest.fn(), + }); + }); + + it('renders the perps toggle block when data is available', () => { + const { getByTestId } = renderTab(); + expect(getByTestId('mock-perps-toggle-block')).toBeTruthy(); + }); + + it('does not render the perps block when data is empty and not loading', () => { + mockUsePerpsFeed.mockReturnValue({ + ...DEFAULT_PERPS_FEED, + data: [], + isLoading: false, + }); + + const { queryByTestId } = renderTab(); + expect(queryByTestId('mock-perps-toggle-block')).toBeNull(); + }); + + it('renders the perps block while loading even with no data', () => { + mockUsePerpsFeed.mockReturnValue({ + ...DEFAULT_PERPS_FEED, + data: [], + isLoading: true, + }); + + const { getByTestId } = renderTab(); + expect(getByTestId('mock-perps-toggle-block')).toBeTruthy(); + }); + + it('does not render the perps section when perps feature flag is off', () => { + (useSelector as jest.Mock).mockReturnValue(false); + + const { queryByTestId } = renderTab(); + expect(queryByTestId('mock-perps-toggle-block')).toBeNull(); + }); + + it('calls navigateToPerpsMarketList with correct filter when View All is pressed', () => { + const { getByTestId } = renderTab(); + + act(() => { + fireEvent.press(getByTestId('section-header-view-all-rwa_perps')); + }); + + expect(mockNavigateToPerpsMarketList).toHaveBeenCalledWith( + mockNavigation, + 'stock', + 'priceChange', + ); + }); + + it('renders stocks section when stocks data is present', () => { + mockUseStocksFeed.mockReturnValue({ + data: [ + { + symbol: 'AAPL', + name: 'Apple', + assetId: 'eip155:1/erc20:0xabc', + decimals: 18, + price: '150', + aggregatedUsdVolume: 1000, + marketCap: 2000, + }, + ], + isLoading: false, + refetch: jest.fn(), + }); + + const { getByTestId } = renderTab(); + expect(getByTestId('section-header-view-all-stocks')).toBeTruthy(); + }); + + it('hides stocks section when stocks data is empty and not loading', () => { + mockUseStocksFeed.mockReturnValue({ + data: [], + isLoading: false, + refetch: jest.fn(), + }); + + const { queryByTestId } = renderTab(); + expect(queryByTestId('section-header-view-all-stocks')).toBeNull(); + }); + + it('navigates to RWA tokens full view when stocks View All is pressed', () => { + mockUseStocksFeed.mockReturnValue({ + data: [ + { + symbol: 'AAPL', + name: 'Apple', + assetId: 'eip155:1/erc20:0xabc', + decimals: 18, + price: '150', + aggregatedUsdVolume: 1000, + marketCap: 2000, + }, + ], + isLoading: false, + refetch: jest.fn(), + }); + + const { getByTestId } = renderTab(); + fireEvent.press(getByTestId('section-header-view-all-stocks')); + + expect(mockNavigation.navigate).toHaveBeenCalledWith('RWATokensFullView'); + }); +}); diff --git a/app/components/Views/TrendingView/tabs/RwasTab.tsx b/app/components/Views/TrendingView/tabs/RwasTab.tsx index 79b067807f7..d5dde08ffc3 100644 --- a/app/components/Views/TrendingView/tabs/RwasTab.tsx +++ b/app/components/Views/TrendingView/tabs/RwasTab.tsx @@ -4,8 +4,11 @@ import { useSelector } from 'react-redux'; import { Box } from '@metamask/design-system-react-native'; import type { ListRenderItem } from '@shopify/flash-list'; import type { TrendingAsset } from '@metamask/assets-controllers'; -import type { PerpsMarketData, SortOptionId } from '@metamask/perps-controller'; -import { isEquityAsset } from '../../../UI/Perps/utils/marketHours'; +import { + applyMarketFilters, + type PerpsMarketData, + type SortOptionId, +} from '@metamask/perps-controller'; import type { PerpsNavigationParamList } from '../../../UI/Perps/types/navigation'; import type { AppNavigationProp } from '../../../../core/NavigationService/types'; import { selectPerpsEnabledFlag } from '../../../UI/Perps'; @@ -22,7 +25,10 @@ import { import { getCaipChainIdFromAssetId } from '../../../UI/Trending/components/TrendingTokenRowItem/utils'; import { usePerpsFeed } from '../feeds/perps/usePerpsFeed'; import PerpsSectionProvider from '../feeds/perps/PerpsSectionProvider'; -import PerpsToggleBlock from '../feeds/perps/PerpsToggleBlock'; +import PerpsToggleBlock, { + type PerpsFilterKey, +} from '../feeds/perps/PerpsToggleBlock'; +import { normalizeFilterKey } from '../../../UI/Perps/utils/marketCategoryMapping'; import { navigateToPerpsMarketList } from '../feeds/perps/perpsNavigation'; import { usePredictionsFeed } from '../feeds/predictions/usePredictionsFeed'; import PredictionsCarouselSection from '../feeds/predictions/PredictionsCarouselSection'; @@ -35,9 +41,18 @@ import type { TabProps } from '../hooks/useExploreRefresh'; import { trackExploreInteracted } from '../search/analytics'; import { TrendingViewSelectorsIDs } from '../TrendingView.testIds'; +/** Perps category pills for the RWAs tab, in perps display order. */ +const RWA_PERPS_CATEGORIES: PerpsFilterKey[] = [ + 'stock', + 'pre-ipo', + 'forex', + 'index', + 'etf', +]; + interface RwaPerpsBlockProps { refresh: TabProps['refresh']; - onViewAll: (filter: string, sortOptionId: SortOptionId) => void; + onViewAll: (filter: PerpsFilterKey, sortOptionId: SortOptionId) => void; } const RwaPerpsBlock: React.FC = ({ @@ -45,35 +60,20 @@ const RwaPerpsBlock: React.FC = ({ onViewAll, }) => { const perps = usePerpsFeed({ variant: 'rwa', refresh }); + const markets = useMemo(() => perps.data.map((d) => d.market), [perps.data]); - const tabs = useMemo[]>(() => { - const byType = (type: PerpsMarketData['marketType']) => - perps.data - .filter((d) => d.market.marketType === type) - .slice(0, 3) - .map((d) => d.market); - const stockLikeItems = perps.data - .filter((d) => isEquityAsset(d.market.marketType)) - .slice(0, 3) - .map((d) => d.market); - return [ - { - key: 'commodities', - name: strings('trending.rwa_pill_commodities'), - items: byType('commodity'), - }, - { - key: 'stocks', - name: strings('trending.rwa_pill_stocks'), - items: stockLikeItems, - }, - { - key: 'forex', - name: strings('trending.rwa_pill_forex'), - items: byType('forex'), - }, - ]; - }, [perps.data]); + const tabs = useMemo[]>( + () => + RWA_PERPS_CATEGORIES.map((category) => ({ + key: category, + name: strings(`perps.home.tabs.${normalizeFilterKey(category)}`), + items: applyMarketFilters(markets, { + categories: [category], + limit: 3, + }), + })), + [markets], + ); if (!perps.isLoading && perps.data.length === 0) return null; @@ -82,7 +82,7 @@ const RwaPerpsBlock: React.FC = ({ title={strings('trending.rwa_perps_section')} tabs={tabs} isLoading={perps.isLoading} - defaultPillKey="commodities" + defaultPillKey={RWA_PERPS_CATEGORIES[0]} onViewAll={onViewAll} sortOptionId={perps.defaultSortOptionId} tabName="RWAs" diff --git a/locales/languages/en.json b/locales/languages/en.json index 45002d0ec3c..806075cbaa6 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -9645,11 +9645,6 @@ "perps": "Perps", "rwa_perps_section": "Perps", "macro_stocks_commodity_perps": "Perps", - "macro_pill_stocks": "Stocks", - "macro_pill_commodities": "Commodities", - "rwa_pill_commodities": "Commodities", - "rwa_pill_stocks": "Stocks", - "rwa_pill_forex": "Forex", "crypto_perps_section": "Perps", "predictions": "Predictions", "no_results": "No results found", From 463792971347ff1badd1b5df6461bd59bb40d367 Mon Sep 17 00:00:00 2001 From: Shane T Date: Tue, 16 Jun 2026 17:59:29 +0100 Subject: [PATCH 20/23] chore: display money card transactions as mUSD (#31820) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Display card transactions as mUSD rather than vmUSD Also remove the linked requirement before fetching card transactions, since you can still fetch them even if you are logged out. ## **Changelog** CHANGELOG entry: display money card transactions as mUSD ## **Related issues** Fixes: N/A ## **Manual testing steps** ```gherkin Feature: money account card transactions Scenario: user looks at activity list Given you have a money account with at least one card transaction When you look at the activity item in the list Then the token shown in the row will be mUSD ``` ## **Screenshots/Recordings** ### **Before** Simulator Screenshot - iPhone 16e -
2026-06-16 at 16 27 11 ### **After** Simulator Screenshot - iPhone 16e -
2026-06-16 at 16 27 19 ## **Pre-merge author checklist** - [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** - [ ] 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. --- .../useMoneyAccountCardTransactions.test.ts | 19 ------------------- .../hooks/useMoneyAccountCardTransactions.ts | 3 +-- .../utils/cardTransactionDisplayInfo.test.ts | 4 ++-- .../Money/utils/cardTransactionDisplayInfo.ts | 3 ++- 4 files changed, 5 insertions(+), 24 deletions(-) diff --git a/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.test.ts b/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.test.ts index d2ffa01e39b..beb5fc1eb3b 100644 --- a/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.test.ts +++ b/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.test.ts @@ -3,7 +3,6 @@ import { useQuery } from '@tanstack/react-query'; import { useSelector } from 'react-redux'; import { apiClient } from '../../../../core/apiClient'; import { selectPrimaryMoneyAccount } from '../../../../selectors/moneyAccountController'; -import { selectIsMoneyAccountDelegatedForCard } from '../../../../selectors/cardController'; import { parseCardTransactions } from '../utils/accountsApi'; import { useMoneyAccountCardTransactions } from './useMoneyAccountCardTransactions'; import { MUSD_MONEY_ACCOUNT_CHAIN_IDS } from '../../Earn/constants/musd'; @@ -29,9 +28,6 @@ jest.mock('../../../../core/apiClient', () => ({ jest.mock('../../../../selectors/moneyAccountController', () => ({ selectPrimaryMoneyAccount: jest.fn(), })); -jest.mock('../../../../selectors/cardController', () => ({ - selectIsMoneyAccountDelegatedForCard: jest.fn(), -})); jest.mock('../utils/accountsApi', () => ({ parseCardTransactions: jest.fn(), })); @@ -60,17 +56,12 @@ const CARD: CardTransaction = { function setupSelectors( opts: { - isLinked?: boolean; account?: { address: string } | undefined; } = {}, ) { - const isLinked = opts.isLinked ?? true; // Distinguish "not provided" (default account) from an explicit `undefined`. const account = 'account' in opts ? opts.account : { address: ADDR_A }; mockUseSelector.mockImplementation((selector) => { - if (selector === selectIsMoneyAccountDelegatedForCard) { - return isLinked; - } if (selector === selectPrimaryMoneyAccount) { return account; } @@ -122,16 +113,6 @@ describe('useMoneyAccountCardTransactions', () => { ); }); - it('disables the query for an unlinked account', () => { - setupSelectors({ isLinked: false }); - - renderHook(() => useMoneyAccountCardTransactions()); - - expect(mockUseQuery).toHaveBeenCalledWith( - expect.objectContaining({ enabled: false }), - ); - }); - it('disables the query and sends an empty address when there is no money account', () => { setupSelectors({ account: undefined }); diff --git a/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.ts b/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.ts index ba10a71399d..29c9f502800 100644 --- a/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.ts +++ b/app/components/UI/Money/hooks/useMoneyAccountCardTransactions.ts @@ -28,7 +28,6 @@ const EMPTY: CardTransaction[] = []; */ export function useMoneyAccountCardTransactions(): UseMoneyAccountCardTransactionsResult { const primaryMoneyAccount = useSelector(selectPrimaryMoneyAccount); - const isLinked = useSelector(selectIsMoneyAccountDelegatedForCard); const rawAddress = primaryMoneyAccount?.address; const moneyAddress = rawAddress ? toChecksumHexAddress(rawAddress) : ''; @@ -49,7 +48,7 @@ export function useMoneyAccountCardTransactions(): UseMoneyAccountCardTransactio const query = useQuery({ ...queryOptions, select, - enabled: isLinked && moneyAddress !== '', + enabled: moneyAddress !== '', staleTime: 5 * MINUTE, retry: false, } as unknown as UseQueryOptions< diff --git a/app/components/UI/Money/utils/cardTransactionDisplayInfo.test.ts b/app/components/UI/Money/utils/cardTransactionDisplayInfo.test.ts index 60391802831..e999a6b5332 100644 --- a/app/components/UI/Money/utils/cardTransactionDisplayInfo.test.ts +++ b/app/components/UI/Money/utils/cardTransactionDisplayInfo.test.ts @@ -28,7 +28,7 @@ describe('cardTransactionDisplayInfo', () => { expect(info.isIncoming).toBe(false); expect(info.icon).toBe(IconName.Card); expect(info.description).toBeUndefined(); - expect(info.primaryAmount).toBe('-5.38 USDC'); + expect(info.primaryAmount).toBe('-5.38 mUSD'); expect(info.fiatAmount).toContain('5.38'); expect(info.fiatAmount.startsWith('-')).toBe(true); }); @@ -41,7 +41,7 @@ describe('cardTransactionDisplayInfo', () => { }); // Assert - expect(info.primaryAmount).toBe('-5.38 USDC'); + expect(info.primaryAmount).toBe('-5.38 mUSD'); expect(info.fiatAmount).toContain('10.76'); }); }); diff --git a/app/components/UI/Money/utils/cardTransactionDisplayInfo.ts b/app/components/UI/Money/utils/cardTransactionDisplayInfo.ts index 280c548560d..ccd7eed4272 100644 --- a/app/components/UI/Money/utils/cardTransactionDisplayInfo.ts +++ b/app/components/UI/Money/utils/cardTransactionDisplayInfo.ts @@ -4,6 +4,7 @@ import { strings } from '../../../../../locales/i18n'; import type { CardTransaction } from '../types/moneyActivity'; import type { MoneyTransactionDisplayInfo } from '../hooks/useMoneyTransactionDisplayInfo'; import { moneyFormatFiat } from './moneyFormatFiat'; +import { MONEY_ACCOUNT_DISPLAY_SYMBOL } from '../../Card/util/vedaToken'; export function cardTransactionDisplayInfo( card: CardTransaction, @@ -15,7 +16,7 @@ export function cardTransactionDisplayInfo( new BigNumber(10).pow(card.token.decimals), ); - const primaryAmount = `-${usdValue.toFixed(2)} ${card.token.symbol}`; + const primaryAmount = `-${usdValue.toFixed(2)} ${MONEY_ACCOUNT_DISPLAY_SYMBOL}`; const fiatAmount = usdToCurrentCurrencyRate && usdToCurrentCurrencyRate > 0 From 3a3f58f4d953faa56bb873684e1ed0ed7830eaa9 Mon Sep 17 00:00:00 2001 From: infiniteflower <139582705+infiniteflower@users.noreply.github.com> Date: Wed, 17 Jun 2026 02:04:32 +0900 Subject: [PATCH 21/23] fix: stx always being disabled for non ethereum networks cp-7.82.0 (#31822) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Batch sell was reporting smart transactions (STX) as disabled on all networks except Ethereum mainnet and Sepolia, even when STX was enabled for the user and the Sentinel liveness API returned `smartTransactions: true` for chains like BSC, Base, and Polygon. Unified Swap/Bridge already refreshes STX liveness on entry via `useRefreshSmartTransactionsLiveness`, which calls `SmartTransactionsController.fetchLiveness` and populates `livenessByChainId` in Redux. Batch sell never triggered that fetch, so only the controller defaults (mainnet + sepolia) were present and `selectSmartTransactionsEnabled` returned false for every other chain. This change adds the same liveness refresh to the first batch sell screen (`BatchSellTokenSelect`), keyed off the active source chain (`activeChainId`), matching the BridgeView pattern. When the user switches chain pills, liveness is refetched for the newly selected chain. ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://github.com/MetaMask/metamask-mobile/issues/31821 ## **Manual testing steps** ```gherkin Feature: Batch sell smart transaction liveness Scenario: STX is enabled on a non-Ethereum batch sell network Given smart transactions are opted in in Settings > Advanced Given the wallet has tokens on BSC (or Base / Polygon / Arbitrum / Linea) When the user opens Batch sell token select And selects the non-Ethereum network pill And proceeds through review to fetch quotes Then quote requests include stx_enabled true (when other STX gates pass) And batch sell submission passes isStxEnabled true Scenario: STX liveness refreshes when switching batch sell networks Given the user is on Batch sell token select with multiple eligible networks When the user switches between network pills Then liveness is fetched for each selected chain (verify via Redux livenessByChainId or network inspector) ``` Additional verification: - Confirm Ethereum mainnet and Sepolia batch sell behavior is unchanged. - Confirm batch sell still respects STX opt-out (Settings toggle off → STX false). ## **Screenshots/Recordings** ### **Before** Screenshot 2026-06-16 at 11 27
20 AM ### **After** Screenshot 2026-06-16 at 11 22
41 AM ## **Pre-merge author checklist** - [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) - [x] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [x] 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 - [x] 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** - [ ] 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. --- .../Views/BatchSellTokenSelect/BatchSellTokenSelect.test.tsx | 4 ++++ .../Views/BatchSellTokenSelect/BatchSellTokenSelect.tsx | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.test.tsx b/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.test.tsx index e88bcfd8084..14a739c144c 100644 --- a/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.test.tsx +++ b/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.test.tsx @@ -55,6 +55,10 @@ jest.mock('react-redux', () => ({ useSelector: (selector: (state: unknown) => unknown) => selector({}), })); +jest.mock('../../../../hooks/useRefreshSmartTransactionsLiveness', () => ({ + useRefreshSmartTransactionsLiveness: jest.fn(), +})); + jest.mock('@metamask/design-system-react-native', () => { const DesignSystem = jest.requireActual( '@metamask/design-system-react-native', diff --git a/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.tsx b/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.tsx index f3f78b45d20..da2f13a3b13 100644 --- a/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.tsx +++ b/app/components/UI/Bridge/Views/BatchSellTokenSelect/BatchSellTokenSelect.tsx @@ -61,6 +61,7 @@ import { BatchSellEmptyState } from './BatchSellEmptyState'; import { DEFAULT_BATCH_SELL_SLIPPAGE } from '../../components/SlippageModal/utils'; import { normalizeTokenAddress } from '../../utils/tokenUtils'; import { useBatchSellTokens } from './useBatchSellTokens'; +import { useRefreshSmartTransactionsLiveness } from '../../../../hooks/useRefreshSmartTransactionsLiveness'; const getTokenKey = (token: BridgeToken) => `${formatChainIdToCaip(token.chainId)}:${normalizeTokenAddress( @@ -175,6 +176,10 @@ export function BatchSellTokenSelect() { }, [selectedChainId, sortedEligibleChains]); const activeChainId = selectedChainId ?? sortedEligibleChains[0]?.chainId; + + // Fetch STX liveness for the active batch sell source chain + useRefreshSmartTransactionsLiveness(activeChainId); + const destinationStablecoins = useSelector((state: RootState) => selectBatchSellDestStablecoins(state, activeChainId), ); From 6124d641597c39d8f427e4529365e8f9f4215a38 Mon Sep 17 00:00:00 2001 From: "Matt D." <85914066+geositta@users.noreply.github.com> Date: Tue, 16 Jun 2026 12:07:52 -0500 Subject: [PATCH 22/23] feat(charts): add currentPriceLineColorOverride prop to AdvancedChart (#31751) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Adds currentPriceLineColorOverride prop to AdvancedChart - Adds currentPriceLineColorOverride?: string to AdvancedChartProps and the ChartFeatures template interface, baking it into window.CONFIG.theme.currentPriceColor at HTML creation time - Updates createLastPriceLine (candle chart) and createLineLastPriceLine (line chart) in chartLogic.js to read currentPriceColor || successColor so the override applies without touching candle up-colors, volume, or line-chart series color - Consumers that don't pass the prop get an empty string → falsy → existing successColor fallback; no visual change to the token detail chart - Fixes a race condition in the initial*ColorRef hot-swap pattern: the three color-override refs (initialLineColorRef, initialSuccessColorRef, initialErrorColorRef) are now snapshotted synchronously inside useMemo rather than in a post-render useEffect. This prevents SET_THEME_COLORS from seeing "colors already match" and skipping a needed hot-swap when a theme change and a color override change land in the same render cycle. Motivation The current-price horizontal line currently uses successColor (green), which is also used for candle up-colors and volume. A per-consumer override is needed so Perps can render a white price line without changing candle colors globally. Test plan - [ ] All existing AdvancedChart unit tests pass (yarn jest app/components/UI/Charts/AdvancedChart/) - [ ] Token detail chart: current-price line unchanged (still green/successColor) — no currentPriceLineColorOverride passed - [ ] After this merges, the Perps migration PR adds currentPriceLineColorOverride={colors.text.default} to PerpsAdvancedChart and verifies the price line renders white (dark mode) / near-black (light mode) without affecting candle colors ## **Changelog** CHANGELOG entry: null ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/TAT-3152 ## **Manual testing steps** ```gherkin Feature: Advanced chart current price color Scenario: chart colors update after live price direction changes Given the token details chart is loaded with a custom current price line color When live price data changes the token chart direction from positive to negative Then the chart updates its line and candle colors without rebuilding the WebView And the current price horizontal line keeps the custom current price line color ``` ## **Screenshots/Recordings** ### **Before** N/A ### **After** N/A ## **Pre-merge author checklist** - [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** - [ ] 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. --- .../UI/Charts/AdvancedChart/AdvancedChart.tsx | 55 +++++++++++++------ .../AdvancedChart/AdvancedChart.types.ts | 2 + .../AdvancedChart/AdvancedChartTemplate.ts | 4 +- .../AdvancedChart/webview/chartLogic.js | 12 ++-- .../AdvancedChart/webview/chartLogicString.ts | 12 ++-- 5 files changed, 58 insertions(+), 27 deletions(-) diff --git a/app/components/UI/Charts/AdvancedChart/AdvancedChart.tsx b/app/components/UI/Charts/AdvancedChart/AdvancedChart.tsx index 7f80e8d6eb8..fa2502accb5 100644 --- a/app/components/UI/Charts/AdvancedChart/AdvancedChart.tsx +++ b/app/components/UI/Charts/AdvancedChart/AdvancedChart.tsx @@ -97,6 +97,7 @@ const AdvancedChart = forwardRef( lineColorOverride, successColorOverride, errorColorOverride, + currentPriceLineColorOverride, }, ref, ) => { @@ -130,29 +131,50 @@ const AdvancedChart = forwardRef( const tradingViewOpenInterceptRef = useRef(0); const skeletonHiddenReportedRef = useRef(false); - // Capture the color overrides baked into the HTML template so the + // Track the color overrides baked into the current HTML template so the // SET_THEME_COLORS effect can skip sending when colors haven't diverged. + // Refs are updated synchronously inside the useMemo below (not in a post-render + // effect) so the snapshot is always in sync with what was actually baked, even + // when multiple deps change in the same render cycle. const initialLineColorRef = useRef(lineColorOverride); const initialSuccessColorRef = useRef(successColorOverride); const initialErrorColorRef = useRef(errorColorOverride); const themeColorsSentRef = useRef(false); - const htmlContent = useMemo( - () => - createAdvancedChartTemplate(theme, { - enableDrawingTools, - disabledFeatures, - lineChrome, - lineColorOverride: initialLineColorRef.current, - successColorOverride: initialSuccessColorRef.current, - errorColorOverride: initialErrorColorRef.current, - }), - // Color overrides intentionally excluded — hot-swapped via SET_THEME_COLORS. + const htmlContent = useMemo(() => { + // Snapshot current prop values at the moment the template is created. + // This must happen inside useMemo (not in a separate effect) so the refs + // reflect what is actually baked, preventing a stale-color race where a + // simultaneous non-color dep change causes the SET_THEME_COLORS effect to + // see "colors already match" and skip a needed hot-swap. + initialLineColorRef.current = lineColorOverride; + initialSuccessColorRef.current = successColorOverride; + initialErrorColorRef.current = errorColorOverride; + return createAdvancedChartTemplate(theme, { + enableDrawingTools, + disabledFeatures, + lineChrome, + lineColorOverride, + successColorOverride, + errorColorOverride, + currentPriceLineColorOverride, + }); + // lineColorOverride/successColorOverride/errorColorOverride intentionally excluded — + // color changes hot-swap via SET_THEME_COLORS without rebuilding the WebView. + // currentPriceLineColorOverride is a direct dep: it is theme-derived and changes + // only with theme, so the initial-ref indirection would introduce a stale-color race. // eslint-disable-next-line react-hooks/exhaustive-deps - [theme, enableDrawingTools, disabledFeatures, lineChrome], - ); + }, [ + theme, + enableDrawingTools, + disabledFeatures, + lineChrome, + currentPriceLineColorOverride, + ]); - // Reset all chart state when the WebView reloads due to htmlContent changes + // Reset all chart state when the WebView reloads due to htmlContent changes. + // Color refs are intentionally omitted here — they are snapshotted synchronously + // inside the useMemo above. useEffect(() => { skeletonHiddenReportedRef.current = false; setChartReadyCount(0); @@ -166,9 +188,6 @@ const AdvancedChart = forwardRef( prevOhlcvSeriesKeyRef.current = undefined; ohlcvSeriesStaleSnapshotRef.current = null; themeColorsSentRef.current = false; - initialLineColorRef.current = lineColorOverride; - initialSuccessColorRef.current = successColorOverride; - initialErrorColorRef.current = errorColorOverride; }, [htmlContent]); // eslint-disable-line react-hooks/exhaustive-deps // ---- Helpers ---- diff --git a/app/components/UI/Charts/AdvancedChart/AdvancedChart.types.ts b/app/components/UI/Charts/AdvancedChart/AdvancedChart.types.ts index ad1e526f1fa..d7facfd5e09 100644 --- a/app/components/UI/Charts/AdvancedChart/AdvancedChart.types.ts +++ b/app/components/UI/Charts/AdvancedChart/AdvancedChart.types.ts @@ -507,6 +507,8 @@ export interface AdvancedChartProps { successColorOverride?: string; /** Override the candlestick down/error color baked into the HTML template (A/B test). */ errorColorOverride?: string; + /** Override the current-price horizontal line color. Does not affect candle or volume colors. */ + currentPriceLineColorOverride?: string; } /** diff --git a/app/components/UI/Charts/AdvancedChart/AdvancedChartTemplate.ts b/app/components/UI/Charts/AdvancedChart/AdvancedChartTemplate.ts index 963fd7fbfb8..54933dbfc1a 100644 --- a/app/components/UI/Charts/AdvancedChart/AdvancedChartTemplate.ts +++ b/app/components/UI/Charts/AdvancedChart/AdvancedChartTemplate.ts @@ -56,6 +56,7 @@ interface ChartFeatures { lineColorOverride?: string; successColorOverride?: string; errorColorOverride?: string; + currentPriceLineColorOverride?: string; } const createConfigScript = ( @@ -78,7 +79,8 @@ window.CONFIG = { successColor: '${successColor}', lineColor: '${lineColor}', errorColor: '${errorColor}', - primaryColor: '${theme.colors.primary.default}' + primaryColor: '${theme.colors.primary.default}', + currentPriceColor: '${features.currentPriceLineColorOverride ?? ''}' }, features: { enableDrawingTools: ${features.enableDrawingTools ? 'true' : 'false'}, diff --git a/app/components/UI/Charts/AdvancedChart/webview/chartLogic.js b/app/components/UI/Charts/AdvancedChart/webview/chartLogic.js index 1354556b4d9..412254fc00f 100644 --- a/app/components/UI/Charts/AdvancedChart/webview/chartLogic.js +++ b/app/components/UI/Charts/AdvancedChart/webview/chartLogic.js @@ -766,6 +766,7 @@ function handleSetThemeColors(payload) { var chart = window.chartWidget.activeChart(); var lineColor = theme.lineColor || theme.successColor; + var currentPriceColor = theme.currentPriceColor || lineColor; // Update volume study colors if present if (window.volumeStudyId) { @@ -796,7 +797,7 @@ function handleSetThemeColors(payload) { if (window.lastPriceShapeId) { try { chart.getShapeById(window.lastPriceShapeId).setProperties({ - linecolor: theme.successColor, + linecolor: theme.currentPriceColor || theme.successColor, }); } catch (e) {} } @@ -804,7 +805,7 @@ function handleSetThemeColors(payload) { if (window.lineLastPriceShapeId) { try { chart.getShapeById(window.lineLastPriceShapeId).setProperties({ - linecolor: lineColor, + linecolor: currentPriceColor, }); } catch (e) {} } @@ -2243,7 +2244,8 @@ function createLastPriceLine() { var lastBar = window.ohlcvData[window.ohlcvData.length - 1]; var chart = window.chartWidget.activeChart(); - var color = window.CONFIG.theme.successColor; + var color = + window.CONFIG.theme.currentPriceColor || window.CONFIG.theme.successColor; var candlePt = getLineEndDotTimeAndPriceFromSeries(chart); var candlePrice = candlePt && isFinite(candlePt.price) ? candlePt.price : lastBar.close; @@ -2329,7 +2331,9 @@ function createLineLastPriceLine() { var lastBar = window.ohlcvData[window.ohlcvData.length - 1]; var chart = window.chartWidget.activeChart(); const color = - window.CONFIG.theme.lineColor || window.CONFIG.theme.successColor; + window.CONFIG.theme.currentPriceColor || + window.CONFIG.theme.lineColor || + window.CONFIG.theme.successColor; var seriesPt = resolveLineEndOverlayPoint(chart); var linePrice = seriesPt && isFinite(seriesPt.price) ? seriesPt.price : lastBar.close; diff --git a/app/components/UI/Charts/AdvancedChart/webview/chartLogicString.ts b/app/components/UI/Charts/AdvancedChart/webview/chartLogicString.ts index 9572154e993..4421fca3ba2 100644 --- a/app/components/UI/Charts/AdvancedChart/webview/chartLogicString.ts +++ b/app/components/UI/Charts/AdvancedChart/webview/chartLogicString.ts @@ -775,6 +775,7 @@ function handleSetThemeColors(payload) { var chart = window.chartWidget.activeChart(); var lineColor = theme.lineColor || theme.successColor; + var currentPriceColor = theme.currentPriceColor || lineColor; // Update volume study colors if present if (window.volumeStudyId) { @@ -805,7 +806,7 @@ function handleSetThemeColors(payload) { if (window.lastPriceShapeId) { try { chart.getShapeById(window.lastPriceShapeId).setProperties({ - linecolor: theme.successColor, + linecolor: theme.currentPriceColor || theme.successColor, }); } catch (e) {} } @@ -813,7 +814,7 @@ function handleSetThemeColors(payload) { if (window.lineLastPriceShapeId) { try { chart.getShapeById(window.lineLastPriceShapeId).setProperties({ - linecolor: lineColor, + linecolor: currentPriceColor, }); } catch (e) {} } @@ -2252,7 +2253,8 @@ function createLastPriceLine() { var lastBar = window.ohlcvData[window.ohlcvData.length - 1]; var chart = window.chartWidget.activeChart(); - var color = window.CONFIG.theme.successColor; + var color = + window.CONFIG.theme.currentPriceColor || window.CONFIG.theme.successColor; var candlePt = getLineEndDotTimeAndPriceFromSeries(chart); var candlePrice = candlePt && isFinite(candlePt.price) ? candlePt.price : lastBar.close; @@ -2338,7 +2340,9 @@ function createLineLastPriceLine() { var lastBar = window.ohlcvData[window.ohlcvData.length - 1]; var chart = window.chartWidget.activeChart(); const color = - window.CONFIG.theme.lineColor || window.CONFIG.theme.successColor; + window.CONFIG.theme.currentPriceColor || + window.CONFIG.theme.lineColor || + window.CONFIG.theme.successColor; var seriesPt = resolveLineEndOverlayPoint(chart); var linePrice = seriesPt && isFinite(seriesPt.price) ? seriesPt.price : lastBar.close; From dc704c53dd193c1395c233cd8940109137b64f7f Mon Sep 17 00:00:00 2001 From: Shane T Date: Tue, 16 Jun 2026 18:27:25 +0100 Subject: [PATCH 23/23] feat: geo-block money account in unavailable regions (#31793) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** We aren’t permitted to render Money account UI elements when users are geo-blocked. This PR uses the new feature flag `moneyAccountGeoBlockedCountries` and hides - Money balance card on home, instead showing money hub (as it does when money account is disabled) - Money navbar button, instead restoring the activity buton - Wallet home Contentful banners are not shown ## **Changelog** CHANGELOG entry: geo-block money account in unavailable regions ## **Related issues** Fixes: https://consensyssoftware.atlassian.net/browse/MUSD-828 ## **Manual testing steps** Feature: Money geo-blocking ``` Background: Given the Money account feature flag is enabled Scenario: User in a blocked country sees no Money UI Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"] And the detected geolocation is "GB" When the user opens the app Then the Money balance card is not rendered on the wallet home screen And the bottom nav shows the Activity tab instead of the Money tab And the Activity clock icon is not rendered in the wallet header And the growth banners are not rendered on the wallet home screen Scenario: User in an unblocked country sees all Money UI Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"] And the detected geolocation is "US" When the user opens the app Then the Money balance card is visible on the wallet home screen And the bottom nav shows the Money tab And the Activity clock icon is visible in the wallet header And the growth banners are visible on the wallet home screen Scenario: Growth banners are visible when Money is disabled entirely Given the Money account feature flag is disabled And the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"] And the detected geolocation is "GB" When the user opens the app Then the growth banners are visible on the wallet home screen Scenario: Empty blocked regions list allows all users through Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions [] And the detected geolocation is "GB" When the user opens the app Then the Money balance card is visible on the wallet home screen And the bottom nav shows the Money tab Scenario: Country-region code is matched by country prefix Given the "moneyAccountGeoBlockedCountries" flag has blockedRegions ["GB"] And the detected geolocation is "GB-ENG" When the user opens the app Then the Money balance card is not rendered on the wallet home screen And the bottom nav shows the Activity tab instead of the Money tab Scenario: Default blocklist applies when no remote flag is configured Given the "moneyAccountGeoBlockedCountries" remote flag is not set And the MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES env var is not set And the detected geolocation is "GB" When the user opens the app Then the Money balance card is not rendered on the wallet home screen And the bottom nav shows the Activity tab instead of the Money tab Scenario: Env var blocklist is used when remote flag is absent Given the "moneyAccountGeoBlockedCountries" remote flag is not set And the MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES env var is set to "US" And the detected geolocation is "US" When the user opens the app Then the Money balance card is not rendered on the wallet home screen And the detected geolocation is "GB" When the user opens the app Then the Money balance card is visible on the wallet home screen ``` ## **Screenshots/Recordings** ### **Before** Simulator Screenshot - iPhone 16e -
2026-06-16 at 14 04 01 ### **After** Simulator Screenshot - iPhone 16e -
2026-06-16 at 14 00 13 ## **Pre-merge author checklist** - [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) - [X] I've tested on Android - Ideally on a mid-range device; emulator is acceptable - [X] 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 - [X] 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** - [ ] 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. --- .js.env.example | 4 + app/components/Nav/Main/MainNavigator.js | 10 +- .../Nav/Main/MainNavigator.test.tsx | 6 + .../Earn/selectors/featureFlags/index.test.ts | 57 ------- .../UI/Earn/selectors/featureFlags/index.ts | 18 +- .../UI/Money/selectors/eligibility.test.ts | 155 ++++++++++++++++++ .../UI/Money/selectors/eligibility.ts | 26 +++ .../UI/Money/selectors/featureFlags.test.ts | 71 ++++++++ .../UI/Money/selectors/featureFlags.ts | 44 +++++ app/components/Views/Wallet/index.test.tsx | 5 + app/components/Views/Wallet/index.tsx | 20 ++- app/util/remoteFeatureFlag/index.test.ts | 47 ++++++ app/util/remoteFeatureFlag/index.ts | 18 ++ tests/feature-flags/feature-flag-registry.ts | 10 ++ 14 files changed, 410 insertions(+), 81 deletions(-) create mode 100644 app/components/UI/Money/selectors/eligibility.test.ts create mode 100644 app/components/UI/Money/selectors/eligibility.ts diff --git a/.js.env.example b/.js.env.example index a6a3c96bef1..e0e4990f340 100644 --- a/.js.env.example +++ b/.js.env.example @@ -137,6 +137,10 @@ export MM_MUSD_CONVERSION_REWARDS_UI_ENABLED="false" # Geo-blocked countries for mUSD conversion (comma-separated ISO 3166-1 alpha-2 codes) # LaunchDarkly takes precedence; this is a fallback. Default blocks UK. export MM_MUSD_CONVERSION_GEO_BLOCKED_COUNTRIES="GB" + +# Geo-blocked countries for Money Account +export MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES="GB" + export MM_MUSD_CONVERSION_MIN_ASSET_BALANCE_REQUIRED="0.01" # Money Hub diff --git a/app/components/Nav/Main/MainNavigator.js b/app/components/Nav/Main/MainNavigator.js index 46bc288e37a..29ad825fdb8 100644 --- a/app/components/Nav/Main/MainNavigator.js +++ b/app/components/Nav/Main/MainNavigator.js @@ -128,6 +128,7 @@ import { import MoneyOnboardingView from '../../UI/Money/Views/MoneyOnboardingView'; import MoneyPotentialEarningsView from '../../UI/Money/Views/MoneyPotentialEarningsView'; import { selectMoneyEnableMoneyAccountFlag } from '../../UI/Money/selectors/featureFlags'; +import { selectIsMoneyAccountGeoEligible } from '../../UI/Money/selectors/eligibility'; import { BridgeTransactionDetails } from '../../UI/Bridge/components/TransactionDetails/TransactionDetails'; import { BridgeModalStack, BridgeScreenStack } from '../../UI/Bridge/routes'; import { @@ -607,6 +608,11 @@ const HomeTabs = () => { const [isKeyboardHidden, setIsKeyboardHidden] = useState(true); const isMoneyAccountEnabled = useSelector(selectMoneyEnableMoneyAccountFlag); + const isMoneyAccountGeoEligible = useSelector( + selectIsMoneyAccountGeoEligible, + ); + const isMoneyAccountVisible = + isMoneyAccountEnabled && isMoneyAccountGeoEligible; const trackMoneyTabPressRef = useRef(null); @@ -850,8 +856,8 @@ const HomeTabs = () => { component={WalletTabStackFlow} /> - {/* Activity Tab (replaced by Money when feature flag is on) */} - {isMoneyAccountEnabled ? ( + {/* Activity Tab (replaced by Money when feature flag is on and user is geo-eligible) */} + {isMoneyAccountVisible ? ( ({ mockSelectMoneyEnableMoneyAccountFlag(state), })); +const mockSelectIsMoneyAccountGeoEligible = jest.fn().mockReturnValue(true); +jest.mock('../../UI/Money/selectors/eligibility', () => ({ + selectIsMoneyAccountGeoEligible: (state: unknown) => + mockSelectIsMoneyAccountGeoEligible(state), +})); + describe('MainNavigator', () => { const originalEnv = process.env.METAMASK_ENVIRONMENT; diff --git a/app/components/UI/Earn/selectors/featureFlags/index.test.ts b/app/components/UI/Earn/selectors/featureFlags/index.test.ts index b399cec9b4c..c32a759d890 100644 --- a/app/components/UI/Earn/selectors/featureFlags/index.test.ts +++ b/app/components/UI/Earn/selectors/featureFlags/index.test.ts @@ -12,7 +12,6 @@ import { selectMusdConversionPaymentTokensBlocklist, selectIsMusdConversionRewardsUiEnabledFlag, selectMusdConversionBlockedCountries, - parseBlockedCountriesEnv, selectMusdConversionMinAssetBalanceRequired, selectMusdTokenRegistrationChainIds, MUSD_TOKEN_REGISTRATION_CHAIN_IDS_FALLBACK, @@ -1770,62 +1769,6 @@ describe('Earn Feature Flag Selectors', () => { }); }); - describe('parseBlockedCountriesEnv', () => { - it('returns empty array for undefined input', () => { - const result = parseBlockedCountriesEnv(undefined); - - expect(result).toEqual([]); - }); - - it('returns empty array for empty string', () => { - const result = parseBlockedCountriesEnv(''); - - expect(result).toEqual([]); - }); - - it('returns empty array for whitespace-only string', () => { - const result = parseBlockedCountriesEnv(' '); - - expect(result).toEqual([]); - }); - - it('parses single country code', () => { - const result = parseBlockedCountriesEnv('GB'); - - expect(result).toEqual(['GB']); - }); - - it('parses comma-separated country codes', () => { - const result = parseBlockedCountriesEnv('GB,US,FR'); - - expect(result).toEqual(['GB', 'US', 'FR']); - }); - - it('trims whitespace around country codes', () => { - const result = parseBlockedCountriesEnv('GB , US , FR'); - - expect(result).toEqual(['GB', 'US', 'FR']); - }); - - it('converts country codes to uppercase', () => { - const result = parseBlockedCountriesEnv('gb,us,fr'); - - expect(result).toEqual(['GB', 'US', 'FR']); - }); - - it('filters out empty entries', () => { - const result = parseBlockedCountriesEnv('GB,,US,'); - - expect(result).toEqual(['GB', 'US']); - }); - - it('handles mixed case and whitespace', () => { - const result = parseBlockedCountriesEnv(' gb , Us, FR '); - - expect(result).toEqual(['GB', 'US', 'FR']); - }); - }); - describe('selectMusdConversionBlockedCountries', () => { it('returns blocked countries array when remote flag is valid', () => { const blockedRegions = ['GB', 'US']; diff --git a/app/components/UI/Earn/selectors/featureFlags/index.ts b/app/components/UI/Earn/selectors/featureFlags/index.ts index 8b92250bb42..3a44a4a786b 100644 --- a/app/components/UI/Earn/selectors/featureFlags/index.ts +++ b/app/components/UI/Earn/selectors/featureFlags/index.ts @@ -2,6 +2,7 @@ import { createSelector } from 'reselect'; import { selectRemoteFeatureFlags } from '../../../../../selectors/featureFlagController'; import { validatedVersionGatedFeatureFlag, + parseBlockedCountriesEnv, VersionGatedFeatureFlag, } from '../../../../../util/remoteFeatureFlag'; import { @@ -244,23 +245,6 @@ export const selectIsMusdConversionRewardsUiEnabledFlag = createSelector( }, ); -/** - * Parses a comma-separated string of country codes into an array. - * Returns empty array if input is undefined/empty. - * - * @param envValue - Comma-separated country codes (e.g., "GB,US,FR") - * @returns Array of country codes - */ -export const parseBlockedCountriesEnv = (envValue?: string): string[] => { - if (!envValue || envValue.trim() === '') { - return []; - } - return envValue - .split(',') - .map((code) => code.trim().toUpperCase()) - .filter((code) => code.length > 0); -}; - /** * Selects the geo-blocked countries for mUSD conversion from remote config or local fallback. * Returns an array of ISO 3166-1 alpha-2 country codes (e.g., ['GB', 'US']). diff --git a/app/components/UI/Money/selectors/eligibility.test.ts b/app/components/UI/Money/selectors/eligibility.test.ts new file mode 100644 index 00000000000..3ce33c3fc33 --- /dev/null +++ b/app/components/UI/Money/selectors/eligibility.test.ts @@ -0,0 +1,155 @@ +import { selectIsMoneyAccountGeoEligible } from './eligibility'; +import type { RootState } from '../../../../reducers'; + +describe('selectIsMoneyAccountGeoEligible', () => { + const createStateWithGeolocation = ( + geolocation: string | null | undefined, + remoteFeatureFlags: Record = {}, + ) => + ({ + engine: { + backgroundState: { + RemoteFeatureFlagController: { + remoteFeatureFlags, + cacheTimestamp: 0, + }, + GeolocationController: { + location: geolocation, + }, + }, + }, + }) as unknown as RootState; + + const noBlockedCountriesFlags = { + moneyAccountGeoBlockedCountries: { blockedRegions: [] }, + }; + + const gbBlockedFlags = { + moneyAccountGeoBlockedCountries: { blockedRegions: ['GB'] }, + }; + + const gbUsBlockedFlags = { + moneyAccountGeoBlockedCountries: { blockedRegions: ['GB', 'US'] }, + }; + + it('returns false when geolocation is undefined (loading state)', () => { + const state = createStateWithGeolocation(undefined, gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns false when geolocation is null', () => { + const state = createStateWithGeolocation(null, gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns false when geolocation is UNKNOWN', () => { + const state = createStateWithGeolocation('UNKNOWN', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns false when user country is in the blocked list', () => { + const state = createStateWithGeolocation('GB', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns false when country-region code matches a blocked country', () => { + const state = createStateWithGeolocation('GB-ENG', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns false when user is in one of multiple blocked countries', () => { + const state = createStateWithGeolocation('US', gbUsBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns true when user country is not in the blocked list', () => { + const state = createStateWithGeolocation('US', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(true); + }); + + it('returns true when the blocked countries list is empty', () => { + const state = createStateWithGeolocation('GB', noBlockedCountriesFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(true); + }); + + it('comparison is case-insensitive for geolocation codes', () => { + const state = createStateWithGeolocation('gb', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('comparison is case-insensitive for blocked country codes', () => { + const lowercaseBlockedFlags = { + moneyAccountGeoBlockedCountries: { blockedRegions: ['gb'] }, + }; + const state = createStateWithGeolocation('GB', lowercaseBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + }); + + it('returns true when user country-region does not match any blocked country', () => { + const state = createStateWithGeolocation('US-CA', gbBlockedFlags); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(true); + }); + + it('defaults to blocking GB when no remote flag and no env var is set', () => { + const originalEnv = process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES; + delete process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES; + + const state = createStateWithGeolocation('GB', {}); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(false); + + if (originalEnv !== undefined) { + process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES = originalEnv; + } + }); + + it('returns true for non-blocked country when using default blocked list', () => { + const originalEnv = process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES; + delete process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES; + + const state = createStateWithGeolocation('US', {}); + + const result = selectIsMoneyAccountGeoEligible(state); + + expect(result).toBe(true); + + if (originalEnv !== undefined) { + process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES = originalEnv; + } + }); +}); diff --git a/app/components/UI/Money/selectors/eligibility.ts b/app/components/UI/Money/selectors/eligibility.ts new file mode 100644 index 00000000000..2a14aad31cb --- /dev/null +++ b/app/components/UI/Money/selectors/eligibility.ts @@ -0,0 +1,26 @@ +/** + * Determines whether the current user is geo-eligible for the Money account. + * + * Defaults to BLOCKING when geolocation is unknown to ensure regulatory + * compliance. Users in blocked regions cannot bypass restrictions by having + * geolocation fail to load. + */ + +import { createSelector } from 'reselect'; +import { selectMoneyAccountGeoBlockedCountries } from './featureFlags'; +import { getDetectedGeolocation } from '../../../../reducers/fiatOrders'; + +export const selectIsMoneyAccountGeoEligible = createSelector( + selectMoneyAccountGeoBlockedCountries, + getDetectedGeolocation, + (blockedCountries, geolocation): boolean => { + const userCountry = geolocation?.toUpperCase().split('-')[0] ?? null; + + if (!userCountry) return false; + if (blockedCountries.length === 0) return true; + + return blockedCountries.every( + (blocked) => !userCountry.startsWith(blocked.toUpperCase()), + ); + }, +); diff --git a/app/components/UI/Money/selectors/featureFlags.test.ts b/app/components/UI/Money/selectors/featureFlags.test.ts index b7b3452ccf8..ee5e18ec4e6 100644 --- a/app/components/UI/Money/selectors/featureFlags.test.ts +++ b/app/components/UI/Money/selectors/featureFlags.test.ts @@ -8,6 +8,8 @@ import { selectMoneyNoFeeTokens, selectMoneyDepositMinBalance, selectMoneyTokensSortMode, + selectMoneyAccountGeoBlockedCountries, + DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES, } from './featureFlags'; jest.mock('../../../../core/Engine', () => ({ @@ -413,3 +415,72 @@ describe('selectMoneyTokensSortMode', () => { expect(result).toBe('fiatBalanceDesc'); }); }); + +describe('selectMoneyAccountGeoBlockedCountries', () => { + const originalEnv = process.env; + + beforeEach(() => { + jest.clearAllMocks(); + process.env = { ...originalEnv }; + }); + + afterEach(() => { + process.env = originalEnv; + }); + + it('returns blockedRegions array from remote flag when valid', () => { + const state = createState({ + moneyAccountGeoBlockedCountries: { blockedRegions: ['GB', 'US'] }, + }); + + const result = selectMoneyAccountGeoBlockedCountries(state as never); + + expect(result).toEqual(['GB', 'US']); + }); + + it('returns empty array when remote flag has empty blockedRegions', () => { + const state = createState({ + moneyAccountGeoBlockedCountries: { blockedRegions: [] }, + }); + + const result = selectMoneyAccountGeoBlockedCountries(state as never); + + expect(result).toEqual([]); + }); + + it('falls back to env var when remote flag is absent', () => { + process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES = 'US,FR'; + + const state = createState({}); + + const result = selectMoneyAccountGeoBlockedCountries(state as never); + + expect(result).toEqual(['US', 'FR']); + }); + + it('falls back to default blocked countries when both remote and env are absent', () => { + delete process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES; + + const state = createState({}); + + const result = selectMoneyAccountGeoBlockedCountries(state as never); + + expect(result).toEqual(DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES); + }); + + it('ignores remote flag when blockedRegions is not an array', () => { + process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES = 'IE'; + + const state = createState({ + moneyAccountGeoBlockedCountries: { blockedRegions: 'not-an-array' }, + }); + + const result = selectMoneyAccountGeoBlockedCountries(state as never); + + expect(result).toEqual(['IE']); + }); + + it('DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES includes GB', () => { + expect(DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES).toContain('GB'); + }); +}); diff --git a/app/components/UI/Money/selectors/featureFlags.ts b/app/components/UI/Money/selectors/featureFlags.ts index 7a53c2b495a..200ba522b2c 100644 --- a/app/components/UI/Money/selectors/featureFlags.ts +++ b/app/components/UI/Money/selectors/featureFlags.ts @@ -2,6 +2,7 @@ import { createSelector } from 'reselect'; import { selectRemoteFeatureFlags } from '../../../../selectors/featureFlagController'; import { validatedVersionGatedFeatureFlag, + parseBlockedCountriesEnv, VersionGatedFeatureFlag, } from '../../../../util/remoteFeatureFlag'; import { isMoneyAccountEnabled } from '../../../../lib/Money/feature-flags'; @@ -153,3 +154,46 @@ export const selectMoneyTokensSortMode = createSelector( return 'fiatBalanceDesc'; }, ); + +/** Default blocked countries for Money account when no remote flag is configured. */ +export const DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES = ['GB']; + +/** + * Selects the geo-blocked countries for the Money account from remote config or local fallback. + * Returns an array of ISO 3166-1 alpha-2 country codes (e.g., ['GB', 'US']). + * + * The Ramps geolocation API returns country codes like "GB" or "US-CA" (country-region). + * Matching uses startsWith to handle both country-only and country-region formats. + * + * Remote flag takes precedence over local env var. + * + * Examples: + * - Remote: { "blockedRegions": ["GB"] } - Block users in Great Britain + * - Remote: { "blockedRegions": ["GB", "US"] } - Block users in GB and US + * - Local env: "GB,US,FR" - Block users in GB, US, and FR + * + * If both remote and local are unavailable or invalid, defaults to blocking Great Britain. + */ +export const selectMoneyAccountGeoBlockedCountries = createSelector( + selectRemoteFeatureFlags, + (remoteFeatureFlags): string[] => { + // Try remote flag first (takes precedence) + const remoteFlag = remoteFeatureFlags?.moneyAccountGeoBlockedCountries as + | { blockedRegions?: string[] } + | undefined; + + if (Array.isArray(remoteFlag?.blockedRegions)) { + return remoteFlag.blockedRegions; + } + + // Fallback to local env var + const envBlockedCountries = parseBlockedCountriesEnv( + process.env.MM_MONEY_ACCOUNT_GEO_BLOCKED_COUNTRIES, + ); + + // If env var is also empty, use default blocked countries + return envBlockedCountries.length > 0 + ? envBlockedCountries + : DEFAULT_MONEY_ACCOUNT_BLOCKED_COUNTRIES; + }, +); diff --git a/app/components/Views/Wallet/index.test.tsx b/app/components/Views/Wallet/index.test.tsx index 61eb0c3b8e6..569940b275a 100644 --- a/app/components/Views/Wallet/index.test.tsx +++ b/app/components/Views/Wallet/index.test.tsx @@ -86,6 +86,11 @@ jest.mock('../../UI/Money/selectors/featureFlags', () => ({ selectMoneyEnableMoneyAccountFlag: jest.fn(() => mockMoneyAccountEnabled), })); +const mockMoneyAccountGeoEligible = true; +jest.mock('../../UI/Money/selectors/eligibility', () => ({ + selectIsMoneyAccountGeoEligible: jest.fn(() => mockMoneyAccountGeoEligible), +})); + // Mock MoneyBalanceCard so the integration test does not depend on its hooks/contexts. jest.mock('../../UI/Money/components/MoneyBalanceCard', () => { const ReactMock = jest.requireActual('react'); diff --git a/app/components/Views/Wallet/index.tsx b/app/components/Views/Wallet/index.tsx index 7869a39bd4d..0a0a10b97ea 100644 --- a/app/components/Views/Wallet/index.tsx +++ b/app/components/Views/Wallet/index.tsx @@ -57,6 +57,7 @@ import PickerAccount from '../../../component-library/components/Pickers/PickerA import AddressCopy from '../../UI/AddressCopy'; import CardButton from '../../UI/Card/components/CardButton'; import { selectMoneyEnableMoneyAccountFlag } from '../../UI/Money/selectors/featureFlags'; +import { selectIsMoneyAccountGeoEligible } from '../../UI/Money/selectors/eligibility'; import MoneyBalanceCard from '../../UI/Money/components/MoneyBalanceCard'; // eslint-disable-next-line import-x/no-restricted-paths -- TODO(ADR-0020): route-isolation backlog import { createAccountSelectorNavDetails } from '../AccountSelector'; @@ -410,6 +411,11 @@ const Wallet = ({ const selectedInternalAccount = useSelector(selectSelectedInternalAccount); const isMoneyAccountEnabled = useSelector(selectMoneyEnableMoneyAccountFlag); + const isMoneyAccountGeoEligible = useSelector( + selectIsMoneyAccountGeoEligible, + ); + const isMoneyAccountVisible = + isMoneyAccountEnabled && isMoneyAccountGeoEligible; /** * Provider configuration for the current selected network @@ -1038,8 +1044,10 @@ const Wallet = ({ {bannerContent} {walletHomeMainAssetDetailsActions} - {homeGrowthBannerContent} - {isMoneyAccountEnabled && } + {/* Hide growth banners when money account is enabled but user is geo-blocked */} + {(!isMoneyAccountEnabled || isMoneyAccountGeoEligible) && + homeGrowthBannerContent} + {isMoneyAccountVisible && } ); @@ -1050,8 +1058,10 @@ const Wallet = ({ {walletHomeMainAssetDetailsActions} - {homeGrowthBannerContent} - {isMoneyAccountEnabled && } + {/* Hide growth banners when money account is enabled but user is geo-blocked */} + {(!isMoneyAccountEnabled || isMoneyAccountGeoEligible) && + homeGrowthBannerContent} + {isMoneyAccountVisible && } ); @@ -1103,7 +1113,7 @@ const Wallet = ({ style={styles.headerActionButtonsContainer} accessible={false} > - {isMoneyAccountEnabled && ( + {isMoneyAccountVisible && ( { + it('returns empty array for undefined input', () => { + expect(parseBlockedCountriesEnv(undefined)).toEqual([]); + }); + + it('returns empty array for empty string', () => { + expect(parseBlockedCountriesEnv('')).toEqual([]); + }); + + it('returns empty array for whitespace-only string', () => { + expect(parseBlockedCountriesEnv(' ')).toEqual([]); + }); + + it('parses single country code', () => { + expect(parseBlockedCountriesEnv('GB')).toEqual(['GB']); + }); + + it('parses comma-separated country codes', () => { + expect(parseBlockedCountriesEnv('GB,US,FR')).toEqual(['GB', 'US', 'FR']); + }); + + it('trims whitespace around country codes', () => { + expect(parseBlockedCountriesEnv('GB , US , FR')).toEqual([ + 'GB', + 'US', + 'FR', + ]); + }); + + it('converts country codes to uppercase', () => { + expect(parseBlockedCountriesEnv('gb,us,fr')).toEqual(['GB', 'US', 'FR']); + }); + + it('filters out empty entries', () => { + expect(parseBlockedCountriesEnv('GB,,US,')).toEqual(['GB', 'US']); + }); + + it('handles mixed case and whitespace', () => { + expect(parseBlockedCountriesEnv(' gb , Us, FR ')).toEqual([ + 'GB', + 'US', + 'FR', + ]); + }); +}); + describe('isVersionGatedFeatureFlag', () => { it('returns true for valid VersionGatedFeatureFlag', () => { const validFlag = { diff --git a/app/util/remoteFeatureFlag/index.ts b/app/util/remoteFeatureFlag/index.ts index 91857303fd1..1d072f2a00a 100644 --- a/app/util/remoteFeatureFlag/index.ts +++ b/app/util/remoteFeatureFlag/index.ts @@ -65,6 +65,24 @@ const unwrapVersionGatedFeatureFlag = ( return undefined; }; +/** + * Parses a comma-separated string of country codes into an array. + * Used by feature flag selectors to read geo-block lists from env vars. + * Returns empty array if input is undefined/empty. + * + * @param envValue - Comma-separated country codes (e.g., "GB,US,FR") + * @returns Array of uppercased country codes with whitespace stripped + */ +export const parseBlockedCountriesEnv = (envValue?: string): string[] => { + if (!envValue || envValue.trim() === '') { + return []; + } + return envValue + .split(',') + .map((code) => code.trim().toUpperCase()) + .filter((code) => code.length > 0); +}; + export const validatedVersionGatedFeatureFlag = (remoteFlag: unknown) => { // If remote flag is overridden, return undefined to trigger caller fallback if (isRemoteFeatureFlagOverrideActivated) { diff --git a/tests/feature-flags/feature-flag-registry.ts b/tests/feature-flags/feature-flag-registry.ts index 9d1a643e0c4..97ad7897b04 100644 --- a/tests/feature-flags/feature-flag-registry.ts +++ b/tests/feature-flags/feature-flag-registry.ts @@ -3480,6 +3480,16 @@ export const FEATURE_FLAG_REGISTRY: Record = { status: FeatureFlagStatus.Active, }, + moneyAccountGeoBlockedCountries: { + name: 'moneyAccountGeoBlockedCountries', + type: FeatureFlagType.Remote, + inProd: true, + productionDefault: { + blockedRegions: ['GB'], + }, + status: FeatureFlagStatus.Active, + }, + moneyAccountVaultConfig: { name: 'moneyAccountVaultConfig', type: FeatureFlagType.Remote,

K}&AR#JcUvlWl6kSKrJc>T0sGuK-Yf8~T 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