0xtrails 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +42 -0
- package/dist/abi.d.ts +37 -0
- package/dist/abi.d.ts.map +1 -0
- package/dist/abi.js +36 -0
- package/dist/apiClient.d.ts +9 -0
- package/dist/apiClient.d.ts.map +1 -0
- package/dist/apiClient.js +18 -0
- package/dist/buffer.d.ts +3 -0
- package/dist/buffer.d.ts.map +1 -0
- package/dist/buffer.js +8 -0
- package/dist/cctp.d.ts +84 -0
- package/dist/cctp.d.ts.map +1 -0
- package/dist/cctp.js +401 -0
- package/dist/chainSwitch.d.ts +7 -0
- package/dist/chainSwitch.d.ts.map +1 -0
- package/dist/chainSwitch.js +33 -0
- package/dist/chains.d.ts +13 -0
- package/dist/chains.d.ts.map +1 -0
- package/dist/chains.js +95 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +16 -0
- package/dist/encoders.d.ts +7 -0
- package/dist/encoders.d.ts.map +1 -0
- package/dist/encoders.js +8 -0
- package/dist/error.d.ts +2 -0
- package/dist/error.d.ts.map +1 -0
- package/dist/error.js +12 -0
- package/dist/explorer.d.ts +12 -0
- package/dist/explorer.d.ts.map +1 -0
- package/dist/explorer.js +18 -0
- package/dist/gasless.d.ts +116 -0
- package/dist/gasless.d.ts.map +1 -0
- package/dist/gasless.js +297 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/indexerClient.d.ts +9 -0
- package/dist/indexerClient.d.ts.map +1 -0
- package/dist/indexerClient.js +18 -0
- package/dist/intents.d.ts +83 -0
- package/dist/intents.d.ts.map +1 -0
- package/dist/intents.js +288 -0
- package/dist/metaTxnMonitor.d.ts +14 -0
- package/dist/metaTxnMonitor.d.ts.map +1 -0
- package/dist/metaTxnMonitor.js +121 -0
- package/dist/metaTxns.d.ts +6 -0
- package/dist/metaTxns.d.ts.map +1 -0
- package/dist/metaTxns.js +4 -0
- package/dist/paymasterSend.d.ts +90 -0
- package/dist/paymasterSend.d.ts.map +1 -0
- package/dist/paymasterSend.js +329 -0
- package/dist/preconditions.d.ts +11 -0
- package/dist/preconditions.d.ts.map +1 -0
- package/dist/preconditions.js +29 -0
- package/dist/prepareSend.d.ts +102 -0
- package/dist/prepareSend.d.ts.map +1 -0
- package/dist/prepareSend.js +1080 -0
- package/dist/prices.d.ts +18 -0
- package/dist/prices.d.ts.map +1 -0
- package/dist/prices.js +142 -0
- package/dist/queryParams.d.ts +9 -0
- package/dist/queryParams.d.ts.map +1 -0
- package/dist/queryParams.js +66 -0
- package/dist/relaySdk.d.ts +65 -0
- package/dist/relaySdk.d.ts.map +1 -0
- package/dist/relaySdk.js +314 -0
- package/dist/relayer.d.ts +23 -0
- package/dist/relayer.d.ts.map +1 -0
- package/dist/relayer.js +230 -0
- package/dist/sendUserOp.d.ts +140 -0
- package/dist/sendUserOp.d.ts.map +1 -0
- package/dist/sendUserOp.js +388 -0
- package/dist/sequenceWallet.d.ts +79 -0
- package/dist/sequenceWallet.d.ts.map +1 -0
- package/dist/sequenceWallet.js +374 -0
- package/dist/theme.d.ts +3 -0
- package/dist/theme.d.ts.map +1 -0
- package/dist/theme.js +1 -0
- package/dist/toSimpleSmartAccount.d.ts +95 -0
- package/dist/toSimpleSmartAccount.d.ts.map +1 -0
- package/dist/toSimpleSmartAccount.js +373 -0
- package/dist/tokenBalances.d.ts +118 -0
- package/dist/tokenBalances.d.ts.map +1 -0
- package/dist/tokenBalances.js +492 -0
- package/dist/tokens.d.ts +50 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +356 -0
- package/dist/trails.d.ts +128 -0
- package/dist/trails.d.ts.map +1 -0
- package/dist/trails.js +1031 -0
- package/dist/umd/trails.min.js +12610 -0
- package/dist/umd/trails.min.js.map +1 -0
- package/dist/umd.d.ts +24 -0
- package/dist/umd.d.ts.map +1 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +9 -0
- package/dist/widget/ConstantsUtil-B-_-u8aQ.js +6 -0
- package/dist/widget/add-hVLs3ldJ.js +20 -0
- package/dist/widget/all-wallets-Cwxnx4BT.js +11 -0
- package/dist/widget/app-store-CAAVQjW0.js +22 -0
- package/dist/widget/apple-C3BSbglw.js +23 -0
- package/dist/widget/arrow-bottom-circle-BGU9MmsZ.js +16 -0
- package/dist/widget/arrow-bottom-hS_SA8Gp.js +13 -0
- package/dist/widget/arrow-left-CJZanWz7.js +13 -0
- package/dist/widget/arrow-right-C1qL8EMd.js +13 -0
- package/dist/widget/arrow-top-CbuCmbQs.js +13 -0
- package/dist/widget/bank-CXBEEGbb.js +19 -0
- package/dist/widget/bin-Dqzv3zCZ.js +9 -0
- package/dist/widget/bitcoin-4y3sovZp.js +18 -0
- package/dist/widget/browser-DyOl4_8m.js +1413 -0
- package/dist/widget/browser-t7Fh0sEU.js +19 -0
- package/dist/widget/card-Bo4CZkTs.js +19 -0
- package/dist/widget/ccip-BynehMIN.js +232 -0
- package/dist/widget/checkmark-DV6OKvnY.js +16 -0
- package/dist/widget/checkmark-bold-CAp1-IQ2.js +13 -0
- package/dist/widget/chevron-bottom-BjzsVzk9.js +13 -0
- package/dist/widget/chevron-left-CQZBDCiR.js +13 -0
- package/dist/widget/chevron-right-Dhg4zeZM.js +13 -0
- package/dist/widget/chevron-top-CDQmfJef.js +13 -0
- package/dist/widget/chrome-store-BNaC_b6w.js +66 -0
- package/dist/widget/circle-BC_GBj91.js +9 -0
- package/dist/widget/clock-BmF8-4a0.js +13 -0
- package/dist/widget/close-Bf61nZ8o.js +13 -0
- package/dist/widget/coinPlaceholder-7cZW2058.js +13 -0
- package/dist/widget/compass-CFC3yhnW.js +13 -0
- package/dist/widget/components/ChainImage.d.ts +8 -0
- package/dist/widget/components/ChainImage.d.ts.map +1 -0
- package/dist/widget/components/ChainImage.js +6 -0
- package/dist/widget/components/ConnectWallet.d.ts +18 -0
- package/dist/widget/components/ConnectWallet.d.ts.map +1 -0
- package/dist/widget/components/ConnectWallet.js +66 -0
- package/dist/widget/components/DebugScreensDropdown.d.ts +9 -0
- package/dist/widget/components/DebugScreensDropdown.d.ts.map +1 -0
- package/dist/widget/components/DebugScreensDropdown.js +40 -0
- package/dist/widget/components/FeeOptions.d.ts +17 -0
- package/dist/widget/components/FeeOptions.d.ts.map +1 -0
- package/dist/widget/components/FeeOptions.js +65 -0
- package/dist/widget/components/Footer.d.ts +9 -0
- package/dist/widget/components/Footer.d.ts.map +1 -0
- package/dist/widget/components/Footer.js +13 -0
- package/dist/widget/components/GreenCheckAnimation.d.ts +2 -0
- package/dist/widget/components/GreenCheckAnimation.d.ts.map +1 -0
- package/dist/widget/components/GreenCheckAnimation.js +74 -0
- package/dist/widget/components/Modal.d.ts +11 -0
- package/dist/widget/components/Modal.d.ts.map +1 -0
- package/dist/widget/components/Modal.js +36 -0
- package/dist/widget/components/Receipt.d.ts +13 -0
- package/dist/widget/components/Receipt.d.ts.map +1 -0
- package/dist/widget/components/Receipt.js +36 -0
- package/dist/widget/components/SendForm.d.ts +44 -0
- package/dist/widget/components/SendForm.d.ts.map +1 -0
- package/dist/widget/components/SendForm.js +177 -0
- package/dist/widget/components/TokenImage.d.ts +10 -0
- package/dist/widget/components/TokenImage.d.ts.map +1 -0
- package/dist/widget/components/TokenImage.js +8 -0
- package/dist/widget/components/TokenList.d.ts +16 -0
- package/dist/widget/components/TokenList.d.ts.map +1 -0
- package/dist/widget/components/TokenList.js +39 -0
- package/dist/widget/components/TransferPending.d.ts +11 -0
- package/dist/widget/components/TransferPending.d.ts.map +1 -0
- package/dist/widget/components/TransferPending.js +77 -0
- package/dist/widget/components/TransferPendingVertical.d.ts +18 -0
- package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -0
- package/dist/widget/components/TransferPendingVertical.js +183 -0
- package/dist/widget/components/WalletConfirmation.d.ts +18 -0
- package/dist/widget/components/WalletConfirmation.d.ts.map +1 -0
- package/dist/widget/components/WalletConfirmation.js +22 -0
- package/dist/widget/config.d.ts +4 -0
- package/dist/widget/config.d.ts.map +1 -0
- package/dist/widget/config.js +3 -0
- package/dist/widget/copy-e0xXvKN0.js +20 -0
- package/dist/widget/cursor-CqM3v0xJ.js +8 -0
- package/dist/widget/cursor-transparent-CUQpdsCG.js +17 -0
- package/dist/widget/desktop-DUDGIRpM.js +14 -0
- package/dist/widget/disconnect-DUFST9QQ.js +13 -0
- package/dist/widget/discord-C1cj365Z.js +22 -0
- package/dist/widget/email-BHhmb_lX.js +703 -0
- package/dist/widget/embedded-wallet-CuuC4eah.js +467 -0
- package/dist/widget/ethereum-CfmBVfeB.js +15 -0
- package/dist/widget/etherscan-BSiynDhW.js +11 -0
- package/dist/widget/exclamation-triangle-DEiFNpHw.js +9 -0
- package/dist/widget/extension-mRmfCDxo.js +13 -0
- package/dist/widget/external-link-B4xMIVnW.js +13 -0
- package/dist/widget/facebook-CBAZStBR.js +31 -0
- package/dist/widget/farcaster-LHDEDf5S.js +17 -0
- package/dist/widget/filters-CBijuvFv.js +13 -0
- package/dist/widget/github-C3ILD420.js +23 -0
- package/dist/widget/google-CSj73POX.js +23 -0
- package/dist/widget/help-circle-2hdG5IdB.js +17 -0
- package/dist/widget/hooks/useAmountUsd.d.ts +13 -0
- package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -0
- package/dist/widget/hooks/useAmountUsd.js +35 -0
- package/dist/widget/hooks/useSendForm.d.ts +125 -0
- package/dist/widget/hooks/useSendForm.d.ts.map +1 -0
- package/dist/widget/hooks/useSendForm.js +450 -0
- package/dist/widget/hooks/useTokenList.d.ts +52 -0
- package/dist/widget/hooks/useTokenList.d.ts.map +1 -0
- package/dist/widget/hooks/useTokenList.js +252 -0
- package/dist/widget/id-ByYSrwsd.js +17 -0
- package/dist/widget/if-defined-DRXJEhv7.js +752 -0
- package/dist/widget/image-C90L4Rf6.js +9 -0
- package/dist/widget/index-B3SlQ9v3.js +46 -0
- package/dist/widget/index-B8LPuLXQ.js +78 -0
- package/dist/widget/index-BDbworWA.js +171 -0
- package/dist/widget/index-BTlDgFSK.js +98 -0
- package/dist/widget/index-BUCcjXbd.js +306 -0
- package/dist/widget/index-BZ34edi2.js +1055 -0
- package/dist/widget/index-BiCU29wK.js +147 -0
- package/dist/widget/index-BlmqIKsY.js +266 -0
- package/dist/widget/index-BlviH5nG.js +55 -0
- package/dist/widget/index-Bwd5X3fS.js +8306 -0
- package/dist/widget/index-C5gmknHK.js +78 -0
- package/dist/widget/index-CD6dBcRj.js +76 -0
- package/dist/widget/index-CDlhy529.js +63 -0
- package/dist/widget/index-CHXa5ke-.js +59 -0
- package/dist/widget/index-CK94R-H7.js +22498 -0
- package/dist/widget/index-CQzo3m3x.js +182 -0
- package/dist/widget/index-CRT8cAwG.js +325 -0
- package/dist/widget/index-CY7Lt2Yu.js +310 -0
- package/dist/widget/index-CiKfAu1E.js +79 -0
- package/dist/widget/index-CkCu6rMi.js +258 -0
- package/dist/widget/index-CngLTu_R.js +517 -0
- package/dist/widget/index-CsMV8-em.js +2577 -0
- package/dist/widget/index-Cu2Wva8v.js +200 -0
- package/dist/widget/index-DKBxLTEF.js +240 -0
- package/dist/widget/index-DQEVT3dx.js +511 -0
- package/dist/widget/index-DU2HcCis.js +200 -0
- package/dist/widget/index-DutZGWNW.js +321 -0
- package/dist/widget/index-O0glArmc.js +182 -0
- package/dist/widget/index-O8FmRjKe.js +63719 -0
- package/dist/widget/index-RtKXrB6I.js +576 -0
- package/dist/widget/index-TIYtS0gE.js +88 -0
- package/dist/widget/index-dQNJvWHs.js +66 -0
- package/dist/widget/index-wmEwdsq7.js +909 -0
- package/dist/widget/index.d.ts +3 -0
- package/dist/widget/index.d.ts.map +1 -0
- package/dist/widget/index.js +2 -0
- package/dist/widget/info-DMPChDjV.js +8 -0
- package/dist/widget/info-circle-DAvS_7nY.js +17 -0
- package/dist/widget/lightbulb-DnZ9mNEs.js +8 -0
- package/dist/widget/lit-html-BRjl1r6K.js +243 -0
- package/dist/widget/mail-DpaVSOP8.js +13 -0
- package/dist/widget/mobile-CRvdyu7I.js +14 -0
- package/dist/widget/more-C5VqW9PR.js +16 -0
- package/dist/widget/network-placeholder-CZ0vApma.js +19 -0
- package/dist/widget/nftPlaceholder-7jjIK2bT.js +13 -0
- package/dist/widget/off-4mHjJLLX.js +9 -0
- package/dist/widget/onramp-Bc0ozVsw.js +929 -0
- package/dist/widget/play-store-Uocul8nC.js +37 -0
- package/dist/widget/plus-DrYF7siO.js +18 -0
- package/dist/widget/prepareSend-BQJmzM5B.js +54987 -0
- package/dist/widget/qr-code-DcnGMUB3.js +11 -0
- package/dist/widget/receive-fvIVd7R_.js +184 -0
- package/dist/widget/recycle-horizontal-DrDwXC4D.js +14 -0
- package/dist/widget/ref-CXNmEjML.js +41 -0
- package/dist/widget/refresh-OK9lIPLS.js +13 -0
- package/dist/widget/reown-logo-C-Qn7mS3.js +17 -0
- package/dist/widget/search-DZqv1oKg.js +13 -0
- package/dist/widget/send-CJlmI-xe.js +1039 -0
- package/dist/widget/send-otoEC8uU.js +20 -0
- package/dist/widget/socials-BJciurWF.js +599 -0
- package/dist/widget/solana-Bv5Hs_0T.js +18 -0
- package/dist/widget/swapHorizontal-BzOPGV37.js +13 -0
- package/dist/widget/swapHorizontalBold-axyHnSmj.js +13 -0
- package/dist/widget/swapHorizontalMedium-C6YOPfPz.js +21 -0
- package/dist/widget/swapHorizontalRoundedBold-yVcLbWNT.js +13 -0
- package/dist/widget/swapVertical-BDjxt9pE.js +13 -0
- package/dist/widget/swaps-DEWNj4kd.js +1637 -0
- package/dist/widget/telegram-BQJD7dlP.js +21 -0
- package/dist/widget/three-dots-DW9jmSMG.js +10 -0
- package/dist/widget/transactions-uCseGQQt.js +38 -0
- package/dist/widget/twitch-XugxDfOE.js +23 -0
- package/dist/widget/twitterIcon-DQVObQUL.js +11 -0
- package/dist/widget/types.d.ts +51 -0
- package/dist/widget/types.d.ts.map +1 -0
- package/dist/widget/types.js +1 -0
- package/dist/widget/verify-DpMYHxLf.js +13 -0
- package/dist/widget/verify-filled-KpEL6ZJ_.js +13 -0
- package/dist/widget/w3m-modal-C8e-6Kba.js +1047 -0
- package/dist/widget/wallet-D8ssEB0o.js +13 -0
- package/dist/widget/wallet-placeholder-HtAy21Wc.js +19 -0
- package/dist/widget/walletconnect-Bp_4XfrY.js +37 -0
- package/dist/widget/warning-circle-FgYS7P7n.js +17 -0
- package/dist/widget/widget/index.js +7 -0
- package/dist/widget/widget.d.ts +47 -0
- package/dist/widget/widget.d.ts.map +1 -0
- package/dist/widget/widget.js +932 -0
- package/dist/widget/x-DlZBoP9k.js +17 -0
- package/dist/widget/x-mark-Ba9pt-_h.js +8 -0
- package/package.json +102 -8
- package/src/abi.ts +38 -0
- package/src/apiClient.ts +32 -0
- package/src/buffer.ts +10 -0
- package/src/cctp.ts +579 -0
- package/src/chainSwitch.ts +55 -0
- package/src/chains.ts +124 -0
- package/src/constants.ts +26 -0
- package/src/encoders.ts +20 -0
- package/src/error.ts +15 -0
- package/src/explorer.ts +37 -0
- package/src/gasless.ts +545 -0
- package/src/index.ts +48 -0
- package/src/indexerClient.ts +36 -0
- package/src/intents.ts +537 -0
- package/src/metaTxnMonitor.ts +163 -0
- package/src/metaTxns.ts +21 -0
- package/src/paymasterSend.ts +503 -0
- package/src/preconditions.ts +52 -0
- package/src/prepareSend.ts +1849 -0
- package/src/prices.ts +186 -0
- package/src/queryParams.ts +80 -0
- package/src/relaySdk.ts +481 -0
- package/src/relayer.ts +255 -0
- package/src/sendUserOp.ts +570 -0
- package/src/sequenceWallet.ts +579 -0
- package/src/theme.ts +2 -0
- package/src/toSimpleSmartAccount.ts +567 -0
- package/src/tokenBalances.ts +760 -0
- package/src/tokens.ts +471 -0
- package/src/trails.ts +1591 -0
- package/src/types.d.ts +11 -0
- package/src/umd.tsx +49 -0
- package/src/utils.ts +16 -0
- package/src/vite-env.d.ts +4 -0
- package/src/widget/assets/MetaMask-icon-fox-with-margins.svg +31 -0
- package/src/widget/assets/MetaMask-icon-fox.svg +26 -0
- package/src/widget/assets/MetaMask-logo-black.svg +3 -0
- package/src/widget/assets/MetaMask-logo-white.svg +16 -0
- package/src/widget/assets/Privy_Brandmark_Black.svg +9 -0
- package/src/widget/assets/Privy_Brandmark_White.svg +9 -0
- package/src/widget/assets/Trails-logo-black.svg +11 -0
- package/src/widget/assets/Trails-logo-white.svg +11 -0
- package/src/widget/components/ChainImage.tsx +28 -0
- package/src/widget/components/ConnectWallet.tsx +206 -0
- package/src/widget/components/DebugScreensDropdown.tsx +88 -0
- package/src/widget/components/FeeOptions.tsx +199 -0
- package/src/widget/components/Footer.tsx +51 -0
- package/src/widget/components/GreenCheckAnimation.tsx +119 -0
- package/src/widget/components/Modal.tsx +97 -0
- package/src/widget/components/Receipt.tsx +237 -0
- package/src/widget/components/SendForm.tsx +695 -0
- package/src/widget/components/TokenImage.tsx +37 -0
- package/src/widget/components/TokenList.tsx +287 -0
- package/src/widget/components/TransferPending.tsx +204 -0
- package/src/widget/components/TransferPendingVertical.tsx +412 -0
- package/src/widget/components/WalletConfirmation.tsx +172 -0
- package/src/widget/config.ts +5 -0
- package/src/widget/hooks/useAmountUsd.ts +59 -0
- package/src/widget/hooks/useSendForm.ts +715 -0
- package/src/widget/hooks/useTokenList.ts +397 -0
- package/src/widget/index.css +2 -0
- package/src/widget/index.tsx +8 -0
- package/src/widget/types/svg.d.ts +8 -0
- package/src/widget/types.ts +59 -0
- package/src/widget/widget.tsx +1438 -0
- package/index.js +0 -1
package/src/tokens.ts
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import { QueryClient, useQuery } from "@tanstack/react-query"
|
|
2
|
+
import { zeroAddress, erc20Abi } from "viem"
|
|
3
|
+
import * as chains from "viem/chains"
|
|
4
|
+
import { getChainInfo } from "./chains.js"
|
|
5
|
+
import { getRelaySupportedTokens } from "./relaySdk.js"
|
|
6
|
+
import { useReadContracts } from "wagmi"
|
|
7
|
+
import { useMemo } from "react"
|
|
8
|
+
|
|
9
|
+
export type SupportedToken = {
|
|
10
|
+
id: string
|
|
11
|
+
symbol: string
|
|
12
|
+
name: string
|
|
13
|
+
contractAddress: string
|
|
14
|
+
decimals: number
|
|
15
|
+
chainId: number
|
|
16
|
+
chainName: string
|
|
17
|
+
imageUrl: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// LocalStorage cache utilities for token images
|
|
21
|
+
const TOKEN_IMAGE_CACHE_KEY = "trails-sdk:token-image-cache"
|
|
22
|
+
const TOKEN_IMAGE_CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000 // 7 days
|
|
23
|
+
|
|
24
|
+
interface TokenImageCacheEntry {
|
|
25
|
+
imageUrl: string
|
|
26
|
+
timestamp: number
|
|
27
|
+
found: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getTokenImageCache(): Record<string, TokenImageCacheEntry> {
|
|
31
|
+
if (typeof window === "undefined") return {}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
const cached = localStorage.getItem(TOKEN_IMAGE_CACHE_KEY)
|
|
35
|
+
if (!cached) return {}
|
|
36
|
+
|
|
37
|
+
const parsed = JSON.parse(cached) as Record<string, TokenImageCacheEntry>
|
|
38
|
+
const now = Date.now()
|
|
39
|
+
|
|
40
|
+
// Clean up expired entries
|
|
41
|
+
const validEntries = Object.entries(parsed).filter(([_, entry]) => {
|
|
42
|
+
return now - entry.timestamp < TOKEN_IMAGE_CACHE_EXPIRY
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
return Object.fromEntries(validEntries) as Record<
|
|
46
|
+
string,
|
|
47
|
+
TokenImageCacheEntry
|
|
48
|
+
>
|
|
49
|
+
} catch {
|
|
50
|
+
return {}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function setTokenImageCache(
|
|
55
|
+
key: string,
|
|
56
|
+
imageUrl: string,
|
|
57
|
+
found: boolean,
|
|
58
|
+
): void {
|
|
59
|
+
if (typeof window === "undefined") return
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const cache = getTokenImageCache()
|
|
63
|
+
cache[key] = {
|
|
64
|
+
imageUrl,
|
|
65
|
+
timestamp: Date.now(),
|
|
66
|
+
found,
|
|
67
|
+
}
|
|
68
|
+
localStorage.setItem(TOKEN_IMAGE_CACHE_KEY, JSON.stringify(cache))
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.warn("[trails-sdk] Failed to cache token image:", error)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Dedicated QueryClient for token image fetching
|
|
75
|
+
const tokenImageQueryClient = new QueryClient({
|
|
76
|
+
defaultOptions: {
|
|
77
|
+
queries: {
|
|
78
|
+
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
|
79
|
+
gcTime: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
80
|
+
retry: 2,
|
|
81
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
82
|
+
refetchOnWindowFocus: false,
|
|
83
|
+
refetchOnReconnect: false,
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
// Priority tokens that should appear first in the list
|
|
89
|
+
const PRIORITY_TOKENS = [
|
|
90
|
+
"ETH",
|
|
91
|
+
"WETH",
|
|
92
|
+
"AVAX",
|
|
93
|
+
"WAVAX",
|
|
94
|
+
"xDAI",
|
|
95
|
+
"POL",
|
|
96
|
+
"USDC",
|
|
97
|
+
"USDT",
|
|
98
|
+
"DAI",
|
|
99
|
+
"MATIC",
|
|
100
|
+
"ARB",
|
|
101
|
+
"OP",
|
|
102
|
+
"BAT",
|
|
103
|
+
"WBTC",
|
|
104
|
+
"cbBTC",
|
|
105
|
+
"XAI",
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
// Sort function for tokens with the specified priority order
|
|
109
|
+
function sortTokens(tokens: SupportedToken[]): SupportedToken[] {
|
|
110
|
+
return tokens.sort((a, b) => {
|
|
111
|
+
// 1. Priority tokens first (ETH, USDC, USDT, DAI)
|
|
112
|
+
const aPriority = PRIORITY_TOKENS.indexOf(a.symbol)
|
|
113
|
+
const bPriority = PRIORITY_TOKENS.indexOf(b.symbol)
|
|
114
|
+
|
|
115
|
+
// If both are priority tokens, sort by priority order
|
|
116
|
+
if (aPriority !== -1 && bPriority !== -1) {
|
|
117
|
+
return aPriority - bPriority
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If only one is a priority token, prioritize it
|
|
121
|
+
if (aPriority !== -1) return -1
|
|
122
|
+
if (bPriority !== -1) return 1
|
|
123
|
+
|
|
124
|
+
// 2. Tokens with imageUrl before those without
|
|
125
|
+
const aHasImage = !!a.imageUrl
|
|
126
|
+
const bHasImage = !!b.imageUrl
|
|
127
|
+
|
|
128
|
+
if (aHasImage && !bHasImage) return -1
|
|
129
|
+
if (!aHasImage && bHasImage) return 1
|
|
130
|
+
|
|
131
|
+
// 3. Alphabetical by symbol
|
|
132
|
+
const symbolComparison = a.symbol.localeCompare(b.symbol)
|
|
133
|
+
if (symbolComparison !== 0) {
|
|
134
|
+
return symbolComparison
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 4. If symbols are the same, sort by chainName
|
|
138
|
+
return a.chainName.localeCompare(b.chainName)
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function getTokenImageUrlOrFallback(
|
|
143
|
+
chainId: number,
|
|
144
|
+
contractAddress: string,
|
|
145
|
+
): Promise<string> {
|
|
146
|
+
const cacheKey = `${chainId}:${contractAddress}`
|
|
147
|
+
const imageUrl = getTokenImageUrl(chainId, contractAddress)
|
|
148
|
+
|
|
149
|
+
// Check localStorage cache first
|
|
150
|
+
const cache = getTokenImageCache()
|
|
151
|
+
const cachedEntry = cache[cacheKey]
|
|
152
|
+
|
|
153
|
+
if (cachedEntry) {
|
|
154
|
+
if (cachedEntry.found) {
|
|
155
|
+
return cachedEntry.imageUrl
|
|
156
|
+
} else {
|
|
157
|
+
return "" // Return empty string if we previously found no image
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Use QueryClient to fetch and cache the result
|
|
162
|
+
try {
|
|
163
|
+
const result = await tokenImageQueryClient.fetchQuery({
|
|
164
|
+
queryKey: ["tokenImage", chainId, contractAddress],
|
|
165
|
+
queryFn: async () => {
|
|
166
|
+
const response = await fetch(imageUrl, {
|
|
167
|
+
method: "HEAD", // Only fetch headers to check if image exists
|
|
168
|
+
cache: "no-cache", // Don't cache the fetch request itself
|
|
169
|
+
})
|
|
170
|
+
const found = response.ok
|
|
171
|
+
const resultUrl = found ? imageUrl : ""
|
|
172
|
+
|
|
173
|
+
// Cache the result in localStorage
|
|
174
|
+
setTokenImageCache(cacheKey, resultUrl, found)
|
|
175
|
+
|
|
176
|
+
return resultUrl
|
|
177
|
+
},
|
|
178
|
+
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
|
179
|
+
gcTime: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return result
|
|
183
|
+
} catch (error) {
|
|
184
|
+
console.error("[trails-sdk] Error fetching token image:", error)
|
|
185
|
+
// Cache the failure to avoid repeated requests
|
|
186
|
+
setTokenImageCache(cacheKey, "", false)
|
|
187
|
+
return ""
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export async function getSupportedTokens(): Promise<SupportedToken[]> {
|
|
192
|
+
const tokens = await getRelaySupportedTokens()
|
|
193
|
+
for (const token of tokens) {
|
|
194
|
+
if (!token.imageUrl) {
|
|
195
|
+
token.imageUrl = getTokenImageUrl(token.chainId, token.contractAddress)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
getTokenImageUrlOrFallback(token.chainId, token.contractAddress)
|
|
199
|
+
.then((imageUrl) => {
|
|
200
|
+
token.imageUrl = imageUrl
|
|
201
|
+
})
|
|
202
|
+
.catch((error) => {
|
|
203
|
+
console.error("[trails-sdk] Error getting token image url:", error)
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const uniqueTokens = tokens.filter(
|
|
208
|
+
(token, index, self) =>
|
|
209
|
+
index ===
|
|
210
|
+
self.findIndex(
|
|
211
|
+
(t) =>
|
|
212
|
+
t.chainId === token.chainId &&
|
|
213
|
+
t.contractAddress === token.contractAddress,
|
|
214
|
+
),
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
// Sort tokens according to priority order
|
|
218
|
+
return sortTokens(uniqueTokens as SupportedToken[])
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function useSupportedTokens({ chainId }: { chainId?: number } = {}): {
|
|
222
|
+
supportedTokens: SupportedToken[]
|
|
223
|
+
isLoadingTokens: boolean
|
|
224
|
+
} {
|
|
225
|
+
const { data: supportedTokens = [], isLoading: isLoadingTokens } = useQuery({
|
|
226
|
+
queryKey: ["supportedTokens"],
|
|
227
|
+
queryFn: getSupportedTokens,
|
|
228
|
+
staleTime: 60 * 60 * 1000, // 1 hour - tokens rarely change
|
|
229
|
+
gcTime: 24 * 60 * 60 * 1000, // 24 hours - keep in cache for a full day
|
|
230
|
+
refetchOnWindowFocus: false, // Don't refetch when window regains focus
|
|
231
|
+
refetchOnReconnect: false, // Don't refetch on network reconnect
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const filteredTokens = useMemo(() => {
|
|
235
|
+
if (!chainId) {
|
|
236
|
+
return supportedTokens
|
|
237
|
+
}
|
|
238
|
+
return supportedTokens.filter((token) => token.chainId === chainId)
|
|
239
|
+
}, [supportedTokens, chainId])
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
supportedTokens: filteredTokens || [],
|
|
243
|
+
isLoadingTokens,
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export async function getSourceTokenList(): Promise<string[]> {
|
|
248
|
+
const tokens = await getSupportedTokens()
|
|
249
|
+
return tokens.map((token) => token.symbol)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function useSourceTokenList(): string[] {
|
|
253
|
+
const { data: list = [] } = useQuery({
|
|
254
|
+
queryKey: ["sourceTokenList"],
|
|
255
|
+
queryFn: getSourceTokenList,
|
|
256
|
+
staleTime: 1000 * 60 * 60, // 1 hour - token list rarely changes
|
|
257
|
+
gcTime: 1000 * 60 * 60 * 24, // 24 hours cache time
|
|
258
|
+
refetchOnWindowFocus: false,
|
|
259
|
+
refetchOnReconnect: false,
|
|
260
|
+
})
|
|
261
|
+
return list
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const tokenNames: Record<string, string> = {
|
|
265
|
+
ETH: "Ethereum",
|
|
266
|
+
WETH: "Wrapped ETH",
|
|
267
|
+
USDC: "USDC",
|
|
268
|
+
USDT: "Tether",
|
|
269
|
+
DAI: "Dai Stablecoin",
|
|
270
|
+
OP: "Optimism",
|
|
271
|
+
ARB: "Arbitrum",
|
|
272
|
+
POL: "POL",
|
|
273
|
+
MATIC: "Matic Token",
|
|
274
|
+
BAT: "Basic Attention Token",
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export const tokensToPrefix: Record<string, string> = {
|
|
278
|
+
USDC: "USDC",
|
|
279
|
+
ETH: "ETH",
|
|
280
|
+
POL: "POL",
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export const tokenNamePrefixes: Record<string, string> = {
|
|
284
|
+
[chains.optimism.id]: "Optimistic",
|
|
285
|
+
[chains.arbitrum.id]: "Arbitrum",
|
|
286
|
+
[chains.polygon.id]: "Polygon",
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export function getFormatttedTokenName(
|
|
290
|
+
currentName: string,
|
|
291
|
+
tokenSymbol: string,
|
|
292
|
+
chainId?: number,
|
|
293
|
+
): string {
|
|
294
|
+
let name = tokenNames[tokenSymbol] || currentName || tokenSymbol
|
|
295
|
+
if (chainId) {
|
|
296
|
+
try {
|
|
297
|
+
const chainInfo = getChainInfo(chainId)
|
|
298
|
+
if (chainInfo) {
|
|
299
|
+
if (tokensToPrefix[tokenSymbol]) {
|
|
300
|
+
if (chainId !== chains.mainnet.id) {
|
|
301
|
+
name = `${chainInfo?.name} ${tokenSymbol}`
|
|
302
|
+
}
|
|
303
|
+
const prefix = tokenNamePrefixes[chainId]
|
|
304
|
+
if (prefix) {
|
|
305
|
+
name = `${prefix} ${tokenSymbol}`
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} catch (e) {
|
|
310
|
+
console.error("[trails-sdk] Error getting chain info:", e)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return name
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export async function getTokenAddress(chainId: number, tokenSymbol: string) {
|
|
317
|
+
const chainInfo = getChainInfo(chainId)
|
|
318
|
+
if (tokenSymbol === chainInfo?.nativeCurrency.symbol) {
|
|
319
|
+
return zeroAddress
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const tokens = await getSupportedTokens()
|
|
323
|
+
const token = tokens.find(
|
|
324
|
+
(t) => t.symbol === tokenSymbol && t.chainId === chainId,
|
|
325
|
+
)
|
|
326
|
+
if (token?.contractAddress) {
|
|
327
|
+
return token.contractAddress
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
throw new Error(
|
|
331
|
+
`Unsupported token symbol: ${tokenSymbol} for chainId: ${chainId}`,
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
type UseTokenAddressProps = {
|
|
336
|
+
chainId?: number | null
|
|
337
|
+
tokenSymbol?: string | null
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export function useTokenAddress({
|
|
341
|
+
chainId,
|
|
342
|
+
tokenSymbol,
|
|
343
|
+
}: UseTokenAddressProps) {
|
|
344
|
+
const { data: tokenAddress } = useQuery({
|
|
345
|
+
queryKey: ["tokenAddress", chainId, tokenSymbol],
|
|
346
|
+
queryFn: () =>
|
|
347
|
+
chainId && tokenSymbol ? getTokenAddress(chainId, tokenSymbol) : null,
|
|
348
|
+
enabled: !!chainId && !!tokenSymbol,
|
|
349
|
+
staleTime: 60 * 60 * 1000, // 1 hour - token addresses rarely change
|
|
350
|
+
gcTime: 24 * 60 * 60 * 1000, // 24 hours - keep in cache for a full day
|
|
351
|
+
refetchOnWindowFocus: false, // Don't refetch when window regains focus
|
|
352
|
+
refetchOnReconnect: false, // Don't refetch on network reconnect
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
return tokenAddress || null
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function getTokenImageUrl(chainId: number, contractAddress: string) {
|
|
359
|
+
const imageUrl = `https://assets.sequence.info/images/tokens/large/${chainId}/${contractAddress}.webp`
|
|
360
|
+
return imageUrl
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// React hook for token image fetching with caching
|
|
364
|
+
export function useTokenImageUrl(
|
|
365
|
+
chainId: number | undefined,
|
|
366
|
+
contractAddress: string | undefined,
|
|
367
|
+
) {
|
|
368
|
+
const {
|
|
369
|
+
data: imageUrl = "",
|
|
370
|
+
isLoading,
|
|
371
|
+
error,
|
|
372
|
+
} = useQuery({
|
|
373
|
+
queryKey: ["tokenImage", chainId, contractAddress],
|
|
374
|
+
queryFn: () => getTokenImageUrlOrFallback(chainId!, contractAddress!),
|
|
375
|
+
enabled: !!chainId && !!contractAddress,
|
|
376
|
+
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
|
377
|
+
gcTime: 7 * 24 * 60 * 60 * 1000, // 7 days
|
|
378
|
+
retry: 2,
|
|
379
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000),
|
|
380
|
+
refetchOnWindowFocus: false,
|
|
381
|
+
refetchOnReconnect: false,
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
return {
|
|
385
|
+
imageUrl,
|
|
386
|
+
isLoading,
|
|
387
|
+
error,
|
|
388
|
+
hasImage: !!imageUrl,
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
export function useTokenList() {
|
|
393
|
+
const { supportedTokens: tokens, isLoadingTokens } = useSupportedTokens()
|
|
394
|
+
|
|
395
|
+
return {
|
|
396
|
+
tokens,
|
|
397
|
+
isLoadingTokens: isLoadingTokens,
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
export function useTokenInfo({
|
|
402
|
+
address,
|
|
403
|
+
chainId,
|
|
404
|
+
}: {
|
|
405
|
+
address: string
|
|
406
|
+
chainId?: number
|
|
407
|
+
}): {
|
|
408
|
+
tokenInfo: Partial<SupportedToken> | null
|
|
409
|
+
isLoading: boolean
|
|
410
|
+
error: Error | null
|
|
411
|
+
} {
|
|
412
|
+
const isAddress = address?.startsWith("0x") ?? false
|
|
413
|
+
|
|
414
|
+
if (!isAddress || !chainId) {
|
|
415
|
+
return {
|
|
416
|
+
tokenInfo: null,
|
|
417
|
+
isLoading: false,
|
|
418
|
+
error: null,
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const contract = {
|
|
423
|
+
address: address as `0x${string}`,
|
|
424
|
+
abi: erc20Abi,
|
|
425
|
+
chainId,
|
|
426
|
+
} as const
|
|
427
|
+
|
|
428
|
+
const result = useReadContracts({
|
|
429
|
+
contracts: [
|
|
430
|
+
{ ...contract, functionName: "name" },
|
|
431
|
+
{ ...contract, functionName: "symbol" },
|
|
432
|
+
{ ...contract, functionName: "decimals" },
|
|
433
|
+
],
|
|
434
|
+
})
|
|
435
|
+
|
|
436
|
+
const error =
|
|
437
|
+
result?.error ?? result?.data?.find((r) => r.error)?.error ?? null
|
|
438
|
+
|
|
439
|
+
const [name, symbol, decimals] = result.data ?? []
|
|
440
|
+
const chainInfo = getChainInfo(chainId)
|
|
441
|
+
|
|
442
|
+
const tokenInfo = useMemo(() => {
|
|
443
|
+
if (!symbol?.result || !name?.result || decimals?.result == null) {
|
|
444
|
+
return null
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return {
|
|
448
|
+
id: symbol.result,
|
|
449
|
+
name: name.result,
|
|
450
|
+
symbol: symbol.result,
|
|
451
|
+
decimals: decimals.result,
|
|
452
|
+
chainId,
|
|
453
|
+
contractAddress: address,
|
|
454
|
+
chainName: chainInfo?.name ?? "",
|
|
455
|
+
imageUrl: "",
|
|
456
|
+
}
|
|
457
|
+
}, [
|
|
458
|
+
address,
|
|
459
|
+
chainId,
|
|
460
|
+
chainInfo?.name,
|
|
461
|
+
name?.result,
|
|
462
|
+
symbol?.result,
|
|
463
|
+
decimals?.result,
|
|
464
|
+
])
|
|
465
|
+
|
|
466
|
+
return {
|
|
467
|
+
tokenInfo,
|
|
468
|
+
isLoading: result.isLoading,
|
|
469
|
+
error: error,
|
|
470
|
+
}
|
|
471
|
+
}
|