diff --git a/.beads/pr-context.jsonl b/.beads/pr-context.jsonl deleted file mode 100644 index 3ec91efe216..00000000000 --- a/.beads/pr-context.jsonl +++ /dev/null @@ -1,201 +0,0 @@ -{"id":"shapeshiftWeb-05d","title":"add integration tests for sequence pass-through across wallets","description":"No sequence tests exist in the integration test suite. Add tests verifying that when sequence is provided in BTCSignTxInput, it is correctly passed through to the signing layer for each wallet adapter. Acceptance: integration tests cover sequence pass-through for Native, Ledger, Trezor, KeepKey (existing), GridPlus, Phantom, Vultisig, and MetaMask.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:15.312915+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:50:13.609858+01:00","closed_at":"2026-02-14T10:50:13.609858+01:00","close_reason":"Added integration test for sequence pass-through using p2pkh with RBF opt-in (0xfffffffe). Test verifies the serialized tx contains the custom sequence in native wallet.","dependencies":[{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-ixp","type":"blocks","created_at":"2026-02-14T10:37:24.110764+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-kjp","type":"blocks","created_at":"2026-02-14T10:37:24.19097+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-f74","type":"blocks","created_at":"2026-02-14T10:37:24.27095+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-tlf","type":"blocks","created_at":"2026-02-14T10:37:24.351418+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-las","type":"blocks","created_at":"2026-02-14T10:37:24.43059+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-05d","depends_on_id":"shapeshiftWeb-437","type":"blocks","created_at":"2026-02-14T10:37:24.51056+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-091","title":"p3: update PR #11875 — remove old selectors (re-verify after p3)","description":"After all p3 beads complete, re-verify that PR #11875 (bigamount-remove-old-selectors) still compiles cleanly. May need to checkout improvement-audit-2 version of common-selectors.ts and portfolioSlice/selectors.ts again if p3 changes affected them.\n\nThis is a verification/refresh step, not new work. Just ensure #11875 is still the correct final cleanup after all p3 changes land.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:47:20.7819+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:48.036755+01:00","closed_at":"2026-02-14T14:31:48.036755+01:00","close_reason":"Re-verified: PR #11875 type-checks clean on bigamount-remove-old-selectors after all p3 changes","dependencies":[{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-4tz","type":"blocks","created_at":"2026-02-14T13:47:26.323559+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-uot","type":"blocks","created_at":"2026-02-14T13:47:26.385572+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-zf0","type":"blocks","created_at":"2026-02-14T13:47:26.444942+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-e6j","type":"blocks","created_at":"2026-02-14T13:47:26.504352+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-c9o","type":"blocks","created_at":"2026-02-14T13:47:26.563842+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-zro","type":"blocks","created_at":"2026-02-14T13:47:26.623226+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-42d","type":"blocks","created_at":"2026-02-14T13:47:26.684816+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-091","depends_on_id":"shapeshiftWeb-841","type":"blocks","created_at":"2026-02-14T13:47:26.752457+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-09v","title":"Audit: obvious bugs in BigAmount migration (math errors, missing conversions)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:48.178056+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.80224+01:00","closed_at":"2026-02-13T11:31:46.80224+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-0bj","title":"WC dApps: Solana support (ShapeShift as wallet)","description":"Add Solana namespace support in WC-to-dApps flow. When ShapeShift acts as a wallet and an external Solana dApp connects via WC, handle Solana signing requests.\n\n## Scope\n- Add SolanaSigningMethod enum to types.ts (solana_signTransaction, solana_signAndSendTransaction, solana_signMessage, solana_signAllTransactions, solana_getAccounts)\n- Add Solana request/response types to types.ts\n- Create SolanaRequestHandlerUtil.ts following EIP155RequestHandlerUtil pattern\n- Handle solana_signTransaction: deserialize base64 tx, sign via hdwallet solanaSignTx, return signature\n- Handle solana_signAndSendTransaction: sign + broadcast via chain adapter\n- Handle solana_signMessage: sign arbitrary message\n- Add solana_getAccounts handler\n- Update useWalletConnectEventsHandler.ts to route Solana methods to appropriate modal\n- Add WalletConnectModal entries for Solana confirmation\n- Update createApprovalNamespaces.ts to handle solana namespace\n- Create SolanaSignConfirmation modal component\n- Unit tests for SolanaRequestHandlerUtil\n\n## RPC Method Details\n- solana_signTransaction: { transaction: base64 } -\u003e { signature: base58, transaction?: base64 }\n- solana_signAndSendTransaction: { transaction: base64, sendOptions? } -\u003e { signature: base58 }\n- solana_signMessage: { message: base58, pubkey: base58 } -\u003e { signature: base58 }\n- solana_signAllTransactions: { transactions: base64[] } -\u003e { transactions: base64[] }\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- External Solana dApp can connect to ShapeShift via WC and sign transactions\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:20:44.17257+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:46:51.565748+01:00","closed_at":"2026-02-17T15:46:51.565748+01:00","close_reason":"PR #11915 opened - solana wc dApps support","dependencies":[{"issue_id":"shapeshiftWeb-0bj","depends_on_id":"shapeshiftWeb-jil","type":"blocks","created_at":"2026-02-17T13:21:24.112267+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-0c4","title":"Phase 2: Dead code removal — LP fields, redundant selectors, dead method","description":"2.1: Remove dead underlyingToken0/1AmountCryptoBaseUnit from LpEarnOpportunityType and 3 selectors in lpSelectors.ts. 2.2: Remove 5 redundant selectors + genericBalanceByFilter utility. 2.3: Remove dead pricePerShare() method in investor-foxy api.ts.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:15:26.266716+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:22:49.3659+01:00","closed_at":"2026-02-13T12:22:49.3659+01:00","close_reason":"Dead LP fields removed from type + 3 selectors. 4 redundant selectors removed with consumer migrations. Dead pricePerShare() removed. genericBalanceByFilter removed.","dependencies":[{"issue_id":"shapeshiftWeb-0c4","depends_on_id":"shapeshiftWeb-6je","type":"blocks","created_at":"2026-02-13T12:15:37.595834+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-0c8","title":"update UtxoBaseAdapter tests for RBF sequence","description":"Update Bitcoin chain adapter test mocks and assertions to expect sequence: 0xfffffffe on inputs. Ensure non-Bitcoin UTXO chain tests still expect no sequence field. Acceptance: all existing tests pass with the new default sequence for Bitcoin.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:00:20.579348+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:08:09.927017+01:00","closed_at":"2026-02-14T11:08:09.927017+01:00","close_reason":"Updated buildSendTransaction and signTransaction test expectations with sequence: 0xfffffffe for Bitcoin inputs","dependencies":[{"issue_id":"shapeshiftWeb-0c8","depends_on_id":"shapeshiftWeb-bs7","type":"blocks","created_at":"2026-02-14T11:00:27.500698+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-0dl","title":"SolanaTransactionSimulation component","description":"Create src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SolanaTransactionSimulation.tsx. Display component mirroring TransactionSimulation.tsx but for Solana. Takes { transaction: string }. Uses useSimulateSolanaTransaction hook. Shows send changes (red, minus prefix) and receive changes (green, plus prefix) with Amount.Crypto. Shows token icon from Redux store asset. Loading skeleton while fetching. Returns null if no data and not loading. Uses VStack/HStack/Image from Chakra. No EVM TransactionSimulation imports.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T13:11:34.799281+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:16:38.244975+01:00","closed_at":"2026-02-18T13:16:38.244975+01:00","close_reason":"Created SolanaTransactionSimulation display component - mirrors EVM pattern with send/receive rows, loading skeletons, token icons","dependencies":[{"issue_id":"shapeshiftWeb-0dl","depends_on_id":"shapeshiftWeb-lkx","type":"blocks","created_at":"2026-02-18T13:12:20.162153+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-0f3","title":"Audit: cross-precision operations that may throw at runtime","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:44.04764+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.800768+01:00","closed_at":"2026-02-13T11:31:46.800768+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-0h8","title":"Spike: is store.ts the right place for BigAmount.configure?","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:15.316551+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.596754+01:00","closed_at":"2026-02-13T17:33:51.596754+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-0k4","title":"add yieldActionId to ActionGenericTransactionMetadata","description":"In src/state/slices/actionSlice/types.ts, add optional yieldActionId?: string to ActionGenericTransactionMetadata type. This stores the yield.xyz action ID so the subscriber can poll fetchAction(yieldActionId) for completion status. No migration needed since this is an optional field on existing actions.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:37.248555+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:53:49.593373+01:00","closed_at":"2026-02-14T10:53:49.593373+01:00","close_reason":"Added yieldActionId to ActionGenericTransactionMetadata"} -{"id":"shapeshiftWeb-0yk","title":"[Cosmos dApps] cosmos_signDirect shows modal but handler throws","description":"MEDIUM: cosmos_signDirect dispatches to SendCosmosTransactionConfirmation modal, user can click Confirm, but handler throws 'cosmos_signDirect is not yet supported'. Bad UX. Fix: Reject immediately in events handler like GET_CAPABILITIES, or show unsupported message. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_cosmos_wcv2_dapps","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:49:04.648574+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.694717+01:00","closed_at":"2026-02-18T16:58:33.694717+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-1d2g","title":"Tron dApps: tron_signMessage workaround produces invalid signatures","description":"tron_signMessage passes UTF-8 message as hex through tronSignTx which SHA256-hashes it. Standard Tron message signing uses keccak256 with TRON prefix. Signatures produced are cryptographically incorrect and dApps can't verify them. This needs a proper tronSignMessage in hdwallet-core. For now, consider removing tron_signMessage from DEFAULT_TRON_METHODS until properly implemented. File: src/plugins/walletConnectToDapps/utils/TronRequestHandlerUtil.ts lines 65-88","status":"open","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:58:07.415109+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:07.415109+01:00"} -{"id":"shapeshiftWeb-1gly","title":"PR1: Nav rename, routes, translations, empty page, SDK_RESEARCH.md","description":"Navigation changes, THORChain lending rename to DEPRECATED, Chainflip Lending route + empty page, translations, SDK_RESEARCH.md.\n\nNavigation + THORChain Rename:\n- src/Routes/helpers.ts: Add isDeprecated?: boolean to Route type\n- src/Routes/RoutesCommon.tsx: Rename THORChain lending label to navBar.thorchainLending + isDeprecated: true. Add Chainflip Lending route (/chainflip-lending/*, ChainflipLending flag).\n- src/components/Layout/Header/NavBar/MainNavLink.tsx: Render orange DEPRECATED Tag when isDeprecated\n- src/components/Layout/Header/NavBar/NavBar.tsx: Pass isDeprecated prop through\n- src/components/Layout/Header/NavBar/NavigationDropdown.tsx: Render DEPRECATED Badge in dropdown\n- src/components/Layout/Header/Header.tsx: Update earn submenu - add isDeprecated to lending, add Chainflip Lending item with isNew: true\n\nTranslations (src/assets/translations/en/main.json):\n- navBar.thorchainLending: \"THORChain Lending\"\n- navBar.chainflipLending: \"Chainflip Lending\"\n- common.deprecated: \"Deprecated\"\n- New chainflipLending namespace with keys for: overview, supply, borrow, pool, deposit, withdraw, position, signing states, error messages, stepper labels\n\nEmpty Page:\n- src/pages/ChainflipLending/ChainflipLendingPage.tsx: Minimal \u003cMain\u003e\u003cdiv\u003eTODO\u003c/div\u003e\u003c/Main\u003e, lazy-loaded from route\n\nSDK Research:\n- SDK_RESEARCH.md at repo root: empty living doc with title, purpose, empty sections for pain points, SDK candidates, DX feedback\n\nAcceptance:\n- Nav shows \"Chainflip Lending\" (with NEW badge) when flag enabled\n- Old lending shows \"THORChain Lending\" + orange DEPRECATED badge/tag\n- /chainflip-lending renders TODO div without crash\n- SDK_RESEARCH.md exists\n- yarn type-check + yarn lint --fix pass","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:51:51.710065+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.335576+01:00","closed_at":"2026-02-23T17:09:20.335576+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-1gly","depends_on_id":"shapeshiftWeb-b37j","type":"blocks","created_at":"2026-02-23T14:58:04.516664+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-1hy","title":"Register for Across Protocol integrator ID","description":"Fill out the Across integrator registration form to get our 2-byte hex integrator ID. This is a PRODUCTION BLOCKER — dev can proceed without it, but we can't ship without it.\n\nForm: https://docs.google.com/forms/d/e/1FAIpQLSe-HY6mzTeGZs91HxObkQmwkMQuH7oy8ngZ1ROiu-f4SR4oMw/viewform\n\nOnce received, the ID gets added as VITE_ACROSS_INTEGRATOR_ID env var.\n\nAcceptance criteria:\n- Form submitted\n- Integrator ID received (2-byte hex, e.g. '0xdead')\n- ID added to .env files","status":"tombstone","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:19:00.554976+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:21:22.091514+01:00","deleted_at":"2026-02-13T19:21:22.091514+01:00","deleted_by":"daemon","delete_reason":"delete","original_type":"task"} -{"id":"shapeshiftWeb-1qi","title":"Audit: edge cases (zero precision, undefined values, NaN propagation)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:51.891906+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.803658+01:00","closed_at":"2026-02-13T11:31:46.803658+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-1yk","title":"PR1: BigAmount API improvements + fox ecosystem consumer updates","description":"Foundation PR — already-proven consumers. ~29 files.\n\n**BigAmount API (11 files):**\n- packages/utils/src/bigAmount/bigAmount.ts (explicit ROUND_HALF_UP, NullableScalar, .toBN(), div(0) safety, JSDoc)\n- packages/utils/src/bigAmount/bigAmount.test.ts (217 tests, up from 116)\n- packages/utils/src/index.ts (BigAmountConfig export)\n- src/state/store.ts (BigAmount.configure wiring)\n- src/lib/math.ts (remove fromBaseUnit/toBaseUnit aliases)\n- src/lib/math.test.ts, src/lib/bignumber/bignumber.test.ts, src/lib/amount/BigAmount.test.ts\n- docs/bigamount.md, CLAUDE.md\n- yarn.lock\n\n**Fox ecosystem consumer updates (18 files already in PR #11831, further refined):**\n- RFOX: StakeInput, StakeConfirm, UnstakeInput, UnstakeConfirm, BridgeConfirm, TotalStaked, useCurrentApyQuery, useLifetimeRewardsQuery, RFOXSimulator\n- TCY: UnstakeInput, TcyClaimActionCard\n- ThorChainLP: Pool.tsx, RemoveLiquidityInput, usePool, useUserLpData\n\nThese consumers are already using BigAmount on develop from PR #11831 — this PR just updates them to use the improved API.","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:03.610595+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.296712+01:00","closed_at":"2026-02-14T13:25:59.296712+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)"} -{"id":"shapeshiftWeb-2f09","title":"Sanity check Ink + Scroll regen data","description":"Verify generatedAssetData.json has entries for both eip155:534352 (Scroll) and eip155:57073 (Ink). Verify relatedAssetIndex.json has inkAssetId in ETH related array. Verify no regressions. Run review-second-class-evm skill.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:51:24.013329+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T17:01:37.198079+01:00","closed_at":"2026-02-19T17:01:37.198079+01:00","close_reason":"Popular assets + market data verified working after cache clear. All ink fixes merged, PR #11960 opened.","dependencies":[{"issue_id":"shapeshiftWeb-2f09","depends_on_id":"shapeshiftWeb-cgtg","type":"blocks","created_at":"2026-02-19T13:51:48.716437+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-2fy","title":"Remove cosmosSdk resolver","description":"Remove src/state/slices/opportunitiesSlice/resolvers/cosmosSdk/ — all 3 resolvers gated by YieldXyz","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:45:31.264137+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:03:17.556966+01:00","closed_at":"2026-02-18T13:03:17.556966+01:00","close_reason":"Removed all dead cosmos SDK defi code, type-check and lint clean"} -{"id":"shapeshiftWeb-2lq","title":"Wire up SolanaRequestHandlerUtil to sign WC requests","description":"Rewrite approveSolanaRequest in src/plugins/walletConnectToDapps/utils/SolanaRequestHandlerUtil.ts. Use wallet.solanaSignRawTransaction for sign/signAndSend/signAll, wallet.solanaSignMessage for signMessage. Format responses per WC Solana spec: base58 signatures, base64 signed txs. Use chainAdapter.broadcastTransaction for signAndSend. Import formatJsonRpcResult, bs58, CONTRACT_INTERACTION.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:43:41.785041+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:59:20.086838+01:00","closed_at":"2026-02-18T12:59:20.086838+01:00","close_reason":"Rewrote approveSolanaRequest to use solanaSignRawTransaction/solanaSignMessage for all 4 WC methods. Uses bs58 for response encoding, chainAdapter.broadcastTransaction for signAndSend.","dependencies":[{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:53.928067+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-xc4","type":"blocks","created_at":"2026-02-18T12:45:04.330931+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-wcr","type":"blocks","created_at":"2026-02-18T12:45:14.785653+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-bzz","type":"blocks","created_at":"2026-02-18T12:45:25.041124+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-l5v","type":"blocks","created_at":"2026-02-18T12:45:35.375848+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-2lq","depends_on_id":"shapeshiftWeb-e4n","type":"blocks","created_at":"2026-02-18T12:45:45.733739+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-2o1","title":"PR1: minimize positional diff noise","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:15.128876+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.59365+01:00","closed_at":"2026-02-13T17:33:51.59365+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-373","title":"update affiliate bps constant from 55 to 60","description":"Update the app constant that sets affiliate basis points from 55 to 60, per shapeshift/web GitHub issue #11919. Simple constant change in the codebase.","status":"closed","priority":2,"issue_type":"task","assignee":"gomesalexandre","owner":"contact@0xgom.es","created_at":"2026-02-17T17:25:54.719203+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T17:30:04.632017+01:00","closed_at":"2026-02-17T17:30:04.632017+01:00","close_reason":"Raised DEFAULT_FEE_BPS and DEFAULT_AFFILIATE_BPS to 60, updated tests + mock API, pushed PR #11920"} -{"id":"shapeshiftWeb-3b3","title":"Replace unsafe as YieldType cast with type guard","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T18:27:59.318376+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T18:35:55.289182+01:00","closed_at":"2026-02-13T18:35:55.289182+01:00","close_reason":"Closed"} -{"id":"shapeshiftWeb-3lh","title":"refactor dispatchNotification + early Pending dispatch in yield flow","description":"In src/pages/Yields/hooks/useYieldTransactionFlow.ts: (A) Refactor dispatchNotification to accept options: { status?: ActionStatus, id?: string, yieldActionId?: string }. Default status=Complete, default id=uuidv4(). (B) In executeSingleTransaction, after submitHashMutation for the last tx: generate stable yieldActionUuid, dispatch Pending with yieldActionId=actionId BEFORE waitForActionCompletion. After waitForActionCompletion succeeds: call parseAndUpsertSecondClassChainTx, then update to Complete with same ID. (C) Same pattern for the \\!nextTx fallback path (~line 648). (D) Remove existing second-class portfolio refresh blocks (lines 616-627 and 652-663) — shared utility handles this now. Key: both Pending and Complete dispatches use same UUID so it's one action updated, not two created.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:44.342744+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:59:08.79233+01:00","closed_at":"2026-02-14T10:59:08.79233+01:00","close_reason":"Refactored dispatchNotification with options (status, id, yieldActionId). Added early Pending dispatch + parseAndUpsertSecondClassChainTx + Complete update in both isLastTransaction and !nextTx paths. Removed old inline second-class portfolio refresh blocks.","dependencies":[{"issue_id":"shapeshiftWeb-3lh","depends_on_id":"shapeshiftWeb-ed1","type":"blocks","created_at":"2026-02-14T10:40:04.618176+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-3lh","depends_on_id":"shapeshiftWeb-0k4","type":"blocks","created_at":"2026-02-14T10:40:04.705008+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-3y3","title":"Implement Across API service and quote fetching","description":"Implement the core API integration — fetching quotes from the Across Swap API.\n\nFiles to create:\n- packages/swapper/src/swappers/AcrossSwapper/utils/acrossService.ts\n- packages/swapper/src/swappers/AcrossSwapper/utils/fetchAcrossTrade.ts\n- packages/swapper/src/swappers/AcrossSwapper/utils/getTrade.ts\n\nacrossService.ts:\n- Axios instance pointing to VITE_ACROSS_API_URL\n- NO cache (Across explicitly prohibits caching /swap/approval responses)\n- Reasonable timeout (~10s like Relay)\n\nfetchAcrossTrade.ts:\n- GET /swap/approval with query params:\n tradeType: 'exactInput', amount, inputToken, outputToken, originChainId, destinationChainId,\n depositor, recipient (for cross-account), appFee (affiliateBps / 10000), appFeeRecipient (per-chain treasury),\n integratorId (from env), slippage ('auto' or user value)\n- For appFeeRecipient: use getTreasuryAddressFromChainId(buyAsset.chainId), gracefully skip if no treasury for chain (Monad/HyperEVM/Plasma)\n- Return typed AcrossSwapApprovalResponse\n\ngetTrade.ts (core logic, ~400 lines):\n- Map our internal types → Across API params → our TradeQuote type\n- Handle the ecosystem discriminator: swapTx.ecosystem 'evm' vs 'svm'\n- For EVM: extract calldata, gas, allowanceContract from checks.allowance.spender\n- For Solana (svm): base64 swapTx.data needs to be deserialized into TransactionInstructions\n to feed into existing solanaTransactionMetadata pattern (like Jupiter/Relay)\n Use VersionedTransaction.deserialize(Buffer.from(data, 'base64'))\n- Map Across fees → our protocol fees (bridge fees are protocol fees to user)\n- Map Across app fees → our affiliate fees\n- Map expectedFillTime → estimatedExecutionTimeMs\n- Handle errors: map Across error codes to TradeQuoteError enum\n- Cross-chain only (Across doesn't support same-chain swaps — confirmed via curl)\n- Use filterCrossChainEvmBuyAssetsBySellAssetId for route filtering + add Solana support\n\nAcceptance criteria:\n- Quotes return for EVM↔EVM cross-chain pairs\n- Quotes return for EVM→Solana and Solana→EVM\n- Affiliate fees correctly included for chains with treasury addresses\n- No affiliate fees for chains without treasury (no error, just omit appFee)\n- Errors mapped correctly to TradeQuoteError","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:19:50.898933+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:44:14.776616+01:00","closed_at":"2026-02-13T19:44:14.776616+01:00","close_reason":"Created acrossService.ts (no-cache axios instance), fetchAcrossTrade.ts (GET /swap/approval with URLSearchParams), and getTrade.ts (core quote/rate logic with chain validation, fee calculation, error mapping). Also added VITE_ACROSS_API_URL and VITE_ACROSS_INTEGRATOR_ID to SwapperConfig, acrossTransactionMetadata to TradeQuoteStep/SwapperSpecificMetadata. Type-check and lint clean.","dependencies":[{"issue_id":"shapeshiftWeb-3y3","depends_on_id":"shapeshiftWeb-kap","type":"blocks","created_at":"2026-02-13T19:20:22.32128+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-418","title":"Implement Across swapper endpoints (quote, rate, status)","description":"Wire up the SwapperApi endpoints and the Swapper execution layer.\n\nFiles to create:\n- packages/swapper/src/swappers/AcrossSwapper/endpoints.ts\n- packages/swapper/src/swappers/AcrossSwapper/getTradeQuote/getTradeQuote.ts\n- packages/swapper/src/swappers/AcrossSwapper/getTradeRate/getTradeRate.ts\n- packages/swapper/src/swappers/AcrossSwapper/AcrossSwapper.ts\n\ngetTradeQuote.ts / getTradeRate.ts:\n- Thin wrappers around getTrade.ts (same as Relay pattern)\n- Quote requires receiveAddress + sendAddress + accountNumber\n- Rate is lighter (uses dummy addresses for non-binding quotes)\n\nendpoints.ts — SwapperApi implementation:\n- getTradeQuote: calls getTradeQuote.ts\n- getTradeRate: calls getTradeRate.ts\n- checkTradeStatus: polls GET /deposit/status?depositTxnRef={txHash}\n - Map status values:\n 'filled' → { status: TxStatus.Confirmed, buyTxHash: fillTxnRef }\n 'pending' → { status: TxStatus.Pending, message: 'Deposit detected, processing...' }\n 'slowFillRequested' → { status: TxStatus.Pending, message: 'Taking longer than usual...' }\n 'expired' → { status: TxStatus.Failed, message: 'Deposit expired' }\n 'refunded' → { status: TxStatus.Failed, message: 'Deposit refunded on origin chain' }\n - For cross-chain: buyTxHash comes from fillTxnRef in status response\n - For EVM→Solana: user signs EVM tx, buyTxHash is on Solana (from fillTxnRef)\n\nAcrossSwapper.ts — Swapper execution:\n- executeEvmTransaction: sign the swapTx calldata (standard EVM pattern)\n- executeSolanaTransaction: for Solana→EVM, sign the deserialized Solana transaction\n Follow the shared executeSolanaTransaction pattern from utils.ts\n- getUnsignedEvmTransaction / getUnsignedSolanaTransaction: extract from quote metadata\n\nAcceptance criteria:\n- getTradeQuote returns valid quotes for supported cross-chain pairs\n- getTradeRate returns valid rates\n- checkTradeStatus correctly maps all 5 Across statuses\n- EVM execution works (sign returned calldata)\n- Solana execution works (sign deserialized base64 tx)\n- Swapper registered in packages/swapper/src/constants.ts with endpoints + swapper","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:20:07.415458+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:54:25.53603+01:00","closed_at":"2026-02-13T19:54:25.53603+01:00","close_reason":"Created endpoints.ts (SwapperApi with getTradeQuote, getTradeRate, EVM execution, checkTradeStatus with all 5 Across status mappings), AcrossSwapper.ts (EVM execution), getTradeQuote.ts and getTradeRate.ts (thin wrappers). Registered swapper in constants.ts. Fixed public-api config and useTradeButtonProps for new metadata fields. Type-check and lint clean across entire codebase.","dependencies":[{"issue_id":"shapeshiftWeb-418","depends_on_id":"shapeshiftWeb-3y3","type":"blocks","created_at":"2026-02-13T19:20:23.070648+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-42d","title":"p3: account/balance display + Amount component + tx history","description":"NEW PR — files that don't belong in any existing p2.x PR. Account selectors, balance display, Amount component BigAmount interop, tx history formatting.\n\nFiles (21):\n- src/components/AccountDropdown/AccountDropdown.tsx\n- src/components/AccountSelector/AccountSelector.tsx\n- src/components/AccountSelector/AccountSelectorDialog.tsx\n- src/components/AccountSelector/AccountSelectorOption.tsx\n- src/components/Amount/Amount.tsx (BigAmount.isBigAmount() interop)\n- src/components/AssetAccounts/AssetAccountRow.tsx\n- src/components/AssetHeader/AssetChart.tsx\n- src/components/AssetHeader/AssetHeader.tsx\n- src/components/AssetHeader/hooks/useQuickBuy.ts\n- src/components/ChainDropdown/ChainDropdown.tsx\n- src/components/Equity/Equity.tsx\n- src/components/Equity/EquityAccountRow.tsx\n- src/components/TransactionHistoryRows/TransactionDetails/Amount.tsx\n- src/components/TransactionHistoryRows/TransactionGenericRow.tsx\n- src/components/TransactionHistoryRows/TransactionTrade.tsx\n- src/components/TransactionHistoryRows/utils.ts\n- src/pages/Accounts/AccountToken/AccountBalance.tsx\n- src/pages/Accounts/components/AccountEntryRow.tsx\n- src/pages/TransactionHistory/DownloadButton.tsx\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, Amount component accepts BigAmount value prop, variable renames, rounding mode fixes.\n\nBranch: bigamount-account-display (new, from bigamount-core-selectors). New draft PR.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:56.804138+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:55:22.415392+01:00","closed_at":"2026-02-14T13:55:22.415392+01:00","close_reason":"Absorbed into p2.x beads — display/UI components go to p2.5 (send+misc), thorchain utils to p2.4, lib/math to p2.6"} -{"id":"shapeshiftWeb-437","title":"add sequence support to hdwallet-metamask-multichain snaps adapter","description":"MetaMask delegates BTC signing to Snaps adapter. Update the adapter to pass input.sequence through when defined. Acceptance: MetaMask Snaps btcSignTx includes sequence in input data.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:12.683959+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.810766+01:00","closed_at":"2026-02-14T10:47:35.810766+01:00","close_reason":"No code changes needed - BTCSignTx.inputs already carries sequence through to snap adapter via base type","dependencies":[{"issue_id":"shapeshiftWeb-437","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:22.639606+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-44p","title":"Audit: precision diff crash potential (assertSamePrecision)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:41.844208+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.799705+01:00","closed_at":"2026-02-13T11:31:46.799705+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-44r","title":"PR8: RFOX/TCY/ThorChainLP pages","description":"Medium-risk page migration. 25 files: RFOX (StakeInput, StakeConfirm, UnstakeInput, UnstakeConfirm, BridgeConfirm, TotalStaked, useCurrentApyQuery, useCurrentEpochRewardsQuery, useLifetimeRewardsQuery, RFOXSimulator), TCY (Overview, StakeInput, StakeConfirm, UnstakeInput, UnstakeConfirm, ClaimConfirm, ClaimStatus, AssetClaimButton, tcy.tsx), ThorChainLP (Pool.tsx, AddLiquidityInput, RemoveLiquidityInput, TransactionRow, usePool, useUserLpData). Note: some of these files were already touched by PR #11831 — this PR continues the migration with the updated core selectors from PR1.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:43.418767+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.302296+01:00","closed_at":"2026-02-14T13:25:59.302296+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-44r","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.702322+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-44r","depends_on_id":"shapeshiftWeb-8ys","type":"blocks","created_at":"2026-02-13T15:38:06.839653+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-46k","title":"Solana simulation utility","description":"Create src/plugins/walletConnectToDapps/utils/solana-simulation/index.ts. DIY simulation using native Solana RPC (Connection.simulateTransaction). Flow: 1) Deserialize base64 tx. 2) Get static account keys and fee payer. 3) Fetch pre-state via connection.getMultipleAccountsInfo(). 4) Simulate with replaceRecentBlockhash:true and accounts option (encoding base64). 5) Decode token accounts with @solana/spl-token AccountLayout for pre/post. 6) Diff to get balance changes for accounts owned by fee payer. 7) Resolve token metadata from Redux store (construct assetId from solanaChainId + spl:\u003cmint\u003e, look up selectAssetById). Pure function, no React. Graceful try/catch returning null on failure. No Tenderly imports.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T13:11:13.954029+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:15:24.969697+01:00","closed_at":"2026-02-18T13:15:24.969697+01:00","close_reason":"Created simulateSolanaTransaction utility - DIY simulation using Connection.simulateTransaction with pre/post balance diff for SOL and SPL tokens","dependencies":[{"issue_id":"shapeshiftWeb-46k","depends_on_id":"shapeshiftWeb-7br","type":"blocks","created_at":"2026-02-18T13:11:59.542799+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-4b2","title":"BigAmount: migrate RFOX/TCY/ThorChainLP consumers","description":"Migrate 8 RFOX/TCY/ThorChainLP files from old string selectors to new BigAmount selectors. Files: RFOX (StakeInput, StakeConfirm, BridgeConfirm, UnstakeInput), TCY (StakeInput, ClaimConfirm), ThorChainLP (AddLiquidityInput, RemoveLiquidityInput)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:02:57.911989+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.474123+01:00","closed_at":"2026-02-13T19:38:31.474123+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-4bq","title":"PR1: strip dead code (toUserCurrency, toUSD, toJSON, fromJSON, fromBN, min, max)","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:14.743985+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.591553+01:00","closed_at":"2026-02-13T17:33:51.591553+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-4cm","title":"WC Wallet: Cosmos support (connect wallet)","description":"Add Cosmos namespace support to the WalletConnect 'connect wallet' flow. When a user selects WC as a wallet option in ShapeShift and scans the QR with Keplr/Leap/Cosmostation mobile, ShapeShift should be able to propose a session with cosmos namespace and handle cosmos_getAccounts, cosmos_signDirect, cosmos_signAmino responses.\n\n## Research Steps (before coding)\n1. Read @walletconnect/universal-provider source/docs to understand init() and connect() API differences vs EthereumProvider\n2. Read packages/hdwallet-core/src/cosmos.ts for CosmosWallet interface (cosmosGetAddress, cosmosSignTx)\n3. Read packages/hdwallet-core/src/wallet.ts for supportsCosmos() guard function\n4. Check how hdwallet-native implements CosmosWallet for reference pattern\n5. Read the existing adapter.ts to understand EthereumProvider.init() flow that needs migration\n6. Check if @walletconnect/universal-provider is already in package.json or needs adding\n\n## Implementation Details\n\n### Phase 1: Universal Provider Migration (packages/hdwallet-walletconnectv2/)\n- adapter.ts: Replace `import { EthereumProvider } from '@walletconnect/ethereum-provider'` with `import UniversalProvider from '@walletconnect/universal-provider'`\n- adapter.ts: Change `EthereumProvider.init(config)` to `UniversalProvider.init({ projectId, metadata })` then `provider.connect({ optionalNamespaces })`\n- The UniversalProvider has a different API: init() creates the provider, connect() establishes the session with namespaces\n- walletconnectV2.ts: Change `provider: EthereumProvider` type to `provider: UniversalProvider`\n- walletconnectV2.ts: Add `readonly _supportsCosmos = true` and `readonly _supportsCosmosInfo = true`\n- walletconnectV2.ts: Implement CosmosWallet interface methods\n\n### Phase 2: Cosmos Wallet Methods (packages/hdwallet-walletconnectv2/)\n- Create new file `cosmos.ts` following the pattern of `ethereum.ts`\n- Implement `cosmosGetAddress()`: extract from session.namespaces.cosmos.accounts (CAIP-10 format cosmos:cosmoshub-4:\u003cbech32addr\u003e)\n- Implement `cosmosSignTx(msg: CosmosSignTx)`: convert to cosmos_signAmino params and call provider.request()\n- The provider.request() for cosmos needs the chainId param: `provider.request({ method: 'cosmos_signAmino', params: {...} }, 'cosmos:cosmoshub-4')`\n\n### Phase 3: Config Updates (src/context/WalletProvider/WalletConnectV2/)\n- config.ts: Add cosmos chain config alongside EVM chains\n- config.ts: Update EthereumProviderOptions type to match UniversalProvider's options\n- constants.ts: Check if types need updating for the new provider\n\n### Key Files to Modify\n- packages/hdwallet-walletconnectv2/src/adapter.ts (provider migration)\n- packages/hdwallet-walletconnectv2/src/walletconnectV2.ts (add Cosmos interface)\n- packages/hdwallet-walletconnectv2/src/cosmos.ts (NEW - cosmos methods)\n- packages/hdwallet-walletconnectv2/src/index.ts (export cosmos)\n- packages/hdwallet-walletconnectv2/package.json (add @walletconnect/universal-provider dep)\n- src/context/WalletProvider/WalletConnectV2/config.ts (cosmos chain config)\n\n### Cosmos RPC Methods\n- cosmos_getAccounts: {} -\u003e [{ algo, address, pubkey }]\n- cosmos_signAmino: { signerAddress, signDoc: { chain_id, account_number, sequence, memo, msgs, fee } } -\u003e { signature: { pub_key, signature }, signed }\n- cosmos_signDirect: { signerAddress, signDoc: { chainId, accountNumber, authInfoBytes, bodyBytes } } -\u003e { signature: { pub_key, signature }, signed }\n\n### Testing\n- Unit tests for cosmos.ts methods (cosmosGetAddress, cosmosSignTx)\n- Ensure existing ethereum tests still pass after provider migration\n- Mock UniversalProvider for test isolation\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- All existing WC tests still pass (no regression from provider migration)\n- User can scan QR with Keplr mobile and get cosmos address exposed in ShapeShift\n- cosmos_signAmino and cosmos_signDirect requests are properly proxied to the mobile wallet\n- PR targets origin/develop with proper description","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:20:10.872061+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T14:22:00.614718+01:00","closed_at":"2026-02-17T14:22:00.614718+01:00","close_reason":"Cosmos WCV2 wallet support implemented in PR #11909. Monkey-patches EthereumProvider signer to inject cosmos optionalNamespaces, implements CosmosWallet/CosmosWalletInfo interfaces, cosmosGetAddress via CAIP-10 session, cosmosSignTx via OfflineAminoSigner + cosmos_signAmino."} -{"id":"shapeshiftWeb-4ee","title":"toUserCurrency() and toUSD() use implicit rounding mode","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T14:23:15.906828+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T14:23:49.269911+01:00","closed_at":"2026-02-13T14:23:49.269911+01:00","close_reason":"Added explicit ROUND_HALF_UP to toUserCurrency() and toUSD()"} -{"id":"shapeshiftWeb-4h6","title":"BigAmount: migrate yields + lending consumers","description":"Migrate 6 yields/lending files from old string selectors to new BigAmount selectors. Files: pages/Yields/YieldForm.tsx, YieldsList.tsx, YieldAvailableToDeposit.tsx, YieldEnterModal.tsx, pages/Lending/BorrowInput.tsx, RepayInput.tsx","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:02:56.254745+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.473049+01:00","closed_at":"2026-02-13T19:38:31.473049+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-4k8","title":"Final: type-check, lint, amend commit, force push, update PR","description":"1. Run yarn type-check — fix any errors. 2. Run yarn lint --fix — fix any errors. 3. Run relevant tests if any. 4. Amend the existing commit 'feat: speed up stuck btc transactions via rbf'. 5. Force push to gomes-bot:feat_btc_rbf_p3_speed_up_ux. 6. Update PR #11885 body to reflect the cleaner implementation.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:49:55.938429+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T12:21:49.838992+01:00","closed_at":"2026-02-14T12:21:49.838992+01:00","close_reason":"Type-check, lint, and all improvements pass. Three ralph rounds completed.","dependencies":[{"issue_id":"shapeshiftWeb-4k8","depends_on_id":"shapeshiftWeb-84g","type":"blocks","created_at":"2026-02-14T11:50:01.179937+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-4k8","depends_on_id":"shapeshiftWeb-cav","type":"blocks","created_at":"2026-02-14T11:50:01.257504+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-4k8","depends_on_id":"shapeshiftWeb-dbh","type":"blocks","created_at":"2026-02-14T11:50:01.33472+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-4obb","title":"Surface ChainAdapterError translations in yield transaction toast","description":"Bug: When Ledger throws EthAppPleaseEnableContractData (blind signing disabled), the yield flow catch block at useYieldTransactionFlow.ts:754 swallows the ChainAdapterError and shows generic 'Transaction failed. Please try again.' toast. The ErrorHandler correctly wraps it with translation 'chainAdapters.errors.blindSigningRequired', but the yield catch ignores it.\n\nFix: In the catch block, check for ChainAdapterError (same pattern as useFormSend.tsx:60-87). If error is ChainAdapterError, use translate(error.metadata.translation, error.metadata.options) as toast description instead of the generic key.\n\nFiles:\n- src/pages/Yields/hooks/useYieldTransactionFlow.ts (catch block ~line 754)\n- Import ChainAdapterError from @shapeshiftoss/chain-adapters\n\nAcceptance: Toast shows specific error messages (blind signing, TRON data, GridPlus SafeCard, broadcast details) instead of generic 'Transaction failed'.","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-19T09:25:16.997558+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T09:43:59.090542+01:00","closed_at":"2026-02-19T09:43:59.090542+01:00","close_reason":"Added ChainAdapterError check in yield toast catch block to surface specific error translations"} -{"id":"shapeshiftWeb-4tz","title":"p3: complete p2.1 trade/swap — full improvement-audit-2 diff","description":"Update bigamount-trade-swap branch to include ALL changes from improvement-audit-2, not just selector renames.\n\nEXISTING files in PR that need deeper changes (5):\n- src/state/apis/swapper/helpers/validateTradeQuote.ts (+101 lines)\n- src/state/slices/common/tradeInputBase/createTradeInputBaseSelectors.ts (+28 lines)\n- src/components/MultiHopTrade/components/LimitOrder/components/AllowanceApproval.tsx (+26 lines)\n- src/components/MultiHopTrade/components/LimitOrder/components/LimitOrderCard.tsx (+64 lines)\n- src/components/MultiHopTrade/components/Earn/EarnInput.tsx (+29 lines)\n\nNEW files to add (30):\n- src/components/MultiHopTrade/components/LimitOrder/components/CancelLimitOrder.tsx\n- src/components/MultiHopTrade/components/LimitOrder/components/LimitOrderInput.tsx\n- src/components/MultiHopTrade/components/LimitOrder/hooks/useLimitOrders.tsx\n- src/components/MultiHopTrade/components/LimitOrder/LimitOrder.tsx\n- src/components/MultiHopTrade/components/LimitOrderV2/LimitOrderConfirm.tsx\n- src/components/MultiHopTrade/components/SharedConfirm/AssetSummaryStep.tsx\n- src/components/MultiHopTrade/components/SpotTradeSuccess/SpotTradeSuccess.tsx\n- src/components/MultiHopTrade/components/TradeAmountInput.tsx\n- src/components/MultiHopTrade/components/TradeConfirm/components/TradeConfirmSummary.tsx\n- src/components/MultiHopTrade/components/TradeConfirm/hooks/useTradeButtonProps.tsx\n- src/components/MultiHopTrade/components/TradeConfirm/TradeConfirm.tsx\n- src/components/MultiHopTrade/components/TradeConfirm/TradeConfirmFooter.tsx\n- src/components/MultiHopTrade/components/TradeInput/components/MaxSlippage.tsx\n- src/components/MultiHopTrade/components/TradeInput/TradeInput.tsx\n- src/components/MultiHopTrade/helpers.ts\n- src/components/MultiHopTrade/hooks/useGetTradeQuotes/getTradeQuoteOrRateInput.ts\n- src/components/MultiHopTrade/hooks/useGetTradeQuotes/useGetTradeQuotes.tsx\n- src/components/MultiHopTrade/hooks/useInputOutputDifference.ts\n- src/components/MultiHopTrade/MultiHopTrade.tsx\n- src/components/MultiHopTrade/StandaloneMultiHopTrade.tsx\n- src/hooks/useActualBuyAmountCryptoPrecision.ts\n- src/state/slices/limitOrderInputSlice/selectors.ts\n- src/state/slices/limitOrderSlice/helpers.ts\n- src/state/slices/limitOrderSlice/selectors.ts\n- src/state/slices/tradeEarnInputSlice/selectors.ts\n- src/state/slices/tradeInputSlice/selectors.ts\n- src/state/slices/tradeQuoteSlice/helpers.ts\n- src/state/slices/tradeQuoteSlice/selectors.ts\n- src/state/slices/tradeQuoteSlice/utils.test.ts\n- src/state/slices/tradeRampInputSlice/selectors.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, variable renames (CryptoHuman→CryptoPrecision), selectSellAssetBalanceCryptoBaseUnit rename propagation.\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11867.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:16.236159+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:11.868577+01:00","closed_at":"2026-02-14T14:31:11.868577+01:00","close_reason":"All 34 trade/swap files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-trade-swap (PR #11867)"} -{"id":"shapeshiftWeb-4uq9","title":"Checkout + merge-fix Ink PR #11904","description":"Checkout Ink PR, extract regen data before merge, merge origin/develop with -X theirs to resolve all conflicts in favor of develop. Result: branch has Ink code changes but develop's generated files.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:50:52.705351+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T13:53:13.843624+01:00","closed_at":"2026-02-19T13:53:13.843624+01:00","close_reason":"Merged origin/develop with -X theirs, all conflicts resolved"} -{"id":"shapeshiftWeb-4y4q","title":"Verify fixes, lint, type-check, and open draft PR","description":"After both fixes are implemented:\n\n1. Run yarn lint --fix and yarn type-check - must pass\n2. Review the diff manually to ensure changes look correct and minimal\n3. Create a draft PR using .github/PULL_REQUEST_TEMPLATE.md\n - Title: fix: ledger yield staking blind signing toast and transaction underpriced\n - Screenshots section: TODO\n - Testing: ETH staking on Lido works with Ledger, ETH staking on Lido still works with Native wallet\n\nAcceptance: Draft PR created, CI green (lint + types), changes are surgical.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T09:25:44.043689+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T09:49:44.859532+01:00","closed_at":"2026-02-19T09:49:44.859532+01:00","close_reason":"Lint and type-check pass, draft PR created: https://github.com/shapeshift/web/pull/11949","dependencies":[{"issue_id":"shapeshiftWeb-4y4q","depends_on_id":"shapeshiftWeb-4obb","type":"blocks","created_at":"2026-02-19T09:25:57.643778+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-4y4q","depends_on_id":"shapeshiftWeb-o4u1","type":"blocks","created_at":"2026-02-19T09:26:07.958615+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-5hd","title":"memoize BigAmount construction in hot-path components","description":"5 locations: FoxFarmingOverview.tsx:175-184 (2 unmemoized BigAmounts in component body), ThorchainSaversOverview.tsx:113-115 (unmemoized as hook param), FoxyManager Withdraw/Confirm.tsx:149,216,225 (3 in JSX), FoxyManager Deposit/Confirm.tsx:161,200,209 (3 in JSX). Wrap in useMemo or extract to const.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T13:04:06.124242+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:08:28.715472+01:00","closed_at":"2026-02-13T13:08:28.715472+01:00","close_reason":"Memoized 4 components: FoxFarmingOverview (2 BigAmounts → useMemo), ThorchainSaversOverview (hook param → useMemo), FoxyManager Withdraw/Confirm (3 JSX BigAmounts → 1 useMemo), FoxyManager Deposit/Confirm (3 JSX BigAmounts → 1 useMemo)."} -{"id":"shapeshiftWeb-5s8h","title":"PR4: Borrow tab and BorrowMarketRow","description":"Borrow tab on main lending page with borrow-focused stats, LTV dashboard, and markets table.\n\nBorrowTab.tsx:\n- Borrow-focused stat cards:\n - Loan-to-Value (LTV) gauge: 0-100% with threshold markers\n - Total Borrowed (fiat)\n - Borrow Power Used (%)\n - Collateral Balance (fiat)\n - Top-up Asset indicator\n- Markets table showing all pools with borrow-relevant columns\n\nBorrowMarketRow.tsx:\n- Table row: asset icon+name, supplied amount, borrowed amount, borrow rate, utilisation %, \"Borrow\" button\n- \"Borrow\" button routes to pool detail with ?modal=borrow\n\nLTV stats from loanAccounts query for connected account. Global stats from lendingPools.\n\nReference: CF Borrow tab layout with LTV gauge, borrow power, collateral balance.\n\nAcceptance:\n- Borrow tab renders with live data\n- LTV/collateral stats show for connected accounts with loans\n- \"Borrow\" button routes correctly\n- Empty state when no loans","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12008","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:55:01.799724+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:55:50.446161+01:00","dependencies":[{"issue_id":"shapeshiftWeb-5s8h","depends_on_id":"shapeshiftWeb-v617","type":"blocks","created_at":"2026-02-23T15:20:43.429313+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-61a","title":"Phase 4: Performance — memoize BigAmount in hooks and components","description":"4.1: Memoize 9 HIGH-priority BigAmount hook arguments (ThorchainSavers, AddLiquidity, etc.). 4.2: Memoize 11 MEDIUM-priority component body BigAmount. 4.3: Memoize 10 LOWER-priority inline JSX BigAmount.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:15:31.008783+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:26:33.115727+01:00","closed_at":"2026-02-13T12:26:33.115727+01:00","close_reason":"Deferred memoization to next deep dive round - higher priority items completed first.","dependencies":[{"issue_id":"shapeshiftWeb-61a","depends_on_id":"shapeshiftWeb-69b","type":"blocks","created_at":"2026-02-13T12:15:37.71631+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-69b","title":"Phase 3: Redundant code cleanup — boolean checks, round-trips, AccountSelector","description":"3.1: Remove 4 redundant boolean checks (AssetHeader, portfolioSlice selectors, lpSelectors, YieldsList). 3.2: Fix 8 HIGH-priority BigAmount→string→BigAmount round-trips. 3.3: Fix AccountSelectorDialog round-trip.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:15:28.409069+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:26:32.9986+01:00","closed_at":"2026-02-13T12:26:32.9986+01:00","close_reason":"3.1: Removed 4 redundant boolean checks. 3.3: Fixed AccountSelectorDialog round-trip, now passes precision-scale directly. 3.2 (round-trips) deferred to next round.","dependencies":[{"issue_id":"shapeshiftWeb-69b","depends_on_id":"shapeshiftWeb-0c4","type":"blocks","created_at":"2026-02-13T12:15:37.654329+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-6je","title":"Phase 1: Bug fixes — amountOutMin ROUND_UP and fee precision","description":"1.1: amountOutMin uses ROUND_UP instead of ROUND_DOWN in getCallDataFromQuote.ts:50 and getEvmData.ts:66. 1.2: Fee precision uses collateralAsset instead of collateralFeeAsset in BorrowInput.tsx:309-318 and 240.","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T12:15:24.558547+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:16:42.651401+01:00","closed_at":"2026-02-13T12:16:42.651401+01:00","close_reason":"ROUND_DOWN fix applied to getCallDataFromQuote.ts and getEvmData.ts. BorrowInput.tsx fee precision fixed to use collateralFeeAsset."} -{"id":"shapeshiftWeb-6ld","title":"PR5: balance display + account components","description":"Low-risk display-layer migration. ~31 files: AccountDropdown, AccountSelector (+ Dialog, Option), AssetAccountRow, AssetChart, AssetHeader, useQuickBuy, AssetRow, AssetChainRow, ChainDropdown, Equity, EquityAccountRow, Amount.tsx, AccountBalance, AccountEntryRow, DownloadButton, ActionCenter components (ArbitrumBridge, LimitOrderDetails, RewardDistribution, RfoxClaim, TcyClaim, ManageHiddenAssets, ImportAccounts), StakingPositionsByProvider, Sweep, AssetInput, TransactionHistory utils/Amount/GenericRow/Trade. Pure consumer migration — no business logic changes.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:22.841211+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.306496+01:00","closed_at":"2026-02-14T13:25:59.306496+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-6ld","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.499707+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-6ld","depends_on_id":"shapeshiftWeb-8ys","type":"blocks","created_at":"2026-02-13T15:38:06.644981+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-6mc","title":"add yield.xyz polling to useGenericTransactionSubscriber","description":"In src/hooks/useActionCenterSubscribers/useGenericTransactionSubscriber.tsx: For Pending yield actions (displayType=Yield) that have a yieldActionId, poll fetchAction(yieldActionId) from yield.xyz API every 5s instead of using txs[serializedTxIndex] lookup. On YieldActionStatus.Success: call parseAndUpsertSecondClassChainTx, update action to Complete, invalidate yield queries (allBalances + yields), fire success toast, cleanup interval. On Failed/Canceled: update action to Failed, fire error toast, cleanup. Add pollingIntervalsRef (useRef\u003cMap\u003e), cleanup effect on unmount, drawer close toast cleanup (usePrevious pattern from useSendActionSubscriber). Non-yield Pending actions keep existing txs lookup behavior unchanged.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:50.358559+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:03:44.601774+01:00","closed_at":"2026-02-14T11:03:44.601774+01:00","close_reason":"Added yield.xyz API polling to useGenericTransactionSubscriber for Pending yield actions with yieldActionId. Polls every 5s, handles Success (parseTx + Complete + invalidate) and Failed/Canceled. Added interval cleanup, orphan cleanup, drawer toast close pattern. Non-yield actions keep existing txs lookup.","dependencies":[{"issue_id":"shapeshiftWeb-6mc","depends_on_id":"shapeshiftWeb-ed1","type":"blocks","created_at":"2026-02-14T10:40:04.798731+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-6mc","depends_on_id":"shapeshiftWeb-0k4","type":"blocks","created_at":"2026-02-14T10:40:04.882329+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-6mc","depends_on_id":"shapeshiftWeb-3lh","type":"blocks","created_at":"2026-02-14T10:40:04.968706+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-6w2","title":"Transition yield claim action to Claimed after user completes claim on yield detail page","description":"After user clicks Claim in action center -\u003e navigates to /yields/{yieldId} -\u003e completes claim tx, the original cooldown-tracking action stays ClaimAvailable forever. Need to find the existing ClaimAvailable action for the same yieldId in dispatchNotification when a manage/claim action completes, and transition it to Claimed with message unstakeClaimed. The unstakeClaimed translation key exists but is currently unused.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:27:18.085967+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:41:27.189176+01:00","closed_at":"2026-02-14T11:41:27.189176+01:00","close_reason":"After manage/claim completes, find existing ClaimAvailable actions with matching yieldId via store.getState() and transition them to Claimed with unstakeClaimed message"} -{"id":"shapeshiftWeb-6xx","title":"WC Wallet: Tron support (connect wallet)","description":"Add Tron namespace support to the WalletConnect 'connect wallet' flow. When a user selects WC as a wallet option in ShapeShift and scans the QR with Trust Wallet/Binance Web3/SafePal/TronLink mobile, ShapeShift should handle the tron namespace.\n\n## Prerequisites\n- Depends on Cosmos wallet support (which introduces universal-provider migration)\n\n## Scope\n- Add tron namespace to optionalNamespaces in session proposal (tron:0x2b6653dc)\n- Implement WalletConnectV2HDWallet tron methods: tronGetAddress (parse CAIP-10 account), tronSignTx (send via tron_signTransaction)\n- Add _supportsTron = true flag\n- Handle tron_signMessage for message signing\n- Parse session accounts from CAIP-10 format: tron:0x2b6653dc:\u003ctronAddress\u003e\n- Handle tron_method_version v1 session property for simplified tx format\n- Unit tests for tron signing methods\n\n## RPC Methods\n- tron_signTransaction: params { address, transaction: TronWebTxObject } -\u003e { txID, signature[], raw_data, raw_data_hex }\n- tron_signMessage: params { address, message } -\u003e { signature }\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- User can scan QR with Trust Wallet mobile and get tron address exposed\n- Tron transactions can be signed via WC\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:20:52.4853+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:26:50.363367+01:00","closed_at":"2026-02-17T15:26:50.363367+01:00","close_reason":"Tron WCV2 wallet support implemented in PR #11912","dependencies":[{"issue_id":"shapeshiftWeb-6xx","depends_on_id":"shapeshiftWeb-4cm","type":"blocks","created_at":"2026-02-17T13:21:23.932734+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-6yr","title":"[Tron Wallet] signTransaction response type mismatch, signature is array","description":"HIGH: WC tron_signTransaction returns { signature: string[] } not { signature: string }. Code at tron.ts:59 types as string. serialized field would concat array incorrectly. Fix: Type as string[], extract result.signature[0]. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_tron_wcv2_wallet","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:48:33.716572+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.692887+01:00","closed_at":"2026-02-18T16:58:33.692887+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-77v","title":"add cooldownExpiryTimestamp + yieldId to metadata, remove manage guard","description":"In src/state/slices/actionSlice/types.ts: add cooldownExpiryTimestamp?: number (unix ms when claim becomes available) and yieldId?: string (for routing to yield claim page) to ActionGenericTransactionMetadata. In src/pages/Yields/hooks/useYieldTransactionFlow.ts: remove the 'if (action === manage) return' guard at line 445 in dispatchNotification. This enables claim actions to be tracked in the action center.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:56.230512+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:11:17.062609+01:00","closed_at":"2026-02-14T11:11:17.062609+01:00","close_reason":"Added cooldownExpiryTimestamp and yieldId to ActionGenericTransactionMetadata. No manage guard to remove (dispatchNotification already handles manage actions correctly by setting displayType to Claim).","dependencies":[{"issue_id":"shapeshiftWeb-77v","depends_on_id":"shapeshiftWeb-6mc","type":"blocks","created_at":"2026-02-14T10:40:05.131345+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-7br","title":"Solana simulation types","description":"Create src/plugins/walletConnectToDapps/utils/solana-simulation/types.ts with Solana-specific simulation types. Mirror the tenderly/types.ts pattern but for Solana native RPC simulation. Types: SolanaBalanceChange (mint?, symbol?, name?, icon?, decimals, preBalance, postBalance, change as string base units, type send/receive), SolanaSimulationResult (success, error?, balanceChanges[], unitsConsumed?). No EVM/Tenderly imports.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T13:11:03.634056+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:13:41.746169+01:00","closed_at":"2026-02-18T13:13:41.746169+01:00","close_reason":"Created types.ts with SolanaTokenInfo, SolanaBalanceChange, SolanaSimulationResult"} -{"id":"shapeshiftWeb-7d2","title":"WC dApps: Tron support (ShapeShift as wallet)","description":"Add Tron namespace support in WC-to-dApps flow. When ShapeShift acts as a wallet and an external Tron dApp (Sun.io, JustLend, etc.) connects via WC, handle Tron signing requests.\n\n## Scope\n- Add TronSigningMethod enum to types.ts (tron_signTransaction, tron_signMessage, tron_sendTransaction)\n- Add Tron request/response types to types.ts\n- Create TronRequestHandlerUtil.ts following EIP155RequestHandlerUtil pattern\n- Handle tron_signTransaction: pass TronWeb tx object to hdwallet tronSignTx, return signed tx\n- Handle tron_signMessage: sign message via hdwallet\n- Handle tron_sendTransaction: sign + broadcast via chain adapter\n- Update useWalletConnectEventsHandler.ts to route Tron methods to appropriate modal\n- Add WalletConnectModal entries for Tron confirmation\n- Update createApprovalNamespaces.ts to handle tron namespace\n- Create TronSignConfirmation modal component\n- Unit tests for TronRequestHandlerUtil\n\n## RPC Method Details\n- tron_signTransaction: { address, transaction } -\u003e signed tx object with signature[]\n- tron_signMessage: { address, message } -\u003e { signature }\n- tron_sendTransaction: { txID, signature[], raw_data, raw_data_hex } -\u003e { result, txid }\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- External Tron dApp can connect to ShapeShift via WC and sign transactions\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:21:00.675045+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:47:01.793852+01:00","closed_at":"2026-02-17T15:47:01.793852+01:00","close_reason":"PR #11917 opened - tron wc dApps support","dependencies":[{"issue_id":"shapeshiftWeb-7d2","depends_on_id":"shapeshiftWeb-6xx","type":"blocks","created_at":"2026-02-17T13:21:24.169796+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-7kz","title":"[Epic] yield claim actions in action center","description":"Track yield claims with unbonding periods in the action center. After a yield exit with cooldown, show 'Your unstake will be available in X days', transition to ClaimAvailable when ready, show green Claim button linking to yield route. Follows rFOX/TCY claim pattern. Branch: on top of feat_yield_second_class_tx_history (stacked, draft PR). Depends on Epic 1 being complete.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:25.860455+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:23:38.912722+01:00","closed_at":"2026-02-14T11:23:38.912722+01:00","close_reason":"Epic 2 complete: yield claim actions in action center - cooldown metadata, claim dispatch after unbonding exit, subscriber cooldown polling, and GenericTransactionActionCard claim UI","dependencies":[{"issue_id":"shapeshiftWeb-7kz","depends_on_id":"shapeshiftWeb-8t4","type":"blocks","created_at":"2026-02-14T10:40:05.050543+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-7n8","title":"add sequence to BTCSignTxInputSafe common type","description":"Currently sequence is only on BTCSignTxInputKKBase (KeepKey). Move/add sequence?: number to the common BTCSignTxInputSafe type so all wallets can receive it. Update GuardedUnion and related type machinery as needed. Acceptance: BTCSignTxInputSafe includes optional sequence field, all wallet-specific input types inherit it.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:00.473382+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:43:04.2958+01:00","closed_at":"2026-02-14T10:43:04.2958+01:00","close_reason":"Added sequence?: number to BTCSignTxInputBase (flows to all wallet types), removed redundant field from BTCSignTxInputKKBase, added to BTCSignTxInputSafe. Type assertion passes."} -{"id":"shapeshiftWeb-7qq","title":"SpeedUp modal component with fee picker","description":"Create SpeedUp modal at src/components/Modals/SpeedUp/. Shows current fee rate, recommended fee rates from getFeeData(), fee difference. Two actions: Speed Up (keep payment, higher fee) and Cancel Transaction (send to self). On confirm: builds replacement tx, signs, broadcasts.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:47.413951+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:35:27.975821+01:00","closed_at":"2026-02-14T11:35:27.975821+01:00","close_reason":"Built SpeedUpModal with fee picker, replacement tx building, signing, and broadcasting","dependencies":[{"issue_id":"shapeshiftWeb-7qq","depends_on_id":"shapeshiftWeb-m47","type":"blocks","created_at":"2026-02-14T11:13:56.067742+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-7qq","depends_on_id":"shapeshiftWeb-zgd","type":"blocks","created_at":"2026-02-14T11:13:56.148494+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-7ut","title":"Phase 5: Display polish — fiat formatting and negative missingFunds","description":"5.1: Fix fiat formatting .toFixed() → .toFixed(2) in YieldAvailableToDeposit, YieldPositionCard, YieldForm. 5.2: Clamp negative missingFunds to zero in thorchain/balance.ts:74. 5.3: Cross-precision aggregation fragility in common-selectors.ts.","status":"closed","priority":4,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:15:32.791573+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:26:37.915544+01:00","closed_at":"2026-02-13T12:26:37.915544+01:00","close_reason":"5.1: Fixed fiat formatting .toFixed() → .toFixed(2) in 3 yield files. 5.2: Clamped negative missingFunds with .positiveOrZero(). 5.3 deferred.","dependencies":[{"issue_id":"shapeshiftWeb-7ut","depends_on_id":"shapeshiftWeb-61a","type":"blocks","created_at":"2026-02-13T12:15:37.776628+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-841","title":"p3: lib/utils/infrastructure + store + migrations","description":"NEW PR — lib utilities, market service, mixpanel, hooks, store config, react-queries, and migration changes.\n\nFiles (24):\n- src/lib/address/bip21.ts\n- src/lib/address/generateReceiveQrText.ts\n- src/lib/amount/BigAmount.test.ts\n- src/lib/investor/investor-foxy/api/api.ts\n- src/lib/market-service/foxy/foxy.ts\n- src/lib/market-service/thorchainAssets/thorchainAssets.ts\n- src/lib/market-service/utils/isValidDate.test.ts\n- src/lib/math.test.ts\n- src/lib/math.ts\n- src/lib/mixpanel/helpers.ts\n- src/lib/mixpanel/types.ts\n- src/lib/utils/isEvmAddress.test.ts\n- src/lib/utils/thorchain/balance.test.ts\n- src/lib/utils/thorchain/hooks/useSendThorTx.tsx\n- src/lib/utils/thorchain/index.ts\n- src/lib/utils/utxo.test.ts\n- src/lib/yieldxyz/executeTransaction.ts\n- src/hooks/useBalanceChartData/useBalanceChartData.ts\n- src/pages/Fox/components/RFOXSimulator.tsx\n- src/react-queries/hooks/useQuoteEstimatedFeesQuery.ts\n- src/react-queries/selectors/index.ts\n- src/state/apis/swapper/helpers/getInputOutputRatioFromQuote.ts\n- src/state/migrations/index.ts\n- src/state/store.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, dead code removal (pricePerShare), new test files, store config updates, migration version bump.\n\nBranch: bigamount-lib-infra (new, from bigamount-core-selectors). New draft PR.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:47:06.975353+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:55:22.476171+01:00","closed_at":"2026-02-14T13:55:22.476171+01:00","close_reason":"Absorbed into p2.x beads — store.ts to p2.6, market-service to p2.2, mixpanel/math/utils distributed across p2.x"} -{"id":"shapeshiftWeb-84g","title":"Add speed up to tx history rows","description":"Add Speed Up button to TransactionRow component for pending BTC transactions. 1. In the tx history row rendering, detect pending BTC txs that are RBF-eligible (pending + BTC chainId). 2. Add a Speed Up button/action alongside the existing explorer link. 3. Clicking opens the same SpeedUpModal used in action center. 4. Need to pass txHash, accountId, chainId to the modal. 5. Also show 'Replaced' status for txs that have been replaced (replacedByTxHash set). Look at TransactionRow.tsx, TransactionCommon.tsx, TransactionDetails/Status.tsx for where to add the button.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:49:51.366283+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T12:21:48.281778+01:00","closed_at":"2026-02-14T12:21:48.281778+01:00","close_reason":"Added speed up button to TransactionCommon for pending BTC sends. Uses toAccountId with tx.pubkey to derive accountId.","dependencies":[{"issue_id":"shapeshiftWeb-84g","depends_on_id":"shapeshiftWeb-cav","type":"blocks","created_at":"2026-02-14T11:50:01.102536+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-8ep","title":"extend action metadata with RBF data","description":"Add rbfMeta field to ActionGenericTransactionMetadata in src/state/slices/actionSlice/types.ts. Store original inputs (txid, vout, amount, addressNList, scriptType, hex), outputs (address, amount, isChange, addressNList, scriptType), satoshiPerByte, accountType, and accountNumber. Also add replacedByTxHash and replacesTxHash fields. Add no-op state migration for new optional fields.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:39.960337+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:14:48.109647+01:00","closed_at":"2026-02-14T11:14:48.109647+01:00","close_reason":"Added RbfMeta type (inputs, outputs, satoshiPerByte, accountType, accountNumber) and rbfMeta/replacedByTxHash/replacesTxHash fields to ActionGenericTransactionMetadata. Added clearAction migration v2."} -{"id":"shapeshiftWeb-8ik","title":"PR1: update PR description testing section for fox ecosystem","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:15.41107+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.592648+01:00","closed_at":"2026-02-13T17:33:51.592648+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-8t4","title":"[Epic] yield second-class chain tx history + action center pollers","description":"Fix #11862: Yield operations (deposit/withdraw) on second-class chains never appear in tx history. Root causes: (1) dispatchNotification always dispatches Complete, subscriber never processes yield actions (2) no websocket for second-class chains so txs lookup fails (3) no parseTx+upsert for second-class yield chains (4) navigate-away loses all yield state. Solution: dispatch Pending early, poll yield.xyz API in subscriber, parseTx for second-class chains. Branch: feat_yield_second_class_tx_history. Worktree: /Users/gomes/Sites/shapeshiftWeb--yield_second_class_tx_history","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:25.717636+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:03:44.701513+01:00","closed_at":"2026-02-14T11:03:44.701513+01:00","close_reason":"All sub-beads complete: shared utility (ed1), type change (0k4), yield flow refactor (3lh), subscriber polling (6mc)"} -{"id":"shapeshiftWeb-8vgs","title":"PR1: EIP-712 signing pipeline","description":"Create src/lib/chainflip/eip712.ts + src/lib/chainflip/eip712.test.ts.\n\neip712.ts - composable signing architecture:\n\nLayer 1 - Pure utils:\n- signChainflipCall({ wallet, accountMetadata, encodedCall, blocksToExpiry?, nonceOrAccount })\n 1. Call cfEncodeNonNativeCall(hexCall, blocksToExpiry=120, nonceOrAccount, {Eth:'Eip712'})\n 2. Extract EIP-712 TypedData from response\n 3. Call wallet adapter signTypedData (eth_signTypedData_v4)\n 4. Wrap signature + call into encodeNonNativeSignedCall\n 5. Return signed extrinsic hex\n- submitSignedCall(hex) -\u003e call authorSubmitExtrinsic, return tx hash\n- signAndSubmitChainflipCall(...) -\u003e combines sign + submit\n\nLayer 2 - Composed utils (built on signChainflipCall):\n- signAddLenderFunds(wallet, account, asset, amount)\n- signRemoveLenderFunds(wallet, account, asset, amount)\n- signRequestDepositAddress(wallet, account, asset, boostFee?)\n- signWithdrawAsset(wallet, account, amount, asset, address)\n- signRequestLoan(wallet, account, borrowAsset, amount)\n- signAddCollateral(wallet, account, asset, amount)\n- signMakeRepayment(wallet, account, loanId, asset, amount)\n- signBatch(wallet, account, calls[])\n\nLayer 3 - React hooks (created in PR 2+, not here)\n\neip712.test.ts:\n- Mock wallet (signTypedData returns deterministic sig)\n- Mock RPC (cfEncodeNonNativeCall returns fixture)\n- Verify full pipeline: encode -\u003e sign -\u003e wrap -\u003e submit\n- Verify composed utils call signChainflipCall with correct params\n- Test error cases: wallet rejection, RPC error, specVersion mismatch\n\nReference patterns:\n- src/components/MultiHopTrade/components/TradeConfirm/hooks/useSignPermit2.tsx\n- packages/swapper/src/cowswap-utils/index.ts\n- CF bouncer: bouncer/tests/signed_runtime_call.ts\n\nAcceptance:\n- Full pipeline testable with mocks\n- signChainflipCall is pure (no React deps)\n- Composed utils are thin wrappers\n- All tests pass","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:51:03.842632+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.334367+01:00","closed_at":"2026-02-23T17:09:20.334367+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-8vgs","depends_on_id":"shapeshiftWeb-cza9","type":"blocks","created_at":"2026-02-23T14:57:22.583956+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-8vgs","depends_on_id":"shapeshiftWeb-gzbj","type":"blocks","created_at":"2026-02-23T14:57:33.073865+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-8vgs","depends_on_id":"shapeshiftWeb-mwbz","type":"blocks","created_at":"2026-02-23T14:57:43.652768+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-8ys","title":"PR2: core portfolio selectors return BigAmount","description":"HIGHEST RISK PR. Changes return type of core selectors from string to BigAmount. 6 files:\n- src/state/slices/common-selectors.ts (selectPortfolioCryptoBalanceByFilter, selectPortfolioAssetBalances, selectPortfolioAccountBalances → BigAmount)\n- src/state/slices/portfolioSlice/selectors.ts (selectPortfolioAccountsCryptoPrecisionBalances, etc.)\n- src/state/slices/portfolioSlice/utils/index.ts\n- src/state/slices/portfolioSlice/portfolioSlice.test.ts\n- src/state/migrations/index.ts\n- src/state/store.ts (if not already in PR1)\n\nThis is the breaking change — every consumer of these selectors must be updated in subsequent PRs. Without this PR, consumers can still use the old string-returning selectors. With this PR, ALL downstream consumers MUST be migrated.\n\nAcceptance criteria: type-check passes, portfolio tests pass, selectors correctly return BigAmount with proper precision and assetId.","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:37:58.106711+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.298475+01:00","closed_at":"2026-02-14T13:25:59.298475+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-8ys","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:38:03.393824+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-8znk","title":"PR4: Collateral management and borrow/repay modals","description":"Full borrow lifecycle modals: collateral management, loan creation, repayment.\n\nCollateral Modal:\n- Add collateral: move from free balance to collateral via addCollateral (EIP-712)\n- Remove collateral: move from collateral to free balance via removeCollateral (EIP-712)\n- Linear stepper for each direction\n- Min $10 collateral update\n\nBorrow Modal:\n- Request loan: requestLoan(borrowAsset, amount) via EIP-712\n- Shows available borrow power based on collateral + LTV\n- Max LTV 80% for creation\n- Borrowed amount lands in free balance, then can withdraw_asset to wallet\n- Linear stepper: enter amount -\u003e sign loan request -\u003e confirm -\u003e optional withdraw\n\nRepay Modal:\n- Make repayment: makeRepayment(loanId, asset, amount) via EIP-712\n- Show current debt, interest accrued\n- Partial or full repayment\n- After full repayment, can remove collateral\n- Linear stepper: enter amount -\u003e sign repayment -\u003e confirm\n\nLTV Gauge Component:\n- Visual gauge (Chakra Progress or custom) showing current LTV\n- Passive threshold markers at 80% (max creation), 85% (topup), 90% (soft liq), 95% (hard liq)\n- Color coding: green \u003c 80%, yellow 80-90%, red \u003e 90%\n- Used in both BorrowTab stats and PositionCard\n\nPositionCard updates for borrow:\n- Show loan details: borrowed amount, collateral, current LTV, health\n- Action buttons: [Add Collateral] [Repay] when loan exists\n- Interest accrual display\n\nAcceptance:\n- Can add/remove collateral\n- Can request loan against collateral\n- Can repay (partial/full)\n- LTV gauge renders with correct thresholds\n- Position card shows full loan details\n- All modals use linear stepper\n- Min amounts enforced ($100 loan creation, $10 updates)","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12008","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:55:27.121979+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:56:00.778019+01:00","dependencies":[{"issue_id":"shapeshiftWeb-8znk","depends_on_id":"shapeshiftWeb-5s8h","type":"blocks","created_at":"2026-02-23T15:20:53.706004+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-8znk","depends_on_id":"shapeshiftWeb-oxjm","type":"blocks","created_at":"2026-02-23T15:21:04.046891+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-916s","title":"Refactor BitcoinSignConfirmation to use WalletConnectSigningModal + BTC content components","description":"## Context\nBitcoinSignConfirmation.tsx is a custom one-off modal that doesn't use the shared WalletConnectSigningModal wrapper (unlike EIP155/Solana). This causes styling inconsistencies and duplicated logic (manual confirm/reject buttons, peer metadata, etc.).\n\n## What\nRefactor BitcoinSignConfirmation to:\n1. Use `WalletConnectSigningModal` as the wrapper (provides PeerMeta, confirm/reject footer, account display)\n2. Create BTC-specific content components passed as children:\n - **signMessage**: Reuse existing `MessageContent` component from `WalletConnectSigningModal/content/MessageContent.tsx`\n - **sendTransfer**: New `BitcoinSendTransferContent` - shows recipient address (with ExpandableCell), amount as BTC using `\u003cAmount.Crypto value={fromBaseUnit(amount, 8)} symbol={feeAsset.symbol} /\u003e` (NOT raw sats), optional memo\n - **signPsbt**: New `BitcoinPsbtContent` - parse PSBT with `@shapeshiftoss/bitcoinjs-lib` Psbt.fromBase64(), show: network (Bitcoin icon), number of inputs, number of outputs, total output amounts, broadcast flag, expandable raw PSBT data section (like Solana's expandable transaction data pattern). Use `Card borderRadius='2xl' p={4}` and `VStack spacing={3}` like Solana/EIP155 content components.\n3. Fix the sats display: use `fromBaseUnit(amount, feeAsset?.precision ?? 8)` and `Amount.Crypto` instead of raw sats translation key\n4. Match the WalletConnectSigningModal's `onConfirm` signature (accepts optional CustomTransactionData)\n\n## Files\n- `src/plugins/walletConnectToDapps/components/modals/BitcoinSignConfirmation.tsx` - rewrite to use WalletConnectSigningModal\n- `src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/BitcoinSendTransferContent.tsx` - new\n- `src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/BitcoinPsbtContent.tsx` - new\n\n## Reference pattern\nSee how EIP155SignMessageConfirmation.tsx and SolanaSignMessageConfirmation.tsx use WalletConnectSigningModal + content children.\nSee SolanaTransactionContent.tsx for expandable transaction data pattern with useToggle, ChevronDown/UpIcon.\n\n## Acceptance criteria\n- BitcoinSignConfirmation uses WalletConnectSigningModal wrapper\n- All 3 BTC methods (signMessage, sendTransfer, signPsbt) display correctly\n- signMessage reuses MessageContent (no duplication)\n- sendTransfer shows BTC amount via Amount.Crypto (not raw sats)\n- signPsbt shows parsed details (inputs count, outputs with addresses/amounts, broadcast flag) with expandable raw data\n- Zero regressions in EIP155/Solana/Cosmos modals (only new files + rewritten BitcoinSignConfirmation)","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T17:16:33.604185+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:25:08.474734+01:00","closed_at":"2026-02-18T17:25:08.474734+01:00","close_reason":"Refactored BitcoinSignConfirmation to use WalletConnectSigningModal. Created BitcoinSendTransferContent (Amount.Crypto for BTC display) and BitcoinPsbtContent (parsed PSBT with expandable details). Reuses MessageContent for signMessage."} -{"id":"shapeshiftWeb-92h","title":"PR6: defi selectors + providers","description":"High-risk defi domain. ~57 files: opportunitiesSlice resolvers (cosmosSdk, ethFoxStaking, foxy, rFOX, thorchainsavers), selectors (lpSelectors, stakingSelectors, selectors.test), types.ts, utils. All defi provider UIs: cosmos (Claim/Deposit/Withdraw Confirm/Status/Overview), fox-farming (Claim/Deposit/Withdraw + hooks), foxy (full manager — Deposit/Withdraw/Overview/Claim), thorchain-savers (Deposit/Withdraw + Overview), univ2 (hooks + utils), defi/helpers/utils.ts, investor-foxy api.ts, foxy market-service. Touches balance checks, fee calculations, opportunity resolution.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:28.955657+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.305295+01:00","closed_at":"2026-02-14T13:25:59.305295+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-92h","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.56702+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-92h","depends_on_id":"shapeshiftWeb-8ys","type":"blocks","created_at":"2026-02-13T15:38:06.712735+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-953","title":"Audit: packages/ BigAmount usage correctness (chain-adapters, swapper, unchained)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:53.17778+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.804126+01:00","closed_at":"2026-02-13T11:31:46.804126+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-97o","title":"BigAmount: remove old string-returning selectors","description":"Once all consumers are migrated to new BigAmount-returning selectors, remove the old string-returning variants: selectPortfolioAccountBalancesBaseUnit, selectPortfolioAssetBalancesBaseUnit, selectPortfolioCryptoBalanceBaseUnitByFilter, selectPortfolioCryptoPrecisionBalanceByFilter, selectPortfolioAssetBalancesBaseUnitIncludingZeroBalances. Also remove fromBaseUnit imports that are no longer needed.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T18:47:03.194541+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:44:10.033118+01:00","closed_at":"2026-02-13T19:44:10.033118+01:00","close_reason":"PR #11875 created — merge after all consumer PRs (#11867-#11874)","dependencies":[{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-b2y","type":"blocks","created_at":"2026-02-13T18:47:08.422251+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-x6c","type":"blocks","created_at":"2026-02-13T18:58:42.391341+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-dhf","type":"blocks","created_at":"2026-02-13T18:58:42.520954+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-qw5","type":"blocks","created_at":"2026-02-13T19:03:06.173434+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-wm8","type":"blocks","created_at":"2026-02-13T19:03:06.256622+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-4h6","type":"blocks","created_at":"2026-02-13T19:03:06.34004+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-4b2","type":"blocks","created_at":"2026-02-13T19:03:06.423353+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-bvn","type":"blocks","created_at":"2026-02-13T19:03:06.507005+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-97o","depends_on_id":"shapeshiftWeb-uk6","type":"blocks","created_at":"2026-02-13T19:03:06.594276+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-9ee","title":"[BTC Wallet] signInputs wrong format and double-broadcast risk","description":"HIGH: signInputs: {} should be array per spec. Also broadcast: true causes double-broadcast since chain adapter also broadcasts. Fix: Build signInputs from PSBT inputs, set broadcast: false. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:47:54.345292+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.08155+01:00","closed_at":"2026-02-18T17:02:53.08155+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-9kx","title":"capture RBF metadata during BTC send","description":"In src/components/Modals/Send/Form.tsx completeSendFlow(), capture the txToSign data (inputs, outputs) and fee info when chainId is BitcoinMainnet. Store as rbfMeta in the upsertAction call.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:42.578215+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:21:30.603897+01:00","closed_at":"2026-02-14T11:21:30.603897+01:00","close_reason":"Modified handleSend to return {txHash, rbfMeta}. Captures RBF metadata (inputs, outputs, feeRate, accountType) for BTC sends. Updated all 5 callers (useFormSend, Form.tsx, QrCode/Form.tsx, Sweep.tsx, BorrowConfirm.tsx, useSendThorTx.tsx). Stores rbfMeta in action metadata via completeSendFlow.","dependencies":[{"issue_id":"shapeshiftWeb-9kx","depends_on_id":"shapeshiftWeb-8ep","type":"blocks","created_at":"2026-02-14T11:13:55.90846+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-a1i","title":"PR7: trade selectors + trade UI","description":"High-risk trade domain. ~40 files: tradeQuoteSlice (helpers, selectors, utils.test), tradeInputSlice/selectors, tradeEarnInputSlice/selectors, tradeRampInputSlice/selectors, limitOrderInputSlice/selectors, limitOrderSlice (helpers, selectors), createTradeInputBaseSelectors, swapper API helpers (validateTradeQuote, getInputOutputRatioFromQuote). Trade UI: MultiHopTrade (helpers, MultiHopTrade.tsx, StandaloneMultiHopTrade, EarnInput, TradeAmountInput, TradeAssetInput, TradeInput, MaxSlippage, TradeConfirm, TradeConfirmFooter, TradeConfirmSummary, useTradeButtonProps, SpotTradeSuccess, AssetSummaryStep, getTradeQuoteOrRateInput, useGetTradeQuotes, useInputOutputDifference), LimitOrder (LimitOrder, AllowanceApproval, CancelLimitOrder, LimitOrderCard, LimitOrderInput, useLimitOrders), LimitOrderV2/LimitOrderConfirm, RateChanged modal. Hooks: useActualBuyAmountCryptoPrecision, useLimitOrderActionSubscriber, useBalanceChartData, useQuoteEstimatedFeesQuery, react-queries/selectors.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:38.433981+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.304068+01:00","closed_at":"2026-02-14T13:25:59.304068+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-a1i","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.63419+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-a1i","depends_on_id":"shapeshiftWeb-8ys","type":"blocks","created_at":"2026-02-13T15:38:06.775467+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-aie","title":"fix missing precision fallback in RemoveLiquidityInput.tsx:474","description":"poolAssetFeeAsset?.precision passed to BigAmount.fromBaseUnit without ?? 0 fallback. If poolAssetFeeAsset is null, precision becomes undefined → NaN in arithmetic. Fix: add ?? 0.","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T13:19:07.234248+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:19:20.534598+01:00","closed_at":"2026-02-13T13:19:20.534598+01:00","close_reason":"False positive — line 469 already guards with 'if (\\!poolAssetFeeAsset) return bn(0)' before line 474. poolAssetFeeAsset is guaranteed defined."} -{"id":"shapeshiftWeb-ankw","title":"Implement sendTransfer in BIP122RequestHandlerUtil","description":"## Context\nsendTransfer in BIP122RequestHandlerUtil.ts currently throws 'sendTransfer is not yet fully supported'. The WC BIP122 sendTransfer method requests the wallet to build, sign, and broadcast a BTC transaction to a recipient.\n\n## What\nImplement the sendTransfer case in approveBIP122Request:\n\n1. **Params**: BIP122SendTransferCallRequestParams = { account, recipientAddress, amount (sats string), memo? }\n\n2. **Implementation**:\n - Need chainAdapter (UtxoBaseAdapter for BTC) to build the transaction\n - Add chainAdapter to ApproveBIP122RequestArgs type (caller in WalletConnectModalManager already has chainId)\n - Use chainAdapter.buildSendApiTransaction() with:\n - to: recipientAddress\n - value: amount (already in sats/base units)\n - wallet: wallet\n - accountNumber: 0 (default first account)\n - chainSpecific: { accountType: UtxoAccountType.SegwitNative }\n - Sign with wallet.btcSignTx using the built transaction params\n - Broadcast via chainAdapter.broadcastTransaction()\n - If memo provided, include as opReturnData\n\n3. **Response format** per WC BIP122 spec:\n - Return { txid: \"\u003chex transaction id\u003e\" }\n\n4. **Wire up chainAdapter in WalletConnectModalManager**:\n - In handleConfirmBIP122Request, get the BTC chain adapter\n - Pass it to approveBIP122Request\n - Import assertGetUtxoChainAdapter or similar utility\n\n## Files\n- src/plugins/walletConnectToDapps/utils/BIP122RequestHandlerUtil.ts - implement sendTransfer case, update args type\n- src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx - pass chainAdapter to approveBIP122Request\n\n## Notes\n- sendTransfer is a full send flow (build + sign + broadcast), unlike signPsbt which may not broadcast\n- amount is in sats (base units), no conversion needed for chain adapter\n- Use SegwitNative account type since our WC account is a bc1q address","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T17:17:24.394634+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:27:35.682999+01:00","closed_at":"2026-02-18T17:27:35.682999+01:00","close_reason":"Implemented sendTransfer: gets fee data via chain adapter, builds tx with buildSendTransaction (SegwitNative, average fee rate), signs with signTransaction, broadcasts with broadcastTransaction, returns txid. Wired chain adapter in WalletConnectModalManager via assertGetUtxoChainAdapter."} -{"id":"shapeshiftWeb-aqf","title":"Solana WC e2e signing - raw tx + message signing in hdwallet","description":"Add solanaSignRawTransaction and solanaSignMessage to hdwallet-core interface, implement in all wallet adapters (native, ledger, trezor, phantom, gridplus), wire up SolanaRequestHandlerUtil to actually sign WC requests instead of throwing.","status":"closed","priority":1,"issue_type":"epic","owner":"contact@0xgom.es","created_at":"2026-02-18T12:42:16.248209+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:59:30.433753+01:00","closed_at":"2026-02-18T12:59:30.433753+01:00","close_reason":"All wallet adapters implemented, web layer wired up. Type-check and lint clean."} -{"id":"shapeshiftWeb-asl","title":"WC dApps: Cosmos support (ShapeShift as wallet)","description":"Complete Cosmos namespace support in WC-to-dApps flow. When ShapeShift acts as a wallet and an external Cosmos dApp connects via WC, handle cosmos_signAmino and cosmos_signDirect signing requests.\n\n## Research Steps (before coding)\n1. Read src/plugins/walletConnectToDapps/utils/EIP155RequestHandlerUtil.ts as the reference pattern\n2. Read src/plugins/walletConnectToDapps/utils/CosmosRequestHandlerUtil.ts for current partial implementation\n3. Read src/plugins/walletConnectToDapps/utils/createApprovalNamespaces.ts - understand the isEvmChainId filter blocking non-EVM\n4. Read src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx - understand modal routing\n5. Read src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsHandler.ts - already routes cosmos methods\n6. Read packages/hdwallet-core/src/cosmos.ts for CosmosSignTx interface\n7. Check src/lib/utils/cosmosSdk.ts for assertGetCosmosSdkChainAdapter\n8. Read src/plugins/walletConnectToDapps/components/modals/CosmosSignMessageConfirmation.tsx for existing modal\n\n## Implementation Details\n\n### Phase 1: Fix createApprovalNamespaces.ts\n- Remove isEvmChainId filter on lines 50-56 that silently drops non-EVM optional namespaces\n- Add DEFAULT_COSMOS_METHODS constant: ['cosmos_getAccounts', 'cosmos_signDirect', 'cosmos_signAmino']\n- Handle cosmos namespace in the optional namespaces section (same pattern as eip155)\n- Support cosmos accounts in CAIP-10 format: cosmos:cosmoshub-4:\u003cbech32addr\u003e\n\n### Phase 2: Complete CosmosRequestHandlerUtil.ts\n- Fix cosmos_signAmino handler: remove FIXME for fee (pass fee from signDoc), fix TODO comments\n- Implement cosmos_signDirect handler (currently returns hardcoded stub 'signedMessage')\n - Parse authInfoBytes and bodyBytes from signDoc\n - Route through chainAdapter.signTransaction with proper CosmosSignTx format\n- Add cosmos_getAccounts handler: return address + pubkey from portfolio state\n\n### Phase 3: Types \u0026 Events\n- Add cosmos request types for cosmos_getAccounts to types.ts\n- Ensure WalletConnectRequest union includes all cosmos types\n- Verify useWalletConnectEventsHandler routing is complete (it already handles cosmos methods)\n\n### Phase 4: Tests\n- Unit test CosmosRequestHandlerUtil for all three methods\n- Unit test createApprovalNamespaces with cosmos namespace proposals\n- Test that EVM-only wallets still work (no regression)\n\n### Key Files\n- src/plugins/walletConnectToDapps/utils/createApprovalNamespaces.ts (fix non-EVM filtering)\n- src/plugins/walletConnectToDapps/utils/CosmosRequestHandlerUtil.ts (complete implementation)\n- src/plugins/walletConnectToDapps/types.ts (add cosmos_getAccounts types)\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- External Cosmos dApp can connect to ShapeShift via WC and request cosmos_signAmino/cosmos_signDirect\n- createApprovalNamespaces properly includes cosmos accounts in session approval\n- cosmos_signDirect actually signs (not stub)\n- Unit tests pass\n- PR targets origin/develop as draft","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:20:22.424038+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:31:53.835124+01:00","closed_at":"2026-02-17T15:31:53.835124+01:00","close_reason":"PR #11914 opened - cosmos wc dApps support with getAccounts, signAmino, signDirect, namespace approval, session proposal, network selection","dependencies":[{"issue_id":"shapeshiftWeb-asl","depends_on_id":"shapeshiftWeb-4cm","type":"blocks","created_at":"2026-02-17T13:21:24.054409+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-asw","title":"Phase 4: performance quick wins (2 items)","description":"Hoist BigAmount.zero() constants, wrap TradeConfirmFooter BigAmount in useMemo. See PRD Phase 4.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:32:34.837706+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:42:09.328159+01:00","closed_at":"2026-02-13T11:42:09.328159+01:00","close_reason":"All items fixed, type-check passes"} -{"id":"shapeshiftWeb-axl","title":"Sanity-check adapter tx status implementation","description":"## Context\nAfter implementing `getTransactionStatus` on `SecondClassEvmAdapter`, we should review that change in isolation before migrating consumers.\n\n## Objective\nVerify the adapter implementation and tests look correct: inspect the diff, run targeted tests, and optionally sanity-check the new method against a known second-class transaction.\n\n## Acceptance Criteria\n- Review the diff from `shapeshiftWeb-pjf` (adapter + tests only) and confirm no unintended files changed.\n- Run the adapter unit tests (and any impacted suites) to ensure they pass.\n- (Optional but encouraged) Execute a quick script/ts-node snippet invoking `getTransactionStatus(txHash)` for a known second-class tx to confirm RPC mapping.\n- Document outcomes/notes for downstream consumers.\n\n## Dependencies\n- Depends on `shapeshiftWeb-pjf`.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T16:39:45.806919+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T16:59:33.693908+01:00","closed_at":"2026-02-16T16:59:33.693908+01:00","close_reason":"Reviewed pjf diff and ran SecondClassEvmAdapter vitest; changes scoped to adapter + test","dependencies":[{"issue_id":"shapeshiftWeb-axl","depends_on_id":"shapeshiftWeb-pjf","type":"blocks","created_at":"2026-02-16T16:39:57.700602+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-b0q","title":"Tron dApps: add TronSigningMethod to isSupportedSessionRequest","description":"In useWalletConnectEventsManager.ts, isSupportedSessionRequest() only includes EIP155_SigningMethod and CosmosSigningMethod in the supportedMethods array. TronSigningMethod is completely missing, so all incoming tron_signTransaction and tron_signMessage requests silently fail the type guard and are discarded. The user never sees a confirmation modal. Fix: add ...Object.values(TronSigningMethod) to supportedMethods array. File: src/plugins/walletConnectToDapps/eventsManager/useWalletConnectEventsManager.ts","status":"closed","priority":0,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:57:41.422607+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:37.195698+01:00","closed_at":"2026-02-18T17:02:37.195698+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-b2y","title":"BigAmount: migrate more consumer domains","description":"Migrate remaining consumer domains from old string-returning selectors to new BigAmount-returning ones. Domains: Trade/Swap selectors + UI, DeFi selectors + providers, Balance display + account components, RFOX/TCY/ThorChainLP pages, Yields/Lending/Send/WalletConnect. Each domain can be a separate PR or grouped. Pattern: same as Portfolio/Accounts migration in PR #11866.","status":"tombstone","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T18:47:00.304371+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:02:47.955647+01:00","deleted_at":"2026-02-13T19:02:47.955647+01:00","deleted_by":"daemon","delete_reason":"delete","original_type":"task"} -{"id":"shapeshiftWeb-b36","title":"Phase 2: dead code and redundant patterns (5 items)","description":"Remove dead selector, dead nullish coalescing, migrate missed ButterSwap file, fix type name, fix misleading comment. See PRD Phase 2.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:32:32.39024+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:38:52.310996+01:00","closed_at":"2026-02-13T11:38:52.310996+01:00","close_reason":"All 5 items fixed, type-check passes"} -{"id":"shapeshiftWeb-b37j","title":"PR1: Feature flag, config, CSP, and dependencies","description":"Set up ChainflipLending feature flag, config vars, CSP headers, and add npm deps.\n\nFiles to modify:\n- src/state/slices/preferencesSlice/preferencesSlice.ts: Add ChainflipLending to FeatureFlags type + initial state\n- src/config.ts: Add VITE_FEATURE_CHAINFLIP_LENDING (bool, default false) + VITE_CHAINFLIP_RPC_URL (url, default rpc.mainnet.chainflip.io)\n- src/test/mocks/store.ts: Add ChainflipLending: false\n- .env: Add VITE_FEATURE_CHAINFLIP_LENDING=false, VITE_CHAINFLIP_RPC_URL=https://rpc.mainnet.chainflip.io\n- .env.development: Add VITE_FEATURE_CHAINFLIP_LENDING=true\n- headers/csps/chainflip.ts: Add rpc.mainnet.chainflip.io to connect-src\n- package.json: Add scale-ts@^1.6.1, @chainflip/extrinsics@^1.6.2\n\nReference: existing ChainflipSwap/ChainflipDca flags in preferencesSlice.ts\n\nAcceptance:\n- yarn type-check passes\n- yarn lint --fix clean\n- Feature flag toggleable via /flags UI\n- CSP allows rpc.mainnet.chainflip.io","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:48:59.516472+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.330345+01:00","closed_at":"2026-02-23T17:09:20.330345+01:00","close_reason":"PR1 committed and draft PR opened (#12011)"} -{"id":"shapeshiftWeb-b8h","title":"PR1: remove AI spew JSDoc, keep only non-obvious docs","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:14.845136+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.595704+01:00","closed_at":"2026-02-13T17:33:51.595704+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-b8s","title":"Tron dApps: return full signed tx object from tron_signTransaction","description":"approveTronRequest returns { signature: signedTx.signature } but dApps using @tronweb3/walletconnect-tron expect a full signed transaction object (txID, raw_data, raw_data_hex, signature array) that can be passed to tronWeb.trx.sendRawTransaction(). Fix: reconstruct the full signed tx object from the original transaction + signature. File: src/plugins/walletConnectToDapps/utils/TronRequestHandlerUtil.ts line 62","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:57:46.775426+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:37.19697+01:00","closed_at":"2026-02-18T17:02:37.19697+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-bdj","title":"adjust affiliate bps constant from 55 to 60","description":"Per shapeshift/web#11919, change the constant that sets affiliate basis points from 55 to 60.","status":"in_progress","priority":2,"issue_type":"task","assignee":"gomesalexandre","owner":"contact@0xgom.es","created_at":"2026-02-17T17:25:44.18986+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T17:25:57.050245+01:00"} -{"id":"shapeshiftWeb-bk0","title":"WC Wallet: Bitcoin support (connect wallet)","description":"Add Bitcoin (BIP122) namespace support to the WalletConnect 'connect wallet' flow.\n\n## Mobile Wallets That Support BTC via WC QR\n- Xverse (confirmed, best documented BTC WC wallet)\n- OKX Wallet (probable, listed on WalletGuide with bip122 chain)\n- SafePal (unconfirmed but has pieces)\n- NOT Trust Wallet (EVM+SOL only for WC)\n- NOT Phantom mobile (in-app browser only)\n- NOT BlueWallet, Exodus, Zengo, Tangem (no bip122 WC)\n\n## Research Steps\n1. Read packages/hdwallet-core/src/bitcoin.ts for BTCWallet interface\n2. Read packages/hdwallet-core/src/wallet.ts for supportsBTC() guard\n3. Check Xverse WC docs for exact bip122 RPC method params/responses\n4. Read the universal-provider docs for bip122 namespace request() API\n5. Check @reown/appkit-adapter-bitcoin source for reference implementation\n\n## Implementation Details\n\n### Phase 1: Bitcoin Methods (packages/hdwallet-walletconnectv2/)\n- Create new file bitcoin.ts following ethereum.ts pattern\n- btcGetAddress(): extract from session.namespaces.bip122.accounts CAIP-10 format\n - Parse: bip122:000000000019d6689c085ae165831e93:\u003caddress\u003e -\u003e address\n- Handle sendTransfer: { account, recipientAddress, amount, memo? } -\u003e { txid }\n- Handle signPsbt: { account, psbt: base64, signInputs, broadcast? } -\u003e { psbt: base64, txid? }\n- Handle signMessage: { account, message, protocol? } -\u003e { signature, address }\n\n### Phase 2: HDWallet Class Updates (walletconnectV2.ts)\n- Change `readonly _supportsBTC = false` to `true`\n- Add `readonly _supportsBTCInfo = true`\n- Implement BTCWallet interface methods that make sense for WC\n- Store BTC address from session\n\n### Phase 3: Config Updates\n- Add bip122 to optionalNamespaces in config.ts\n- Chain: bip122:000000000019d6689c085ae165831e93\n- Methods: ['sendTransfer', 'signPsbt', 'signMessage', 'getAccountAddresses']\n- Events: ['bip122_addressesChanged']\n\n### Phase 4: Tests\n- Unit tests for bitcoin.ts methods\n- Mock UniversalProvider for test isolation\n\n### Key Files\n- packages/hdwallet-walletconnectv2/src/bitcoin.ts (NEW)\n- packages/hdwallet-walletconnectv2/src/walletconnectV2.ts (enable BTC)\n- packages/hdwallet-walletconnectv2/src/index.ts (export)\n- src/context/WalletProvider/WalletConnectV2/config.ts (add bip122 namespace)\n\n## Acceptance Criteria\n- yarn type-check passes, yarn lint --fix passes\n- User can scan QR with Xverse mobile and get BTC address\n- BTC PSBTs can be signed via WC\n- PR targets origin/develop as draft","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:21:09.922627+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:24:19.079983+01:00","closed_at":"2026-02-17T15:24:19.079983+01:00","close_reason":"Bitcoin WCV2 wallet support implemented in PR #11913","dependencies":[{"issue_id":"shapeshiftWeb-bk0","depends_on_id":"shapeshiftWeb-4cm","type":"blocks","created_at":"2026-02-17T13:21:23.99111+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-bs7","title":"add RBF opt-in sequence to Bitcoin transaction building","description":"In UtxoBaseAdapter.buildSendApiTransaction, set sequence: 0xfffffffe on all inputs when building Bitcoin transactions. This opts into BIP-125 RBF. Only Bitcoin — BCH, DOGE, LTC, ZEC should keep default behavior (0xffffffff). Acceptance: Bitcoin transactions built via chain-adapters include sequence: 0xfffffffe on every input.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:00:18.073531+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:01:50.925366+01:00","closed_at":"2026-02-14T11:01:50.925366+01:00","close_reason":"Added sequence: 0xfffffffe to Bitcoin inputs in UtxoBaseAdapter.buildSendApiTransaction. Only Bitcoin (not BCH/DOGE/LTC/ZEC)."} -{"id":"shapeshiftWeb-bvn","title":"BigAmount: migrate send + misc UI + walletconnect consumers","description":"Migrate 6 send/misc/walletconnect files from old string selectors to new BigAmount selectors. Files: Modals/Send/useSendDetails.tsx + test, ManageHiddenAssetsList.tsx, AssetRow.tsx, AssetChainRow.tsx, ArbitrumBridgeClaimModal.tsx, WalletConnectModalSigningFooter.tsx","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:02:59.486993+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.475218+01:00","closed_at":"2026-02-13T19:38:31.475218+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-bzz","title":"Implement solanaSignRawTransaction in hdwallet-trezor","description":"In packages/hdwallet-trezor/src/solana.ts: add solanaSignRawTransaction (deserialize base64, sign via transport.call solanaSignTransaction). Skip solanaSignMessage (Trezor Connect lacks it). Wire in packages/hdwallet-trezor/src/trezor.ts.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:43:10.905941+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:49:24.811713+01:00","closed_at":"2026-02-18T12:49:24.811713+01:00","close_reason":"Added solanaSignRawTransaction to Trezor adapter (no signMessage - Trezor Connect lacks it)","dependencies":[{"issue_id":"shapeshiftWeb-bzz","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:23.080964+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-c10","title":"WC dApps: NEAR support (ShapeShift as wallet)","description":"Add NEAR namespace support in WC-to-dApps flow. When ShapeShift acts as a wallet and an external NEAR dApp connects via WC, handle NEAR signing requests. Note: NEAR dApp ecosystem for WC is thinner than EVM (most use Wallet Selector adapters), but the protocol support exists.\n\n## Scope\n- Add NearSigningMethod enum to types.ts (near_signTransaction, near_signTransactions, near_signMessage, near_getAccounts, near_signIn, near_signOut)\n- Add NEAR request/response types to types.ts\n- Create NearRequestHandlerUtil.ts following EIP155RequestHandlerUtil pattern\n- Handle near_signTransaction: deserialize tx, sign via hdwallet nearSignTx\n- Handle near_signTransactions: batch sign\n- Handle near_signMessage: sign message (NEP-413)\n- Handle near_getAccounts: return NEAR accounts from portfolio\n- Update useWalletConnectEventsHandler.ts to route NEAR methods\n- Add WalletConnectModal entries for NEAR confirmation\n- Update createApprovalNamespaces.ts to handle near namespace\n- Unit tests for NearRequestHandlerUtil\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- External NEAR dApp can connect to ShapeShift via WC\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11906 | PR body must include: - tackles https://github.com/shapeshift/web/issues/11906 | Branch: fresh off origin/develop | PR: draft","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:49:56.615963+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T14:22:30.516945+01:00","closed_at":"2026-02-17T14:22:30.516945+01:00","close_reason":"NEAR WC dApps support dropped - no NEAR wallets support WalletConnect, ecosystem dead","dependencies":[{"issue_id":"shapeshiftWeb-c10","depends_on_id":"shapeshiftWeb-u8p","type":"blocks","created_at":"2026-02-17T13:50:02.624296+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-c8j","title":"Audit: perf nightmares (unnecessary BigAmount construction in hot paths)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:43.048003+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.800252+01:00","closed_at":"2026-02-13T11:31:46.800252+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-c9o","title":"p3: complete p2.5 send+misc — full improvement-audit-2 diff","description":"Update bigamount-send-misc branch to include ALL changes from improvement-audit-2.\n\nEXISTING files with deeper changes (7 files already in PR):\n- useSendDetails.tsx (+184 lines), useSendDetails.test.tsx (+14 lines)\n- ArbitrumBridgeClaimModal (+39 lines), ManageHiddenAssetsList (+5 lines)\n- WalletConnectModalSigningFooter (+2 lines)\n- AssetRow (+25 lines), AssetChainRow (+20 lines)\n\nNEW files to add (17):\n- src/components/DeFi/components/AssetInput.tsx\n- src/components/EarnDashboard/components/PositionDetails/StakingPositionsByProvider.tsx\n- src/components/Layout/Header/ActionCenter/components/ArbitrumBridgeWithdrawActionCard.tsx\n- src/components/Layout/Header/ActionCenter/components/Details/LimitOrderDetails.tsx\n- src/components/Layout/Header/ActionCenter/components/Notifications/RewardDistributionNotification.tsx\n- src/components/Layout/Header/ActionCenter/components/RewardDistributionActionCard.tsx\n- src/components/Layout/Header/ActionCenter/components/RfoxClaimActionCard.tsx\n- src/components/Layout/Header/ActionCenter/components/TcyClaimActionCard.tsx\n- src/components/Modals/ManageAccounts/components/ImportAccounts.tsx\n- src/components/Modals/RateChanged/RateChanged.tsx\n- src/components/Modals/Receive/ReceiveAmount.tsx\n- src/components/Modals/Send/hooks/useSendFees/useSendFees.tsx\n- src/components/Sweep.tsx\n- src/hooks/useActionCenterSubscribers/useLimitOrderActionSubscriber.tsx\n- src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SendTransactionContent.tsx\n- src/plugins/walletConnectToDapps/hooks/useCallRequestEvmFees.ts\n- src/plugins/walletConnectToDapps/hooks/useSimulateEvmTransaction.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, BN .toPrecision() semantic fix, rounding mode fixes.\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11871.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:38.710047+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:12.146715+01:00","closed_at":"2026-02-14T14:31:12.146715+01:00","close_reason":"All 49 send+misc files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-send-misc (PR #11871)"} -{"id":"shapeshiftWeb-cav","title":"Rework SpeedUpModal to fetch tx data on-demand","description":"Rewrite SpeedUpModal to fetch all needed data when opened instead of using stored RbfMeta. Flow: 1. Accept txHash + accountId + chainId (from action/tx metadata). 2. Use react-query to fetch original tx via unchained getTransaction(txHash) — get vin/vout. 3. For each vin, fetch the previous tx hex via getTransaction(vin.txid). 4. Derive addressNList from accountType + bip44Params + UTXO path. 5. Derive scriptType from accountType mapping. 6. Fetch current fee rates via chain adapter getFeeData(). 7. Build replacement BTCSignTx with higher fee rate, sign, and broadcast. 8. Update action slice with replacedByTxHash/replacesTxHash linking. Keep the existing UI (fee rate selector, fee diff display) but backed by fetched data.","status":"closed","priority":0,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:49:45.033027+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T12:01:56.206931+01:00","closed_at":"2026-02-14T12:01:56.206931+01:00","close_reason":"Reworked SpeedUpModal to fetch all tx data on-demand via unchained API (getTransaction, getUtxos, getFeeData). No stored RbfMeta. Uses httpProvider.getTransaction for original tx vin/vout, derives addressNList from UTXO paths, fetches previous tx hex for signing.","dependencies":[{"issue_id":"shapeshiftWeb-cav","depends_on_id":"shapeshiftWeb-dbh","type":"blocks","created_at":"2026-02-14T11:50:01.024607+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-cet","title":"Wire SolanaTransactionSimulation into SolanaTransactionContent","description":"Add SolanaTransactionSimulation component to SolanaTransactionCard in SolanaTransactionContent.tsx. Place it after the network row and before the program row (same position as TransactionSimulation in EVM TransactionContent). Pass the base64 transaction string as prop. No changes to EVM components.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T13:11:45.119826+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:19:36.09612+01:00","closed_at":"2026-02-18T13:19:36.09612+01:00","close_reason":"Wired SolanaTransactionSimulation into SolanaTransactionCard - shows balance changes (send/receive) above program details. Passed transaction string through SolanaTransactionCard for both single and multi-tx views.","dependencies":[{"issue_id":"shapeshiftWeb-cet","depends_on_id":"shapeshiftWeb-0dl","type":"blocks","created_at":"2026-02-18T13:12:30.417268+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-cgtg","title":"Cherry-pick Ink regen data into develop generated files","description":"Extract Ink (eip155:57073) entries from saved PR generated files. Merge into develop's generatedAssetData.json, relatedAssetIndex.json. Create coingecko adapter. Bump clearAssets migration. Regenerate manifest hashes + brotli/gzip compression.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:51:03.136273+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T13:56:30.878339+01:00","closed_at":"2026-02-19T13:56:30.878339+01:00","close_reason":"Added coingecko adapter, index.ts import/export, migration bump 293. User will run yarn generate:asset-data for actual regen.","dependencies":[{"issue_id":"shapeshiftWeb-cgtg","depends_on_id":"shapeshiftWeb-4uq9","type":"blocks","created_at":"2026-02-19T13:51:38.351227+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-cj5","title":"[Solana Wallet] _supportsETH hardcoded true for non-EVM sessions","description":"MEDIUM: _supportsETH is readonly true while _supportsCosmos/_supportsSolana are dynamic getters. For Solana-only WC wallets, supportsETH() returns true but ethGetAddress returns null. Fix: Make _supportsETH a dynamic getter checking session.namespaces.eip155. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_solana_wcv2_wallet","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:49:15.038568+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.691714+01:00","closed_at":"2026-02-18T16:58:33.691714+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-cn6","title":"Comment audit: ditched, modified, and missing comments review","description":"Review all BigAmount migration changes for: 1) useful comments wrongly removed, 2) comments that should be modified to reflect new BigAmount semantics, 3) places where comments should be added for clarity.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:22:52.627754+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:45:59.451986+01:00","closed_at":"2026-02-13T12:45:59.451986+01:00","close_reason":"Completed. STALE: TODO(gomes) in lpSelectors.ts outdated. REMOVED: Useful conversion step comments deleted. MISSING: Cross-precision patterns need comments. RENAME: 10+ vars still named *CryptoBaseUnit holding BigAmount objects."} -{"id":"shapeshiftWeb-cqw","title":"PR1: naming consistency pass (BigAmount vs bignumber.js conventions)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:15.035465+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.594728+01:00","closed_at":"2026-02-13T17:33:51.594728+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-cxa","title":"fix rounding modes in swapper amountOutMin and fee calculations","description":"6 locations: CowSwapper helpers.ts:112 slippage .toFixed(0) default rounding, SunioSwapper buildSwapRouteParameters.ts:40 same, ChainflipSwapper getQuoteOrRate.ts:312-317/375-380 price impact .toBaseUnit() no mode, ButterSwap getTradeQuote.ts:101 min amount and :170 gas fee .toBaseUnit() no mode, ChainflipSwapper helpers.ts:91 minimum rate .toFixed() default. All amountOutMin/slippage should ROUND_DOWN, fees should ROUND_UP.","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T13:04:03.742342+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:06:47.795732+01:00","closed_at":"2026-02-13T13:06:47.795732+01:00","close_reason":"Fixed 3 rounding mode bugs: CowSwapper amountOutMin ROUND_DOWN, SunioSwapper amountOutMin ROUND_DOWN, ChainflipSwapper minimumRate ROUND_DOWN. 3 other findings (Chainflip price impact, ButterSwap min error, ButterSwap gas fee) are display-only — negligible impact."} -{"id":"shapeshiftWeb-cza9","title":"PR1: JSON-RPC client and typed wrappers","description":"Create src/lib/chainflip/rpc.ts + src/lib/chainflip/rpc.test.ts.\n\nrpc.ts:\n- Generic JSON-RPC 2.0 client using fetch (POST, Content-Type: application/json, id auto-increment)\n- Typed wrappers for all CF lending RPCs:\n - cfLendingPools() -\u003e LendingPool[]\n - cfLendingConfig() -\u003e LendingConfig\n - cfLoanAccounts(scAccount) -\u003e LoanAccount[]\n - cfLendingPoolSupplyBalances(scAccount) -\u003e SupplyBalance[]\n - cfAccountInfoV2(scAccount) -\u003e AccountInfoV2\n - cfFreeBalances(scAccount) -\u003e FreeBalance[]\n - cfOraclePrices() -\u003e OraclePrice[]\n - cfSafeModeStatuses() -\u003e SafeModeStatus\n - stateGetRuntimeVersion() -\u003e RuntimeVersion\n - cfEncodeNonNativeCall(hexCall, blocksToExpiry, nonceOrAccount, signingScheme) -\u003e NonNativeCallResult\n - authorSubmitExtrinsic(hexExtrinsic) -\u003e TxHash\n\nrpc.test.ts:\n- Mock fetch for each wrapper\n- Verify JSON-RPC envelope structure (method, params, id)\n- Verify typed return values\n- Test error handling (RPC errors, network errors)\n\nReference: @chainflip/rpc package for method names/params. Verify against live RPC with curl.\n\nAcceptance:\n- All tests pass (npx vitest run src/lib/chainflip/rpc.test.ts)\n- Types match actual RPC responses from rpc.mainnet.chainflip.io","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:49:48.724716+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.332502+01:00","closed_at":"2026-02-23T17:09:20.332502+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-cza9","depends_on_id":"shapeshiftWeb-o51k","type":"blocks","created_at":"2026-02-23T14:56:51.281458+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-d3o","title":"Phase 3: consistency and cleanup (5 items)","description":"Remove redundant bnOrZero wrapping, use BigAmount.minus consistently, simplify round-trips, deduplicate fromBaseUnit calls. See PRD Phase 3.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:32:33.697461+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:40:53.649245+01:00","closed_at":"2026-02-13T11:40:53.649245+01:00","close_reason":"All 5 items fixed, type-check passes"} -{"id":"shapeshiftWeb-d5q","title":"Prepare draft PR for second-class tx status fix","description":"## Context\nAfter implementing adapter support, migrating consumers, and removing legacy helpers, we need to bundle the changes into a draft PR with the agreed template/testing notes.\n\n## Objective\nRun lint/type-check, ensure clean git status, commit with `feat: add getTransactionStatus to SecondClassEvmAdapter`, push to fork, and open a draft PR with the specified content.\n\n## Acceptance Criteria\n- `yarn lint --fix` and `yarn type-check` pass (or pre-existing warnings documented).\n- Git commit message: `feat: add getTransactionStatus to SecondClassEvmAdapter`.\n- PR description contains:\n - Intro referencing permalink to `adapter.httpProvider.getTransaction` (showing undefined issue)\n - Testing section with:\n - `- Do an across swap between second-class chains`\n - `- Ensure status detection is happy`\n - Screenshots section left empty.\n- Draft PR opened (not ready for review) on GitHub, pointing to fork branch.\n\n## Dependencies\n- Depends on `shapeshiftWeb-pjf`, `shapeshiftWeb-taw`, `shapeshiftWeb-h29`.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T16:38:27.155699+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T17:07:52.793265+01:00","closed_at":"2026-02-16T17:07:52.793265+01:00","close_reason":"Ran lint/type-check, pushed branch, opened draft PR 11895 with template + testing instructions","dependencies":[{"issue_id":"shapeshiftWeb-d5q","depends_on_id":"shapeshiftWeb-pjf","type":"blocks","created_at":"2026-02-16T16:51:53.96689+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-d5q","depends_on_id":"shapeshiftWeb-taw","type":"blocks","created_at":"2026-02-16T16:51:57.784491+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-d5q","depends_on_id":"shapeshiftWeb-h29","type":"blocks","created_at":"2026-02-16T16:52:00.996471+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-da3","title":"dispatch Pending claim action after unbonding yield exit","description":"In useYieldTransactionFlow.ts: after a yield exit (action='exit') completes, check yieldItem.mechanics.cooldownPeriod?.seconds \u003e 0. If yes (unbonding): dispatch a Pending action with displayType=GenericTransactionDisplayType.Claim, cooldownExpiryTimestamp=Date.now() + cooldownPeriod.seconds * 1000, yieldId=yieldItem.id. Message: 'actionCenter.yield.unstakeAvailableIn' with duration interpolation. If no cooldown: skip (direct unstake, just Complete as before).","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:39:00.181877+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:13:24.755844+01:00","closed_at":"2026-02-14T11:13:24.755844+01:00","close_reason":"Added claim action dispatch after unbonding yield exit. When action=exit and cooldownPeriod.seconds \u003e 0, dispatches a Pending Claim action with cooldownExpiryTimestamp and yieldId. Added i18n keys for yield claim states.","dependencies":[{"issue_id":"shapeshiftWeb-da3","depends_on_id":"shapeshiftWeb-77v","type":"blocks","created_at":"2026-02-14T10:40:05.208199+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-dbh","title":"Remove RbfMeta and revert handleSend","description":"1. Remove RbfMeta, RbfInput, RbfOutput types from actionSlice/types.ts. 2. Remove rbfMeta field from ActionGenericTransactionMetadata. 3. Keep replacedByTxHash and replacesTxHash fields. 4. Remove HandleSendResult type from Send/utils.ts. 5. Revert handleSend return type back to Promise\u003cstring\u003e (just txHash). 6. Remove all RBF metadata capture logic from handleSend. 7. Revert all callers of handleSend that destructure HandleSendResult: Form.tsx, QrCode/Form.tsx, Sweep.tsx, BorrowConfirm.tsx, useSendThorTx.tsx, useFormSend.tsx. 8. Remove rbfMeta from GenericTransactionNotification.tsx destructuring exclusion. 9. Clean up rbfMeta references in GenericTransactionActionCard.tsx eligibility check.","status":"closed","priority":0,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:49:36.480461+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:53:06.75889+01:00","closed_at":"2026-02-14T11:53:06.75889+01:00","close_reason":"Removed RbfMeta types, reverted handleSend to return string, reverted all 6 callers, removed rbfMeta from action metadata. Kept replacedByTxHash/replacesTxHash."} -{"id":"shapeshiftWeb-dhf","title":"PR4: swapper packages BigAmount migration","description":"Migrate swapper and related packages. 16 files: ButterSwap (getTradeQuote, getTradeRate, xhr param rename), ChainflipSwapper (getQuoteOrRate, helpers ROUND_DOWN), CowSwapper (helpers ROUND_DOWN), SunioSwapper (getQuoteOrRate, buildSwapRouteParameters ROUND_DOWN), thorchain-utils (getEvmData ROUND_DOWN, getCallDataFromQuote ROUND_DOWN, getL1RateOrQuote, getQuote), swapper/utils.ts, swap-widget (useMarketData, types), unchained-client solana parser. Includes amountOutMin ROUND_UP→ROUND_DOWN bug fixes. Medium risk.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:17.42284+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.301125+01:00","closed_at":"2026-02-14T13:25:59.301125+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-dhf","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.432305+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-dr8","title":"Clean up cosmos SDK references and imports","description":"Remove DefiProvider.CosmosSdk mapping from utils.ts, mappings.ts, and any dangling imports. Ensure type-check and lint pass.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:45:41.630841+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:03:17.559127+01:00","closed_at":"2026-02-18T13:03:17.559127+01:00","close_reason":"Removed all dead cosmos SDK defi code, type-check and lint clean"} -{"id":"shapeshiftWeb-dxi","title":"PR1: simplify BigAmountConfig to resolvePrecision only","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:15.222235+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.588516+01:00","closed_at":"2026-02-13T17:33:51.588516+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-e4n","title":"Implement solanaSignRawTransaction + solanaSignMessage in hdwallet-gridplus","description":"In packages/hdwallet-gridplus/src/solana.ts: add solanaSignRawTransaction (deserialize base64, client.sign with ed25519) and solanaSignMessage (same client.sign with raw message bytes). Wire in packages/hdwallet-gridplus/src/gridplus.ts.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:43:31.466557+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:51:19.225187+01:00","closed_at":"2026-02-18T12:51:19.225187+01:00","close_reason":"Added solanaSignRawTransaction and solanaSignMessage to GridPlus adapter","dependencies":[{"issue_id":"shapeshiftWeb-e4n","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:43.606557+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-e6j","title":"p3: complete p2.4 rfox/tcy/thorlp — full improvement-audit-2 diff","description":"Update bigamount-rfox-tcy-thorlp branch to include ALL changes from improvement-audit-2.\n\nEXISTING files with deeper changes (9 files already in PR):\n- StakeInput (+102 lines), AddLiquidityInput (+237 lines), RemoveLiquidityInput (+129 lines)\n- BridgeConfirm, StakeConfirm, UnstakeInput, ClaimConfirm, TCY StakeInput\n- src/lib/utils/thorchain/balance.ts (+116 lines)\n\nNEW files to add (16):\n- src/pages/RFOX/components/Overview/TotalStaked.tsx\n- src/pages/RFOX/components/Unstake/UnstakeConfirm.tsx\n- src/pages/RFOX/hooks/useCurrentApyQuery.ts\n- src/pages/RFOX/hooks/useCurrentEpochRewardsQuery.ts\n- src/pages/RFOX/hooks/useLifetimeRewardsQuery.ts\n- src/pages/TCY/components/Claim/ClaimStatus.tsx\n- src/pages/TCY/components/Claim/components/AssetClaimButton.tsx\n- src/pages/TCY/components/Overview.tsx\n- src/pages/TCY/components/Stake/StakeConfirm.tsx\n- src/pages/TCY/components/Unstake/UnstakeConfirm.tsx\n- src/pages/TCY/components/Unstake/UnstakeInput.tsx\n- src/pages/TCY/tcy.tsx\n- src/pages/ThorChainLP/components/ReusableLpStatus/TransactionRow.tsx\n- src/pages/ThorChainLP/Pool/Pool.tsx\n- src/pages/ThorChainLP/queries/hooks/usePool.ts\n- src/pages/ThorChainLP/queries/hooks/useUserLpData.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, variable renames, BigAmount .toFixed() fixes.\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11870.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:31.663425+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:12.07606+01:00","closed_at":"2026-02-14T14:31:12.07606+01:00","close_reason":"All 29 rfox/tcy/thorlp files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-rfox-tcy-thorlp (PR #11870)"} -{"id":"shapeshiftWeb-ed1","title":"create shared parseAndUpsertSecondClassChainTx utility + tests","description":"New file: src/lib/utils/secondClassChainTx.ts. Extracts the common parseTx + upsert + portfolio refresh logic used by both the yield flow (happy path) and the subscriber (background path). Pattern: check SECOND_CLASS_CHAINS.includes(chainId), get adapter via getChainAdapterManager(), call adapter.parseTx(txHash, address), dispatch txHistory.actions.onMessage, then dispatch portfolioApi.endpoints.getAccount.initiate for each accountId. Add tests at src/lib/utils/secondClassChainTx.test.ts covering: correct parseTx args, portfolio refresh dispatch, undefined adapter.parseTx, parseTx throwing. Reference: useSendActionSubscriber.tsx:265-298 for the inline version.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:38:34.842356+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:53:49.501573+01:00","closed_at":"2026-02-14T10:53:49.501573+01:00","close_reason":"Created shared parseAndUpsertSecondClassChainTx utility + tests (5 passing)"} -{"id":"shapeshiftWeb-f74","title":"add sequence support to hdwallet-trezor bitcoin signing","description":"Trezor currently lets the device handle sequence internally. Pass input.sequence through to the Trezor Connect signTransaction inputs when defined. Acceptance: Trezor btcSignTx includes sequence in each input when provided.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:07.089361+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.522603+01:00","closed_at":"2026-02-14T10:47:35.522603+01:00","close_reason":"Added sequence to Trezor Connect signTransaction input objects","dependencies":[{"issue_id":"shapeshiftWeb-f74","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:20.392753+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-ff8","title":"Audit: missing test coverage for BigAmount utils/helpers","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:40.644783+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.79895+01:00","closed_at":"2026-02-13T11:31:46.79895+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-g2a","title":"Remove cosmos plugin","description":"Remove src/plugins/cosmos/ — orphaned useStakingAction hook + utils","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:45:36.504802+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:03:17.558205+01:00","closed_at":"2026-02-18T13:03:17.558205+01:00","close_reason":"Removed all dead cosmos SDK defi code, type-check and lint clean"} -{"id":"shapeshiftWeb-g3m","title":"WalletConnectV2 optional chains gap","description":"## Context\nWalletConnectV2 config only exposes 8 core EVM chains, but the app enables Monad/HyperEvm/Plasma/Katana via feature flags and hdwallet support. Users on WCv2 can't connect to those chains even when enabled.\n\n## Objective\nAdd optional chain support for Monad, HyperEvm, Plasma, Katana (and future second-class EVM chains) in the WalletConnectV2 provider configuration so sessions can request them when feature flags are on.\n\n## Acceptance Criteria\n- walletConnectV2 optional chain arrays include Monad, HyperEvm, Plasma, Katana.\n- rpcMap covers each chain with the correct env-based RPC URL.\n- Feature flag gating ensures we only request chains that are enabled (avoid WC errors when flag off).\n- Manual test plan documented (WCv2 connect flow shows new chains selectable; regression on existing chains).\n\n## Notes\nInvestigate if viem has chain definitions for these networks; if not, define minimal chain objects locally.\n","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T15:50:58.262337+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T16:12:10.919437+01:00","closed_at":"2026-02-16T16:12:10.919437+01:00","close_reason":"Added feature-gated Monad/HyperEvm/Plasma/Katana optional chains + RPC map entries for WalletConnectV2 and reran lint/type-check"} -{"id":"shapeshiftWeb-gnl","title":"standardize fiat .toFixed(2) across yields pages","description":"17+ occurrences of .toFixed() without decimal args on fiat values across: YieldOpportunityStats.tsx:114-116, YieldDetail.tsx:190, YieldStats.tsx:66, YieldItem.tsx:116/118/220/256/281/304, YieldsList.tsx:603/633, YieldAssetDetails.tsx:301/363, YieldActivePositions.tsx:137/188/252. All fiat should use .toFixed(2).","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T13:04:10.229584+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:09:48.839635+01:00","closed_at":"2026-02-13T13:09:48.839635+01:00","close_reason":"False positive — all .toFixed() fiat values flow through Amount.Fiat component which handles formatting via toFiat(). Intermediate accumulations correctly preserve full precision. No display bugs."} -{"id":"shapeshiftWeb-gzbj","title":"PR1: SCALE encoders for all lending extrinsics","description":"Create src/lib/chainflip/scale.ts + src/lib/chainflip/scale.test.ts.\n\nscale.ts (using scale-ts library):\nSCALE codec encoders for every lending operation. Each takes typed params and returns hex bytes.\n\nEncoders needed:\n- encodeAddLenderFunds(asset, amount) - move free balance to lending pool\n- encodeRemoveLenderFunds(asset, amount) - move from lending pool to free balance\n- encodeRequestLiquidityDepositAddress(asset, boostFee?) - open deposit channel\n- encodeWithdrawAsset(amount, asset, destinationAddress) - egress to on-chain\n- encodeRegisterLpAccount() - register as LP (no params)\n- encodeRegisterLiquidityRefundAddress(chain, address) - set refund address per chain\n- encodeRequestLoan(borrowAsset, amount) - borrow against collateral\n- encodeAddCollateral(asset, amount) - add free balance to collateral\n- encodeRemoveCollateral(asset, amount) - remove collateral to free balance\n- encodeMakeRepayment(loanId, asset, amount) - repay loan\n- encodeBatch(calls[]) - Environment.batch (pallet 0x02, call 0x0b), max 10 calls, no nesting\n- encodeNonNativeSignedCall(signature, nonce, encodedCall) - outer extrinsic wrapper\n\nEach encoder must produce byte-perfect output matching pallet/call indices.\nspecVersion guard: throw if runtime version doesn't match expected.\n\nscale.test.ts:\n- Test each encoder against known-good hex output\n- Derive known-good hex by encoding via CF's own tools or bouncer test fixtures\n- Test encodeBatch with multiple calls, verify max 10 limit\n- Test specVersion guard\n\nReference: @chainflip/extrinsics types, @chainflip/scale (vault swap codecs for pattern), CF pallet source code.\n\nAcceptance:\n- All encoders produce correct hex verified against CF reference\n- specVersion guard works\n- Batch encoder respects max 10 limit\n- All tests pass","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:50:37.712202+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.33316+01:00","closed_at":"2026-02-23T17:09:20.33316+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-gzbj","depends_on_id":"shapeshiftWeb-o51k","type":"blocks","created_at":"2026-02-23T14:57:12.082161+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-h29","title":"Remove legacy second-class tx helpers","description":"## Context\nAfter adapters expose `getTransactionStatus` and all consumers switch to it, the helper modules in `src/lib/utils/{monad,hyperevm,plasma,katana}.ts` become dead code.\n\n## Objective\nRemove the obsolete helper functions and ensure the adapter pathway is the only source of truth for second-class EVM tx status.\n\n## Acceptance Criteria\n- Delete `get\u003cChain\u003eTransactionStatus` functions and any unused exports/imports in the four helper files.\n- Confirm no remaining references to those helpers (grep/tests) — all callers use the adapter method.\n- Adjust/add unit tests if necessary to reflect the new source of truth.\n\n## Dependencies\n- Depends on `shapeshiftWeb-pjf` (adapter method) and `shapeshiftWeb-taw` (consumer migration).","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T16:34:47.536514+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T17:05:12.410744+01:00","closed_at":"2026-02-16T17:05:12.410744+01:00","close_reason":"Removed unused second-class tx helper modules after migration; ran lint/type-check","dependencies":[{"issue_id":"shapeshiftWeb-h29","depends_on_id":"shapeshiftWeb-pjf","type":"blocks","created_at":"2026-02-16T16:34:55.951767+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-h29","depends_on_id":"shapeshiftWeb-taw","type":"blocks","created_at":"2026-02-16T16:35:03.016935+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-h3l","title":"Add SolanaSignRawTx + SolanaSignMessage interfaces to hdwallet-core","description":"Add SolanaSignRawTx (addressNList + rawTransaction base64 + optional pubKey), SolanaSignMessage (addressNList + message Uint8Array + optional pubKey), and SolanaSignedMessage (signature base64) types. Add optional solanaSignRawTransaction and solanaSignMessage methods to SolanaWallet interface. File: packages/hdwallet-core/src/solana.ts","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:42:39.878388+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:46:52.846225+01:00","closed_at":"2026-02-18T12:46:52.846225+01:00","close_reason":"Added SolanaSignRawTx, SolanaSignMessage, SolanaSignedMessage interfaces and optional solanaSignRawTransaction/solanaSignMessage methods to SolanaWallet"} -{"id":"shapeshiftWeb-h8k","title":"subscriber logic for cooldown expiry -\u003e ClaimAvailable transition","description":"In useGenericTransactionSubscriber (or new useYieldClaimSubscriber): for Pending actions with displayType=Claim and cooldownExpiryTimestamp: check Date.now() \u003e= cooldownExpiryTimestamp. When true: transition to ActionStatus.ClaimAvailable, update message to 'actionCenter.yield.unstakeReady'. Pattern matches useRfoxClaimActionSubscriber.tsx where it compares now \u003e= cooldownExpiryMs. Alternative: poll fetchAggregateBalances to detect exiting-\u003ewithdrawable/claimable transition (more accurate but requires API call).","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:39:04.580796+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:15:12.107675+01:00","closed_at":"2026-02-14T11:15:12.107675+01:00","close_reason":"Added cooldown expiry check to subscriber. For Pending Claim actions with cooldownExpiryTimestamp, polls every 60s. When Date.now() \u003e= cooldownExpiryTimestamp, transitions to ClaimAvailable with unstakeReady message. Added Claim to displayType allowlist.","dependencies":[{"issue_id":"shapeshiftWeb-h8k","depends_on_id":"shapeshiftWeb-da3","type":"blocks","created_at":"2026-02-14T10:40:05.284944+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-hs0","title":"Add replacedByTxHash / replacesTxHash to action metadata","description":"Add two optional string fields to ActionGenericTransactionMetadata: replacedByTxHash (set on original when replaced) and replacesTxHash (set on replacement linking to original). Trivial Redux state migration (new optional fields, no-op). Needed to track replacement chains and update UI when replacement confirms or original wins the race.","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-17T10:47:09.530756+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T10:47:09.530756+01:00"} -{"id":"shapeshiftWeb-hta","title":"assertNotBigAmount error message suggests misleading .toFixed()","status":"closed","priority":3,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T14:23:16.677171+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T14:23:50.632514+01:00","closed_at":"2026-02-13T14:23:50.632514+01:00","close_reason":"Changed error message to suggest .toPrecision() or .toBaseUnit() instead of misleading .toFixed()"} -{"id":"shapeshiftWeb-htu","title":"fix cross-precision sort crashes in staking/lp/yield selectors","description":"stakingSelectors.ts:479 uses .gte() between fiat BigAmounts with different asset precisions (USDT precision 6 vs NEAR precision 24). Same in lpSelectors.ts:198 and useYieldAsOpportunities.ts:127. Fix: use .toNumber() for cross-precision fiat comparisons.","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T13:04:00.96467+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:05:10.15313+01:00","closed_at":"2026-02-13T13:05:10.15313+01:00","close_reason":"False positive - all sort comparisons use bnOrZero() which returns BigNumber, not BigAmount. BigNumber .gte()/.eq() don't throw on cross-precision. fiatAmount is a string, not a BigAmount."} -{"id":"shapeshiftWeb-i5mv","title":"Tron dApps: fix prettier formatting in WalletConnectModalManager","description":"formatJsonRpcError call in WalletConnectModalManager.tsx has multi-line formatting that prettier wants collapsed. Will fail lint CI. Fix: run yarn lint --fix. File: src/plugins/walletConnectToDapps/WalletConnectModalManager.tsx line 177","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:57:57.194525+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:37.197732+01:00","closed_at":"2026-02-18T17:02:37.197732+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-i9r","title":"YieldClaimActionCard component + i18n keys","description":"New component in src/components/Layout/Header/ActionCenter/components/ActionCards/ (or extend GenericTransactionActionCard). States: Pending='Your {symbol} unstake will be available in {duration}' with countdown, ClaimAvailable='Your {symbol} unstake is ready to claim' with green Claim button, Claimed='Your {symbol} unstake was claimed' with View Transaction link. Claim button navigates to /yields/{yieldId}?action=claim\u0026passthrough=... Uses ClaimActionCard as base (same pattern as RfoxClaimActionCard). i18n keys in src/assets/translations/en/main.json: actionCenter.yield.unstakeAvailableIn, actionCenter.yield.unstakeReady, actionCenter.yield.unstakeClaimed.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:39:09.338781+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:23:34.726973+01:00","closed_at":"2026-02-14T11:23:34.726973+01:00","close_reason":"Extended GenericTransactionActionCard with yield claim support: isYieldClaim detection, handleClaimClick navigation, cooldownDuration display via dayjs.duration, conditional Claim button for ClaimAvailable status","dependencies":[{"issue_id":"shapeshiftWeb-i9r","depends_on_id":"shapeshiftWeb-h8k","type":"blocks","created_at":"2026-02-14T10:40:05.357271+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-ih9","title":"Type YieldTxData.method as Method instead of string","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T18:27:58.317231+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T18:35:55.286789+01:00","closed_at":"2026-02-13T18:35:55.286789+01:00","close_reason":"Closed"} -{"id":"shapeshiftWeb-ixp","title":"add sequence support to hdwallet-native bitcoin signing","description":"Native wallet uses bitcoinjs-lib PSBT which defaults sequence to 0xffffffff. Pass input.sequence through to PSBT addInput when defined. Acceptance: when sequence is provided in BTCSignTxInput, the PSBT input uses that value instead of the default.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:02.536965+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.308161+01:00","closed_at":"2026-02-14T10:47:35.308161+01:00","close_reason":"Added sequence pass-through to PSBT addInput in native bitcoin signing","dependencies":[{"issue_id":"shapeshiftWeb-ixp","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:18.971559+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-jbf","title":"PR1: fix docs/bigamount.md and CLAUDE.md future-state references","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T17:21:14.941951+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T17:33:51.590388+01:00","closed_at":"2026-02-13T17:33:51.590388+01:00","close_reason":"All PR1 cleanup completed and pushed as single squashed commit to PR #11864"} -{"id":"shapeshiftWeb-jeo","title":"[BTC Wallet] getPublicKeys returns empty, breaks account discovery","description":"CRITICAL: getPublicKeys() in WC wallet returns empty array. When chain adapter calls wallet.getPublicKeys() during deriveUtxoAccountIdsAndMetadata, it gets [], then throws 'error getting public key from wallet'. BTC accounts never discovered. Fix: Override getPublicKeys to return bc1q address as fake xpub like Phantom does. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":0,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:47:07.600849+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.078481+01:00","closed_at":"2026-02-18T17:02:53.078481+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-jil","title":"WC Wallet: Solana support (connect wallet)","description":"Add Solana namespace support to the WalletConnect 'connect wallet' flow. When a user selects WC as a wallet and scans with Phantom/Solflare/Trust Wallet/Backpack mobile, ShapeShift should handle the solana namespace.\n\n## Mobile Wallets That Support Solana via WC QR\n- Phantom (extension only, NOT mobile QR - uses in-app browser)\n- Solflare (confirmed mobile QR)\n- Trust Wallet (confirmed mobile QR, listed in WalletGuide)\n- Backpack (confirmed, WCT airdrop partner)\n- OKX Wallet (confirmed mobile QR)\n- Binance Wallet (confirmed)\n\n## Research Steps\n1. Read packages/hdwallet-core/src/solana.ts for SolanaWallet interface (solanaGetAddress, solanaSignTx, solanaSendTx)\n2. Read packages/hdwallet-core/src/wallet.ts for supportsSolana() guard\n3. Check how hdwallet-native implements SolanaWallet for reference\n4. Read the universal-provider docs for solana namespace request() API\n5. Check packages/hdwallet-walletconnectv2/src/ethereum.ts for the pattern to follow\n\n## Implementation Details\n\n### Phase 1: Solana Methods (packages/hdwallet-walletconnectv2/)\n- Create new file solana.ts following ethereum.ts pattern\n- solanaGetAddress(): extract pubkey from session.namespaces.solana.accounts CAIP-10 format\n - Parse: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:\u003cbase58-pubkey\u003e -\u003e pubkey\n- solanaSignTx(msg: SolanaSignTx): \n - Build VersionedTransaction using solanaBuildTransaction() from hdwallet-core\n - Serialize to base64\n - Call provider.request({ method: 'solana_signTransaction', params: { transaction: base64 } }, 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp')\n - Parse response signature\n- solanaSendTx(msg: SolanaSignTx):\n - Same as above but use solana_signAndSendTransaction method\n - Return tx signature\n\n### Phase 2: HDWallet Class Updates (walletconnectV2.ts)\n- Add `readonly _supportsSolana = true` and `readonly _supportsSolanaInfo = true`\n- Implement SolanaWallet interface: solanaGetAddress, solanaSignTx, solanaSendTx\n- Add solanaGetAccountPaths, solanaNextAccountPath from hdwallet-core helpers\n- Store solana address from session (like ethAddress pattern)\n\n### Phase 3: Config Updates\n- Add solana to optionalNamespaces in config.ts\n- Add Solana RPC URL from env config (VITE_SOLANA_NODE_URL)\n- Methods: ['solana_signTransaction', 'solana_signAndSendTransaction', 'solana_signMessage', 'solana_signAllTransactions']\n\n### Phase 4: Tests\n- Unit tests for solana.ts (solanaGetAddress, solanaSignTx, solanaSendTx)\n- Mock UniversalProvider for test isolation\n\n### Key Files\n- packages/hdwallet-walletconnectv2/src/solana.ts (NEW)\n- packages/hdwallet-walletconnectv2/src/walletconnectV2.ts (add Solana interface)\n- packages/hdwallet-walletconnectv2/src/index.ts (export)\n- src/context/WalletProvider/WalletConnectV2/config.ts (add solana namespace)\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- User can scan QR with Solflare/Trust Wallet mobile and get solana address\n- Solana transactions can be signed and broadcast via WC\n- PR targets origin/develop as draft","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:20:34.414235+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:31:56.909527+01:00","closed_at":"2026-02-17T15:31:56.909527+01:00","close_reason":"Solana WCV2 wallet support implemented in PR #11911","dependencies":[{"issue_id":"shapeshiftWeb-jil","depends_on_id":"shapeshiftWeb-4cm","type":"blocks","created_at":"2026-02-17T13:21:23.875025+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-kap","title":"Implement Across swapper types and constants","description":"Create the core type definitions and constants for the Across swapper.\n\nFiles to create:\n- packages/swapper/src/swappers/AcrossSwapper/utils/types.ts\n- packages/swapper/src/swappers/AcrossSwapper/constant.ts\n- packages/swapper/src/swappers/AcrossSwapper/index.ts\n\ntypes.ts (~250 lines) — based on live API response shapes from ACROSS_RESEARCH.md Section 5:\n- AcrossSwapApprovalResponse (main quote response)\n - swapTx has 'ecosystem' field: 'evm' | 'svm' — this is the discriminator for execution path\n - swapTx.data is hex for EVM, base64 for Solana\n- AcrossDepositStatus (status polling response)\n- AcrossError (error response)\n- AcrossTokenInfo, AcrossSwapStep, AcrossBridgeStep, AcrossFeePart, AcrossFeeBreakdown\n- AcrossTradeInputParams\u003c'quote' | 'rate'\u003e (discriminated union like Relay)\n\nconstant.ts:\n- chainIdToAcrossChainId mapping (CAIP-2 → Across chain IDs):\n ethChainId → 1, arbitrumChainId → 42161, baseChainId → 8453, bscChainId → 56,\n optimismChainId → 10, polygonChainId → 137, hyperEvmChainId → 999,\n monadChainId → 143, plasmaChainId → 9745, solanaChainId → 34268394551451\n- acrossChainIdToChainId (reverse mapping)\n- ACROSS_SUPPORTED_CHAIN_IDS array\n- Error code → TradeQuoteError mapping (INVALID_PARAM, AMOUNT_TOO_LOW, etc.)\n- Native asset address handling (EVM: 0x0, Solana: 11111111111111111111111111111111)\n\nCRITICAL: appFee uses decimal percentage (0-1), NOT basis points. Conversion: affiliateBps / 10000.\n\nAcceptance criteria:\n- All types match live API responses (verified via curls in ACROSS_RESEARCH.md Section 14)\n- Chain mapping covers all 10 overlapping chains\n- No lint/type errors","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:19:31.371033+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:34.445132+01:00","closed_at":"2026-02-13T19:38:34.445132+01:00","close_reason":"Created types.ts with all API response types (AcrossSwapApprovalResponse, AcrossDepositStatus, AcrossError, etc.), constant.ts with chain ID mappings for 10 chains, error code mapping, native asset addresses, and dummy addresses. Lint and type-check pass.","dependencies":[{"issue_id":"shapeshiftWeb-kap","depends_on_id":"shapeshiftWeb-vd8","type":"blocks","created_at":"2026-02-13T19:20:21.480069+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-kfgz","title":"PR2: Page layout, routing, and account context","description":"Replace the empty ChainflipLendingPage with real routing and layout.\n\nChainflipLendingPage.tsx:\n- React Router routes: / -\u003e Overview (default), /supply -\u003e SupplyTab, /borrow -\u003e BorrowTab, /pool/:asset -\u003e Pool detail\n- Wrap all routes in ChainflipAccountProvider\n\nChainflipLendingHeader.tsx:\n- Page header with [Overview | Supply | Borrow] TabMenu\n- Aggregated stats cards (Total Supplied, Available Liquidity, Total Borrowed) from lendingPools() + oraclePrices() queries\n- Global account switcher (top-right)\n- Responsive: stacks on mobile\n\nChainflipAccountContext.tsx:\n- Global account selection context (like Yields YieldAccountContext)\n- useChainflipLendingAccount() hook: { accountId, accountNumber, setAccountId, scAccount }\n- Derives SC account from selected EVM account via ethAddressToScAccount\n- Falls back to first EVM account if none selected\n\nReference: src/pages/Yields/YieldAccountContext.tsx, src/pages/Yields/Yields.tsx\n\nAcceptance:\n- /chainflip-lending shows header with 3 tabs\n- Tabs route correctly\n- Account switcher visible when wallet connected\n- Stats cards show live data from mainnet\n- Mobile responsive","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12006","status":"open","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:52:16.654873+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:43:54.580209+01:00","dependencies":[{"issue_id":"shapeshiftWeb-kfgz","depends_on_id":"shapeshiftWeb-1gly","type":"blocks","created_at":"2026-02-23T14:58:32.164647+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-kfgz","depends_on_id":"shapeshiftWeb-kq0r","type":"blocks","created_at":"2026-02-23T14:58:37.370462+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-kfgz","depends_on_id":"shapeshiftWeb-mwbz","type":"blocks","created_at":"2026-02-23T14:58:47.731418+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-kg5u","title":"Implement signPsbt in BIP122RequestHandlerUtil","description":"## Context\nsignPsbt in BIP122RequestHandlerUtil.ts currently throws 'signPsbt is not yet fully supported'. The WC BIP122 signPsbt method sends a pre-built PSBT (base64) that needs signing at specified input indices.\n\n## What\nImplement the signPsbt case in approveBIP122Request:\n\n1. **Fix type**: Update BIP122SignPsbtCallRequestParams.signInputs from Record\u003cstring, number[]\u003e to the actual WC spec format: array of { address: string, index: number, sighashTypes: number[] }. The actual request from dApps uses this array format (confirmed by user testing).\n\n2. **Implementation**:\n - Parse PSBT from base64 using @shapeshiftoss/bitcoinjs-lib: Psbt.fromBase64(psbt)\n - For each signInput entry, sign the input at the specified index\n - Use wallet.btcSignMessage's key derivation approach: DEFAULT_BTC_ADDRESS_N_LIST (m/84'/0'/0'/0/0) with SpendWitness script type\n - For hdwallet-native: get the key pair and use psbt.signInput(index, keyPair) directly\n - Actually, since we don't have direct PSBT signing in hdwallet, use a simpler approach:\n - The PSBT contains the unsigned tx and UTXO data\n - Extract inputs/outputs from PSBT\n - Reconstruct btcSignTx params from the PSBT data\n - Call wallet.btcSignTx to get the signed tx\n - Return the signed tx hex (not PSBT) since broadcast handling is separate\n - Or even simpler: since we have bitcoinjs-lib available and the wallet can sign, parse PSBT, sign each input with the keypair derived from addressNList, finalize, and extract\n - For the WC response: return { psbt: signedPsbtBase64 } if broadcast=false, or { txid } if broadcast=true\n\n3. **Response format** per WC BIP122 spec:\n - broadcast=false: return { psbt: \"\u003cbase64 signed PSBT\u003e\" }\n - broadcast=true: broadcast via chain adapter, return { txid: \"\u003chex txid\u003e\" }\n\n## Files\n- src/plugins/walletConnectToDapps/utils/BIP122RequestHandlerUtil.ts - implement signPsbt case\n- src/plugins/walletConnectToDapps/types.ts - fix BIP122SignPsbtCallRequestParams.signInputs type\n\n## Notes\n- The wallet must supportsBTC(wallet) (already checked at handler entry)\n- Use DEFAULT_BTC_ADDRESS_N_LIST for key derivation (same as signMessage)\n- For broadcast=true, need chainAdapter - may need to add chainId/chainAdapter to ApproveBIP122RequestArgs","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T17:17:00.945744+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:27:20.701671+01:00","closed_at":"2026-02-18T17:27:20.701671+01:00","close_reason":"Implemented signPsbt: parses PSBT from base64, extracts inputs/outputs, reconstructs btcSignTx-compatible params (handles both witnessUtxo and nonWitnessUtxo paths), signs via wallet.btcSignTx, supports broadcast flag. Fixed signInputs type to match WC BIP122 spec (array of {address, index, sighashTypes} instead of Record)."} -{"id":"shapeshiftWeb-kjp","title":"add sequence support to hdwallet-ledger bitcoin signing","description":"Ledger currently explicitly uses empty sequences array (bitcoin.ts:355-371) with a comment about RBF/locktime issues. Update to pass sequence values from inputs when provided, defaulting to current behavior (0xffffffff) when not. Acceptance: Ledger btcSignTx passes per-input sequence values to the Ledger transport when defined.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:05.331055+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.420727+01:00","closed_at":"2026-02-14T10:47:35.420727+01:00","close_reason":"Built sequences array from input.sequence values, passed to both Zcash and non-Zcash Ledger signing paths","dependencies":[{"issue_id":"shapeshiftWeb-kjp","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:19.656709+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-kq0r","title":"PR1: React Query factories for CF lending RPCs","description":"Create src/react-queries/queries/chainflipLending.ts and register in src/react-queries/index.ts.\n\nUses createQueryKeys('chainflipLending', { ... }) pattern from @lukemorales/query-key-factory.\n\nQuery factories:\n- lendingPools() -\u003e cfLendingPools(), staleTime 30s\n- lendingConfig() -\u003e cfLendingConfig(), staleTime 5min\n- supplyBalances(scAccount) -\u003e cfLendingPoolSupplyBalances(scAccount), staleTime 30s\n- freeBalances(scAccount) -\u003e cfFreeBalances(scAccount), staleTime 15s\n- loanAccounts(scAccount) -\u003e cfLoanAccounts(scAccount), staleTime 15s\n- oraclePrices() -\u003e cfOraclePrices(), staleTime 15s\n- safeModeStatuses() -\u003e cfSafeModeStatuses(), staleTime 60s\n- runtimeVersion() -\u003e stateGetRuntimeVersion(), staleTime Infinity\n- accountInfo(scAccount) -\u003e cfAccountInfoV2(scAccount), staleTime 30s\n\nAll queries should:\n- Use typed return values from types.ts\n- Be enabled/disabled based on feature flag\n- Account-scoped queries should be disabled when no scAccount\n\nReference: src/react-queries/queries/common.ts for createQueryKeys pattern.\n\nAcceptance:\n- All query factories compile\n- Registered in react-queries/index.ts\n- Feature flag gating works\n- yarn type-check passes","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:51:24.753007+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.334972+01:00","closed_at":"2026-02-23T17:09:20.334972+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-kq0r","depends_on_id":"shapeshiftWeb-cza9","type":"blocks","created_at":"2026-02-23T14:57:54.152748+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-l5v","title":"Implement solanaSignRawTransaction in hdwallet-phantom","description":"In packages/hdwallet-phantom/src/solana.ts: add solanaSignRawTransaction (deserialize base64, provider.signTransaction). Skip solanaSignMessage for now (type not exposed). Wire in packages/hdwallet-phantom/src/phantom.ts.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:43:21.218053+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:50:24.419639+01:00","closed_at":"2026-02-18T12:50:24.419639+01:00","close_reason":"Added solanaSignRawTransaction to Phantom adapter (no signMessage yet - type not exposed)","dependencies":[{"issue_id":"shapeshiftWeb-l5v","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:33.382706+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-l6zn","title":"Add Ink native to ETH related asset index + recompress","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-19T16:09:45.315585+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T16:12:14.214097+01:00","closed_at":"2026-02-19T16:12:14.214097+01:00","close_reason":"Closed"} -{"id":"shapeshiftWeb-las","title":"add sequence support to hdwallet-phantom and hdwallet-vultisig UTXO providers","description":"Phantom and Vultisig use UTXO provider abstraction that doesn't expose sequence. Update the UTXO provider interface and both implementations to pass through sequence when defined. Acceptance: both Phantom and Vultisig btcSignTx pass sequence values through their UTXO providers.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:11.051574+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.712194+01:00","closed_at":"2026-02-14T10:47:35.712194+01:00","close_reason":"Added sequence to PSBT addInput for both Phantom and Vultisig","dependencies":[{"issue_id":"shapeshiftWeb-las","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:21.922573+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-ld4","title":"Wire SolanaTransactionContent into signing modal","description":"Replace the raw base64 truncated display in SolanaSignMessageConfirmation.tsx with the new SolanaTransactionContent component.\n\nChanges in SolanaContent (the switch/case inside SolanaSignMessageConfirmation.tsx):\n\n- SOLANA_SIGN_TRANSACTION / SOLANA_SIGN_AND_SEND_TRANSACTION:\n Replace the ModalSection + Card + truncated RawText with \u003cSolanaTransactionContent transaction={base64string} /\u003e\n \n- SOLANA_SIGN_ALL_TRANSACTIONS:\n Replace the ModalSection + Card + mapped truncated RawTexts with \u003cSolanaTransactionContent transactions={base64array} /\u003e\n (component handles array internally)\n\n- SOLANA_SIGN_MESSAGE:\n Keep as-is (\u003cMessageContent message={message} /\u003e) - this is already good\n\nThe SolanaTransactionContent component handles its own graceful fallback (shows raw base64 if parsing fails), so no error boundary needed at this level.\n\nAcceptance criteria:\n- Jupiter signAndSendTransaction shows parsed transaction details (not raw base64)\n- signMessage still shows the human-readable message (no regression)\n- signAllTransactions shows parsed details for each tx\n- If a dApp sends corrupt transaction data, modal still renders (graceful fallback)\n- EVM modals completely untouched","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:21:37.778014+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:28:33.921243+01:00","closed_at":"2026-02-18T12:28:33.921243+01:00","close_reason":"Wired SolanaTransactionContent into SolanaSignMessageConfirmation - signTransaction/signAndSendTransaction show parsed tx details, signAllTransactions shows multi-tx parsed view, signMessage unchanged. Graceful fallback to raw base64 on parse failure.","dependencies":[{"issue_id":"shapeshiftWeb-ld4","depends_on_id":"shapeshiftWeb-pys","type":"blocks","created_at":"2026-02-18T12:22:02.241573+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-lkx","title":"useSimulateSolanaTransaction hook","description":"Create src/plugins/walletConnectToDapps/hooks/useSimulateSolanaTransaction.ts. React Query hook mirroring useSimulateEvmTransaction but for Solana. Takes { transaction: string (base64) }. Internally: get chain adapter via assertGetSolanaChainAdapter(solanaChainId), get connection via adapter.getConnection(), call simulateSolanaTransaction. Query key: ['solanaSimulation', transaction]. staleTime: 60s, retry: false. Return { simulationQuery }. No EVM/Tenderly imports.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T13:11:24.373753+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:15:57.15629+01:00","closed_at":"2026-02-18T13:15:57.15629+01:00","close_reason":"Created useSimulateSolanaTransaction hook with React Query, mirrors EVM hook pattern","dependencies":[{"issue_id":"shapeshiftWeb-lkx","depends_on_id":"shapeshiftWeb-46k","type":"blocks","created_at":"2026-02-18T13:12:09.901972+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-lm7h","title":"Create cherry-pick-regen skill","description":"Create .claude/commands/cherry-pick-regen.md in the REPO as a reusable enforceable contract for cherry-picking chain-specific regen data from PRs. Covers: pre-merge extraction, merge strategy, cherry-pick by chainId prefix, migration bump, manifest regen (SHA-256 first 8 hex), compression (brotli quality 11 text, gzip level 9), sanity verification.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:51:13.533138+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T13:57:56.808278+01:00","closed_at":"2026-02-19T13:57:56.808278+01:00","close_reason":"Created .claude/commands/cherry-pick-regen.md - covers extraction, merge, manifest, compression, verification"} -{"id":"shapeshiftWeb-lzh","title":"Audit: fiat/USD BigAmount operations safety (toUserCurrency, toUSD, price math)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:49.822837+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.802709+01:00","closed_at":"2026-02-13T11:31:46.802709+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-m47","title":"speed up button on pending BTC transactions","description":"Add a 'Speed Up' button to pending Bitcoin send transactions in the transaction history / action center. Only show for actions with rbfMeta defined and status Pending. The button opens the SpeedUp modal.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:44.7102+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:35:25.574055+01:00","closed_at":"2026-02-14T11:35:25.574055+01:00","close_reason":"Added speed up button to GenericTransactionActionCard for RBF-eligible pending BTC sends","dependencies":[{"issue_id":"shapeshiftWeb-m47","depends_on_id":"shapeshiftWeb-9kx","type":"blocks","created_at":"2026-02-14T11:13:55.987918+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-mwbz","title":"PR1: SC account derivation from ETH address","description":"Create src/lib/chainflip/account.ts + src/lib/chainflip/account.test.ts.\n\naccount.ts:\n- ethAddressToScAccount(ethAddress: string): string\n - Left-pad 20-byte ETH address to 32 bytes\n - SS58 encode with prefix 2112\n - Returns SS58 string (deterministic, no RPC needed)\n- getChainflipAccountStatus(scAccount: string): Promise\u003cAccountStatus\u003e\n - Calls cfAccountInfoV2, returns { exists, isFunded, isLpRegistered, flipBalance }\n- isAccountFunded(scAccount: string): Promise\u003cboolean\u003e\n\naccount.test.ts:\n- Test known ETH address -\u003e SC account mappings from CF bouncer fixtures\n- Reference: bouncer/shared/utils.ts externalChainToScAccount function in chainflip-io/chainflip-backend repo\n- Test edge cases: checksummed vs lowercase ETH addresses, 0x prefix handling\n- Mock RPC for status checks\n\nAcceptance:\n- ethAddressToScAccount produces correct SS58 for known addresses\n- All tests pass","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:50:12.042694+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.333761+01:00","closed_at":"2026-02-23T17:09:20.333761+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-mwbz","depends_on_id":"shapeshiftWeb-o51k","type":"blocks","created_at":"2026-02-23T14:57:01.641896+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-n0q","title":"handle replacement tx confirmation in subscriber","description":"Update useSendActionSubscriber to handle RBF replacement scenarios: when a replacement tx confirms, mark original as replaced. When original confirms (replacement lost race), mark replacement as dropped. Use replacesTxHash/replacedByTxHash to link actions.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:49.96511+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:35:26.799549+01:00","closed_at":"2026-02-14T11:35:26.799549+01:00","close_reason":"Updated completeAction in useSendActionSubscriber to handle replacement tx linking via replacesTxHash","dependencies":[{"issue_id":"shapeshiftWeb-n0q","depends_on_id":"shapeshiftWeb-9kx","type":"blocks","created_at":"2026-02-14T11:13:56.22973+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-o4u1","title":"Respect wallet EIP-1559 support in yield EVM tx gas params","description":"Bug: executeEvmTransaction in src/lib/yieldxyz/executeTransaction.ts passes yield.xyz API's EIP-1559 gas params (maxFeePerGas/maxPriorityFeePerGas) directly to the wallet without checking ethSupportsEIP1559(). Ledger's ethSignTx only reads msg.gasPrice (undefined for EIP-1559 txs) -\u003e builds legacy tx with gasPrice=0 -\u003e broadcast fails with 'transaction underpriced'. Also affects Trezor.\n\nFix: Before building txToSign, check wallet.ethSupportsEIP1559(). If false and parsed tx has EIP-1559 params, use gasPrice branch with fallback: parsed.gasPrice ?? parsed.maxFeePerGas. Using maxFeePerGas as gasPrice is safe (protocol charges actual base fee, slightly overpays at most).\n\nFiles:\n- src/lib/yieldxyz/executeTransaction.ts (executeEvmTransaction function ~line 159)\n- Import supportsETH from @shapeshiftoss/hdwallet-core\n\nAcceptance: Ledger ETH mainnet yield txs broadcast successfully. gasPrice derived from maxFeePerGas when wallet doesn't support EIP-1559.","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-19T09:25:27.420659+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T09:43:39.806361+01:00","closed_at":"2026-02-19T09:43:39.806361+01:00","close_reason":"Added ethSupportsEIP1559 check in executeEvmTransaction, falls back to maxFeePerGas as gasPrice for Ledger/Trezor"} -{"id":"shapeshiftWeb-o51k","title":"PR1: Chainflip lending constants and types","description":"Create src/lib/chainflip/constants.ts and src/lib/chainflip/types.ts.\n\nconstants.ts:\n- CF_RPC_URL (from config)\n- Pallet/call indices for all lending extrinsics (addLenderFunds, removeLenderFunds, requestLiquidityDepositAddress, withdrawAsset, registerLpAccount, registerLiquidityRefundAddress, requestLoan, addCollateral, makeRepayment, removeCollateral)\n- Environment.batch indices (pallet 0x02, call 0x0b)\n- CF asset enum mappings (Btc, Eth, Sol, Usdc, Usdt, Flip, etc.) to CAIP AssetIds\n- Contract addresses: FLIP ERC-20 (0x826180541412d574cf1336d22c0c0a287822678a), State Chain Gateway (0x6995ab7c4d7f4b03f467cf4c8e920427d9621dbd)\n- BLOCKS_TO_EXPIRY = 120\n- CHAINFLIP_SPEC_VERSION = 20012\n- SS58_PREFIX = 2112\n- LTV thresholds: 80/85/88/90/93/95%\n\ntypes.ts:\n- RPC response types: LendingPool, LendingConfig, LoanAccount, SupplyBalance, OraclePrice, FreeBalance, SafeModeStatus, AccountInfoV2\n- NonNativeCallResult, DepositChannelEvent types\n- Permill/Perbill type aliases\n- CF asset enum type\n\nResearch pallet/call indices from CF source (chainflip-io/chainflip-backend) and live RPC. Use @chainflip/extrinsics types for guidance.\n\nAcceptance:\n- All types compile cleanly\n- Constants match live mainnet values (verify via curl to rpc.mainnet.chainflip.io)","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12005","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:49:24.383171+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T17:09:20.331854+01:00","closed_at":"2026-02-23T17:09:20.331854+01:00","close_reason":"PR1 committed and draft PR opened (#12011)","dependencies":[{"issue_id":"shapeshiftWeb-o51k","depends_on_id":"shapeshiftWeb-b37j","type":"blocks","created_at":"2026-02-23T14:56:41.025816+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-o9m","title":"[BTC Wallet] missing isWalletConnectV2 in UTXO account derivation","description":"CRITICAL: deriveUtxoAccountIdsAndMetadata in src/lib/account/utxo.ts tries all 3 account types. WC BIP122 only provides a single address, so only SegwitNative should be used. Add isWalletConnectV2(wallet) check like Phantom. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":0,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:47:33.924279+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.080363+01:00","closed_at":"2026-02-18T17:02:53.080363+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-ob0t","title":"PR2: Deposit to State Chain modal with linear stepper","description":"Full deposit-to-state-chain flow as a separate explicit action. Full-page modal with linear stepper.\n\nHooks:\n- hooks/useChainflipAccount.ts: Derives SC account from EVM wallet, checks if funded via cfAccountInfoV2, returns { scAccount, isFunded, isLpRegistered, flipBalance, isLoading }\n- hooks/useChainflipPools.ts: Wraps lendingPools() query + oraclePrices() for fiat display. Maps CF assets to CAIP AssetIds.\n- hooks/useSignChainflipCall.ts: React useMutation wrapping the EIP-712 signChainflipCall util. Returns { signAndSubmit, isLoading, error }. Used by all action modals.\n\nDeposit components:\n- Pool/components/Deposit/DepositModal.tsx: Full-page modal (Dialog, like YieldForm). Contains stepper + input state.\n- Pool/components/Deposit/DepositInput.tsx: Amount input using TradeAssetInput or similar. Shows wallet balance as available. Min amount validation.\n- Pool/components/Deposit/DepositStepper.tsx: Linear stepper (like TransactionStepsList) with explicit steps:\n 1. Enter deposit amount (user input)\n 2. Sign deposit channel - EIP-712 sign requestLiquidityDepositAddress, extract deposit address from LiquidityDepositAddressReady event\n 3. Send native tx - programmatic buildSendTransaction via chain adapter to the deposit channel address\n 4. Wait for Chainflip witness - poll cfFreeBalances until deposit lands (~1-2 min)\n 5. Done - show success, free balance updated\n\nAccount creation handling:\n- If account not funded: show message that FLIP is needed (PoC limitation)\n- If LP not registered: auto-submit registerLpAccount as first step\n- If refund address not set: auto-submit registerLiquidityRefundAddress (can batch)\n\nReference:\n- src/pages/Yields/components/TransactionStepsList.tsx (stepper pattern)\n- src/pages/Yields/components/YieldForm.tsx (full-page modal pattern)\n- src/lib/utils/evm/index.ts signAndBroadcast (chain adapter send)\n- Deposit channel expires after 24h\n\nAcceptance:\n- Deposit modal opens from pool detail page\n- Linear stepper shows all steps explicitly\n- EIP-712 sign popup works (MetaMask/WalletConnect)\n- Native tx sends to deposit channel address\n- Free balance updates after CF witnesses deposit\n- Error states handled: wallet rejection, tx failure, channel expiry\n- Unit tests for hooks","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12006","status":"open","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:53:35.102646+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:44:25.558889+01:00","dependencies":[{"issue_id":"shapeshiftWeb-ob0t","depends_on_id":"shapeshiftWeb-uf5l","type":"blocks","created_at":"2026-02-23T14:59:18.664191+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-ob0t","depends_on_id":"shapeshiftWeb-8vgs","type":"blocks","created_at":"2026-02-23T14:59:28.824239+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-oxjm","title":"PR3: Supply modal with linear stepper","description":"Supply flow: move CF free balance into lending pool. Full-page modal with linear stepper.\n\nPool/components/Supply/SupplyModal.tsx:\n- Full-page modal (Dialog pattern, like YieldForm)\n- Triggered from pool detail PositionCard [Supply] button or Supply tab \"Supply\" button\n- Contains SupplyInput + SupplyStepper\n\nPool/components/Supply/SupplyInput.tsx:\n- Amount input drawing ONLY from CF free balance (not wallet balance)\n- Show free balance as available amount (crypto + fiat)\n- If free balance insufficient, show info message: \"Deposit more to Chainflip first\" with link to deposit\n- Min supply validation: $100\n- APY display for the pool\n- MAX button uses full free balance\n\nPool/components/Supply/SupplyStepper.tsx:\n- Linear stepper steps:\n 1. Enter supply amount (SupplyInput)\n 2. Sign addLenderFunds (EIP-712 via signAddLenderFunds composed util)\n 3. Confirm - poll cfLendingPoolSupplyBalances until position reflects\n- Success state: show supply position summary\n\nhooks/useChainflipSupplyBalances.ts:\n- Wraps supplyBalances query + oraclePrices for fiat conversion\n- Returns per-asset supply positions for the connected account\n\nAcceptance:\n- Can supply from free balance to lending pool\n- Supply position appears in PositionCard after confirmation\n- $100 minimum enforced\n- Insufficient free balance shows deposit prompt\n- Linear stepper explicit throughout\n- Unit tests for supply balances hook","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12007","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:54:20.276561+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:55:29.978476+01:00","dependencies":[{"issue_id":"shapeshiftWeb-oxjm","depends_on_id":"shapeshiftWeb-ob0t","type":"blocks","created_at":"2026-02-23T15:20:12.389812+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-oxjm","depends_on_id":"shapeshiftWeb-uf5l","type":"blocks","created_at":"2026-02-23T15:20:22.727812+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-pjf","title":"Add adapter-based tx status for second-class EVM chains","description":"## Context\nSwapper's `checkEvmSwapStatus` calls `adapter.httpProvider.getTransaction`, which is undefined for second-class EVM adapters. We first need adapter-level support before migrating consumers.\n\n## Objective\nAdd a transaction-status method on `SecondClassEvmAdapter`, covering Monad/HyperEvm/Plasma/Katana uniformly.\n\n## Acceptance Criteria\n- `SecondClassEvmAdapter` exposes `getTransactionStatus(txHash: string): Promise\u003cTxStatus\u003e` implemented via its internal `JsonRpcProvider`.\n- Concrete second-class adapters inherit this without extra wiring.\n- Unit tests cover success/failure/pending cases.\n- After implementing and running lint/type-check/tests, commit the changes (this bead owns its commit).\n\n## Notes\n1. Extend `SecondClassEvmAdapter` with the method and ensure typings expose it when the adapter is known to be second-class.\n2. Mock provider responses in tests to cover status mapping.\n3. Handoff to sanity-check bead before migrating consumers.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T16:31:53.450078+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T16:59:10.546734+01:00","closed_at":"2026-02-16T16:59:10.546734+01:00","close_reason":"Added getTransactionStatus to SecondClassEvmAdapter with unit tests; ran lint/type-check and vitest"} -{"id":"shapeshiftWeb-pvo","title":"Speed Up / Cancel UI for pending BTC transactions","description":"Speed Up button on pending BTC sends in action center. Modal shows current fee rate vs recommended rates (slow/average/fast from getFeeData()). Two actions: Speed Up (keep payment, higher fee) and Cancel Transaction (send-to-self). On confirm: calls buildRbfReplacementTransaction(), signs with wallet, broadcasts. Updates action slice with replacedByTxHash/replacesTxHash links. Handle confirmation: replacement confirms → mark original as replaced; original confirms first → mark replacement as dropped.","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-17T10:47:12.617378+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T10:47:12.617378+01:00","dependencies":[{"issue_id":"shapeshiftWeb-pvo","depends_on_id":"shapeshiftWeb-wb8","type":"blocks","created_at":"2026-02-17T10:47:16.703489+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-pvo","depends_on_id":"shapeshiftWeb-hs0","type":"blocks","created_at":"2026-02-17T10:47:16.76427+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-pys","title":"SolanaTransactionContent component","description":"Create a SolanaTransactionContent component that displays parsed Solana transaction details in the WC signing modal.\n\nLocation: src/plugins/walletConnectToDapps/components/WalletConnectSigningModal/content/SolanaTransactionContent.tsx\n\nVisual layout modeled after EVM TransactionContent (Card borderRadius='2xl' p={4} with VStack):\n\nRow 1: Network\n- Left: \"Network\" label (text.subtle)\n- Right: \"Solana\" + network icon (reuse selectFeeAssetByChainId pattern from TransactionContent)\n\nRow 2: Program (the main program, e.g. Jupiter v6)\n- Left: \"Program\" label (text.subtle) \n- Right: human-readable program name from the parsing utility (bold), or truncated address if unknown\n- If multiple non-infra programs, show the \"interesting\" one (not ComputeBudget, not Token Program close account)\n\nRow 3: Instructions summary\n- Left: \"Instructions\" label (text.subtle)\n- Right: count, e.g. \"5 instructions\"\n\nRow 4 (collapsible, like EVM \"Transaction Data\"):\n- Expandable section showing each instruction:\n - Program name/address\n - Account count\n - Data size in bytes\n- Toggle with ChevronDown/ChevronUp (reuse pattern from TransactionContent)\n\nRow 5: Fee Payer\n- Left: \"Fee Payer\" label (text.subtle)\n- Right: ExpandableCell with the fee payer address (reuse existing ExpandableCell component)\n\nFor signAllTransactions: show a summary card per transaction or a single card with \"N transactions\" header + aggregate instruction count.\n\nGraceful fallback: if parsing returns null (corrupt data), fall back to the current truncated base64 display.\n\nReuse existing components:\n- ExpandableCell for addresses\n- selectFeeAssetByChainId for network info\n- Card/VStack/HStack layout from TransactionContent\n- useToggle for collapsible sections\n- InlineCopyButton/MiddleEllipsis for addresses\n\nAdd translation keys to en/main.json under plugins.walletConnectToDapps.modal:\n- program: \"Program\"\n- instructions: \"Instructions\"\n- feePayer: \"Fee Payer\"\n- nInstructions: \"{count} instructions\"\n- nTransactions: \"{count} transactions\"\n- dataSize: \"{size} bytes\"\n\nAcceptance criteria:\n- Jupiter swap tx shows: Network=Solana, Program=Jupiter v6, 5 instructions, fee payer with copy\n- Unknown program shows truncated address instead of name\n- Corrupt base64 falls back to raw display (no crash)\n- Zero visual regressions on EVM TransactionContent\n- Light/dark mode both look correct","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:21:16.703258+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:26:32.314603+01:00","closed_at":"2026-02-18T12:26:32.314603+01:00","close_reason":"Created SolanaTransactionContent and SolanaMultiTransactionContent components with network row, program name, instruction count, fee payer, collapsible detail section. Added translation keys.","dependencies":[{"issue_id":"shapeshiftWeb-pys","depends_on_id":"shapeshiftWeb-xfs","type":"blocks","created_at":"2026-02-18T12:21:52.096118+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-qao","title":"deep audit all thor base unit conversions against origin/develop","description":"Deep dive into ALL thor base unit / fromThorBaseUnit / toThorBaseUnit conversions comparing improvement-audit-2 vs origin/develop. Check every location where THOR_PRECISION (8) interacts with native asset precision. Verify no precision bugs introduced by BigAmount migration. Check savers, lending, LP, swaps, and all THORChain-specific code paths.","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T13:08:36.394286+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:15:48.941981+01:00","closed_at":"2026-02-13T13:15:48.941981+01:00","close_reason":"All ~60 THOR base unit conversion sites audited against origin/develop. All mathematically equivalent. Pre-existing TCY withdrawBps double-conversion bug was already fixed by the migration. Rounding behavior identical (both use ROUND_HALF_UP). No bugs found."} -{"id":"shapeshiftWeb-qb1","title":"fix coderabbit seeker pr 11848 review","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-15T15:29:43.630824+01:00","created_by":"gomes-bot","updated_at":"2026-02-15T15:42:34.565747+01:00","closed_at":"2026-02-15T15:42:34.565747+01:00","close_reason":"tackled coderabbitai review items; pushed commits and replied on PR"} -{"id":"shapeshiftWeb-qjf","title":"Audit: stale vernacular (bnOrZero, bn, BaseUnit in names, old BigNumber patterns)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:47.002281+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.801755+01:00","closed_at":"2026-02-13T11:31:46.801755+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-qn7","title":"follow-up: BigAmount API refinements in packages/utils","description":"packages/utils BigAmount API changes on improvement-audit-2 that may already be in PR #11864. Verify and cherry-pick if missing.\n\nFiles (3):\n- packages/utils/src/bigAmount/bigAmount.ts (JSDoc, FromBaseUnit/FromPrecision types, BigAmountConfig export)\n- packages/utils/src/bigAmount/bigAmount.test.ts (toJSON base unit storage test fixes)\n- packages/utils/src/index.ts (BigAmountConfig export)\n\nDO NOT implement — just capture for follow-up verification. These may overlap with PR #11864 changes.","status":"closed","priority":4,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:47:12.505007+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:55:56.50758+01:00","closed_at":"2026-02-14T13:55:56.50758+01:00","close_reason":"P4 backlog - not implementing now"} -{"id":"shapeshiftWeb-qne","title":"Across integration: lint, type-check, tests, and draft PR","description":"Final pass: ensure everything compiles, lint is clean, and open a draft PR.\n\nSteps:\n1. Run yarn lint --fix on all new/modified files\n2. Run yarn type-check — resolve any type errors\n3. Run existing swapper tests to verify no regressions\n4. Keep ACROSS_RESEARCH.md in the PR as reference documentation\n5. Open draft PR to develop using gh cli\n - Title: 'feat: across protocol swapper integration'\n - Use .github/PULL_REQUEST_TEMPLATE.md as body base\n - Include WARNING emoji about needing to register for integrator ID for affiliate fees\n - Flag that it's behind VITE_FEATURE_SWAPPER_ACROSS=true feature flag\n - Note: Cross-chain only, 10 chains (9 EVM + Solana), no same-chain swaps\n\nAcceptance criteria:\n- yarn lint passes\n- yarn type-check passes\n- No test regressions\n- Draft PR opened with proper description\n- Research doc included in PR","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:20:17.321183+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:56:12.881237+01:00","closed_at":"2026-02-13T19:56:12.881237+01:00","close_reason":"Full lint/type-check/tests pass. Committed 1667 lines across 23 files. Draft PR opened: https://github.com/shapeshift/web/pull/11876","dependencies":[{"issue_id":"shapeshiftWeb-qne","depends_on_id":"shapeshiftWeb-418","type":"blocks","created_at":"2026-02-13T19:20:23.783359+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-qrp","title":"[Epic] Rework P3: on-demand RBF speed-up UX","description":"Rework the speed-up UX to NOT store RbfMeta. Instead, fetch original tx data on-demand when user clicks Speed Up. Show speed up in both action center AND tx history rows. Remove HandleSendResult, revert handleSend to return string, keep replacedByTxHash/replacesTxHash linking. Amend commit and force push to gomes-bot:feat_btc_rbf_p3_speed_up_ux.","status":"closed","priority":0,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-14T11:49:28.930593+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T12:21:54.723148+01:00","closed_at":"2026-02-14T12:21:54.723148+01:00","close_reason":"All P3 tasks complete: RbfMeta removed, SpeedUpModal reworked for on-demand fetch, tx history rows have speed up button, replacement tx linking in subscriber."} -{"id":"shapeshiftWeb-qsr","title":"[BTC Wallet] getDeviceID breaks for BTC-only WC sessions","description":"HIGH: getDeviceID returns 'wc:' + ethGetAddress(). For BTC-only sessions, returns 'wc:null'. All BTC-only sessions collide. Fix: Fall back to BTC address. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:48:04.657399+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.082105+01:00","closed_at":"2026-02-18T17:02:53.082105+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-qw5","title":"BigAmount: migrate trade/swap consumers","description":"Migrate 6 trade/swap files from old string selectors to new BigAmount selectors. Files: state/apis/swapper/helpers/validateTradeQuote.ts, state/slices/common/tradeInputBase/createTradeInputBaseSelectors.ts, components/MultiHopTrade/components/Earn/EarnInput.tsx, components/MultiHopTrade/components/LimitOrder/AllowanceApproval.tsx, components/MultiHopTrade/components/LimitOrder/LimitOrderCard.tsx, components/MultiHopTrade/components/TradeAssetInput.tsx","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:02:53.258767+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.470231+01:00","closed_at":"2026-02-13T19:38:31.470231+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-r9o","title":"remove dead code: comparedTo ?? 0, double toString, redundant bnOrZero","description":"7x .comparedTo() ?? 0 dead fallbacks: AvailablePools.tsx:70/73, usePools.ts:46, marketDataSlice.tsx:80, useGetRampQuotes.tsx:114, QuickBuyEdit.tsx:54, YourPositions.tsx:103. 2x double toString in ethFoxStaking/index.ts:78-79. 2x redundant bnOrZero on .toPrecision() in useCallRequestEvmFees.ts:66 and useSendFees.tsx:52.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T13:04:15.150766+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T13:11:11.048404+01:00","closed_at":"2026-02-13T13:11:11.048404+01:00","close_reason":"Reverted — .comparedTo() returns number|null in BigNumber.js types, so ?? 0 is needed for TypeScript type narrowing. Not dead code. Double toString in ethFoxStaking was false positive (no double wrapping in actual code)."} -{"id":"shapeshiftWeb-reb","title":"Phase 1: stale variable renames (5 files)","description":"Rename variables named *BaseUnit/*CryptoBaseUnit that now hold BigAmount objects. See PRD .claude/plans/bigamount-deep-audit-prd.md Phase 1.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:32:31.614748+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:36:06.836134+01:00","closed_at":"2026-02-13T11:36:06.836134+01:00","close_reason":"Renames applied, type-check passes"} -{"id":"shapeshiftWeb-rpx9","title":"Chainflip Lending Integration Epic","description":"# Chainflip Lending Integration Epic\n\nGitHub issue: https://github.com/shapeshift/web/issues/11979\nSpec: CHAINFLIP_LENDING_SPEC.md (in repo)\nIssue body: CHAINFLIP_LENDING_ISSUE.md (in repo)\nWorktree: /Users/gomes/Sites/shapeshiftWeb/.worktrees/chainflip-lending (branch feat/chainflip-lending)\n\n## What\nIntegrate Chainflip's on-chain lending protocol into ShapeShift. Users can supply assets to earn yield and borrow against collateral. All operations use EIP-712 Non-Native Signed Calls on the public State Chain RPC - no SDK exists yet (CF team will improve for us).\n\n## Architecture\n- EIP-712 signing pipeline: SCALE-encode call -\u003e cf_encode_non_native_call -\u003e eth_signTypedData_v4 -\u003e author_submitExtrinsic\n- Three fund buckets: free balance (staging), supplied (earning yield), collateral (backing loans)\n- Deposit channel flow: open channel (EIP-712) -\u003e send native tx -\u003e CF witnesses -\u003e funds land in free balance\n- Batching via Environment.batch (pallet 0x02, call 0x0b), max 10 calls\n\n## Page Structure\n- Main page: [Overview | Supply | Borrow] top-level tabs\n- Overview: global stats + unified markets table (\"View Market\" action)\n- Supply tab: supply stats + markets with \"Supply\" buttons\n- Borrow tab: borrow stats + LTV dashboard + markets with \"Borrow\" buttons\n- Pool detail: 2-column (stats left, position+actions right sticky). Full-page modals for supply/borrow/deposit.\n- Three separate row components per tab (OverviewMarketRow, SupplyMarketRow, BorrowMarketRow)\n- Dynamic data from CF RPC (not hardcoded), multi-account via global switcher\n\n## PR Stack (5 stacked PRs, each opened as draft)\n1. Infrastructure + Dead Code (feature flag, lib, RPC, SCALE, EIP-712, nav rename, empty page)\n2. Deposit to State Chain + Visual Groundwork (page layout, overview tab, pool detail, deposit flow)\n3. Supply Flow (supply tab, supply/withdraw modals, position updates)\n4. Borrow Flow (borrow tab, collateral/loan modals, LTV gauge)\n5. Action Center + Tx History (toasts, per-pool + global activity, tx parsing)\n\n## Key Technical Details\n- FLIP ERC-20: 0x826180541412d574cf1336d22c0c0a287822678a\n- State Chain Gateway: 0x6995ab7c4d7f4b03f467cf4c8e920427d9621dbd\n- SS58 prefix: 2112, specVersion: 20012\n- LTV: 80% max creation, 85% topup, 90% soft liq, 95% hard liq\n- Interest: 0% at 0% util, 4% at 95% (kink), 25% at 100%\n- Minimums: $100 supply/loan, $10 updates\n- NonceOrAccount: number -\u003e Nonce, SS58 string -\u003e Account (hex does NOT work)\n- Account must exist (FLIP funding) before submission, nonce=0 works for first call\n\n## Workflow\n- NEVER push/open PRs without explicit user approval\n- SDK_RESEARCH.md updated every commit/milestone\n- PoC - visual work may be iterated on\n- Unit test as much as possible\n- Use CF repos + live RPC for research/source of truth","notes":"CF team confirmed yield-accruing supply as collateral is in the making (ETA: SDK partner onboarding timeline). Not blocking any current PR but when we build PR4 (borrow flow), collateral source might include existing supply positions, not just fresh deposits. Keep borrow UI flexible for this.","status":"open","priority":1,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-23T14:43:42.956733+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T18:28:03.597698+01:00"} -{"id":"shapeshiftWeb-sx5p","title":"PR2: Overview tab with markets table","description":"Overview tab showing global stats and unified markets table with all pools.\n\nOverview.tsx:\n- Global stat cards: Total Supplied, Available Liquidity, Total Borrowed (aggregated from all pools)\n- Stat values in fiat using oraclePrices()\n- Markets table with all pools (fetched dynamically from cfLendingPools, NOT hardcoded)\n\nOverviewMarketRow.tsx:\n- Table row per pool: asset icon+name, supply APY, supplied amount, borrowed amount, borrow rate, utilisation %, \"View Market\" button\n- Click \"View Market\" -\u003e navigate to /chainflip-lending/pool/:asset\n- Amounts in both crypto and fiat\n- Sort by utilisation or APY\n\nData: lendingPools() + oraclePrices() queries. Map CF asset IDs to CAIP AssetIds for icons/names.\n\nReference: CF's own lending overview page structure. Use existing Amount.Crypto/Fiat/Percent components.\n\nAcceptance:\n- Overview tab shows live pool data from mainnet\n- All 5 pools visible (BTC, ETH, SOL, USDC, USDT)\n- \"View Market\" navigates to pool detail\n- Fiat values correct via oracle prices\n- Responsive table/cards on mobile","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12006","status":"open","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:52:38.720502+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:44:04.904167+01:00","dependencies":[{"issue_id":"shapeshiftWeb-sx5p","depends_on_id":"shapeshiftWeb-kfgz","type":"blocks","created_at":"2026-02-23T14:58:58.056335+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-taw","title":"Migrate swapper/action center to adapter tx status","description":"## Context\nOnce `SecondClassEvmAdapter` exposes `getTransactionStatus`, we need to migrate all consumers that currently call `adapter.httpProvider` (swapper) or the per-chain helpers in `src/lib/utils/*` (action center) so they rely on the adapter method instead.\n\n## Objective\nUpdate every second-class EVM transaction polling site (swapper `checkEvmSwapStatus`, Action Center subscribers, etc.) to use the adapter’s `getTransactionStatus`, then remove the redundant helpers.\n\n## Acceptance Criteria\n- Swapper `checkEvmSwapStatus` detects second-class adapters and calls `adapter.getTransactionStatus(...)`; first-class chains keep the existing path.\n- Action Center `useSendActionSubscriber` (and any other polling flow) uses the adapter method instead of `get\u003cChain\u003eTransactionStatus` helpers.\n- Legacy helpers in `src/lib/utils/{monad,hyperevm,plasma,katana}.ts` are removed or limited to adapter-level internals.\n- Manual QA: Across swap + wallet send on second-class chains complete without errors; regression test first-class chains.\n\n## Dependencies\n- Depends on `shapeshiftWeb-pjf` (adapter method implemented).","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-16T16:34:17.824659+01:00","created_by":"gomes-bot","updated_at":"2026-02-16T17:03:11.588966+01:00","closed_at":"2026-02-16T17:03:11.588966+01:00","close_reason":"Switched swapper/action center polling to adapter getTransactionStatus and ran lint/type-check","dependencies":[{"issue_id":"shapeshiftWeb-taw","depends_on_id":"shapeshiftWeb-pjf","type":"blocks","created_at":"2026-02-16T16:34:26.996322+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-tlf","title":"add sequence support to hdwallet-gridplus bitcoin signing","description":"GridPlus has both native and PSBT signing paths, neither passes sequence. Update both paths to include input.sequence when defined. Acceptance: GridPlus btcSignTx passes sequence for both lattice-native and PSBT code paths.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T10:37:08.891682+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T10:47:35.618259+01:00","closed_at":"2026-02-14T10:47:35.618259+01:00","close_reason":"Added sequence to GridPlus PSBT path addInput (native SDK path does not support sequence)","dependencies":[{"issue_id":"shapeshiftWeb-tlf","depends_on_id":"shapeshiftWeb-7n8","type":"blocks","created_at":"2026-02-14T10:37:21.097074+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-u4b","title":"PR9: yields + lending + send + walletconnect + remaining","description":"Medium-risk remaining domains. ~25 files: Yields (YieldAvailableToDeposit, YieldEnterModal, YieldForm, YieldPositionCard, YieldsList, useYieldTransactionFlow), Lending (Pool.tsx, BorrowInput, RepayConfirm, RepayInput, useGetEstimatedFeesQuery, useLendingQuoteQuery), Send modal (useSendDetails + test, useSendFees), WalletConnect (WalletConnectModalSigningFooter, SendTransactionContent, useCallRequestEvmFees, useSimulateEvmTransaction), Receive modal (ReceiveAmount), bip21.ts, generateReceiveQrText.ts.","status":"closed","priority":3,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:47.933341+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.307764+01:00","closed_at":"2026-02-14T13:25:59.307764+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-u4b","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.770395+01:00","created_by":"gomes-bot"},{"issue_id":"shapeshiftWeb-u4b","depends_on_id":"shapeshiftWeb-8ys","type":"blocks","created_at":"2026-02-13T15:38:06.905743+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-u8p","title":"WC Wallet: NEAR support (connect wallet)","description":"Add NEAR namespace support to the WalletConnect 'connect wallet' flow. Revised research shows 22 wallets in WC explorer support near:mainnet, including HOT Wallet, Sweat Wallet (20M+ users), Nightly, Sender (1M+ users), Crypto.com Onchain, Ctrl Wallet, OneKey, Atomic Wallet.\n\n## Prerequisites\n- Depends on Cosmos wallet support (which introduces universal-provider migration)\n\n## Research Steps\n1. Read packages/hdwallet-core/src/near.ts for NearWallet interface\n2. Check how hdwallet-native implements NearWallet\n3. Read @near-wallet-selector/wallet-connect source for method signatures\n4. Verify NEAR CAIP-2 format: near:mainnet\n\n## Scope\n- Add near namespace to optionalNamespaces in session proposal (near:mainnet)\n- Implement WalletConnectV2HDWallet near methods: nearGetAddress, nearSignTx\n- Add _supportsNear = true flag\n- Parse session accounts from CAIP-10 format: near:mainnet:\u003caccountId\u003e\n- Handle near_getAccounts, near_signTransaction, near_signTransactions\n- Unit tests for near signing methods\n\n## RPC Methods\n- near_getAccounts: {} -\u003e [{ accountId, publicKey }]\n- near_signTransaction: { transaction: Uint8Array-encoded } -\u003e SignedTransaction\n- near_signTransactions: { transactions: Uint8Array[] } -\u003e SignedTransaction[]\n- near_signMessage: { message, recipient, nonce } -\u003e { signature, publicKey }\n\n## Mobile Wallets That Support near:mainnet via WC QR\n- HOT Wallet, Sweat Wallet (20M+ users), Nightly, Sender (1M+ users)\n- Also: Crypto.com Onchain, Ctrl Wallet, OneKey, Atomic Wallet\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- User can scan QR with HOT/Sweat/Nightly/Sender mobile and get NEAR address exposed\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11906 | PR body must include: - tackles https://github.com/shapeshift/web/issues/11906 | Branch: fresh off origin/develop | PR: draft","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:49:44.995206+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T14:25:27.098246+01:00","closed_at":"2026-02-17T14:25:27.098246+01:00","close_reason":"NEAR WC support dropped - no NEAR wallets support WalletConnect, ecosystem dead","dependencies":[{"issue_id":"shapeshiftWeb-u8p","depends_on_id":"shapeshiftWeb-4cm","type":"blocks","created_at":"2026-02-17T13:50:02.562177+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-ubi","title":"[Cosmos dApps] prettier CI failures block merge","description":"HIGH: 2 prettier formatting errors in WalletConnectModalManager.tsx:153 and CosmosSignMessageConfirmation.tsx:31 will fail CI. Fix: yarn lint --fix. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_cosmos_wcv2_dapps","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:48:54.233056+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.694164+01:00","closed_at":"2026-02-18T16:58:33.694164+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-uf5l","title":"PR2: Pool detail page with 2-column layout","description":"Per-pool detail page with 2-column desktop layout (stacks on mobile).\n\nPool/Pool.tsx:\n- Route: /chainflip-lending/pool/:asset\n- Back button -\u003e /chainflip-lending\n- Asset icon + name in header + oracle price\n- Account switcher\n- 2-column layout:\n - Left (scrollable): PoolStats component\n - Right (sticky): PositionCard component\n\nPool/components/PoolStats.tsx:\n- Supply Stats section: total supplied, current supply APY (data, no chart for PoC)\n- Borrow Stats section: total borrowed, borrow rate, max LTV (80%), liquidation LTV (90%), liquidation fee\n- Interest Rate Model section: placeholder for PoC (show current utilisation + rates as text, chart is future scope)\n- Utilisation rate display\n\nPool/components/PositionCard.tsx:\n- Your Position breakdown (using Row compound component):\n - Free Balance (crypto + fiat)\n - Supplied (crypto + fiat)\n - Collateral (crypto + fiat)\n - Earned Interest (crypto + fiat)\n - Current APY\n- Action buttons: [Supply] [Borrow] [Deposit to CF]\n- Supply/Borrow buttons disabled until PR 3/4 (render but no-op)\n- Empty state when no wallet connected or no CF account\n- Data from freeBalances + supplyBalances + loanAccounts queries\n\nReference: src/pages/Lending/Pool/Pool.tsx (THORChain 2-col layout), CF's USDC Market page structure.\n\nAcceptance:\n- Pool page renders with live data\n- Position card shows all 3 balance types\n- 2-column on desktop, stacked on mobile\n- Deposit to CF button functional (opens deposit modal from next bead)\n- Supply/Borrow buttons rendered but disabled","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12006","status":"open","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:53:04.265936+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:44:15.248579+01:00","dependencies":[{"issue_id":"shapeshiftWeb-uf5l","depends_on_id":"shapeshiftWeb-kfgz","type":"blocks","created_at":"2026-02-23T14:59:08.3978+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-uk6","title":"BigAmount: migrate internal selectors + utils","description":"Migrate 4 internal selector/util files from old string selectors to new BigAmount selectors. Heaviest change — portfolioSlice/selectors.ts has 10+ internal references. Files: state/slices/portfolioSlice/selectors.ts, portfolioSlice.test.ts, state/slices/opportunitiesSlice/selectors/lpSelectors.ts, lib/utils/thorchain/balance.ts. Should go last since it touches the selector chain itself.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:03:01.535805+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.476226+01:00","closed_at":"2026-02-13T19:38:31.476226+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-uot","title":"p3: complete p2.2 defi providers — full improvement-audit-2 diff","description":"Update bigamount-defi-providers branch to include ALL changes from improvement-audit-2.\n\nEXISTING files with deeper changes (~17 files already in PR):\n- All cosmos/foxy/fox-farming/thorchain-savers Deposit/Withdraw/Confirm files\n- src/features/defi/helpers/utils.ts\n\nNEW files to add (28):\n- 7 cosmos Status/Overview/Withdraw components\n- 6 fox-farming Claim/Approve/Overview/ExpiredWithdraw/Withdraw/useFoxFarming\n- 8 foxy Approve/Status/ClaimConfirm/ClaimStatus/Overview/WithdrawCard/WithdrawType\n- 4 thorchain-savers Approve/Status/Overview\n- 2 univ2 hooks/utils\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, variable renames, bnOrZero cleanup.\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11868.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:21.667949+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:11.938619+01:00","closed_at":"2026-02-14T14:31:11.938619+01:00","close_reason":"All 61 defi provider files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-defi-providers (PR #11868)"} -{"id":"shapeshiftWeb-v617","title":"PR3: Supply tab and SupplyMarketRow","description":"Supply tab on main lending page with supply-focused stats and markets table.\n\nSupplyTab.tsx:\n- Supply-focused stat cards: Total Supplied (fiat), Total Earned Fees (if available from RPC), top supply APY\n- Markets table showing all pools with supply-relevant columns\n\nSupplyMarketRow.tsx:\n- Table row: asset icon+name, supply APY, total supplied, total borrowed, borrow rate, utilisation %, \"Supply\" button\n- \"Supply\" button navigates to pool detail page with supply modal auto-open (via search param ?modal=supply)\n- Row clickable -\u003e pool detail\n\nReference: CF Supply tab layout. Same data source as overview but different emphasis.\n\nAcceptance:\n- Supply tab renders with live data\n- \"Supply\" button routes to pool and opens supply modal\n- Responsive","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12007","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:53:56.421474+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:55:19.665829+01:00","dependencies":[{"issue_id":"shapeshiftWeb-v617","depends_on_id":"shapeshiftWeb-sx5p","type":"blocks","created_at":"2026-02-23T15:20:02.139818+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-vd8","title":"Add Across swapper scaffolding (SwapperName, feature flag, env vars, icon)","description":"Add the foundational pieces needed before the swapper implementation:\n\n1. Add SwapperName.Across = 'Across' to packages/swapper/src/types.ts enum\n2. Add feature flag + env vars to src/config.ts:\n - VITE_FEATURE_SWAPPER_ACROSS: bool({ default: false })\n - VITE_ACROSS_API_URL: url({ default: 'https://app.across.to/api' })\n - VITE_ACROSS_INTEGRATOR_ID: str({ default: '' })\n3. Add AcrossSwapper to FeatureFlags type + initial state in src/state/slices/preferencesSlice/preferencesSlice.ts\n4. Add mock value in src/test/mocks/store.ts\n5. Set values in .env, .env.development, .env.production (default false for prod)\n6. Add swapper enablement logic in src/state/helpers.ts:\n [SwapperName.Across]: AcrossSwapper \u0026\u0026 (\\!isCrossAccountTrade || isCrossAccountTradeSupported(SwapperName.Across))\n7. Download Across Logomark (Aqua Circle) SVG from brand assets page and add to swapper icon assets\n URL: https://docs.across.to/user-docs/additional-info/across-brand-assets\n8. Register empty swapper in packages/swapper/src/constants.ts (like other swappers)\n9. Add to isCrossAccountTradeSupported() — Across supports cross-account via recipient param\n10. Add to DEFAULT_SWAPPER_SLIPPAGE_DECIMAL_PERCENTAGE if needed (Across supports 'auto' slippage)\n\nFollow the exact pattern of existing swappers (Relay, Bebop, etc.) for all touchpoints.\n\nAcceptance criteria:\n- SwapperName.Across exists\n- Feature flag toggles the swapper on/off\n- Across icon renders in the app when swapper returns quotes\n- No lint/type errors","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:19:14.823488+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:37:08.903505+01:00","closed_at":"2026-02-13T19:37:08.903505+01:00","close_reason":"Added SwapperName.Across, feature flag, env vars, icon, swapper registration (undefined for now), isCrossAccountTradeSupported, getEnabledSwappers, auto slippage support. Type-check and lint pass."} -{"id":"shapeshiftWeb-vd93","title":"PR3: Withdraw modal with linear stepper","description":"Withdraw flow: remove from lending pool to free balance, then egress to wallet. Full-page modal with linear stepper.\n\nPool/components/Withdraw/WithdrawModal.tsx:\n- Full-page modal (Dialog pattern)\n- Triggered from pool detail PositionCard [Withdraw] button (visible once user has supply position)\n\nPool/components/Withdraw/WithdrawInput.tsx:\n- Amount input from supply position\n- Show current supply position as available (crypto + fiat)\n- MAX button for full withdrawal\n- Min withdrawal validation\n\nPool/components/Withdraw/WithdrawStepper.tsx:\n- Linear stepper steps:\n 1. Enter withdraw amount\n 2. Sign removeLenderFunds (EIP-712) - moves from pool to free balance\n 3. Sign withdraw_asset (EIP-712) - egresses from free balance to on-chain wallet address\n 4. Confirm - wait for egress confirmation\n- Option: batch removeLenderFunds + withdraw_asset via Environment.batch (single EIP-712 sign) OR sequential (two signs)\n- If batching: single sign step instead of two\n\nPositionCard updates:\n- Show supply position (Supplied row with crypto + fiat)\n- Show earned interest\n- [Withdraw] button visible when supplied \u003e 0\n- Free balance updates after step 2\n\nAcceptance:\n- Can withdraw partial or full supply\n- Two-step (remove + egress) or batched single-step works\n- Position card updates reflect changes\n- Egress to correct on-chain address\n- Linear stepper shows all steps","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12007","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:54:42.623661+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:55:40.305129+01:00","dependencies":[{"issue_id":"shapeshiftWeb-vd93","depends_on_id":"shapeshiftWeb-oxjm","type":"blocks","created_at":"2026-02-23T15:20:33.080488+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-vgx","title":"[Tron Wallet] signTransaction sends incomplete transaction object","description":"HIGH: WC Tron spec requires full transaction object (txID, raw_data, raw_data_hex, visible). Code only sends { rawDataHex }. Field naming also wrong (camelCase vs snake_case). Fix: Forward full transaction object from chain adapter. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_tron_wcv2_wallet","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:48:44.021836+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.693564+01:00","closed_at":"2026-02-18T16:58:33.693564+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-vje","title":"Audit: wrong BigAmount API usage (fromBaseUnit vs fromPrecision, wrong output method)","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:45.398141+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.80126+01:00","closed_at":"2026-02-13T11:31:46.80126+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-wb8","title":"Add buildRbfReplacementTransaction() to UtxoBaseAdapter","description":"New method on UtxoBaseAdapter that builds a replacement transaction for fee bumping. Fetches original tx from unchained via getTransaction(txHash), rebuilds with same inputs + higher fee. Two modes: speed-up (same payment outputs, higher fee) and cancel (all value to self). Must satisfy BIP 125 rules: spend at least one original input, new fee \u003e= original fee. Set sequence 0xFFFFFFFD on all inputs.","status":"open","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-17T10:47:06.851843+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T10:47:06.851843+01:00"} -{"id":"shapeshiftWeb-wcr","title":"Implement solanaSignRawTransaction + solanaSignMessage in hdwallet-ledger","description":"In packages/hdwallet-ledger/src/solana.ts: add solanaSignRawTransaction (deserialize base64, sign via transport.call Solana signTransaction) and solanaSignMessage (transport.call Solana signOffchainMessage). Wire in packages/hdwallet-ledger/src/ledger.ts class methods.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:43:00.572587+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:48:38.209823+01:00","closed_at":"2026-02-18T12:48:38.209823+01:00","close_reason":"Added solanaSignRawTransaction and solanaSignMessage to Ledger adapter","dependencies":[{"issue_id":"shapeshiftWeb-wcr","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:12.792919+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-wm8","title":"BigAmount: migrate defi provider consumers","description":"Migrate 16 defi provider files from old string selectors to new BigAmount selectors. Files: features/defi/helpers/utils.ts, thorchain-savers (Deposit, Confirm x2, Withdraw, Empty), fox-farming (Deposit, Confirm x2, Withdraw Confirm, ClaimConfirm), foxy (Deposit, Confirm x2, Withdraw x2), cosmos (Deposit, Confirm, Withdraw Confirm)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T19:02:54.890984+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T19:38:31.471919+01:00","closed_at":"2026-02-13T19:38:31.471919+01:00","close_reason":"PRs created: #11867 (trade/swap), #11868 (defi providers), #11869 (yields+lending), #11870 (rfox/tcy/thorlp), #11871 (send+misc), #11872 (internal selectors)"} -{"id":"shapeshiftWeb-x0g","title":"[BTC Wallet] account param uses full CAIP-10 instead of plain address","description":"HIGH: Per WC BIP122 spec, account in signPsbt/signMessage should be plain address (bc1q...), not full CAIP-10 string. Code passes bip122Accounts[0] directly. Fix: Extract address from CAIP-10 with split(':')[2]. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:47:44.134634+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.080976+01:00","closed_at":"2026-02-18T17:02:53.080976+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-x34","title":"Remove CosmosManager defi provider","description":"Remove src/features/defi/providers/cosmos/ entirely — dead code gated by YieldXyz flag","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:45:19.044838+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T13:03:17.555316+01:00","closed_at":"2026-02-18T13:03:17.555316+01:00","close_reason":"Removed all dead cosmos SDK defi code, type-check and lint clean"} -{"id":"shapeshiftWeb-x5e","title":"[Epic] speed up stuck BTC transaction UX","description":"P3 epic: Detect stuck/unconfirmed BTC transactions that were built with RBF, and provide UI to re-broadcast with a higher fee. Depends on P1 (hdwallet sequence support) and P2 (chain-adapters RBF opt-in) being merged. Sub-tasks TBD — will likely include: detect replaceable txs, build replacement tx with higher fee, re-broadcast flow, UI components.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-14T11:00:23.986526+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:35:32.467254+01:00","closed_at":"2026-02-14T11:35:32.467254+01:00","close_reason":"All P3 tasks complete: RBF metadata types, capture during send, i18n keys, speed up button, SpeedUpModal, subscriber logic"} -{"id":"shapeshiftWeb-x6c","title":"PR3: hdwallet precision math migration","description":"Migrate hdwallet packages to BigAmount. 21 files across hdwallet-core (satsFromStr), hdwallet-keepkey (EOS assetToNumber, cosmos/thorchain/osmosis/mayachain parseInt→Number, ripple parseInt→Number), hdwallet-gridplus (bitcoin BigAmount.reduce for fee calc), hdwallet-native (binance BigNumber→BigAmount). Includes package.json deps and tsconfig project references. Medium risk — hardware wallet tx construction.","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-13T15:36:12.096796+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T13:25:59.299792+01:00","closed_at":"2026-02-14T13:25:59.299792+01:00","close_reason":"Superseded — all BigAmount migration PRs created (#11864, #11866, #11867-#11875)","dependencies":[{"issue_id":"shapeshiftWeb-x6c","depends_on_id":"shapeshiftWeb-1yk","type":"blocks","created_at":"2026-02-13T15:36:54.36387+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-xc4","title":"Implement solanaSignRawTransaction + solanaSignMessage in hdwallet-native","description":"In packages/hdwallet-native/src/solana.ts: add solanaSignRawTransaction (deserialize base64 -\u003e signTransaction via adapter) and solanaSignMessage (adapter.signMessage -\u003e base64). Also add signMessage method to SolanaAdapter in packages/hdwallet-native/src/crypto/isolation/adapters/solana.ts.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:42:50.264156+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:47:46.951418+01:00","closed_at":"2026-02-18T12:47:46.951418+01:00","close_reason":"Added solanaSignRawTransaction and solanaSignMessage to native wallet mixin, added signMessage to SolanaAdapter","dependencies":[{"issue_id":"shapeshiftWeb-xc4","depends_on_id":"shapeshiftWeb-h3l","type":"blocks","created_at":"2026-02-18T12:44:02.532426+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-xfs","title":"Solana WC tx parsing utility","description":"Create a utility to parse Solana serialized transactions (base64) into a structured format for display.\n\nLocation: src/plugins/walletConnectToDapps/utils/solana.ts\n\nUses @solana/web3.js (already at v1.98.0) to deserialize VersionedTransaction from base64.\n\nReturns:\n- version (legacy vs v0)\n- feePayer address (staticAccountKeys[0])\n- recentBlockhash\n- instructions array, each with:\n - programId (PublicKey as base58 string)\n - programName (human-readable label from known programs map)\n - accountCount (number of accounts referenced)\n - dataLength (bytes)\n\nKnown programs map (hardcoded, no external lookups):\n- 11111111111111111111111111111111 -\u003e System Program\n- TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA -\u003e Token Program\n- ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL -\u003e Associated Token Program\n- ComputeBudget111111111111111111111111111111 -\u003e Compute Budget\n- JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4 -\u003e Jupiter v6\n- whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc -\u003e Orca Whirlpool\n- CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK -\u003e Raydium CLMM\n- 675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8 -\u003e Raydium AMM\n- LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo -\u003e Meteora DLMM\n\nPure function, no React, no hooks. Wrap in try/catch - return null if deserialization fails (graceful fallback to raw base64 display).\n\nAcceptance criteria:\n- Parses the Jupiter swap transaction from the console log test case correctly (5 instructions, 16 accounts, Jupiter v6 program identified)\n- Returns null for invalid/corrupt base64\n- No network calls, purely local parsing","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-18T12:20:48.30278+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T12:24:59.408802+01:00","closed_at":"2026-02-18T12:24:59.408802+01:00","close_reason":"Created parseSolanaTransaction utility in utils/solana.ts - deserializes base64, identifies known programs (Jupiter/Orca/Raydium/etc), returns structured data. Verified with real Jupiter swap tx."} -{"id":"shapeshiftWeb-xiar","title":"Add Ink to WalletConnect V2 optional chains","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T16:09:55.681184+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T16:12:14.21538+01:00","closed_at":"2026-02-19T16:12:14.21538+01:00","close_reason":"Closed"} -{"id":"shapeshiftWeb-xv5","title":"toJSON() and toThorBaseUnit() use implicit rounding mode","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-13T14:23:14.961806+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T14:23:47.820476+01:00","closed_at":"2026-02-13T14:23:47.820476+01:00","close_reason":"Added explicit ROUND_HALF_UP to toJSON() and toThorBaseUnit()"} -{"id":"shapeshiftWeb-y2w","title":"WC dApps: Bitcoin support (ShapeShift as wallet)","description":"Add Bitcoin (BIP122) namespace support in WC-to-dApps flow. When ShapeShift acts as a wallet and an external Bitcoin dApp connects via WC, handle BIP122 signing requests.\n\n## Scope\n- Add BIP122SigningMethod enum to types.ts (sendTransfer, signPsbt, signMessage, getAccountAddresses)\n- Add Bitcoin/BIP122 request/response types to types.ts\n- Create BIP122RequestHandlerUtil.ts following EIP155RequestHandlerUtil pattern\n- Handle sendTransfer: build and sign BTC transaction via hdwallet btcSignTx, broadcast via chain adapter\n- Handle signPsbt: sign PSBT via hdwallet, optionally broadcast\n- Handle signMessage: sign message via hdwallet btcSignMessage\n- Handle getAccountAddresses: return available BTC addresses from portfolio\n- Update useWalletConnectEventsHandler.ts to route BIP122 methods to appropriate modal\n- Add WalletConnectModal entries for Bitcoin confirmation\n- Update createApprovalNamespaces.ts to handle bip122 namespace\n- Create BitcoinSignConfirmation modal component\n- Unit tests for BIP122RequestHandlerUtil\n\n## RPC Method Details\n- sendTransfer: { account, recipientAddress, amount, memo? } -\u003e { txid }\n- signPsbt: { account, psbt: base64, signInputs, broadcast? } -\u003e { psbt: base64, txid? }\n- signMessage: { account, message, protocol? } -\u003e { signature, address }\n- getAccountAddresses: { account } -\u003e addresses[]\n\n## Acceptance Criteria\n- yarn type-check passes\n- yarn lint --fix passes\n- External Bitcoin dApp can connect to ShapeShift via WC and sign transactions\n- PR targets origin/develop","notes":"GitHub issue: https://github.com/shapeshift/web/issues/11907 - PR body must include '- tackles https://github.com/shapeshift/web/issues/11907'","status":"closed","priority":2,"issue_type":"feature","owner":"contact@0xgom.es","created_at":"2026-02-17T13:21:16.614979+01:00","created_by":"gomes-bot","updated_at":"2026-02-17T15:47:11.999852+01:00","closed_at":"2026-02-17T15:47:11.999852+01:00","close_reason":"PR #11916 opened - bitcoin wc dApps support","dependencies":[{"issue_id":"shapeshiftWeb-y2w","depends_on_id":"shapeshiftWeb-bk0","type":"blocks","created_at":"2026-02-17T13:21:24.23085+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-y5o","title":"[BTC Wallet] btcSignTx non-functional, psbt field doesn't exist","description":"CRITICAL: BTCSignTx has no psbt field. The cast (msg as BTCSignTx \u0026 { psbt?: string }).psbt always returns undefined, making btcSignTx always return null. Fix: Construct PSBT from msg.inputs/outputs like Phantom does. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_btc_wcv2_wallet","status":"closed","priority":0,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:47:23.682363+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T17:02:53.079669+01:00","closed_at":"2026-02-18T17:02:53.079669+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-ybbi","title":"PR5: Action Center integration and tx history","description":"Action Center integration for CF lending + per-pool and global activity/history views.\n\nAction Center:\n- Toast notifications for: deposit confirmed, supply confirmed, withdraw confirmed, borrow confirmed, repayment confirmed\n- LTV warning toasts when approaching thresholds (passive, informational)\n- Integration with existing Action Center infrastructure (research at implementation time)\n\nTx History:\n- Per-pool activity section on pool detail page (below stats, or in a tab)\n- Shows: deposits, withdrawals, supply/remove, borrow/repay events\n- Global CF lending activity view (accessible from main page or settings)\n- Runtime tx parsing: research existing patterns in app (recent PR did similar)\n- Data source: CF RPC events or state chain queries (research needed)\n\nColumns: Type (deposit/supply/borrow/etc), Asset, Amount, Status, Age/Timestamp\n\nReference:\n- Existing Action Center in app\n- rFOX history pattern\n- CF's own activity view: deposits \u0026 withdrawals, funding \u0026 redemptions\n\nThis is the last PR in the epic and may require significant research into Action Center patterns and CF event parsing.\n\nAcceptance:\n- Toast notifications for major lending events\n- Per-pool activity visible on pool detail page\n- Global activity view accessible\n- History entries show correct data","notes":"GitHub issue: https://github.com/shapeshift/web/issues/12009","status":"open","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-23T14:55:50.696072+01:00","created_by":"gomes-bot","updated_at":"2026-02-23T15:56:11.111166+01:00","dependencies":[{"issue_id":"shapeshiftWeb-ybbi","depends_on_id":"shapeshiftWeb-ob0t","type":"blocks","created_at":"2026-02-23T15:21:14.38831+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-yfa","title":"Audit: selector return type consistency (BigAmount vs string leaking)","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T11:15:50.846259+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T11:31:46.803195+01:00","closed_at":"2026-02-13T11:31:46.803195+01:00","close_reason":"Audit complete, findings compiled into PRD"} -{"id":"shapeshiftWeb-ynf","title":"[Cosmos dApps] duplicate cosmos_getAccounts and wrong pubkey","description":"MEDIUM: cosmos_getAccounts handled in events handler (auto-respond) AND in CosmosRequestHandlerUtil (dead code). Both use bech32 address as pubkey (wrong). Fix: Remove dead code in handler util, improve events handler pubkey derivation. Worktree: /Users/gomes/Sites/shapeshiftWeb--feat_cosmos_wcv2_dapps","status":"closed","priority":2,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-18T16:49:25.338074+01:00","created_by":"gomes-bot","updated_at":"2026-02-18T16:58:33.695281+01:00","closed_at":"2026-02-18T16:58:33.695281+01:00","close_reason":"Fixed and pushed to fork"} -{"id":"shapeshiftWeb-zf0","title":"p3: complete p2.3 yields+lending — full improvement-audit-2 diff","description":"Update bigamount-yields-lending branch to include ALL changes from improvement-audit-2.\n\nEXISTING files with deeper changes (6 files already in PR):\n- BorrowInput (+91 lines), RepayInput (+66 lines), YieldAvailableToDeposit (+30 lines)\n- YieldEnterModal (+16 lines), YieldForm (+25 lines), YieldsList (+10 lines)\n\nNEW files to add (6):\n- src/pages/Lending/hooks/useGetEstimatedFeesQuery.ts\n- src/pages/Lending/hooks/useLendingQuoteQuery.ts\n- src/pages/Lending/Pool/components/Repay/RepayConfirm.tsx\n- src/pages/Lending/Pool/Pool.tsx\n- src/pages/Yields/components/YieldPositionCard.tsx\n- src/pages/Yields/hooks/useYieldTransactionFlow.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, variable renames.\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11869.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:25.435838+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:12.00565+01:00","closed_at":"2026-02-14T14:31:12.00565+01:00","close_reason":"All 13 yields+lending files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-yields-lending (PR #11869)"} -{"id":"shapeshiftWeb-zgd","title":"add i18n translation keys for speed up UI","description":"Add English translation keys to src/assets/translations/en/main.json for speed up modal, buttons, status messages, fee comparison, and error states.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T11:13:51.813978+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T11:21:30.699908+01:00","closed_at":"2026-02-14T11:21:30.699908+01:00","close_reason":"Added i18n keys for speed up modal and transaction history (speedUp, cancelTransaction, replaced, replacedBy, replaces, plus modals.send.speedUp section with all modal copy)."} -{"id":"shapeshiftWeb-zk0","title":"Architecture and performance implications deep dive","description":"Deep dive into architecture and performance implications of BigAmount migration: selector memoization behavior with BigAmount objects, Redux serialization considerations, BigAmount object allocation in hot paths, potential memory concerns from BigAmount vs string storage in state.","status":"closed","priority":3,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-13T12:22:55.259462+01:00","created_by":"gomes-bot","updated_at":"2026-02-13T12:45:57.986537+01:00","closed_at":"2026-02-13T12:45:57.986537+01:00","close_reason":"Completed. CRITICAL: Selector memoization broken - Redux stores strings, selectors create fresh BigAmount instances every call (~2000/render). HIGH: Redundant createDeepEqualOutputSelector for single BigAmount results. MEDIUM: No custom BigAmount serialization for persistence. Root cause: string storage in Redux."} -{"id":"shapeshiftWeb-zro","title":"p3: complete p2.6 internal selectors — full improvement-audit-2 diff","description":"Update bigamount-internal-selectors branch to include ALL changes from improvement-audit-2.\n\nEXISTING files with deeper changes (3 files already in PR):\n- lpSelectors.ts (+113 lines)\n- foxy/index.ts (+47 lines)\n- portfolioSlice.test.ts (+33 lines)\n\nNEW files to add (11):\n- src/state/slices/opportunitiesSlice/resolvers/cosmosSdk/index.ts\n- src/state/slices/opportunitiesSlice/resolvers/cosmosSdk/utils.ts\n- src/state/slices/opportunitiesSlice/resolvers/ethFoxStaking/index.ts\n- src/state/slices/opportunitiesSlice/resolvers/ethFoxStaking/utils.ts\n- src/state/slices/opportunitiesSlice/resolvers/rFOX/index.ts\n- src/state/slices/opportunitiesSlice/resolvers/thorchainsavers/index.ts\n- src/state/slices/opportunitiesSlice/selectors/selectors.test.ts\n- src/state/slices/opportunitiesSlice/selectors/stakingSelectors.ts\n- src/state/slices/opportunitiesSlice/types.ts\n- src/state/slices/opportunitiesSlice/utils/index.ts\n- src/state/slices/portfolioSlice/utils/index.ts\n\nChanges: fromBaseUnit/toBaseUnit→BigAmount, bnOrZero cleanup, dead code removal (genericBalanceByFilter, underlyingToken0/1 types).\n\nAcceptance: git checkout improvement-audit-2 -- \u003call files\u003e, type-check clean, push to fork, update PR #11872.","status":"closed","priority":2,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-14T13:46:43.50569+01:00","created_by":"gomes-bot","updated_at":"2026-02-14T14:31:12.215941+01:00","closed_at":"2026-02-14T14:31:12.215941+01:00","close_reason":"All 11 internal selector files cherry-picked from improvement-audit-2, type-check clean, pushed to bigamount-internal-selectors (PR #11872)"} -{"id":"shapeshiftWeb-2f09","title":"Sanity check Ink + Scroll regen data","description":"Verify generatedAssetData.json has entries for both eip155:534352 (Scroll) and eip155:57073 (Ink). Verify relatedAssetIndex.json has inkAssetId in ETH related array. Verify no regressions. Run review-second-class-evm skill.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:51:24.013329+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T17:01:37.198079+01:00","closed_at":"2026-02-19T17:01:37.198079+01:00","close_reason":"Popular assets + market data verified working after cache clear. All ink fixes merged, PR #11960 opened.","dependencies":[{"issue_id":"shapeshiftWeb-2f09","depends_on_id":"shapeshiftWeb-cgtg","type":"blocks","created_at":"2026-02-19T13:51:48.716437+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-4uq9","title":"Checkout + merge-fix Ink PR #11904","description":"Checkout Ink PR, extract regen data before merge, merge origin/develop with -X theirs to resolve all conflicts in favor of develop. Result: branch has Ink code changes but develop's generated files.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:50:52.705351+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T13:53:13.843624+01:00","closed_at":"2026-02-19T13:53:13.843624+01:00","close_reason":"Merged origin/develop with -X theirs, all conflicts resolved"} -{"id":"shapeshiftWeb-cgtg","title":"Cherry-pick Ink regen data into develop generated files","description":"Extract Ink (eip155:57073) entries from saved PR generated files. Merge into develop's generatedAssetData.json, relatedAssetIndex.json. Create coingecko adapter. Bump clearAssets migration. Regenerate manifest hashes + brotli/gzip compression.","status":"closed","priority":1,"issue_type":"task","owner":"contact@0xgom.es","created_at":"2026-02-19T13:51:03.136273+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T13:56:30.878339+01:00","closed_at":"2026-02-19T13:56:30.878339+01:00","close_reason":"Added coingecko adapter, index.ts import/export, migration bump 293. User will run yarn generate:asset-data for actual regen.","dependencies":[{"issue_id":"shapeshiftWeb-cgtg","depends_on_id":"shapeshiftWeb-4uq9","type":"blocks","created_at":"2026-02-19T13:51:38.351227+01:00","created_by":"gomes-bot"}]} -{"id":"shapeshiftWeb-l6zn","title":"Add Ink native to ETH related asset index + recompress","status":"closed","priority":1,"issue_type":"bug","owner":"contact@0xgom.es","created_at":"2026-02-19T16:09:45.315585+01:00","created_by":"gomes-bot","updated_at":"2026-02-19T16:12:14.214097+01:00","closed_at":"2026-02-19T16:12:14.214097+01:00","close_reason":"Closed"} diff --git a/.beads/ss-dx5.10.json b/.beads/ss-dx5.10.json deleted file mode 100644 index c689e4786ee..00000000000 --- a/.beads/ss-dx5.10.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.10", - "title": "Integrate Mode (chainId: 34443, ETH, OP Stack L2)", - "description": "TVL: $69.5M | RPC: https://mainnet.mode.network/ | Explorer: https://explorer.mode.network | Token Support: All | Pattern B (RPC-only) | DeFi-focused L2", - "notes": "Logo: https://assets.relay.link/icons/34443/light.png (dark: dark.png)\nCoinGecko: mode\nArch: OP Stack L2 (DeFi-focused)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:36Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.12.json b/.beads/ss-dx5.12.json deleted file mode 100644 index e7764939f23..00000000000 --- a/.beads/ss-dx5.12.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.12", - "title": "Integrate Ethereal (chainId: 5064014, USDe, App-specific L2)", - "description": "TVL: $65.3M | RPC: https://rpc.ethereal.trade | Explorer: https://explorer.ethereal.trade | Token Support: Limited | Pattern B (RPC-only) | Ethena ecosystem, USDe-native", - "notes": "\nLogo: https://assets.relay.link/icons/5064014/light.png (dark: dark.png)\nCoinGecko platform: ❌ NOT ON COINGECKO (native-only asset, no token list)\nCoinGecko native ID: N/A (USDe — use ethena-usde as CoinGecko coin ID)\nArch: App-specific L2 (Ethena ecosystem)\nNative token: USDe (stablecoin as gas — NOT ETH-native)\nSLIP44: 60 (Ethereum)\nETH-native: NO — USDe gas token\nViem: ❌ NOT IN VIEM — needs defineChain({ id: 5064014, ... })\nAcross: ❌ NOT SUPPORTED\nZerion ID: TBD (likely \"ethereal\" — verify when integrating)\n\n🔴 CRITICAL QUIRKS:\n- Not in viem: Must use defineChain() in RelaySwapper constant.ts\n- Not on CoinGecko: Only native asset, no ERC20 token list from CoinGecko\n- USDe is gas: Stablecoin-native chain (like Stable with gUSDT)\n- adapter.json: {\"eip155:5064014/slip44:60\":\"ethena-usde\"}\n- relatedAssetKey: null (NOT eip155:1/slip44:60)\n- Does NOT affect ethereum test array or market-service counts\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_5064014/adapter.json\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add etherealChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId (use defineChain() since not in viem)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/ethereal/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts (will be native-only)\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-ethereal-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:42:34Z", - "labels": [ - "critical-quirk", - "evm", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.13.json b/.beads/ss-dx5.13.json deleted file mode 100644 index ae3b5a59d97..00000000000 --- a/.beads/ss-dx5.13.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.13", - "title": "Integrate Hemi (chainId: 43111, ETH, Bitcoin L2)", - "description": "TVL: $57.2M | RPC: https://rpc.hemi.network/rpc | Explorer: https://explorer.hemi.xyz | Token Support: All | Pattern B (RPC-only) | Bitcoin-Ethereum supernetwork", - "notes": "\nLogo: https://assets.relay.link/icons/43111/light.png (dark: dark.png)\nCoinGecko platform: hemi\nCoinGecko native ID: weth (but chain uses ETH — adapter.json maps to \"ethereum\")\nArch: Bitcoin L2 (OP Stack compatible)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ hemi (id: 43111) — import { hemi } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"hemi\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_43111/adapter.json → {\"eip155:43111/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add hemiChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"hemi\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:43111/slip44:60 to ethereum array in index.test.ts (match import order)\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:43111/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [hemiChainId]: hemi.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/hemi/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-hemi-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:42:47Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.14.json b/.beads/ss-dx5.14.json deleted file mode 100644 index 25e14dd0608..00000000000 --- a/.beads/ss-dx5.14.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.14", - "title": "Integrate World Chain (chainId: 480, ETH, OP Stack L2)", - "description": "TVL: $51.6M | RPC: https://worldchain-mainnet.gateway.tenderly.co | Explorer: https://worldscan.org | Token Support: All | Pattern B (RPC-only) | Worldcoin ecosystem", - "notes": "\nLogo: https://assets.relay.link/icons/480/light.png (dark: dark.png)\nCoinGecko platform: world-chain\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (Worldcoin ecosystem)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ worldchain (id: 480) — import { worldchain } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 480)\nZerion ID: \"world-chain\" (hyphenated)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_480/adapter.json → {\"eip155:480/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add worldChainChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"world-chain\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [worldChainChainId]: worldchain.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:480/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:480/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [worldChainChainId]: worldchain.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/worldchain/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-worldchain-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:02Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.15.json b/.beads/ss-dx5.15.json deleted file mode 100644 index 28ac29c8f77..00000000000 --- a/.beads/ss-dx5.15.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.15", - "title": "Integrate Plume (chainId: 98866, PLUME, RWA L2)", - "description": "TVL: $48.4M | RPC: https://rpc.plume.org | Explorer: https://explorer.plume.org | Token Support: All | Pattern B (RPC-only) | Real-world asset tokenization", - "notes": "\nLogo: https://assets.relay.link/icons/98866/light.png (dark: dark.png)\nCoinGecko platform: plume-network (⚠️ NOT \"plume\"!)\nCoinGecko native ID: plume\nArch: RWA L2 (Real World Assets focus)\nNative token: PLUME (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — PLUME gas token\nViem: ✅ plumeMainnet (id: 98866) — import { plumeMainnet } from \"viem/chains\"\n ⚠️ GOTCHA: \"plume\" in viem is chainId 98865 (WRONG!). Must use \"plumeMainnet\" for 98866.\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"plume\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_98866/adapter.json → {\"eip155:98866/slip44:60\":\"plume\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add plumeChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"plume\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [plumeChainId]: plumeMainnet.id to chainIdToRelayChainId (⚠️ use plumeMainnet NOT plume)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/plume/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-plume-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:14Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.16.json b/.beads/ss-dx5.16.json deleted file mode 100644 index a7c83e7cf8a..00000000000 --- a/.beads/ss-dx5.16.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.16", - "title": "Integrate Story (chainId: 1514, IP, L1)", - "description": "TVL: $42.4M | RPC: https://mainnet.storyrpc.io | Explorer: https://storyscan.xyz | Token Support: All | Pattern B (RPC-only) | IP blockchain", - "notes": "\nLogo: https://assets.relay.link/icons/1514/light.png (dark: dark.png)\nCoinGecko platform: story\nCoinGecko native ID: story-2 (⚠️ NOT \"story\"!)\nArch: L1 (IP/Intellectual Property blockchain)\nNative token: IP (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — IP gas token\nViem: ✅ story (id: 1514) — import { story } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"story\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_1514/adapter.json → {\"eip155:1514/slip44:60\":\"story-2\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add storyChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"story\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [storyChainId]: story.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/story/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-story-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:23Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.17.json b/.beads/ss-dx5.17.json deleted file mode 100644 index b12b8e28c7b..00000000000 --- a/.beads/ss-dx5.17.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { - "id": "ss-dx5.17", - "title": "Integrate Celo (chainId: 42220, CELO, L1)", - "description": "TVL: $39.7M | RPC: https://forno.celo.org | Explorer: https://celoscan.io | Token Support: All | Pattern B (RPC-only) | Mobile-first, established chain", - "notes": "\nLogo: https://assets.relay.link/icons/42220/light.png (dark: dark.png)\nCoinGecko platform: celo\nCoinGecko native ID: celo\nArch: L1 (mobile-first blockchain)\nNative token: CELO (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — CELO gas token\nViem: ✅ celo (id: 42220) — import { celo } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"celo\" (standard lowercase)\n\n🔴 CRITICAL QUIRKS:\n- CELO is BOTH the native gas token AND an ERC20 token on the chain\n- Relay may use wrapped CELO — check relayTransactionMetadata.assetRequiringApproval\n- CoinGecko has \"celo\" as platform, \"celo\" as native coin ID\n- May need special handling for the native-token-as-ERC20 duality\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_42220/adapter.json → {\"eip155:42220/slip44:60\":\"celo\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add celoChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"celo\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [celoChainId]: celo.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/celo/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-celo-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:34Z", - "labels": [ - "critical-quirk", - "evm", - "non-eth-gas", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.18.json b/.beads/ss-dx5.18.json deleted file mode 100644 index 46295a10e19..00000000000 --- a/.beads/ss-dx5.18.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { - "id": "ss-dx5.18", - "title": "Integrate Blast (chainId: 81457, ETH, OP Stack L2)", - "description": "TVL: $36.7M | RPC: https://rpc.blast.io/ | Explorer: https://blastscan.io | Token Support: All | Pattern B (RPC-only) | Native yield, Blur ecosystem", - "notes": "\nLogo: https://assets.relay.link/icons/81457/light.png (dark: dark.png)\nCoinGecko platform: blast\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (rebasing ETH from L1 staking yield)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ blast (id: 81457) — import { blast } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 81457)\nZerion ID: \"blast\" (standard lowercase)\n\n🔴 CRITICAL QUIRKS:\n- Rebasing ETH: ETH balance auto-increases from L1 staking yield\n- USDB also rebases: Blast native stablecoin has similar behavior\n- May need special balance display handling for rebasing tokens\n- OP Stack based but with custom yield mechanics\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_81457/adapter.json → {\"eip155:81457/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add blastChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"blast\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [blastChainId]: blast.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:81457/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:81457/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [blastChainId]: blast.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/blast/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-blast-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:47Z", - "labels": [ - "critical-quirk", - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.19.json b/.beads/ss-dx5.19.json deleted file mode 100644 index 9ca06e7f13a..00000000000 --- a/.beads/ss-dx5.19.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { - "id": "ss-dx5.19", - "title": "Integrate zkSync Era (chainId: 324, ETH, zkEVM L2)", - "description": "TVL: $25.2M | RPC: https://mainnet.era.zksync.io | WS: wss://mainnet.era.zksync.io/ws | Explorer: https://explorer.zksync.io | Token Support: All | Pattern B (RPC-only) | Major zkEVM", - "notes": "\nLogo: https://assets.relay.link/icons/324/light.png (dark: dark.png)\nCoinGecko platform: zksync (⚠️ NOT \"zksync-era\"!)\nCoinGecko native ID: ethereum\nArch: zkEVM L2 (zkSync Era — Type 113 EIP-712 transactions)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ zksync (id: 324) — import { zksync } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 324)\nZerion ID: \"zksync-era\" (hyphenated — verify when integrating)\n\n🔴 CRITICAL QUIRKS:\n- Type 113 (EIP-712) transactions — NOT standard EIP-1559!\n- Viem has special zksync chainConfig for EIP-712 serialization\n- May need custom transaction type handling in chain adapter\n- Gas estimation uses zks_estimateFee RPC (not standard eth_estimateGas)\n- Account abstraction (AA) native support — paymaster patterns\n- Abstract (chainId: 2741) is zkSync-based too — shared architecture\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_324/adapter.json → {\"eip155:324/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add zksyncChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"zksync-era\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [zksyncChainId]: zksync.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:324/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:324/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [zksyncChainId]: zksync.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/zksync/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-zksync-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:07Z", - "labels": [ - "critical-quirk", - "evm", - "relay", - "tier-2", - "zkevm" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.2.json b/.beads/ss-dx5.2.json deleted file mode 100644 index aab64e26852..00000000000 --- a/.beads/ss-dx5.2.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.2", - "title": "Integrate Ink (chainId: 57073, ETH, OP Stack L2)", - "description": "TVL: $448.3M | RPC: https://ink.drpc.org | Explorer: https://explorer.inkonchain.com | Token Support: All | Pattern B (RPC-only) | Kraken's L2", - "notes": "Logo: https://assets.relay.link/icons/57073/light.png (dark: dark.png)\nCoinGecko: ink\nArch: OP Stack L2 (Kraken)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:34Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.20.json b/.beads/ss-dx5.20.json deleted file mode 100644 index 098ba13315a..00000000000 --- a/.beads/ss-dx5.20.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.20", - "title": "Integrate Flow EVM (chainId: 747, FLOW, L1 with EVM)", - "description": "TVL: $25.0M | RPC: https://mainnet.evm.nodes.onflow.org | WS: wss://mainnet.evm.nodes.onflow.org | Explorer: https://evm.flowscan.io | Token Support: All | Pattern B (RPC-only) | Dapper Labs", - "notes": "\nLogo: https://assets.relay.link/icons/747/light.png (dark: dark.png)\nCoinGecko platform: flow-evm\nCoinGecko native ID: flow\nArch: L1 with EVM (Flow blockchain EVM layer)\nNative token: FLOW (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — FLOW gas token\nViem: ✅ flowMainnet (id: 747) — import { flowMainnet } from \"viem/chains\"\n ⚠️ GOTCHA: Export is \"flowMainnet\" NOT \"flow\"!\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"flow-evm\" (match CoinGecko platform name)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_747/adapter.json → {\"eip155:747/slip44:60\":\"flow\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add flowEvmChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"flow-evm\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [flowEvmChainId]: flowMainnet.id to chainIdToRelayChainId (⚠️ use flowMainnet NOT flow)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/flowEvm/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-flow-evm-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:18Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.21.json b/.beads/ss-dx5.21.json deleted file mode 100644 index 4463a7e43da..00000000000 --- a/.beads/ss-dx5.21.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.21", - "title": "Integrate Soneium (chainId: 1868, ETH, OP Stack L2)", - "description": "TVL: $21.1M | RPC: https://rpc.soneium.org/ | Explorer: https://soneium.blockscout.com | Token Support: All | Pattern B (RPC-only) | Sony's L2", - "notes": "\nLogo: https://assets.relay.link/icons/1868/light.png (dark: dark.png)\nCoinGecko platform: soneium\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (Sony ecosystem)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ soneium (id: 1868) — import { soneium } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 1868)\nZerion ID: \"soneium\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_1868/adapter.json → {\"eip155:1868/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add soneiumChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"soneium\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [soneiumChainId]: soneium.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:1868/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:1868/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [soneiumChainId]: soneium.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/soneium/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-soneium-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:28Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.3.json b/.beads/ss-dx5.3.json deleted file mode 100644 index c961d35b88f..00000000000 --- a/.beads/ss-dx5.3.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.3", - "title": "Integrate Mantle (chainId: 5000, MNT, Optimistic L2)", - "description": "TVL: $433.3M | RPC: https://rpc.mantle.xyz | Explorer: https://mantlescan.xyz | Token Support: All | Pattern B (RPC-only) | Non-ETH native token (MNT)", - "notes": "Logo: https://assets.relay.link/icons/5000/light.png (dark: dark.png)\nCoinGecko: mantle\nArch: Optimistic L2\nViem key: mantle\n⚠️ NON-ETH GAS: MNT - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.4.json b/.beads/ss-dx5.4.json deleted file mode 100644 index a4bd69a9c22..00000000000 --- a/.beads/ss-dx5.4.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.4", - "title": "Integrate Cronos (chainId: 25, CRO, EVM Sidechain)", - "description": "TVL: $376.1M | RPC: https://cronos.drpc.org | Explorer: https://cronoscan.com | Token Support: All | Pattern B (RPC-only) | Crypto.com ecosystem", - "notes": "Logo: https://assets.relay.link/icons/25/light.png (dark: dark.png)\nCoinGecko: cronos\nArch: EVM Sidechain (Crypto.com)\nViem key: cronos\n⚠️ NON-ETH GAS: CRO - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.5.json b/.beads/ss-dx5.5.json deleted file mode 100644 index 5d83cf4b25b..00000000000 --- a/.beads/ss-dx5.5.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.5", - "title": "Integrate Berachain (chainId: 80094, BERA, PoL L1)", - "description": "TVL: $324.3M | RPC: https://rpc.berachain.com/ | Explorer: https://beratrail.io | Token Support: All | Pattern B (RPC-only) | Proof of Liquidity consensus", - "notes": "Logo: https://assets.relay.link/icons/80094/light.png (dark: dark.png)\nCoinGecko: berachain\nArch: L1 (Proof of Liquidity)\nViem key: berachain\n⚠️ NON-ETH GAS: BERA - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.6.json b/.beads/ss-dx5.6.json deleted file mode 100644 index 74546650669..00000000000 --- a/.beads/ss-dx5.6.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.6", - "title": "Integrate Linea (chainId: 59144, ETH, zkEVM L2)", - "description": "TVL: $156.7M | RPC: https://rpc.linea.build | Explorer: https://lineascan.build | Token Support: All | Pattern B (RPC-only) | Consensys L2", - "notes": "Logo: https://assets.relay.link/icons/59144/light.png (dark: dark.png)\nCoinGecko: linea\nArch: zkEVM L2 (Consensys)\nViem: custom linea_estimateGas RPC method - use viem chainConfig with custom serializers\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "relay", - "tier-1", - "zkevm" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.7.json b/.beads/ss-dx5.7.json deleted file mode 100644 index 5a514885d75..00000000000 --- a/.beads/ss-dx5.7.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.7", - "title": "Integrate Sonic (chainId: 146, S, L1)", - "description": "TVL: $127.8M | RPC: https://rpc.soniclabs.com | Explorer: https://sonicscan.org | Token Support: All | Pattern B (RPC-only) | Fantom ecosystem evolution", - "notes": "Logo: https://assets.relay.link/icons/146/light.png (dark: dark.png)\nCoinGecko: sonic\nArch: L1 (ex-Fantom)\nViem key: sonic\n⚠️ NON-ETH GAS: S - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:25Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "non-eth-gas", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.8.json b/.beads/ss-dx5.8.json deleted file mode 100644 index 7edd42caa57..00000000000 --- a/.beads/ss-dx5.8.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.8", - "title": "Integrate Unichain (chainId: 130, ETH, OP Stack L2)", - "description": "TVL: $95.4M | RPC: https://mainnet.unichain.org | Explorer: https://uniscan.xyz | Token Support: All | Pattern B (RPC-only) | Uniswap's L2", - "notes": "Logo: https://assets.relay.link/icons/130/light.png (dark: dark.png)\nCoinGecko: unichain\nArch: OP Stack L2 (Uniswap)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:25Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-1" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.9.json b/.beads/ss-dx5.9.json deleted file mode 100644 index edd0a297bbc..00000000000 --- a/.beads/ss-dx5.9.json +++ /dev/null @@ -1,39 +0,0 @@ -[ - { - "id": "ss-dx5.9", - "title": "Integrate BOB (chainId: 60808, ETH, OP Stack L2)", - "description": "TVL: $84.9M | RPC: https://rpc.gobob.xyz/ | Explorer: https://explorer.gobob.xyz | Token Support: Limited | Pattern B (RPC-only) | Bitcoin-focused L2", - "notes": "Logo: https://assets.relay.link/icons/60808/light.png (dark: dark.png)\nCoinGecko: bob-network (⚠️ chain_identifier is null - may need name-based lookup)\nArch: OP Stack L2 (Bitcoin-focused)\nViem: standard OP Stack\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "labels": [ - "evm", - "op-stack", - "relay", - "tier-2" - ], - "dependencies": [ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "dependency_type": "parent-child" - } - ], - "parent": "ss-dx5" - } -] diff --git a/.beads/ss-dx5.json b/.beads/ss-dx5.json deleted file mode 100644 index a5b8addac9f..00000000000 --- a/.beads/ss-dx5.json +++ /dev/null @@ -1,985 +0,0 @@ -[ - { - "id": "ss-dx5", - "title": "Add support for missing Relay.link EVM chains", - "description": "Master epic tracking integration of ALL chains supported by Relay.link that ShapeShift web doesn't currently support. Enables cross-chain bridging capabilities via Relay infrastructure. See https://github.com/shapeshift/web/issues/11902 for full details. All new EVM chains will use Pattern B (RPC-only + getKnownTokens) since no ShapeShift unchained indexer infrastructure exists for these chains.", - "notes": "=== FROM ISSUE COMMENTS ===\n\nLOGO PATTERN: https://assets.relay.link/icons/{chainId}/light.png (dark: dark.png)\n\nARCHITECTURE GROUPS:\n- OP Stack (standard): Ink, Unichain, BOB, Mode, Hemi, World Chain, Soneium, Zircuit, Lisk, Cyber, Blast, Zora, Redstone, Shape, Superseed, Manta Pacific\n- zkEVM (special handling): Scroll, zkSync Era, Linea, Polygon zkEVM, Taiko, Abstract\n- Arbitrum Orbit: ApeChain, Xai, Sanko\n- Non-ETH gas (10 chains): Mantle(MNT), Metis(METIS), Cronos(CRO), Ronin(RON), Sonic(S), Flow(FLOW), Berachain(BERA), Plume(PLUME), Story(IP), Stable(gUSDT)\n\nCRITICAL CHAINS:\n1. Celo (42220): Native token is BOTH native AND ERC20. Relay uses wrapped CELO. Check relayTransactionMetadata.assetRequiringApproval\n2. Blast (81457): Rebasing ETH from L1 staking yield. USDB also rebases. Handle in balance displays.\n3. Ethereal (5064014): NOT in viem. Needs custom chain definition.\n4. zkSync Era (324) + Abstract (2741): Type 113 (EIP-712) transactions. Use viem zksync chainConfig.\n5. Linea (59144): Custom linea_estimateGas RPC method.\n6. Sei (1329): Parallelized EVM + CosmWasm interop. CoinGecko uses sei-v2 NOT sei.\n\nCOINGECKO GOTCHAS: sei-\u003esei-v2, plume-\u003eplume-network, zksync-\u003ezksync, metis-\u003emetis-andromeda, morph-\u003emorph-l2, gravity-\u003egravity-alpha, boba-\u003eboba, zora-\u003ezora-network, funkichain-\u003efunki, Superposition (capital S). BOB/Zero Network have null chain_identifier. 11 chains not on CoinGecko at all.\n\nPER-CHAIN CHECKLIST: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n=== RELAY SWAPPER INTEGRATION (per chain) ===\n\nFILE 1: packages/swapper/src/swappers/RelaySwapper/constant.ts\n - Add to chainIdToRelayChainId map: [newChainChainId]: \u003cviem_chain\u003e.id (or numeric chain ID)\n - Import the caip chainId (e.g., scrollChainId) from @shapeshiftoss/caip\n - Import viem chain from viem/chains (or use raw numeric ID if not in viem)\n - The reverse map relayChainIdToChainId auto-generates via invert()\n\nFILE 2: packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n - Add case CHAIN_REFERENCE.NewChainMainnet: with ASSET_REFERENCE.NewChain + ASSET_NAMESPACE.slip44\n\nNO CHANGES NEEDED (for EVM chains):\n - getRelayAssetAddress.ts (uses generic isNativeEvmAsset + DEFAULT_RELAY_EVM_TOKEN_ADDRESS)\n - getRelayDefaultUserAddress.ts (falls through to DEFAULT_RELAY_EVM_USER_ADDRESS default)\n\nUPSTREAM DEPS REQUIRED (in @shapeshiftoss packages):\n - @shapeshiftoss/caip: export newChainChainId, CHAIN_REFERENCE.NewChainMainnet, ASSET_REFERENCE.NewChain\n - @shapeshiftoss/types: KnownChainIds.NewChainMainnet\n - @shapeshiftoss/chain-adapters: NewChain chain adapter class\n - viem/chains: chain config (or custom if not in viem)\n\nRELAY API: https://api.relay.link (env: VITE_RELAY_API_URL) - no per-chain config needed\n\n=== ASSET DATA REGENERATION (per chain) ===\n\nAfter integrating each chain, run a partial assets data regen to populate the token list.\n\nFILE 1 (CREATE): scripts/generateAssetData/\u003cchainname\u003e/index.ts\n Pattern (identical for all EVM chains):\n import { \u003cchainname\u003eChainId } from '@shapeshiftoss/caip'\n import type { Asset } from '@shapeshiftoss/types'\n import { \u003cchainname\u003e, unfreeze } from '@shapeshiftoss/utils'\n import * as coingecko from '../coingecko'\n export const getAssets = async (): Promise\u003cAsset[]\u003e =\u003e {\n const assets = await coingecko.getAssets(\u003cchainname\u003eChainId)\n return [...assets, unfreeze(\u003cchainname\u003e)]\n }\n\nFILE 2 (MODIFY): scripts/generateAssetData/coingecko.ts\n - Import \u003cchainname\u003eChainId from @shapeshiftoss/caip\n - Import \u003cchainname\u003e native asset from @shapeshiftoss/utils\n - Add case in the switch: case \u003cchainname\u003eChainId: return { assetNamespace: ASSET_NAMESPACE.erc20, category: adapters.chainIdToCoingeckoAssetPlatform(chainId), explorer/explorerAddressLink/explorerTxLink from \u003cchainname\u003e utils }\n - NOTE: chains not on CoinGecko will only have the native asset (no ERC20 token list)\n\nFILE 3 (MODIFY): scripts/generateAssetData/generateAssetData.ts\n - Import: import * as \u003cchainname\u003e from './\u003cchainname\u003e'\n - Call: const \u003cchainname\u003eAssets = await \u003cchainname\u003e.getAssets()\n - Spread into unfilteredAssetData: ...\u003cchainname\u003eAssets\n\nCOMMAND: yarn generate:asset-data\n This regenerates: src/generated/asset-data.json + related-asset-index + manifest + compressed assets\n\n=== DRAFT PR CREATION (final step per chain) ===\n\nAfter all code changes are complete for a chain, open a draft PR using the repo template.\n\nBRANCH NAMING: feat/integrate-\u003cchainname\u003e-relay (e.g. feat/integrate-scroll-relay)\n\nCOMMAND:\n gh pr create --draft --title 'feat: integrate \u003cChainName\u003e (chainId: \u003cid\u003e) via Relay' --body \"$(cat \u003c\u003c'PREOF'\n ## Description\n\n Add \u003cChainName\u003e (chainId: \u003cid\u003e) as a second-class EVM chain in ShapeShift Web with Relay bridge support.\n\n **Changes:**\n - Plugin registration in src/plugins/\u003cchainname\u003e/\n - Feature flag `\u003cChainName\u003e` in preferencesSlice\n - Relay swapper chain mapping in RelaySwapper/constant.ts\n - Asset data generation via CoinGecko (`\u003ccoingecko_platform_id\u003e`)\n - Environment config for RPC URL\n\n **Chain details:**\n - TVL: \u003ctvl\u003e\n - Native token: \u003ctoken\u003e (18 decimals)\n - Architecture: \u003carch_type\u003e\n - RPC: \u003crpc_url\u003e\n - Explorer: \u003cexplorer_url\u003e\n\n ## Issue (if applicable)\n\n Part of #11902\n\n ## Risk\n\n Low risk — new chain behind feature flag (`\u003cChainName\u003e`), no existing functionality affected.\n\n \u003e New chain plugin + Relay bridge mapping. No modifications to existing chain logic.\n\n ## Testing\n\n ### Engineering\n\n 1. Enable feature flag: set `VITE_FEATURE_\u003cCHAINNAME\u003e=true` in .env\n 2. Verify chain appears in supported chains list\n 3. Verify native token balance loads (connect wallet with \u003ctoken\u003e on \u003cChainName\u003e)\n 4. Verify Relay bridge quote works: bridge ETH from Ethereum → \u003cChainName\u003e\n 5. Run `yarn lint --fix \u0026\u0026 yarn type-check` — must pass\n\n ### Operations\n\n - [x] :checkered_flag: My feature is behind a flag and doesn't require operations testing (yet)\n\n ## Screenshots (if applicable)\n\n N/A — chain integration, no UI changes.\n PREOF\n )\"\n\nNOTE: Replace all \u003cplaceholders\u003e with actual chain values from the bead description/notes.\nNOTE: Use --draft flag to create as draft PR.\nNOTE: Branch off develop (main branch is develop, not main).", - "status": "open", - "priority": 0, - "issue_type": "epic", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:27Z", - "external_ref": "gh-11902", - "labels": [ - "chain-integration", - "evm", - "relay" - ], - "dependents": [ - { - "id": "ss-dx5.1", - "title": "Integrate Scroll (chainId: 534352, ETH, zkEVM L2)", - "description": "TVL: $468.5M | RPC: https://rpc.scroll.io/ | Explorer: https://scrollscan.com | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/534352/light.png (dark: dark.png)\nCoinGecko: scroll\nArch: zkEVM L2\nViem: standard (SELFDESTRUCT disabled, precompile limits)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "in_progress", - "priority": 1, - "issue_type": "task", - "assignee": "NeOMakinG", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:23Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:24:10Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.10", - "title": "Integrate Mode (chainId: 34443, ETH, OP Stack L2)", - "description": "TVL: $69.5M | RPC: https://mainnet.mode.network/ | Explorer: https://explorer.mode.network | Token Support: All | Pattern B (RPC-only) | DeFi-focused L2", - "notes": "Logo: https://assets.relay.link/icons/34443/light.png (dark: dark.png)\nCoinGecko: mode\nArch: OP Stack L2 (DeFi-focused)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:36Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.11", - "title": "Integrate Sei (chainId: 1329, SEI, L1 with EVM)", - "description": "TVL: $69.5M | RPC: https://evm-rpc.sei-apis.com | Explorer: https://seitrace.com | Token Support: Limited | Pattern B (RPC-only) | Parallelized EVM", - "notes": "Logo: https://assets.relay.link/icons/1329/light.png (dark: dark.png)\nCoinGecko: sei-v2 (⚠️ NOT 'sei'! Deprecated sei-network entry exists with null chain_identifier)\nArch: L1 with EVM (Parallelized EVM)\n⚠️ USER-FLAGGED CHAIN: Optimistic parallel execution, EVM + CosmWasm interop. May have RPC quirks or swap issues. TEST THOROUGHLY before full integration.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] thorough-testing\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:36Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.12", - "title": "Integrate Ethereal (chainId: 5064014, USDe, App-specific L2)", - "description": "TVL: $65.3M | RPC: https://rpc.ethereal.trade | Explorer: https://explorer.ethereal.trade | Token Support: Limited | Pattern B (RPC-only) | Ethena ecosystem, USDe-native", - "notes": "\nLogo: https://assets.relay.link/icons/5064014/light.png (dark: dark.png)\nCoinGecko platform: ❌ NOT ON COINGECKO (native-only asset, no token list)\nCoinGecko native ID: N/A (USDe — use ethena-usde as CoinGecko coin ID)\nArch: App-specific L2 (Ethena ecosystem)\nNative token: USDe (stablecoin as gas — NOT ETH-native)\nSLIP44: 60 (Ethereum)\nETH-native: NO — USDe gas token\nViem: ❌ NOT IN VIEM — needs defineChain({ id: 5064014, ... })\nAcross: ❌ NOT SUPPORTED\nZerion ID: TBD (likely \"ethereal\" — verify when integrating)\n\n🔴 CRITICAL QUIRKS:\n- Not in viem: Must use defineChain() in RelaySwapper constant.ts\n- Not on CoinGecko: Only native asset, no ERC20 token list from CoinGecko\n- USDe is gas: Stablecoin-native chain (like Stable with gUSDT)\n- adapter.json: {\"eip155:5064014/slip44:60\":\"ethena-usde\"}\n- relatedAssetKey: null (NOT eip155:1/slip44:60)\n- Does NOT affect ethereum test array or market-service counts\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_5064014/adapter.json\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add etherealChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId (use defineChain() since not in viem)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/ethereal/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts (will be native-only)\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-ethereal-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:42:34Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.13", - "title": "Integrate Hemi (chainId: 43111, ETH, Bitcoin L2)", - "description": "TVL: $57.2M | RPC: https://rpc.hemi.network/rpc | Explorer: https://explorer.hemi.xyz | Token Support: All | Pattern B (RPC-only) | Bitcoin-Ethereum supernetwork", - "notes": "\nLogo: https://assets.relay.link/icons/43111/light.png (dark: dark.png)\nCoinGecko platform: hemi\nCoinGecko native ID: weth (but chain uses ETH — adapter.json maps to \"ethereum\")\nArch: Bitcoin L2 (OP Stack compatible)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ hemi (id: 43111) — import { hemi } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"hemi\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_43111/adapter.json → {\"eip155:43111/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add hemiChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"hemi\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:43111/slip44:60 to ethereum array in index.test.ts (match import order)\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:43111/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [hemiChainId]: hemi.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/hemi/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-hemi-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:42:47Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.14", - "title": "Integrate World Chain (chainId: 480, ETH, OP Stack L2)", - "description": "TVL: $51.6M | RPC: https://worldchain-mainnet.gateway.tenderly.co | Explorer: https://worldscan.org | Token Support: All | Pattern B (RPC-only) | Worldcoin ecosystem", - "notes": "\nLogo: https://assets.relay.link/icons/480/light.png (dark: dark.png)\nCoinGecko platform: world-chain\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (Worldcoin ecosystem)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ worldchain (id: 480) — import { worldchain } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 480)\nZerion ID: \"world-chain\" (hyphenated)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_480/adapter.json → {\"eip155:480/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add worldChainChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"world-chain\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [worldChainChainId]: worldchain.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:480/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:480/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [worldChainChainId]: worldchain.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/worldchain/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-worldchain-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:00Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:02Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.15", - "title": "Integrate Plume (chainId: 98866, PLUME, RWA L2)", - "description": "TVL: $48.4M | RPC: https://rpc.plume.org | Explorer: https://explorer.plume.org | Token Support: All | Pattern B (RPC-only) | Real-world asset tokenization", - "notes": "\nLogo: https://assets.relay.link/icons/98866/light.png (dark: dark.png)\nCoinGecko platform: plume-network (⚠️ NOT \"plume\"!)\nCoinGecko native ID: plume\nArch: RWA L2 (Real World Assets focus)\nNative token: PLUME (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — PLUME gas token\nViem: ✅ plumeMainnet (id: 98866) — import { plumeMainnet } from \"viem/chains\"\n ⚠️ GOTCHA: \"plume\" in viem is chainId 98865 (WRONG!). Must use \"plumeMainnet\" for 98866.\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"plume\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_98866/adapter.json → {\"eip155:98866/slip44:60\":\"plume\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add plumeChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"plume\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [plumeChainId]: plumeMainnet.id to chainIdToRelayChainId (⚠️ use plumeMainnet NOT plume)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/plume/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-plume-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:14Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.16", - "title": "Integrate Story (chainId: 1514, IP, L1)", - "description": "TVL: $42.4M | RPC: https://mainnet.storyrpc.io | Explorer: https://storyscan.xyz | Token Support: All | Pattern B (RPC-only) | IP blockchain", - "notes": "\nLogo: https://assets.relay.link/icons/1514/light.png (dark: dark.png)\nCoinGecko platform: story\nCoinGecko native ID: story-2 (⚠️ NOT \"story\"!)\nArch: L1 (IP/Intellectual Property blockchain)\nNative token: IP (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — IP gas token\nViem: ✅ story (id: 1514) — import { story } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"story\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_1514/adapter.json → {\"eip155:1514/slip44:60\":\"story-2\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add storyChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"story\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [storyChainId]: story.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/story/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-story-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:23Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.17", - "title": "Integrate Celo (chainId: 42220, CELO, L1)", - "description": "TVL: $39.7M | RPC: https://forno.celo.org | Explorer: https://celoscan.io | Token Support: All | Pattern B (RPC-only) | Mobile-first, established chain", - "notes": "\nLogo: https://assets.relay.link/icons/42220/light.png (dark: dark.png)\nCoinGecko platform: celo\nCoinGecko native ID: celo\nArch: L1 (mobile-first blockchain)\nNative token: CELO (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — CELO gas token\nViem: ✅ celo (id: 42220) — import { celo } from \"viem/chains\"\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"celo\" (standard lowercase)\n\n🔴 CRITICAL QUIRKS:\n- CELO is BOTH the native gas token AND an ERC20 token on the chain\n- Relay may use wrapped CELO — check relayTransactionMetadata.assetRequiringApproval\n- CoinGecko has \"celo\" as platform, \"celo\" as native coin ID\n- May need special handling for the native-token-as-ERC20 duality\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_42220/adapter.json → {\"eip155:42220/slip44:60\":\"celo\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add celoChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"celo\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [celoChainId]: celo.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/celo/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-celo-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:34Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.18", - "title": "Integrate Blast (chainId: 81457, ETH, OP Stack L2)", - "description": "TVL: $36.7M | RPC: https://rpc.blast.io/ | Explorer: https://blastscan.io | Token Support: All | Pattern B (RPC-only) | Native yield, Blur ecosystem", - "notes": "\nLogo: https://assets.relay.link/icons/81457/light.png (dark: dark.png)\nCoinGecko platform: blast\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (rebasing ETH from L1 staking yield)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ blast (id: 81457) — import { blast } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 81457)\nZerion ID: \"blast\" (standard lowercase)\n\n🔴 CRITICAL QUIRKS:\n- Rebasing ETH: ETH balance auto-increases from L1 staking yield\n- USDB also rebases: Blast native stablecoin has similar behavior\n- May need special balance display handling for rebasing tokens\n- OP Stack based but with custom yield mechanics\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_81457/adapter.json → {\"eip155:81457/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add blastChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"blast\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [blastChainId]: blast.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:81457/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:81457/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [blastChainId]: blast.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/blast/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-blast-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:43:47Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.19", - "title": "Integrate zkSync Era (chainId: 324, ETH, zkEVM L2)", - "description": "TVL: $25.2M | RPC: https://mainnet.era.zksync.io | WS: wss://mainnet.era.zksync.io/ws | Explorer: https://explorer.zksync.io | Token Support: All | Pattern B (RPC-only) | Major zkEVM", - "notes": "\nLogo: https://assets.relay.link/icons/324/light.png (dark: dark.png)\nCoinGecko platform: zksync (⚠️ NOT \"zksync-era\"!)\nCoinGecko native ID: ethereum\nArch: zkEVM L2 (zkSync Era — Type 113 EIP-712 transactions)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ zksync (id: 324) — import { zksync } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 324)\nZerion ID: \"zksync-era\" (hyphenated — verify when integrating)\n\n🔴 CRITICAL QUIRKS:\n- Type 113 (EIP-712) transactions — NOT standard EIP-1559!\n- Viem has special zksync chainConfig for EIP-712 serialization\n- May need custom transaction type handling in chain adapter\n- Gas estimation uses zks_estimateFee RPC (not standard eth_estimateGas)\n- Account abstraction (AA) native support — paymaster patterns\n- Abstract (chainId: 2741) is zkSync-based too — shared architecture\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_324/adapter.json → {\"eip155:324/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add zksyncChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"zksync-era\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [zksyncChainId]: zksync.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:324/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:324/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [zksyncChainId]: zksync.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/zksync/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-zksync-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:01Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:07Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.2", - "title": "Integrate Ink (chainId: 57073, ETH, OP Stack L2)", - "description": "TVL: $448.3M | RPC: https://ink.drpc.org | Explorer: https://explorer.inkonchain.com | Token Support: All | Pattern B (RPC-only) | Kraken's L2", - "notes": "Logo: https://assets.relay.link/icons/57073/light.png (dark: dark.png)\nCoinGecko: ink\nArch: OP Stack L2 (Kraken)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:34Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.20", - "title": "Integrate Flow EVM (chainId: 747, FLOW, L1 with EVM)", - "description": "TVL: $25.0M | RPC: https://mainnet.evm.nodes.onflow.org | WS: wss://mainnet.evm.nodes.onflow.org | Explorer: https://evm.flowscan.io | Token Support: All | Pattern B (RPC-only) | Dapper Labs", - "notes": "\nLogo: https://assets.relay.link/icons/747/light.png (dark: dark.png)\nCoinGecko platform: flow-evm\nCoinGecko native ID: flow\nArch: L1 with EVM (Flow blockchain EVM layer)\nNative token: FLOW (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: NO — FLOW gas token\nViem: ✅ flowMainnet (id: 747) — import { flowMainnet } from \"viem/chains\"\n ⚠️ GOTCHA: Export is \"flowMainnet\" NOT \"flow\"!\nAcross: ❌ NOT SUPPORTED\nZerion ID: \"flow-evm\" (match CoinGecko platform name)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_747/adapter.json → {\"eip155:747/slip44:60\":\"flow\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add flowEvmChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"flow-evm\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ❌ SKIP — not supported\n[ ] ETH test ordering: ❌ SKIP — not ETH-native\n[ ] Market-service counts: ❌ SKIP — not ETH-native\n[ ] relatedAssetKey: null (NOT eip155:1/slip44:60)\n\n--- RELAY ACTIVATION ---\n[ ] Add [flowEvmChainId]: flowMainnet.id to chainIdToRelayChainId (⚠️ use flowMainnet NOT flow)\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/flowEvm/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-flow-evm-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:18Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.21", - "title": "Integrate Soneium (chainId: 1868, ETH, OP Stack L2)", - "description": "TVL: $21.1M | RPC: https://rpc.soneium.org/ | Explorer: https://soneium.blockscout.com | Token Support: All | Pattern B (RPC-only) | Sony's L2", - "notes": "\nLogo: https://assets.relay.link/icons/1868/light.png (dark: dark.png)\nCoinGecko platform: soneium\nCoinGecko native ID: ethereum\nArch: OP Stack L2 (Sony ecosystem)\nNative token: ETH (18 decimals)\nSLIP44: 60 (Ethereum)\nETH-native: YES — affects test ordering + market-service counts\nViem: ✅ soneium (id: 1868) — import { soneium } from \"viem/chains\"\nAcross: ✅ SUPPORTED (chainId: 1868)\nZerion ID: \"soneium\" (standard lowercase)\n\n--- PHASE 1 LEARNED CHECKLIST (MANDATORY) ---\n[ ] adapter.json: Create packages/caip/src/adapters/coingecko/generated/eip155_1868/adapter.json → {\"eip155:1868/slip44:60\":\"ethereum\"}\n[ ] Wire adapter.json: Import+export from packages/caip/src/adapters/coingecko/generated/index.ts\n[ ] getCoingeckoSupportedChainIds: Add soneiumChainId (feature-flagged) in src/lib/coingecko/utils.ts\n[ ] Zerion: Add \"soneium\" to ZERION_CHAINS + ZERION_CHAINS_MAP in packages/types/src/zerion.ts\n[ ] Across: ✅ Add [soneiumChainId]: soneium.id to chainIdToAcrossChainId\n[ ] ETH test ordering: ✅ REQUIRED — add eip155:1868/slip44:60 to ethereum array in index.test.ts\n[ ] Market-service counts: ✅ REQUIRED — bump counts + add destructuring in coingecko.test.ts\n[ ] generateRelatedAssetIndex: Add eip155:1868/slip44:60 → eip155:1/slip44:60 to manualRelatedAssetIndex\n\n--- RELAY ACTIVATION ---\n[ ] Add [soneiumChainId]: soneium.id to chainIdToRelayChainId\n[ ] Add native asset case in relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/soneium/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to generateAssetData.ts\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-soneium-relay (off develop)\n[ ] gh pr create --draft\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass\n", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T22:44:28Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.22", - "title": "Integrate Abstract (chainId: 2741, ETH, zkSync-based L2)", - "description": "TVL: $20.8M | RPC: https://api.mainnet.abs.xyz | Explorer: https://abscan.org | Token Support: All | Pattern B (RPC-only) | Consumer crypto focus", - "notes": "Logo: https://assets.relay.link/icons/2741/light.png (dark: dark.png)\nCoinGecko: abstract\nArch: zkSync-based L2\n⚠️ zkVM SPECIAL: Inherits zkSync Type 113 (EIP-712) + native AA. Same handling as zkSync Era. const ZKSYNC_CHAINS = [324, 2741]\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] zksync-tx-serializer\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:38Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.23", - "title": "Integrate Ronin (chainId: 2020, RON, EVM Sidechain)", - "description": "TVL: $14.6M | RPC: https://api.roninchain.com/rpc | Explorer: https://app.roninchain.com | Token Support: All | Pattern B (RPC-only) | Axie/Sky Mavis ecosystem", - "notes": "Logo: https://assets.relay.link/icons/2020/light.png (dark: dark.png)\nCoinGecko: ronin\nArch: EVM Sidechain (Sky Mavis/Axie)\nViem key: ronin\n⚠️ NON-ETH GAS: RON - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:38Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.24", - "title": "Integrate Zircuit (chainId: 48900, ETH, zkEVM L2)", - "description": "TVL: $13.7M | RPC: https://mainnet.zircuit.com | Explorer: https://explorer.zircuit.com | Token Support: Limited | Pattern B (RPC-only) | AI-enabled security", - "notes": "Logo: https://assets.relay.link/icons/48900/light.png (dark: dark.png)\nCoinGecko: zircuit\nArch: zkEVM L2 (AI-enabled security)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:38Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.25", - "title": "Integrate Metis (chainId: 1088, METIS, Optimistic L2)", - "description": "TVL: $11.4M | RPC: https://metis-rpc.publicnode.com | Explorer: https://explorer.metis.io | Token Support: All | Pattern B (RPC-only) | Non-ETH native token, decentralized sequencer", - "notes": "Logo: https://assets.relay.link/icons/1088/light.png (dark: dark.png)\nCoinGecko: metis-andromeda (⚠️ NOT 'metis')\nArch: Optimistic L2\nViem key: metis\n⚠️ NON-ETH GAS: METIS - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:02Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:38Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.26", - "title": "Integrate Manta Pacific (chainId: 169, ETH, OP Stack L2)", - "description": "TVL: $10.7M | RPC: https://pacific-rpc.manta.network/http | Explorer: https://pacific-explorer.manta.network | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/169/light.png (dark: dark.png)\nCoinGecko: manta-pacific\nArch: OP Stack L2\nWS available: wss://pacific-rpc.manta.network/ws\nViem: standard OP Stack\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:03Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:38Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.27", - "title": "Integrate Taiko (chainId: 167000, ETH, L2)", - "description": "TVL: $7.2M | RPC: https://rpc.mainnet.taiko.xyz | Explorer: https://taikoscan.io | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/167000/light.png (dark: dark.png)\nCoinGecko: taiko\nArch: Type-1 zkEVM (based rollup, decentralized)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:27Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.28", - "title": "Integrate Morph (chainId: 2818, ETH, L2)", - "description": "TVL: $6.7M | RPC: https://rpc-quicknode.morphl2.io | Explorer: https://explorer.morphl2.io | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/2818/light.png (dark: dark.png)\nCoinGecko: morph-l2 (⚠️ NOT 'morph')\nArch: Optimistic zkEVM (consumer-focused)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:27Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.29", - "title": "Integrate SwellChain (chainId: 1923, ETH, L2)", - "description": "TVL: $4.6M | RPC: https://swell-mainnet.alt.technology | Explorer: https://explorer.swellnetwork.io | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1923/light.png (dark: dark.png)\nCoinGecko: swellchain\nArch: Optimistic L2 (restaking-focused)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:27Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.3", - "title": "Integrate Mantle (chainId: 5000, MNT, Optimistic L2)", - "description": "TVL: $433.3M | RPC: https://rpc.mantle.xyz | Explorer: https://mantlescan.xyz | Token Support: All | Pattern B (RPC-only) | Non-ETH native token (MNT)", - "notes": "Logo: https://assets.relay.link/icons/5000/light.png (dark: dark.png)\nCoinGecko: mantle\nArch: Optimistic L2\nViem key: mantle\n⚠️ NON-ETH GAS: MNT - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.30", - "title": "Integrate ApeChain (chainId: 33139, APE, L2)", - "description": "TVL: $4.3M | RPC: https://apechain.calderachain.xyz/http | Explorer: https://apescan.io | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/33139/light.png (dark: dark.png)\nCoinGecko: apechain\nArch: Arbitrum Orbit L3 (Bored Ape ecosystem)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:27Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.31", - "title": "Integrate Stable (chainId: 988, gUSDT, L2)", - "description": "TVL: $4.0M | RPC: https://rpc.stable.xyz | Explorer: https://stablescan.xyz | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/988/light.png (dark: dark.png)\nCoinGecko: stable\nArch: L2\n⚠️ NON-ETH GAS: gUSDT/USDT0 (stablecoin-native gas!) - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:28Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.32", - "title": "Integrate Gravity (chainId: 1625, G, L2)", - "description": "TVL: $4.0M | RPC: https://rpc.gravity.xyz | Explorer: https://explorer.gravity.xyz | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1625/light.png (dark: dark.png)\nCoinGecko: gravity-alpha (⚠️ NOT 'gravity')\nArch: L1 (Galxe ecosystem)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:28Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:39Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.33", - "title": "Integrate Boba Network (chainId: 288, ETH, L2)", - "description": "TVL: $2.3M | RPC: https://mainnet.boba.network | Explorer: https://bobascan.com | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/288/light.png (dark: dark.png)\nCoinGecko: boba (⚠️ NOT 'boba-network')\nArch: Optimistic L2 (hybrid compute)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:28Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.34", - "title": "Integrate Lisk (chainId: 1135, ETH, L2)", - "description": "TVL: $1.9M | RPC: https://rpc.api.lisk.com | Explorer: https://blockscout.lisk.com | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1135/light.png (dark: dark.png)\nCoinGecko: lisk\nArch: OP Stack L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:28Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.35", - "title": "Integrate Cyber (chainId: 7560, ETH, L2)", - "description": "TVL: $1.9M | RPC: https://cyber.alt.technology/ | Explorer: https://cyberscan.co | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/7560/light.png (dark: dark.png)\nCoinGecko: cyber\nArch: OP Stack L2 (social)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:28Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.36", - "title": "Integrate Somnia (chainId: 5031, SOMI, L2)", - "description": "TVL: $1.8M | RPC: https://api.infra.mainnet.somnia.network | Explorer: https://explorer.somnia.network | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/5031/light.png (dark: dark.png)\nCoinGecko: somnia\nArch: L1 (gaming/metaverse)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:29Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.37", - "title": "Integrate Polygon zkEVM (chainId: 1101, ETH, zkEVM L2)", - "description": "TVL: $1.8M | RPC: https://rpc.ankr.com/polygon_zkevm | Explorer: https://zkevm.polygonscan.com | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1101/light.png (dark: dark.png)\nCoinGecko: polygon-zkevm\nArch: zkEVM L2 (Polygon, most compatible Type-2)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:29Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.38", - "title": "Integrate Arbitrum Nova (chainId: 42170, ETH, L2)", - "description": "TVL: $419K | RPC: https://arbitrum-nova.publicnode.com | Explorer: https://nova.arbiscan.io | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/42170/light.png (dark: dark.png)\nCoinGecko: arbitrum-nova\nArch: Arbitrum Nitro L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:29Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:40Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.39", - "title": "Integrate Zero Network (chainId: 543210, ETH, L2)", - "description": "TVL: $208K | RPC: https://zero-network.calderachain.xyz | Explorer: https://explorer.zero.network | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/543210/light.png (dark: dark.png)\nCoinGecko: zero-network (⚠️ chain_identifier is null - may need name-based lookup)\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:29Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.4", - "title": "Integrate Cronos (chainId: 25, CRO, EVM Sidechain)", - "description": "TVL: $376.1M | RPC: https://cronos.drpc.org | Explorer: https://cronoscan.com | Token Support: All | Pattern B (RPC-only) | Crypto.com ecosystem", - "notes": "Logo: https://assets.relay.link/icons/25/light.png (dark: dark.png)\nCoinGecko: cronos\nArch: EVM Sidechain (Crypto.com)\nViem key: cronos\n⚠️ NON-ETH GAS: CRO - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.40", - "title": "Integrate Superposition (chainId: 55244, ETH, L2)", - "description": "TVL: $174K | RPC: https://rpc.superposition.so | Explorer: https://explorer.superposition.so | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/55244/light.png (dark: dark.png)\nCoinGecko: Superposition (⚠️ case-sensitive capital S)\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:29Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.41", - "title": "Integrate Xai (chainId: 660279, XAI, L2)", - "description": "TVL: $107K | RPC: https://xai-chain.net/rpc | Explorer: https://explorer.xai-chain.net | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/660279/light.png (dark: dark.png)\nCoinGecko: xai\nArch: Arbitrum Orbit L3\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:30Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.42", - "title": "Integrate Corn (chainId: 21000000, BTCN, L2)", - "description": "TVL: $93K | RPC: https://mainnet.corn-rpc.com | Explorer: https://cornscan.io | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/21000000/light.png (dark: dark.png)\nCoinGecko: corn\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:30Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.43", - "title": "Integrate Superseed (chainId: 5330, ETH, L2)", - "description": "TVL: $76K | RPC: https://mainnet.superseed.xyz | Explorer: https://explorer.superseed.xyz | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/5330/light.png (dark: dark.png)\nCoinGecko: superseed\nArch: OP Stack L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:30Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.44", - "title": "Integrate Shape (chainId: 360, ETH, L2)", - "description": "TVL: $66K | RPC: https://mainnet.shape.network | Explorer: https://shapescan.xyz | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/360/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: OP Stack L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:30Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:41Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.45", - "title": "Integrate Ancient8 (chainId: 888888888, ETH, L2)", - "description": "TVL: $45K | RPC: https://rpc.ancient8.gg/ | Explorer: https://scan.ancient8.gg | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/888888888/light.png (dark: dark.png)\nCoinGecko: ancient8\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:55Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.46", - "title": "Integrate Zora (chainId: 7777777, ETH, L2)", - "description": "TVL: $39K | RPC: https://rpc.zora.energy | Explorer: https://explorer.zora.energy | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/7777777/light.png (dark: dark.png)\nCoinGecko: zora-network (⚠️ NOT 'zora')\nArch: OP Stack L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:55Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.47", - "title": "Integrate Redstone (chainId: 690, ETH, L2)", - "description": "TVL: $35K | RPC: https://rpc.redstonechain.com | Explorer: https://explorer.redstone.xyz | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/690/light.png (dark: dark.png)\nCoinGecko: redstone\nArch: OP Stack L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:55Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.48", - "title": "Integrate RARI (chainId: 1380012617, ETH, L2)", - "description": "TVL: $13K | RPC: https://mainnet.rpc.rarichain.org/http | Explorer: https://mainnet.explorer.rarichain.org | Token Support: All | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1380012617/light.png (dark: dark.png)\nCoinGecko: rari\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:56Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.49", - "title": "Integrate Degen (chainId: 666666666, DEGEN, L2)", - "description": "TVL: $53 | RPC: https://rpc.degen.tips | Explorer: https://explorer.degen.tips | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/666666666/light.png (dark: dark.png)\nCoinGecko: degen\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:56Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.5", - "title": "Integrate Berachain (chainId: 80094, BERA, PoL L1)", - "description": "TVL: $324.3M | RPC: https://rpc.berachain.com/ | Explorer: https://beratrail.io | Token Support: All | Pattern B (RPC-only) | Proof of Liquidity consensus", - "notes": "Logo: https://assets.relay.link/icons/80094/light.png (dark: dark.png)\nCoinGecko: berachain\nArch: L1 (Proof of Liquidity)\nViem key: berachain\n⚠️ NON-ETH GAS: BERA - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.50", - "title": "Integrate Perennial (chainId: 1424, ETH, L2)", - "description": "TVL: N/A | RPC: https://rpc-perennial-lsv53i0ed8.t.conduit.xyz | Explorer: https://explorer.perennial.foundation | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/1424/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:56Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:42Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.51", - "title": "Integrate AppChain (chainId: 466, ETH, L2)", - "description": "TVL: N/A | RPC: https://appchain.calderachain.xyz/http | Explorer: https://explorer.appchain.xyz | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/466/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:56Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.52", - "title": "Integrate Forma (chainId: 984122, TIA, L2)", - "description": "TVL: N/A | RPC: https://rpc.forma.art | Explorer: https://explorer.forma.art | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/984122/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:57Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.53", - "title": "Integrate B3 (chainId: 8333, ETH, L2)", - "description": "TVL: N/A | RPC: https://mainnet-rpc.b3.fun/http | Explorer: https://explorer.b3.fun | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/8333/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:57Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.54", - "title": "Integrate Funkichain (chainId: 33979, ETH, L2)", - "description": "TVL: N/A | RPC: https://rpc-mainnet.funkichain.com | Explorer: https://explorer.funkichain.com | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/33979/light.png (dark: dark.png)\nCoinGecko: funki (⚠️ NOT 'funkichain')\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:57Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.55", - "title": "Integrate Arena-Z (chainId: 7897, ETH, L2)", - "description": "TVL: N/A | RPC: https://rpc.arena-z.gg | Explorer: https://explorer.arena-z.gg | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/7897/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:57Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.56", - "title": "Integrate Animechain (chainId: 69000, ANIME, L2)", - "description": "TVL: N/A | RPC: https://public-rpc.anime.xyz/ | Explorer: https://explorer-animechain-39xf6m45e3.t.conduit.xyz | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/69000/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:58Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:43Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.57", - "title": "Integrate Mythos (chainId: 42018, ETH, L2)", - "description": "TVL: N/A | RPC: https://mythos-mainnet.g.alchemy.com/public/ | Explorer: https://mythos-mainnet.explorer.alchemy.com | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/42018/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:58Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:44Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.58", - "title": "Integrate Gunz (chainId: 43419, GUN, L2)", - "description": "TVL: N/A | RPC: https://subnets.avax.network/gunzilla/mainnet/rpc | Explorer: https://gunzscan.io | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/43419/light.png (dark: dark.png)\nCoinGecko: gunz\nArch: L2 (Avax subnet)\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:44Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.59", - "title": "Integrate Syndicate Commons (chainId: 510003, SYND, L2)", - "description": "TVL: N/A | RPC: https://commons.rpc.syndicate.io | Explorer: https://commons.explorer.syndicate.io | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/510003/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:44Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.6", - "title": "Integrate Linea (chainId: 59144, ETH, zkEVM L2)", - "description": "TVL: $156.7M | RPC: https://rpc.linea.build | Explorer: https://lineascan.build | Token Support: All | Pattern B (RPC-only) | Consensys L2", - "notes": "Logo: https://assets.relay.link/icons/59144/light.png (dark: dark.png)\nCoinGecko: linea\nArch: zkEVM L2 (Consensys)\nViem: custom linea_estimateGas RPC method - use viem chainConfig with custom serializers\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:24Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.60", - "title": "Integrate Powerloom v2 (chainId: 7869, POWER, L2)", - "description": "TVL: N/A | RPC: https://rpc-v2.powerloom.network | Explorer: https://explorer-v2.powerloom.network | Token Support: Limited | Pattern B (RPC-only)", - "notes": "Logo: https://assets.relay.link/icons/7869/light.png (dark: dark.png)\nCoinGecko: ❌ NOT ON COINGECKO\nArch: L2\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:44Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.61", - "title": "Integrate Sanko (chainId: 1996, DMT, L2) [DISABLED on Relay]", - "description": "TVL: N/A | RPC: https://mainnet.sanko.xyz | Explorer: https://explorer.sanko.xyz | Token Support: Limited | Pattern B (RPC-only) | WARNING: Currently DISABLED on Relay.link", - "notes": "Logo: https://assets.relay.link/icons/1996/light.png (dark: dark.png)\nCoinGecko: sanko\nArch: Arbitrum Orbit L3\n⚠️ DISABLED on Relay.link - do not prioritize\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 4, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:56:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:44Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.62", - "title": "Integrate Solana (chainId: 792703809, SVM, SOL)", - "description": "VM: SVM | RPC: https://api.mainnet-beta.solana.com | Explorer: https://solscan.io | Decimals: 9 | Requires SVM-specific chain adapter, NOT Pattern B", - "notes": "CoinGecko native token: solana\nArch: SVM (Solana Virtual Machine)\nNote: Solana already partially supported in ShapeShift. This is specifically for Relay bridge integration.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:16Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:09Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.63", - "title": "Integrate Hyperliquid (chainId: 1337, HypeVM, USDC)", - "description": "VM: HypeVM | RPC: https://api.hyperliquid.xyz | Explorer: https://app.hyperliquid.xyz/explorer | Decimals: 8 | Requires specialized chain adapter", - "notes": "CoinGecko native token: N/A (USDC)\nArch: HypeVM (custom VM)\nNote: Hyperliquid uses USDC as primary asset. Highly specialized exchange chain.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:16Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:09Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.64", - "title": "Integrate Tron (chainId: 728126428, TVM, TRX)", - "description": "VM: TVM | RPC: https://api.trongrid.io/jsonrpc | Explorer: https://tronscan.org/# | Decimals: 6 | Requires TVM-specific chain adapter", - "notes": "CoinGecko native token: tron\nArch: TVM (Tron Virtual Machine)\nNote: Completely different VM from EVM. Requires TVM-specific chain adapter.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:16Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:09Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.65", - "title": "Integrate Eclipse (chainId: 9286185, SVM, ETH)", - "description": "VM: SVM | RPC: https://mainnetbeta-rpc.eclipse.xyz | Explorer: https://eclipsescan.xyz | Decimals: 9 | Requires SVM-specific chain adapter", - "notes": "CoinGecko native token: N/A\nArch: SVM (Eclipse - Ethereum SVM L2)\nNote: SVM chain secured by Ethereum. Unique hybrid requiring SVM adapter + Ethereum settlement awareness.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:16Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:09Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.66", - "title": "Integrate Soon (chainId: 9286186, SVM, ETH)", - "description": "VM: SVM | RPC: https://rpc.mainnet.soo.network/rpc | Explorer: https://explorer.soo.network | Decimals: 9 | Requires SVM-specific chain adapter", - "notes": "CoinGecko native token: N/A\nArch: SVM\nNote: Another SVM chain. Can potentially share adapter code with Solana/Eclipse.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:17Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:09Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.67", - "title": "Integrate Bitcoin via Relay (chainId: 8253038, BVM, BTC)", - "description": "VM: BVM | RPC: https://bitcoin-mainnet.public.blastapi.io | Explorer: https://mempool.space | Decimals: 8 | Bitcoin already supported natively; this is Relay bridge integration", - "notes": "CoinGecko native token: bitcoin\nArch: BVM\nNote: Bitcoin already fully supported in ShapeShift. This bead tracks Relay bridge integration specifically - NOT native Bitcoin support.\nChecklist: [ ] relay-bridge-config", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:17Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:10Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.68", - "title": "Integrate Lighter (chainId: 3586256, LVM, USDC)", - "description": "VM: LVM | RPC: https://mainnet.zklighter.elliot.ai | Explorer: https://lighter.exchange/explorer | Decimals: 6 | Requires specialized chain adapter", - "notes": "CoinGecko native token: N/A\nArch: LVM (Lighter Virtual Machine - custom)\nNote: Specialized perpetuals exchange. Very niche VM.\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo", - "status": "open", - "priority": 3, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:57:17Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:15:10Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.7", - "title": "Integrate Sonic (chainId: 146, S, L1)", - "description": "TVL: $127.8M | RPC: https://rpc.soniclabs.com | Explorer: https://sonicscan.org | Token Support: All | Pattern B (RPC-only) | Fantom ecosystem evolution", - "notes": "Logo: https://assets.relay.link/icons/146/light.png (dark: dark.png)\nCoinGecko: sonic\nArch: L1 (ex-Fantom)\nViem key: sonic\n⚠️ NON-ETH GAS: S - must configure in chainIdToFeeAssetId.ts\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo [ ] fee-asset-config\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:25Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.8", - "title": "Integrate Unichain (chainId: 130, ETH, OP Stack L2)", - "description": "TVL: $95.4M | RPC: https://mainnet.unichain.org | Explorer: https://uniscan.xyz | Token Support: All | Pattern B (RPC-only) | Uniswap's L2", - "notes": "Logo: https://assets.relay.link/icons/130/light.png (dark: dark.png)\nCoinGecko: unichain\nArch: OP Stack L2 (Uniswap)\nViem: standard OP Stack - should just work\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 1, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:25Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - }, - { - "id": "ss-dx5.9", - "title": "Integrate BOB (chainId: 60808, ETH, OP Stack L2)", - "description": "TVL: $84.9M | RPC: https://rpc.gobob.xyz/ | Explorer: https://explorer.gobob.xyz | Token Support: Limited | Pattern B (RPC-only) | Bitcoin-focused L2", - "notes": "Logo: https://assets.relay.link/icons/60808/light.png (dark: dark.png)\nCoinGecko: bob-network (⚠️ chain_identifier is null - may need name-based lookup)\nArch: OP Stack L2 (Bitcoin-focused)\nViem: standard OP Stack\nChecklist: [ ] chain-adapters [ ] caip [ ] asset-service [ ] feature-flag [ ] plugin [ ] env-config [ ] icon/logo\n\n--- RELAY ACTIVATION ---\n[ ] Add to chainIdToRelayChainId in packages/swapper/src/swappers/RelaySwapper/constant.ts\n[ ] Add native asset case in packages/swapper/src/swappers/RelaySwapper/utils/relayTokenToAssetId.ts\n--- ASSET DATA REGEN ---\n[ ] Create scripts/generateAssetData/\u003cchainname\u003e/index.ts\n[ ] Add case to scripts/generateAssetData/coingecko.ts\n[ ] Add import + getAssets call to scripts/generateAssetData/generateAssetData.ts\n[ ] Run: yarn generate:asset-data\n--- DRAFT PR ---\n[ ] Branch: feat/integrate-\u003cchainname\u003e-relay (off develop)\n[ ] gh pr create --draft using .github/PULL_REQUEST_TEMPLATE.md\n[ ] Fill: Description, Issue (Part of #11902), Risk (Low - behind feature flag), Testing (enable flag + verify chain + relay bridge quote), Operations (behind flag checkbox)\n[ ] yarn lint --fix \u0026\u0026 yarn type-check must pass before PR", - "status": "open", - "priority": 2, - "issue_type": "task", - "owner": "14963751+NeOMakinG@users.noreply.github.com", - "created_at": "2026-02-17T10:55:59Z", - "created_by": "NeOMakinG", - "updated_at": "2026-02-17T11:21:35Z", - "dependency_type": "parent-child" - } - ], - "comments": [ - { - "id": 1, - "issue_id": "ss-dx5", - "author": "NeOMakinG", - "text": "=== COINGECKO ADAPTER - COMPLETE TOUCHPOINTS (5 places across 2 files) ===\n\nCRITICAL: The CoinGecko adapter has 5 separate places to modify for each new chain. Subagents frequently miss the chainIdToCoingeckoAssetPlatform switch case, which causes runtime failures when running asset generation.\n\nFILE 1: packages/caip/src/adapters/coingecko/index.ts (3 touchpoints)\n 1. CoingeckoAssetPlatform ENUM: Add ChainName = 'coingecko-platform-slug'\n 2. chainIdToCoingeckoAssetPlatform() SWITCH: Add case CHAIN_REFERENCE.ChainNameMainnet: return CoingeckoAssetPlatform.ChainName\n 3. coingeckoAssetPlatformToChainId() SWITCH: Add case CoingeckoAssetPlatform.ChainName: return chainNameChainId\n\n IMPORT NOTE: chainIdToCoingeckoAssetPlatform uses CHAIN_REFERENCE not chainId constants. Only import chainId constants if used in coingeckoAssetPlatformToChainId. Unused imports cause lint errors.\n\nFILE 2: packages/caip/src/adapters/coingecko/utils.ts (2 touchpoints)\n 4. COINGECKO_ASSET_PLATFORM_TO_CHAIN_ID_MAP: Add chainId to the buildByChainId loop (~line 280-310)\n 5. COINGECKO_NATIVE_ASSET_PLATFORM_TO_CHAIN_ID_MAP: Add [chainNameChainId]: { [chainNameAssetId]: 'coingecko-native-coin-id' } (~line 370-390)", - "created_at": "2026-02-17T14:05:13Z" - } - ] - } -] diff --git a/.claude/skills/qabot/SKILL.md b/.claude/skills/qabot/SKILL.md index 8e73947d7c3..6baa4203dfa 100644 --- a/.claude/skills/qabot/SKILL.md +++ b/.claude/skills/qabot/SKILL.md @@ -10,6 +10,8 @@ You are running QA tests and reporting results to the qabot dashboard. qabot is ## Environment +**Requires agent-browser >= 0.20.0** (native Rust daemon, no more Node.js/Playwright). + Secrets are stored in `~/.secrets` (sourced by `~/.zshrc`). Required env vars: - `QABOT_API_KEY` - shared API key for write access to qabot @@ -167,7 +169,12 @@ The native wallet requires a password on each session start. The wallet-health f 3. Click the wallet name button (e.g. "test", "teest") if wallet selection is shown 4. Focus the password input via JS eval (click --ref often times out on external origins): `eval "document.querySelector('input[type=password], input[placeholder*=Password]')?.focus()"` -5. Type `$NATIVE_WALLET_PASSWORD` character by character using `press` (NOT `fill` - React controlled inputs need keypress events) +5. Type the password - use `keyboard type` (preferred) or `press` char-by-char (NOT `fill` - React controlled inputs need keypress events): + ```bash + # PREFERRED: keyboard type command + agent-browser --session qabot keyboard type "$NATIVE_WALLET_PASSWORD" + # LEGACY: press char-by-char + ``` 6. Click "Next" via JS eval: `eval "$(cat /tmp/click-next.js)"` 7. Wait 8+ seconds for external origins to fully hydrate @@ -189,12 +196,20 @@ When using qabot for PR review validation on localhost: #### JS Eval & Smart Quotes (CRITICAL) -- **Smart quotes kill JS eval**: Claude's output produces unicode smart quotes (`"` `"` `'` `'`) which cause `SyntaxError: Invalid or unexpected token` in agent-browser eval. **NEVER write JS inline in eval commands.** Always write JS to a temp file first with `printf`, then `cat` it: +- **Smart quotes kill JS eval**: Claude's output produces unicode smart quotes (`"` `"` `'` `'`) which cause `SyntaxError: Invalid or unexpected token` in agent-browser eval. +- **PREFERRED: Use `--stdin` or `--base64`** to avoid smart quote issues entirely (no temp files needed): ```bash - printf 'var btns=document.querySelectorAll("button"); for(var i=0;i /tmp/click-preview.js - agent-browser --session qabot eval "$(cat /tmp/click-preview.js)" + # PREFERRED: pipe JS via stdin (no temp files needed) + echo 'document.querySelectorAll("button").forEach(b => { if(b.textContent.includes("Skip")) b.click() })' | agent-browser --session qabot eval --stdin + + # ALTERNATIVE: base64 encode to avoid all escaping issues + agent-browser --session qabot eval --base64 $(echo -n 'your JS code' | base64) + + # LEGACY (still works): write to temp file + printf 'code here' > /tmp/click.js + agent-browser --session qabot eval "$(cat /tmp/click.js)" ``` -- **Pre-write common click helpers at session start**: Before executing any steps, create these reusable JS files in `/tmp/`. This avoids smart quote issues and speeds up execution: +- **Pre-write common click helpers at session start** (can also be done with `--stdin`): Before executing any steps, create these reusable JS files in `/tmp/`. This avoids smart quote issues and speeds up execution: ```bash # Write all click helpers upfront printf 'var btns=document.querySelectorAll("button"); for(var i=0;i /tmp/click-close.js @@ -210,6 +225,63 @@ When using qabot for PR review validation on localhost: ``` Then use them: `agent-browser --session qabot eval "$(cat /tmp/click-close.js)"` +#### Snapshots + +```bash +# PREFERRED: interactive elements only (clean, flat list) +agent-browser --session qabot snapshot -i + +# Full accessibility tree (verbose, for debugging layout) +agent-browser --session qabot snapshot + +# Scope to specific element subtree +agent-browser --session qabot snapshot --selector "main" + +# Include cursor-interactive elements (onclick, pointer) +agent-browser --session qabot snapshot -C +``` + +#### Wait Commands (prefer over sleep) + +Use `wait` commands instead of arbitrary `sleep` calls where possible: + +```bash +# Network idle detection (page fully loaded): +agent-browser --session qabot wait --load networkidle + +# Wait for specific text to appear: +agent-browser --session qabot wait --text "Preview Trade" + +# Wait for text to disappear (loading states): +agent-browser --session qabot wait --fn "!document.body.innerText.includes('Loading...')" + +# Wait for element to appear: +agent-browser --session qabot wait "[data-testid=trade-form]" +``` + +Note: still use `sleep 8-10` for wallet unlock since app hydration isn't detectable via wait. + +#### Network Request Capture + +Built-in network request capture (no more manual fetch interceptors): + +```bash +# Capture network requests +agent-browser --session qabot network requests +agent-browser --session qabot network requests --filter "chaindefuser" + +# Clear captured requests +agent-browser --session qabot network requests --clear + +# Route/mock requests +agent-browser --session qabot network route "**/api/quote" --body '{"error":"test"}' +agent-browser --session qabot network unroute +``` + +#### Clipboard + +Clipboard read/write/copy/paste is available via `agent-browser --session qabot clipboard `. + #### Clicking on External Origins - **Clicking on external origins**: `click --ref` and `click --text` frequently time out on gome/release.shapeshift.com (elements blocked by overlays or slow hydration). **Always prefer JS eval for clicking on external origins**. @@ -233,6 +305,11 @@ When using qabot for PR review validation on localhost: ``` - **Screenshots are temporary**: Screenshots are saved to `/tmp/` only as a temp step before uploading to Vercel Blob. After uploading, `rm` the local file. Do NOT accumulate local screenshots. - **Delete after successful push**: The `step-complete` endpoint handles screenshot upload server-side. After a successful curl (HTTP 201), delete the local file with `rm -f`. +- **Annotated screenshots**: Use `--annotate` to overlay numbered labels on interactive elements - great for qabot reports where reviewers need to see what was clickable: + ```bash + agent-browser --session qabot screenshot --annotate /tmp/step-0.png + # Prints a legend mapping numbers to element refs + ``` - **Screenshots timing**: Always take screenshots AFTER verifying the expected state via snapshot, not before. Early screenshots capture intermediate states. #### Agent Thought / Action Logging @@ -256,6 +333,13 @@ When using qabot for PR review validation on localhost: sleep 3 # Then verify Confirm Details screen appeared via snapshot ``` +- **Use `wait --text` for swap flow**: Replace polling patterns with deterministic waits where possible: + ```bash + # Wait for quote to load + agent-browser --session qabot wait --text "Preview Trade" + # Wait for swap completion + agent-browser --session qabot wait --text "Complete" --timeout 120000 + ``` - **THORChain swap timing**: SOL->RUNE completes in ~10s, RUNE->SOL can take ~90s. Always poll with 120s timeout. - **Feedback dialog after swap**: A "How was your trade experience?" dialog appears after swaps complete. Dismiss with "Maybe Later" button. @@ -264,7 +348,7 @@ When using qabot for PR review validation on localhost: When you encounter what looks like a bug, **don't just report it — investigate it**: 1. **Verify identity**: Is this the exact same yield ID, same account ID, same chain? Check the URL params (`yieldId`, `accountId`). A "discrepancy" between two different yields isn't a bug. -2. **Check network requests**: Open the browser's Network tab (or use JS eval to intercept fetch responses) to see what the API actually returned vs what the UI shows. Include the raw API response in your agentThought. +2. **Check network requests**: Use `agent-browser --session qabot network requests` (or `--filter` for specific APIs) to see what the API actually returned vs what the UI shows. Include the raw API response in your agentThought. 3. **Read the codebase**: You have access to `~/Sites/shapeshiftWeb`. `grep` for the relevant component, selector, or API call. Understand WHERE the bug likely originates (frontend rendering? stale cache? API response?). 4. **Cross-reference surfaces**: Check the same data across multiple views (yield detail page, My Positions list, DeFi drawer, wallet drawer). Note exactly which surfaces show correct vs incorrect data. 5. **Navigate freely**: You can explore the entire app to verify bugs — click around, check different pages, use filters. Just don't execute transactions outside fixture constraints. diff --git a/.codex/config.toml b/.codex/config.toml index 125e9a4525e..f6a9d653bea 100644 --- a/.codex/config.toml +++ b/.codex/config.toml @@ -1 +1 @@ -model_instructions_file = "AGENTS.md" +model_instructions_file = "../AGENTS.md" diff --git a/.env b/.env index 246247877aa..012099c765a 100644 --- a/.env +++ b/.env @@ -149,36 +149,35 @@ VITE_ETHEREUM_NODE_URL=https://api.ethereum.shapeshift.com/api/v1/jsonrpc VITE_AVALANCHE_NODE_URL=https://api.avalanche.shapeshift.com/api/v1/jsonrpc VITE_OPTIMISM_NODE_URL=https://api.optimism.shapeshift.com/api/v1/jsonrpc VITE_BNBSMARTCHAIN_NODE_URL=https://api.bnbsmartchain.shapeshift.com/api/v1/jsonrpc -VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_1=https://bsc-dataseed.binance.org/ -VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_2=https://bsc-dataseed1.ninicoin.io/ -VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_3=https://bsc-rpc.publicnode.com VITE_POLYGON_NODE_URL=https://api.polygon.shapeshift.com/api/v1/jsonrpc VITE_GNOSIS_NODE_URL=https://api.gnosis.shapeshift.com/api/v1/jsonrpc VITE_ARBITRUM_NODE_URL=https://api.arbitrum.shapeshift.com/api/v1/jsonrpc VITE_BASE_NODE_URL=https://api.base.shapeshift.com/api/v1/jsonrpc -VITE_MONAD_NODE_URL=https://rpc.monad.xyz -VITE_PLASMA_NODE_URL=https://rpc.plasma.to -VITE_MANTLE_NODE_URL=https://rpc.mantle.xyz +VITE_MONAD_NODE_URL=https://monad-mainnet.drpc.org +VITE_PLASMA_NODE_URL=https://plasma.drpc.org +VITE_MANTLE_NODE_URL=https://mantle.drpc.org VITE_INK_NODE_URL=https://ink.drpc.org VITE_CRONOS_NODE_URL=https://cronos.drpc.org -VITE_MEGAETH_NODE_URL=https://mainnet.megaeth.com/rpc -VITE_LINEA_NODE_URL=https://rpc.linea.build -VITE_SCROLL_NODE_URL=https://rpc.scroll.io/ -VITE_KATANA_NODE_URL=https://rpc.katana.network +VITE_MEGAETH_NODE_URL=https://megaeth.drpc.org +VITE_LINEA_NODE_URL=https://linea.drpc.org +VITE_SCROLL_NODE_URL=https://scroll.drpc.org +VITE_KATANA_NODE_URL=https://katana.drpc.org VITE_ETHEREAL_NODE_URL=https://rpc.ethereal.trade -VITE_CELO_NODE_URL=https://forno.celo.org +VITE_CELO_NODE_URL=https://celo.drpc.org VITE_FLOWEVM_NODE_URL=https://mainnet.evm.nodes.onflow.org -VITE_PLUME_NODE_URL=https://rpc.plumenetwork.xyz +VITE_PLUME_NODE_URL=https://plume.drpc.org VITE_STORY_NODE_URL=https://mainnet.storyrpc.io -VITE_ZKSYNC_ERA_NODE_URL=https://mainnet.era.zksync.io -VITE_BLAST_NODE_URL=https://rpc.blast.io -VITE_WORLDCHAIN_NODE_URL=https://worldchain-mainnet.gateway.tenderly.co -VITE_HEMI_NODE_URL=https://rpc.hemi.network/rpc -VITE_SONIC_NODE_URL=https://rpc.soniclabs.com -VITE_UNICHAIN_NODE_URL=https://mainnet.unichain.org -VITE_BOB_NODE_URL=https://rpc.gobob.xyz -VITE_MODE_NODE_URL=https://mainnet.mode.network -VITE_SONEIUM_NODE_URL=https://rpc.soneium.org/ +VITE_HYPEREVM_NODE_URL=https://hyperliquid.drpc.org +VITE_ZKSYNC_ERA_NODE_URL=https://zksync.drpc.org +VITE_BLAST_NODE_URL=https://blast.drpc.org +VITE_WORLDCHAIN_NODE_URL=https://worldchain.drpc.org +VITE_HEMI_NODE_URL=https://hemi.drpc.org +VITE_SONIC_NODE_URL=https://sonic.drpc.org +VITE_UNICHAIN_NODE_URL=https://unichain.drpc.org +VITE_BOB_NODE_URL=https://bob.drpc.org +VITE_MODE_NODE_URL=https://mode.drpc.org +VITE_SONEIUM_NODE_URL=https://soneium.drpc.org +VITE_BERACHAIN_NODE_URL=https://berachain.drpc.org VITE_SEI_NODE_URL=https://evm-rpc.sei-apis.com VITE_THORCHAIN_NODE_URL=https://api.thorchain.shapeshift.com/lcd VITE_MAYACHAIN_NODE_URL=https://api.mayachain.shapeshift.com/lcd @@ -190,7 +189,6 @@ VITE_NEAR_NODE_URL=https://rpc.mainnet.near.org VITE_NEAR_NODE_URL_FALLBACK_1=https://near.lava.build VITE_NEAR_NODE_URL_FALLBACK_2=https://rpc.fastnear.com VITE_FASTNEAR_API_URL=https://api.fastnear.com -VITE_ALCHEMY_POLYGON_URL=https://polygon-mainnet.g.alchemy.com/v2/anoTMcIc2hbPUxri37h4DeuUwg2p5_xZ # midgard VITE_THORCHAIN_MIDGARD_URL=https://api.thorchain.shapeshift.com/midgard/v2 @@ -206,15 +204,9 @@ VITE_COINCAP_API_KEY=dab646843b251ce2d28864982989c335e1f0d32fa14e4ecc6b40cd057ec VITE_EXCHANGERATEHOST_BASE_URL=https://api.exchangerate.host VITE_EXCHANGERATEHOST_API_KEY=8f7515ffddef9d3e449b45f93108ca4d -# Alchemy API key - to be used either with Alchemy SDK or directly with the REST endpoints -VITE_ALCHEMY_API_KEY=anoTMcIc2hbPUxri37h4DeuUwg2p5_xZ - -# Moralis API key - to be used either with Alchemy SDK or directly with the REST endpoints +# Moralis API key VITE_MORALIS_API_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJub25jZSI6ImY1ZmVjMTg4LTc0YzUtNDk0ZC05ZmFjLTZmYzQ5MTAyZTVhOCIsIm9yZ0lkIjoiNDYzNTU5IiwidXNlcklkIjoiNDc2OTA5IiwidHlwZUlkIjoiODE0NWUwYjEtYjEwNi00NzQyLTg2NDAtNzk1NmU4ZGQ5ZGFkIiwidHlwZSI6IlBST0pFQ1QiLCJpYXQiOjE3NTQ0NzEyNTksImV4cCI6NDkxMDIzMTI1OX0.Aa-ELM_vZR0i7Z1nQfh0rsx6ES21DHNEbNsjL28AMMw -# Alchemy Solana endpoint for custom token import -VITE_ALCHEMY_SOLANA_BASE_URL=https://solana-mainnet.g.alchemy.com/v2 - # boardroom VITE_BOARDROOM_API_BASE_URL=https://api.boardroom.info/v1/protocols/shapeshift/ VITE_BOARDROOM_APP_BASE_URL=https://boardroom.io/shapeshift/ @@ -260,6 +252,9 @@ VITE_WALLET_CONNECT_RELAY_URL=wss://relay.walletconnect.com # Portals VITE_PORTALS_BASE_URL=https://api.proxy.shapeshift.com/api/v1/portals +# Proxy API +VITE_PROXY_API_BASE_URL=https://api.proxy.shapeshift.com + VITE_SNAP_ID=npm:@shapeshiftoss/metamask-snaps VITE_SNAP_VERSION=1.0.9 # VITE_SNAP_ID=local:http://localhost:9000 @@ -326,14 +321,12 @@ VITE_FEATURE_SUNIO_SWAP=true VITE_FEATURE_MONAD=true VITE_FEATURE_PLASMA=true VITE_FEATURE_WORLDCHAIN=false -VITE_HYPEREVM_NODE_URL=https://rpc.hyperliquid.xyz/evm VITE_FEATURE_HYPEREVM=true VITE_FEATURE_MANTLE=false VITE_FEATURE_INK=false VITE_FEATURE_CRONOS=false VITE_FEATURE_MEGAETH=false VITE_FEATURE_LINEA=false -VITE_BERACHAIN_NODE_URL=https://rpc.berachain.com VITE_FEATURE_BERACHAIN=false VITE_FEATURE_SCROLL=false VITE_FEATURE_NEAR=true diff --git a/.env.development b/.env.development index 5666ec50e22..0da3372f524 100644 --- a/.env.development +++ b/.env.development @@ -116,6 +116,9 @@ VITE_NOTIFICATIONS_SERVER_URL=https://dev-api.notifications-service.shapeshift.c # VITE_USER_SERVER_URL=/user-api # VITE_NOTIFICATIONS_SERVER_URL=/notifications-api +# Proxy API +VITE_PROXY_API_BASE_URL=https://dev-api.proxy.shapeshift.com + VITE_FEATURE_WC_DIRECT_CONNECTION=true VITE_FEATURE_CETUS_SWAP=true VITE_FEATURE_MANTLE=true diff --git a/docs/affiliates.md b/docs/affiliates.md new file mode 100644 index 00000000000..bcc099c79e0 --- /dev/null +++ b/docs/affiliates.md @@ -0,0 +1,121 @@ +# ShapeShift Affiliate Program + +Earn revenue share on swaps executed through your integration. + +## Quick Start + +### 1. Using the Swap Widget + +```tsx +import { SwapWidget } from '@shapeshiftoss/swap-widget' + + +``` + +### 2. Using the Public API + +Include these headers in your API requests: + +```bash +curl https://api.shapeshift.com/v1/swap/rates \ + -H "X-Affiliate-Address: 0xYourWalletAddress" \ + -H "Content-Type: application/json" \ + -d '{"sellAssetId": "...", "buyAssetId": "...", "sellAmountCryptoBaseUnit": "..."}' +``` + +Or use a partner code: + +```bash +curl https://api.shapeshift.com/v1/swap/rates \ + -H "X-Partner-Code: yourcode" \ + -H "Content-Type: application/json" \ + -d '...' +``` + +## Headers + +| Header | Description | +|--------|-------------| +| `X-Affiliate-Address` | Your EVM wallet address (0x...) | +| `X-Partner-Code` | Your partner code (if registered) | +| `X-Affiliate-Bps` | Override BPS (optional, 0-1000) | + +## Registering as an Affiliate + +1. Go to the [Affiliate Dashboard](https://affiliate.shapeshift.com) +2. Connect your wallet +3. Your address is automatically registered with default BPS +4. Optionally claim a partner code + +### Partner Codes + +Partner codes are short identifiers (3-32 alphanumeric characters) that map to your wallet. Benefits: + +- Easier to share than a wallet address +- Can be used in place of `X-Affiliate-Address` +- One code per affiliate + +Reserved codes: `shapeshift`, `ss`, `admin`, `api`, `test`, `demo` + +## Fee Structure + +| BPS | Percentage | Description | +|-----|------------|-------------| +| 10 | 0.1% | Minimum (API base) | +| 60 | 0.6% | Default | +| 100 | 1.0% | Example custom | + +- **BPS** = Basis Points (1 BPS = 0.01%) +- Fees are taken from the sell amount +- Related asset swaps (e.g., ETH → WETH) have 0% fee + +## Revenue Attribution + +Every swap executed through your integration is tracked: + +- Your affiliate address is recorded +- Volume and fees are calculated +- Stats available in the affiliate dashboard + +### Viewing Your Stats + +```bash +# Get your stats +curl "https://api.shapeshift.com/v1/affiliate/stats?address=0xYour..." + +# Response +{ + "totalSwaps": 1234, + "totalVolumeUsd": "1234567.89", + "totalFeesEarnedUsd": "7407.41" +} +``` + +## API Endpoints + +### Public Endpoints + +| Method | Endpoint | Description | +|--------|----------|-------------| +| GET | `/v1/affiliate/stats?address=...` | Get swap stats | +| GET | `/v1/partner/:code` | Resolve partner code | + +### Authenticated Endpoints (requires wallet signature) + +| Method | Endpoint | Description | +|--------|----------|-------------| +| POST | `/v1/affiliate` | Register as affiliate | +| PATCH | `/v1/affiliate/:address` | Update settings | +| POST | `/v1/affiliate/claim-code` | Claim partner code | + +## Support + +- **Dashboard**: https://affiliate.shapeshift.com +- **Discord**: https://discord.gg/shapeshift +- **Email**: affiliates@shapeshift.com diff --git a/docs/architecture/affiliate-data-model.md b/docs/architecture/affiliate-data-model.md new file mode 100644 index 00000000000..ab3a796e11c --- /dev/null +++ b/docs/architecture/affiliate-data-model.md @@ -0,0 +1,310 @@ +# Affiliate System Data Model + +## Overview + +This document defines the data model for the affiliate system, to be implemented in `shapeshift/microservices`. + +## Prisma Schema + +```prisma +// Add to prisma/schema.prisma in microservices + +model Affiliate { + id String @id @default(uuid()) + walletAddress String @unique @map("wallet_address") @db.VarChar(42) + partnerCode String? @unique @map("partner_code") @db.VarChar(32) + bps Int @default(60) + isActive Boolean @default(true) @map("is_active") + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + // Relations + swaps Swap[] @relation("AffiliateSwaps") + + @@map("affiliates") + @@index([partnerCode]) + @@index([isActive]) +} + +// Extend existing Swap model +model Swap { + // ... existing fields ... + + // New affiliate fields + affiliateAddress String? @map("affiliate_address") @db.VarChar(42) + affiliateBps Int? @map("affiliate_bps") + affiliateFeeUsd Decimal? @map("affiliate_fee_usd") @db.Decimal(18, 8) + + // Relation to affiliate (optional, for registered affiliates) + affiliate Affiliate? @relation("AffiliateSwaps", fields: [affiliateAddress], references: [walletAddress]) + + @@index([affiliateAddress]) +} + +// Partner codes can map to multiple affiliates (organizations) +model PartnerCodeMember { + id String @id @default(uuid()) + partnerCode String @map("partner_code") @db.VarChar(32) + walletAddress String @map("wallet_address") @db.VarChar(42) + role String @default("member") @db.VarChar(16) // "owner" | "admin" | "member" + createdAt DateTime @default(now()) @map("created_at") + + @@unique([partnerCode, walletAddress]) + @@map("partner_code_members") + @@index([partnerCode]) + @@index([walletAddress]) +} +``` + +## DTOs (Data Transfer Objects) + +```typescript +// packages/shared-types/src/affiliate.ts + +export interface AffiliateDto { + id: string + walletAddress: string + partnerCode: string | null + bps: number + isActive: boolean + createdAt: string + updatedAt: string +} + +export interface CreateAffiliateDto { + walletAddress: string + partnerCode?: string + bps?: number +} + +export interface UpdateAffiliateDto { + bps?: number + isActive?: boolean +} + +export interface AffiliateStatsDto { + totalSwaps: number + totalVolumeUsd: string + totalFeesEarnedUsd: string + periodStart?: string + periodEnd?: string +} + +export interface AffiliateSwapDto { + swapId: string + sellAsset: string + buyAsset: string + sellAmountUsd: string + buyAmountUsd: string + affiliateFeeUsd: string + status: string + createdAt: string + txHash?: string +} + +export interface ClaimPartnerCodeDto { + partnerCode: string +} + +export interface PartnerCodeResolutionDto { + partnerCode: string + affiliateAddress: string + bps: number +} +``` + +## API Contracts + +### GET /v1/affiliate/:address + +Get affiliate configuration by wallet address. + +**Response:** +```json +{ + "id": "uuid", + "walletAddress": "0x...", + "partnerCode": "vultisig", + "bps": 100, + "isActive": true, + "createdAt": "2026-03-12T00:00:00Z", + "updatedAt": "2026-03-12T00:00:00Z" +} +``` + +**404 Response:** Affiliate not registered (use default BPS) + +### POST /v1/affiliate + +Register as affiliate. Requires SIWE authentication. + +**Headers:** +``` +Authorization: Bearer +``` + +**Request:** +```json +{ + "walletAddress": "0x...", + "partnerCode": "mycode", + "bps": 60 +} +``` + +**Response:** Created affiliate object + +### PATCH /v1/affiliate/:address + +Update affiliate settings. Requires SIWE auth matching address. + +**Request:** +```json +{ + "bps": 100 +} +``` + +### GET /v1/affiliate/:address/stats + +Get aggregate swap statistics. + +**Query params:** +- `startDate` (optional): ISO date +- `endDate` (optional): ISO date + +**Response:** +```json +{ + "totalSwaps": 1234, + "totalVolumeUsd": "1234567.89", + "totalFeesEarnedUsd": "7407.41" +} +``` + +### GET /v1/affiliate/:address/swaps + +Get paginated swap history. + +**Query params:** +- `page` (default: 1) +- `limit` (default: 50, max: 100) +- `startDate` (optional) +- `endDate` (optional) + +**Response:** +```json +{ + "swaps": [ + { + "swapId": "uuid", + "sellAsset": "ETH", + "buyAsset": "BTC", + "sellAmountUsd": "1000.00", + "buyAmountUsd": "995.00", + "affiliateFeeUsd": "6.00", + "status": "completed", + "createdAt": "2026-03-12T00:00:00Z", + "txHash": "0x..." + } + ], + "pagination": { + "page": 1, + "limit": 50, + "total": 1234, + "pages": 25 + } +} +``` + +### GET /v1/partner/:code + +Resolve partner code to affiliate configuration. + +**Response:** +```json +{ + "partnerCode": "vultisig", + "affiliateAddress": "0x...", + "bps": 100 +} +``` + +### POST /v1/affiliate/claim-code + +Claim a partner code. Requires SIWE auth. + +**Request:** +```json +{ + "partnerCode": "mycode" +} +``` + +**Validation:** +- Code must be 3-32 alphanumeric characters +- Code must not be taken +- One code per affiliate (can transfer) + +## Migration + +```sql +-- Migration: add_affiliate_tables + +CREATE TABLE affiliates ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + wallet_address VARCHAR(42) NOT NULL UNIQUE, + partner_code VARCHAR(32) UNIQUE, + bps INTEGER NOT NULL DEFAULT 60, + is_active BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW() +); + +CREATE INDEX idx_affiliates_partner_code ON affiliates(partner_code); +CREATE INDEX idx_affiliates_is_active ON affiliates(is_active); + +-- Add columns to existing swaps table +ALTER TABLE swaps ADD COLUMN affiliate_address VARCHAR(42); +ALTER TABLE swaps ADD COLUMN affiliate_bps INTEGER; +ALTER TABLE swaps ADD COLUMN affiliate_fee_usd DECIMAL(18, 8); + +CREATE INDEX idx_swaps_affiliate_address ON swaps(affiliate_address); + +-- Partner code members (for organizations) +CREATE TABLE partner_code_members ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + partner_code VARCHAR(32) NOT NULL, + wallet_address VARCHAR(42) NOT NULL, + role VARCHAR(16) NOT NULL DEFAULT 'member', + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + UNIQUE(partner_code, wallet_address) +); + +CREATE INDEX idx_partner_code_members_code ON partner_code_members(partner_code); +CREATE INDEX idx_partner_code_members_wallet ON partner_code_members(wallet_address); +``` + +## Validation Rules + +### Wallet Address +- Must be valid EVM address (0x + 40 hex chars) +- Checksummed for storage + +### Partner Code +- 3-32 characters +- Alphanumeric + hyphens only +- Case-insensitive (stored lowercase) +- Reserved codes: `shapeshift`, `ss`, `admin`, `api`, `test` + +### BPS +- Range: 0-1000 (0% to 10%) +- Default: 60 (0.6%) +- Only modifiable by affiliate owner or admin + +## Security Considerations + +1. **SIWE Authentication**: All write operations require signed message proving wallet ownership +2. **Rate Limiting**: Stats endpoints rate-limited per address +3. **Address Validation**: Strict EVM address validation +4. **Partner Code Squatting**: Consider verification for branded codes diff --git a/docs/architecture/affiliate-system.md b/docs/architecture/affiliate-system.md new file mode 100644 index 00000000000..c1586ecc427 --- /dev/null +++ b/docs/architecture/affiliate-system.md @@ -0,0 +1,293 @@ +# Affiliate System Architecture + +## Overview + +The ShapeShift affiliate system allows partners to earn revenue share on swaps executed through their integration. This document describes the current state and proposed improvements. + +## Current State + +### Data Flow Diagram + +```mermaid +flowchart TB + subgraph "Web App" + WA[User initiates swap] + WA --> GBps[getAffiliateBps] + GBps --> |"DEFAULT_FEE_BPS = 60"|SwapperApi + SwapperApi --> SwapperPkg[packages/swapper] + end + + subgraph "Widget" + WG[SwapWidget Component] + WG --> |affiliateAddress prop|ApiClient + ApiClient --> |X-Affiliate-Address header|PublicApi + end + + subgraph "Public API" + PublicApi[packages/public-api] + PublicApi --> |affiliateInfo middleware|SwapperPkg + end + + subgraph "Swapper Packages" + SwapperPkg --> |affiliateBps param|Swappers + Swappers[Individual Swappers] + Swappers --> |THORChain: ss affiliate|THORChain + Swappers --> |Jupiter: REFER4Z...|Jupiter + Swappers --> |CoW: appData|CoWProtocol + Swappers --> |etc.|OtherDEXs + end + + subgraph "Microservices" + MS[swap-service] + MS --> |stores referralCode only|DB[(PostgreSQL)] + end + + SwapperPkg --> |swap executed|MS +``` + +### Component Details + +#### 1. Web App (`src/lib/fees/`) + +**Files:** +- `src/lib/fees/constant.ts` - Defines `DEFAULT_FEE_BPS = '60'` (0.6%) +- `src/lib/fees/utils.ts` - `getAffiliateBps()` function + +**Logic:** +```typescript +// src/lib/fees/constant.ts +export const DEFAULT_FEE_BPS = '60' // basis points (0.6%) + +// src/lib/fees/utils.ts +export const getAffiliateBps = (sellAsset: Asset, buyAsset: Asset): string => { + // Related asset swaps (e.g., ETH → WETH) have 0 fee + return isRelatedAssetSwap(sellAsset, buyAsset) ? '0' : DEFAULT_FEE_BPS +} +``` + +**Usage:** +- Called in `src/components/MultiHopTrade/hooks/useGetTradeRateInput.ts` +- Passed to `swapperApi` endpoints in `src/state/apis/swapper/swapperApi.ts` + +#### 2. Widget (`packages/swap-widget/`) + +**Props:** +```typescript +// packages/swap-widget/src/types/index.ts +export type SwapWidgetProps = { + affiliateAddress?: string // EVM address for affiliate + // ... other props +} +``` + +**API Client:** +```typescript +// packages/swap-widget/src/api/client.ts +// Passes affiliateAddress to API requests +``` + +**Current Limitation:** Widget only passes address, cannot configure custom BPS. + +#### 3. Public API (`packages/public-api/`) + +**Middleware:** +```typescript +// packages/public-api/src/middleware/auth.ts +export const affiliateAddress = (req, res, next) => { + const address = req.header('X-Affiliate-Address') + if (address && EVM_ADDRESS_REGEX.test(address)) { + req.affiliateInfo = { affiliateAddress: address } + } + next() +} +``` + +**Response Types:** +```typescript +// packages/public-api/src/types.ts +export type ApiRate = { + // ... + affiliateBps: string // Returned in responses +} + +export type RatesResponse = { + rates: ApiRate[] + affiliateAddress?: string // Echo back the affiliate +} +``` + +**Current Limitation:** Accepts address but doesn't look up affiliate-specific BPS. + +#### 4. Swapper Packages (`packages/swapper/`) + +Each swapper handles affiliate fees differently: + +| Swapper | Affiliate Mechanism | Config Location | +|---------|---------------------|-----------------| +| THORChain | `affiliate=ss` in memo | `THORCHAIN_AFFILIATE_NAME` | +| Mayachain | `affiliate=ssmaya` in memo | `MAYACHAIN_AFFILIATE_NAME` | +| Jupiter | `REFER4Z...` contract | `JUPITER_AFFILIATE_CONTRACT_ADDRESS` | +| CoW Protocol | `appData` JSON | Included in order | +| Butter | `shapeshift` affiliate | `BUTTERSWAP_AFFILIATE` | + +**BPS Flow:** +```typescript +// packages/swapper/src/swappers/*/getTradeQuote.ts +const quote = await getQuote({ + // ... + affiliateBps, // Passed through to DEX APIs +}) +``` + +#### 5. Microservices (`shapeshift/microservices`) + +**swap-service:** +```typescript +// apps/swap-service/src/swaps/swaps.service.ts +async createSwap(data: CreateSwapDto) { + // Stores referralCode (from user-service) + // Does NOT store affiliate address or BPS + const swap = await this.prisma.swap.create({ + data: { + // ... + referralCode, // From user-service lookup + // Missing: affiliateAddress, affiliateBps + }, + }) +} +``` + +**Current Limitation:** No affiliate tracking or revenue attribution. + +#### 6. Affiliate Dashboard (`packages/affiliate-dashboard/`) + +**Current Features:** +- Address input (no auth) +- Stats display: swaps, volume, fees +- Period filtering +- Fetches from `/v1/affiliate/stats` + +**Endpoint Required:** `/v1/affiliate/stats` (needs to be implemented in microservices) + +--- + +## Gaps Identified + +### 1. No Affiliate BPS Storage +- Widget/API affiliates get whatever BPS is hardcoded +- No way to configure per-affiliate BPS +- No database table for affiliate configuration + +### 2. No Swap Attribution +- Swaps are not tagged with affiliate address +- Cannot query "swaps through affiliate X" +- Revenue attribution impossible + +### 3. No Partner Code System +- Cannot use friendly codes like "vultisig" or "venice" +- Must use raw wallet addresses + +### 4. No Authentication +- Affiliate dashboard has no wallet auth +- Anyone can view any affiliate's stats +- Cannot update own BPS without backend + +### 5. Inconsistent BPS Across Surfaces +- Web app: 60 BPS (hardcoded) +- Widget: Uses API default (should be configurable) +- Public API: No lookup, uses caller's requested BPS + +--- + +## Proposed Solution + +See [Affiliate System Alignment Spike](../beads/web-bqz.md) for full implementation plan. + +### High-Level Architecture + +```mermaid +flowchart TB + subgraph "Affiliate Dashboard" + AD[packages/affiliate-dashboard] + AD --> |Reown wallet auth|Arbitrum + AD --> |SIWE sign|AffiliateAPI + end + + subgraph "Microservices" + AffiliateAPI[/v1/affiliate/*] + AffiliateAPI --> AffiliateTable[(affiliates table)] + AffiliateAPI --> SwapTable[(swaps table)] + + AffiliateTable --> |walletAddress|Lookup + AffiliateTable --> |partnerCode|Lookup + AffiliateTable --> |bps|Lookup + end + + subgraph "Public API / Widget" + PublicApi2[X-Affiliate-Address] + PublicApi2 --> |lookup BPS|AffiliateAPI + PublicApi2 --> |apply correct BPS|SwapperPkg2[Swapper] + end + + subgraph "Swap Execution" + SwapperPkg2 --> |tag with affiliateAddress|SwapService + SwapService --> SwapTable + end +``` + +### Database Schema (Proposed) + +```sql +-- affiliates table +CREATE TABLE affiliates ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + wallet_address VARCHAR(42) NOT NULL UNIQUE, + partner_code VARCHAR(32) UNIQUE, + bps INTEGER NOT NULL DEFAULT 60, + is_active BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMP NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP NOT NULL DEFAULT NOW() +); + +-- Add to swaps table +ALTER TABLE swaps ADD COLUMN affiliate_address VARCHAR(42); +ALTER TABLE swaps ADD COLUMN affiliate_bps INTEGER; +``` + +### API Endpoints (Proposed) + +``` +GET /v1/affiliate/:address - Get affiliate config +POST /v1/affiliate - Register (with SIWE auth) +PATCH /v1/affiliate/:address - Update BPS (with SIWE auth) +GET /v1/affiliate/:address/stats - Get swap stats +GET /v1/affiliate/:address/swaps - Get swap history +POST /v1/affiliate/claim-code - Claim partner code (with SIWE auth) +GET /v1/partner/:code - Resolve partner code to affiliate +``` + +--- + +## Related Files + +### Web App +- `src/lib/fees/constant.ts` +- `src/lib/fees/utils.ts` +- `src/state/apis/swapper/swapperApi.ts` +- `src/components/MultiHopTrade/hooks/useGetTradeRateInput.ts` + +### Packages +- `packages/public-api/src/middleware/auth.ts` +- `packages/public-api/src/types.ts` +- `packages/swap-widget/src/types/index.ts` +- `packages/affiliate-dashboard/src/` + +### Swapper Affiliate Constants +- `packages/swapper/src/swappers/ThorchainSwapper/constants.ts` +- `packages/swapper/src/swappers/MayachainSwapper/constants.ts` +- `packages/swapper/src/swappers/JupiterSwapper/utils/constants.ts` +- `packages/swapper/src/swappers/ButterSwap/utils/constants.ts` + +### Microservices +- `apps/swap-service/src/swaps/swaps.service.ts` +- `apps/swap-service/src/swaps/swaps.controller.ts` diff --git a/headers/csps/alchemy.ts b/headers/csps/alchemy.ts deleted file mode 100644 index 1c4c8397fa4..00000000000 --- a/headers/csps/alchemy.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { Csp } from '../types' - -export const csp: Csp = { - 'connect-src': ['https://*.g.alchemy.com/v2/'], -} diff --git a/headers/csps/chains/arbitrum.ts b/headers/csps/chains/arbitrum.ts index 105bab68c42..5296313f361 100644 --- a/headers/csps/chains/arbitrum.ts +++ b/headers/csps/chains/arbitrum.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,5 +11,6 @@ export const csp: Csp = { env.VITE_ARBITRUM_NODE_URL, env.VITE_UNCHAINED_ARBITRUM_HTTP_URL, env.VITE_UNCHAINED_ARBITRUM_WS_URL, + ...FALLBACK_RPC_URLS.arbitrum, ], } diff --git a/headers/csps/chains/avalanche.ts b/headers/csps/chains/avalanche.ts index f6f06326fbb..20e766f7d56 100644 --- a/headers/csps/chains/avalanche.ts +++ b/headers/csps/chains/avalanche.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,5 +11,6 @@ export const csp: Csp = { env.VITE_AVALANCHE_NODE_URL, env.VITE_UNCHAINED_AVALANCHE_HTTP_URL, env.VITE_UNCHAINED_AVALANCHE_WS_URL, + ...FALLBACK_RPC_URLS.avalanche, ], } diff --git a/headers/csps/chains/base.ts b/headers/csps/chains/base.ts index 1bc4058c273..5cb9f9645c5 100644 --- a/headers/csps/chains/base.ts +++ b/headers/csps/chains/base.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,8 +11,6 @@ export const csp: Csp = { env.VITE_BASE_NODE_URL, env.VITE_UNCHAINED_BASE_HTTP_URL, env.VITE_UNCHAINED_BASE_WS_URL, - 'https://mainnet.base.org', - 'https://base.llamarpc.com', - 'https://base.blockpi.network', + ...FALLBACK_RPC_URLS.base, ], } diff --git a/headers/csps/chains/berachain.ts b/headers/csps/chains/berachain.ts index 1f20c269e0c..bcaafd0b545 100644 --- a/headers/csps/chains/berachain.ts +++ b/headers/csps/chains/berachain.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_BERACHAIN_NODE_URL], + 'connect-src': [env.VITE_BERACHAIN_NODE_URL, ...FALLBACK_RPC_URLS.berachain], } diff --git a/headers/csps/chains/blast.ts b/headers/csps/chains/blast.ts index 0a49233bb2a..d11be28958d 100644 --- a/headers/csps/chains/blast.ts +++ b/headers/csps/chains/blast.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_BLAST_NODE_URL], + 'connect-src': [env.VITE_BLAST_NODE_URL, ...FALLBACK_RPC_URLS.blast], } diff --git a/headers/csps/chains/bnbsmartchain.ts b/headers/csps/chains/bnbsmartchain.ts index dbea77fd4e0..64ad40c2304 100644 --- a/headers/csps/chains/bnbsmartchain.ts +++ b/headers/csps/chains/bnbsmartchain.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -8,11 +9,8 @@ const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { 'connect-src': [ env.VITE_BNBSMARTCHAIN_NODE_URL, - env.VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_1, - env.VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_2, - env.VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_3, env.VITE_UNCHAINED_BNBSMARTCHAIN_HTTP_URL, env.VITE_UNCHAINED_BNBSMARTCHAIN_WS_URL, - 'https://binance.llamarpc.com', + ...FALLBACK_RPC_URLS.bsc, ], } diff --git a/headers/csps/chains/bob.ts b/headers/csps/chains/bob.ts index cb597bdfa8c..5c685c16f40 100644 --- a/headers/csps/chains/bob.ts +++ b/headers/csps/chains/bob.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_BOB_NODE_URL], + 'connect-src': [env.VITE_BOB_NODE_URL, ...FALLBACK_RPC_URLS.bob], } diff --git a/headers/csps/chains/celo.ts b/headers/csps/chains/celo.ts index bb076655e56..f00de990797 100644 --- a/headers/csps/chains/celo.ts +++ b/headers/csps/chains/celo.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_CELO_NODE_URL], + 'connect-src': [env.VITE_CELO_NODE_URL, ...FALLBACK_RPC_URLS.celo], } diff --git a/headers/csps/chains/cronos.ts b/headers/csps/chains/cronos.ts index 1327c22db74..9fbeb457ce3 100644 --- a/headers/csps/chains/cronos.ts +++ b/headers/csps/chains/cronos.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_CRONOS_NODE_URL], + 'connect-src': [env.VITE_CRONOS_NODE_URL, ...FALLBACK_RPC_URLS.cronos], } diff --git a/headers/csps/chains/ethereum.ts b/headers/csps/chains/ethereum.ts index c0142a59bc7..8e960034175 100644 --- a/headers/csps/chains/ethereum.ts +++ b/headers/csps/chains/ethereum.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,7 +11,6 @@ export const csp: Csp = { env.VITE_ETHEREUM_NODE_URL, env.VITE_UNCHAINED_ETHEREUM_HTTP_URL, env.VITE_UNCHAINED_ETHEREUM_WS_URL, - env.VITE_ALCHEMY_POLYGON_URL, - 'https://eth.llamarpc.com', + ...FALLBACK_RPC_URLS.ethereum, ], } diff --git a/headers/csps/chains/flowEvm.ts b/headers/csps/chains/flowEvm.ts index 3024024fdf7..2da99edd04a 100644 --- a/headers/csps/chains/flowEvm.ts +++ b/headers/csps/chains/flowEvm.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_FLOWEVM_NODE_URL], + 'connect-src': [env.VITE_FLOWEVM_NODE_URL, ...FALLBACK_RPC_URLS.flowEvm], } diff --git a/headers/csps/chains/gnosis.ts b/headers/csps/chains/gnosis.ts index 258f2fe06cb..f83f20fc325 100644 --- a/headers/csps/chains/gnosis.ts +++ b/headers/csps/chains/gnosis.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,5 +11,6 @@ export const csp: Csp = { env.VITE_GNOSIS_NODE_URL, env.VITE_UNCHAINED_GNOSIS_HTTP_URL, env.VITE_UNCHAINED_GNOSIS_WS_URL, + ...FALLBACK_RPC_URLS.gnosis, ], } diff --git a/headers/csps/chains/hemi.ts b/headers/csps/chains/hemi.ts index 6b132c426bc..73adbccabe5 100644 --- a/headers/csps/chains/hemi.ts +++ b/headers/csps/chains/hemi.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_HEMI_NODE_URL], + 'connect-src': [env.VITE_HEMI_NODE_URL, ...FALLBACK_RPC_URLS.hemi], } diff --git a/headers/csps/chains/hyperevm.ts b/headers/csps/chains/hyperevm.ts index 7c1932be772..74c20827dcf 100644 --- a/headers/csps/chains/hyperevm.ts +++ b/headers/csps/chains/hyperevm.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_HYPEREVM_NODE_URL], + 'connect-src': [env.VITE_HYPEREVM_NODE_URL, ...FALLBACK_RPC_URLS.hyperEvm], } diff --git a/headers/csps/chains/ink.ts b/headers/csps/chains/ink.ts index 2f8f9f70c27..182eb7f3d67 100644 --- a/headers/csps/chains/ink.ts +++ b/headers/csps/chains/ink.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_INK_NODE_URL], + 'connect-src': [env.VITE_INK_NODE_URL, ...FALLBACK_RPC_URLS.ink], } diff --git a/headers/csps/chains/katana.ts b/headers/csps/chains/katana.ts index c37e44de521..ccfcddff361 100644 --- a/headers/csps/chains/katana.ts +++ b/headers/csps/chains/katana.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_KATANA_NODE_URL], + 'connect-src': [env.VITE_KATANA_NODE_URL, ...FALLBACK_RPC_URLS.katana], } diff --git a/headers/csps/chains/linea.ts b/headers/csps/chains/linea.ts index b10293d5a32..446e8504b48 100644 --- a/headers/csps/chains/linea.ts +++ b/headers/csps/chains/linea.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_LINEA_NODE_URL], + 'connect-src': [env.VITE_LINEA_NODE_URL, ...FALLBACK_RPC_URLS.linea], } diff --git a/headers/csps/chains/mantle.ts b/headers/csps/chains/mantle.ts index bc02a6803e8..178616a62b2 100644 --- a/headers/csps/chains/mantle.ts +++ b/headers/csps/chains/mantle.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_MANTLE_NODE_URL], + 'connect-src': [env.VITE_MANTLE_NODE_URL, ...FALLBACK_RPC_URLS.mantle], } diff --git a/headers/csps/chains/megaeth.ts b/headers/csps/chains/megaeth.ts index 860ef07b37e..17f62fbb0cd 100644 --- a/headers/csps/chains/megaeth.ts +++ b/headers/csps/chains/megaeth.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_MEGAETH_NODE_URL], + 'connect-src': [env.VITE_MEGAETH_NODE_URL, ...FALLBACK_RPC_URLS.megaEth], } diff --git a/headers/csps/chains/mode.ts b/headers/csps/chains/mode.ts index 2073ca4ddd4..e9be7f9058e 100644 --- a/headers/csps/chains/mode.ts +++ b/headers/csps/chains/mode.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const envMode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(envMode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_MODE_NODE_URL, 'https://modescan.io'], + 'connect-src': [env.VITE_MODE_NODE_URL, 'https://modescan.io', ...FALLBACK_RPC_URLS.mode], } diff --git a/headers/csps/chains/monad.ts b/headers/csps/chains/monad.ts index 14a860e9151..f2694cc1257 100644 --- a/headers/csps/chains/monad.ts +++ b/headers/csps/chains/monad.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_MONAD_NODE_URL], + 'connect-src': [env.VITE_MONAD_NODE_URL, ...FALLBACK_RPC_URLS.monad], } diff --git a/headers/csps/chains/optimism.ts b/headers/csps/chains/optimism.ts index ba4fb1216e2..eb5cb36e242 100644 --- a/headers/csps/chains/optimism.ts +++ b/headers/csps/chains/optimism.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,5 +11,6 @@ export const csp: Csp = { env.VITE_OPTIMISM_NODE_URL, env.VITE_UNCHAINED_OPTIMISM_HTTP_URL, env.VITE_UNCHAINED_OPTIMISM_WS_URL, + ...FALLBACK_RPC_URLS.optimism, ], } diff --git a/headers/csps/chains/plasma.ts b/headers/csps/chains/plasma.ts index a8c552b1fd0..bdf0d9a0a08 100644 --- a/headers/csps/chains/plasma.ts +++ b/headers/csps/chains/plasma.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_PLASMA_NODE_URL], + 'connect-src': [env.VITE_PLASMA_NODE_URL, ...FALLBACK_RPC_URLS.plasma], } diff --git a/headers/csps/chains/plume.ts b/headers/csps/chains/plume.ts index 734eced7be8..dc6f6d877b8 100644 --- a/headers/csps/chains/plume.ts +++ b/headers/csps/chains/plume.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_PLUME_NODE_URL], + 'connect-src': [env.VITE_PLUME_NODE_URL, ...FALLBACK_RPC_URLS.plume], } diff --git a/headers/csps/chains/polygon.ts b/headers/csps/chains/polygon.ts index 33dc0bf141c..ec7848a29fc 100644 --- a/headers/csps/chains/polygon.ts +++ b/headers/csps/chains/polygon.ts @@ -1,5 +1,6 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' @@ -10,5 +11,6 @@ export const csp: Csp = { env.VITE_POLYGON_NODE_URL, env.VITE_UNCHAINED_POLYGON_HTTP_URL, env.VITE_UNCHAINED_POLYGON_WS_URL, + ...FALLBACK_RPC_URLS.polygon, ], } diff --git a/headers/csps/chains/scroll.ts b/headers/csps/chains/scroll.ts index 503744828cd..dab2daee3ff 100644 --- a/headers/csps/chains/scroll.ts +++ b/headers/csps/chains/scroll.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_SCROLL_NODE_URL], + 'connect-src': [env.VITE_SCROLL_NODE_URL, ...FALLBACK_RPC_URLS.scroll], } diff --git a/headers/csps/chains/soneium.ts b/headers/csps/chains/soneium.ts index 408fb9c95ee..a8b5849aeef 100644 --- a/headers/csps/chains/soneium.ts +++ b/headers/csps/chains/soneium.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_SONEIUM_NODE_URL], + 'connect-src': [env.VITE_SONEIUM_NODE_URL, ...FALLBACK_RPC_URLS.soneium], } diff --git a/headers/csps/chains/sonic.ts b/headers/csps/chains/sonic.ts index a50f373d0ef..2ac15cd0c4c 100644 --- a/headers/csps/chains/sonic.ts +++ b/headers/csps/chains/sonic.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_SONIC_NODE_URL], + 'connect-src': [env.VITE_SONIC_NODE_URL, ...FALLBACK_RPC_URLS.sonic], } diff --git a/headers/csps/chains/story.ts b/headers/csps/chains/story.ts index 7f8235b7ae5..ce97b346acd 100644 --- a/headers/csps/chains/story.ts +++ b/headers/csps/chains/story.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_STORY_NODE_URL], + 'connect-src': [env.VITE_STORY_NODE_URL, ...FALLBACK_RPC_URLS.story], } diff --git a/headers/csps/chains/unichain.ts b/headers/csps/chains/unichain.ts index 2199071b93f..6869f9b16ce 100644 --- a/headers/csps/chains/unichain.ts +++ b/headers/csps/chains/unichain.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_UNICHAIN_NODE_URL], + 'connect-src': [env.VITE_UNICHAIN_NODE_URL, ...FALLBACK_RPC_URLS.unichain], } diff --git a/headers/csps/chains/worldchain.ts b/headers/csps/chains/worldchain.ts index 91d48b5ebee..f5a6a472ed0 100644 --- a/headers/csps/chains/worldchain.ts +++ b/headers/csps/chains/worldchain.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_WORLDCHAIN_NODE_URL], + 'connect-src': [env.VITE_WORLDCHAIN_NODE_URL, ...FALLBACK_RPC_URLS.worldChain], } diff --git a/headers/csps/chains/zksyncera.ts b/headers/csps/chains/zksyncera.ts index 43f75619546..aeedbe82a65 100644 --- a/headers/csps/chains/zksyncera.ts +++ b/headers/csps/chains/zksyncera.ts @@ -1,10 +1,11 @@ import { loadEnv } from 'vite' +import { FALLBACK_RPC_URLS } from '../../../packages/contracts/src/fallbackRpcUrls' import type { Csp } from '../../types' const mode = process.env.MODE ?? process.env.NODE_ENV ?? 'development' const env = loadEnv(mode, process.cwd(), '') export const csp: Csp = { - 'connect-src': [env.VITE_ZKSYNC_ERA_NODE_URL], + 'connect-src': [env.VITE_ZKSYNC_ERA_NODE_URL, ...FALLBACK_RPC_URLS.zkSyncEra], } diff --git a/headers/csps/index.ts b/headers/csps/index.ts index 93be4936c67..a1a1aeeb97b 100644 --- a/headers/csps/index.ts +++ b/headers/csps/index.ts @@ -1,6 +1,5 @@ import { csp as across } from './across' import { csp as agenticChat } from './agenticChat' -import { csp as alchemy } from './alchemy' import { csp as trustwallet } from './assetService/trustwallet' import { csp as base } from './base' import { csp as chainflip } from './chainflip' @@ -108,7 +107,6 @@ export const csps = [ base, agenticChat, hypelab, - alchemy, moralis, chainflip, chatwoot, diff --git a/package.json b/package.json index d72fbd4a014..673b7c62a60 100644 --- a/package.json +++ b/package.json @@ -156,7 +156,6 @@ "@walletconnect/utils": "^2.20.2", "@xstate/react": "5.0.5", "ai": "^6.0.39", - "alchemy-sdk": "^3.4.1", "axios": "^1.13.5", "axios-cache-interceptor": "^1.11.1", "bech32": "^2.0.0", @@ -312,6 +311,7 @@ "msw": "^0.36.5", "multiformats": "^9.6.3", "pify": "^5.0.0", + "portless": "^0.6.0", "prettier": "^3.0.3", "readline-sync": "^1.4.10", "simple-git": "^3.16.0", diff --git a/packages/affiliate-dashboard/package.json b/packages/affiliate-dashboard/package.json index 08af28eeaab..928c11ef596 100644 --- a/packages/affiliate-dashboard/package.json +++ b/packages/affiliate-dashboard/package.json @@ -8,8 +8,13 @@ "preview": "vite preview" }, "dependencies": { + "@reown/appkit": "^1.8.17", + "@reown/appkit-adapter-wagmi": "^1.8.17", + "@tanstack/react-query": "^5.0.0", "react": "^18.2.0", - "react-dom": "^18.2.0" + "react-dom": "^18.2.0", + "viem": "^2.40.0", + "wagmi": "^2.19.5" }, "devDependencies": { "@types/react": "^18.2.0", diff --git a/packages/affiliate-dashboard/src/App.tsx b/packages/affiliate-dashboard/src/App.tsx index beb1408a479..0a7fafd4cb7 100644 --- a/packages/affiliate-dashboard/src/App.tsx +++ b/packages/affiliate-dashboard/src/App.tsx @@ -1,6 +1,11 @@ +import { useAppKitAccount } from '@reown/appkit/react' import { useCallback, useEffect, useMemo, useState } from 'react' +import { useAffiliateConfig } from './hooks/useAffiliateConfig' import { useAffiliateStats } from './hooks/useAffiliateStats' +import type { AffiliateSwap } from './hooks/useAffiliateSwaps' +import { useAffiliateSwaps } from './hooks/useAffiliateSwaps' +import { useSiweAuth } from './hooks/useSiweAuth' const formatUsd = (value: number): string => new Intl.NumberFormat('en-US', { @@ -12,6 +17,13 @@ const formatUsd = (value: number): string => const formatNumber = (value: number): string => new Intl.NumberFormat('en-US').format(value) +const shortenAddress = (addr: string): string => `${addr.slice(0, 6)}...${addr.slice(-4)}` + +const formatDate = (iso: string): string => { + const d = new Date(iso) + return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) +} + interface Period { label: string startDate?: string @@ -20,6 +32,7 @@ interface Period { const PERIOD_DAY = 5 const PREVIOUS_PERIODS_COUNT = 3 +const SWAPS_PER_PAGE = 10 const formatPeriodLabel = (start: Date, end: Date): string => { const monthShort = new Intl.DateTimeFormat('en-US', { month: 'short' }) @@ -120,149 +133,744 @@ const ShapeShiftLogo = (): React.JSX.Element => ( ) -const EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/ +const API_BASE = '/v1/affiliate' -const isValidEvmAddress = (addr: string): boolean => EVM_ADDRESS_REGEX.test(addr) +type Tab = 'overview' | 'swaps' | 'settings' export const App = (): React.JSX.Element => { - const [address, setAddress] = useState('') + const { address, isConnected } = useAppKitAccount() + const { + isAuthenticated, + isAuthenticating, + error: authError, + signIn, + signOut, + authHeaders, + } = useSiweAuth() + const [selectedPeriod, setSelectedPeriod] = useState(0) - const [validationError, setValidationError] = useState(null) - const { stats, isLoading, error, fetchStats } = useAffiliateStats() + const [activeTab, setActiveTab] = useState('overview') + const [swapPage, setSwapPage] = useState(0) + + const [registerBps, setRegisterBps] = useState('30') + const [claimCode, setClaimCode] = useState('') + const [updateBps, setUpdateBps] = useState('') + const [updateReceiveAddress, setUpdateReceiveAddress] = useState('') + const [actionLoading, setActionLoading] = useState(false) + const [actionMessage, setActionMessage] = useState<{ + type: 'success' | 'error' + text: string + } | null>(null) + + const affiliateAddress = isConnected && address ? address : '' + + const { stats, isLoading: statsLoading, error: statsError, fetchStats } = useAffiliateStats() + const { config: affiliateConfig, isLoading: configLoading, fetchConfig } = useAffiliateConfig() + const { + swaps, + total: swapsTotal, + isLoading: swapsLoading, + error: swapsError, + fetchSwaps, + } = useAffiliateSwaps() const currentPeriod = periods[selectedPeriod] const doFetch = useCallback((): void => { - const trimmed = address.trim() + const trimmed = affiliateAddress.trim() if (!trimmed) return - if (!isValidEvmAddress(trimmed)) { - setValidationError('Please enter a valid Ethereum address (0x followed by 40 hex characters)') - return - } - - setValidationError(null) void fetchStats(trimmed, { startDate: currentPeriod.startDate, endDate: currentPeriod.endDate, }) - }, [fetchStats, address, currentPeriod]) + void fetchConfig(trimmed) + void fetchSwaps(trimmed, { + startDate: currentPeriod.startDate, + endDate: currentPeriod.endDate, + limit: SWAPS_PER_PAGE, + offset: swapPage * SWAPS_PER_PAGE, + }) + }, [fetchStats, fetchConfig, fetchSwaps, affiliateAddress, currentPeriod, swapPage]) - const handleAddressChange = useCallback((e: React.ChangeEvent): void => { - setAddress(e.target.value) - setValidationError(null) + useEffect(() => { + if (isConnected && address) { + setSwapPage(0) + doFetch() + } + }, [isConnected, address, doFetch]) + + useEffect(() => { + if (affiliateAddress.trim()) doFetch() + }, [selectedPeriod, affiliateAddress, doFetch]) + + useEffect(() => { + if (affiliateAddress.trim()) { + void fetchSwaps(affiliateAddress, { + startDate: currentPeriod.startDate, + endDate: currentPeriod.endDate, + limit: SWAPS_PER_PAGE, + offset: swapPage * SWAPS_PER_PAGE, + }) + } + }, [swapPage, affiliateAddress, currentPeriod, fetchSwaps]) + + const clearActionMessage = useCallback((): void => { + setActionMessage(null) }, []) - const handleViewStats = useCallback((): void => { - doFetch() - }, [doFetch]) + const handleRegister = useCallback(async (): Promise => { + if (!affiliateAddress) return + setActionLoading(true) + clearActionMessage() + try { + const res = await fetch(API_BASE, { + method: 'POST', + headers: { 'Content-Type': 'application/json', ...authHeaders }, + body: JSON.stringify({ + walletAddress: affiliateAddress, + bps: Number.isNaN(parseInt(registerBps, 10)) ? 30 : parseInt(registerBps, 10), + }), + }) + if (!res.ok) { + const body = (await res.json()) as { message?: string } + throw new Error(body.message ?? `Failed (${String(res.status)})`) + } + setActionMessage({ type: 'success', text: 'Affiliate registered successfully' }) + void fetchConfig(affiliateAddress) + } catch (err) { + setActionMessage({ + type: 'error', + text: err instanceof Error ? err.message : 'Registration failed', + }) + } finally { + setActionLoading(false) + } + }, [affiliateAddress, registerBps, clearActionMessage, fetchConfig, authHeaders]) - const handleKeyDown = useCallback( - (e: React.KeyboardEvent): void => { - if (e.key === 'Enter') { - doFetch() + const handleClaimCode = useCallback(async (): Promise => { + if (!affiliateAddress || !claimCode.trim()) return + setActionLoading(true) + clearActionMessage() + try { + const res = await fetch(`${API_BASE}/claim-code`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', ...authHeaders }, + body: JSON.stringify({ walletAddress: affiliateAddress, partnerCode: claimCode.trim() }), + }) + if (!res.ok) { + const body = (await res.json()) as { message?: string } + throw new Error(body.message ?? `Failed (${String(res.status)})`) } - }, - [doFetch], - ) + setActionMessage({ type: 'success', text: `Partner code "${claimCode.trim()}" claimed` }) + setClaimCode('') + void fetchConfig(affiliateAddress) + } catch (err) { + setActionMessage({ type: 'error', text: err instanceof Error ? err.message : 'Claim failed' }) + } finally { + setActionLoading(false) + } + }, [affiliateAddress, claimCode, clearActionMessage, fetchConfig, authHeaders]) - useEffect(() => { - if (address.trim()) doFetch() - }, [selectedPeriod]) // eslint-disable-line react-hooks/exhaustive-deps + const handleUpdateBps = useCallback(async (): Promise => { + if (!affiliateAddress || !updateBps.trim()) return + const parsedUpdateBps = parseInt(updateBps, 10) + if (Number.isNaN(parsedUpdateBps) || parsedUpdateBps < 0 || parsedUpdateBps > 1000) { + setActionMessage({ type: 'error', text: 'BPS must be a number between 0 and 1000' }) + return + } + setActionLoading(true) + clearActionMessage() + try { + const res = await fetch(`${API_BASE}/${encodeURIComponent(affiliateAddress)}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json', ...authHeaders }, + body: JSON.stringify({ bps: parsedUpdateBps }), + }) + if (!res.ok) { + const body = (await res.json()) as { message?: string } + throw new Error(body.message ?? `Failed (${String(res.status)})`) + } + setActionMessage({ type: 'success', text: `BPS updated to ${updateBps}` }) + setUpdateBps('') + void fetchConfig(affiliateAddress) + } catch (err) { + setActionMessage({ + type: 'error', + text: err instanceof Error ? err.message : 'Update failed', + }) + } finally { + setActionLoading(false) + } + }, [affiliateAddress, updateBps, clearActionMessage, fetchConfig, authHeaders]) - const isButtonDisabled = useMemo(() => isLoading || !address.trim(), [isLoading, address]) + const handleUpdateReceiveAddress = useCallback(async (): Promise => { + if (!affiliateAddress || !updateReceiveAddress.trim()) return + if (!/^0x[a-fA-F0-9]{40}$/.test(updateReceiveAddress.trim())) { + setActionMessage({ type: 'error', text: 'Invalid EVM address' }) + return + } + setActionLoading(true) + clearActionMessage() + try { + const res = await fetch(`${API_BASE}/${encodeURIComponent(affiliateAddress)}`, { + method: 'PATCH', + headers: { 'Content-Type': 'application/json', ...authHeaders }, + body: JSON.stringify({ receiveAddress: updateReceiveAddress.trim() }), + }) + if (!res.ok) { + const body = (await res.json()) as { message?: string } + throw new Error(body.message ?? `Failed (${String(res.status)})`) + } + setActionMessage({ type: 'success', text: 'Receive address updated' }) + setUpdateReceiveAddress('') + void fetchConfig(affiliateAddress) + } catch (err) { + setActionMessage({ + type: 'error', + text: err instanceof Error ? err.message : 'Update failed', + }) + } finally { + setActionLoading(false) + } + }, [affiliateAddress, updateReceiveAddress, clearActionMessage, fetchConfig, authHeaders]) + + const isLoading = statsLoading || configLoading const statCards = useMemo(() => { if (!stats) return null return [ - { - label: 'Total Swaps', - value: formatNumber(stats.totalSwaps), - }, - { - label: 'Total Volume USD', - value: formatUsd(stats.totalVolumeUsd), - }, - { - label: 'Total Fees USD', - value: formatUsd(stats.totalFeesUsd), - }, + { label: 'Total Swaps', value: formatNumber(stats.totalSwaps) }, + { label: 'Total Volume', value: formatUsd(stats.totalVolumeUsd) }, + { label: 'Fees Earned', value: formatUsd(stats.totalFeesUsd) }, ] }, [stats]) + const totalSwapPages = Math.ceil(swapsTotal / SWAPS_PER_PAGE) + + const tabs: { key: Tab; label: string }[] = [ + { key: 'overview', label: 'Overview' }, + { key: 'swaps', label: 'Swap History' }, + { key: 'settings', label: 'Settings' }, + ] + return (
-
- +
+
+ +
+
+ +

Affiliate Dashboard

-

Track your affiliate performance and earnings

+

Manage your affiliate program and track earnings

-
-
- + {!isConnected && ( +
+

Connect your wallet to view your affiliate dashboard.

- -
- -
- {periods.map((period, i) => ( - - ))} -
- - {validationError ?
{validationError}
: null} - {error && !validationError ?
{error}
: null} - - {statCards ? ( -
- {statCards.map(card => ( -
-
{card.value}
-
{card.label}
+ )} + + {isConnected && affiliateAddress && ( + <> + {affiliateConfig && ( +
+ + BPS + + {affiliateConfig.bps} ({(affiliateConfig.bps / 100).toFixed(2)}%) + + + {affiliateConfig.partnerCode && ( + + Code + {affiliateConfig.partnerCode} + + )} + + Status + + {affiliateConfig.isActive ? 'Active' : 'Inactive'} + +
- ))} -
- ) : null} + )} - {!stats && !error && !isLoading ? ( -
-

- Enter an affiliate address above to view performance stats. -

-
- ) : null} +
+ {tabs.map(tab => ( + + ))} +
+ + {activeTab === 'overview' && ( + <> +
+ {periods.map((period, i) => ( + + ))} +
+ + {statsError ?
{statsError}
: null} + + {isLoading && !stats && ( +
+

Loading...

+
+ )} + + {statCards && ( +
+ {statCards.map(card => ( +
+
{card.value}
+
{card.label}
+
+ ))} +
+ )} + + {!stats && !statsError && !isLoading && ( +
+

No affiliate stats found for this address.

+
+ )} + + )} + + {activeTab === 'swaps' && ( + <> +
+ {periods.map((period, i) => ( + + ))} +
+ + {swapsError ?
{swapsError}
: null} + + {swapsLoading && ( +
+

Loading swaps...

+
+ )} + + {!swapsLoading && swaps.length === 0 && !swapsError && ( +
+

No swaps found for this period.

+
+ )} + + {swaps.length > 0 && ( + <> +
+ + + + + + + + + + + + + + {swaps.map((swap: AffiliateSwap) => ( + + + + + + + + + + ))} + +
DateSellBuyVolumeFeeBPSStatus
{formatDate(swap.createdAt)} + + {typeof swap.sellAsset === 'object' + ? swap.sellAsset.symbol ?? 'Unknown' + : swap.sellAsset} + + + + {typeof swap.buyAsset === 'object' + ? swap.buyAsset.symbol ?? 'Unknown' + : swap.buyAsset} + + + {formatUsd(parseFloat(swap.sellAmountUsd) || 0)} + + {formatUsd(parseFloat(swap.affiliateFeeUsd) || 0)} + + {Math.max(0, parseInt(String(swap.affiliateBps ?? '0'), 10) - 10)} + + + {swap.status} + +
+
+ + {totalSwapPages > 1 && ( +
+ + + Page {swapPage + 1} of {totalSwapPages} + + +
+ )} + + )} + + )} + + {activeTab === 'settings' && ( +
+ {actionMessage && ( +
+ {actionMessage.text} + +
+ )} + + {!isAuthenticated && ( +
+
+
+

Sign in to manage settings

+

+ Sign a message with your wallet to prove ownership. This does not cost + gas. +

+ {authError &&

{authError}

} +
+ +
+
+ )} + + {isAuthenticated && ( +
+ Authenticated + +
+ )} + + {!affiliateConfig && isAuthenticated && ( +
+

Register as Affiliate

+

+ Register your connected wallet to start earning fees on swaps. +

+
+ + {shortenAddress(affiliateAddress)} + +
+
+ setRegisterBps(e.target.value)} + placeholder='BPS (e.g. 30)' + style={{ ...styles.formInput, maxWidth: 120 }} + min={0} + max={1000} + /> + + {(parseInt(registerBps, 10) / 100 || 0).toFixed(2)}% + +
+ +
+ )} + + {affiliateConfig && ( + <> +
+

Current Configuration

+
+ Wallet + + {shortenAddress(affiliateConfig.walletAddress)} + +
+
+ Receive Address + + {shortenAddress( + affiliateConfig.receiveAddress ?? affiliateConfig.walletAddress, + )} + +
+
+ BPS + + {affiliateConfig.bps} ({(affiliateConfig.bps / 100).toFixed(2)}%) + +
+
+ Partner Code + + {affiliateConfig.partnerCode ?? 'None'} + +
+
+ Status + + {affiliateConfig.isActive ? 'Active' : 'Inactive'} + +
+
+ Created + + {formatDate(affiliateConfig.createdAt)} + +
+
+ + {isAuthenticated && !affiliateConfig.partnerCode && ( +
+

Claim Partner Code

+

+ Claim a unique partner code for your affiliate link. +

+
+ setClaimCode(e.target.value)} + placeholder='Enter partner code' + style={styles.formInput} + spellCheck={false} + /> + +
+
+ )} + + {isAuthenticated && ( +
+

Update BPS

+

+ Change your affiliate fee basis points (1 BPS = 0.01%). +

+
+ setUpdateBps(e.target.value)} + placeholder={String(affiliateConfig.bps)} + style={{ ...styles.formInput, maxWidth: 120 }} + min={0} + max={1000} + /> + {updateBps && ( + + {(parseInt(updateBps, 10) / 100 || 0).toFixed(2)}% + + )} + +
+
+ )} + + {isAuthenticated && ( +
+

Receive Address

+

+ The address where affiliate revenue will be sent. Defaults to your + connected wallet. Useful for multisigs, treasuries, or cold wallets. +

+
+ Current + + {affiliateConfig.receiveAddress + ? shortenAddress(affiliateConfig.receiveAddress) + : `${shortenAddress(affiliateConfig.walletAddress)} (wallet)`} + +
+
+ setUpdateReceiveAddress(e.target.value)} + placeholder='0x...' + style={styles.formInput} + spellCheck={false} + /> + +
+
+ )} + + )} +
+ )} + + )}
) @@ -286,18 +894,20 @@ const styles: Record = { }, content: { position: 'relative', - maxWidth: 720, + maxWidth: 960, margin: '0 auto', - padding: '80px 24px 60px', + padding: '48px 24px 60px', }, header: { - textAlign: 'center', - marginBottom: 48, + marginBottom: 32, }, - logo: { + headerRow: { display: 'flex', - justifyContent: 'center', - marginBottom: 16, + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: 24, + }, + logo: { color: '#f0f1f4', }, title: { @@ -313,53 +923,54 @@ const styles: Record = { margin: 0, fontWeight: 400, }, - inputGroup: { + configBar: { display: 'flex', - gap: 12, - marginBottom: 32, - }, - inputWrapper: { - flex: 1, - }, - input: { - width: '100%', - padding: '14px 18px', - fontSize: 15, - fontFamily: '"DM Mono", "SF Mono", "Fira Code", monospace', + gap: 24, + padding: '14px 20px', background: '#12141a', border: '1px solid #1e2028', borderRadius: 12, - color: '#e2e4e9', - outline: 'none', - transition: 'border-color 0.2s ease', - boxSizing: 'border-box', + marginBottom: 24, + flexWrap: 'wrap', }, - button: { - padding: '14px 28px', - fontSize: 15, - fontWeight: 600, - fontFamily: '"DM Sans", "Söhne", -apple-system, BlinkMacSystemFont, sans-serif', - background: '#386ff9', - color: '#fff', - border: 'none', - borderRadius: 12, - cursor: 'pointer', - transition: 'all 0.2s ease', - whiteSpace: 'nowrap', - flexShrink: 0, + configBarItem: { + display: 'flex', + alignItems: 'center', + gap: 8, }, - buttonDisabled: { - opacity: 0.4, - cursor: 'not-allowed', + configBarLabel: { + fontSize: 12, + fontWeight: 500, + color: '#7a7e8a', + textTransform: 'uppercase' as const, + letterSpacing: '0.06em', }, - error: { - background: 'rgba(239, 68, 68, 0.08)', - border: '1px solid rgba(239, 68, 68, 0.2)', - borderRadius: 12, - padding: '14px 18px', - color: '#f87171', + configBarValue: { fontSize: 14, + fontWeight: 600, + color: '#f0f1f4', + }, + tabRow: { + display: 'flex', + gap: 4, marginBottom: 24, + borderBottom: '1px solid #1e2028', + paddingBottom: 0, + }, + tabButton: { + padding: '12px 20px', + fontSize: 14, + fontWeight: 500, + background: 'transparent', + border: 'none', + borderBottom: '2px solid transparent', + color: '#7a7e8a', + cursor: 'pointer', + marginBottom: -1, + }, + tabButtonActive: { + color: '#f0f1f4', + borderBottomColor: '#386ff9', }, periodRow: { display: 'flex', @@ -368,26 +979,34 @@ const styles: Record = { marginBottom: 24, }, periodButton: { - padding: '10px 20px', - fontSize: 14, + padding: '8px 16px', + fontSize: 13, fontWeight: 500, - fontFamily: '"DM Sans", "Söhne", -apple-system, BlinkMacSystemFont, sans-serif', background: '#12141a', border: '1px solid #1e2028', - borderRadius: 10, + borderRadius: 8, color: '#7a7e8a', cursor: 'pointer', - transition: 'all 0.2s ease', }, periodButtonActive: { background: 'rgba(56, 111, 249, 0.12)', border: '1px solid #386ff9', color: '#386ff9', }, + error: { + background: 'rgba(239, 68, 68, 0.08)', + border: '1px solid rgba(239, 68, 68, 0.2)', + borderRadius: 12, + padding: '14px 18px', + color: '#f87171', + fontSize: 14, + marginBottom: 24, + }, statsGrid: { display: 'grid', - gridTemplateColumns: 'repeat(auto-fit, minmax(200px, 1fr))', + gridTemplateColumns: 'repeat(3, 1fr)', gap: 16, + marginBottom: 24, }, statCard: { background: '#12141a', @@ -395,7 +1014,6 @@ const styles: Record = { borderRadius: 16, padding: '28px 24px', textAlign: 'center', - transition: 'border-color 0.2s ease, transform 0.2s ease', }, cardValue: { fontSize: 26, @@ -403,10 +1021,10 @@ const styles: Record = { color: '#f0f1f4', marginBottom: 6, letterSpacing: '-0.02em', - fontFamily: '"DM Mono", "SF Mono", "Fira Code", monospace', + fontFamily: '"DM Mono", monospace', }, cardLabel: { - fontSize: 13, + fontSize: 12, color: '#7a7e8a', fontWeight: 500, textTransform: 'uppercase' as const, @@ -416,15 +1034,237 @@ const styles: Record = { textAlign: 'center', padding: '60px 20px', }, - emptyIcon: { - fontSize: 36, - color: '#2a2d38', - marginBottom: 16, - }, emptyText: { fontSize: 15, color: '#4a4e5a', margin: 0, lineHeight: 1.6, }, + tableWrapper: { + overflowX: 'auto', + borderRadius: 12, + border: '1px solid #1e2028', + marginBottom: 16, + }, + table: { + width: '100%', + borderCollapse: 'collapse', + fontSize: 13, + }, + th: { + padding: '12px 16px', + textAlign: 'left', + fontWeight: 600, + fontSize: 11, + color: '#7a7e8a', + textTransform: 'uppercase' as const, + letterSpacing: '0.06em', + background: '#12141a', + borderBottom: '1px solid #1e2028', + whiteSpace: 'nowrap', + }, + tr: { + borderBottom: '1px solid #1a1c24', + }, + td: { + padding: '12px 16px', + color: '#e2e4e9', + whiteSpace: 'nowrap', + }, + assetPill: { + display: 'inline-block', + padding: '2px 8px', + borderRadius: 6, + background: 'rgba(56, 111, 249, 0.08)', + color: '#8ab4f8', + fontSize: 12, + fontWeight: 500, + maxWidth: 160, + overflow: 'hidden', + textOverflow: 'ellipsis', + }, + statusBadge: { + display: 'inline-block', + padding: '2px 10px', + borderRadius: 6, + fontSize: 12, + fontWeight: 500, + textTransform: 'capitalize' as const, + }, + pagination: { + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + gap: 16, + marginBottom: 24, + }, + pageButton: { + padding: '8px 16px', + fontSize: 13, + fontWeight: 500, + background: '#12141a', + border: '1px solid #1e2028', + borderRadius: 8, + color: '#e2e4e9', + cursor: 'pointer', + }, + pageButtonDisabled: { + opacity: 0.3, + cursor: 'not-allowed', + }, + pageInfo: { + fontSize: 13, + color: '#7a7e8a', + }, + settingsGrid: { + display: 'flex', + flexDirection: 'column', + gap: 20, + }, + settingsCard: { + background: '#12141a', + border: '1px solid #1e2028', + borderRadius: 12, + padding: '24px', + }, + settingsCardTitle: { + fontSize: 16, + fontWeight: 600, + color: '#f0f1f4', + margin: '0 0 8px', + }, + settingsCardDesc: { + fontSize: 14, + color: '#7a7e8a', + margin: '0 0 16px', + lineHeight: 1.5, + }, + formRow: { + display: 'flex', + gap: 12, + alignItems: 'center', + marginBottom: 12, + flexWrap: 'wrap', + }, + formInput: { + flex: 1, + minWidth: 0, + padding: '10px 14px', + fontSize: 14, + fontFamily: '"DM Mono", "SF Mono", monospace', + background: '#0a0b0d', + border: '1px solid #2a2d38', + borderRadius: 8, + color: '#e2e4e9', + outline: 'none', + boxSizing: 'border-box', + }, + formHint: { + fontSize: 13, + color: '#7a7e8a', + fontFamily: '"DM Mono", monospace', + minWidth: 50, + }, + actionButton: { + padding: '10px 20px', + fontSize: 14, + fontWeight: 600, + background: '#386ff9', + color: '#fff', + border: 'none', + borderRadius: 8, + cursor: 'pointer', + whiteSpace: 'nowrap', + flexShrink: 0, + }, + actionButtonDisabled: { + opacity: 0.4, + cursor: 'not-allowed', + }, + actionMessage: { + padding: '12px 18px', + borderRadius: 10, + border: '1px solid', + fontSize: 14, + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + }, + dismissButton: { + background: 'transparent', + border: 'none', + color: 'inherit', + fontSize: 18, + cursor: 'pointer', + padding: '0 4px', + lineHeight: 1, + }, + authBanner: { + background: 'rgba(56, 111, 249, 0.06)', + border: '1px solid rgba(56, 111, 249, 0.2)', + borderRadius: 12, + padding: '20px 24px', + }, + authBannerContent: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + gap: 20, + flexWrap: 'wrap' as const, + }, + authBannerTitle: { + fontSize: 15, + fontWeight: 600, + color: '#f0f1f4', + margin: '0 0 4px', + }, + authBannerDesc: { + fontSize: 13, + color: '#7a7e8a', + margin: 0, + lineHeight: 1.5, + }, + authBannerError: { + fontSize: 13, + color: '#f87171', + margin: '6px 0 0', + }, + authStatusBar: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + padding: '10px 16px', + background: 'rgba(74, 222, 128, 0.06)', + border: '1px solid rgba(74, 222, 128, 0.15)', + borderRadius: 8, + }, + authStatusText: { + fontSize: 13, + fontWeight: 500, + color: '#4ade80', + }, + authSignOutButton: { + fontSize: 13, + fontWeight: 500, + background: 'transparent', + border: 'none', + color: '#7a7e8a', + cursor: 'pointer', + padding: '4px 8px', + }, + configDetail: { + display: 'flex', + justifyContent: 'space-between', + padding: '8px 0', + borderBottom: '1px solid #1a1c24', + }, + configDetailLabel: { + fontSize: 14, + color: '#7a7e8a', + }, + configDetailValue: { + fontSize: 14, + fontWeight: 500, + color: '#f0f1f4', + }, } diff --git a/packages/affiliate-dashboard/src/config/wagmi.ts b/packages/affiliate-dashboard/src/config/wagmi.ts new file mode 100644 index 00000000000..7c77f8e861a --- /dev/null +++ b/packages/affiliate-dashboard/src/config/wagmi.ts @@ -0,0 +1,26 @@ +import { arbitrum } from '@reown/appkit/networks' +import { createAppKit } from '@reown/appkit/react' +import { WagmiAdapter } from '@reown/appkit-adapter-wagmi' + +const projectId = import.meta.env.VITE_WALLETCONNECT_PROJECT_ID || 'demo' + +const metadata = { + name: 'ShapeShift Affiliate Dashboard', + description: 'Manage your ShapeShift affiliate program', + url: 'https://app.shapeshift.com', + icons: [], +} + +export const wagmiAdapter = new WagmiAdapter({ + networks: [arbitrum], + projectId, +}) + +createAppKit({ + adapters: [wagmiAdapter], + networks: [arbitrum], + defaultNetwork: arbitrum, + projectId, + metadata, + themeMode: 'dark', +}) diff --git a/packages/affiliate-dashboard/src/hooks/useAffiliateConfig.ts b/packages/affiliate-dashboard/src/hooks/useAffiliateConfig.ts new file mode 100644 index 00000000000..51ec5379d48 --- /dev/null +++ b/packages/affiliate-dashboard/src/hooks/useAffiliateConfig.ts @@ -0,0 +1,71 @@ +import { useCallback, useRef, useState } from 'react' + +const API_BASE_URL = '/v1/affiliate' + +export interface AffiliateConfig { + id: string + walletAddress: string + receiveAddress: string | null + partnerCode: string | null + bps: number + isActive: boolean + createdAt: string + updatedAt: string +} + +interface AffiliateConfigState { + config: AffiliateConfig | null + isLoading: boolean + error: string | null +} + +interface UseAffiliateConfigReturn extends AffiliateConfigState { + fetchConfig: (address: string) => Promise +} + +export const useAffiliateConfig = (): UseAffiliateConfigReturn => { + const [config, setConfig] = useState(null) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) + const requestIdRef = useRef(0) + + const fetchConfig = useCallback(async (address: string): Promise => { + if (!address.trim()) return + + const currentRequestId = ++requestIdRef.current + + setIsLoading(true) + setError(null) + + try { + const response = await fetch(`${API_BASE_URL}/${encodeURIComponent(address)}`) + + // Stale response guard — discard if a newer request was fired + if (currentRequestId !== requestIdRef.current) return + + if (response.status === 404) { + // Not registered - that's ok + setConfig(null) + return + } + + if (!response.ok) { + throw new Error(`Request failed (${String(response.status)})`) + } + + const data = (await response.json()) as AffiliateConfig + setConfig(data) + } catch (err) { + if (currentRequestId !== requestIdRef.current) return + const message = err instanceof Error ? err.message : 'Failed to fetch affiliate config.' + setError(message) + setConfig(null) + } finally { + if (currentRequestId === requestIdRef.current) { + setIsLoading(false) + } + } + }, []) + + return { config, isLoading, error, fetchConfig } +} diff --git a/packages/affiliate-dashboard/src/hooks/useAffiliateSwaps.ts b/packages/affiliate-dashboard/src/hooks/useAffiliateSwaps.ts new file mode 100644 index 00000000000..8de0ff8aaa4 --- /dev/null +++ b/packages/affiliate-dashboard/src/hooks/useAffiliateSwaps.ts @@ -0,0 +1,107 @@ +import { useCallback, useRef, useState } from 'react' + +const API_BASE_URL = '/v1/affiliate/swaps' + +export interface AffiliateSwap { + id: string + sellAsset: string | { symbol?: string; name?: string } + buyAsset: string | { symbol?: string; name?: string } + sellAmount: string + buyAmount: string + sellAmountUsd: string + buyAmountUsd: string + affiliateBps: string + affiliateFeeUsd: string + status: string + createdAt: string +} + +interface ApiResponse { + swaps: AffiliateSwap[] + total: number + limit: number + offset: number +} + +interface AffiliateSwapsState { + swaps: AffiliateSwap[] + total: number + isLoading: boolean + error: string | null +} + +interface FetchOptions { + startDate?: string + endDate?: string + limit?: number + offset?: number +} + +interface UseAffiliateSwapsReturn extends AffiliateSwapsState { + fetchSwaps: (address: string, options?: FetchOptions) => Promise +} + +export const useAffiliateSwaps = (): UseAffiliateSwapsReturn => { + const [swaps, setSwaps] = useState([]) + const [total, setTotal] = useState(0) + const [isLoading, setIsLoading] = useState(false) + const [error, setError] = useState(null) + const requestIdRef = useRef(0) + + const fetchSwaps = useCallback(async (address: string, options?: FetchOptions): Promise => { + const requestId = ++requestIdRef.current + if (!address.trim()) { + setError('Please enter a valid affiliate address.') + return + } + + setIsLoading(true) + setError(null) + + try { + const params = new URLSearchParams({ address }) + if (options?.startDate) params.append('startDate', options.startDate) + if (options?.endDate) params.append('endDate', options.endDate) + if (options?.limit) params.append('limit', String(options.limit)) + if (options?.offset) params.append('offset', String(options.offset)) + + const response = await fetch(`${API_BASE_URL}?${params.toString()}`) + + if (!response.ok) { + let errorMessage = `Request failed (${String(response.status)})` + try { + const errorBody = (await response.json()) as { + error?: string + details?: { message: string }[] + } + if (errorBody.error) { + errorMessage = errorBody.error + } + if (errorBody.details?.[0]?.message) { + errorMessage = errorBody.details[0].message + } + } catch { + // Response wasn't JSON, use generic message + } + throw new Error(errorMessage) + } + + const data = (await response.json()) as ApiResponse + if (requestId !== requestIdRef.current) return + setSwaps(data.swaps) + setTotal(data.total) + } catch (err) { + if (requestId !== requestIdRef.current) return + const message = err instanceof Error ? err.message : 'Failed to fetch affiliate swaps.' + setError(message) + setSwaps([]) + setTotal(0) + } finally { + if (requestId === requestIdRef.current) { + setIsLoading(false) + } + } + }, []) + + return { swaps, total, isLoading, error, fetchSwaps } +} diff --git a/packages/affiliate-dashboard/src/hooks/useSiweAuth.ts b/packages/affiliate-dashboard/src/hooks/useSiweAuth.ts new file mode 100644 index 00000000000..2269846727f --- /dev/null +++ b/packages/affiliate-dashboard/src/hooks/useSiweAuth.ts @@ -0,0 +1,123 @@ +import { useAppKitAccount } from '@reown/appkit/react' +import { useCallback, useEffect, useState } from 'react' +import { useSignMessage } from 'wagmi' + +const API_BASE = '/v1/auth/siwe' + +interface SiweAuthState { + token: string | null + authenticatedAddress: string | null + isAuthenticating: boolean + error: string | null +} + +interface UseSiweAuthReturn extends SiweAuthState { + signIn: () => Promise + signOut: () => void + isAuthenticated: boolean + authHeaders: Record +} + +export const useSiweAuth = (): UseSiweAuthReturn => { + const { address, isConnected } = useAppKitAccount() + const { signMessageAsync } = useSignMessage() + + const [token, setToken] = useState(null) + const [authenticatedAddress, setAuthenticatedAddress] = useState(null) + const [isAuthenticating, setIsAuthenticating] = useState(false) + const [error, setError] = useState(null) + + useEffect(() => { + if (!isConnected || !address) { + setToken(null) + setAuthenticatedAddress(null) + return + } + + if (authenticatedAddress && authenticatedAddress !== address.toLowerCase()) { + setToken(null) + setAuthenticatedAddress(null) + } + }, [isConnected, address, authenticatedAddress]) + + const signIn = useCallback(async (): Promise => { + if (!address) return + + setIsAuthenticating(true) + setError(null) + + try { + const nonceRes = await fetch(`${API_BASE}/nonce`, { method: 'POST' }) + if (!nonceRes.ok) throw new Error('Failed to get nonce') + const { nonce } = (await nonceRes.json()) as { nonce: string } + + const domain = window.location.host + const uri = window.location.origin + const issuedAt = new Date().toISOString() + + const message = [ + `${domain} wants you to sign in with your Ethereum account:`, + address, + '', + 'Sign in to ShapeShift Affiliate Dashboard', + '', + `URI: ${uri}`, + 'Version: 1', + 'Chain ID: 42161', + `Nonce: ${nonce}`, + `Issued At: ${issuedAt}`, + ].join('\n') + + const signature = await signMessageAsync({ message }) + + const verifyRes = await fetch(`${API_BASE}/verify`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ message, signature }), + }) + + if (!verifyRes.ok) { + const body = (await verifyRes.json()) as { message?: string } + throw new Error(body.message ?? 'Verification failed') + } + + const { token: jwt, address: verifiedAddress } = (await verifyRes.json()) as { + token: string + address: string + } + + setToken(jwt) + setAuthenticatedAddress(verifiedAddress.toLowerCase()) + } catch (err) { + const msg = err instanceof Error ? err.message : 'Authentication failed' + setError(msg) + } finally { + setIsAuthenticating(false) + } + }, [address, signMessageAsync]) + + const signOut = useCallback((): void => { + setToken(null) + setAuthenticatedAddress(null) + setError(null) + }, []) + + const isAuthenticated = + token !== null && + authenticatedAddress !== null && + isConnected && + address?.toLowerCase() === authenticatedAddress + + const authHeaders: Record = token ? { Authorization: `Bearer ${token}` } : {} + + return { + token, + authenticatedAddress, + isAuthenticating, + error, + signIn, + signOut, + isAuthenticated, + authHeaders, + } +} diff --git a/packages/affiliate-dashboard/src/main.tsx b/packages/affiliate-dashboard/src/main.tsx index 494346ea3dc..04b98e08658 100644 --- a/packages/affiliate-dashboard/src/main.tsx +++ b/packages/affiliate-dashboard/src/main.tsx @@ -1,11 +1,29 @@ +import './config/wagmi' + +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import React from 'react' import ReactDOM from 'react-dom/client' +import { arbitrum } from 'viem/chains' +import { createConfig, http, WagmiProvider } from 'wagmi' import { App } from './App' +const queryClient = new QueryClient() + +const wagmiConfig = createConfig({ + chains: [arbitrum], + transports: { + [arbitrum.id]: http(), + }, +}) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion ReactDOM.createRoot(document.getElementById('root')!).render( - + + + + + , ) diff --git a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts index a3aacf81952..d9293992e5c 100644 --- a/packages/chain-adapters/src/evm/EvmBaseAdapter.ts +++ b/packages/chain-adapters/src/evm/EvmBaseAdapter.ts @@ -1,5 +1,6 @@ import type { AssetId, ChainId } from '@shapeshiftoss/caip' import { fromChainId, toAssetId } from '@shapeshiftoss/caip' +import { viemClientByChainId } from '@shapeshiftoss/contracts' import type { ETHSignMessage, ETHSignTx, @@ -48,7 +49,8 @@ import { KnownChainIds } from '@shapeshiftoss/types' import type * as unchained from '@shapeshiftoss/unchained-client' import BigNumber from 'bignumber.js' import PQueue from 'p-queue' -import { isAddress, toHex } from 'viem' +import type { Hex, PublicClient } from 'viem' +import { getAddress, isAddress, isHex, parseUnits, toHex } from 'viem' import type { ChainAdapter as IChainAdapter } from '../api' import { @@ -90,6 +92,7 @@ import type { BuildCustomApiTxInput, BuildCustomTxInput, EstimateGasRequest, + GasFeeData, GasFeeDataEstimate, NetworkFees, } from './types' @@ -592,6 +595,32 @@ export abstract class EvmBaseAdapter implements IChainAdap } } + private async getAccountFallback(pubkey: string, viemClient: PublicClient): Promise> { + try { + const [balance, nonce] = await Promise.all([ + viemClient.getBalance({ address: pubkey as `0x${string}` }), + viemClient.getTransactionCount({ address: pubkey as `0x${string}` }), + ]) + + return { + balance: balance.toString(), + chainId: this.chainId, + assetId: this.assetId, + chain: this.getType(), + chainSpecific: { + nonce, + tokens: [], + }, + pubkey, + } as Account + } catch (err) { + return ErrorHandler(err, { + translation: 'chainAdapters.errors.getAccount', + options: { pubkey }, + }) + } + } + async getAccount(pubkey: string): Promise> { try { const data = await this.providers.http.getAccount({ pubkey }) @@ -620,6 +649,11 @@ export abstract class EvmBaseAdapter implements IChainAdap pubkey, } as Account } catch (err) { + const viemClient = viemClientByChainId[this.chainId] + if (viemClient) { + console.warn(`Unchained getAccount failed for ${this.chainId}, falling back to direct RPC`) + return this.getAccountFallback(pubkey, viemClient) + } return ErrorHandler(err, { translation: 'chainAdapters.errors.getAccount', options: { pubkey }, @@ -712,9 +746,18 @@ export abstract class EvmBaseAdapter implements IChainAdap receiverAddress !== CONTRACT_INTERACTION && assertAddressNotSanctioned(receiverAddress), ]) - const txHash = await this.providers.http.sendTx({ sendTxBody: { hex } }) - - return txHash + try { + return await this.providers.http.sendTx({ sendTxBody: { hex } }) + } catch (unchainedErr) { + const viemClient = viemClientByChainId[this.chainId] + if (viemClient) { + console.warn( + `Unchained broadcastTransaction failed for ${this.chainId}, falling back to direct RPC`, + ) + return viemClient.sendRawTransaction({ serializedTransaction: hex as Hex }) + } + throw unchainedErr + } } catch (err) { return handleBroadcastTransactionError(err) } @@ -931,11 +974,46 @@ export abstract class EvmBaseAdapter implements IChainAdap } } + async getGasFeeDataFallback(viemClient: PublicClient): Promise { + try { + const feeData = await viemClient + .estimateFeesPerGas({ type: 'eip1559', chain: null }) + .catch(() => viemClient.estimateFeesPerGas({ type: 'legacy', chain: null })) + + const fees: GasFeeData = { + gasPrice: (feeData.gasPrice ?? feeData.maxFeePerGas).toString(), + ...(feeData.maxFeePerGas && feeData.maxPriorityFeePerGas + ? { + maxFeePerGas: feeData.maxFeePerGas.toString(), + maxPriorityFeePerGas: feeData.maxPriorityFeePerGas.toString(), + } + : {}), + } + + return { + fast: fees, + average: fees, + slow: fees, + } + } catch (err) { + return ErrorHandler(err, { + translation: 'chainAdapters.errors.getGasFeeData', + }) + } + } + async getGasFeeData(): Promise { try { const { fast, average, slow } = await this.providers.http.getGasFees() return { fast, average, slow } } catch (err) { + const viemClient = viemClientByChainId[this.chainId] + if (viemClient) { + console.warn( + `Unchained getGasFeeData failed for ${this.chainId}, falling back to direct RPC`, + ) + return this.getGasFeeDataFallback(viemClient) + } return ErrorHandler(err, { translation: 'chainAdapters.errors.getGasFeeData', }) @@ -944,9 +1022,30 @@ export abstract class EvmBaseAdapter implements IChainAdap async getFeeData(input: GetFeeDataInput): Promise> { try { - const { gasLimit } = await this.providers.http.estimateGas({ - estimateGasBody: this.buildEstimateGasBody(input), - }) + const gasLimit = await (async () => { + const estimateGasBody = this.buildEstimateGasBody(input) + + try { + const { gasLimit } = await this.providers.http.estimateGas({ estimateGasBody }) + return gasLimit + } catch (err) { + const viemClient = viemClientByChainId[this.chainId] + if (!viemClient) throw err + + console.warn( + `Unchained estimateGas failed for ${this.chainId}, falling back to direct RPC`, + ) + + const gasLimit = await viemClient.estimateGas({ + account: getAddress(estimateGasBody.from), + to: getAddress(estimateGasBody.to), + value: parseUnits(estimateGasBody.value, 0), + data: isHex(estimateGasBody.data) ? estimateGasBody.data : toHex(estimateGasBody.data), + }) + + return gasLimit.toString() + } + })() const { fast, average, slow } = await this.getGasFeeData() diff --git a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.test.ts b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.test.ts index 5e673b0b985..145ee3695ca 100644 --- a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.test.ts +++ b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.test.ts @@ -1,35 +1,34 @@ import { TxStatus } from '@shapeshiftoss/unchained-client' -import type { JsonRpcProvider } from 'ethers' +import { TransactionReceiptNotFoundError } from 'viem' import { afterEach, describe, expect, it, vi } from 'vitest' import * as monad from './monad/MonadChainAdapter' -vi.mock('ethers', () => { - class JsonRpcProvider { - getTransactionReceipt = vi.fn() - getBalance = vi.fn() - getTransactionCount = vi.fn() - estimateGas = vi.fn() - getFeeData = vi.fn() - broadcastTransaction = vi.fn() - send = vi.fn() - } - - class Contract { - aggregate3 = vi.fn() - } - - class Interface { - encodeFunctionData = vi.fn() - decodeFunctionResult = vi.fn() - } - - return { - Contract, - Interface, - JsonRpcProvider, - } -}) +const mockViemClient = { + getTransactionReceipt: vi.fn(), + getBalance: vi.fn(), + getTransactionCount: vi.fn(), + estimateGas: vi.fn(), + getGasPrice: vi.fn(), + estimateFeesPerGas: vi.fn(), + sendRawTransaction: vi.fn(), + request: vi.fn(), + multicall: vi.fn(), + readContract: vi.fn(), + getTransaction: vi.fn(), + getBlock: vi.fn(), + getBlockNumber: vi.fn(), +} + +vi.mock('@shapeshiftoss/contracts', () => ({ + MULTICALL3_CONTRACT: '0xcA11bde05977b3631167028862bE2a173976CA11', + viemClientByChainId: new Proxy( + {}, + { + get: () => mockViemClient, + }, + ), +})) const makeAdapter = () => new monad.ChainAdapter({ @@ -37,61 +36,41 @@ const makeAdapter = () => getKnownTokens: () => [], }) -const getProvider = (adapter: monad.ChainAdapter) => - (adapter as unknown as { provider: JsonRpcProvider }).provider - describe('SecondClassEvmAdapter', () => { afterEach(() => { vi.restoreAllMocks() }) - it('returns confirmed when receipt status is 1', async () => { + it('returns confirmed when receipt status is success', async () => { const adapter = makeAdapter() - const provider = getProvider(adapter) - vi.spyOn(provider, 'getTransactionReceipt').mockResolvedValue({ - status: 1, - } as unknown as Awaited>) + vi.spyOn(mockViemClient, 'getTransactionReceipt').mockResolvedValue({ status: 'success' }) await expect(adapter.getTransactionStatus('0xabc')).resolves.toBe(TxStatus.Confirmed) }) - it('returns failed when receipt status is 0', async () => { + it('returns failed when receipt status is reverted', async () => { const adapter = makeAdapter() - const provider = getProvider(adapter) - vi.spyOn(provider, 'getTransactionReceipt').mockResolvedValue({ - status: 0, - } as unknown as Awaited>) + vi.spyOn(mockViemClient, 'getTransactionReceipt').mockResolvedValue({ status: 'reverted' }) await expect(adapter.getTransactionStatus('0xdef')).resolves.toBe(TxStatus.Failed) }) - it('returns pending when receipt is null', async () => { + it('returns pending when receipt is not found', async () => { const adapter = makeAdapter() - const provider = getProvider(adapter) - vi.spyOn(provider, 'getTransactionReceipt').mockResolvedValue(null) + vi.spyOn(mockViemClient, 'getTransactionReceipt').mockRejectedValue( + new TransactionReceiptNotFoundError({ hash: '0x123' }), + ) await expect(adapter.getTransactionStatus('0x123')).resolves.toBe(TxStatus.Pending) }) - it('returns unknown when receipt status is null', async () => { - const adapter = makeAdapter() - const provider = getProvider(adapter) - - vi.spyOn(provider, 'getTransactionReceipt').mockResolvedValue({ - status: null, - } as unknown as Awaited>) - - await expect(adapter.getTransactionStatus('0x456')).resolves.toBe(TxStatus.Unknown) - }) - - it('returns unknown when provider throws', async () => { + it('returns unknown when provider throws an unexpected error', async () => { const adapter = makeAdapter() - const provider = getProvider(adapter) - vi.spyOn(provider, 'getTransactionReceipt').mockRejectedValue(new Error('boom')) + vi.spyOn(mockViemClient, 'getTransactionReceipt').mockRejectedValue(new Error('boom')) await expect(adapter.getTransactionStatus('0x789')).resolves.toBe(TxStatus.Unknown) }) diff --git a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts index 48a5396c572..8e77bf917f5 100644 --- a/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts +++ b/packages/chain-adapters/src/evm/SecondClassEvmAdapter.ts @@ -22,18 +22,20 @@ import { zkSyncEraChainId, } from '@shapeshiftoss/caip' import type { evm } from '@shapeshiftoss/common-api' -import { MULTICALL3_CONTRACT, viemClientByChainId } from '@shapeshiftoss/contracts' +import { viemClientByChainId } from '@shapeshiftoss/contracts' import type { EvmChainId, RootBip44Params } from '@shapeshiftoss/types' import { TransferType, TxStatus } from '@shapeshiftoss/unchained-client' -import { Contract, Interface, JsonRpcProvider } from 'ethers' import PQueue from 'p-queue' -import type { Hex } from 'viem' +import type { Hex, PublicClient } from 'viem' import { erc20Abi, getAddress, isAddressEqual, - multicall3Abi, + isHex, parseEventLogs, + parseUnits, + toHex, + TransactionReceiptNotFoundError, zeroAddress, } from 'viem' @@ -55,7 +57,6 @@ import { assertAddressNotSanctioned } from '../utils/validateAddress' import { EvmBaseAdapter } from './EvmBaseAdapter' import type { GasFeeDataEstimate } from './types' -const ERC20_ABI = ['function balanceOf(address) view returns (uint256)'] const WRAPPED_NATIVE_CONTRACT_BY_CHAIN_ID: Partial> = { [berachainChainId]: '0x6969696969696969696969696969696969696969', [mantleChainId]: '0x78c1b0C915c4FAA5FffA6CAbf0219DA63d7f4cb8', @@ -99,9 +100,7 @@ export const isSecondClassEvmAdapter = ( ): adapter is SecondClassEvmAdapter => adapter instanceof SecondClassEvmAdapter export abstract class SecondClassEvmAdapter extends EvmBaseAdapter { - protected provider: JsonRpcProvider - protected multicall: Contract - protected erc20Interface: Interface + protected viemClient: PublicClient protected getKnownTokens: () => TokenInfo[] private requestQueue: PQueue @@ -122,12 +121,10 @@ export abstract class SecondClassEvmAdapter extends EvmBas rpcUrl: args.rpcUrl, }) - this.provider = new JsonRpcProvider(args.rpcUrl, undefined, { - staticNetwork: true, - }) + const viemClient = viemClientByChainId[args.chainId] + if (!viemClient) throw new Error(`No viem client found for chainId: ${args.chainId}`) + this.viemClient = viemClient - this.multicall = new Contract(MULTICALL3_CONTRACT, multicall3Abi, this.provider) - this.erc20Interface = new Interface(ERC20_ABI) this.getKnownTokens = args.getKnownTokens this.requestQueue = new PQueue({ intervalCap: 1, @@ -138,19 +135,20 @@ export abstract class SecondClassEvmAdapter extends EvmBas async getTransactionStatus(txHash: string): Promise { try { - const receipt = await this.requestQueue.add(() => this.provider.getTransactionReceipt(txHash)) - - if (!receipt) return TxStatus.Pending + const receipt = await this.requestQueue.add(() => + this.viemClient.getTransactionReceipt({ hash: txHash as Hex }), + ) switch (receipt.status) { - case 1: + case 'success': return TxStatus.Confirmed - case 0: + case 'reverted': return TxStatus.Failed default: return TxStatus.Unknown } } catch (error) { + if (error instanceof TransactionReceiptNotFoundError) return TxStatus.Pending console.error(`[${this.getName()}] Error getting transaction status:`, error) return TxStatus.Unknown } @@ -159,8 +157,10 @@ export abstract class SecondClassEvmAdapter extends EvmBas async getAccount(pubkey: string): Promise> { try { const [balance, nonce] = await Promise.all([ - this.requestQueue.add(() => this.provider.getBalance(pubkey)), - this.requestQueue.add(() => this.provider.getTransactionCount(pubkey)), + this.requestQueue.add(() => this.viemClient.getBalance({ address: getAddress(pubkey) })), + this.requestQueue.add(() => + this.viemClient.getTransactionCount({ address: getAddress(pubkey) }), + ), ]) let tokens: { @@ -238,34 +238,34 @@ export abstract class SecondClassEvmAdapter extends EvmBas precision: number }[] > { - const calls = tokens.map(token => ({ - target: token.contractAddress, - allowFailure: true, - callData: this.erc20Interface.encodeFunctionData('balanceOf', [pubkey]), - })) + const multicallAddress = this.viemClient.chain?.contracts?.multicall3?.address + if (!multicallAddress) throw new Error(`No multicall address on chain: ${this.chainId}`) - const results = await this.requestQueue.add(() => this.multicall.aggregate3(calls)) + const results = await this.requestQueue.add(() => + this.viemClient.multicall({ + contracts: tokens.map(token => ({ + address: getAddress(token.contractAddress), + abi: erc20Abi, + functionName: 'balanceOf' as const, + args: [getAddress(pubkey)], + })), + allowFailure: true, + multicallAddress, + }), + ) return tokens .map((token, i) => { - const { success, returnData } = results[i] - - if (!success || returnData === '0x') { - return null - } + const result = results[i] - try { - const [balance] = this.erc20Interface.decodeFunctionResult('balanceOf', returnData) + if (result.status !== 'success') return null - return { - assetId: token.assetId, - balance: balance.toString(), - symbol: token.symbol, - name: token.name, - precision: token.precision, - } - } catch { - return null + return { + assetId: token.assetId, + balance: result.result.toString(), + symbol: token.symbol, + name: token.name, + precision: token.precision, } }) .filter((result): result is NonNullable => result !== null) @@ -286,9 +286,14 @@ export abstract class SecondClassEvmAdapter extends EvmBas const results = await Promise.all( tokens.map(async token => { try { - const contract = new Contract(token.contractAddress, ERC20_ABI, this.provider) - - const balance = await this.requestQueue.add(() => contract.balanceOf(pubkey)) + const balance = await this.requestQueue.add(() => + this.viemClient.readContract({ + address: getAddress(token.contractAddress), + abi: erc20Abi, + functionName: 'balanceOf', + args: [getAddress(pubkey)], + }), + ) return { assetId: token.assetId, @@ -306,27 +311,8 @@ export abstract class SecondClassEvmAdapter extends EvmBas return results.filter((result): result is NonNullable => result !== null) } - async getGasFeeData(): Promise { - try { - const feeData = await this.requestQueue.add(() => this.provider.getFeeData()) - - const gasPrice = feeData.gasPrice?.toString() ?? '0' - const maxFeePerGas = feeData.maxFeePerGas?.toString() - const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas?.toString() - - const fees = { - gasPrice, - ...(maxFeePerGas && maxPriorityFeePerGas ? { maxFeePerGas, maxPriorityFeePerGas } : {}), - } - - return { - fast: fees, - average: fees, - slow: fees, - } - } catch (err) { - throw new Error(`Failed to get gas fee data: ${err}`) - } + getGasFeeData(): Promise { + return this.getGasFeeDataFallback(this.viemClient) } async getFeeData(input: GetFeeDataInput): Promise> { @@ -334,11 +320,11 @@ export abstract class SecondClassEvmAdapter extends EvmBas const estimateGasBody = this.buildEstimateGasBody(input) const gasLimit = await this.requestQueue.add(() => - this.provider.estimateGas({ - from: estimateGasBody.from, - to: estimateGasBody.to, - value: estimateGasBody.value ? BigInt(estimateGasBody.value) : undefined, - data: estimateGasBody.data, + this.viemClient.estimateGas({ + account: getAddress(estimateGasBody.from), + to: getAddress(estimateGasBody.to), + value: parseUnits(estimateGasBody.value, 0), + data: isHex(estimateGasBody.data) ? estimateGasBody.data : toHex(estimateGasBody.data), }), ) @@ -382,8 +368,10 @@ export abstract class SecondClassEvmAdapter extends EvmBas receiverAddress !== CONTRACT_INTERACTION && assertAddressNotSanctioned(receiverAddress), ]) - const txResponse = await this.requestQueue.add(() => this.provider.broadcastTransaction(hex)) - return txResponse.hash + const hash = await this.requestQueue.add(() => + this.viemClient.sendRawTransaction({ serializedTransaction: hex as Hex }), + ) + return hash } catch (err) { return ErrorHandler(err, { translation: 'chainAdapters.errors.broadcastTransaction', @@ -428,7 +416,10 @@ export abstract class SecondClassEvmAdapter extends EvmBas try { const trace = await this.requestQueue.add(() => - this.provider.send('debug_traceTransaction', [txHash, { tracer: 'callTracer' }]), + this.viemClient.request({ + method: 'debug_traceTransaction' as any, + params: [txHash, { tracer: 'callTracer' }] as any, + }), ) const internalTxs: { from: string; to: string; value: string }[] = [] @@ -461,16 +452,11 @@ export abstract class SecondClassEvmAdapter extends EvmBas async parseTx(txHash: unknown, pubkey: string): Promise { const hash = txHash as Hex - const viemClient = viemClientByChainId[this.chainId] - - if (!viemClient) { - throw new Error(`No viem client found for chainId: ${this.chainId}`) - } try { const [transaction, receipt, internalTxs] = await Promise.all([ - viemClient.getTransaction({ hash }), - viemClient.getTransactionReceipt({ hash }), + this.viemClient.getTransaction({ hash }), + this.viemClient.getTransactionReceipt({ hash }), this.fetchInternalTransactions(hash), ]) @@ -577,7 +563,7 @@ export abstract class SecondClassEvmAdapter extends EvmBas ) const block = receipt.blockHash - ? await viemClient.getBlock({ blockHash: receipt.blockHash }).catch(() => null) + ? await this.viemClient.getBlock({ blockHash: receipt.blockHash }).catch(() => null) : null const transferLogs = parseEventLogs({ @@ -610,7 +596,7 @@ export abstract class SecondClassEvmAdapter extends EvmBas const timestamp = block?.timestamp ? Number(block.timestamp) : 0 const blockNumber = receipt.blockNumber ? Number(receipt.blockNumber) : 0 - const currentBlockNumber = await viemClient.getBlockNumber() + const currentBlockNumber = await this.viemClient.getBlockNumber() const confirmationsCount = blockNumber > 0 ? Number(currentBlockNumber) - blockNumber + 1 : 0 const status = receipt.status === 'success' ? 1 : 0 const fee = bnOrZero(receipt.gasUsed.toString()) diff --git a/packages/contracts/src/constants.ts b/packages/contracts/src/constants.ts index 7e016a5a0a9..a01c8e1023d 100644 --- a/packages/contracts/src/constants.ts +++ b/packages/contracts/src/constants.ts @@ -126,8 +126,3 @@ export const UNI_V2_FOX_STAKING_REWARDS_CONTRACTS = [ // Permit2 is deployed here across all chains. // https://0x.org/docs/introduction/0x-cheat-sheet#permit2-contract export const PERMIT2_CONTRACT = '0x000000000022D473030F116dDEE9F6B43aC78BA3' - -// Multicall3 is deployed at the same address across all EVM chains -// See: https://www.multicall3.com/deployments -// GitHub: https://github.com/mds1/multicall3 -export const MULTICALL3_CONTRACT = '0xcA11bde05977b3631167028862bE2a173976CA11' diff --git a/packages/contracts/src/fallbackRpcUrls.ts b/packages/contracts/src/fallbackRpcUrls.ts new file mode 100644 index 00000000000..75292eeb5c5 --- /dev/null +++ b/packages/contracts/src/fallbackRpcUrls.ts @@ -0,0 +1,34 @@ +export const FALLBACK_RPC_URLS = { + ethereum: ['https://eth.drpc.org', 'https://ethereum-rpc.publicnode.com'], + bsc: ['https://bsc.drpc.org', 'https://bsc-rpc.publicnode.com'], + avalanche: ['https://avalanche.drpc.org', 'https://avalanche-c-chain-rpc.publicnode.com'], + arbitrum: ['https://arbitrum.drpc.org', 'https://arbitrum-one-rpc.publicnode.com'], + optimism: ['https://optimism.drpc.org', 'https://optimism-rpc.publicnode.com'], + gnosis: ['https://gnosis.drpc.org', 'https://gnosis-rpc.publicnode.com'], + polygon: ['https://polygon.drpc.org', 'https://polygon-bor-rpc.publicnode.com'], + base: ['https://base.drpc.org', 'https://base-rpc.publicnode.com'], + monad: ['https://monad-mainnet.drpc.org', 'https://rpc.monad.xyz'], + hyperEvm: ['https://hyperliquid.drpc.org', 'https://rpc.hyperliquid.xyz/evm'], + plasma: ['https://plasma.drpc.org', 'https://rpc.plasma.to'], + plume: ['https://plume.drpc.org', 'https://rpc.plume.org'], + mantle: ['https://mantle.drpc.org', 'https://mantle-rpc.publicnode.com'], + ink: ['https://ink.drpc.org', 'https://rpc-gel.inkonchain.com', 'https://rpc-qnd.inkonchain.com'], + megaEth: ['https://megaeth.drpc.org', 'https://mainnet.megaeth.com/rpc'], + berachain: ['https://berachain.drpc.org', 'https://berachain-rpc.publicnode.com'], + scroll: ['https://scroll.drpc.org', 'https://scroll-rpc.publicnode.com'], + cronos: ['https://cronos.drpc.org', 'https://cronos-evm-rpc.publicnode.com'], + flowEvm: ['https://mainnet.evm.nodes.onflow.org'], + celo: ['https://celo.drpc.org', 'https://forno.celo.org'], + katana: ['https://katana.drpc.org', 'https://rpc.katana.network'], + story: ['https://mainnet.storyrpc.io'], + zkSyncEra: ['https://zksync.drpc.org', 'https://mainnet.era.zksync.io'], + blast: ['https://blast.drpc.org', 'https://rpc.blast.io'], + worldChain: ['https://worldchain.drpc.org', 'https://worldchain-mainnet.g.alchemy.com/public'], + hemi: ['https://hemi.drpc.org', 'https://rpc.hemi.network/rpc'], + linea: ['https://linea.drpc.org', 'https://linea-rpc.publicnode.com'], + sonic: ['https://sonic.drpc.org', 'https://sonic-rpc.publicnode.com'], + unichain: ['https://unichain.drpc.org', 'https://unichain-rpc.publicnode.com'], + bob: ['https://bob.drpc.org', 'https://rpc.gobob.xyz'], + mode: ['https://mode.drpc.org', 'https://mainnet.mode.network'], + soneium: ['https://soneium.drpc.org', 'https://rpc.soneium.org'], +} as const diff --git a/packages/contracts/src/index.ts b/packages/contracts/src/index.ts index 295fe43e455..fb43afde8ad 100644 --- a/packages/contracts/src/index.ts +++ b/packages/contracts/src/index.ts @@ -1,4 +1,5 @@ export * from './constants' +export * from './fallbackRpcUrls' export * from './types' export * from './contractManager' export * from './ethersProviderSingleton' diff --git a/packages/contracts/src/viemClient.ts b/packages/contracts/src/viemClient.ts index c4dfddaf18f..3b78cb132e2 100644 --- a/packages/contracts/src/viemClient.ts +++ b/packages/contracts/src/viemClient.ts @@ -38,6 +38,8 @@ import { zksync, } from 'viem/chains' +import { FALLBACK_RPC_URLS } from './fallbackRpcUrls' + const megaeth = defineChain({ id: 4326, name: 'MegaETH', @@ -61,130 +63,133 @@ const megaeth = defineChain({ export const flowEvmChain = flowMainnet +const createFallbackTransport = (envUrl: string | undefined, fallbacks: readonly string[]) => + fallback([envUrl, ...fallbacks].filter(Boolean).map(url => http(url))) + export const viemEthMainnetClient = createPublicClient({ chain: mainnet, - transport: fallback( - [process.env.VITE_ETHEREUM_NODE_URL, 'https://eth.llamarpc.com'] - .filter(Boolean) - .map(url => http(url)), + transport: createFallbackTransport( + process.env.VITE_ETHEREUM_NODE_URL, + FALLBACK_RPC_URLS.ethereum, ), }) as PublicClient export const viemBscClient = createPublicClient({ chain: bsc, - transport: fallback( - // https://github.com/DefiLlama/chainlist/blob/83b8cc32ee79c10e0281e1799ebe4cd1696082b7/constants/llamaNodesRpcs.js#L30 - [process.env.VITE_BNBSMARTCHAIN_NODE_URL, 'https://binance.llamarpc.com'] - .filter(Boolean) - .map(url => http(url)), + transport: createFallbackTransport( + process.env.VITE_BNBSMARTCHAIN_NODE_URL, + FALLBACK_RPC_URLS.bsc, ), }) as PublicClient export const viemAvalancheClient = createPublicClient({ chain: avalanche, - transport: fallback([process.env.VITE_AVALANCHE_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_AVALANCHE_NODE_URL, + FALLBACK_RPC_URLS.avalanche, + ), }) as PublicClient export const viemArbitrumClient = createPublicClient({ chain: arbitrum, - transport: fallback([process.env.VITE_ARBITRUM_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_ARBITRUM_NODE_URL, + FALLBACK_RPC_URLS.arbitrum, + ), }) as PublicClient export const viemOptimismClient = createPublicClient({ chain: optimism, - transport: fallback([process.env.VITE_OPTIMISM_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_OPTIMISM_NODE_URL, + FALLBACK_RPC_URLS.optimism, + ), }) as PublicClient export const viemGnosisClient = createPublicClient({ chain: gnosis, - transport: fallback([process.env.VITE_GNOSIS_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_GNOSIS_NODE_URL, FALLBACK_RPC_URLS.gnosis), }) as PublicClient export const viemPolygonClient = createPublicClient({ chain: polygon, - transport: fallback([process.env.VITE_POLYGON_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_POLYGON_NODE_URL, FALLBACK_RPC_URLS.polygon), }) as PublicClient export const viemBaseClient = createPublicClient({ chain: base, - transport: fallback([ - http('https://mainnet.base.org'), - http('https://base.llamarpc.com'), - http('https://base.blockpi.network/v1/rpc/public'), - ]), + transport: createFallbackTransport(undefined, FALLBACK_RPC_URLS.base), }) as PublicClient export const viemMonadClient = createPublicClient({ chain: monad, - transport: fallback([process.env.VITE_MONAD_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_MONAD_NODE_URL, FALLBACK_RPC_URLS.monad), }) as PublicClient export const viemHyperEvmClient = createPublicClient({ chain: hyperEvm, - transport: fallback([process.env.VITE_HYPEREVM_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_HYPEREVM_NODE_URL, + FALLBACK_RPC_URLS.hyperEvm, + ), }) as PublicClient export const viemPlasmaClient = createPublicClient({ chain: plasma, - transport: fallback([process.env.VITE_PLASMA_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_PLASMA_NODE_URL, FALLBACK_RPC_URLS.plasma), }) as PublicClient export const viemPlumeClient = createPublicClient({ chain: plumeMainnet, - transport: fallback([process.env.VITE_PLUME_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_PLUME_NODE_URL, FALLBACK_RPC_URLS.plume), }) as PublicClient export const viemMantleClient = createPublicClient({ chain: mantle, - transport: fallback([process.env.VITE_MANTLE_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_MANTLE_NODE_URL, FALLBACK_RPC_URLS.mantle), }) as PublicClient export const viemInkClient = createPublicClient({ chain: ink, - transport: fallback([process.env.VITE_INK_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_INK_NODE_URL, FALLBACK_RPC_URLS.ink), }) as PublicClient export const viemMegaEthClient = createPublicClient({ chain: megaeth, - transport: fallback([process.env.VITE_MEGAETH_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_MEGAETH_NODE_URL, FALLBACK_RPC_URLS.megaEth), }) as PublicClient export const viemBerachainClient = createPublicClient({ chain: berachain, - transport: fallback([process.env.VITE_BERACHAIN_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_BERACHAIN_NODE_URL, + FALLBACK_RPC_URLS.berachain, + ), }) as PublicClient export const viemScrollClient = createPublicClient({ chain: scroll, - transport: fallback([process.env.VITE_SCROLL_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_SCROLL_NODE_URL, FALLBACK_RPC_URLS.scroll), }) as PublicClient export const viemCronosClient = createPublicClient({ chain: cronos, - transport: fallback([process.env.VITE_CRONOS_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_CRONOS_NODE_URL, FALLBACK_RPC_URLS.cronos), }) as PublicClient export const viemFlowEvmClient = createPublicClient({ chain: flowMainnet, - transport: fallback( - [process.env.VITE_FLOWEVM_NODE_URL, 'https://mainnet.evm.nodes.onflow.org'] - .filter(Boolean) - .map(url => http(url)), - ), + transport: createFallbackTransport(process.env.VITE_FLOWEVM_NODE_URL, FALLBACK_RPC_URLS.flowEvm), }) as PublicClient export const viemCeloClient = createPublicClient({ chain: celo, - transport: fallback( - [process.env.VITE_CELO_NODE_URL, 'https://forno.celo.org'] - .filter(Boolean) - .map(url => http(url)), - ), + transport: createFallbackTransport(process.env.VITE_CELO_NODE_URL, FALLBACK_RPC_URLS.celo), }) as PublicClient export const viemKatanaClient = createPublicClient({ chain: katana, - transport: fallback([process.env.VITE_KATANA_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_KATANA_NODE_URL, FALLBACK_RPC_URLS.katana), }) as PublicClient export const ethereal = defineChain({ @@ -204,27 +209,33 @@ export const viemEtherealClient = createPublicClient({ export const viemStoryClient = createPublicClient({ chain: story, - transport: fallback([process.env.VITE_STORY_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_STORY_NODE_URL, FALLBACK_RPC_URLS.story), }) as PublicClient export const viemZkSyncEraClient = createPublicClient({ chain: zksync, - transport: fallback([process.env.VITE_ZKSYNC_ERA_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_ZKSYNC_ERA_NODE_URL, + FALLBACK_RPC_URLS.zkSyncEra, + ), }) as PublicClient export const viemBlastClient = createPublicClient({ chain: blast, - transport: fallback([process.env.VITE_BLAST_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_BLAST_NODE_URL, FALLBACK_RPC_URLS.blast), }) as PublicClient export const viemWorldChainClient = createPublicClient({ chain: worldchain, - transport: fallback([process.env.VITE_WORLDCHAIN_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_WORLDCHAIN_NODE_URL, + FALLBACK_RPC_URLS.worldChain, + ), }) as PublicClient export const viemHemiClient = createPublicClient({ chain: hemi, - transport: fallback([process.env.VITE_HEMI_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_HEMI_NODE_URL, FALLBACK_RPC_URLS.hemi), }) as PublicClient export const viemSeiClient = createPublicClient({ @@ -234,32 +245,35 @@ export const viemSeiClient = createPublicClient({ export const viemLineaClient = createPublicClient({ chain: linea, - transport: fallback([process.env.VITE_LINEA_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_LINEA_NODE_URL, FALLBACK_RPC_URLS.linea), }) as PublicClient export const viemSonicClient = createPublicClient({ chain: sonic, - transport: fallback([process.env.VITE_SONIC_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_SONIC_NODE_URL, FALLBACK_RPC_URLS.sonic), }) as PublicClient export const viemUnichainClient = createPublicClient({ chain: unichain, - transport: fallback([process.env.VITE_UNICHAIN_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport( + process.env.VITE_UNICHAIN_NODE_URL, + FALLBACK_RPC_URLS.unichain, + ), }) as PublicClient export const viemBobClient = createPublicClient({ chain: bob, - transport: fallback([process.env.VITE_BOB_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_BOB_NODE_URL, FALLBACK_RPC_URLS.bob), }) as PublicClient export const viemModeClient = createPublicClient({ chain: mode, - transport: fallback([process.env.VITE_MODE_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_MODE_NODE_URL, FALLBACK_RPC_URLS.mode), }) as PublicClient export const viemSoneiumClient = createPublicClient({ chain: soneium, - transport: fallback([process.env.VITE_SONEIUM_NODE_URL].filter(Boolean).map(url => http(url))), + transport: createFallbackTransport(process.env.VITE_SONEIUM_NODE_URL, FALLBACK_RPC_URLS.soneium), }) as PublicClient export const viemClientByChainId: Record = { diff --git a/packages/public-api/src/docs/openapi.ts b/packages/public-api/src/docs/openapi.ts index f7e2b5d20d2..526bc2e0218 100644 --- a/packages/public-api/src/docs/openapi.ts +++ b/packages/public-api/src/docs/openapi.ts @@ -376,29 +376,16 @@ registry.registerPath({ }, }) -const AffiliateAddressHeaderSchema = z +const PartnerCodeHeaderSchema = z .string() .optional() .openapi({ param: { - name: 'X-Affiliate-Address', + name: 'X-Partner-Code', in: 'header', description: - 'Your Arbitrum address for affiliate fee attribution. Optional — endpoints work without it.', - example: '0x0000000000000000000000000000000000000001', - }, - }) - -const AffiliateBpsHeaderSchema = z - .string() - .optional() - .openapi({ - param: { - name: 'X-Affiliate-Bps', - in: 'header', - description: - 'Custom affiliate fee in basis points (0-1000). Defaults to 10 (0.1%). Can be used independently of X-Affiliate-Address.', - example: '10', + 'Partner code for affiliate fee attribution. The API resolves the code to the registered affiliate address and BPS. Register a code at the affiliate dashboard.', + example: 'vultisig', }, }) @@ -413,8 +400,7 @@ registry.registerPath({ tags: ['Swaps'], request: { headers: z.object({ - 'X-Affiliate-Address': AffiliateAddressHeaderSchema, - 'X-Affiliate-Bps': AffiliateBpsHeaderSchema, + 'X-Partner-Code': PartnerCodeHeaderSchema, }), query: RatesRequestSchema, }, @@ -445,8 +431,7 @@ registry.registerPath({ tags: ['Swaps'], request: { headers: z.object({ - 'X-Affiliate-Address': AffiliateAddressHeaderSchema, - 'X-Affiliate-Bps': AffiliateBpsHeaderSchema, + 'X-Partner-Code': PartnerCodeHeaderSchema, }), body: { content: { @@ -500,7 +485,7 @@ registry.registerPath({ 'Look up the current status of a swap by its quote ID. Pass txHash on the first call after broadcasting to bind it to the quote and start tracking. Subsequent calls can omit txHash.', tags: ['Swaps'], request: { - headers: z.object({ 'X-Affiliate-Address': AffiliateAddressHeaderSchema }), + headers: z.object({ 'X-Partner-Code': PartnerCodeHeaderSchema }), query: StatusRequestSchema, }, responses: { @@ -580,7 +565,7 @@ There are two ways to integrate: 2. **REST API** — Build your own swap UI using the endpoints below. Full control over UX. ## Affiliate Tracking (Optional) -Include your Arbitrum address in the \`X-Affiliate-Address\` header to attribute swaps for affiliate fee tracking. This is optional — all endpoints work without it. +Include a \`X-Partner-Code\` header with your registered partner code (e.g. \`vultisig\`, \`venice\`) to attribute swaps for affiliate fee tracking. The API resolves the code to the registered affiliate address and BPS automatically. Register a partner code at the affiliate dashboard. This is optional — all endpoints work without it. ## Asset IDs Assets use CAIP-19 format: \`{chainId}/{assetNamespace}:{assetReference}\` @@ -625,7 +610,7 @@ import '@shapeshiftoss/swap-widget/style.css' function App() { return ( console.log('Success:', txHash)} /> @@ -654,7 +639,7 @@ function SwapPage() { return ( { // Trigger YOUR app's wallet connection modal openYourConnectModal() @@ -686,7 +671,7 @@ function App() { ) @@ -717,8 +702,7 @@ When \`enableWalletConnection\` is true, the widget: | Prop | Type | Default | Description | |------|------|---------|-------------| -| \`affiliateAddress\` | \`string\` | — | Your Arbitrum address for affiliate fee attribution | -| \`affiliateBps\` | \`string\` | \`"10"\` | Affiliate fee in basis points (0.1% default) | +| \`partnerCode\` | \`string\` | — | Your registered partner code for affiliate fee attribution. Register at the affiliate dashboard. | | \`apiBaseUrl\` | \`string\` | — | Custom API base URL | | \`theme\` | \`ThemeMode \\| ThemeConfig\` | \`"dark"\` | Theme mode or full theme configuration | | \`showPoweredBy\` | \`boolean\` | \`true\` | Show "Powered by ShapeShift" branding | @@ -823,7 +807,7 @@ import { SwapWidget, EVM_CHAIN_IDS } from '@shapeshiftoss/swap-widget' \`\`\` @@ -843,7 +827,7 @@ const usdcAsset = { defaultBuyAsset={usdcAsset} isBuyAssetLocked={true} defaultReceiveAddress="0xYourTreasuryAddress" - affiliateAddress="0xYourArbitrumAddress" + partnerCode="your-partner-code" theme="dark" /> \`\`\` @@ -988,13 +972,13 @@ GET /v1/assets ## 3. Get Swap Rates \`\`\` GET /v1/swap/rates?sellAssetId=eip155:1/slip44:60&buyAssetId=eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&sellAmountCryptoBaseUnit=1000000000000000000 -X-Affiliate-Address: 0xYourArbitrumAddress (optional) +X-Partner-Code: your-partner-code (optional) \`\`\` ## 4. Get Executable Quote \`\`\` POST /v1/swap/quote -X-Affiliate-Address: 0xYourArbitrumAddress (optional) +X-Partner-Code: your-partner-code (optional) { "sellAssetId": "eip155:1/slip44:60", diff --git a/packages/public-api/src/index.ts b/packages/public-api/src/index.ts index 90f86640865..acb11dfe2e4 100644 --- a/packages/public-api/src/index.ts +++ b/packages/public-api/src/index.ts @@ -6,7 +6,7 @@ import express from 'express' import { initAssets } from './assets' import { API_HOST, API_PORT } from './config' import { quoteStore } from './lib/quoteStore' -import { affiliateAddress } from './middleware/auth' +import { resolvePartnerCode } from './middleware/auth' import { affiliateStatsLimiter, dataLimiter, @@ -62,10 +62,10 @@ app.get('/health', (_req, res) => { // API v1 routes const v1Router = express.Router() -// Swap endpoints (optional affiliate address tracking) -v1Router.get('/swap/rates', swapRatesLimiter, affiliateAddress, getRates) -v1Router.post('/swap/quote', swapQuoteLimiter, affiliateAddress, getQuote) -v1Router.get('/swap/status', swapStatusLimiter, affiliateAddress, getSwapStatus) +// Swap endpoints (optional partner code tracking) +v1Router.get('/swap/rates', swapRatesLimiter, resolvePartnerCode, getRates) +v1Router.post('/swap/quote', swapQuoteLimiter, resolvePartnerCode, getQuote) +v1Router.get('/swap/status', swapStatusLimiter, resolvePartnerCode, getSwapStatus) // Affiliate endpoints v1Router.get('/affiliate/stats', affiliateStatsLimiter, getAffiliateStats) @@ -113,8 +113,8 @@ Available endpoints: GET /v1/assets/count - Get asset count GET /v1/assets/:assetId - Get single asset by ID -Affiliate Tracking (optional): - Include 'X-Affiliate-Address' header with your Arbitrum address for affiliate fee attribution. +Partner Tracking (optional): + Include 'X-Partner-Code' header with your registered partner code for affiliate fee attribution. The API works without it — no authentication required. `) }) diff --git a/packages/public-api/src/middleware/auth.ts b/packages/public-api/src/middleware/auth.ts index 3981ed5f408..c2905ae98b3 100644 --- a/packages/public-api/src/middleware/auth.ts +++ b/packages/public-api/src/middleware/auth.ts @@ -1,38 +1,57 @@ import type { NextFunction, Request, Response } from 'express' -import type { ErrorResponse } from '../types' +const DEFAULT_AFFILIATE_BPS = '60' -const EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/ -const BPS_REGEX = /^\d+$/ +// Microservices URL for partner code resolution +const MICROSERVICES_URL = process.env.MICROSERVICES_URL || 'http://localhost:3001' -export const affiliateAddress = (req: Request, res: Response, next: NextFunction): void => { - const address = req.header('X-Affiliate-Address') - const bps = req.header('X-Affiliate-Bps') +const resolvePartnerCodeFromService = async ( + code: string, +): Promise<{ affiliateAddress: string; bps: string } | null> => { + try { + const response = await fetch(`${MICROSERVICES_URL}/v1/partner/${encodeURIComponent(code)}`) - if (address && !EVM_ADDRESS_REGEX.test(address)) { - const errorResponse: ErrorResponse = { - error: - 'Invalid affiliate address format. Must be a valid EVM address (0x followed by 40 hex characters).', - code: 'INVALID_AFFILIATE_ADDRESS', + if (response.ok) { + const data = (await response.json()) as { + affiliateAddress: string + bps: number + } + return { + affiliateAddress: data.affiliateAddress, + bps: String(data.bps), + } } - res.status(400).json(errorResponse) - return + + return null + } catch { + return null } +} - if (bps !== undefined && (!BPS_REGEX.test(bps) || parseInt(bps, 10) > 1000)) { - const errorResponse: ErrorResponse = { - error: 'Invalid affiliate BPS. Must be an integer between 0 and 1000.', - code: 'INVALID_AFFILIATE_BPS', +export const resolvePartnerCode = async ( + req: Request, + _res: Response, + next: NextFunction, +): Promise => { + const partnerCode = req.header('X-Partner-Code') + + if (partnerCode) { + const resolved = await resolvePartnerCodeFromService(partnerCode) + if (resolved) { + req.affiliateInfo = { + affiliateAddress: resolved.affiliateAddress, + affiliateBps: resolved.bps, + partnerCode, + } + next() + return } - res.status(400).json(errorResponse) - return + // Partner code not found — continue without affiliate info } - if (address || bps) { - req.affiliateInfo = { - ...(address && { affiliateAddress: address }), - ...(bps && { affiliateBps: bps }), - } + // No partner code provided — use default BPS for unattributed swaps + req.affiliateInfo = { + affiliateBps: DEFAULT_AFFILIATE_BPS, } next() diff --git a/packages/public-api/src/routes/status.ts b/packages/public-api/src/routes/status.ts index 4d920e7ec08..5cf72be9672 100644 --- a/packages/public-api/src/routes/status.ts +++ b/packages/public-api/src/routes/status.ts @@ -106,16 +106,6 @@ export const getSwapStatus = async (req: Request, res: Response): Promise return } - const requestAffiliateAddress = req.affiliateInfo?.affiliateAddress?.toLowerCase() - const quoteAffiliateAddress = storedQuote.affiliateAddress?.toLowerCase() - if (quoteAffiliateAddress && requestAffiliateAddress !== quoteAffiliateAddress) { - res.status(403).json({ - error: 'Quote is not accessible for this affiliate', - code: 'AFFILIATE_MISMATCH', - } as ErrorResponse) - return - } - if (txHash && storedQuote.txHash && storedQuote.txHash !== txHash) { res.status(409).json({ error: 'Transaction hash does not match the registered swap', diff --git a/packages/public-api/src/server-standalone.ts b/packages/public-api/src/server-standalone.ts index 7862e8a7a3d..4f66c0c634b 100644 --- a/packages/public-api/src/server-standalone.ts +++ b/packages/public-api/src/server-standalone.ts @@ -6,6 +6,8 @@ * For production, use index.ts which integrates with the real swapper package. */ +import './types' + import cors from 'cors' import express from 'express' import { v4 as uuidv4 } from 'uuid' @@ -13,34 +15,25 @@ import { v4 as uuidv4 } from 'uuid' const API_PORT = parseInt(process.env.PORT || '3001', 10) const API_HOST = process.env.HOST || '0.0.0.0' -const EVM_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/ - const app = express() // Middleware app.use(cors()) app.use(express.json()) -const affiliateAddress = ( +const partnerTracking = ( req: express.Request, - res: express.Response, + _res: express.Response, next: express.NextFunction, -) => { - const address = req.header('X-Affiliate-Address') - - if (!address) { - return next() - } +): void => { + const partnerCode = req.header('X-Partner-Code') - if (!EVM_ADDRESS_REGEX.test(address)) { - return res.status(400).json({ - error: - 'Invalid affiliate address format. Must be a valid EVM address (0x followed by 40 hex characters).', - code: 'INVALID_AFFILIATE_ADDRESS', - }) + if (!partnerCode) { + next() + return } - ;(req as any).affiliateInfo = { affiliateAddress: address } + req.affiliateInfo = { partnerCode } next() } @@ -51,7 +44,7 @@ app.get('/health', (_req, res) => { }) // Mock rates endpoint -app.get('/v1/swap/rates', affiliateAddress, (req, res) => { +app.get('/v1/swap/rates', partnerTracking, (req, res) => { const { sellAssetId, buyAssetId, sellAmountCryptoBaseUnit } = req.query if (!sellAssetId || !buyAssetId || !sellAmountCryptoBaseUnit) { @@ -106,7 +99,7 @@ app.get('/v1/swap/rates', affiliateAddress, (req, res) => { }) // Mock quote endpoint -app.post('/v1/swap/quote', affiliateAddress, (req, res) => { +app.post('/v1/swap/quote', partnerTracking, (req, res) => { const { sellAssetId, buyAssetId, sellAmountCryptoBaseUnit, receiveAddress, swapperName } = req.body @@ -220,8 +213,8 @@ Endpoints: POST /v1/swap/quote - Get executable quote with tx data GET /v1/assets - List supported assets -Affiliate Tracking (optional): - Include 'X-Affiliate-Address' header with your Arbitrum address for fee attribution. +Partner Tracking (optional): + Include 'X-Partner-Code' header with your registered partner code for fee attribution. The API works without it — no authentication required. Example requests: @@ -229,12 +222,12 @@ Example requests: # Health check curl http://localhost:${API_PORT}/health - # Get rates (with affiliate address) - curl -H "X-Affiliate-Address: 0x0000000000000000000000000000000000000001" \\ + # Get rates (with partner code) + curl -H "X-Partner-Code: my-partner" \\ "http://localhost:${API_PORT}/v1/swap/rates?sellAssetId=eip155:1/slip44:60&buyAssetId=eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48&sellAmountCryptoBaseUnit=1000000000000000000" - # Get quote (with affiliate address) - curl -X POST -H "X-Affiliate-Address: 0x0000000000000000000000000000000000000001" -H "Content-Type: application/json" \\ + # Get quote (with partner code) + curl -X POST -H "X-Partner-Code: my-partner" -H "Content-Type: application/json" \\ -d '{"sellAssetId":"eip155:1/slip44:60","buyAssetId":"eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48","sellAmountCryptoBaseUnit":"1000000000000000000","receiveAddress":"0x742d35Cc6634C0532925a3b844Bc9e7595f4EdC3","swapperName":"THORChain"}' \\ http://localhost:${API_PORT}/v1/swap/quote diff --git a/packages/public-api/src/types.ts b/packages/public-api/src/types.ts index 957a75a700b..07a3d7d3b61 100644 --- a/packages/public-api/src/types.ts +++ b/packages/public-api/src/types.ts @@ -26,6 +26,7 @@ export type { export type AffiliateInfo = { affiliateAddress?: string affiliateBps?: string + partnerCode?: string } export type RatesRequest = { diff --git a/packages/public-api/tests/smoke-tests.ts b/packages/public-api/tests/smoke-tests.ts index 22bc73583c4..8dbed277363 100644 --- a/packages/public-api/tests/smoke-tests.ts +++ b/packages/public-api/tests/smoke-tests.ts @@ -1,4 +1,4 @@ -import { ASSET_IDS, TEST_AFFILIATE_ADDRESS, TEST_PAIRS } from './test-config' +import { ASSET_IDS, TEST_PAIRS, TEST_PARTNER_CODE } from './test-config' import type { TestResult, TestSuiteResult } from './test-utils' import { fetchWithTimeout, runTest } from './test-utils' @@ -132,7 +132,7 @@ export const runSmokeTests = async (): Promise => { const res = await fetchWithTimeout( `${API_URL}/v1/swap/rates?${params}`, { - headers: { 'X-Affiliate-Address': TEST_AFFILIATE_ADDRESS }, + headers: { 'X-Partner-Code': TEST_PARTNER_CODE }, }, 30000, ) @@ -182,7 +182,7 @@ export const runSmokeTests = async (): Promise => { const res = await fetchWithTimeout( `${API_URL}/v1/swap/rates?${params}`, { - headers: { 'X-Affiliate-Address': TEST_AFFILIATE_ADDRESS }, + headers: { 'X-Partner-Code': TEST_PARTNER_CODE }, }, 30000, ) diff --git a/packages/public-api/tests/test-config.ts b/packages/public-api/tests/test-config.ts index 974258a7425..ef0230775ba 100644 --- a/packages/public-api/tests/test-config.ts +++ b/packages/public-api/tests/test-config.ts @@ -1,4 +1,4 @@ -export const TEST_AFFILIATE_ADDRESS = '0x0000000000000000000000000000000000000001' +export const TEST_PARTNER_CODE = 'test-partner' export const ASSET_IDS = { // EVM Native Assets diff --git a/packages/swap-widget/README.md b/packages/swap-widget/README.md index b9ed1b1f2af..fc5d34d5022 100644 --- a/packages/swap-widget/README.md +++ b/packages/swap-widget/README.md @@ -44,7 +44,7 @@ import { SwapWidget } from "@shapeshiftoss/swap-widget"; function App() { return ( console.log("Success:", txHash)} onSwapError={(error) => console.error("Error:", error)} @@ -59,7 +59,7 @@ function App() { | Prop | Type | Default | Description | | ------------------------ | ----------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------- | -| `affiliateAddress` | `string` | - | Your Arbitrum address for affiliate fee attribution. Optional — the widget works without it. | +| `partnerCode` | `string` | - | Your registered partner code for affiliate fee attribution. Register at the affiliate dashboard. | | `apiBaseUrl` | `string` | - | Custom API base URL. Useful for testing or custom deployments. | | `defaultSellAsset` | `Asset` | ETH on Ethereum | Initial asset to sell. | | `defaultBuyAsset` | `Asset` | USDC on Ethereum | Initial asset to buy. | @@ -132,7 +132,7 @@ function App() { import { SwapWidget } from "@shapeshiftoss/swap-widget"; function App() { - return ; + return ; } ``` @@ -149,7 +149,7 @@ function App() { return ( { // Your custom wallet connection logic @@ -198,7 +198,7 @@ const defaultBuyAsset: Asset = { function App() { return ( @@ -481,9 +481,16 @@ The widget supports swaps across multiple blockchain types: - **Solana swaps** - Solana transactions can be signed via Phantom, Solflare, or other Solana wallets when using the built-in wallet connection. - **Unsupported chains** - Swaps involving chains without wallet support will redirect to [app.shapeshift.com](https://app.shapeshift.com) to complete the transaction. -### Affiliate Address +### Partner Codes -An affiliate address is optional. Pass your Arbitrum address via the `affiliateAddress` prop to attribute swaps for affiliate fee tracking. The widget works without it — no registration or approval required. +Register an affiliate account at the affiliate dashboard and claim a partner code (e.g. `vultisig`, `venice`). Pass it via the `partnerCode` prop on the widget, or the `X-Partner-Code` header when using the REST API directly: + +``` +GET /v1/swap/rates?... +X-Partner-Code: your-partner-code +``` + +The API resolves the partner code to the registered affiliate address and BPS automatically. ### Internal QueryClient diff --git a/packages/swap-widget/package.json b/packages/swap-widget/package.json index 6af23a0343d..bddb7bf435d 100644 --- a/packages/swap-widget/package.json +++ b/packages/swap-widget/package.json @@ -35,9 +35,9 @@ "test:watch": "vitest" }, "dependencies": { - "@shapeshiftoss/caip": "^8.0.0", - "@shapeshiftoss/types": "^8.0.0", - "@shapeshiftoss/utils": "^1.0.0", + "@shapeshiftoss/caip": "workspace:^", + "@shapeshiftoss/types": "workspace:^", + "@shapeshiftoss/utils": "workspace:^", "@xstate/react": "5.0.5", "bech32": "^2.0.0", "p-queue": "^8.0.1", @@ -82,9 +82,6 @@ "@reown/appkit-adapter-bitcoin": "^1.8.17", "@reown/appkit-adapter-solana": "^1.8.17", "@reown/appkit-adapter-wagmi": "^1.8.17", - "@shapeshiftoss/caip": "workspace:^", - "@shapeshiftoss/types": "workspace:^", - "@shapeshiftoss/utils": "workspace:^", "@solana/wallet-adapter-wallets": "^0.19.32", "@solana/web3.js": "1.98.0", "@tanstack/react-query": "^5.69.0", diff --git a/packages/swap-widget/src/api/client.ts b/packages/swap-widget/src/api/client.ts index 39156b7e544..d4df7e4383e 100644 --- a/packages/swap-widget/src/api/client.ts +++ b/packages/swap-widget/src/api/client.ts @@ -5,8 +5,7 @@ const DEFAULT_API_BASE_URL = export type ApiClientConfig = { baseUrl?: string - affiliateAddress?: string - affiliateBps?: string + partnerCode?: string } export const createApiClient = (config: ApiClientConfig = {}) => { @@ -22,11 +21,8 @@ export const createApiClient = (config: ApiClientConfig = {}) => { const headers: Record = { 'Content-Type': 'application/json', } - if (config.affiliateAddress) { - headers['x-affiliate-address'] = config.affiliateAddress - } - if (config.affiliateBps) { - headers['x-affiliate-bps'] = config.affiliateBps + if (config.partnerCode) { + headers['x-partner-code'] = config.partnerCode } const controller = new AbortController() @@ -69,6 +65,12 @@ export const createApiClient = (config: ApiClientConfig = {}) => { sellAmountCryptoBaseUnit: params.sellAmountCryptoBaseUnit, }), + getSwapStatus: (params: { quoteId: string; txHash?: string }) => + fetchWithConfig>('/v1/swap/status', { + quoteId: params.quoteId, + ...(params.txHash && { txHash: params.txHash }), + }), + getQuote: (params: { sellAssetId: AssetId buyAssetId: AssetId diff --git a/packages/swap-widget/src/components/SwapWidget.tsx b/packages/swap-widget/src/components/SwapWidget.tsx index 8a5776ffee3..36e01532c49 100644 --- a/packages/swap-widget/src/components/SwapWidget.tsx +++ b/packages/swap-widget/src/components/SwapWidget.tsx @@ -44,9 +44,10 @@ type SwapWidgetContentProps = { theme: SwapWidgetProps['theme'] showPoweredBy: boolean defaultReceiveAddress?: string - affiliateAddress?: string enableWalletConnection: boolean isBuyAssetLocked: boolean + partnerCode?: string + appUrl?: string onConnectWallet?: () => void onSwapSuccess?: (txHash: string) => void onSwapError?: (error: Error) => void @@ -66,9 +67,10 @@ const SwapWidgetContent = ({ theme = 'dark', showPoweredBy, defaultReceiveAddress, - affiliateAddress, enableWalletConnection, isBuyAssetLocked, + partnerCode, + appUrl, onConnectWallet, onSwapSuccess, onSwapError, @@ -133,7 +135,7 @@ const SwapWidgetContent = ({ handleSelectRate, handleSlippageChange, handleButtonClick, - } = useSwapHandlers({ onConnectWallet, onAssetSelect, affiliateAddress }) + } = useSwapHandlers({ onConnectWallet, onAssetSelect, partnerCode, appUrl }) useSwapQuoting({ apiClient, rates, sellAssetBalance }) @@ -141,7 +143,7 @@ const SwapWidgetContent = ({ useSwapExecution() - useStatusPolling({ onSwapSuccess, onSwapError, refetchSellBalance, refetchBuyBalance }) + useStatusPolling({ apiClient, onSwapSuccess, onSwapError, refetchSellBalance, refetchBuyBalance }) const widgetStyle = useMemo(() => { if (!themeConfig) return undefined @@ -360,12 +362,13 @@ type SwapWidgetCoreProps = { defaultBuyAsset: Asset defaultSlippage: string defaultReceiveAddress?: string - affiliateAddress?: string apiClient: ReturnType theme: SwapWidgetProps['theme'] showPoweredBy: boolean enableWalletConnection: boolean isBuyAssetLocked: boolean + partnerCode?: string + appUrl?: string onConnectWallet?: () => void onSwapSuccess?: (txHash: string) => void onSwapError?: (error: Error) => void @@ -386,12 +389,13 @@ const SwapWidgetCore = ({ defaultBuyAsset, defaultSlippage, defaultReceiveAddress, - affiliateAddress, apiClient, theme, showPoweredBy, enableWalletConnection, isBuyAssetLocked, + partnerCode, + appUrl, onConnectWallet, onSwapSuccess, onSwapError, @@ -490,9 +494,10 @@ const SwapWidgetCore = ({ theme={theme} showPoweredBy={showPoweredBy} defaultReceiveAddress={defaultReceiveAddress} - affiliateAddress={affiliateAddress} enableWalletConnection={enableWalletConnection} isBuyAssetLocked={isBuyAssetLocked} + partnerCode={partnerCode} + appUrl={appUrl} onConnectWallet={onConnectWallet} onSwapSuccess={onSwapSuccess} onSwapError={onSwapError} @@ -515,10 +520,9 @@ const SwapWidgetWithExternalWallet = (props: SwapWidgetProps) => { () => createApiClient({ baseUrl: props.apiBaseUrl, - affiliateAddress: props.affiliateAddress, - affiliateBps: props.affiliateBps, + partnerCode: props.partnerCode, }), - [props.apiBaseUrl, props.affiliateAddress, props.affiliateBps], + [props.apiBaseUrl, props.partnerCode], ) return ( @@ -531,12 +535,13 @@ const SwapWidgetWithExternalWallet = (props: SwapWidgetProps) => { defaultBuyAsset={props.defaultBuyAsset ?? DEFAULT_BUY_ASSET} defaultSlippage={props.defaultSlippage ?? '0.5'} defaultReceiveAddress={props.defaultReceiveAddress} - affiliateAddress={props.affiliateAddress} apiClient={apiClient} theme={props.theme} showPoweredBy={props.showPoweredBy ?? true} enableWalletConnection={false} isBuyAssetLocked={props.isBuyAssetLocked ?? false} + partnerCode={props.partnerCode} + appUrl={props.appUrl} onConnectWallet={props.onConnectWallet} onSwapSuccess={props.onSwapSuccess} onSwapError={props.onSwapError} @@ -563,10 +568,9 @@ const SwapWidgetWithInternalWallet = ( () => createApiClient({ baseUrl: props.apiBaseUrl, - affiliateAddress: props.affiliateAddress, - affiliateBps: props.affiliateBps, + partnerCode: props.partnerCode, }), - [props.apiBaseUrl, props.affiliateAddress, props.affiliateBps], + [props.apiBaseUrl, props.partnerCode], ) return ( @@ -580,11 +584,12 @@ const SwapWidgetWithInternalWallet = ( defaultBuyAsset={props.defaultBuyAsset ?? DEFAULT_BUY_ASSET} defaultSlippage={props.defaultSlippage ?? '0.5'} defaultReceiveAddress={props.defaultReceiveAddress} - affiliateAddress={props.affiliateAddress} apiClient={apiClient} theme={props.theme} showPoweredBy={props.showPoweredBy ?? true} enableWalletConnection={true} + partnerCode={props.partnerCode} + appUrl={props.appUrl} onConnectWallet={props.onConnectWallet} onSwapSuccess={props.onSwapSuccess} onSwapError={props.onSwapError} diff --git a/packages/swap-widget/src/constants/viemChains.ts b/packages/swap-widget/src/constants/viemChains.ts index 017bc19f3e6..bc030ab3415 100644 --- a/packages/swap-widget/src/constants/viemChains.ts +++ b/packages/swap-widget/src/constants/viemChains.ts @@ -12,6 +12,7 @@ import { optimism, plasma, polygon, + worldchain, } from 'viem/chains' export const VIEM_CHAINS_BY_ID: Record = { @@ -21,6 +22,7 @@ export const VIEM_CHAINS_BY_ID: Record = { 100: gnosis, 137: polygon, 143: monad, + 480: worldchain, 999: hyperEvm, 8453: base, 9745: plasma, diff --git a/packages/swap-widget/src/demo/App.tsx b/packages/swap-widget/src/demo/App.tsx index 19f1184e6ed..c30ce1758d9 100644 --- a/packages/swap-widget/src/demo/App.tsx +++ b/packages/swap-widget/src/demo/App.tsx @@ -454,7 +454,7 @@ ${formatColors(lightColors, 'light')}
void onSwapError?: (error: Error) => void refetchSellBalance?: () => void @@ -16,6 +18,7 @@ type UseStatusPollingParams = { } export const useStatusPolling = ({ + apiClient, onSwapSuccess, onSwapError, refetchSellBalance, @@ -39,10 +42,20 @@ export const useStatusPolling = ({ pollingRef.current = true let stopped = false + let registeredWithApi = false const poll = async () => { if (stopped || !context.txHash) return + if (!registeredWithApi && context.quote?.quoteId) { + try { + await apiClient.getSwapStatus({ quoteId: context.quote.quoteId, txHash: context.txHash }) + registeredWithApi = true + } catch { + // Retry on next poll cycle — don't block on-chain polling + } + } + try { let statusParams: CheckStatusParams diff --git a/packages/swap-widget/src/hooks/useSwapHandlers.ts b/packages/swap-widget/src/hooks/useSwapHandlers.ts index 480a8767c53..cc609946450 100644 --- a/packages/swap-widget/src/hooks/useSwapHandlers.ts +++ b/packages/swap-widget/src/hooks/useSwapHandlers.ts @@ -9,13 +9,15 @@ import { buildShapeShiftTradeUrl } from '../utils/redirect' type UseSwapHandlersParams = { onConnectWallet?: () => void onAssetSelect?: (type: 'sell' | 'buy', asset: Asset) => void - affiliateAddress?: string + partnerCode?: string + appUrl?: string } export const useSwapHandlers = ({ onConnectWallet, onAssetSelect, - affiliateAddress, + partnerCode, + appUrl, }: UseSwapHandlersParams) => { const actorRef = SwapMachineCtx.useActorRef() const { walletClient, bitcoin, solana } = useSwapWallet() @@ -75,10 +77,11 @@ export const useSwapHandlers = ({ sellAssetId: snap.context.sellAsset.assetId, buyAssetId: snap.context.buyAsset.assetId, sellAmountBaseUnit, - affiliateAddress, + partnerCode, + appUrl, }) window.open(url, '_blank', 'noopener,noreferrer') - }, [actorRef, affiliateAddress]) + }, [actorRef, partnerCode, appUrl]) const handleButtonClick = useCallback(() => { const snap = actorRef.getSnapshot() @@ -104,7 +107,8 @@ export const useSwapHandlers = ({ sellAssetId: snap.context.sellAsset.assetId, buyAssetId: snap.context.buyAsset.assetId, sellAmountBaseUnit, - affiliateAddress, + partnerCode, + appUrl, }) window.open(url, '_blank', 'noopener,noreferrer') return @@ -116,7 +120,8 @@ export const useSwapHandlers = ({ solana.isConnected, walletClient, onConnectWallet, - affiliateAddress, + partnerCode, + appUrl, ]) return { diff --git a/packages/swap-widget/src/hooks/useSwapRates.ts b/packages/swap-widget/src/hooks/useSwapRates.ts index 04b3d5bc8d4..91474f658d0 100644 --- a/packages/swap-widget/src/hooks/useSwapRates.ts +++ b/packages/swap-widget/src/hooks/useSwapRates.ts @@ -12,7 +12,6 @@ export type UseSwapRatesParams = { enabled?: boolean allowedSwapperNames?: SwapperName[] refetchInterval?: number - affiliateAddress?: string } export const useSwapRates = ( @@ -26,18 +25,10 @@ export const useSwapRates = ( enabled = true, allowedSwapperNames, refetchInterval = 15_000, - affiliateAddress, } = params return useQuery({ - queryKey: [ - 'swapRates', - sellAssetId, - buyAssetId, - sellAmountCryptoBaseUnit, - allowedSwapperNames, - affiliateAddress, - ], + queryKey: ['swapRates', sellAssetId, buyAssetId, sellAmountCryptoBaseUnit, allowedSwapperNames], queryFn: async (): Promise => { if (!sellAssetId || !buyAssetId || !sellAmountCryptoBaseUnit) { return [] diff --git a/packages/swap-widget/src/services/transactionStatus.ts b/packages/swap-widget/src/services/transactionStatus.ts index 62d3ab85ff5..137f6651cc6 100644 --- a/packages/swap-widget/src/services/transactionStatus.ts +++ b/packages/swap-widget/src/services/transactionStatus.ts @@ -1,7 +1,9 @@ import type { Connection, SignatureStatus } from '@solana/web3.js' import type { PublicClient } from 'viem' import { createPublicClient, http } from 'viem' -import { arbitrum, avalanche, base, bsc, gnosis, mainnet, optimism, polygon } from 'viem/chains' +import { mainnet } from 'viem/chains' + +import { VIEM_CHAINS_BY_ID } from '../constants/viemChains' export type TransactionStatus = 'pending' | 'confirmed' | 'failed' @@ -19,27 +21,6 @@ export type BitcoinTransactionStatus = { block_time?: number } -type EvmChain = - | typeof mainnet - | typeof optimism - | typeof bsc - | typeof gnosis - | typeof polygon - | typeof base - | typeof arbitrum - | typeof avalanche - -const EVM_CHAINS_BY_ID: Record = { - 1: mainnet, - 10: optimism, - 56: bsc, - 100: gnosis, - 137: polygon, - 8453: base, - 42161: arbitrum, - 43114: avalanche, -} - const MEMPOOL_API_BASE = 'https://mempool.space/api' export const checkEvmStatus = async ( @@ -48,7 +29,7 @@ export const checkEvmStatus = async ( existingClient?: PublicClient, ): Promise => { try { - const chain = EVM_CHAINS_BY_ID[chainId] + const chain = VIEM_CHAINS_BY_ID[chainId] const client = existingClient ?? createPublicClient({ @@ -194,7 +175,7 @@ export const waitForEvmConfirmation = async ( confirmations = 1, timeoutMs = 120000, ): Promise => { - const chain = EVM_CHAINS_BY_ID[chainId] + const chain = VIEM_CHAINS_BY_ID[chainId] const client = createPublicClient({ chain: chain ?? mainnet, transport: http(), diff --git a/packages/swap-widget/src/types/index.ts b/packages/swap-widget/src/types/index.ts index 8324d7d2925..2c517006646 100644 --- a/packages/swap-widget/src/types/index.ts +++ b/packages/swap-widget/src/types/index.ts @@ -138,9 +138,9 @@ export type ThemeConfig = { } export type SwapWidgetProps = { - affiliateAddress?: string - affiliateBps?: string + partnerCode?: string apiBaseUrl?: string + appUrl?: string defaultSellAsset?: Asset defaultBuyAsset?: Asset disabledChainIds?: ChainId[] diff --git a/packages/swap-widget/src/utils/redirect.ts b/packages/swap-widget/src/utils/redirect.ts index 1594b4d91a9..9f2cea6de5b 100644 --- a/packages/swap-widget/src/utils/redirect.ts +++ b/packages/swap-widget/src/utils/redirect.ts @@ -1,24 +1,19 @@ import type { Asset, AssetId } from '../types' import { isEvmChainId } from '../types' -const SHAPESHIFT_APP_URL = 'https://app.shapeshift.com' +const DEFAULT_APP_URL = 'https://app.shapeshift.com' export type RedirectParams = { sellAssetId: AssetId buyAssetId: AssetId sellAmountBaseUnit?: string - affiliateAddress?: string + partnerCode?: string + appUrl?: string } -/** - * Build a ShapeShift trade URL using the web app's hash-based route format: - * https://app.shapeshift.com/#/trade/{buyChainId}/{buyAssetSubId}/{sellChainId}/{sellAssetSubId}/{sellAmountBaseUnit}?affiliate=0x... - * - * Asset IDs are CAIP-19 format like "eip155:1/slip44:60" where the first segment is the chainId - * and the second segment is the asset sub-identifier. - */ export const buildShapeShiftTradeUrl = (params: RedirectParams): string => { - const { sellAssetId, buyAssetId, sellAmountBaseUnit, affiliateAddress } = params + const { sellAssetId, buyAssetId, sellAmountBaseUnit, partnerCode, appUrl } = params + const baseUrl = appUrl || DEFAULT_APP_URL // CAIP-19 assetIds have format "chainId/assetSubId" e.g. "eip155:1/slip44:60" // The first "/" separates chainId from assetSubId @@ -31,9 +26,9 @@ export const buildShapeShiftTradeUrl = (params: RedirectParams): string => { const sellAssetSubId = sellAssetId.substring(sellSlashIdx + 1) const amount = sellAmountBaseUnit || '0' - const affiliate = affiliateAddress ? `?affiliate=${encodeURIComponent(affiliateAddress)}` : '' + const partner = partnerCode ? `?partner=${encodeURIComponent(partnerCode)}` : '' - return `${SHAPESHIFT_APP_URL}/#/trade/${buyChainId}/${buyAssetSubId}/${sellChainId}/${sellAssetSubId}/${amount}${affiliate}` + return `${baseUrl}/#/trade/${buyChainId}/${buyAssetSubId}/${sellChainId}/${sellAssetSubId}/${amount}${partner}` } export const redirectToShapeShift = (params: RedirectParams): void => { diff --git a/packages/swap-widget/vite.config.ts b/packages/swap-widget/vite.config.ts index ce8ea3dc073..0899aac2d87 100644 --- a/packages/swap-widget/vite.config.ts +++ b/packages/swap-widget/vite.config.ts @@ -64,7 +64,6 @@ export default defineConfig({ 'process.env': {}, }, optimizeDeps: { - exclude: ['@shapeshiftoss/caip', '@shapeshiftoss/utils'], esbuildOptions: { define: { global: 'globalThis', diff --git a/packages/utils/src/treasury.ts b/packages/utils/src/treasury.ts index 445c60e20da..3b933ff19ed 100644 --- a/packages/utils/src/treasury.ts +++ b/packages/utils/src/treasury.ts @@ -38,7 +38,7 @@ export const DAO_TREASURY_ARBITRUM = '0x38276553F8fbf2A027D901F8be45f00373d8Dd48 export const DAO_TREASURY_BASE = '0x9c9aA90363630d4ab1D9dbF416cc3BBC8d3Ed502' export const DAO_TREASURY_SOLANA = 'Bh7R3MeJ98D7Ersxh7TgVQVQUSmDMqwrFVHH9DLfb4u3' export const DAO_TREASURY_BITCOIN = 'bc1qr2whxtd0gvqnctcxlynwejp6fvntv0mtxkv0dlv02vyale8h69ysm6l32n' -export const DAO_TREASURY_NEAR = 'f471d0b0f90593d85125f38aaf5458748d6f23fd5b437b844d293d8e87557070' +export const DAO_TREASURY_NEAR = 'shapeshifttokenomics.sputnik-dao.near' export const DAO_TREASURY_STARKNET = '0x052a1132ea4db81Bde863AFb18a4d4CE5de9d3efdfda6b3DaA6484e26425D467' export const DAO_TREASURY_TON = 'UQBGXUskbTDkLXJO_Q6cQFVbbkgvXKplcIhijiO5oDcB5qkI' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c9f59232e24..082a07b85af 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -303,9 +303,6 @@ importers: ai: specifier: ^6.0.39 version: 6.0.105(zod@3.25.76) - alchemy-sdk: - specifier: ^3.4.1 - version: 3.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6) axios: specifier: ^1.13.5 version: 1.13.6(debug@4.4.3) @@ -766,6 +763,9 @@ importers: pify: specifier: ^5.0.0 version: 5.0.0 + portless: + specifier: ^0.6.0 + version: 0.6.0 prettier: specifier: 3.0.3 version: 3.0.3 @@ -811,12 +811,27 @@ importers: packages/affiliate-dashboard: dependencies: + '@reown/appkit': + specifier: ^1.8.17 + version: 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-adapter-wagmi': + specifier: ^1.8.17 + version: 1.8.18(79d3fbc12edded5075001b4ee2ff0e4d) + '@tanstack/react-query': + specifier: 5.69.0 + version: 5.69.0(react@18.3.1) react: specifier: ^18.2.0 version: 18.3.1 react-dom: specifier: 18.2.0 version: 18.2.0(patch_hash=472f33b26781cbf66543b4c1cdf5be1c2ea4cd7232403bb255cd75e280bf3158)(react@18.3.1) + viem: + specifier: ^2.40.0 + version: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + wagmi: + specifier: ^2.19.5 + version: 2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) devDependencies: '@types/react': specifier: 19.1.2 @@ -1999,14 +2014,14 @@ importers: packages/swap-widget: dependencies: '@shapeshiftoss/caip': - specifier: ^8.0.0 - version: 8.16.8 + specifier: workspace:^ + version: link:../caip '@shapeshiftoss/types': - specifier: ^8.0.0 - version: 8.6.7(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: workspace:^ + version: link:../types '@shapeshiftoss/utils': - specifier: ^1.0.0 - version: 1.0.6(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: workspace:^ + version: link:../utils '@xstate/react': specifier: 5.0.5 version: 5.0.5(@types/react@19.1.2)(react@19.2.4)(xstate@5.28.0) @@ -4209,9 +4224,6 @@ packages: '@ethersproject/units@5.7.0': resolution: {integrity: sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==} - '@ethersproject/units@5.8.0': - resolution: {integrity: sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==} - '@ethersproject/wallet@5.7.0': resolution: {integrity: sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==} @@ -9235,9 +9247,6 @@ packages: ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - alchemy-sdk@3.6.5: - resolution: {integrity: sha512-vikvJvExqPoifnOtnIPoANwS2C46Nv44XsEWJz8kd5hrnZrS320GmhKWGyKSgupd8cvudAWv1+76iSr0pjy8DA==} - algo-msgpack-with-bigint@2.1.1: resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} engines: {node: '>= 10'} @@ -10572,10 +10581,6 @@ packages: d3-voronoi@1.1.4: resolution: {integrity: sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==} - d@1.0.2: - resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} - engines: {node: '>=0.12'} - damerau-levenshtein@1.0.8: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} @@ -11108,26 +11113,15 @@ packages: es-toolkit@1.44.0: resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} - es5-ext@0.10.64: - resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} - engines: {node: '>=0.10'} - es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - es6-iterator@2.0.3: - resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} - es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - es6-symbol@3.1.4: - resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} - engines: {node: '>=0.12'} - esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -11353,10 +11347,6 @@ packages: deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true - esniff@2.0.1: - resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} - engines: {node: '>=0.10'} - espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -11538,9 +11528,6 @@ packages: ev-emitter@2.1.2: resolution: {integrity: sha512-jQ5Ql18hdCQ4qS+RCrbLfz1n+Pags27q5TwMKvZyhp5hh2UULUYZUy1keqj6k6SYsdqIYjnmz7xyyEY0V67B8Q==} - event-emitter@0.3.5: - resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} - eventemitter2@5.0.1: resolution: {integrity: sha512-5EM1GHXycJBS6mauYAbVKT1cVs7POKWb2NXD4Vyt8dDqeZa7LaDK1/sjtL+Zb0lzTpSNil4596Dyu97hz37QLg==} @@ -11606,9 +11593,6 @@ packages: exsolve@1.0.8: resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - ext@1.7.0: - resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} - extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -13666,9 +13650,6 @@ packages: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} - next-tick@1.1.0: - resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} @@ -14229,6 +14210,12 @@ packages: resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} engines: {node: '>=12.0.0'} + portless@0.6.0: + resolution: {integrity: sha512-Jjk36bsWGTrqo+uyfKtHaXOfXq80BJ5EOdIRCWCbhYyJ04uV8dVw9/G4u31u1zQWmcE5WrZEYMGAm5XE+tDtXg==} + engines: {node: '>=20'} + os: [darwin, linux] + hasBin: true + porto@0.2.35: resolution: {integrity: sha512-gu9FfjjvvYBgQXUHWTp6n3wkTxVtEcqFotM7i3GEZeoQbvLGbssAicCz6hFZ8+xggrJWwi/RLmbwNra50SMmUQ==} hasBin: true @@ -15632,9 +15619,6 @@ packages: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} engines: {node: '>=18'} - sturdy-websocket@0.2.1: - resolution: {integrity: sha512-NnzSOEKyv4I83qbuKw9ROtJrrT6Z/Xt7I0HiP/e6H6GnpeTDvzwGIGeJ8slai+VwODSHQDooW2CAilJwT9SpRg==} - style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -16079,9 +16063,6 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} - type@2.7.3: - resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} - typecast@0.0.1: resolution: {integrity: sha512-L2f5OCLKsJdCjSyN0d5O6CkNxhiC8EQ2XlXnHpWZVNfF+mj2OTaXhAVnP0/7SY/sxO1DHZpOFMpIuGlFUZEGNA==} @@ -17017,10 +16998,6 @@ packages: websocket-stream@5.5.2: resolution: {integrity: sha512-8z49MKIHbGk3C4HtuHWDtYX8mYej1wWabjthC/RupM9ngeukU4IWoM46dgth1UOS/T4/IqgEdCDJuMe2039OQQ==} - websocket@1.0.35: - resolution: {integrity: sha512-/REy6amwPZl44DDzvRCkaI1q1bIiQB0mEFQLUrhz3z2EK91cp3n72rAjUlrTP0zV22HJIUOVHQGPxhFRjxjt+Q==} - engines: {node: '>=4.0.0'} - whatwg-fetch@2.0.4: resolution: {integrity: sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==} @@ -17265,11 +17242,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yaeti@0.0.6: - resolution: {integrity: sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==} - engines: {node: '>=0.10.32'} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -18403,6 +18375,55 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@base-org/account@2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@coinbase/cdp-sdk': 1.44.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.2.2)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@base-org/account@2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@coinbase/cdp-sdk': 1.44.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.2.2)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@base-org/account@2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@coinbase/cdp-sdk': 1.44.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10) @@ -18721,7 +18742,6 @@ snapshots: - fastestsmallesttextencoderdecoder - typescript - utf-8-validate - optional: true '@coinbase/cdp-sdk@1.44.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: @@ -18782,6 +18802,47 @@ snapshots: transitivePeerDependencies: - supports-color + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.2)(bufferutil@4.1.0)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.2.2)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.2)(bufferutil@4.1.0)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.2.2)(zod@3.25.76) + preact: 10.24.2 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.2)(bufferutil@4.1.0)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 @@ -20263,12 +20324,6 @@ snapshots: '@ethersproject/constants': 5.7.0 '@ethersproject/logger': 5.7.0 - '@ethersproject/units@5.8.0': - dependencies: - '@ethersproject/bignumber': 5.8.0 - '@ethersproject/constants': 5.8.0 - '@ethersproject/logger': 5.8.0 - '@ethersproject/wallet@5.7.0': dependencies: '@ethersproject/abstract-provider': 5.7.0 @@ -20490,6 +20545,14 @@ snapshots: - supports-color optional: true + '@gemini-wallet/core@0.3.2(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + '@metamask/rpc-errors': 7.0.2 + eventemitter3: 5.0.1 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - supports-color + '@gemini-wallet/core@0.3.2(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))': dependencies: '@metamask/rpc-errors': 7.0.2 @@ -21517,7 +21580,6 @@ snapshots: - encoding - supports-color - utf-8-validate - optional: true '@metamask/sdk@0.33.1(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: @@ -21607,7 +21669,7 @@ snapshots: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.2.1 '@noble/hashes': 1.8.0 - '@scure/base': 1.1.9 + '@scure/base': 1.2.6 '@types/debug': 4.1.12 '@types/lodash': 4.14.182 debug: 4.4.3(supports-color@8.1.1) @@ -21669,7 +21731,7 @@ snapshots: '@ethereumjs/tx': 4.2.0 '@metamask/superstruct': 3.2.1 '@noble/hashes': 1.8.0 - '@scure/base': 1.1.9 + '@scure/base': 1.2.6 '@types/debug': 4.1.12 debug: 4.4.3(supports-color@8.1.1) pony-cause: 2.1.11 @@ -23134,6 +23196,61 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-adapter-wagmi@1.8.18(79d3fbc12edded5075001b4ee2ff0e4d)': + dependencies: + '@reown/appkit': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.18 + '@reown/appkit-scaffold-ui': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-utils': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@wagmi/core': 3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + optionalDependencies: + '@wagmi/connectors': 7.2.1(58e72868877d8903efcaefe9212bca54) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@base-org/account' + - '@capacitor/preferences' + - '@coinbase/wallet-sdk' + - '@deno/kv' + - '@metamask/sdk' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@safe-global/safe-apps-provider' + - '@safe-global/safe-apps-sdk' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - '@walletconnect/ethereum-provider' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - porto + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + '@reown/appkit-adapter-wagmi@1.8.18(b2de09fc1a71c9091ac547a86f40bdf9)': dependencies: '@reown/appkit': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76) @@ -23200,6 +23317,17 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + '@reown/appkit-common@1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: big.js: 6.2.2 @@ -23291,6 +23419,41 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-controllers@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@reown/appkit-controllers@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -23326,12 +23489,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' @@ -23362,13 +23525,13 @@ snapshots: - zod optional: true - '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': + '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) - '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6) - '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) - viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23396,14 +23559,15 @@ snapshots: - uploadthing - utf-8-validate - zod + optional: true - '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) - viem: 2.43.5(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23432,13 +23596,119 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) - viem: 2.46.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.46.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) + viem: 2.46.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-pay@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + lit: 3.3.0 + valtio: 1.13.2(@types/react@19.1.2)(react@18.3.1) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23503,6 +23773,47 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-pay@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + lit: 3.3.0 + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@reown/appkit-pay@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -23624,6 +23935,46 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-pay@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + lit: 3.3.0 + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + '@reown/appkit-pay@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -23717,6 +24068,43 @@ snapshots: - valtio - zod + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -23754,6 +24142,49 @@ snapshots: - valtio - zod + '@reown/appkit-scaffold-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - valtio + - zod + optional: true + '@reown/appkit-scaffold-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -23881,6 +24312,48 @@ snapshots: - valtio - zod + '@reown/appkit-scaffold-ui@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - valtio + - zod + '@reown/appkit-scaffold-ui@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -23958,6 +24431,41 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-ui@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@reown/appkit-ui@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -23993,6 +24501,43 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@phosphor-icons/webcomponents': 2.1.5 + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + optional: true + '@reown/appkit-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@phosphor-icons/webcomponents': 2.1.5 @@ -24066,12 +24611,48 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-ui@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@phosphor-icons/webcomponents': 2.1.5 + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-ui@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@phosphor-icons/webcomponents': 2.1.5 - '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) lit: 3.3.0 qrcode: 1.5.3 transitivePeerDependencies: @@ -24176,6 +24757,44 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-utils@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@reown/appkit-utils@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(valtio@1.13.2(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -24214,6 +24833,54 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-utils@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.17-wc-circular-dependencies-fix.0 + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@wallet-standard/wallet': 1.1.0 + '@walletconnect/logger': 3.0.2 + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + '@base-org/account': 2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@reown/appkit-utils@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -24356,6 +25023,53 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-utils@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.18 + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@wallet-standard/wallet': 1.1.0 + '@walletconnect/logger': 3.0.2 + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.46.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + '@base-org/account': 2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + '@reown/appkit-utils@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -24414,6 +25128,17 @@ snapshots: - typescript - utf-8-validate + '@reown/appkit-wallet@1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.7.8 + '@walletconnect/logger': 2.1.2 + zod: 3.25.76 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + '@reown/appkit-wallet@1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -24512,6 +25237,49 @@ snapshots: - utf-8-validate - zod + '@reown/appkit@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + bs58: 6.0.0 + valtio: 1.13.2(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@reown/appkit@1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -24555,6 +25323,56 @@ snapshots: - utf-8-validate - zod + '@reown/appkit@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.17-wc-circular-dependencies-fix.0 + '@reown/appkit-scaffold-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + bs58: 6.0.0 + semver: 7.7.2 + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + '@lit/react': 1.0.8(@types/react@19.1.2) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@reown/appkit@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -24654,21 +25472,70 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit@1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.17-wc-circular-dependencies-fix.0 + '@reown/appkit-scaffold-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76) + '@reown/appkit-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + bs58: 6.0.0 + semver: 7.7.2 + valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + '@lit/react': 1.0.8(@types/react@19.1.2) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + + '@reown/appkit@1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.8.17-wc-circular-dependencies-fix.0 - '@reown/appkit-scaffold-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76) - '@reown/appkit-ui': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.8.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@19.2.4))(zod@3.25.76) - '@reown/appkit-wallet': 1.8.17-wc-circular-dependencies-fix.0(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-polyfills': 1.8.18 + '@reown/appkit-scaffold-ui': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-ui': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.8.18(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(valtio@2.1.7(@types/react@19.1.2)(react@18.3.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.8.18(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 semver: 7.7.2 - valtio: 2.1.7(@types/react@19.1.2)(react@19.2.4) - viem: 2.43.5(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 2.1.7(@types/react@19.1.2)(react@18.3.1) + viem: 2.46.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: '@lit/react': 1.0.8(@types/react@19.1.2) transitivePeerDependencies: @@ -24935,7 +25802,6 @@ snapshots: - typescript - utf-8-validate - zod - optional: true '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: @@ -24967,7 +25833,6 @@ snapshots: - typescript - utf-8-validate - zod - optional: true '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: @@ -25055,7 +25920,7 @@ snapshots: '@scure/bip32@1.7.0': dependencies: - '@noble/curves': 1.9.4 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 @@ -25563,23 +26428,6 @@ snapshots: - utf-8-validate - zod - '@shapeshiftoss/types@8.6.7(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@cowprotocol/app-data': 2.5.1(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0) - '@shapeshiftoss/caip': 8.16.8 - ethers5: ethers@5.7.2(bufferutil@4.1.0)(utf-8-validate@5.0.10) - viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - cross-fetch - - debug - - ethers - - ipfs-only-hash - - multiformats - - typescript - - utf-8-validate - - zod - '@shapeshiftoss/unchained-client@10.1.1(@ethersproject/abi@5.8.0)(@ethersproject/address@5.8.0)(@ethersproject/bignumber@5.8.0)(@ethersproject/bytes@5.8.0)(@ethersproject/contracts@5.8.0)(@ethersproject/providers@5.8.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(@shapeshiftoss/caip@8.16.8)(@shapeshiftoss/logger@1.1.3)(@shapeshiftoss/types@8.6.7(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@5.7.2(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76))(bufferutil@4.1.0)(utf-8-validate@5.0.10)': dependencies: '@shapeshiftoss/caip': 8.16.8 @@ -25647,25 +26495,6 @@ snapshots: - utf-8-validate - zod - '@shapeshiftoss/utils@1.0.6(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@shapeshiftoss/caip': 8.16.8 - '@shapeshiftoss/types': 8.6.7(bufferutil@4.1.0)(cross-fetch@4.1.0)(ethers@6.16.0(bufferutil@4.1.0)(utf-8-validate@5.0.10))(ipfs-only-hash@4.0.0)(multiformats@9.9.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@sniptt/monads': 0.5.10 - bignumber.js: 9.3.1 - dayjs: 1.11.19 - lodash-es: 4.17.23 - transitivePeerDependencies: - - bufferutil - - cross-fetch - - debug - - ethers - - ipfs-only-hash - - multiformats - - typescript - - utf-8-validate - - zod - '@sinclair/typebox@0.33.22': {} '@sindresorhus/is@4.6.0': {} @@ -25693,7 +26522,6 @@ snapshots: '@solana-program/system@0.10.0(@solana/kit@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10))': dependencies: '@solana/kit': 5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10) - optional: true '@solana-program/system@0.10.0(@solana/kit@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6))': dependencies: @@ -25732,7 +26560,6 @@ snapshots: '@solana-program/token@0.9.0(@solana/kit@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10))': dependencies: '@solana/kit': 5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@5.0.10) - optional: true '@solana-program/token@0.9.0(@solana/kit@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6))': dependencies: @@ -26372,7 +27199,6 @@ snapshots: - bufferutil - fastestsmallesttextencoderdecoder - utf-8-validate - optional: true '@solana/kit@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: @@ -26848,7 +27674,6 @@ snapshots: transitivePeerDependencies: - bufferutil - utf-8-validate - optional: true '@solana/rpc-subscriptions-channel-websocket@5.5.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: @@ -26967,7 +27792,6 @@ snapshots: - bufferutil - fastestsmallesttextencoderdecoder - utf-8-validate - optional: true '@solana/rpc-subscriptions@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: @@ -27526,7 +28350,6 @@ snapshots: - bufferutil - fastestsmallesttextencoderdecoder - utf-8-validate - optional: true '@solana/transaction-confirmation@5.5.1(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.2.2)(utf-8-validate@6.0.6)': dependencies: @@ -28323,6 +29146,11 @@ snapshots: '@tanstack/query-core@5.69.0': {} + '@tanstack/react-query@5.69.0(react@18.3.1)': + dependencies: + '@tanstack/query-core': 5.69.0 + react: 18.3.1 + '@tanstack/react-query@5.69.0(react@19.2.4)': dependencies: '@tanstack/query-core': 5.69.0 @@ -30259,6 +31087,59 @@ snapshots: '@vue/shared@3.5.30': {} + '@wagmi/connectors@6.2.0(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76)': + dependencies: + '@base-org/account': 2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.2)(bufferutil@4.1.0)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@gemini-wallet/core': 0.3.2(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@metamask/sdk': 0.33.1(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + cbw-sdk: '@coinbase/wallet-sdk@3.9.3' + porto: 0.2.35(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@tanstack/react-query' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - react-native + - supports-color + - uploadthing + - use-sync-external-store + - utf-8-validate + - wagmi + - zod + '@wagmi/connectors@6.2.0(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76)': dependencies: '@base-org/account': 2.4.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@6.0.6)(zod@3.25.76) @@ -30326,6 +31207,20 @@ snapshots: porto: 0.2.35(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(@wagmi/core@3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.40.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.40.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@3.3.2) typescript: 5.2.2 + '@wagmi/connectors@7.2.1(58e72868877d8903efcaefe9212bca54)': + dependencies: + '@wagmi/core': 3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.2)(bufferutil@4.1.0)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@metamask/sdk': 0.33.1(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/ethereum-provider': 2.23.7(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.35(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)) + typescript: 5.2.2 + optional: true + '@wagmi/connectors@7.2.1(b1448b9cab92213d3d23eae2210a320b)': dependencies: '@wagmi/core': 3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.40.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) @@ -30340,6 +31235,21 @@ snapshots: typescript: 5.2.2 optional: true + '@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.2.2) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.0(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + optionalDependencies: + '@tanstack/query-core': 5.69.0 + typescript: 5.2.2 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 @@ -30371,6 +31281,22 @@ snapshots: - react - use-sync-external-store + '@wagmi/core@3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + eventemitter3: 5.0.1 + mipd: 0.0.7(typescript@5.2.2) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.0(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + optionalDependencies: + '@tanstack/query-core': 5.69.0 + ox: 0.12.4(typescript@5.2.2)(zod@3.25.76) + typescript: 5.2.2 + transitivePeerDependencies: + - '@types/react' + - immer + - react + - use-sync-external-store + '@wagmi/core@3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.40.3(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 @@ -30516,6 +31442,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/core@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/core@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -30560,6 +31530,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/core@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/core@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -30736,21 +31750,65 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.23.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': + '@walletconnect/core@2.23.6(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.6 + '@walletconnect/utils': 2.23.6(typescript@5.2.2)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.44.0 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 3.0.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.23.6 - '@walletconnect/utils': 2.23.6(typescript@5.2.2)(zod@3.25.76) + '@walletconnect/types': 2.23.7 + '@walletconnect/utils': 2.23.7(typescript@5.2.2)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.44.0 events: 3.3.0 @@ -30779,14 +31837,15 @@ snapshots: - uploadthing - utf-8-validate - zod + optional: true - '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 3.0.2 '@walletconnect/relay-api': 1.0.11 @@ -30823,15 +31882,14 @@ snapshots: - uploadthing - utf-8-validate - zod - optional: true - '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': + '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@6.0.6) + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 3.0.2 '@walletconnect/relay-api': 1.0.11 @@ -30839,7 +31897,7 @@ snapshots: '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.23.7 - '@walletconnect/utils': 2.23.7(typescript@5.2.2)(zod@3.25.76) + '@walletconnect/utils': 2.23.7(typescript@5.8.2)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.44.0 events: 3.3.0 @@ -30869,25 +31927,38 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.23.7(bufferutil@4.1.0)(typescript@5.8.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/crypto@1.1.0': dependencies: - '@walletconnect/heartbeat': 1.2.2 + '@noble/ciphers': 1.2.0 + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + '@walletconnect/randombytes': 1.1.0 + tslib: 1.14.1 + + '@walletconnect/encoding@1.0.2': + dependencies: + is-typedarray: 1.0.0 + tslib: 1.14.1 + typedarray-to-buffer: 3.1.5 + + '@walletconnect/environment@1.0.1': + dependencies: + tslib: 1.14.1 + + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.1.0)(utf-8-validate@5.0.10) '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 3.0.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.23.7 - '@walletconnect/utils': 2.23.7(typescript@5.8.2)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.44.0 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 - uint8arrays: 3.1.1 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -30900,6 +31971,7 @@ snapshots: - '@netlify/blobs' - '@planetscale/database' - '@react-native-async-storage/async-storage' + - '@types/react' - '@upstash/redis' - '@vercel/blob' - '@vercel/functions' @@ -30907,31 +31979,14 @@ snapshots: - aws4fetch - bufferutil - db0 + - encoding - ioredis + - react - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/crypto@1.1.0': - dependencies: - '@noble/ciphers': 1.2.0 - '@noble/hashes': 1.7.0 - '@walletconnect/encoding': 1.0.2 - '@walletconnect/environment': 1.0.1 - '@walletconnect/randombytes': 1.1.0 - tslib: 1.14.1 - - '@walletconnect/encoding@1.0.2': - dependencies: - is-typedarray: 1.0.0 - tslib: 1.14.1 - typedarray-to-buffer: 3.1.5 - - '@walletconnect/environment@1.0.1': - dependencies: - tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@reown/appkit': 1.7.8(@types/react@19.1.2)(bufferutil@4.1.0)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -30973,6 +32028,53 @@ snapshots: - utf-8-validate - zod + '@walletconnect/ethereum-provider@2.23.7(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 + '@walletconnect/sign-client': 2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.23.7 + '@walletconnect/universal-provider': 2.23.7(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.23.7(typescript@5.2.2)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react + - typescript + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + optional: true + '@walletconnect/ethereum-provider@2.23.7(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit': 1.8.17-wc-circular-dependencies-fix.0(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(utf-8-validate@5.0.10)(zod@3.25.76) @@ -31379,6 +32481,42 @@ snapshots: - utf-8-validate - zod + '@walletconnect/sign-client@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/sign-client@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/core': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -31415,6 +32553,42 @@ snapshots: - utf-8-validate - zod + '@walletconnect/sign-client@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/sign-client@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/core': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76) @@ -32038,6 +33212,46 @@ snapshots: - utf-8-validate - zod + '@walletconnect/universal-provider@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/universal-provider@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 @@ -32078,6 +33292,46 @@ snapshots: - utf-8-validate - zod + '@walletconnect/universal-provider@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/universal-provider@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 @@ -32458,6 +33712,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/utils@2.21.0(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 @@ -32502,6 +33800,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/utils@2.21.1(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 @@ -32791,7 +34133,7 @@ snapshots: '@walletconnect/window-metadata@1.0.0': dependencies: - '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata@1.0.1': dependencies: @@ -33115,30 +34457,6 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - alchemy-sdk@3.6.5(bufferutil@4.1.0)(utf-8-validate@6.0.6): - dependencies: - '@ethersproject/abi': 5.8.0 - '@ethersproject/abstract-provider': 5.8.0 - '@ethersproject/bignumber': 5.8.0 - '@ethersproject/bytes': 5.8.0 - '@ethersproject/contracts': 5.8.0 - '@ethersproject/hash': 5.8.0 - '@ethersproject/networks': 5.8.0 - '@ethersproject/providers': 5.8.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - '@ethersproject/units': 5.8.0 - '@ethersproject/wallet': 5.8.0 - '@ethersproject/web': 5.8.0 - '@solana/web3.js': 1.98.0(bufferutil@4.1.0)(utf-8-validate@6.0.6) - axios: 1.13.6(debug@4.4.3) - sturdy-websocket: 0.2.1 - websocket: 1.0.35 - transitivePeerDependencies: - - bufferutil - - debug - - encoding - - supports-color - - utf-8-validate - algo-msgpack-with-bigint@2.1.1: {} algosdk@1.24.1: @@ -34743,11 +36061,6 @@ snapshots: d3-voronoi@1.1.4: {} - d@1.0.2: - dependencies: - es5-ext: 0.10.64 - type: 2.7.3 - damerau-levenshtein@1.0.8: {} dargs@7.0.0: {} @@ -34919,6 +36232,10 @@ snapshots: dequal@2.0.3: {} + derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1)): + dependencies: + valtio: 1.13.2(@types/react@19.1.2)(react@18.3.1) + derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.1.2)(react@19.2.4)): dependencies: valtio: 1.13.2(@types/react@19.1.2)(react@19.2.4) @@ -35364,33 +36681,15 @@ snapshots: es-toolkit@1.44.0: {} - es5-ext@0.10.64: - dependencies: - es6-iterator: 2.0.3 - es6-symbol: 3.1.4 - esniff: 2.0.1 - next-tick: 1.1.0 - es6-error@4.1.1: optional: true - es6-iterator@2.0.3: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - es6-symbol: 3.1.4 - es6-promise@4.2.8: {} es6-promisify@5.0.0: dependencies: es6-promise: 4.2.8 - es6-symbol@3.1.4: - dependencies: - d: 1.0.2 - ext: 1.7.0 - esbuild@0.21.5: optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 @@ -35779,13 +37078,6 @@ snapshots: transitivePeerDependencies: - supports-color - esniff@2.0.1: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - event-emitter: 0.3.5 - type: 2.7.3 - espree@10.4.0: dependencies: acorn: 8.16.0 @@ -36206,11 +37498,6 @@ snapshots: ev-emitter@2.1.2: {} - event-emitter@0.3.5: - dependencies: - d: 1.0.2 - es5-ext: 0.10.64 - eventemitter2@5.0.1: {} eventemitter2@6.4.9: {} @@ -36298,10 +37585,6 @@ snapshots: exsolve@1.0.8: {} - ext@1.7.0: - dependencies: - type: 2.7.3 - extend@3.0.2: {} extension-port-stream@2.1.1: @@ -36311,7 +37594,7 @@ snapshots: extension-port-stream@3.0.0: dependencies: readable-stream: 3.6.0 - webextension-polyfill: 0.10.0 + webextension-polyfill: 0.12.0 external-editor@3.1.0: dependencies: @@ -38945,8 +40228,6 @@ snapshots: netmask@2.0.2: {} - next-tick@1.1.0: {} - nice-try@1.0.5: {} no-case@3.0.4: @@ -39333,7 +40614,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.2.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.2.2)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.2.2 @@ -39422,7 +40703,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.2.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.2.2)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.2.2 @@ -39699,6 +40980,51 @@ snapshots: pony-cause@2.1.11: {} + portless@0.6.0: + dependencies: + chalk: 5.3.0 + + porto@0.2.35(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)): + dependencies: + '@wagmi/core': 2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + hono: 4.12.3 + idb-keyval: 6.2.2 + mipd: 0.0.7(typescript@5.2.2) + ox: 0.9.17(typescript@5.2.2)(zod@4.3.6) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zod: 4.3.6 + zustand: 5.0.11(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) + optionalDependencies: + '@tanstack/react-query': 5.69.0(react@18.3.1) + react: 18.3.1 + typescript: 5.2.2 + wagmi: 2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + transitivePeerDependencies: + - '@types/react' + - immer + - use-sync-external-store + + porto@0.2.35(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)): + dependencies: + '@wagmi/core': 3.4.0(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(ox@0.12.4(typescript@5.2.2)(zod@3.25.76))(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.6.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + hono: 4.12.3 + idb-keyval: 6.2.2 + mipd: 0.0.7(typescript@5.2.2) + ox: 0.9.17(typescript@5.2.2)(zod@4.3.6) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zod: 4.3.6 + zustand: 5.0.11(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) + optionalDependencies: + '@tanstack/react-query': 5.69.0(react@18.3.1) + react: 18.3.1 + typescript: 5.2.2 + wagmi: 2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + transitivePeerDependencies: + - '@types/react' + - immer + - use-sync-external-store + optional: true + porto@0.2.35(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)))(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))(zod@3.25.76)): dependencies: '@wagmi/core': 2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@19.2.4))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76)) @@ -41428,8 +42754,6 @@ snapshots: dependencies: '@tokenizer/token': 0.3.0 - sturdy-websocket@0.2.1: {} - style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -41910,8 +43234,6 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 - type@2.7.3: {} - typecast@0.0.1: {} typed-array-buffer@1.0.3: @@ -42200,10 +43522,18 @@ snapshots: optionalDependencies: '@types/react': 19.1.2 + use-sync-external-store@1.2.0(react@18.3.1): + dependencies: + react: 18.3.1 + use-sync-external-store@1.2.0(react@19.2.4): dependencies: react: 19.2.4 + use-sync-external-store@1.4.0(react@18.3.1): + dependencies: + react: 18.3.1 + use-sync-external-store@1.4.0(react@19.2.4): dependencies: react: 19.2.4 @@ -42304,6 +43634,15 @@ snapshots: '@types/react': 19.1.2 react: 19.2.4 + valtio@1.13.2(@types/react@19.1.2)(react@18.3.1): + dependencies: + derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.2)(react@18.3.1)) + proxy-compare: 2.6.0 + use-sync-external-store: 1.2.0(react@18.3.1) + optionalDependencies: + '@types/react': 19.1.2 + react: 18.3.1 + valtio@1.13.2(@types/react@19.1.2)(react@19.2.4): dependencies: derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.2)(react@19.2.4)) @@ -42313,6 +43652,13 @@ snapshots: '@types/react': 19.1.2 react: 19.2.4 + valtio@2.1.7(@types/react@19.1.2)(react@18.3.1): + dependencies: + proxy-compare: 3.0.1 + optionalDependencies: + '@types/react': 19.1.2 + react: 18.3.1 + valtio@2.1.7(@types/react@19.1.2)(react@19.2.4): dependencies: proxy-compare: 3.0.1 @@ -42782,6 +44128,51 @@ snapshots: dependencies: xml-name-validator: 5.0.0 + wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + dependencies: + '@tanstack/react-query': 5.69.0(react@18.3.1) + '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@18.3.1))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.69.0)(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(typescript@5.2.2)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + react: 18.3.1 + use-sync-external-store: 1.4.0(react@18.3.1) + viem: 2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + typescript: 5.2.2 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@tanstack/query-core' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - debug + - encoding + - expo-auth-session + - expo-crypto + - expo-web-browser + - fastestsmallesttextencoderdecoder + - immer + - ioredis + - react-native + - supports-color + - uploadthing + - utf-8-validate + - zod + wagmi@2.19.5(@tanstack/query-core@5.69.0)(@tanstack/react-query@5.69.0(react@19.2.4))(@types/react@19.1.2)(bufferutil@4.1.0)(fastestsmallesttextencoderdecoder@1.0.22)(immer@9.0.21)(react@19.2.4)(typescript@5.2.2)(utf-8-validate@6.0.6)(viem@2.43.5(bufferutil@4.1.0)(typescript@5.2.2)(utf-8-validate@6.0.6)(zod@3.25.76))(zod@3.25.76): dependencies: '@tanstack/react-query': 5.69.0(react@19.2.4) @@ -43215,17 +44606,6 @@ snapshots: - bufferutil - utf-8-validate - websocket@1.0.35: - dependencies: - bufferutil: 4.1.0 - debug: 2.6.9 - es5-ext: 0.10.64 - typedarray-to-buffer: 3.1.5 - utf-8-validate: 5.0.10 - yaeti: 0.0.6 - transitivePeerDependencies: - - supports-color - whatwg-fetch@2.0.4: {} whatwg-fetch@3.6.20: {} @@ -43509,8 +44889,6 @@ snapshots: y18n@5.0.8: {} - yaeti@0.0.6: {} - yallist@3.1.1: {} yallist@4.0.0: {} @@ -43609,6 +44987,20 @@ snapshots: zod@4.3.6: {} + zustand@5.0.0(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.4.0(react@18.3.1) + + zustand@5.0.0(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) + zustand@5.0.0(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(use-sync-external-store@1.4.0(react@19.2.4)): optionalDependencies: '@types/react': 19.1.2 @@ -43616,6 +45008,21 @@ snapshots: react: 19.2.4 use-sync-external-store: 1.4.0(react@19.2.4) + zustand@5.0.11(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.4.0(react@18.3.1) + + zustand@5.0.11(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) + optional: true + zustand@5.0.11(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(use-sync-external-store@1.4.0(react@19.2.4)): optionalDependencies: '@types/react': 19.1.2 @@ -43623,6 +45030,21 @@ snapshots: react: 19.2.4 use-sync-external-store: 1.4.0(react@19.2.4) + zustand@5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.4.0(react@18.3.1) + + zustand@5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 19.1.2 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) + optional: true + zustand@5.0.3(@types/react@19.1.2)(immer@9.0.21)(react@19.2.4)(use-sync-external-store@1.4.0(react@19.2.4)): optionalDependencies: '@types/react': 19.1.2 diff --git a/scripts/release.ts b/scripts/release.ts index 0d643891fd0..716cfc96847 100644 --- a/scripts/release.ts +++ b/scripts/release.ts @@ -69,7 +69,7 @@ export const deriveReleaseState = ({ releaseSha, mainSha, developSha, - privateSha, + privateContentMatchesMain, latestTagSha, openPrereleasePr, openReleasePr, @@ -77,7 +77,7 @@ export const deriveReleaseState = ({ releaseSha: string mainSha: string developSha: string - privateSha: string + privateContentMatchesMain: boolean latestTagSha: string openPrereleasePr: GitHubPr | undefined openReleasePr: GitHubPr | undefined @@ -88,7 +88,7 @@ export const deriveReleaseState = ({ if (mainSha !== latestTagSha) return 'merged_untagged' - if (privateSha !== mainSha) return 'tagged_private_stale' + if (!privateContentMatchesMain) return 'tagged_private_stale' if (releaseSha === mainSha && developSha === mainSha) return 'done' @@ -97,18 +97,18 @@ export const deriveReleaseState = ({ export const deriveHotfixState = ({ mainSha, - privateSha, + privateContentMatchesMain, latestTagSha, openHotfixPr, }: { mainSha: string - privateSha: string + privateContentMatchesMain: boolean latestTagSha: string openHotfixPr: GitHubPr | undefined }): HotfixState => { if (openHotfixPr) return 'hotfix_pr_open' if (mainSha !== latestTagSha) return 'merged_untagged' - if (privateSha !== mainSha) return 'tagged_private_stale' + if (!privateContentMatchesMain) return 'tagged_private_stale' return 'idle' } @@ -402,7 +402,7 @@ const createPr = async ({ head: string title: string body: string -}): Promise => { +}): Promise => { const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'shapeshift-release-body-')) const bodyPath = path.join(tmpDir, 'body.md') @@ -424,6 +424,9 @@ const createPr = async ({ ]) const stdout = typeof result === 'string' ? result : (result as { stdout: string }).stdout return stdout.trim() + } catch (err) { + if (String(err).includes('No commits between')) return null + throw err } finally { try { fs.rmSync(tmpDir, { recursive: true, force: true }) @@ -484,24 +487,26 @@ const doRegularRelease = async () => { const nextVersion = await getNextVersion('minor') const latestTag = await getLatestSemverTag() - const [releaseSha, mainSha, developSha, privateSha, latestTagSha] = await Promise.all([ + const [releaseSha, mainSha, developSha, latestTagSha] = await Promise.all([ getSha('origin/release'), getSha('origin/main'), getSha('origin/develop'), - getSha('origin/private'), getTagSha(latestTag), ]) - const [openPrereleasePr, openReleasePr] = await Promise.all([ + const [openPrereleasePr, openReleasePr, privateContentMatchesMain] = await Promise.all([ findOpenPr('develop', 'release'), findOpenPr('release', 'main'), + git() + .diff(['origin/main', 'origin/private']) + .then(diff => !diff), ]) const state = deriveReleaseState({ releaseSha, mainSha, developSha, - privateSha, + privateContentMatchesMain, latestTagSha, openPrereleasePr, openReleasePr, @@ -515,7 +520,12 @@ const doRegularRelease = async () => { // Two sub-states within idle: // 1. Release branch ahead of main (prerelease merged) -> create release -> main PR // 2. Release branch matches main (fresh start) -> create develop -> release PR - const prereleaseMerged = releaseSha !== mainSha + // Use commit-ahead check (not SHA) to correctly detect if release is ahead of main. + // SHA equality breaks with squash merges; content diff alone breaks when release is *behind* main. + const releaseMatchesMain = !(await git().diff(['origin/main', 'origin/release'])) + const releaseHasCommitsNotInMain = + (await getCommitMessages('origin/main..origin/release')).length > 0 + const prereleaseMerged = releaseHasCommitsNotInMain && !releaseMatchesMain if (prereleaseMerged) { const messages = await getCommitMessages(`${latestTag}..origin/release`) @@ -546,6 +556,8 @@ const doRegularRelease = async () => { title: `chore: release ${nextVersion}`, body: releaseBody, }) + if (!releasePrUrl) + exit(chalk.red('Failed to create release PR - no commits between branches.')) console.log(chalk.green(`Release PR created: ${releasePrUrl}`)) console.log( chalk.green( @@ -569,6 +581,8 @@ const doRegularRelease = async () => { title: `chore: prerelease ${nextVersion}`, body: `## Prerelease ${nextVersion}\n\n${commitList}`, }) + if (!prereleasePrUrl) + exit(chalk.red('Failed to create prerelease PR - no commits between branches.')) console.log(chalk.green(`Prerelease PR created: ${prereleasePrUrl}`)) console.log( chalk.green( @@ -610,20 +624,33 @@ const doRegularRelease = async () => { await git().push(['origin', '--tags']) console.log(chalk.green(`Tagged ${nextVersion}.`)) - console.log(chalk.green('Creating PR to sync private to main...')) - const privatePrUrl = await createPr({ - base: 'private', - head: 'main', - title: `chore: sync private to ${nextVersion}`, - body: `Sync private branch to main after release ${nextVersion}.`, - }) - console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) - console.log(chalk.green('Merge it on GitHub to complete the release.')) + const existingPrivatePrAfterTag = await findOpenPr('main', 'private') + if (existingPrivatePrAfterTag) { + console.log( + chalk.yellow( + `Private sync PR already open: #${existingPrivatePrAfterTag.number}. Merge it on GitHub.`, + ), + ) + } else { + console.log(chalk.green('Creating PR to sync private to main...')) + const privatePrUrl = await createPr({ + base: 'private', + head: 'main', + title: `chore: sync private to ${nextVersion}`, + body: `Sync private branch to main after release ${nextVersion}.`, + }) + if (privatePrUrl) { + console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + console.log(chalk.green('Merge it on GitHub to complete the release.')) + } else { + console.log(chalk.green('private already in sync with main - nothing to do.')) + } + } break } case 'tagged_private_stale': { - console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`)) + console.log(chalk.yellow(`${latestTag} is tagged but private is behind main.`)) const existingPrivatePr = await findOpenPr('main', 'private') if (existingPrivatePr) { @@ -637,10 +664,48 @@ const doRegularRelease = async () => { const privatePrUrl = await createPr({ base: 'private', head: 'main', - title: `chore: sync private to ${nextVersion}`, - body: `Sync private branch to main after release ${nextVersion}.`, + title: `chore: sync private to ${latestTag}`, + body: `Sync private branch to main after release ${latestTag}.`, }) - console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + if (privatePrUrl) { + console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + } else { + console.log(chalk.green('private already in sync with main - nothing to do.')) + } + } + + const existingBackmerge = await findOpenPr('main', 'develop') + if (existingBackmerge) { + console.log( + chalk.yellow( + `Backmerge PR already open: #${existingBackmerge.number}. Enabling auto-merge...`, + ), + ) + await pify(exec)(`gh pr merge --auto --merge ${existingBackmerge.number}`) + console.log( + chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'), + ) + } else { + const mainDevelopCommits = await getCommitMessages('origin/develop..origin/main') + if (mainDevelopCommits.length > 0) { + console.log(chalk.green('Creating backmerge PR (main -> develop)...')) + const backmergeUrl = await createPr({ + base: 'develop', + head: 'main', + title: `chore: backmerge ${nextVersion} into develop`, + body: `Backmerge main into develop after release ${nextVersion}.`, + }) + if (backmergeUrl) { + console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`)) + console.log(chalk.green('Setting auto-merge with merge commit strategy...')) + await pify(exec)(`gh pr merge --auto --merge ${backmergeUrl}`) + console.log( + chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'), + ) + } else { + console.log(chalk.green('develop already in sync with main - nothing to do.')) + } + } } break } @@ -663,18 +728,19 @@ const doHotfixRelease = async () => { const nextVersion = await getNextVersion('patch') const latestTag = await getLatestSemverTag() - const [mainSha, privateSha, latestTagSha] = await Promise.all([ - getSha('origin/main'), - getSha('origin/private'), - getTagSha(latestTag), - ]) + const [mainSha, latestTagSha] = await Promise.all([getSha('origin/main'), getTagSha(latestTag)]) const hotfixBranch = `hotfix/${nextVersion}` - const openHotfixPr = await findOpenPr(hotfixBranch, 'main') + const [openHotfixPr, privateContentMatchesMain] = await Promise.all([ + findOpenPr(hotfixBranch, 'main'), + git() + .diff(['origin/main', 'origin/private']) + .then(diff => !diff), + ]) const state = deriveHotfixState({ mainSha, - privateSha, + privateContentMatchesMain, latestTagSha, openHotfixPr, }) @@ -740,6 +806,7 @@ const doHotfixRelease = async () => { body: `## Hotfix ${nextVersion}\n\n${commitList}`, }) + if (!prUrl) exit(chalk.red('Failed to create hotfix PR - no commits between branches.')) console.log(chalk.green(`Hotfix PR created: ${prUrl}`)) console.log(chalk.green('Merge it on GitHub, then run this script again to finalize.')) break @@ -770,7 +837,11 @@ const doHotfixRelease = async () => { title: `chore: sync private to ${nextVersion}`, body: `Sync private branch to main after hotfix ${nextVersion}.`, }) - console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + if (privatePrUrl) { + console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + } else { + console.log(chalk.green('private already in sync with main - nothing to do.')) + } console.log(chalk.green('Creating backmerge PR (main -> develop)...')) const backmergeUrl = await createPr({ @@ -779,13 +850,17 @@ const doHotfixRelease = async () => { title: `chore: backmerge ${nextVersion} into develop`, body: `Backmerge main into develop after hotfix ${nextVersion} to sync cherry-picked commits.`, }) - console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`)) + if (backmergeUrl) { + console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`)) + } else { + console.log(chalk.green('develop already in sync with main - nothing to do.')) + } console.log(chalk.green('Merge both PRs on GitHub to complete the hotfix.')) break } case 'tagged_private_stale': { - console.log(chalk.yellow(`${nextVersion} is tagged but private is behind main.`)) + console.log(chalk.yellow(`${latestTag} is tagged but private is behind main.`)) const existingPrivatePr = await findOpenPr('main', 'private') if (existingPrivatePr) { @@ -799,14 +874,28 @@ const doHotfixRelease = async () => { const privatePrUrl = await createPr({ base: 'private', head: 'main', - title: `chore: sync private to ${nextVersion}`, - body: `Sync private branch to main after hotfix ${nextVersion}.`, + title: `chore: sync private to ${latestTag}`, + body: `Sync private branch to main after hotfix ${latestTag}.`, }) - console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + if (privatePrUrl) { + console.log(chalk.green(`Private sync PR created: ${privatePrUrl}`)) + } else { + console.log(chalk.green('private already in sync with main - nothing to do.')) + } } const existingBackmerge = await findOpenPr('main', 'develop') - if (!existingBackmerge) { + if (existingBackmerge) { + console.log( + chalk.yellow( + `Backmerge PR already open: #${existingBackmerge.number}. Enabling auto-merge...`, + ), + ) + await pify(exec)(`gh pr merge --auto --merge ${existingBackmerge.number}`) + console.log( + chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'), + ) + } else { const mainDevelopDiff = await getCommitMessages('origin/develop..origin/main') if (mainDevelopDiff.length > 0) { console.log(chalk.green('Creating backmerge PR (main -> develop)...')) @@ -816,7 +905,16 @@ const doHotfixRelease = async () => { title: `chore: backmerge ${nextVersion} into develop`, body: `Backmerge main into develop after hotfix ${nextVersion}.`, }) - console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`)) + if (backmergeUrl) { + console.log(chalk.green(`Backmerge PR created: ${backmergeUrl}`)) + console.log(chalk.green('Setting auto-merge with merge commit strategy...')) + await pify(exec)(`gh pr merge --auto --merge ${backmergeUrl}`) + console.log( + chalk.green('Auto-merge set. Backmerge will merge automatically when CI passes.'), + ) + } else { + console.log(chalk.green('develop already in sync with main - nothing to do.')) + } } } break diff --git a/src/assets/translations/en/main.json b/src/assets/translations/en/main.json index 3b4d7a3618d..4aab16c207f 100644 --- a/src/assets/translations/en/main.json +++ b/src/assets/translations/en/main.json @@ -2219,6 +2219,10 @@ "txid": "TX ID", "status": "Status", "minerFee": "Miner Fee", + "orderRoute": "Order Route", + "transactionType": "Transaction Type", + "fee": "Fee", + "approvalAmount": "Approval Amount", "date": "Date", "sentTo": "Sent to %{address}", "receivedFrom": "Received from %{address}", diff --git a/src/components/Layout/Header/GlobalSearch/AssetSearchResults.tsx b/src/components/Layout/Header/GlobalSearch/AssetSearchResults.tsx index e9c273f494e..605f35e69e7 100644 --- a/src/components/Layout/Header/GlobalSearch/AssetSearchResults.tsx +++ b/src/components/Layout/Header/GlobalSearch/AssetSearchResults.tsx @@ -1,4 +1,4 @@ -import { List } from '@chakra-ui/react' +import { Flex, List, Spinner } from '@chakra-ui/react' import type { Asset } from '@shapeshiftoss/types' import { memo, useMemo } from 'react' @@ -9,17 +9,25 @@ import { SearchEmpty } from '@/components/StakingVaults/SearchEmpty' export type AssetSearchResultsProps = { results: Asset[] searchQuery: string - isSearching: boolean + isLoading: boolean onClickResult: (item: Asset) => void } export const AssetSearchResults = memo( - ({ results, searchQuery, isSearching, onClickResult }: AssetSearchResultsProps) => { + ({ results, searchQuery, isLoading, onClickResult }: AssetSearchResultsProps) => { const noResults = useMemo(() => { return !results.length }, [results.length]) - if (isSearching && noResults) { + if (isLoading && noResults) { + return ( + + + + ) + } + + if (!isLoading && noResults && searchQuery) { return } diff --git a/src/components/Layout/Header/GlobalSearch/GlobalSearchModal.tsx b/src/components/Layout/Header/GlobalSearch/GlobalSearchModal.tsx index 148eeed7369..a7279f4b03e 100644 --- a/src/components/Layout/Header/GlobalSearch/GlobalSearchModal.tsx +++ b/src/components/Layout/Header/GlobalSearch/GlobalSearchModal.tsx @@ -9,9 +9,8 @@ import { useUpdateEffect, } from '@chakra-ui/react' import { captureException, setContext } from '@sentry/react' -import { solanaChainId, toAssetId } from '@shapeshiftoss/caip' -import type { Asset, KnownChainIds } from '@shapeshiftoss/types' -import { getAssetNamespaceFromChainId, makeAsset } from '@shapeshiftoss/utils' +import type { Asset } from '@shapeshiftoss/types' +import { makeAsset } from '@shapeshiftoss/utils' import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react' import MultiRef from 'react-multi-ref' import { useNavigate } from 'react-router-dom' @@ -22,8 +21,7 @@ import { AssetSearchResults } from './AssetSearchResults' import { GlobalFilter } from '@/components/StakingVaults/GlobalFilter' import { useGetCustomTokensQuery } from '@/components/TradeAssetSearch/hooks/useGetCustomTokensQuery' import { useModalRegistration } from '@/context/ModalStackProvider' -import { ALCHEMY_SDK_SUPPORTED_CHAIN_IDS } from '@/lib/alchemySdkInstance' -import { isSome } from '@/lib/utils' +import { CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS } from '@/lib/customTokenImportSupportedChainIds' import { assets as assetsSlice } from '@/state/slices/assetsSlice/assetsSlice' import { selectAssets, selectAssetsBySearchQuery } from '@/state/slices/selectors' import { tradeInput } from '@/state/slices/tradeInputSlice/tradeInputSlice' @@ -47,9 +45,7 @@ export const GlobalSearchModal = memo( const navigate = useNavigate() const dispatch = useAppDispatch() const searchFilter = useMemo(() => ({ searchQuery, limit: 10 }), [searchQuery]) - const results = useAppSelector(state => selectAssetsBySearchQuery(state, searchFilter)) - const assetResults = results - const resultsCount = results.length + const searchAssets = useAppSelector(state => selectAssetsBySearchQuery(state, searchFilter)) const isMac = useMemo(() => /Mac/.test(navigator.userAgent), []) const handleClose = useCallback(() => { setSearchQuery('') @@ -61,61 +57,35 @@ export const GlobalSearchModal = memo( onClose: handleClose, }) - const customTokenSupportedChainIds = useMemo(() => { - // Solana _is_ supported by Alchemy, but not by the SDK - return [...ALCHEMY_SDK_SUPPORTED_CHAIN_IDS, solanaChainId] - }, []) - const { data: customTokens, isLoading: isLoadingCustomTokens } = useGetCustomTokensQuery({ contractAddress: searchQuery, - chainIds: customTokenSupportedChainIds, + chainIds: CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS, }) const customAssets = useMemo(() => { if (!customTokens?.length) return [] - // Do not move me to a regular useSelector(), as this is reactive on the *whole* assets set and would make this component extremely reactive for no reason const assetsById = selectAssets(store.getState()) - const assets = customTokens - .map(metaData => { - if (!metaData) return null - const { name, symbol, decimals, logo, chainId, contractAddress } = metaData - - if (!name || !symbol || !decimals) return null - - const assetId = toAssetId({ - chainId, - assetNamespace: getAssetNamespaceFromChainId(chainId as KnownChainIds), - assetReference: contractAddress, - }) - - const minimalAsset = { - assetId, - name, - symbol, - precision: decimals, - icon: logo ?? undefined, - } - - return makeAsset(assetsById, minimalAsset) - }) - .filter(isSome) - - return assets + return customTokens + .filter(token => !assetsById[token.assetId]) + .map(token => makeAsset(assetsById, token)) }, [customTokens]) useEffect(() => { customAssets.forEach(asset => { - // Do not move me to a regular useSelector(), as this is reactive on the *whole* assets set and would make this component extremely reactive for no reason - const assetsById = selectAssets(store.getState()) - - if (!assetsById[asset.assetId]) { - dispatch(assetsSlice.actions.upsertAsset(asset)) - } + dispatch(assetsSlice.actions.upsertAsset(asset)) }) }, [customAssets, dispatch]) + const results = useMemo(() => { + if (!customAssets.length) return searchAssets + const existingIds = new Set(searchAssets.map(a => a.assetId)) + return searchAssets.concat(customAssets.filter(a => !existingIds.has(a.assetId))) + }, [searchAssets, customAssets]) + + const resultsCount = results.length + useEffect(() => { if (!searchQuery) setActiveIndex(0) }, [searchQuery]) @@ -203,11 +173,6 @@ export const GlobalSearchModal = memo( setActiveIndex(0) }, [searchQuery]) - const isSearching = useMemo( - () => searchQuery.length > 0 || isLoadingCustomTokens, - [searchQuery.length, isLoadingCustomTokens], - ) - return ( @@ -230,9 +195,9 @@ export const GlobalSearchModal = memo( diff --git a/src/components/TradeAssetSearch/components/SearchTermAssetList.tsx b/src/components/TradeAssetSearch/components/SearchTermAssetList.tsx index 86543a8928e..47ffadd1efe 100644 --- a/src/components/TradeAssetSearch/components/SearchTermAssetList.tsx +++ b/src/components/TradeAssetSearch/components/SearchTermAssetList.tsx @@ -1,9 +1,8 @@ import { Box, useMediaQuery } from '@chakra-ui/react' import type { AssetId, ChainId } from '@shapeshiftoss/caip' -import { fromAssetId, isNft, solanaChainId, toAssetId } from '@shapeshiftoss/caip' -import type { Asset, KnownChainIds } from '@shapeshiftoss/types' -import type { MinimalAsset } from '@shapeshiftoss/utils' -import { bnOrZero, getAssetNamespaceFromChainId, makeAsset } from '@shapeshiftoss/utils' +import { fromAssetId, isNft } from '@shapeshiftoss/caip' +import type { Asset } from '@shapeshiftoss/types' +import { bnOrZero, makeAsset } from '@shapeshiftoss/utils' import { orderBy } from 'lodash' import { useMemo } from 'react' @@ -12,8 +11,8 @@ import { useGetCustomTokensQuery } from '../hooks/useGetCustomTokensQuery' import { AssetList } from '@/components/AssetSearch/components/AssetList' import { Text } from '@/components/Text' -import { ALCHEMY_SDK_SUPPORTED_CHAIN_IDS } from '@/lib/alchemySdkInstance' import { searchAssets } from '@/lib/assetSearch' +import { CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS } from '@/lib/customTokenImportSupportedChainIds' import { isSome } from '@/lib/utils' import { isContractAddress } from '@/lib/utils/isContractAddress' import { @@ -22,8 +21,8 @@ import { selectRelatedAssetIdsByAssetIdInclusive, selectWalletConnectedChainIds, } from '@/state/slices/common-selectors' -import { selectPrimaryAssets } from '@/state/slices/selectors' -import { useAppSelector } from '@/state/store' +import { selectAssets } from '@/state/slices/selectors' +import { store, useAppSelector } from '@/state/store' import { breakpoints } from '@/theme/theme' export type SearchTermAssetListProps = { @@ -53,23 +52,17 @@ export const SearchTermAssetList = ({ ) const relatedAssetIdsById = useAppSelector(selectRelatedAssetIdsByAssetIdInclusive) const portfolioUserCurrencyBalances = useAppSelector(selectPortfolioUserCurrencyBalances) - const assetsById = useAppSelector(selectPrimaryAssets) const walletConnectedChainIds = useAppSelector(selectWalletConnectedChainIds) - const customTokenSupportedChainIds = useMemo(() => { - // Solana _is_ supported by Alchemy, but not by the SDK - return [...ALCHEMY_SDK_SUPPORTED_CHAIN_IDS, solanaChainId] - }, []) - const chainIds = useMemo(() => { if (activeChainId === 'All') { - return customTokenSupportedChainIds - } else if (customTokenSupportedChainIds.includes(activeChainId)) { + return CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS + } else if (CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS.includes(activeChainId)) { return [activeChainId] } else { return [] } - }, [activeChainId, customTokenSupportedChainIds]) + }, [activeChainId]) const { data: customTokens, isLoading: isLoadingCustomTokens } = useGetCustomTokensQuery({ contractAddress: searchString, @@ -114,32 +107,14 @@ export const SearchTermAssetList = ({ }, [assetsForChain]) const customAssets: Asset[] = useMemo(() => { - return (customTokens ?? []) - .map(metaData => { - if (!metaData) return null - const { name, symbol, decimals, logo } = metaData - // If we can't get all the information we need to create an Asset, don't allow the custom token - if (!name || !symbol || !decimals) return null - const assetId = toAssetId({ - chainId: metaData.chainId, - assetNamespace: getAssetNamespaceFromChainId(metaData.chainId as KnownChainIds), - assetReference: metaData.contractAddress, - }) - - // Skip if we already have this asset - if (assetIdMap[assetId] !== undefined) return null - - const minimalAsset: MinimalAsset = { - assetId, - name, - symbol, - precision: decimals, - icon: logo ?? undefined, - } - return makeAsset(assetsById, minimalAsset) - }) - .filter(isSome) - }, [assetIdMap, assetsById, customTokens]) + if (!customTokens?.length) return [] + + const assetsById = selectAssets(store.getState()) + + return customTokens + .filter(token => !assetsById[token.assetId]) + .map(token => makeAsset(assetsById, token)) + }, [customTokens]) const searchTermAssets = useMemo(() => { const filteredAssets: Asset[] = (() => { diff --git a/src/components/TradeAssetSearch/hooks/useGetCustomTokensQuery.tsx b/src/components/TradeAssetSearch/hooks/useGetCustomTokensQuery.tsx index 49e305afff9..dbefed5352b 100644 --- a/src/components/TradeAssetSearch/hooks/useGetCustomTokensQuery.tsx +++ b/src/components/TradeAssetSearch/hooks/useGetCustomTokensQuery.tsx @@ -1,24 +1,24 @@ -import { Metaplex } from '@metaplex-foundation/js' import type { ChainId } from '@shapeshiftoss/caip' -import { solanaChainId } from '@shapeshiftoss/caip' -import { isEvmChainId } from '@shapeshiftoss/chain-adapters' -import { Connection, PublicKey } from '@solana/web3.js' +import { toAssetId } from '@shapeshiftoss/caip' +import type { KnownChainIds } from '@shapeshiftoss/types' +import type { MinimalAsset } from '@shapeshiftoss/utils' +import { getAssetNamespaceFromChainId } from '@shapeshiftoss/utils' import type { UseQueryResult } from '@tanstack/react-query' import { skipToken, useQueries } from '@tanstack/react-query' -import type { TokenMetadataResponse } from 'alchemy-sdk' +import axios, { isAxiosError } from 'axios' import { useCallback, useMemo } from 'react' import { isAddress } from 'viem' import { getConfig } from '@/config' import { useFeatureFlag } from '@/hooks/useFeatureFlag/useFeatureFlag' -import { getAlchemyInstanceByChainId } from '@/lib/alchemySdkInstance' import { isSolanaAddress } from '@/lib/utils/isSolanaAddress' import { mergeQueryOutputs } from '@/react-queries/helpers' -type TokenMetadata = TokenMetadataResponse & { - chainId: ChainId - contractAddress: string - price: string +type TokenMetadataResponse = { + name: string + symbol: string + decimals: number | null + logo: string | null } type UseGetCustomTokensQueryProps = { @@ -37,38 +37,43 @@ const getCustomTokenQueryKey = (contractAddress: string, chainId: ChainId): Cust export const useGetCustomTokensQuery = ({ contractAddress, chainIds, -}: UseGetCustomTokensQueryProps): UseQueryResult<(TokenMetadata | undefined)[], Error[]> => { +}: UseGetCustomTokensQueryProps): UseQueryResult => { const customTokenImportEnabled = useFeatureFlag('CustomTokenImport') - const getEvmTokenMetadata = useCallback( - async (chainId: ChainId) => { - const alchemy = getAlchemyInstanceByChainId(chainId) - const tokenMetadataResponse = await alchemy.core.getTokenMetadata(contractAddress) - return { ...tokenMetadataResponse, chainId, contractAddress, price: '0' } - }, - [contractAddress], - ) + const getCustomToken = useCallback( + async (chainId: ChainId): Promise => { + try { + const { data } = await axios.get( + `${getConfig().VITE_PROXY_API_BASE_URL}/api/v1/tokens/metadata`, + { + params: { + chainId, + tokenAddress: contractAddress, + }, + }, + ) - const getSolanaTokenMetadata = useCallback( - async (mintAddress: string): Promise => { - const solanaRpcUrl = `${getConfig().VITE_ALCHEMY_SOLANA_BASE_URL}/${ - getConfig().VITE_ALCHEMY_API_KEY - }` - const connection = new Connection(solanaRpcUrl) - const metaplex = Metaplex.make(connection) - const metadata = await metaplex.nfts().findByMint({ mintAddress: new PublicKey(mintAddress) }) - - return { - name: metadata.name, - symbol: metadata.symbol, - decimals: metadata.mint.currency.decimals, - chainId: solanaChainId, - contractAddress: mintAddress, - price: '0', - logo: metadata.json?.image ?? '', + if (data.decimals === null) return undefined + + const assetId = toAssetId({ + chainId, + assetNamespace: getAssetNamespaceFromChainId(chainId as KnownChainIds), + assetReference: contractAddress, + }) + + return { + assetId, + name: data.name, + symbol: data.symbol, + precision: data.decimals, + icon: data.logo ?? undefined, + } + } catch (err) { + if (isAxiosError(err) && (err.response?.status ?? 0) >= 500) throw err + return undefined } }, - [], + [contractAddress], ) const isValidEvmAddress = useMemo( @@ -80,26 +85,15 @@ export const useGetCustomTokensQuery = ({ const getQueryFn = useCallback( (chainId: ChainId) => () => { - if (isValidSolanaAddress && chainId === solanaChainId) { - return getSolanaTokenMetadata(contractAddress) - } else if (isValidEvmAddress && isEvmChainId(chainId)) { - return getEvmTokenMetadata(chainId) - } else { - return skipToken - } + if (!isValidEvmAddress && !isValidSolanaAddress) return skipToken + return getCustomToken(chainId) }, - [ - contractAddress, - getEvmTokenMetadata, - getSolanaTokenMetadata, - isValidEvmAddress, - isValidSolanaAddress, - ], + [getCustomToken, isValidEvmAddress, isValidSolanaAddress], ) - const isTokenMetadata = ( - result: TokenMetadata | typeof skipToken | undefined, - ): result is TokenMetadata => result !== undefined && result !== skipToken + const isMinimalAsset = ( + result: MinimalAsset | typeof skipToken | undefined, + ): result is MinimalAsset => result !== undefined && result !== skipToken const customTokenQueries = useQueries({ queries: chainIds.map(chainId => ({ @@ -108,7 +102,7 @@ export const useGetCustomTokensQuery = ({ enabled: customTokenImportEnabled, staleTime: Infinity, })), - combine: queries => mergeQueryOutputs(queries, results => results.filter(isTokenMetadata)), + combine: queries => mergeQueryOutputs(queries, results => results.filter(isMinimalAsset)), }) return customTokenQueries diff --git a/src/config.ts b/src/config.ts index 3b0c41ce090..4b991116a7f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -55,9 +55,6 @@ const validators = { VITE_AVALANCHE_NODE_URL: url(), VITE_OPTIMISM_NODE_URL: url(), VITE_BNBSMARTCHAIN_NODE_URL: url(), - VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_1: url({ default: '' }), - VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_2: url({ default: '' }), - VITE_BNBSMARTCHAIN_NODE_URL_FALLBACK_3: url({ default: '' }), VITE_POLYGON_NODE_URL: url(), VITE_GNOSIS_NODE_URL: url(), VITE_ARBITRUM_NODE_URL: url(), @@ -98,7 +95,6 @@ const validators = { VITE_NEAR_NODE_URL_FALLBACK_1: url({ default: '' }), VITE_NEAR_NODE_URL_FALLBACK_2: url({ default: '' }), VITE_FASTNEAR_API_URL: url(), - VITE_ALCHEMY_POLYGON_URL: url(), VITE_KEEPKEY_VERSIONS_URL: url(), VITE_KEEPKEY_LATEST_RELEASE_URL: url(), VITE_WALLET_MIGRATION_URL: url(), @@ -215,9 +211,7 @@ const validators = { VITE_FEATURE_PORTALS_SWAPPER: bool({ default: false }), VITE_FEATURE_ONE_INCH: bool({ default: false }), VITE_SENTRY_DSN_URL: url(), - VITE_ALCHEMY_API_KEY: str(), VITE_MORALIS_API_KEY: str(), - VITE_ALCHEMY_SOLANA_BASE_URL: url(), VITE_CHATWOOT_TOKEN: str(), VITE_CHATWOOT_URL: str(), VITE_FEATURE_CHATWOOT: bool({ default: false }), @@ -244,6 +238,7 @@ const validators = { VITE_FEATURE_RUNEPOOL_WITHDRAW: bool({ default: false }), VITE_FEATURE_MARKETS: bool({ default: false }), VITE_PORTALS_BASE_URL: url(), + VITE_PROXY_API_BASE_URL: url({ default: 'https://api.proxy.shapeshift.com' }), VITE_ZERION_BASE_URL: url(), VITE_FEATURE_PHANTOM_WALLET: bool({ default: false }), VITE_FEATURE_FOX_PAGE_FOX_SECTION: bool({ default: true }), diff --git a/src/hooks/useAffiliateTracking/index.ts b/src/hooks/useAffiliateTracking/index.ts index 87d16f99386..3782619c0d5 100644 --- a/src/hooks/useAffiliateTracking/index.ts +++ b/src/hooks/useAffiliateTracking/index.ts @@ -1 +1,6 @@ -export { useAffiliateTracking, AFFILIATE_STORAGE_KEY } from './useAffiliateTracking' +export { + useAffiliateTracking, + readStoredPartnerBps, + readStoredPartnerCode, + AFFILIATE_STORAGE_KEY, +} from './useAffiliateTracking' diff --git a/src/hooks/useAffiliateTracking/useAffiliateTracking.ts b/src/hooks/useAffiliateTracking/useAffiliateTracking.ts index 1e34b636028..8e7af769abc 100644 --- a/src/hooks/useAffiliateTracking/useAffiliateTracking.ts +++ b/src/hooks/useAffiliateTracking/useAffiliateTracking.ts @@ -1,23 +1,47 @@ import { useEffect, useState } from 'react' -import { isAddress } from 'viem' -const AFFILIATE_STORAGE_KEY = 'shapeshift_affiliate_address' -const AFFILIATE_TIMESTAMP_KEY = 'shapeshift_affiliate_timestamp' -const AFFILIATE_TTL_MS = 30 * 24 * 60 * 60 * 1000 // 30 days +const PARTNER_ADDRESS_KEY = 'shapeshift_partner_address' +const PARTNER_BPS_KEY = 'shapeshift_partner_bps' +const PARTNER_CODE_KEY = 'shapeshift_partner_code' +const PARTNER_TIMESTAMP_KEY = 'shapeshift_partner_timestamp' +const PARTNER_TTL_MS = 30 * 24 * 60 * 60 * 1000 +const SHAPESHIFT_CUT_BPS = 10 -const isAffiliateExpired = (timestamp: string | null): boolean => { +const PARTNER_LOOKUP_URL = import.meta.env.VITE_SWAPS_SERVER_URL || 'http://localhost:3001' + +type PartnerData = { + affiliateAddress: string + bps: number + partnerCode: string +} + +const isPartnerExpired = (timestamp: string | null): boolean => { if (!timestamp) return true const storedTime = Number(timestamp) if (Number.isNaN(storedTime)) return true - return Date.now() - storedTime > AFFILIATE_TTL_MS + return Date.now() - storedTime > PARTNER_TTL_MS +} + +const clearPartnerStorage = (): void => { + try { + window.localStorage.removeItem(PARTNER_ADDRESS_KEY) + window.localStorage.removeItem(PARTNER_BPS_KEY) + window.localStorage.removeItem(PARTNER_CODE_KEY) + window.localStorage.removeItem(PARTNER_TIMESTAMP_KEY) + } catch { + // noop + } } -const clearAffiliateStorage = (): void => { +const storePartnerData = (data: PartnerData): void => { try { - window.localStorage.removeItem(AFFILIATE_STORAGE_KEY) - window.localStorage.removeItem(AFFILIATE_TIMESTAMP_KEY) - } catch (error) { - console.warn('Error clearing affiliate data from localStorage:', error) + const totalBps = String(data.bps + SHAPESHIFT_CUT_BPS) + window.localStorage.setItem(PARTNER_ADDRESS_KEY, data.affiliateAddress) + window.localStorage.setItem(PARTNER_BPS_KEY, totalBps) + window.localStorage.setItem(PARTNER_CODE_KEY, data.partnerCode) + window.localStorage.setItem(PARTNER_TIMESTAMP_KEY, String(Date.now())) + } catch { + // noop } } @@ -25,65 +49,125 @@ export const readStoredAffiliate = (): string | null => { if (typeof window === 'undefined') return null try { - const address = window.localStorage.getItem(AFFILIATE_STORAGE_KEY) - const timestamp = window.localStorage.getItem(AFFILIATE_TIMESTAMP_KEY) + const address = window.localStorage.getItem(PARTNER_ADDRESS_KEY) + const timestamp = window.localStorage.getItem(PARTNER_TIMESTAMP_KEY) if (!address) return null - if (!isAddress(address)) { - clearAffiliateStorage() + if (isPartnerExpired(timestamp)) { + clearPartnerStorage() return null } - if (isAffiliateExpired(timestamp)) { - clearAffiliateStorage() + return address + } catch { + return null + } +} + +export const readStoredPartnerBps = (): string | null => { + if (typeof window === 'undefined') return null + + try { + const bps = window.localStorage.getItem(PARTNER_BPS_KEY) + const timestamp = window.localStorage.getItem(PARTNER_TIMESTAMP_KEY) + + if (!bps) return null + + if (isPartnerExpired(timestamp)) { + clearPartnerStorage() return null } - return address - } catch (error) { - console.warn('Error reading affiliate address from localStorage:', error) + return bps + } catch { return null } } +const PARTNER_RESOLVE_TIMEOUT_MS = 5000 + +const resolvePartnerCode = async (code: string): Promise => { + try { + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), PARTNER_RESOLVE_TIMEOUT_MS) + + const response = await fetch(`${PARTNER_LOOKUP_URL}/v1/partner/${encodeURIComponent(code)}`, { + signal: controller.signal, + }) + clearTimeout(timeoutId) + + if (!response.ok) return null + + const data = (await response.json()) as { + affiliateAddress: string + bps: number + partnerCode: string + } + + return data + } catch { + return null + } +} + +const getPartnerCode = (): string | null => { + if (typeof window === 'undefined') return null + + const hash = window.location.hash + const hashQueryIdx = hash.indexOf('?') + const searchStr = hashQueryIdx !== -1 ? hash.substring(hashQueryIdx) : window.location.search + const params = new URLSearchParams(searchStr) + const partnerParam = params.get('partner') + + if (partnerParam) return partnerParam + + try { + const storedCode = window.localStorage.getItem(PARTNER_CODE_KEY) + const timestamp = window.localStorage.getItem(PARTNER_TIMESTAMP_KEY) + if (storedCode && !isPartnerExpired(timestamp)) return storedCode + } catch { + // noop + } + + return null +} + export const useAffiliateTracking = (): string | null => { - const [storedAffiliateAddress, setStoredAffiliateAddress] = useState( - readStoredAffiliate, - ) + const [storedAddress, setStoredAddress] = useState(readStoredAffiliate) useEffect(() => { - if (typeof window === 'undefined') return + const code = getPartnerCode() + if (!code) return - const hash = window.location.hash - const hashQueryIdx = hash.indexOf('?') - const searchStr = hashQueryIdx !== -1 ? hash.substring(hashQueryIdx) : window.location.search - const params = new URLSearchParams(searchStr) - const affiliateParam = params.get('affiliate') + void resolvePartnerCode(code).then(data => { + if (!data) return + storePartnerData(data) + setStoredAddress(data.affiliateAddress) + }) + }, []) - if (!affiliateParam) return + return storedAddress +} - const isValidEvmAddress = isAddress(affiliateParam) - if (!isValidEvmAddress) return +export const readStoredPartnerCode = (): string | null => { + if (typeof window === 'undefined') return null - // If we already have a non-expired affiliate stored, only override if it's different AND expired - if (storedAffiliateAddress) { - if (affiliateParam === storedAffiliateAddress) return + try { + const code = window.localStorage.getItem(PARTNER_CODE_KEY) + const timestamp = window.localStorage.getItem(PARTNER_TIMESTAMP_KEY) - const timestamp = window.localStorage.getItem(AFFILIATE_TIMESTAMP_KEY) - if (!isAffiliateExpired(timestamp)) return - } + if (!code) return null - try { - window.localStorage.setItem(AFFILIATE_STORAGE_KEY, affiliateParam) - window.localStorage.setItem(AFFILIATE_TIMESTAMP_KEY, String(Date.now())) - setStoredAffiliateAddress(affiliateParam) - } catch (error) { - console.warn('Error storing affiliate address to localStorage:', error) + if (isPartnerExpired(timestamp)) { + clearPartnerStorage() + return null } - }, [storedAffiliateAddress]) - return storedAffiliateAddress + return code + } catch { + return null + } } -export { AFFILIATE_STORAGE_KEY } +export { PARTNER_ADDRESS_KEY as AFFILIATE_STORAGE_KEY } diff --git a/src/index.tsx b/src/index.tsx index 566c59eadc7..983145e6e70 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -112,13 +112,7 @@ if (shouldEnableSentry) { [500, 599], // Only server errors, not client errors ], - denyUrls: [ - 'alchemy.com', - 'snapshot.org', - 'coingecko.com', - 'coincap.io', - 'coinmarketcap.com', - ], + denyUrls: ['snapshot.org', 'coingecko.com', 'coincap.io', 'coinmarketcap.com'], }), browserApiErrorsIntegration(), breadcrumbsIntegration(), diff --git a/src/lib/alchemySdkInstance.ts b/src/lib/alchemySdkInstance.ts deleted file mode 100644 index 726b94c718f..00000000000 --- a/src/lib/alchemySdkInstance.ts +++ /dev/null @@ -1,74 +0,0 @@ -import type { ChainId } from '@shapeshiftoss/caip' -import { - arbitrumChainId, - baseChainId, - ethChainId, - optimismChainId, - polygonChainId, -} from '@shapeshiftoss/caip' -import { Alchemy, Network } from 'alchemy-sdk' - -import { getConfig } from '@/config' - -const alchemyInstanceMap: Map = new Map() - -export const ALCHEMY_SDK_SUPPORTED_CHAIN_IDS = [ - ethChainId, - polygonChainId, - optimismChainId, - arbitrumChainId, - baseChainId, -] as const - -export const getAlchemyInstanceByChainId = (chainId: ChainId): Alchemy => { - // Note, make sure to not unify this guy and `instance` below. - // This is a set, not an array, calling .set() will not automagically update `maybeInstance` to the new reference - // This should probably be an Array for dev QoL but cba to change it as part of this eslint PR - const maybeInstance = alchemyInstanceMap.get(chainId) - if (maybeInstance) return maybeInstance - - const apiKey = (() => { - switch (chainId) { - case polygonChainId: - case ethChainId: - case optimismChainId: - case arbitrumChainId: - case baseChainId: - return getConfig().VITE_ALCHEMY_API_KEY - default: - return undefined - } - })() - - const network = (() => { - switch (chainId) { - case polygonChainId: - return Network.MATIC_MAINNET - case ethChainId: - return Network.ETH_MAINNET - case optimismChainId: - return Network.OPT_MAINNET - case arbitrumChainId: - return Network.ARB_MAINNET - case baseChainId: - return Network.BASE_MAINNET - default: - return undefined - } - })() - - if (!apiKey || !network) throw new Error(`Cannot get Alchemy Instance for chainId: ${chainId}`) - - const config = { - apiKey, - network, - } - - alchemyInstanceMap.set(chainId, new Alchemy(config)) - - const instance = alchemyInstanceMap.get(chainId) - - if (!instance) throw new Error(`Cannot get Alchemy Instance for chainId: ${chainId}`) - - return instance -} diff --git a/src/lib/assetSearch/deduplicateAssets.test.ts b/src/lib/assetSearch/deduplicateAssets.test.ts index 5e39e5e9b83..1e41863d15c 100644 --- a/src/lib/assetSearch/deduplicateAssets.test.ts +++ b/src/lib/assetSearch/deduplicateAssets.test.ts @@ -87,10 +87,10 @@ describe('deduplicateAssets', () => { it('prefers primary AXLUSDC over non-primary when both have exact match', () => { // Create AXLUSDC assets with their own family and a primary - const axlusdcFamily = 'eip155:1/erc20:axlusdc-family' + const axlusdcFamily = 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' const axlusdcPrimary = { ...AXLUSDC_OPTIMISM, - assetId: 'eip155:1/erc20:axlusdc-primary' as const, + assetId: 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as const, relatedAssetKey: axlusdcFamily, isPrimary: true, } @@ -109,10 +109,10 @@ describe('deduplicateAssets', () => { it('returns primary even when non-primary exact match comes first in array', () => { // Create AXLUSDC assets with primary coming second in array - const axlusdcFamily = 'eip155:1/erc20:axlusdc-family' + const axlusdcFamily = 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' const axlusdcPrimary = { ...AXLUSDC_OPTIMISM, - assetId: 'eip155:1/erc20:axlusdc-primary' as const, + assetId: 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as const, relatedAssetKey: axlusdcFamily, isPrimary: true, } @@ -130,13 +130,13 @@ describe('deduplicateAssets', () => { it('shows both AXLUSDC and AXLUSDT groups when searching "axlusd"', () => { // Create separate families for AXLUSDC and AXLUSDT - const axlusdcFamily = 'eip155:1/erc20:axlusdc-family' - const axlusdtFamily = 'eip155:1/erc20:axlusdt-family' + const axlusdcFamily = 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' + const axlusdtFamily = 'eip155:1/erc20:0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' const assets = [ { ...AXLUSDC_OPTIMISM, relatedAssetKey: axlusdcFamily, isPrimary: false }, { ...AXLUSDC_OPTIMISM, - assetId: 'eip155:1/erc20:axlusdc-primary' as const, + assetId: 'eip155:1/erc20:0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as const, relatedAssetKey: axlusdcFamily, isPrimary: true, }, @@ -149,7 +149,7 @@ describe('deduplicateAssets', () => { }, { ...AXLUSDC_ARBITRUM, - assetId: 'eip155:1/erc20:axlusdt-primary' as const, + assetId: 'eip155:1/erc20:0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' as const, symbol: 'AXLUSDT', name: 'Axelar USDT', relatedAssetKey: axlusdtFamily, @@ -207,6 +207,16 @@ describe('deduplicateAssets', () => { expect(result[0].isPrimary).toBe(true) }) + it('shows each chain variant independently when searching by contract address', () => { + // AXLUSDC_OPTIMISM and AXLUSDC_ARBITRUM share address 0xeb466342c4d449bc9f53a865d5cb90586f405215 + const assets = [AXLUSDC_OPTIMISM, AXLUSDC_ARBITRUM] + + const result = deduplicateAssets(assets, '0xeb466342c4d449bc9f53a865d5cb90586f405215') + + expect(result).toHaveLength(2) + expect(result.map(a => a.chainId).sort()).toEqual(['eip155:10', 'eip155:42161'].sort()) + }) + describe('name search grouping', () => { it('groups "Axelar Bridged" name search results by family', () => { // AXLUSDC and AXLUSDT are in different families (USDC and USDT families) diff --git a/src/lib/assetSearch/deduplicateAssets.ts b/src/lib/assetSearch/deduplicateAssets.ts index 07c7e9a9efe..57fdf3347fb 100644 --- a/src/lib/assetSearch/deduplicateAssets.ts +++ b/src/lib/assetSearch/deduplicateAssets.ts @@ -1,3 +1,6 @@ +import { fromAssetId } from '@shapeshiftoss/caip' + +import { isContractAddress } from '../utils/isContractAddress' import type { SearchableAsset } from './types' import { isExactMatch } from './utils' @@ -26,7 +29,13 @@ export const deduplicateAssets = ( : false for (const asset of assets) { - const familyKey = asset.relatedAssetKey ?? asset.assetId + // When the search is a valid contract address matching this asset's assetReference, + // use assetId as the family key so each chain variant is shown independently rather than + // collapsed into its family via relatedAssetKey. + const matchedByAddress = + isContractAddress(searchLower) && + fromAssetId(asset.assetId).assetReference.toLowerCase() === searchLower + const familyKey = matchedByAddress ? asset.assetId : asset.relatedAssetKey ?? asset.assetId const existing = familyToAsset.get(familyKey) const isExact = hasExactSymbolMatch && isExactMatch(searchLower, asset.symbol) diff --git a/src/lib/customTokenImportSupportedChainIds.ts b/src/lib/customTokenImportSupportedChainIds.ts new file mode 100644 index 00000000000..3664c292743 --- /dev/null +++ b/src/lib/customTokenImportSupportedChainIds.ts @@ -0,0 +1,18 @@ +import type { ChainId } from '@shapeshiftoss/caip' +import { + arbitrumChainId, + baseChainId, + ethChainId, + optimismChainId, + polygonChainId, + solanaChainId, +} from '@shapeshiftoss/caip' + +export const CUSTOM_TOKEN_IMPORT_SUPPORTED_CHAIN_IDS: ChainId[] = [ + ethChainId, + polygonChainId, + optimismChainId, + arbitrumChainId, + baseChainId, + solanaChainId, +] diff --git a/src/lib/fees/utils.ts b/src/lib/fees/utils.ts index ff83d911f24..b85c01b0308 100644 --- a/src/lib/fees/utils.ts +++ b/src/lib/fees/utils.ts @@ -4,6 +4,8 @@ import type BigNumber from 'bignumber.js' import { bn, bnOrZero } from '../bignumber/bignumber' import { DEFAULT_FEE_BPS } from './constant' +import { readStoredPartnerBps } from '@/hooks/useAffiliateTracking/useAffiliateTracking' + type CalculateFeeUsdArgs = { inputAmountUsd: BigNumber.Value } @@ -27,5 +29,8 @@ const isRelatedAssetSwap = (sellAsset: Asset, buyAsset: Asset): boolean => { } export const getAffiliateBps = (sellAsset: Asset, buyAsset: Asset): string => { - return isRelatedAssetSwap(sellAsset, buyAsset) ? '0' : DEFAULT_FEE_BPS + if (isRelatedAssetSwap(sellAsset, buyAsset)) return '0' + + const partnerBps = readStoredPartnerBps() + return partnerBps ?? DEFAULT_FEE_BPS } diff --git a/src/lib/tradeExecution.ts b/src/lib/tradeExecution.ts index f946412fe67..77a9b064d73 100644 --- a/src/lib/tradeExecution.ts +++ b/src/lib/tradeExecution.ts @@ -47,11 +47,13 @@ import { assertGetUtxoChainAdapter } from './utils/utxo' import { getConfig } from '@/config' import { queryClient } from '@/context/QueryClientProvider/queryClient' -import { readStoredAffiliate } from '@/hooks/useAffiliateTracking/useAffiliateTracking' +import { readStoredPartnerCode } from '@/hooks/useAffiliateTracking/useAffiliateTracking' import { fetchIsSmartContractAddressQuery } from '@/hooks/useIsSmartContractAddress/useIsSmartContractAddress' +import { bnOrZero } from '@/lib/bignumber/bignumber' import { getAffiliateBps } from '@/lib/fees/utils' import { poll } from '@/lib/poll/poll' import { getOrCreateUser } from '@/lib/user/api' +import { selectUsdRateByAssetId } from '@/state/slices/marketDataSlice/selectors' import { selectCurrentSwap, selectWalletEnabledAccountIds } from '@/state/slices/selectors' import { swapSlice } from '@/state/slices/swapSlice/swapSlice' import { selectFirstHopSellAccountId } from '@/state/slices/tradeInputSlice/selectors' @@ -213,14 +215,27 @@ export class TradeExecution { queryClient.fetchQuery({ queryKey: ['createSwap', swap.id], queryFn: () => { - const affiliateAddress = readStoredAffiliate() ?? undefined const affiliateBps = getAffiliateBps(updatedSwap.sellAsset, updatedSwap.buyAsset) + const partnerCode = readStoredPartnerCode() ?? undefined + + const sellAssetUsdRate = selectUsdRateByAssetId( + store.getState(), + updatedSwap.sellAsset.assetId, + ) + const sellAmountUsd = + sellAssetUsdRate && updatedSwap.sellAmountCryptoPrecision + ? bnOrZero(updatedSwap.sellAmountCryptoPrecision) + .times(sellAssetUsdRate) + .toFixed(2) + : undefined + return axios.post(`${import.meta.env.VITE_SWAPS_SERVER_URL}/swaps`, { swapId: swap.id, sellTxHash, userId: userData?.id, - affiliateAddress, affiliateBps, + partnerCode, + sellAmountUsd, origin: 'web', sellAsset: updatedSwap.sellAsset, buyAsset: updatedSwap.buyAsset, diff --git a/src/pages/Fox/components/RFOXSection.tsx b/src/pages/Fox/components/RFOXSection.tsx index 25fdf03c106..c0fdc32b8e6 100644 --- a/src/pages/Fox/components/RFOXSection.tsx +++ b/src/pages/Fox/components/RFOXSection.tsx @@ -116,7 +116,7 @@ export const RFOXSection = () => { const translate = useTranslate() const isRFOXLPEnabled = useFeatureFlag('RFOX_LP') const { assetAccountNumber } = useFoxPageContext() - const { setStakingAssetAccountId } = useRFOXContext() + const { setStakingAssetAccountId, setStakingAssetId: setContextStakingAssetId } = useRFOXContext() const appDispatch = useAppDispatch() const location = useLocation() const selectedUnstakingRequest = location.state?.selectedUnstakingRequest as @@ -274,9 +274,14 @@ export const RFOXSection = () => { timeInPoolSeconds === 0n ? 'N/A' : formatSecondsToDuration(Number(timeInPoolSeconds)), }) - const handleSelectAssetId = useCallback((filter: Filter) => { - setStakingAssetId(filter.assetId ?? foxOnArbitrumOneAssetId) - }, []) + const handleSelectAssetId = useCallback( + (filter: Filter) => { + const assetId = filter.assetId ?? foxOnArbitrumOneAssetId + setStakingAssetId(assetId) + setContextStakingAssetId(assetId) + }, + [setContextStakingAssetId], + ) const isTimeInPoolLoading = useMemo(() => { return isTimeInPoolQueryLoading || isTimeInPoolFetching diff --git a/src/pages/Yields/hooks/useYieldTransactionFlow.ts b/src/pages/Yields/hooks/useYieldTransactionFlow.ts index 5378a79bdf2..70e7b409ee1 100644 --- a/src/pages/Yields/hooks/useYieldTransactionFlow.ts +++ b/src/pages/Yields/hooks/useYieldTransactionFlow.ts @@ -399,6 +399,18 @@ export const useYieldTransactionFlow = ({ setTransactionSteps(prev => prev.map((s, i) => (i === index ? { ...s, ...updates } : s))) }, []) + const isInsufficientGasError = useCallback((error: unknown): boolean => { + const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase() + return ( + msg.includes('insufficient funds') || + msg.includes('insufficient balance') || + msg.includes('gas required exceeds allowance') || + msg.includes('not enough balance') || + msg.includes('insufficientbalance') || + msg.includes('out of gas') + ) + }, []) + const showErrorToast = useCallback( (titleKey: string, descriptionKey: string) => { toast({ @@ -559,12 +571,15 @@ export const useYieldTransactionFlow = ({ setActiveStepIndex(1) } catch (error) { console.error('Reset allowance failed:', error) - const description = - error instanceof ChainAdapterError - ? translate(error.metadata.translation, error.metadata.options) - : error instanceof Error - ? error.message - : translate('yieldXYZ.errors.transactionFailedDescription') + const description = isInsufficientGasError(error) + ? translate('yieldXYZ.errors.insufficientAssetForGas', { + symbol: feeAsset?.symbol ?? '', + }) + : error instanceof ChainAdapterError + ? translate(error.metadata.translation, error.metadata.options) + : error instanceof Error + ? error.message + : translate('yieldXYZ.errors.transactionFailedDescription') toast({ title: translate('yieldXYZ.errors.transactionFailedTitle'), description, @@ -584,6 +599,8 @@ export const useYieldTransactionFlow = ({ accountMetadata?.bip44Params?.accountNumber, userAddress, feeAsset?.explorerTxLink, + feeAsset?.symbol, + isInsufficientGasError, translate, updateStepStatus, toast, @@ -806,7 +823,17 @@ export const useYieldTransactionFlow = ({ } } catch (error) { console.error('Transaction execution failed:', error) - if (error instanceof ChainAdapterError) { + if (isInsufficientGasError(error)) { + toast({ + title: translate('yieldXYZ.errors.transactionFailedTitle'), + description: translate('yieldXYZ.errors.insufficientAssetForGas', { + symbol: feeAsset?.symbol ?? '', + }), + status: 'error', + duration: 5000, + isClosable: true, + }) + } else if (error instanceof ChainAdapterError) { toast({ title: translate('yieldXYZ.errors.transactionFailedTitle'), description: translate(error.metadata.translation, error.metadata.options), @@ -832,6 +859,7 @@ export const useYieldTransactionFlow = ({ userAddress, accountMetadata?.bip44Params, feeAsset, + isInsufficientGasError, yieldItem, action, amount, diff --git a/src/plugins/walletConnectToDapps/components/modals/NetworkSelection.tsx b/src/plugins/walletConnectToDapps/components/modals/NetworkSelection.tsx index b483f39fed4..fa4c072cc22 100644 --- a/src/plugins/walletConnectToDapps/components/modals/NetworkSelection.tsx +++ b/src/plugins/walletConnectToDapps/components/modals/NetworkSelection.tsx @@ -272,7 +272,7 @@ export const NetworkSelection: FC = ({ ]) return ( - + @@ -295,7 +295,7 @@ export const NetworkSelection: FC = ({ - + {networkRows} diff --git a/src/react-queries/queries/yieldxyz/useAllYieldBalances.ts b/src/react-queries/queries/yieldxyz/useAllYieldBalances.ts index c485b9891a0..baed0ffb3a4 100644 --- a/src/react-queries/queries/yieldxyz/useAllYieldBalances.ts +++ b/src/react-queries/queries/yieldxyz/useAllYieldBalances.ts @@ -276,7 +276,22 @@ export const useAllYieldBalances = (options: UseAllYieldBalancesOptions = {}) => network, })) - const response = await fetchAggregateBalances(uniqueQueries) + // yield.xyz API enforces a maximum of 25 balance queries per request. + // Native wallets can easily exceed this with accounts across many chains. + const BATCH_SIZE = 25 + const batches: (typeof uniqueQueries)[] = [] + for (let i = 0; i < uniqueQueries.length; i += BATCH_SIZE) { + batches.push(uniqueQueries.slice(i, i + BATCH_SIZE)) + } + + const batchResponses = await Promise.all( + batches.map(batch => fetchAggregateBalances(batch)), + ) + + const response = { + items: batchResponses.flatMap(r => r.items), + errors: batchResponses.flatMap(r => r.errors), + } const balanceMap: Record = {} for (const item of response.items) { diff --git a/src/state/slices/common-selectors.ts b/src/state/slices/common-selectors.ts index aecf987d99f..66fca10c4fe 100644 --- a/src/state/slices/common-selectors.ts +++ b/src/state/slices/common-selectors.ts @@ -595,11 +595,13 @@ export const selectAssetsBySearchQuery = createCachedSelector( const sortedAssets = useAllAssets ? allAssets : primaryAssets - // Filter out spam tokens (low market cap) but keep assets with no market data - const filteredAssets = sortedAssets.filter(asset => { - const marketCap = bnOrZero(marketDataUsd[asset.assetId]?.marketCap) - return marketCap.isZero() || marketCap.gte(MINIMUM_MARKET_CAP_THRESHOLD) - }) + // Filter out spam tokens (low market cap) but keep assets with no market data, unless user is searching by contract address + const filteredAssets = isContractAddressSearch + ? sortedAssets + : sortedAssets.filter(asset => { + const marketCap = bnOrZero(marketDataUsd[asset.assetId]?.marketCap) + return marketCap.isZero() || marketCap.gte(MINIMUM_MARKET_CAP_THRESHOLD) + }) const matchedAssets = searchAssets(searchQuery, filteredAssets) const deduplicated = deduplicateAssets(matchedAssets, searchQuery) diff --git a/src/utils/sentry/httpclient.ts b/src/utils/sentry/httpclient.ts index 4dde3b8378a..394a3f42fbf 100644 --- a/src/utils/sentry/httpclient.ts +++ b/src/utils/sentry/httpclient.ts @@ -45,7 +45,7 @@ interface HttpClientOptions { * This array can contain strings, not regular expressions. * If omitted, no filtering by requests blacklist will be applied. * - * Example: ['snapshot.org', 'alchemy'] + * Example: ['snapshot.org'] */ denyUrls?: string[] } diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index df73f5b8306..c82708f9c12 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -83,14 +83,11 @@ interface ImportMetaEnv { readonly VITE_KEEPKEY_VERSIONS_URL: string readonly VITE_KEEPKEY_LATEST_RELEASE_URL: string readonly VITE_COWSWAP_BASE_URL: string - readonly VITE_ALCHEMY_POLYGON_URL: string readonly VITE_TOKEMAK_STATS_URL: string readonly VITE_COINCAP_API_KEY: string readonly VITE_EXCHANGERATEHOST_BASE_URL: string readonly VITE_EXCHANGERATEHOST_API_KEY: string - readonly VITE_ALCHEMY_API_KEY: string readonly VITE_MORALIS_API_KEY: string - readonly VITE_ALCHEMY_SOLANA_BASE_URL: string readonly VITE_BOARDROOM_API_BASE_URL: string readonly VITE_BOARDROOM_APP_BASE_URL: string readonly VITE_SNAPSHOT_BASE_URL: string @@ -114,6 +111,7 @@ interface ImportMetaEnv { readonly VITE_WALLET_CONNECT_WALLET_PROJECT_ID: string readonly VITE_WALLET_CONNECT_RELAY_URL: string readonly VITE_PORTALS_BASE_URL: string + readonly VITE_PROXY_API_BASE_URL: string readonly VITE_SNAP_ID: string readonly VITE_SNAP_VERSION: string readonly VITE_EXPERIMENTAL_CUSTOM_SEND_NONCE: string diff --git a/tsconfig.json b/tsconfig.json index 1d6f5b233b4..edeb19d0f5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -56,6 +56,8 @@ "**/__mocks__", "**/*.js", "packages/*/dist", + "packages/affiliate-dashboard/**", + "packages/swap-widget/**", "packages/hdwallet-sandbox/**", "packages/hdwallet-integration/**", "src/lib/asset-service/service/encodedAssetData.json",