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
|
@@ -0,0 +1,1080 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { createPublicClient, createWalletClient, decodeFunctionData, erc20Abi, formatUnits, http, parseUnits, zeroAddress, } from "viem";
|
|
3
|
+
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
|
4
|
+
import { useAPIClient } from "./apiClient.js";
|
|
5
|
+
import { cctpTransfer, getIsUsdcAddress, getMessageTransmitter, getMintUSDCData, } from "./cctp.js";
|
|
6
|
+
import { attemptSwitchChain } from "./chainSwitch.js";
|
|
7
|
+
import { getChainInfo, getTestnetChainInfo } from "./chains.js";
|
|
8
|
+
import { intentEntrypoints, DEFAULT_USE_V3_RELAYERS } from "./constants.js";
|
|
9
|
+
import { getERC20TransferData } from "./encoders.js";
|
|
10
|
+
import { getExplorerUrl } from "./explorer.js";
|
|
11
|
+
import { getDepositToIntentCalls, getPermitCalls, getPermitSignature, } from "./gasless.js";
|
|
12
|
+
import { useIndexerGatewayClient } from "./indexerClient.js";
|
|
13
|
+
import { commitIntentConfig, getIntentCallsPayloads as getIntentCallsPayloadsFromIntents, sendOriginTransaction, } from "./intents.js";
|
|
14
|
+
import { getMetaTxStatus } from "./metaTxnMonitor.js";
|
|
15
|
+
import { relayerSendMetaTx } from "./metaTxns.js";
|
|
16
|
+
import { getDelegatorSmartAccount, getPaymasterGaslessTransaction, sendPaymasterGaslessTransaction, } from "./paymasterSend.js";
|
|
17
|
+
import { findFirstPreconditionForChainId } from "./preconditions.js";
|
|
18
|
+
import { useTokenPrice } from "./prices.js";
|
|
19
|
+
import { getQueryParam } from "./queryParams.js";
|
|
20
|
+
import { useRelayers } from "./relayer.js";
|
|
21
|
+
import { executeSimpleRelayTransaction, getRelaySDKQuote, getTxHashFromRelayResult, } from "./relaySdk.js";
|
|
22
|
+
import { getFeeOptions, sequenceSendTransaction, simpleCreateSequenceWallet, } from "./sequenceWallet.js";
|
|
23
|
+
import { useAccountTokenBalance } from "./tokenBalances.js";
|
|
24
|
+
import { useSupportedTokens } from "./tokens.js";
|
|
25
|
+
import { requestWithTimeout } from "./utils.js";
|
|
26
|
+
export function getIsToSameChain(originChainId, destinationChainId) {
|
|
27
|
+
return originChainId?.toString() === destinationChainId?.toString();
|
|
28
|
+
}
|
|
29
|
+
export function getIsToSameToken(originTokenAddress, destinationTokenAddress) {
|
|
30
|
+
return (originTokenAddress?.toLowerCase() === destinationTokenAddress?.toLowerCase());
|
|
31
|
+
}
|
|
32
|
+
export function getIsToSameChainAndToken(originChainId, originTokenAddress, destinationChainId, destinationTokenAddress) {
|
|
33
|
+
return (getIsToSameChain(originChainId, destinationChainId) &&
|
|
34
|
+
getIsToSameToken(originTokenAddress, destinationTokenAddress));
|
|
35
|
+
}
|
|
36
|
+
export function getUseCctp(originTokenAddress, destinationTokenAddress, originChainId, destinationChainId) {
|
|
37
|
+
return (getIsUsdcAddress(originTokenAddress, originChainId) &&
|
|
38
|
+
getIsUsdcAddress(destinationTokenAddress, destinationChainId));
|
|
39
|
+
}
|
|
40
|
+
function isTestnetDebugMode() {
|
|
41
|
+
return getQueryParam("testnet") === "true";
|
|
42
|
+
}
|
|
43
|
+
function getTestnetOriginTokenAddress() {
|
|
44
|
+
return "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
45
|
+
}
|
|
46
|
+
function getIntentArgs(mainSignerAddress, originChainId, originTokenAddress, originTokenAmount, destinationChainId, destinationTokenAddress, destinationTokenAmount, destinationTokenSymbol, recipient, destinationCalldata) {
|
|
47
|
+
const _destinationCalldata = destinationCalldata ||
|
|
48
|
+
(destinationTokenAddress === zeroAddress
|
|
49
|
+
? "0x"
|
|
50
|
+
: getERC20TransferData({
|
|
51
|
+
recipient,
|
|
52
|
+
amount: BigInt(destinationTokenAmount),
|
|
53
|
+
}));
|
|
54
|
+
const _destinationToAddress = destinationCalldata
|
|
55
|
+
? recipient
|
|
56
|
+
: destinationTokenAddress === zeroAddress
|
|
57
|
+
? recipient
|
|
58
|
+
: destinationTokenAddress;
|
|
59
|
+
const _destinationCallValue = destinationTokenAddress === zeroAddress ? destinationTokenAmount : "0";
|
|
60
|
+
const intentArgs = {
|
|
61
|
+
userAddress: mainSignerAddress,
|
|
62
|
+
originChainId,
|
|
63
|
+
originTokenAddress,
|
|
64
|
+
originTokenAmount: originTokenAddress === destinationTokenAddress
|
|
65
|
+
? destinationTokenAmount
|
|
66
|
+
: originTokenAmount, // max amount
|
|
67
|
+
destinationChainId,
|
|
68
|
+
destinationToAddress: _destinationToAddress,
|
|
69
|
+
destinationTokenAddress: destinationTokenAddress,
|
|
70
|
+
destinationTokenAmount: destinationTokenAmount,
|
|
71
|
+
destinationTokenSymbol: destinationTokenSymbol,
|
|
72
|
+
destinationCallData: _destinationCalldata,
|
|
73
|
+
destinationCallValue: _destinationCallValue,
|
|
74
|
+
};
|
|
75
|
+
return intentArgs;
|
|
76
|
+
}
|
|
77
|
+
export async function prepareSend(options) {
|
|
78
|
+
const { account, originTokenAddress, originChainId, originTokenAmount, // account balance
|
|
79
|
+
destinationChainId, recipient, destinationTokenAddress, destinationTokenAmount, destinationTokenSymbol, fee, client: walletClient, dryMode = false, apiClient, originRelayer, destinationRelayer, destinationCalldata, onTransactionStateChange, sourceTokenPriceUsd, destinationTokenPriceUsd, sourceTokenDecimals, destinationTokenDecimals, paymasterUrl, gasless = false, relayerConfig, sequenceProjectAccessKey, } = options;
|
|
80
|
+
if (!walletClient) {
|
|
81
|
+
throw new Error("Wallet client not provided");
|
|
82
|
+
}
|
|
83
|
+
const chain = getChainInfo(originChainId);
|
|
84
|
+
if (!chain) {
|
|
85
|
+
throw new Error(`Chain ${originChainId} not found`);
|
|
86
|
+
}
|
|
87
|
+
const isToSameChain = getIsToSameChain(originChainId, destinationChainId);
|
|
88
|
+
const isToSameToken = getIsToSameToken(originTokenAddress, destinationTokenAddress);
|
|
89
|
+
console.log("[trails-sdk] isToSameChain", isToSameChain);
|
|
90
|
+
console.log("[trails-sdk] isToSameToken", isToSameToken);
|
|
91
|
+
const publicClient = createPublicClient({
|
|
92
|
+
chain,
|
|
93
|
+
transport: http(),
|
|
94
|
+
});
|
|
95
|
+
const mainSignerAddress = account.address;
|
|
96
|
+
const transactionStates = [];
|
|
97
|
+
// origin tx
|
|
98
|
+
transactionStates.push({
|
|
99
|
+
transactionHash: "",
|
|
100
|
+
explorerUrl: "",
|
|
101
|
+
chainId: originChainId,
|
|
102
|
+
state: "pending",
|
|
103
|
+
label: isToSameChain && isToSameToken
|
|
104
|
+
? "Execute"
|
|
105
|
+
: isToSameChain && !isToSameToken
|
|
106
|
+
? "Swap"
|
|
107
|
+
: "Transfer",
|
|
108
|
+
});
|
|
109
|
+
if (!isToSameChain) {
|
|
110
|
+
// swap + bridge tx
|
|
111
|
+
transactionStates.push({
|
|
112
|
+
transactionHash: "",
|
|
113
|
+
explorerUrl: "",
|
|
114
|
+
chainId: originChainId,
|
|
115
|
+
state: "pending",
|
|
116
|
+
label: isToSameToken ? "Bridge" : "Swap & Bridge",
|
|
117
|
+
});
|
|
118
|
+
// destination tx
|
|
119
|
+
transactionStates.push({
|
|
120
|
+
transactionHash: "",
|
|
121
|
+
explorerUrl: "",
|
|
122
|
+
chainId: destinationChainId,
|
|
123
|
+
state: "pending",
|
|
124
|
+
label: "Execute",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
if (isToSameChain && !isToSameToken) {
|
|
128
|
+
return await sendHandlerForSameChainDifferentToken({
|
|
129
|
+
originTokenAddress,
|
|
130
|
+
destinationTokenAmount,
|
|
131
|
+
destinationTokenAddress,
|
|
132
|
+
destinationCalldata,
|
|
133
|
+
recipient,
|
|
134
|
+
originChainId,
|
|
135
|
+
walletClient,
|
|
136
|
+
publicClient,
|
|
137
|
+
account,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
if (isToSameToken && isToSameChain) {
|
|
141
|
+
return await sendHandlerForSameChainSameToken({
|
|
142
|
+
originTokenAddress,
|
|
143
|
+
destinationTokenAmount,
|
|
144
|
+
destinationCalldata,
|
|
145
|
+
recipient,
|
|
146
|
+
originChainId,
|
|
147
|
+
walletClient,
|
|
148
|
+
publicClient,
|
|
149
|
+
onTransactionStateChange,
|
|
150
|
+
dryMode,
|
|
151
|
+
account,
|
|
152
|
+
chain,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return await sendHandlerForDifferentChainDifferentToken({
|
|
156
|
+
mainSignerAddress,
|
|
157
|
+
originChainId,
|
|
158
|
+
originTokenAddress,
|
|
159
|
+
originTokenAmount,
|
|
160
|
+
destinationChainId,
|
|
161
|
+
destinationTokenAddress,
|
|
162
|
+
destinationTokenAmount,
|
|
163
|
+
destinationTokenSymbol,
|
|
164
|
+
recipient,
|
|
165
|
+
destinationCalldata,
|
|
166
|
+
apiClient,
|
|
167
|
+
sourceTokenPriceUsd,
|
|
168
|
+
destinationTokenPriceUsd,
|
|
169
|
+
sourceTokenDecimals,
|
|
170
|
+
destinationTokenDecimals,
|
|
171
|
+
gasless,
|
|
172
|
+
paymasterUrl,
|
|
173
|
+
originRelayer,
|
|
174
|
+
destinationRelayer,
|
|
175
|
+
sequenceProjectAccessKey,
|
|
176
|
+
relayerConfig,
|
|
177
|
+
walletClient,
|
|
178
|
+
publicClient,
|
|
179
|
+
chain,
|
|
180
|
+
account,
|
|
181
|
+
fee,
|
|
182
|
+
dryMode,
|
|
183
|
+
onTransactionStateChange,
|
|
184
|
+
transactionStates,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
async function sendHandlerForDifferentChainDifferentToken({ mainSignerAddress, originChainId, originTokenAddress, originTokenAmount, destinationChainId, destinationTokenAddress, destinationTokenAmount, destinationTokenSymbol, recipient, destinationCalldata, apiClient, sourceTokenPriceUsd, destinationTokenPriceUsd, sourceTokenDecimals, destinationTokenDecimals, gasless, paymasterUrl, originRelayer, destinationRelayer, sequenceProjectAccessKey, relayerConfig, walletClient, publicClient, chain, account, fee, dryMode, onTransactionStateChange, transactionStates, }) {
|
|
188
|
+
const testnet = isTestnetDebugMode();
|
|
189
|
+
const useCctp = getUseCctp(originTokenAddress, destinationTokenAddress, originChainId, destinationChainId);
|
|
190
|
+
if (useCctp && testnet) {
|
|
191
|
+
const amount = destinationTokenAmount;
|
|
192
|
+
return {
|
|
193
|
+
intentAddress: "",
|
|
194
|
+
originSendAmount: amount,
|
|
195
|
+
send: async (onOriginSend) => {
|
|
196
|
+
const originChain = testnet ? getTestnetChainInfo(chain) : chain;
|
|
197
|
+
const destinationChain = testnet
|
|
198
|
+
? getTestnetChainInfo(destinationChainId)
|
|
199
|
+
: getChainInfo(destinationChainId);
|
|
200
|
+
if (!originChain || !destinationChain) {
|
|
201
|
+
throw new Error("Invalid chain");
|
|
202
|
+
}
|
|
203
|
+
console.log("[trails-sdk] originChain", originChain);
|
|
204
|
+
console.log("[trails-sdk] destinationChain", destinationChain);
|
|
205
|
+
const originPublicClient = createPublicClient({
|
|
206
|
+
chain: originChain,
|
|
207
|
+
transport: http(),
|
|
208
|
+
});
|
|
209
|
+
const { txHash, attestation } = await cctpTransfer({
|
|
210
|
+
walletClient,
|
|
211
|
+
originChain,
|
|
212
|
+
destinationChain,
|
|
213
|
+
amount: BigInt(destinationTokenAmount),
|
|
214
|
+
});
|
|
215
|
+
if (!attestation) {
|
|
216
|
+
throw new Error("Failed to retrieve attestation");
|
|
217
|
+
}
|
|
218
|
+
if (onOriginSend) {
|
|
219
|
+
onOriginSend();
|
|
220
|
+
}
|
|
221
|
+
console.log("[trails-sdk] waiting for tx", txHash);
|
|
222
|
+
const receipt = await originPublicClient.waitForTransactionReceipt({
|
|
223
|
+
hash: txHash,
|
|
224
|
+
});
|
|
225
|
+
console.log("[trails-sdk] tx receipt", receipt);
|
|
226
|
+
transactionStates[0] = getTransactionStateFromReceipt(receipt, originChain.id, "Transfer");
|
|
227
|
+
transactionStates[1] = getTransactionStateFromReceipt(receipt, originChain.id, "Bridge");
|
|
228
|
+
onTransactionStateChange(transactionStates);
|
|
229
|
+
const tokenMessenger = getMessageTransmitter(destinationChain.id);
|
|
230
|
+
console.log("[trails-sdk] tokenMessenger", tokenMessenger);
|
|
231
|
+
const calls = [
|
|
232
|
+
await getMintUSDCData({
|
|
233
|
+
tokenMessenger,
|
|
234
|
+
attestation,
|
|
235
|
+
}),
|
|
236
|
+
];
|
|
237
|
+
console.log("[trails-sdk] calls", calls);
|
|
238
|
+
const delegatorPrivateKey = generatePrivateKey();
|
|
239
|
+
const delegatorAccount = privateKeyToAccount(delegatorPrivateKey);
|
|
240
|
+
const delegatorClient = createWalletClient({
|
|
241
|
+
account: delegatorAccount,
|
|
242
|
+
chain: destinationChain,
|
|
243
|
+
transport: http(),
|
|
244
|
+
});
|
|
245
|
+
const destinationPublicClient = createPublicClient({
|
|
246
|
+
chain: destinationChain,
|
|
247
|
+
transport: http(),
|
|
248
|
+
});
|
|
249
|
+
console.log("[trails-sdk] delegatorClient", delegatorClient);
|
|
250
|
+
const sequenceWalletAddress = await simpleCreateSequenceWallet(delegatorAccount, relayerConfig, sequenceProjectAccessKey);
|
|
251
|
+
console.log("[trails-sdk] sequenceWalletAddress", sequenceWalletAddress);
|
|
252
|
+
const sequenceTxHash = await sequenceSendTransaction(sequenceWalletAddress, delegatorClient, destinationPublicClient, calls, destinationChain, relayerConfig, sequenceProjectAccessKey);
|
|
253
|
+
const destinationReceipt = await destinationPublicClient.waitForTransactionReceipt({
|
|
254
|
+
hash: sequenceTxHash,
|
|
255
|
+
});
|
|
256
|
+
console.log("[trails-sdk] destinationReceipt", destinationReceipt);
|
|
257
|
+
transactionStates[2] = getTransactionStateFromReceipt(destinationReceipt, destinationChain.id, "Receive");
|
|
258
|
+
onTransactionStateChange(transactionStates);
|
|
259
|
+
return {
|
|
260
|
+
originUserTxReceipt: receipt,
|
|
261
|
+
originMetaTxnReceipt: null,
|
|
262
|
+
destinationMetaTxnReceipt: null,
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const intentArgs = getIntentArgs(mainSignerAddress, originChainId, originTokenAddress, originTokenAmount, destinationChainId, destinationTokenAddress, destinationTokenAmount, destinationTokenSymbol, recipient, destinationCalldata);
|
|
268
|
+
console.log("[trails-sdk] Creating intent with args:", intentArgs);
|
|
269
|
+
const intent = await getIntentCallsPayloadsFromIntents(apiClient, intentArgs);
|
|
270
|
+
console.log("[trails-sdk] Got intent:", intent);
|
|
271
|
+
if (!intent) {
|
|
272
|
+
throw new Error("Invalid intent");
|
|
273
|
+
}
|
|
274
|
+
if (!intent.preconditions?.length || !intent.calls?.length) {
|
|
275
|
+
throw new Error("Invalid intent");
|
|
276
|
+
}
|
|
277
|
+
const intentAddress = intent.originIntentAddress;
|
|
278
|
+
console.log("[trails-sdk] intent address:", intentAddress.toString());
|
|
279
|
+
await commitIntentConfig(apiClient, mainSignerAddress, intent.calls, intent.preconditions);
|
|
280
|
+
console.log("[trails-sdk] Committed intent config");
|
|
281
|
+
const firstPrecondition = findFirstPreconditionForChainId(intent.preconditions, originChainId);
|
|
282
|
+
if (!firstPrecondition) {
|
|
283
|
+
throw new Error("No precondition found for origin chain");
|
|
284
|
+
}
|
|
285
|
+
const firstPreconditionMin = firstPrecondition?.data?.min?.toString();
|
|
286
|
+
const depositAmount = firstPreconditionMin;
|
|
287
|
+
const hasEnoughBalance = await checkAccountBalance({
|
|
288
|
+
account,
|
|
289
|
+
tokenAddress: originTokenAddress,
|
|
290
|
+
depositAmount,
|
|
291
|
+
publicClient,
|
|
292
|
+
});
|
|
293
|
+
if (!hasEnoughBalance) {
|
|
294
|
+
throw new Error("Account does not have enough balance for deposit");
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
intentAddress,
|
|
298
|
+
originSendAmount: depositAmount,
|
|
299
|
+
send: async (onOriginSend) => {
|
|
300
|
+
console.log("[trails-sdk] sending origin transaction");
|
|
301
|
+
const needsNativeFee = getNeedsLifiNativeFee({
|
|
302
|
+
originTokenAddress,
|
|
303
|
+
destinationTokenAmount,
|
|
304
|
+
destinationTokenDecimals,
|
|
305
|
+
sourceTokenDecimals,
|
|
306
|
+
sourceTokenPriceUsd: sourceTokenPriceUsd ?? null,
|
|
307
|
+
destinationTokenPriceUsd: destinationTokenPriceUsd ?? null,
|
|
308
|
+
depositAmount,
|
|
309
|
+
});
|
|
310
|
+
console.log("[trails-sdk] needsNativeFee", needsNativeFee);
|
|
311
|
+
console.log("[trails-sdk] sourceTokenPriceUsd", sourceTokenPriceUsd);
|
|
312
|
+
console.log("[trails-sdk] destinationTokenPriceUsd", destinationTokenPriceUsd);
|
|
313
|
+
console.log("[trails-sdk] sourceTokenDecimals", sourceTokenDecimals);
|
|
314
|
+
console.log("[trails-sdk] destinationTokenDecimals", destinationTokenDecimals);
|
|
315
|
+
// const originCallParams = {
|
|
316
|
+
// to:
|
|
317
|
+
// originTokenAddress === zeroAddress
|
|
318
|
+
// ? firstPreconditionAddress
|
|
319
|
+
// : originTokenAddress,
|
|
320
|
+
// data:
|
|
321
|
+
// originTokenAddress === zeroAddress
|
|
322
|
+
// ? "0x"
|
|
323
|
+
// : getERC20TransferData({
|
|
324
|
+
// recipient: firstPreconditionAddress,
|
|
325
|
+
// amount: BigInt(firstPreconditionMin) + BigInt(fee),
|
|
326
|
+
// }),
|
|
327
|
+
// value:
|
|
328
|
+
// originTokenAddress === zeroAddress
|
|
329
|
+
// ? BigInt(firstPreconditionMin) + BigInt(fee)
|
|
330
|
+
// : "0",
|
|
331
|
+
// chainId: originChainId,
|
|
332
|
+
// chain,
|
|
333
|
+
// }
|
|
334
|
+
let originUserTxReceipt = null;
|
|
335
|
+
let originMetaTxnReceipt = null;
|
|
336
|
+
let destinationMetaTxnReceipt = null;
|
|
337
|
+
const testnet = isTestnetDebugMode();
|
|
338
|
+
const testnetOriginTokenAddress = getTestnetOriginTokenAddress();
|
|
339
|
+
const chainToUse = testnet ? getTestnetChainInfo(chain) : chain;
|
|
340
|
+
console.log("[trails-sdk] testnet", testnet);
|
|
341
|
+
originUserTxReceipt = await attemptUserDepositTx({
|
|
342
|
+
originTokenAddress: testnet
|
|
343
|
+
? testnetOriginTokenAddress
|
|
344
|
+
: originTokenAddress,
|
|
345
|
+
gasless,
|
|
346
|
+
paymasterUrl,
|
|
347
|
+
chain: chainToUse,
|
|
348
|
+
account,
|
|
349
|
+
relayerConfig,
|
|
350
|
+
sequenceProjectAccessKey,
|
|
351
|
+
originRelayer,
|
|
352
|
+
firstPreconditionMin,
|
|
353
|
+
intentAddress,
|
|
354
|
+
onOriginSend,
|
|
355
|
+
publicClient,
|
|
356
|
+
walletClient,
|
|
357
|
+
destinationTokenDecimals,
|
|
358
|
+
sourceTokenDecimals,
|
|
359
|
+
fee,
|
|
360
|
+
dryMode,
|
|
361
|
+
sourceTokenPriceUsd: sourceTokenPriceUsd ?? null,
|
|
362
|
+
destinationTokenPriceUsd: destinationTokenPriceUsd ?? null,
|
|
363
|
+
destinationTokenAmount,
|
|
364
|
+
});
|
|
365
|
+
if (!originUserTxReceipt) {
|
|
366
|
+
throw new Error("Failed to send origin transaction");
|
|
367
|
+
}
|
|
368
|
+
transactionStates[0] = getTransactionStateFromReceipt(originUserTxReceipt, originChainId, "Transfer");
|
|
369
|
+
onTransactionStateChange(transactionStates);
|
|
370
|
+
if (intent.metaTxns[0] && intent.preconditions[0]) {
|
|
371
|
+
originMetaTxnReceipt = await sendMetaTxAndWaitForReceipt({
|
|
372
|
+
metaTx: intent.metaTxns[0],
|
|
373
|
+
relayer: originRelayer,
|
|
374
|
+
precondition: intent.preconditions[0],
|
|
375
|
+
});
|
|
376
|
+
if (originMetaTxnReceipt) {
|
|
377
|
+
transactionStates[1] = getTransactionStateFromReceipt(originMetaTxnReceipt, originChainId, "Swap & Bridge");
|
|
378
|
+
onTransactionStateChange(transactionStates);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (intent.metaTxns[1] && intent.preconditions[1]) {
|
|
382
|
+
destinationMetaTxnReceipt = await sendMetaTxAndWaitForReceipt({
|
|
383
|
+
metaTx: intent.metaTxns[1],
|
|
384
|
+
relayer: destinationRelayer,
|
|
385
|
+
precondition: intent.preconditions[1],
|
|
386
|
+
});
|
|
387
|
+
if (destinationMetaTxnReceipt) {
|
|
388
|
+
transactionStates[2] = getTransactionStateFromReceipt(destinationMetaTxnReceipt, destinationChainId, "Execute");
|
|
389
|
+
onTransactionStateChange(transactionStates);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
originUserTxReceipt,
|
|
394
|
+
originMetaTxnReceipt,
|
|
395
|
+
destinationMetaTxnReceipt,
|
|
396
|
+
};
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
async function sendHandlerForSameChainSameToken({ originTokenAddress, destinationTokenAmount, destinationCalldata, recipient, originChainId, walletClient, publicClient, onTransactionStateChange, dryMode, account, chain, }) {
|
|
401
|
+
console.log("[trails-sdk] isToSameToken && isToSameChain");
|
|
402
|
+
const hasEnoughBalance = await checkAccountBalance({
|
|
403
|
+
account,
|
|
404
|
+
tokenAddress: originTokenAddress,
|
|
405
|
+
depositAmount: destinationTokenAmount,
|
|
406
|
+
publicClient,
|
|
407
|
+
});
|
|
408
|
+
if (!hasEnoughBalance) {
|
|
409
|
+
throw new Error("Account does not have enough balance for deposit");
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
originSendAmount: destinationTokenAmount,
|
|
413
|
+
send: async (onOriginSend) => {
|
|
414
|
+
const originCallParams = {
|
|
415
|
+
to: destinationCalldata
|
|
416
|
+
? recipient
|
|
417
|
+
: originTokenAddress === zeroAddress
|
|
418
|
+
? recipient
|
|
419
|
+
: originTokenAddress,
|
|
420
|
+
data: destinationCalldata ||
|
|
421
|
+
(originTokenAddress === zeroAddress
|
|
422
|
+
? "0x"
|
|
423
|
+
: getERC20TransferData({
|
|
424
|
+
recipient,
|
|
425
|
+
amount: BigInt(destinationTokenAmount),
|
|
426
|
+
})),
|
|
427
|
+
value: originTokenAddress === zeroAddress
|
|
428
|
+
? BigInt(destinationTokenAmount)
|
|
429
|
+
: "0",
|
|
430
|
+
chainId: originChainId,
|
|
431
|
+
chain,
|
|
432
|
+
};
|
|
433
|
+
console.log("[trails-sdk] origin call params", originCallParams);
|
|
434
|
+
let originUserTxReceipt = null;
|
|
435
|
+
const originMetaTxnReceipt = null;
|
|
436
|
+
const destinationMetaTxnReceipt = null;
|
|
437
|
+
await attemptSwitchChain({
|
|
438
|
+
walletClient,
|
|
439
|
+
desiredChainId: originChainId,
|
|
440
|
+
});
|
|
441
|
+
if (!dryMode) {
|
|
442
|
+
onTransactionStateChange([
|
|
443
|
+
{
|
|
444
|
+
transactionHash: "",
|
|
445
|
+
explorerUrl: "",
|
|
446
|
+
chainId: originChainId,
|
|
447
|
+
state: "pending",
|
|
448
|
+
label: "Execute",
|
|
449
|
+
},
|
|
450
|
+
]);
|
|
451
|
+
console.log("[trails-sdk] origin call params", originCallParams);
|
|
452
|
+
const txHash = await sendOriginTransaction(account, walletClient, originCallParams); // TODO: Add proper type
|
|
453
|
+
console.log("[trails-sdk] origin tx", txHash);
|
|
454
|
+
if (onOriginSend) {
|
|
455
|
+
onOriginSend();
|
|
456
|
+
}
|
|
457
|
+
// Wait for transaction receipt
|
|
458
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
459
|
+
hash: txHash,
|
|
460
|
+
});
|
|
461
|
+
console.log("[trails-sdk] receipt", receipt);
|
|
462
|
+
originUserTxReceipt = receipt;
|
|
463
|
+
onTransactionStateChange([
|
|
464
|
+
getTransactionStateFromReceipt(originUserTxReceipt, originChainId, "Swap"),
|
|
465
|
+
]);
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
originUserTxReceipt,
|
|
469
|
+
originMetaTxnReceipt,
|
|
470
|
+
destinationMetaTxnReceipt,
|
|
471
|
+
};
|
|
472
|
+
},
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
async function sendHandlerForSameChainDifferentToken({ originTokenAddress, destinationTokenAmount, destinationTokenAddress, destinationCalldata, recipient, originChainId, walletClient, publicClient, account, }) {
|
|
476
|
+
const destinationTxs = [];
|
|
477
|
+
if (destinationCalldata) {
|
|
478
|
+
destinationTxs.push({
|
|
479
|
+
to: recipient,
|
|
480
|
+
value: destinationTokenAddress === zeroAddress ? destinationTokenAmount : "0",
|
|
481
|
+
data: destinationCalldata,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
const quote = await getRelaySDKQuote({
|
|
485
|
+
wallet: walletClient,
|
|
486
|
+
chainId: originChainId,
|
|
487
|
+
amount: destinationTokenAmount,
|
|
488
|
+
currency: originTokenAddress,
|
|
489
|
+
toCurrency: destinationTokenAddress,
|
|
490
|
+
txs: destinationTxs,
|
|
491
|
+
});
|
|
492
|
+
console.log("[trails-sdk] relaysdk quote", quote);
|
|
493
|
+
let depositAmount = "0";
|
|
494
|
+
try {
|
|
495
|
+
depositAmount = quote.steps?.[0]?.items?.[0]?.data?.value;
|
|
496
|
+
if (originTokenAddress !== zeroAddress) {
|
|
497
|
+
const decoded = decodeFunctionData({
|
|
498
|
+
abi: erc20Abi,
|
|
499
|
+
data: quote.steps?.[0]?.items?.[0]?.data?.data,
|
|
500
|
+
});
|
|
501
|
+
if (decoded.functionName === "approve") {
|
|
502
|
+
depositAmount = decoded.args[1].toString();
|
|
503
|
+
}
|
|
504
|
+
if (decoded.functionName === "transfer") {
|
|
505
|
+
depositAmount = decoded.args[1].toString();
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
catch (error) {
|
|
510
|
+
console.error("[trails-sdk] Error decoding function data:", error);
|
|
511
|
+
}
|
|
512
|
+
const hasEnoughBalance = await checkAccountBalance({
|
|
513
|
+
account,
|
|
514
|
+
tokenAddress: originTokenAddress,
|
|
515
|
+
depositAmount,
|
|
516
|
+
publicClient,
|
|
517
|
+
});
|
|
518
|
+
if (!hasEnoughBalance) {
|
|
519
|
+
throw new Error("Account does not have enough balance for deposit");
|
|
520
|
+
}
|
|
521
|
+
return {
|
|
522
|
+
originSendAmount: depositAmount,
|
|
523
|
+
send: async (onOriginSend) => {
|
|
524
|
+
await attemptSwitchChain({
|
|
525
|
+
walletClient,
|
|
526
|
+
desiredChainId: originChainId,
|
|
527
|
+
});
|
|
528
|
+
const result = await executeSimpleRelayTransaction(quote, walletClient);
|
|
529
|
+
console.log("[trails-sdk] relaysdk result", result);
|
|
530
|
+
const txHash = getTxHashFromRelayResult(result);
|
|
531
|
+
if (onOriginSend) {
|
|
532
|
+
onOriginSend();
|
|
533
|
+
}
|
|
534
|
+
const originUserTxReceipt = await publicClient.waitForTransactionReceipt({
|
|
535
|
+
hash: txHash,
|
|
536
|
+
});
|
|
537
|
+
return {
|
|
538
|
+
originUserTxReceipt: originUserTxReceipt,
|
|
539
|
+
originMetaTxnReceipt: null,
|
|
540
|
+
destinationMetaTxnReceipt: null,
|
|
541
|
+
};
|
|
542
|
+
},
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
async function attemptGaslessDeposit({ paymasterUrl, depositTokenAddress, depositTokenAmount, depositRecipient, onOriginSend, walletClient, chain, account, relayerConfig, sequenceProjectAccessKey, originRelayer, }) {
|
|
546
|
+
let originUserTxReceipt = null;
|
|
547
|
+
const originChainId = chain.id;
|
|
548
|
+
console.log("[trails-sdk] originChainId", originChainId);
|
|
549
|
+
const publicClient = createPublicClient({
|
|
550
|
+
chain,
|
|
551
|
+
transport: http(),
|
|
552
|
+
});
|
|
553
|
+
const intentEntrypoint = intentEntrypoints[chain.id];
|
|
554
|
+
console.log("[trails-sdk] intentEntrypoint", intentEntrypoint);
|
|
555
|
+
let calls = [];
|
|
556
|
+
if (paymasterUrl) {
|
|
557
|
+
console.log("[trails-sdk] doing gasless with paymaster");
|
|
558
|
+
const delegatorSmartAccount = await getDelegatorSmartAccount({
|
|
559
|
+
publicClient,
|
|
560
|
+
});
|
|
561
|
+
if (intentEntrypoint) {
|
|
562
|
+
calls = await getDepositToIntentCalls({
|
|
563
|
+
publicClient,
|
|
564
|
+
walletClient,
|
|
565
|
+
account,
|
|
566
|
+
intentEntrypoint,
|
|
567
|
+
depositTokenAddress: depositTokenAddress,
|
|
568
|
+
depositTokenAmount: BigInt(depositTokenAmount),
|
|
569
|
+
depositRecipient: depositRecipient,
|
|
570
|
+
chain,
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
calls = await getPaymasterGaslessTransaction({
|
|
575
|
+
walletClient,
|
|
576
|
+
chain,
|
|
577
|
+
tokenAddress: depositTokenAddress,
|
|
578
|
+
amount: BigInt(depositTokenAmount),
|
|
579
|
+
recipient: depositRecipient,
|
|
580
|
+
delegatorSmartAccount,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
console.log("[trails-sdk] calls", calls);
|
|
584
|
+
const txHash = await sendPaymasterGaslessTransaction({
|
|
585
|
+
walletClient,
|
|
586
|
+
publicClient,
|
|
587
|
+
chain,
|
|
588
|
+
paymasterUrl,
|
|
589
|
+
delegatorSmartAccount,
|
|
590
|
+
calls,
|
|
591
|
+
});
|
|
592
|
+
if (onOriginSend) {
|
|
593
|
+
onOriginSend();
|
|
594
|
+
}
|
|
595
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
596
|
+
hash: txHash,
|
|
597
|
+
});
|
|
598
|
+
console.log("[trails-sdk] receipt", receipt);
|
|
599
|
+
originUserTxReceipt = receipt;
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
console.log("[trails-sdk] doing gasless with sequence wallet");
|
|
603
|
+
const delegatorPrivateKey = generatePrivateKey();
|
|
604
|
+
const delegatorAccount = privateKeyToAccount(delegatorPrivateKey);
|
|
605
|
+
const delegatorClient = createWalletClient({
|
|
606
|
+
account: delegatorAccount,
|
|
607
|
+
chain,
|
|
608
|
+
transport: http(),
|
|
609
|
+
});
|
|
610
|
+
console.log("[trails-sdk] attempting to switch chain");
|
|
611
|
+
await attemptSwitchChain({
|
|
612
|
+
walletClient,
|
|
613
|
+
desiredChainId: originChainId,
|
|
614
|
+
});
|
|
615
|
+
console.log("[trails-sdk] creating sequence wallet");
|
|
616
|
+
const sequenceWalletAddress = await simpleCreateSequenceWallet(delegatorAccount, relayerConfig, sequenceProjectAccessKey);
|
|
617
|
+
console.log("[trails-sdk] sequenceWalletAddress", sequenceWalletAddress);
|
|
618
|
+
if (intentEntrypoint) {
|
|
619
|
+
calls = await getDepositToIntentCalls({
|
|
620
|
+
publicClient,
|
|
621
|
+
walletClient,
|
|
622
|
+
account,
|
|
623
|
+
intentEntrypoint,
|
|
624
|
+
depositTokenAddress: depositTokenAddress,
|
|
625
|
+
depositTokenAmount: BigInt(depositTokenAmount),
|
|
626
|
+
depositRecipient: depositRecipient,
|
|
627
|
+
chain,
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
else {
|
|
631
|
+
const { signature, deadline } = await getPermitSignature({
|
|
632
|
+
publicClient,
|
|
633
|
+
walletClient,
|
|
634
|
+
signer: account.address,
|
|
635
|
+
spender: sequenceWalletAddress,
|
|
636
|
+
tokenAddress: depositTokenAddress,
|
|
637
|
+
amount: BigInt(depositTokenAmount),
|
|
638
|
+
chain,
|
|
639
|
+
});
|
|
640
|
+
calls = getPermitCalls(account.address, sequenceWalletAddress, BigInt(depositTokenAmount), deadline, signature, depositRecipient, depositTokenAddress);
|
|
641
|
+
}
|
|
642
|
+
console.log("[trails-sdk] calls", calls);
|
|
643
|
+
const feeOptions = await getFeeOptions(originRelayer, sequenceWalletAddress, originChainId, calls.map((call) => ({
|
|
644
|
+
to: call.to,
|
|
645
|
+
value: BigInt(call.value),
|
|
646
|
+
data: call.data,
|
|
647
|
+
gasLimit: BigInt(0),
|
|
648
|
+
delegateCall: false,
|
|
649
|
+
onlyFallback: false,
|
|
650
|
+
behaviorOnError: "revert",
|
|
651
|
+
})));
|
|
652
|
+
console.log("[trails-sdk] feeOptions", feeOptions);
|
|
653
|
+
const sequenceTxHash = await sequenceSendTransaction(sequenceWalletAddress, delegatorClient, publicClient, calls, chain, relayerConfig, sequenceProjectAccessKey);
|
|
654
|
+
console.log("[trails-sdk] sequenceTxHash", sequenceTxHash);
|
|
655
|
+
if (onOriginSend) {
|
|
656
|
+
onOriginSend();
|
|
657
|
+
}
|
|
658
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
659
|
+
hash: sequenceTxHash,
|
|
660
|
+
});
|
|
661
|
+
console.log("[trails-sdk] receipt", receipt);
|
|
662
|
+
originUserTxReceipt = receipt;
|
|
663
|
+
}
|
|
664
|
+
return originUserTxReceipt;
|
|
665
|
+
}
|
|
666
|
+
export async function attemptNonGaslessUserDeposit({ originTokenAddress, firstPreconditionMin, onOriginSend, publicClient, walletClient, originChainId, chain, account, fee, dryMode, sourceTokenPriceUsd, destinationTokenPriceUsd, destinationTokenAmount, destinationTokenDecimals, sourceTokenDecimals, intentAddress, }) {
|
|
667
|
+
let originUserTxReceipt = null;
|
|
668
|
+
const needsNativeFee = await getNeedsLifiNativeFee({
|
|
669
|
+
originTokenAddress,
|
|
670
|
+
destinationTokenAmount,
|
|
671
|
+
destinationTokenDecimals,
|
|
672
|
+
sourceTokenDecimals,
|
|
673
|
+
sourceTokenPriceUsd: sourceTokenPriceUsd ?? null,
|
|
674
|
+
destinationTokenPriceUsd: destinationTokenPriceUsd ?? null,
|
|
675
|
+
depositAmount: firstPreconditionMin,
|
|
676
|
+
});
|
|
677
|
+
let nativeFee = parseUnits("0.00005", 18).toString();
|
|
678
|
+
if (originChainId === 137) {
|
|
679
|
+
nativeFee = parseUnits("1.5", 18).toString();
|
|
680
|
+
}
|
|
681
|
+
console.log("[trails-sdk] needsNativeFee", needsNativeFee);
|
|
682
|
+
const originCallParams = {
|
|
683
|
+
to: originTokenAddress === zeroAddress ? intentAddress : originTokenAddress,
|
|
684
|
+
data: originTokenAddress === zeroAddress
|
|
685
|
+
? "0x"
|
|
686
|
+
: getERC20TransferData({
|
|
687
|
+
recipient: intentAddress,
|
|
688
|
+
amount: BigInt(firstPreconditionMin) + BigInt(fee),
|
|
689
|
+
}),
|
|
690
|
+
value: originTokenAddress === zeroAddress
|
|
691
|
+
? BigInt(firstPreconditionMin) + BigInt(fee)
|
|
692
|
+
: "0",
|
|
693
|
+
chainId: originChainId,
|
|
694
|
+
chain,
|
|
695
|
+
};
|
|
696
|
+
await attemptSwitchChain({
|
|
697
|
+
walletClient,
|
|
698
|
+
desiredChainId: originChainId,
|
|
699
|
+
});
|
|
700
|
+
let useSendCalls = false;
|
|
701
|
+
const moreThan1Tx = needsNativeFee;
|
|
702
|
+
if (moreThan1Tx) {
|
|
703
|
+
try {
|
|
704
|
+
// the reason for the timeout is some users experience this call to hang indefinitely on metamask on all chains.
|
|
705
|
+
// not sure why this is happening, but it happens.
|
|
706
|
+
const capabilities = await requestWithTimeout(walletClient, [
|
|
707
|
+
{
|
|
708
|
+
method: "wallet_getCapabilities",
|
|
709
|
+
params: [account.address],
|
|
710
|
+
},
|
|
711
|
+
], 10000);
|
|
712
|
+
console.log("[trails-sdk] capabilities", capabilities);
|
|
713
|
+
// Check if the chain supports atomic transactions
|
|
714
|
+
const chainHex = `0x${originChainId.toString(16)}`;
|
|
715
|
+
const chainCapabilities = capabilities[chainHex];
|
|
716
|
+
useSendCalls = chainCapabilities?.atomic?.status === "supported";
|
|
717
|
+
}
|
|
718
|
+
catch (error) {
|
|
719
|
+
console.error("[trails-sdk] Error getting capabilities", error);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
if (dryMode) {
|
|
723
|
+
console.log("[trails-sdk] dry mode, skipping send calls");
|
|
724
|
+
}
|
|
725
|
+
if (useSendCalls) {
|
|
726
|
+
console.log("[trails-sdk] using sendCalls");
|
|
727
|
+
}
|
|
728
|
+
else {
|
|
729
|
+
console.log("[trails-sdk] using sendTransaction");
|
|
730
|
+
}
|
|
731
|
+
if (useSendCalls) {
|
|
732
|
+
if (!dryMode) {
|
|
733
|
+
const calls = [];
|
|
734
|
+
if (needsNativeFee) {
|
|
735
|
+
calls.push({
|
|
736
|
+
to: intentAddress,
|
|
737
|
+
data: "0x00",
|
|
738
|
+
value: `0x${BigInt(nativeFee).toString(16)}`,
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
// Add the origin call
|
|
742
|
+
calls.push({
|
|
743
|
+
to: originCallParams.to,
|
|
744
|
+
data: originCallParams.data,
|
|
745
|
+
value: originCallParams.value
|
|
746
|
+
? `0x${BigInt(originCallParams.value).toString(16)}`
|
|
747
|
+
: "0x0",
|
|
748
|
+
});
|
|
749
|
+
// Send the batched call via EIP-7702
|
|
750
|
+
const result = (await walletClient.request({
|
|
751
|
+
method: "wallet_sendCalls",
|
|
752
|
+
params: [
|
|
753
|
+
{
|
|
754
|
+
version: "2.0.0",
|
|
755
|
+
chainId: `0x${originChainId.toString(16)}`,
|
|
756
|
+
atomicRequired: true,
|
|
757
|
+
calls,
|
|
758
|
+
},
|
|
759
|
+
],
|
|
760
|
+
}));
|
|
761
|
+
console.log("[trails-sdk] sendCalls result", result);
|
|
762
|
+
const requestId = result.requestId || result.id;
|
|
763
|
+
// Poll to check if the tx has been submitted
|
|
764
|
+
let txHash;
|
|
765
|
+
while (!txHash) {
|
|
766
|
+
const status = (await walletClient.request({
|
|
767
|
+
method: "wallet_getCallsStatus",
|
|
768
|
+
params: [requestId],
|
|
769
|
+
}));
|
|
770
|
+
console.log("[trails-sdk] getCallsStatus result", status);
|
|
771
|
+
const receipt = status?.receipts?.[0];
|
|
772
|
+
if (status.status === 200 && receipt?.transactionHash) {
|
|
773
|
+
txHash = receipt.transactionHash;
|
|
774
|
+
break;
|
|
775
|
+
}
|
|
776
|
+
else if (status.status === 500) {
|
|
777
|
+
throw new Error(`Transaction failed: ${status.error}`);
|
|
778
|
+
}
|
|
779
|
+
// wait a bit before polling again
|
|
780
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
781
|
+
}
|
|
782
|
+
if (onOriginSend) {
|
|
783
|
+
onOriginSend();
|
|
784
|
+
}
|
|
785
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
786
|
+
hash: txHash,
|
|
787
|
+
});
|
|
788
|
+
console.log("[trails-sdk] receipt", receipt);
|
|
789
|
+
originUserTxReceipt = receipt;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
if (!dryMode) {
|
|
794
|
+
if (needsNativeFee) {
|
|
795
|
+
const tx0 = await sendOriginTransaction(account, walletClient, {
|
|
796
|
+
to: intentAddress,
|
|
797
|
+
data: "0x00",
|
|
798
|
+
value: nativeFee,
|
|
799
|
+
chainId: originChainId,
|
|
800
|
+
chain,
|
|
801
|
+
}); // TODO: Add proper type
|
|
802
|
+
console.log("[trails-sdk] origin tx", tx0);
|
|
803
|
+
// Wait for transaction receipt
|
|
804
|
+
const feeReceipt = await publicClient.waitForTransactionReceipt({
|
|
805
|
+
hash: tx0,
|
|
806
|
+
});
|
|
807
|
+
console.log("[trails-sdk] nativeFeeReceipt", feeReceipt);
|
|
808
|
+
}
|
|
809
|
+
const tx = await sendOriginTransaction(account, walletClient, originCallParams); // TODO: Add proper type
|
|
810
|
+
console.log("[trails-sdk] origin tx", tx);
|
|
811
|
+
if (onOriginSend) {
|
|
812
|
+
onOriginSend();
|
|
813
|
+
}
|
|
814
|
+
// Wait for transaction receipt
|
|
815
|
+
const receipt = await publicClient.waitForTransactionReceipt({
|
|
816
|
+
hash: tx,
|
|
817
|
+
});
|
|
818
|
+
console.log("[trails-sdk] receipt", receipt);
|
|
819
|
+
originUserTxReceipt = receipt;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return originUserTxReceipt;
|
|
823
|
+
}
|
|
824
|
+
async function attemptUserDepositTx({ originTokenAddress, gasless, paymasterUrl, chain, account, relayerConfig, sequenceProjectAccessKey, originRelayer, firstPreconditionMin, intentAddress, onOriginSend, publicClient, walletClient, destinationTokenDecimals, sourceTokenDecimals, fee, dryMode, sourceTokenPriceUsd, destinationTokenPriceUsd, destinationTokenAmount, }) {
|
|
825
|
+
let originUserTxReceipt = null;
|
|
826
|
+
const originChainId = chain.id;
|
|
827
|
+
const doGasless = getDoGasless(originTokenAddress, gasless, paymasterUrl);
|
|
828
|
+
console.log("[trails-sdk] doGasless", doGasless, paymasterUrl);
|
|
829
|
+
if (doGasless) {
|
|
830
|
+
try {
|
|
831
|
+
originUserTxReceipt = await attemptGaslessDeposit({
|
|
832
|
+
paymasterUrl,
|
|
833
|
+
depositTokenAddress: originTokenAddress,
|
|
834
|
+
depositTokenAmount: firstPreconditionMin,
|
|
835
|
+
depositRecipient: intentAddress,
|
|
836
|
+
onOriginSend,
|
|
837
|
+
walletClient,
|
|
838
|
+
chain,
|
|
839
|
+
account,
|
|
840
|
+
relayerConfig,
|
|
841
|
+
sequenceProjectAccessKey,
|
|
842
|
+
originRelayer,
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
catch (error) {
|
|
846
|
+
console.log("[trails-sdk] gassless attempt failed", error);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
// If gasless attempt failed, try to send a regular transaction
|
|
850
|
+
if (!originUserTxReceipt) {
|
|
851
|
+
originUserTxReceipt = await attemptNonGaslessUserDeposit({
|
|
852
|
+
originTokenAddress,
|
|
853
|
+
firstPreconditionMin,
|
|
854
|
+
intentAddress,
|
|
855
|
+
onOriginSend,
|
|
856
|
+
publicClient,
|
|
857
|
+
walletClient,
|
|
858
|
+
originChainId,
|
|
859
|
+
chain,
|
|
860
|
+
account,
|
|
861
|
+
fee,
|
|
862
|
+
dryMode,
|
|
863
|
+
sourceTokenPriceUsd,
|
|
864
|
+
destinationTokenPriceUsd,
|
|
865
|
+
destinationTokenAmount,
|
|
866
|
+
destinationTokenDecimals,
|
|
867
|
+
sourceTokenDecimals,
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
return originUserTxReceipt;
|
|
871
|
+
}
|
|
872
|
+
export function getDoGasless(originTokenAddress, gasless, paymasterUrl) {
|
|
873
|
+
return Boolean(originTokenAddress !== zeroAddress && (gasless || paymasterUrl));
|
|
874
|
+
}
|
|
875
|
+
function getTransactionStateFromReceipt(receipt, chainId, label) {
|
|
876
|
+
let txHash = "";
|
|
877
|
+
let state = "pending";
|
|
878
|
+
if ("transactionHash" in receipt) {
|
|
879
|
+
txHash = receipt.transactionHash;
|
|
880
|
+
state = receipt.status === "success" ? "confirmed" : "failed";
|
|
881
|
+
}
|
|
882
|
+
else if ("txnHash" in receipt) {
|
|
883
|
+
txHash = receipt.txnHash;
|
|
884
|
+
state = receipt.status === "SUCCEEDED" ? "confirmed" : "failed";
|
|
885
|
+
}
|
|
886
|
+
return {
|
|
887
|
+
transactionHash: txHash,
|
|
888
|
+
explorerUrl: getExplorerUrl({ txHash, chainId }),
|
|
889
|
+
chainId,
|
|
890
|
+
state,
|
|
891
|
+
label,
|
|
892
|
+
};
|
|
893
|
+
}
|
|
894
|
+
async function sendMetaTxAndWaitForReceipt({ metaTx, relayer, precondition, }) {
|
|
895
|
+
let originMetaTxnReceipt = null;
|
|
896
|
+
console.log("[trails-sdk] metaTx", metaTx);
|
|
897
|
+
const opHash = await relayerSendMetaTx(relayer, metaTx, [precondition]);
|
|
898
|
+
console.log("[trails-sdk] opHash", opHash);
|
|
899
|
+
// eslint-disable-next-line no-constant-condition
|
|
900
|
+
while (true) {
|
|
901
|
+
console.log("[trails-sdk] polling status", metaTx.id, BigInt(metaTx.chainId));
|
|
902
|
+
const receipt = await getMetaTxStatus(relayer, metaTx.id, Number(metaTx.chainId));
|
|
903
|
+
console.log("[trails-sdk] status", receipt);
|
|
904
|
+
if (receipt?.transactionHash) {
|
|
905
|
+
originMetaTxnReceipt = receipt.data?.receipt;
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
909
|
+
}
|
|
910
|
+
return originMetaTxnReceipt;
|
|
911
|
+
}
|
|
912
|
+
/**
|
|
913
|
+
* Check if the account has enough balance for the deposit amount
|
|
914
|
+
*/
|
|
915
|
+
async function checkAccountBalance({ account, tokenAddress, depositAmount, publicClient, }) {
|
|
916
|
+
try {
|
|
917
|
+
let balance;
|
|
918
|
+
if (tokenAddress === zeroAddress) {
|
|
919
|
+
// Native token balance
|
|
920
|
+
balance = await publicClient.getBalance({ address: account.address });
|
|
921
|
+
}
|
|
922
|
+
else {
|
|
923
|
+
// ERC20 token balance
|
|
924
|
+
balance = await publicClient.readContract({
|
|
925
|
+
address: tokenAddress,
|
|
926
|
+
abi: erc20Abi,
|
|
927
|
+
functionName: "balanceOf",
|
|
928
|
+
args: [account.address],
|
|
929
|
+
});
|
|
930
|
+
}
|
|
931
|
+
const requiredAmount = BigInt(depositAmount);
|
|
932
|
+
console.log("[trails-sdk] balance", balance);
|
|
933
|
+
console.log("[trails-sdk] requiredAmount", requiredAmount);
|
|
934
|
+
return balance >= requiredAmount;
|
|
935
|
+
}
|
|
936
|
+
catch (error) {
|
|
937
|
+
console.error("[trails-sdk] Error checking account balance:", error);
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
// ETH fee required by some bridges for low token amounts
|
|
942
|
+
// TODO: update backend API to return the native fee requirement, if any
|
|
943
|
+
function getNeedsLifiNativeFee({ originTokenAddress, destinationTokenAmount, destinationTokenDecimals, sourceTokenDecimals, sourceTokenPriceUsd, destinationTokenPriceUsd, depositAmount, }) {
|
|
944
|
+
let needsNativeFee = false;
|
|
945
|
+
if (originTokenAddress !== zeroAddress &&
|
|
946
|
+
sourceTokenPriceUsd &&
|
|
947
|
+
destinationTokenPriceUsd &&
|
|
948
|
+
depositAmount &&
|
|
949
|
+
destinationTokenDecimals !== undefined &&
|
|
950
|
+
sourceTokenDecimals !== undefined) {
|
|
951
|
+
// Convert from wei to token units using formatUnits
|
|
952
|
+
const destinationAmount = Number(formatUnits(BigInt(destinationTokenAmount), destinationTokenDecimals));
|
|
953
|
+
const depositAmountFormatted = Number(formatUnits(BigInt(depositAmount), destinationTokenDecimals));
|
|
954
|
+
console.log("[trails-sdk] destinationAmount", destinationAmount);
|
|
955
|
+
console.log("[trails-sdk] depositAmountFormatted", depositAmountFormatted);
|
|
956
|
+
const destinationAmountUsd = destinationAmount * destinationTokenPriceUsd;
|
|
957
|
+
const depositAmountUsd = depositAmountFormatted * sourceTokenPriceUsd;
|
|
958
|
+
const diff = depositAmountUsd - destinationAmountUsd;
|
|
959
|
+
console.log("[trails-sdk] destinationAmountUsd", destinationAmountUsd, "[trails-sdk] depositAmountUsd", depositAmountUsd, "[trails-sdk] diff", diff);
|
|
960
|
+
if (diff >= 0 && diff <= 0.02) {
|
|
961
|
+
needsNativeFee = true;
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
return needsNativeFee;
|
|
965
|
+
}
|
|
966
|
+
export function useQuote({ walletClient, fromTokenAddress, fromChainId, toTokenAddress, toChainId, toAmount, toRecipient, } = {}) {
|
|
967
|
+
const apiClient = useAPIClient();
|
|
968
|
+
const { getRelayer } = useRelayers({
|
|
969
|
+
env: "dev",
|
|
970
|
+
useV3Relayers: DEFAULT_USE_V3_RELAYERS,
|
|
971
|
+
});
|
|
972
|
+
const indexerGatewayClient = useIndexerGatewayClient();
|
|
973
|
+
const { supportedTokens } = useSupportedTokens();
|
|
974
|
+
const { tokenBalance: originTokenBalance } = useAccountTokenBalance({
|
|
975
|
+
account: walletClient?.account?.address,
|
|
976
|
+
token: fromTokenAddress,
|
|
977
|
+
chainId: fromChainId,
|
|
978
|
+
indexerGatewayClient,
|
|
979
|
+
apiClient,
|
|
980
|
+
});
|
|
981
|
+
const destToken = toTokenAddress && toChainId
|
|
982
|
+
? {
|
|
983
|
+
tokenId: toTokenAddress,
|
|
984
|
+
chainId: toChainId,
|
|
985
|
+
contractAddress: toTokenAddress,
|
|
986
|
+
}
|
|
987
|
+
: null;
|
|
988
|
+
const { tokenPrice: destinationTokenPrice } = useTokenPrice(destToken, apiClient);
|
|
989
|
+
const { data, isLoading, error } = useQuery({
|
|
990
|
+
queryKey: [
|
|
991
|
+
"quote",
|
|
992
|
+
fromTokenAddress,
|
|
993
|
+
fromChainId,
|
|
994
|
+
toTokenAddress,
|
|
995
|
+
toChainId,
|
|
996
|
+
toAmount?.toString(),
|
|
997
|
+
toRecipient,
|
|
998
|
+
],
|
|
999
|
+
queryFn: async () => {
|
|
1000
|
+
if (!walletClient ||
|
|
1001
|
+
!apiClient ||
|
|
1002
|
+
!fromTokenAddress ||
|
|
1003
|
+
!toTokenAddress ||
|
|
1004
|
+
!toAmount ||
|
|
1005
|
+
!toRecipient ||
|
|
1006
|
+
!fromChainId ||
|
|
1007
|
+
!toChainId) {
|
|
1008
|
+
return null;
|
|
1009
|
+
}
|
|
1010
|
+
const originTokenAmount = originTokenBalance?.balance ?? "0";
|
|
1011
|
+
const sequenceProjectAccessKey = "";
|
|
1012
|
+
const destinationRelayer = getRelayer(toChainId);
|
|
1013
|
+
const originRelayer = getRelayer(fromChainId);
|
|
1014
|
+
console.log("originRelayer", originRelayer);
|
|
1015
|
+
console.log("destinationRelayer", destinationRelayer);
|
|
1016
|
+
const sourceTokenPriceUsd = originTokenBalance?.price?.value ?? 0;
|
|
1017
|
+
const destinationTokenPriceUsd = destinationTokenPrice?.price?.value ?? 0;
|
|
1018
|
+
const originToken = supportedTokens?.find((token) => token.contractAddress === fromTokenAddress &&
|
|
1019
|
+
token.chainId === fromChainId);
|
|
1020
|
+
const destinationToken = supportedTokens?.find((token) => token.contractAddress === toTokenAddress &&
|
|
1021
|
+
token.chainId === toChainId);
|
|
1022
|
+
const sourceTokenDecimals = originToken?.decimals ?? 18;
|
|
1023
|
+
const destinationTokenDecimals = destinationToken?.decimals ?? 18;
|
|
1024
|
+
const destinationTokenSymbol = destinationToken?.symbol ?? "";
|
|
1025
|
+
const options = {
|
|
1026
|
+
account: walletClient.account,
|
|
1027
|
+
originTokenAddress: fromTokenAddress,
|
|
1028
|
+
originChainId: fromChainId,
|
|
1029
|
+
originTokenAmount: originTokenAmount,
|
|
1030
|
+
destinationChainId: toChainId,
|
|
1031
|
+
recipient: toRecipient,
|
|
1032
|
+
destinationTokenAddress: toTokenAddress,
|
|
1033
|
+
destinationTokenAmount: toAmount.toString(),
|
|
1034
|
+
destinationTokenSymbol: destinationTokenSymbol,
|
|
1035
|
+
sequenceProjectAccessKey,
|
|
1036
|
+
client: walletClient,
|
|
1037
|
+
apiClient,
|
|
1038
|
+
originRelayer,
|
|
1039
|
+
destinationRelayer,
|
|
1040
|
+
sourceTokenPriceUsd,
|
|
1041
|
+
destinationTokenPriceUsd,
|
|
1042
|
+
sourceTokenDecimals,
|
|
1043
|
+
destinationTokenDecimals,
|
|
1044
|
+
fee: "0",
|
|
1045
|
+
dryMode: false,
|
|
1046
|
+
onTransactionStateChange: () => { },
|
|
1047
|
+
relayerConfig: {},
|
|
1048
|
+
};
|
|
1049
|
+
console.log("[trails-sdk] options", options);
|
|
1050
|
+
const { intentAddress, originSendAmount, send } = await prepareSend(options);
|
|
1051
|
+
console.log("[trails-sdk] Intent address:", intentAddress?.toString());
|
|
1052
|
+
const quote = {
|
|
1053
|
+
fromAmount: originSendAmount,
|
|
1054
|
+
};
|
|
1055
|
+
const swap = async () => {
|
|
1056
|
+
const { originUserTxReceipt, destinationMetaTxnReceipt } = await send();
|
|
1057
|
+
return {
|
|
1058
|
+
originTransaction: {
|
|
1059
|
+
transactionHash: originUserTxReceipt?.transactionHash,
|
|
1060
|
+
receipt: originUserTxReceipt,
|
|
1061
|
+
},
|
|
1062
|
+
destinationTransaction: {
|
|
1063
|
+
transactionHash: destinationMetaTxnReceipt?.txnHash,
|
|
1064
|
+
receipt: destinationMetaTxnReceipt,
|
|
1065
|
+
},
|
|
1066
|
+
};
|
|
1067
|
+
};
|
|
1068
|
+
return {
|
|
1069
|
+
quote,
|
|
1070
|
+
swap,
|
|
1071
|
+
};
|
|
1072
|
+
},
|
|
1073
|
+
});
|
|
1074
|
+
return {
|
|
1075
|
+
quote: data?.quote || null,
|
|
1076
|
+
swap: data?.swap || null,
|
|
1077
|
+
isLoadingQuote: isLoading,
|
|
1078
|
+
quoteError: error,
|
|
1079
|
+
};
|
|
1080
|
+
}
|