Conversation
Reads the policy ID from EXPO_PUBLIC_PIMLICO_SPONSORSHIP_POLICY_ID and passes it as paymasterContext on the smart account client, so Pimlico applies it in pm_sponsorUserOperation. Unset means no policy is sent. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ship-policy feat: attach a Pimlico sponsorship policy to every userop
…o v2 The Fuse v2 module was redeployed on 2026-09-24 (0xE2d4…7b2B → 0xa98f…A999), but a shipped build kept the old address and moved Safes onto the retired core. The backend reads only the new module, so those cards decline every payment with SAFE_NOT_REGISTERED, while the old lens still tells the app they are set up. Once a build has the new address, those Safes show the enable-spending banner. The set-up and mode-switch batches now also disable any retired v2 core still on the Safe. Disables are computed against the module list as each earlier call leaves it, so v1 and the retired core can come off in one batch without GS103. Retired cores are listed in EXPO_PUBLIC_RETIRED_CASH_MODULE_V2_ADDRESSES, which defaults to 0xE2d4… and never includes the live core. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ule-v2 fix(card-spend): disable the retired v2 module when moving a Safe onto v2
65138da made card set-up read the Safe's module list on every v2 set-up, to disable any retired v2 core. A new cardholder's Safe is often still counterfactual on Fuse — the set-up batch is what deploys it — so `getModulesPaginated` returns `0x`, viem throws, and activation fails with "Card not activated" before anything is signed. A Safe with no code has no modules, so there is nothing to disable: return an empty cleanup and let the batch deploy and register the Safe as before. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…module-read fix(card-spend): skip the module read on a Safe not yet deployed on Fuse
… exists buildCardSteps fell back to the bridge.xyz "cards" endorsement for every non-Rain issuer, even when /cards/status already reported a kycStatus. For an old Bridge customer applying for a Wirex card, an approved Bridge endorsement marked the KYC step complete and offered "Activate card" before they had verified with Sumsub. The endorsement now only applies to Bridge-only users, who have no card customer and so no kycStatus. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PmSmmwX1kxkmMBEP7pVKPG
fix(card): ignore the retired Bridge endorsement once a card customer exists
…quota Production has been getting 429s with "Your payg app has exceeded its limit of 10000 token_price requests per 1 hours" (Sentry SOLID-PJ, SOLID-DV). That quota counts requests, and one request can carry 25 tokens, but every price was its own request and nothing was reused: - useBalances refreshed every 5s, and each refresh sent five by-symbol GETs (ETH once per chain, FUSE, BNB) plus one per token still unpriced. That is about 3,600 requests an hour for a single open app, so two or three users used up the whole app's quota. - fusePriceUsd / ethPriceUsd polled every 5s on top of that. Changes: - lib/batchedLoader merges lookups started in the same tick into requests of up to 25. It caches prices for a minute (misses for five), keeps serving the last price while a refresh fails, and pauses both Prices endpoints after a 429. - fetchTokenPriceUsd and the new fetchTokenPricesBySymbol go through it. By-address requests stay within the documented limits of 25 addresses and 3 networks. - Balance fallback poll goes from 5s to 30s (SSE already invalidates on every balance event), native price refresh from 5s to 60s, and vault balance poll from 3s to 30s. - publicClient keeps one client per chain with Multicall3 batching, so reads made together share one eth_call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMuZxhszcH7Kc5s7dc2NNq
Remove the iOS-only gates so Swap is available on every platform: the SwapModal trigger and SwapModalProvider no longer return null on iOS, the home Swap pill shows, and the Swaps fee row, Swap earning method and wallet tooltip copy are no longer hidden on iOS. Geo-restriction and disclaimer gates are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KtULm55FhtV8QpE98RAuqC
Enable Swap functionality on iOS
The vault balance card set its 26px value on a 24px line box and the
rewards summary set its 26px value on a 26px one; iOS clips glyphs that
overflow the line box, cutting the tops of the digits and the `$`.
Both values now get a 32px line, with the vault card's margins trimmed
so its layout height is unchanged.
The vault card also relied on Intl compact notation, which Hermes on iOS
ignores, so balances showed in full ("6,759.16 USD") and wrapped inside
the fixed-height card. The compact figure is now formatted by hand, the
value stays on one line and shrinks to fit on native, and the card uses
a min height so wrapped text on web is no longer cut off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013FB6mLN2hZfRTDENZCHKhw
…o Alchemy Prices now come from POST /accounts/v1/prices, which serves one cache shared by every user and every pod. So the app key's Alchemy token_price quota no longer scales with the number of open apps. The backend is only an optimisation for the app. On any failure it asks Alchemy directly with its own key, exactly as before, and skips the backend for five minutes. Failures include a network error, a timeout, an older backend without the route (404), an expired session (401), the per-user rate limit (429), a token the backend can't price right now (503), or a reply that isn't the expected shape. That keeps every combination safe: - an app build or OTA that ships before the backend route is deployed - a backend rollback - web and native (cookie or Bearer auth) Old builds keep calling Alchemy directly. Symbols and addresses the route's validation would reject are left out of the request, so one malformed token can't fail the lookup for the rest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMuZxhszcH7Kc5s7dc2NNq
Mona Sans has a 1.41em natural line (1.09em ascent, 0.32em descent). When a lineHeight is shorter, iOS keeps the full descent and trims the top of the first line, while Android trims both edges evenly, cutting the bottom of the last line; both then clip the glyphs to the view. Web does neither, which is why only the native apps showed it. The vault card's exact-USD line gets the same ~1.15em headroom as the balance figure (its `$` sat within a pixel of the edge), and the rewards card and its value row use min heights so larger system font sizes, common on Android, grow the card instead of clipping the text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013FB6mLN2hZfRTDENZCHKhw
…fixes-auys1s Fix vault balance formatting and layout on iOS
The backend's price route leaves out tokens on chains it has no Alchemy network for, and the app takes a token left out as having no price and remembers that for five minutes. A chain added to ALCHEMY_NETWORKS (which an OTA can do) before the backend knows it would lose its prices that way. Address lookups are now chunked by whether the backend covers the chain (BACKEND_PRICE_CHAIN_IDS, mirroring its ALCHEMY_PRICE_NETWORKS), and tokens on any other chain are priced from Alchemy directly, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMuZxhszcH7Kc5s7dc2NNq
… polls The slower polls were there to save the Prices API quota. Price lookups are now cached for a minute, in the app and by the backend's shared cache, so polling more often no longer costs token_price requests, and the slower intervals only made balance updates visibly lag. Balances poll every 5s again (staleTime 5s), native-token prices every 5s, and vault balances every 3s, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UMuZxhszcH7Kc5s7dc2NNq
…mit-emails-k9buga Batch and cache Alchemy price API requests to reduce quota usage
The deposit address screens quoted a flat 0.03% everywhere, so a rate an admin set for one route and chain on the Deposit fees page never reached the app. The notice now asks /deposit/fee-quote, which runs the same assessment the deposit workflows charge with and answers 0.03% for any route and chain with no rate of its own. The client's route table still decides which deposits can be charged at all, so an address that is never bridged is never asked about. While the quote loads the line is left off; if it cannot be fetched the notice falls back to 0.03% rather than to free. Rates move to parts per million, as the backend quotes them, so a fractional basis point prints exactly. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…dation A JS number cannot hold 18 decimals, so a soETH balance of 0.361164894291325699 became 0.3611648942913257. Max filled that in, it passed the balance check, and the withdrawal reverted for asking more than the Safe holds. The soFUSE and soETH balance hooks now return wei, and the form validates and fills max in wei. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ce images Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…m-backend feat(deposit): quote the deposit fee the backend charges for each route
The recovery screen opened on an empty email field. The user this came from reached it twice on a phone, sat on that field both times, and left without typing anything — then told support the recovery interface would not open. Their own screen recording shows it opening fine. Prefill it from the account this device last knew about. Logging out and a session expiring both leave that row behind — only "Forget all users" clears it — so on the device someone is locked out of, it is almost always the account they are reaching for. The field now takes a username as well, for the roughly one account in ten that carries no email and for anyone who cannot remember which inbox they used. Validation only holds an entry to the email rules once it contains an "@"; which account it names is the server's call. The OTP step then says where the code actually went, from the masked hint the backend returns, because a username recovery never learns the address — and for the same reason it no longer sends one back on verify. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HRh59soi7iX4J3UwxVVGRS
…w-7gma44 feat(recovery): prefill the identifier, and accept a username
"Deposit with cash" only expanded to MXN: the screen kept its own allowlist of codes, left over from when each row fetched its payment methods from TransFi. Chips now come from the committed corridor list, so "Show more" lists every currency in localCurrencies.tsx after the featured four, and the chooser's "+N" counts them all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. |
Collaborator
Author
|
Superseded by #2607, which has the same change rebuilt on |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
"Show more" on Deposit with cash now lists all 16 local currencies instead of adding only MXN.
CARD_FUND_LOCAL_CURRENCIESin that list's order (AED, ARS, COP, GHS, IDR, KES, MXN, MYR, NGN, PEN, UGX, ZMW).DEPOSIT_CASH_CURRENCY_COUNTis derived from the full list, so the "+N" circle on the chooser's Cash row goes from +4 to +15.Why
DepositCashOptionskept its own allowlist (ADDITIONAL_LOCAL_CURRENCY_CODES = ['MXN']). It dates from when each row fetched its payment-method chips from TransFi, so every extra currency cost a request. Chips now come from the committedCARD_FUND_LOCAL_PAYMENT_METHODSmap, so that reason no longer applies, and the card-fund "Cash deposit" group already shows all 16. A new corridor added tolocalCurrencies.tsxnow shows up here too.For reviewers
useMemo.🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.