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/dist/trails.js
ADDED
|
@@ -0,0 +1,1031 @@
|
|
|
1
|
+
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
2
|
+
import { Address } from "ox";
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { createPublicClient, createWalletClient, custom, http, isAddress, isAddressEqual, zeroAddress, } from "viem";
|
|
5
|
+
import { useEstimateGas, useSendTransaction, useSwitchChain, useWaitForTransactionReceipt, } from "wagmi";
|
|
6
|
+
import { useAPIClient } from "./apiClient.js";
|
|
7
|
+
import { attemptSwitchChain } from "./chainSwitch.js";
|
|
8
|
+
import { getChainInfo } from "./chains.js";
|
|
9
|
+
import { TRAILS_CCTP_SAPIENT_SIGNER_ADDRESS, TRAILS_LIFI_SAPIENT_SIGNER_ADDRESS, TRAILS_RELAY_SAPIENT_SIGNER_ADDRESS, DEFAULT_USE_V3_RELAYERS, } from "./constants.js";
|
|
10
|
+
import { getERC20TransferData } from "./encoders.js";
|
|
11
|
+
import { calculateIntentAddress, calculateOriginAndDestinationIntentAddresses, getIntentCallsPayloads as getIntentCallsPayloadsFromIntents, } from "./intents.js";
|
|
12
|
+
import { useMetaTxnsMonitor } from "./metaTxnMonitor.js";
|
|
13
|
+
import { findPreconditionAddresses } from "./preconditions.js";
|
|
14
|
+
import { getBackupRelayer, useRelayers } from "./relayer.js";
|
|
15
|
+
const RETRY_WINDOW_MS = 10_000;
|
|
16
|
+
export function useTrails(config) {
|
|
17
|
+
const { account, disableAutoExecute = false, env, useV3Relayers = DEFAULT_USE_V3_RELAYERS, sequenceProjectAccessKey, } = config;
|
|
18
|
+
const apiClient = useAPIClient({ projectAccessKey: sequenceProjectAccessKey });
|
|
19
|
+
const [isAutoExecute, setIsAutoExecute] = useState(!disableAutoExecute);
|
|
20
|
+
const [hasAutoExecuted, setHasAutoExecuted] = useState(false);
|
|
21
|
+
// Track timestamps of when each meta-transaction was last sent
|
|
22
|
+
const [sentMetaTxns, setSentMetaTxns] = useState({});
|
|
23
|
+
// State declarations
|
|
24
|
+
const [metaTxns, setMetaTxns] = useState(null);
|
|
25
|
+
const [intentCallsPayloads, setIntentCallsPayloads] = useState(null);
|
|
26
|
+
const [intentPreconditions, setIntentPreconditions] = useState(null);
|
|
27
|
+
const [trailsFee, setTrailsFee] = useState(null);
|
|
28
|
+
const [txnHash, setTxnHash] = useState();
|
|
29
|
+
const [committedOriginIntentAddress, setCommittedOriginIntentAddress] = useState(null);
|
|
30
|
+
const [committedDestinationIntentAddress, setCommittedDestinationIntentAddress,] = useState(null);
|
|
31
|
+
const [originIntentAddress, setOriginIntentAddress] = useState(null);
|
|
32
|
+
const [destinationIntentAddress, setDestinationIntentAddress] = useState(null);
|
|
33
|
+
// const [preconditionStatuses, setPreconditionStatuses] = useState<boolean[]>([])
|
|
34
|
+
const [originCallParams, setOriginCallParams] = useState(null);
|
|
35
|
+
const [operationHashes, setOperationHashes] = useState({});
|
|
36
|
+
const [isTransactionInProgress, setIsTransactionInProgress] = useState(false);
|
|
37
|
+
const [isChainSwitchRequired, setIsChainSwitchRequired] = useState(false);
|
|
38
|
+
const { switchChain, isPending: isSwitchingChain, error: switchChainError, } = useSwitchChain();
|
|
39
|
+
const sendOriginTxn = useSendTransaction();
|
|
40
|
+
const [isEstimatingGas, setIsEstimatingGas] = useState(false);
|
|
41
|
+
const [originCallStatus, setOriginCallStatus] = useState(null);
|
|
42
|
+
const [originBlockTimestamp, setOriginBlockTimestamp] = useState(null);
|
|
43
|
+
const [metaTxnBlockTimestamps, setMetaTxnBlockTimestamps] = useState({});
|
|
44
|
+
const [verificationStatus, setVerificationStatus] = useState(null);
|
|
45
|
+
const { getRelayer } = useRelayers({
|
|
46
|
+
env,
|
|
47
|
+
useV3Relayers,
|
|
48
|
+
});
|
|
49
|
+
// Add gas estimation hook with proper types
|
|
50
|
+
const { data: estimatedGas, isError: isEstimateError, error: estimateError, } = useEstimateGas(originCallParams?.to && originCallParams?.chainId && !originCallParams.error
|
|
51
|
+
? {
|
|
52
|
+
to: originCallParams.to || undefined,
|
|
53
|
+
data: originCallParams.data || undefined,
|
|
54
|
+
value: originCallParams.value || undefined,
|
|
55
|
+
chainId: originCallParams.chainId || undefined,
|
|
56
|
+
}
|
|
57
|
+
: undefined);
|
|
58
|
+
const commitIntentConfigMutation = useMutation({
|
|
59
|
+
mutationFn: async (args) => {
|
|
60
|
+
console.log("[useTrails] commitIntentConfigMutation started with args:", args);
|
|
61
|
+
if (!apiClient) {
|
|
62
|
+
console.error("[useTrails] API client not available");
|
|
63
|
+
throw new Error("API client not available");
|
|
64
|
+
}
|
|
65
|
+
if (!args.quoteProvider) {
|
|
66
|
+
console.error("[useTrails] quoteProvider is required");
|
|
67
|
+
throw new Error("quoteProvider is required");
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
console.log("[useTrails] Calculating intent address...");
|
|
71
|
+
console.log("[useTrails] Main signer:", args.mainSignerAddress);
|
|
72
|
+
console.log("[useTrails] Calls:", args.calls);
|
|
73
|
+
const originChainId = createIntentMutation.variables?.originChainId;
|
|
74
|
+
const destinationChainId = createIntentMutation.variables?.destinationChainId;
|
|
75
|
+
if (!originChainId || !destinationChainId) {
|
|
76
|
+
console.error("[useTrails] Could not determine origin/destination chain IDs for verification.");
|
|
77
|
+
throw new Error("Could not determine origin/destination chain IDs for verification.");
|
|
78
|
+
}
|
|
79
|
+
const { originIntentAddress, destinationIntentAddress } = calculateOriginAndDestinationIntentAddresses(args.mainSignerAddress, args.calls);
|
|
80
|
+
const { originAddress: originPreconditionAddress, destinationAddress: destinationPreconditionAddress, } = findPreconditionAddresses(args.preconditions, originChainId, destinationChainId);
|
|
81
|
+
console.log("[useTrails] Verification addresses:", {
|
|
82
|
+
calculatedOrigin: originIntentAddress.toString(),
|
|
83
|
+
calculatedDestination: destinationIntentAddress.toString(),
|
|
84
|
+
preconditionOrigin: originPreconditionAddress,
|
|
85
|
+
preconditionDestination: destinationPreconditionAddress,
|
|
86
|
+
});
|
|
87
|
+
const isOriginVerified = !!originPreconditionAddress &&
|
|
88
|
+
isAddressEqual(Address.from(originPreconditionAddress), originIntentAddress);
|
|
89
|
+
// For single chain, destination address may not be in preconditions,
|
|
90
|
+
// but the destination intent address should be the zero address.
|
|
91
|
+
const isDestinationVerified = (destinationPreconditionAddress &&
|
|
92
|
+
isAddressEqual(Address.from(destinationPreconditionAddress), destinationIntentAddress)) ||
|
|
93
|
+
(!destinationPreconditionAddress &&
|
|
94
|
+
originChainId === destinationChainId &&
|
|
95
|
+
isAddressEqual(destinationIntentAddress, zeroAddress));
|
|
96
|
+
const isVerified = isOriginVerified && isDestinationVerified;
|
|
97
|
+
setVerificationStatus({
|
|
98
|
+
success: isVerified,
|
|
99
|
+
receivedOriginAddress: originPreconditionAddress,
|
|
100
|
+
receivedDestinationAddress: destinationPreconditionAddress,
|
|
101
|
+
calculatedOriginAddress: originIntentAddress.toString(),
|
|
102
|
+
calculatedDestinationAddress: destinationIntentAddress.toString(),
|
|
103
|
+
});
|
|
104
|
+
if (!isVerified) {
|
|
105
|
+
console.error("[useTrails] Address verification failed.", {
|
|
106
|
+
isOriginVerified,
|
|
107
|
+
isDestinationVerified,
|
|
108
|
+
});
|
|
109
|
+
throw new Error(`Address verification failed. Origin verified: ${isOriginVerified}, Destination verified: ${isDestinationVerified}`);
|
|
110
|
+
}
|
|
111
|
+
// Commit the intent config
|
|
112
|
+
console.log("[useTrails] Committing intent config to API...");
|
|
113
|
+
const response = await apiClient.commitIntentConfig({
|
|
114
|
+
originIntentAddress: originIntentAddress.toString(),
|
|
115
|
+
destinationIntentAddress: destinationIntentAddress.toString(),
|
|
116
|
+
mainSigner: args.mainSignerAddress,
|
|
117
|
+
calls: args.calls,
|
|
118
|
+
preconditions: args.preconditions,
|
|
119
|
+
addressOverrides: {
|
|
120
|
+
trailsLiFiSapientSignerAddress: TRAILS_LIFI_SAPIENT_SIGNER_ADDRESS,
|
|
121
|
+
trailsRelaySapientSignerAddress: TRAILS_RELAY_SAPIENT_SIGNER_ADDRESS,
|
|
122
|
+
trailsCCTPV2SapientSignerAddress: TRAILS_CCTP_SAPIENT_SIGNER_ADDRESS,
|
|
123
|
+
...args.addressOverrides,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
console.log("[useTrails] API Commit Response:", response);
|
|
127
|
+
return {
|
|
128
|
+
originIntentAddress: originIntentAddress.toString(),
|
|
129
|
+
destinationIntentAddress: destinationIntentAddress.toString(),
|
|
130
|
+
response,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
console.error("[useTrails] Error during commit intent mutation:", error);
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
onSuccess: (data) => {
|
|
139
|
+
console.log("[useTrails] Intent config committed successfully. Data:", data);
|
|
140
|
+
console.log("[useTrails] Setting committedOriginIntentAddress:", data.originIntentAddress);
|
|
141
|
+
setCommittedOriginIntentAddress(data.originIntentAddress);
|
|
142
|
+
setCommittedDestinationIntentAddress(data.destinationIntentAddress);
|
|
143
|
+
},
|
|
144
|
+
onError: (error) => {
|
|
145
|
+
console.error("[useTrails] Failed to commit intent config:", error);
|
|
146
|
+
setCommittedOriginIntentAddress(null);
|
|
147
|
+
setCommittedDestinationIntentAddress(null);
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
// New Query to fetch committed intent config
|
|
151
|
+
const { data: committedIntentConfig, isLoading: isLoadingCommittedConfig, error: committedConfigError, } = useQuery({
|
|
152
|
+
queryKey: ["getIntentConfig", committedOriginIntentAddress],
|
|
153
|
+
queryFn: async () => {
|
|
154
|
+
if (!apiClient || !committedOriginIntentAddress) {
|
|
155
|
+
throw new Error("API client or committed intent address not available");
|
|
156
|
+
}
|
|
157
|
+
console.log("Fetching intent config for address:", committedOriginIntentAddress);
|
|
158
|
+
return await apiClient.getIntentConfig({
|
|
159
|
+
intentAddress: committedOriginIntentAddress,
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
enabled: !!committedOriginIntentAddress &&
|
|
163
|
+
!!apiClient &&
|
|
164
|
+
commitIntentConfigMutation.isSuccess,
|
|
165
|
+
staleTime: 1000 * 60 * 5, // 5 minutes
|
|
166
|
+
retry: 1,
|
|
167
|
+
});
|
|
168
|
+
async function getIntentCallsPayloads(args) {
|
|
169
|
+
return getIntentCallsPayloadsFromIntents(apiClient, {
|
|
170
|
+
...args,
|
|
171
|
+
addressOverrides: {
|
|
172
|
+
trailsLiFiSapientSignerAddress: TRAILS_LIFI_SAPIENT_SIGNER_ADDRESS,
|
|
173
|
+
trailsRelaySapientSignerAddress: TRAILS_RELAY_SAPIENT_SIGNER_ADDRESS,
|
|
174
|
+
trailsCCTPV2SapientSignerAddress: TRAILS_CCTP_SAPIENT_SIGNER_ADDRESS,
|
|
175
|
+
...args.addressOverrides,
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
// TODO: Add type for args
|
|
180
|
+
const createIntentMutation = useMutation({
|
|
181
|
+
mutationFn: async (args) => {
|
|
182
|
+
if (args.originChainId === args.destinationChainId &&
|
|
183
|
+
isAddressEqual(Address.from(args.originTokenAddress), Address.from(args.destinationTokenAddress))) {
|
|
184
|
+
throw new Error("The same token cannot be used as both the source and destination token.");
|
|
185
|
+
}
|
|
186
|
+
if (!account.address) {
|
|
187
|
+
throw new Error("Missing selected token or account address");
|
|
188
|
+
}
|
|
189
|
+
// Reset commit state when generating a new intent
|
|
190
|
+
setCommittedOriginIntentAddress(null);
|
|
191
|
+
setCommittedDestinationIntentAddress(null);
|
|
192
|
+
setVerificationStatus(null);
|
|
193
|
+
setTrailsFee(null);
|
|
194
|
+
setMetaTxns(null);
|
|
195
|
+
setIntentCallsPayloads(null);
|
|
196
|
+
setIntentPreconditions(null);
|
|
197
|
+
setOriginIntentAddress(null);
|
|
198
|
+
setDestinationIntentAddress(null);
|
|
199
|
+
const data = await getIntentCallsPayloads(args);
|
|
200
|
+
setMetaTxns(data.metaTxns);
|
|
201
|
+
setIntentCallsPayloads(data.calls);
|
|
202
|
+
setIntentPreconditions(data.preconditions);
|
|
203
|
+
setTrailsFee(data.trailsFee);
|
|
204
|
+
setOriginIntentAddress(data.originIntentAddress);
|
|
205
|
+
setDestinationIntentAddress(data.destinationIntentAddress);
|
|
206
|
+
setCommittedOriginIntentAddress(null);
|
|
207
|
+
setCommittedDestinationIntentAddress(null);
|
|
208
|
+
setVerificationStatus(null);
|
|
209
|
+
return data;
|
|
210
|
+
},
|
|
211
|
+
onSuccess: (data) => {
|
|
212
|
+
console.log("Intent Config Success:", data);
|
|
213
|
+
setTrailsFee(data.trailsFee || null);
|
|
214
|
+
setOriginIntentAddress(data.originIntentAddress);
|
|
215
|
+
setDestinationIntentAddress(data.destinationIntentAddress);
|
|
216
|
+
if (data?.calls &&
|
|
217
|
+
data.calls.length > 0 &&
|
|
218
|
+
data.preconditions &&
|
|
219
|
+
data.preconditions.length > 0 &&
|
|
220
|
+
data.metaTxns &&
|
|
221
|
+
data.metaTxns.length > 0) {
|
|
222
|
+
setIntentCallsPayloads(data.calls);
|
|
223
|
+
setIntentPreconditions(data.preconditions);
|
|
224
|
+
setMetaTxns(data.metaTxns);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.warn("API returned success but no operations found.");
|
|
228
|
+
setIntentCallsPayloads(null);
|
|
229
|
+
setIntentPreconditions(null);
|
|
230
|
+
setMetaTxns(null);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
onError: (error) => {
|
|
234
|
+
console.error("Intent Config Error:", error);
|
|
235
|
+
setIntentCallsPayloads(null);
|
|
236
|
+
setIntentPreconditions(null);
|
|
237
|
+
setMetaTxns(null);
|
|
238
|
+
setTrailsFee(null);
|
|
239
|
+
setOriginIntentAddress(null);
|
|
240
|
+
setDestinationIntentAddress(null);
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
function callIntentCallsPayload(args) {
|
|
244
|
+
createIntentMutation.mutate(args);
|
|
245
|
+
}
|
|
246
|
+
const clearIntent = useCallback(() => {
|
|
247
|
+
console.log("[Trails] Clearing intent state");
|
|
248
|
+
setIntentCallsPayloads(null);
|
|
249
|
+
setIntentPreconditions(null);
|
|
250
|
+
setMetaTxns(null);
|
|
251
|
+
setTrailsFee(null);
|
|
252
|
+
setCommittedOriginIntentAddress(null);
|
|
253
|
+
setCommittedDestinationIntentAddress(null);
|
|
254
|
+
setVerificationStatus(null);
|
|
255
|
+
setOriginIntentAddress(null);
|
|
256
|
+
setDestinationIntentAddress(null);
|
|
257
|
+
setOperationHashes({});
|
|
258
|
+
setHasAutoExecuted(false);
|
|
259
|
+
setMetaTxnBlockTimestamps({});
|
|
260
|
+
}, []); // Empty deps array since these setters are stable
|
|
261
|
+
const updateOriginCallStatus = useCallback((hash, status, gasUsed, effectiveGasPrice, revertReason) => {
|
|
262
|
+
setOriginCallStatus({
|
|
263
|
+
txnHash: hash,
|
|
264
|
+
status: status === "success"
|
|
265
|
+
? "Success"
|
|
266
|
+
: status === "reverted"
|
|
267
|
+
? "Failed"
|
|
268
|
+
: status === "sending"
|
|
269
|
+
? "Sending..."
|
|
270
|
+
: "Pending",
|
|
271
|
+
revertReason: status === "reverted"
|
|
272
|
+
? revertReason || "Transaction reverted"
|
|
273
|
+
: undefined,
|
|
274
|
+
gasUsed: gasUsed ? Number(gasUsed) : undefined,
|
|
275
|
+
effectiveGasPrice: effectiveGasPrice?.toString(),
|
|
276
|
+
});
|
|
277
|
+
}, []);
|
|
278
|
+
const sendOriginTransaction = async () => {
|
|
279
|
+
console.log("Sending origin transaction...");
|
|
280
|
+
console.log(isTransactionInProgress, originCallParams, originCallParams?.error, originCallParams?.to, originCallParams?.data, originCallParams?.value, originCallParams?.chainId);
|
|
281
|
+
if (isTransactionInProgress || // Prevent duplicate transactions
|
|
282
|
+
!originCallParams ||
|
|
283
|
+
originCallParams.error ||
|
|
284
|
+
!originCallParams.to ||
|
|
285
|
+
originCallParams.data === null ||
|
|
286
|
+
originCallParams.value === null ||
|
|
287
|
+
originCallParams.chainId === null) {
|
|
288
|
+
console.error("Origin call parameters not available or invalid:", originCallParams);
|
|
289
|
+
updateOriginCallStatus(undefined, "reverted", undefined, undefined, "Origin call parameters not ready");
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
// Check if we need to switch chains
|
|
293
|
+
if (account.chainId !== originCallParams.chainId) {
|
|
294
|
+
setIsChainSwitchRequired(true);
|
|
295
|
+
updateOriginCallStatus(undefined, "pending", undefined, undefined, `Switching to chain ${originCallParams.chainId}...`);
|
|
296
|
+
const walletClient = createWalletClient({
|
|
297
|
+
chain: getChainInfo(originCallParams.chainId),
|
|
298
|
+
transport: custom((await account.connector.getProvider())), // TODO: Add proper type
|
|
299
|
+
});
|
|
300
|
+
try {
|
|
301
|
+
await attemptSwitchChain({
|
|
302
|
+
walletClient,
|
|
303
|
+
desiredChainId: originCallParams.chainId,
|
|
304
|
+
});
|
|
305
|
+
setIsChainSwitchRequired(false);
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
console.error("Chain switch failed:", error);
|
|
309
|
+
if (error instanceof Error && error.message.includes("User rejected")) {
|
|
310
|
+
setIsAutoExecute(false);
|
|
311
|
+
}
|
|
312
|
+
updateOriginCallStatus(undefined, "reverted", undefined, undefined, error instanceof Error
|
|
313
|
+
? error.message
|
|
314
|
+
: "Unknown error switching chain");
|
|
315
|
+
setIsChainSwitchRequired(false);
|
|
316
|
+
return; // Stop execution on switch failure
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
// Ensure only one transaction is sent at a time
|
|
320
|
+
if (!isTransactionInProgress) {
|
|
321
|
+
setIsTransactionInProgress(true); // Mark transaction as in progress
|
|
322
|
+
setTxnHash(undefined);
|
|
323
|
+
updateOriginCallStatus(undefined, "sending");
|
|
324
|
+
if (!estimatedGas && !isEstimateError) {
|
|
325
|
+
setIsEstimatingGas(true);
|
|
326
|
+
return; // Wait for gas estimation
|
|
327
|
+
}
|
|
328
|
+
if (isEstimateError) {
|
|
329
|
+
console.error("Gas estimation failed:", estimateError);
|
|
330
|
+
updateOriginCallStatus(undefined, "reverted", undefined, undefined, `Gas estimation failed: ${estimateError?.message}`);
|
|
331
|
+
setIsTransactionInProgress(false);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
// Add 20% buffer to estimated gas
|
|
335
|
+
const gasLimit = estimatedGas
|
|
336
|
+
? BigInt(Math.floor(Number(estimatedGas) * 1.2))
|
|
337
|
+
: undefined;
|
|
338
|
+
sendOriginTxn.sendTransaction({
|
|
339
|
+
to: originCallParams.to,
|
|
340
|
+
data: originCallParams.data,
|
|
341
|
+
value: originCallParams.value,
|
|
342
|
+
chainId: originCallParams.chainId,
|
|
343
|
+
gas: gasLimit,
|
|
344
|
+
}, {
|
|
345
|
+
onSuccess: (hash) => {
|
|
346
|
+
console.log("Transaction sent, hash:", hash);
|
|
347
|
+
setTxnHash(hash);
|
|
348
|
+
setIsTransactionInProgress(false); // Reset transaction state
|
|
349
|
+
},
|
|
350
|
+
onError: (error) => {
|
|
351
|
+
console.error("Transaction failed:", error);
|
|
352
|
+
if (error instanceof Error &&
|
|
353
|
+
(error.message.includes("User rejected") ||
|
|
354
|
+
error.message.includes("user rejected"))) {
|
|
355
|
+
setIsAutoExecute(false);
|
|
356
|
+
}
|
|
357
|
+
updateOriginCallStatus(undefined, "reverted", undefined, undefined, error instanceof Error ? error.message : "Unknown error");
|
|
358
|
+
setIsTransactionInProgress(false);
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
console.warn("Transaction already in progress. Skipping duplicate request.");
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
// Remove the chain change effect that might be resetting state
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
if (switchChainError) {
|
|
369
|
+
console.error("Chain switch error:", switchChainError);
|
|
370
|
+
updateOriginCallStatus(undefined, "reverted", undefined, undefined, `Chain switch failed: ${switchChainError.message || "Unknown error"}`);
|
|
371
|
+
setIsChainSwitchRequired(false);
|
|
372
|
+
}
|
|
373
|
+
}, [switchChainError, updateOriginCallStatus]);
|
|
374
|
+
// Reset gas estimation state when parameters change
|
|
375
|
+
useEffect(() => {
|
|
376
|
+
setIsEstimatingGas(false);
|
|
377
|
+
}, []);
|
|
378
|
+
// Only update chain switch required state when needed
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
if (originCallParams?.chainId &&
|
|
381
|
+
account.chainId === originCallParams.chainId) {
|
|
382
|
+
console.log("No chain switch required");
|
|
383
|
+
setIsChainSwitchRequired(false);
|
|
384
|
+
}
|
|
385
|
+
}, [account.chainId, originCallParams?.chainId]);
|
|
386
|
+
// Effect to handle chain switching
|
|
387
|
+
useEffect(() => {
|
|
388
|
+
if (originCallParams?.chainId &&
|
|
389
|
+
account.chainId !== originCallParams.chainId) {
|
|
390
|
+
async function check() {
|
|
391
|
+
try {
|
|
392
|
+
const chainId = originCallParams.chainId;
|
|
393
|
+
const walletClient = createWalletClient({
|
|
394
|
+
chain: getChainInfo(chainId),
|
|
395
|
+
transport: custom((await account.connector.getProvider())), // TODO: Add proper type
|
|
396
|
+
});
|
|
397
|
+
await attemptSwitchChain({
|
|
398
|
+
walletClient,
|
|
399
|
+
desiredChainId: chainId,
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
console.error("Chain switch failed:", error);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
check().catch(console.error);
|
|
407
|
+
}
|
|
408
|
+
}, [account, originCallParams]);
|
|
409
|
+
// Hook to wait for transaction receipt
|
|
410
|
+
const { data: receipt, isLoading: isWaitingForReceipt, isSuccess: receiptIsSuccess, isError: receiptIsError, error: receiptError, } = useWaitForTransactionReceipt({
|
|
411
|
+
hash: txnHash,
|
|
412
|
+
confirmations: 1,
|
|
413
|
+
query: {
|
|
414
|
+
enabled: !!txnHash,
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
// Modify the effect that watches for transaction status
|
|
418
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: False positive
|
|
419
|
+
useEffect(() => {
|
|
420
|
+
if (!txnHash) {
|
|
421
|
+
// Only reset these when txnHash is cleared
|
|
422
|
+
if (originCallStatus?.txnHash) {
|
|
423
|
+
setOriginCallStatus(null);
|
|
424
|
+
}
|
|
425
|
+
setOriginBlockTimestamp(null);
|
|
426
|
+
if (Object.keys(sentMetaTxns).length > 0) {
|
|
427
|
+
setSentMetaTxns({});
|
|
428
|
+
}
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
if (originCallStatus?.txnHash === txnHash &&
|
|
432
|
+
(originCallStatus?.status === "Success" ||
|
|
433
|
+
originCallStatus?.status === "Failed") &&
|
|
434
|
+
!isWaitingForReceipt) {
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (isWaitingForReceipt) {
|
|
438
|
+
setOriginCallStatus((prevStatus) => ({
|
|
439
|
+
...(prevStatus?.txnHash === txnHash
|
|
440
|
+
? prevStatus
|
|
441
|
+
: {
|
|
442
|
+
gasUsed: undefined,
|
|
443
|
+
effectiveGasPrice: undefined,
|
|
444
|
+
revertReason: undefined,
|
|
445
|
+
}),
|
|
446
|
+
txnHash,
|
|
447
|
+
status: "Pending",
|
|
448
|
+
}));
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (receiptIsSuccess && receipt) {
|
|
452
|
+
const newStatus = receipt.status === "success" ? "Success" : "Failed";
|
|
453
|
+
setOriginCallStatus({
|
|
454
|
+
txnHash: receipt.transactionHash,
|
|
455
|
+
status: newStatus,
|
|
456
|
+
gasUsed: receipt.gasUsed ? Number(receipt.gasUsed) : undefined,
|
|
457
|
+
effectiveGasPrice: receipt.effectiveGasPrice?.toString(),
|
|
458
|
+
revertReason: receipt.status === "reverted"
|
|
459
|
+
? receiptError?.message ||
|
|
460
|
+
"Transaction reverted by receipt"
|
|
461
|
+
: undefined,
|
|
462
|
+
});
|
|
463
|
+
if (newStatus === "Success" && receipt.blockNumber) {
|
|
464
|
+
const fetchTimestamp = async () => {
|
|
465
|
+
try {
|
|
466
|
+
if (!originCallParams?.chainId) {
|
|
467
|
+
console.error("[Trails] Origin chainId not available for fetching origin block timestamp.");
|
|
468
|
+
setOriginBlockTimestamp(null);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
const chainConfig = getChainInfo(originCallParams.chainId);
|
|
472
|
+
const client = createPublicClient({
|
|
473
|
+
chain: chainConfig,
|
|
474
|
+
transport: http(),
|
|
475
|
+
});
|
|
476
|
+
const block = await client.getBlock({
|
|
477
|
+
blockNumber: BigInt(receipt.blockNumber),
|
|
478
|
+
});
|
|
479
|
+
setOriginBlockTimestamp(Number(block.timestamp));
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
console.error("[Trails] Error fetching origin block timestamp:", error);
|
|
483
|
+
setOriginBlockTimestamp(null);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
fetchTimestamp();
|
|
487
|
+
}
|
|
488
|
+
else if (newStatus !== "Success") {
|
|
489
|
+
setOriginBlockTimestamp(null);
|
|
490
|
+
}
|
|
491
|
+
if (newStatus === "Success" &&
|
|
492
|
+
metaTxns &&
|
|
493
|
+
metaTxns.length > 0 &&
|
|
494
|
+
isAutoExecute &&
|
|
495
|
+
!metaTxns.some((tx) => sentMetaTxns[`${tx.chainId}-${tx.id}`])) {
|
|
496
|
+
console.log("Origin transaction successful, auto-sending all meta transactions...");
|
|
497
|
+
sendMetaTxnMutation.mutate({ selectedId: null });
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else if (receiptIsError) {
|
|
501
|
+
setOriginCallStatus({
|
|
502
|
+
txnHash,
|
|
503
|
+
status: "Failed",
|
|
504
|
+
revertReason: receiptError?.message ||
|
|
505
|
+
"Failed to get receipt",
|
|
506
|
+
gasUsed: undefined,
|
|
507
|
+
effectiveGasPrice: undefined,
|
|
508
|
+
});
|
|
509
|
+
setOriginBlockTimestamp(null);
|
|
510
|
+
}
|
|
511
|
+
}, [
|
|
512
|
+
txnHash,
|
|
513
|
+
isWaitingForReceipt,
|
|
514
|
+
receiptIsSuccess,
|
|
515
|
+
receiptIsError,
|
|
516
|
+
receipt,
|
|
517
|
+
receiptError,
|
|
518
|
+
metaTxns,
|
|
519
|
+
sentMetaTxns,
|
|
520
|
+
isAutoExecute,
|
|
521
|
+
originCallParams?.chainId,
|
|
522
|
+
originCallStatus?.status,
|
|
523
|
+
originCallStatus?.txnHash,
|
|
524
|
+
]);
|
|
525
|
+
// Modify the auto-execute effect
|
|
526
|
+
useEffect(() => {
|
|
527
|
+
const shouldAutoSend = isAutoExecute &&
|
|
528
|
+
commitIntentConfigMutation.isSuccess &&
|
|
529
|
+
originCallParams?.chainId &&
|
|
530
|
+
account.chainId === originCallParams.chainId &&
|
|
531
|
+
!originCallParams.error &&
|
|
532
|
+
originCallParams.to &&
|
|
533
|
+
originCallParams.data !== null &&
|
|
534
|
+
originCallParams.value !== null &&
|
|
535
|
+
!sendOriginTxn.isPending &&
|
|
536
|
+
!isWaitingForReceipt &&
|
|
537
|
+
!txnHash &&
|
|
538
|
+
!isChainSwitchRequired &&
|
|
539
|
+
!originCallStatus &&
|
|
540
|
+
!hasAutoExecuted;
|
|
541
|
+
if (shouldAutoSend) {
|
|
542
|
+
console.log("Auto-executing transaction: All conditions met.");
|
|
543
|
+
setHasAutoExecuted(true);
|
|
544
|
+
// Set initial status
|
|
545
|
+
setOriginCallStatus({
|
|
546
|
+
status: "Sending...",
|
|
547
|
+
});
|
|
548
|
+
sendOriginTxn.sendTransaction({
|
|
549
|
+
to: originCallParams.to,
|
|
550
|
+
data: originCallParams.data,
|
|
551
|
+
value: originCallParams.value,
|
|
552
|
+
chainId: originCallParams.chainId,
|
|
553
|
+
}, {
|
|
554
|
+
onSuccess: (hash) => {
|
|
555
|
+
console.log("Auto-executed transaction sent, hash:", hash);
|
|
556
|
+
setTxnHash(hash);
|
|
557
|
+
},
|
|
558
|
+
onError: (error) => {
|
|
559
|
+
console.error("Auto-executed transaction failed:", error);
|
|
560
|
+
if (error instanceof Error &&
|
|
561
|
+
(error.message.includes("User rejected") ||
|
|
562
|
+
error.message.includes("user rejected"))) {
|
|
563
|
+
setIsAutoExecute(false);
|
|
564
|
+
}
|
|
565
|
+
setOriginCallStatus({
|
|
566
|
+
status: "Failed",
|
|
567
|
+
revertReason: error instanceof Error ? error.message : "Unknown error",
|
|
568
|
+
});
|
|
569
|
+
setHasAutoExecuted(false);
|
|
570
|
+
},
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
}, [
|
|
574
|
+
isAutoExecute,
|
|
575
|
+
commitIntentConfigMutation.isSuccess,
|
|
576
|
+
originCallParams,
|
|
577
|
+
account.chainId,
|
|
578
|
+
sendOriginTxn.isPending,
|
|
579
|
+
isWaitingForReceipt,
|
|
580
|
+
txnHash,
|
|
581
|
+
isChainSwitchRequired,
|
|
582
|
+
originCallStatus,
|
|
583
|
+
hasAutoExecuted,
|
|
584
|
+
sendOriginTxn,
|
|
585
|
+
]);
|
|
586
|
+
// Effect to auto-commit when intent calls payloads are ready
|
|
587
|
+
useEffect(() => {
|
|
588
|
+
if (isAutoExecute &&
|
|
589
|
+
intentCallsPayloads &&
|
|
590
|
+
intentPreconditions &&
|
|
591
|
+
trailsFee &&
|
|
592
|
+
account.address &&
|
|
593
|
+
originIntentAddress &&
|
|
594
|
+
!commitIntentConfigMutation.isPending &&
|
|
595
|
+
!commitIntentConfigMutation.isSuccess) {
|
|
596
|
+
console.log("Auto-committing intent configuration...");
|
|
597
|
+
commitIntentConfigMutation.mutate({
|
|
598
|
+
mainSignerAddress: account.address,
|
|
599
|
+
calls: intentCallsPayloads,
|
|
600
|
+
preconditions: intentPreconditions,
|
|
601
|
+
quoteProvider: trailsFee.quoteProvider,
|
|
602
|
+
addressOverrides: createIntentMutation.variables?.addressOverrides,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
}, [
|
|
606
|
+
isAutoExecute,
|
|
607
|
+
intentCallsPayloads,
|
|
608
|
+
intentPreconditions,
|
|
609
|
+
trailsFee,
|
|
610
|
+
account.address,
|
|
611
|
+
originIntentAddress,
|
|
612
|
+
commitIntentConfigMutation,
|
|
613
|
+
createIntentMutation.variables,
|
|
614
|
+
]);
|
|
615
|
+
// Update the sendMetaTxn mutation
|
|
616
|
+
const sendMetaTxnMutation = useMutation({
|
|
617
|
+
mutationFn: async ({ selectedId }) => {
|
|
618
|
+
if (!intentCallsPayloads ||
|
|
619
|
+
!intentPreconditions ||
|
|
620
|
+
!metaTxns ||
|
|
621
|
+
!account.address) {
|
|
622
|
+
throw new Error("Missing required data for meta-transaction");
|
|
623
|
+
}
|
|
624
|
+
if (!trailsFee?.quoteProvider) {
|
|
625
|
+
throw new Error("quoteProvider is required");
|
|
626
|
+
}
|
|
627
|
+
const intentAddress = calculateIntentAddress(account.address, intentCallsPayloads);
|
|
628
|
+
// If no specific ID is selected, send all meta transactions
|
|
629
|
+
const txnsToSend = selectedId
|
|
630
|
+
? [metaTxns.find((tx) => tx.id === selectedId)]
|
|
631
|
+
: metaTxns;
|
|
632
|
+
if (!txnsToSend || (selectedId && !txnsToSend[0])) {
|
|
633
|
+
throw new Error("Meta transaction not found");
|
|
634
|
+
}
|
|
635
|
+
const results = [];
|
|
636
|
+
for (const metaTxn of txnsToSend) {
|
|
637
|
+
if (!metaTxn)
|
|
638
|
+
continue;
|
|
639
|
+
const operationKey = `${metaTxn.chainId}-${metaTxn.id}`;
|
|
640
|
+
const lastSentTime = sentMetaTxns[operationKey];
|
|
641
|
+
const now = Date.now();
|
|
642
|
+
if (lastSentTime && now - lastSentTime < RETRY_WINDOW_MS) {
|
|
643
|
+
const timeLeft = Math.ceil((RETRY_WINDOW_MS - (now - lastSentTime)) / 1000);
|
|
644
|
+
console.log(`Meta transaction for ${operationKey} was sent recently. Wait ${timeLeft}s before retry`);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
try {
|
|
648
|
+
const chainId = parseInt(metaTxn.chainId);
|
|
649
|
+
if (Number.isNaN(chainId) || chainId <= 0) {
|
|
650
|
+
throw new Error(`Invalid chainId for meta transaction: ${chainId}`);
|
|
651
|
+
}
|
|
652
|
+
const chainRelayer = getRelayer(chainId);
|
|
653
|
+
if (!chainRelayer) {
|
|
654
|
+
throw new Error(`No relayer found for chainId: ${chainId}`);
|
|
655
|
+
}
|
|
656
|
+
const relevantPreconditions = intentPreconditions.filter((p) => p.chainId && parseInt(p.chainId) === chainId);
|
|
657
|
+
console.log(`Relaying meta transaction ${operationKey} to intent ${intentAddress} via relayer:`, chainRelayer);
|
|
658
|
+
const { opHash } = await chainRelayer.sendMetaTxn(metaTxn.walletAddress, metaTxn.contract, metaTxn.input, BigInt(metaTxn.chainId), undefined, relevantPreconditions);
|
|
659
|
+
const useBackupRelayer = false; // Disable backup relayer for now
|
|
660
|
+
if (useBackupRelayer) {
|
|
661
|
+
try {
|
|
662
|
+
// Fire and forget send tx to backup relayer
|
|
663
|
+
const backupRelayer = getBackupRelayer(chainId);
|
|
664
|
+
backupRelayer
|
|
665
|
+
?.sendMetaTxn(metaTxn.walletAddress, metaTxn.contract, metaTxn.input, BigInt(metaTxn.chainId), undefined, relevantPreconditions)
|
|
666
|
+
.then(() => { })
|
|
667
|
+
.catch(() => { });
|
|
668
|
+
}
|
|
669
|
+
catch { }
|
|
670
|
+
}
|
|
671
|
+
results.push({
|
|
672
|
+
operationKey,
|
|
673
|
+
opHash,
|
|
674
|
+
success: true,
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
catch (error) {
|
|
678
|
+
results.push({
|
|
679
|
+
operationKey,
|
|
680
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
681
|
+
success: false,
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
return results;
|
|
686
|
+
},
|
|
687
|
+
onSuccess: (results) => {
|
|
688
|
+
// Update states based on results
|
|
689
|
+
results.forEach(({ operationKey, opHash, success }) => {
|
|
690
|
+
if (success && opHash) {
|
|
691
|
+
setSentMetaTxns((prev) => ({
|
|
692
|
+
...prev,
|
|
693
|
+
[operationKey]: Date.now(),
|
|
694
|
+
}));
|
|
695
|
+
setOperationHashes((prev) => ({
|
|
696
|
+
...prev,
|
|
697
|
+
[operationKey]: opHash,
|
|
698
|
+
}));
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
},
|
|
702
|
+
onError: (error) => {
|
|
703
|
+
console.error("Error in meta-transaction process:", error);
|
|
704
|
+
},
|
|
705
|
+
retry: 5, // Allow up to 2 retries
|
|
706
|
+
retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 30000), // Exponential backoff
|
|
707
|
+
});
|
|
708
|
+
const [tokenAddress, setTokenAddress] = useState(null);
|
|
709
|
+
const [originChainId, setOriginChainId] = useState(null);
|
|
710
|
+
useEffect(() => {
|
|
711
|
+
if (!originIntentAddress ||
|
|
712
|
+
!intentCallsPayloads?.[0]?.chainId ||
|
|
713
|
+
!tokenAddress ||
|
|
714
|
+
!originChainId ||
|
|
715
|
+
!intentPreconditions ||
|
|
716
|
+
!account.address) {
|
|
717
|
+
setOriginCallParams(null);
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
try {
|
|
721
|
+
const intentAddressString = originIntentAddress;
|
|
722
|
+
if (!intentAddressString || !isAddress(intentAddressString)) {
|
|
723
|
+
setOriginCallParams(null);
|
|
724
|
+
return;
|
|
725
|
+
}
|
|
726
|
+
let calcTo;
|
|
727
|
+
let calcData = "0x";
|
|
728
|
+
let calcValue = 0n;
|
|
729
|
+
const recipientAddress = intentAddressString;
|
|
730
|
+
const isNative = tokenAddress === zeroAddress;
|
|
731
|
+
if (isNative) {
|
|
732
|
+
const nativePrecondition = intentPreconditions.find((p) => (p.type === "transfer-native" || p.type === "native-balance") &&
|
|
733
|
+
p.chainId === originChainId.toString());
|
|
734
|
+
const nativeMinAmount = nativePrecondition?.data?.minAmount?.toString() ??
|
|
735
|
+
nativePrecondition?.data?.min?.toString();
|
|
736
|
+
if (nativeMinAmount === undefined) {
|
|
737
|
+
throw new Error("Could not find native precondition (transfer-native or native-balance) or min amount");
|
|
738
|
+
}
|
|
739
|
+
calcValue = BigInt(nativeMinAmount);
|
|
740
|
+
calcTo = recipientAddress;
|
|
741
|
+
}
|
|
742
|
+
else {
|
|
743
|
+
const erc20Precondition = intentPreconditions.find((p) => p.type === "erc20-balance" &&
|
|
744
|
+
p.chainId === originChainId.toString() &&
|
|
745
|
+
p.data?.token &&
|
|
746
|
+
isAddressEqual(Address.from(p.data.token), Address.from(tokenAddress)));
|
|
747
|
+
const erc20MinAmount = erc20Precondition?.data?.min?.toString();
|
|
748
|
+
if (erc20MinAmount === undefined) {
|
|
749
|
+
throw new Error("Could not find ERC20 balance precondition or min amount");
|
|
750
|
+
}
|
|
751
|
+
calcData = getERC20TransferData({
|
|
752
|
+
recipient: recipientAddress,
|
|
753
|
+
amount: BigInt(erc20MinAmount),
|
|
754
|
+
});
|
|
755
|
+
calcTo = tokenAddress;
|
|
756
|
+
}
|
|
757
|
+
setOriginCallParams({
|
|
758
|
+
to: calcTo,
|
|
759
|
+
data: calcData,
|
|
760
|
+
value: calcValue,
|
|
761
|
+
chainId: originChainId,
|
|
762
|
+
error: undefined,
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
catch (error) {
|
|
766
|
+
console.error("[trails-sdk] Failed to calculate origin call params for UI:", error);
|
|
767
|
+
setOriginCallParams({
|
|
768
|
+
to: null,
|
|
769
|
+
data: null,
|
|
770
|
+
value: null,
|
|
771
|
+
chainId: null,
|
|
772
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
}, [
|
|
776
|
+
intentCallsPayloads,
|
|
777
|
+
tokenAddress,
|
|
778
|
+
originChainId,
|
|
779
|
+
intentPreconditions,
|
|
780
|
+
account.address,
|
|
781
|
+
originIntentAddress,
|
|
782
|
+
]);
|
|
783
|
+
// const checkPreconditionStatuses = useCallback(async () => {
|
|
784
|
+
// if (!intentPreconditions) return
|
|
785
|
+
// const statuses = await Promise.all(
|
|
786
|
+
// intentPreconditions.map(async (precondition) => {
|
|
787
|
+
// try {
|
|
788
|
+
// const chainIdString = precondition.chainId
|
|
789
|
+
// if (!chainIdString) {
|
|
790
|
+
// console.warn('[trails-sdk] Precondition missing chainId:', precondition)
|
|
791
|
+
// return false
|
|
792
|
+
// }
|
|
793
|
+
// const chainId = parseInt(chainIdString)
|
|
794
|
+
// if (isNaN(chainId) || chainId <= 0) {
|
|
795
|
+
// console.warn('[trails-sdk] Precondition has invalid chainId:', chainIdString, precondition)
|
|
796
|
+
// return false
|
|
797
|
+
// }
|
|
798
|
+
// const chainRelayer = getRelayer(chainId)
|
|
799
|
+
// if (!chainRelayer) {
|
|
800
|
+
// console.error(`[trails-sdk] No relayer found for chainId: ${chainId}`)
|
|
801
|
+
// return false
|
|
802
|
+
// }
|
|
803
|
+
// return await chainRelayer.checkPrecondition(precondition)
|
|
804
|
+
// } catch (error) {
|
|
805
|
+
// console.error('[trails-sdk] Error checking precondition:', error, 'Precondition:', precondition)
|
|
806
|
+
// return false
|
|
807
|
+
// }
|
|
808
|
+
// }),
|
|
809
|
+
// )
|
|
810
|
+
// setPreconditionStatuses(statuses)
|
|
811
|
+
// }, [intentPreconditions, getRelayer])
|
|
812
|
+
// useEffect(() => {
|
|
813
|
+
// // TODO: Remove this once we have a way to check precondition statuses
|
|
814
|
+
// if (false) {
|
|
815
|
+
// checkPreconditionStatuses()
|
|
816
|
+
// }
|
|
817
|
+
// }, [intentPreconditions, checkPreconditionStatuses])
|
|
818
|
+
// Add monitoring for each meta transaction
|
|
819
|
+
const metaTxnMonitorStatuses = useMetaTxnsMonitor(metaTxns, getRelayer);
|
|
820
|
+
// Create a stable dependency for the meta timestamp effect
|
|
821
|
+
const _stableMetaTxnStatusesKey = useMemo(() => {
|
|
822
|
+
if (!metaTxns || Object.keys(metaTxnMonitorStatuses).length === 0) {
|
|
823
|
+
return "no_statuses";
|
|
824
|
+
}
|
|
825
|
+
// Sort by a stable key (e.g., id) to ensure consistent order if metaTxns array order changes
|
|
826
|
+
// but content is the same, though metaTxns itself is a dependency, so this might be redundant if metaTxns order is stable.
|
|
827
|
+
const sortedTxnIds = metaTxns
|
|
828
|
+
.map((tx) => `${tx.chainId}-${tx.id}`)
|
|
829
|
+
.sort();
|
|
830
|
+
return sortedTxnIds
|
|
831
|
+
.map((key) => {
|
|
832
|
+
const statusObj = metaTxnMonitorStatuses[key];
|
|
833
|
+
return `${key}:${statusObj ? statusObj.status : "loading"}`;
|
|
834
|
+
})
|
|
835
|
+
.join(",");
|
|
836
|
+
}, [metaTxns, metaTxnMonitorStatuses]);
|
|
837
|
+
const processedTxns = useRef(new Set());
|
|
838
|
+
// Effect to fetch meta-transaction block timestamps
|
|
839
|
+
useEffect(() => {
|
|
840
|
+
console.log("[trails-sdk] Running meta-transaction block timestamp effect:", {
|
|
841
|
+
metaTxnsLength: metaTxns?.length,
|
|
842
|
+
monitorStatusesLength: Object.keys(metaTxnMonitorStatuses).length,
|
|
843
|
+
});
|
|
844
|
+
if (!metaTxns || metaTxns.length === 0) {
|
|
845
|
+
console.log("[trails-sdk] No meta transactions, clearing timestamps");
|
|
846
|
+
processedTxns.current.clear();
|
|
847
|
+
if (Object.keys(metaTxnBlockTimestamps).length > 0) {
|
|
848
|
+
setMetaTxnBlockTimestamps({});
|
|
849
|
+
}
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
if (!Object.keys(metaTxnMonitorStatuses).length) {
|
|
853
|
+
console.log("[trails-sdk] No monitor statuses yet, waiting...");
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
metaTxns.forEach(async (metaTxn) => {
|
|
857
|
+
const operationKey = `${metaTxn.chainId}-${metaTxn.id}`;
|
|
858
|
+
// Skip if already processed
|
|
859
|
+
if (processedTxns.current.has(operationKey)) {
|
|
860
|
+
console.log(`[trails-sdk] MetaTxn ${operationKey}: Already processed, skipping`);
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
const monitorStatus = metaTxnMonitorStatuses[operationKey];
|
|
864
|
+
if (!monitorStatus || monitorStatus.status !== "confirmed") {
|
|
865
|
+
console.log(`[trails-sdk] MetaTxn ${operationKey}: Status not confirmed, skipping`);
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
// Type assertion since we know it exists when status is "confirmed"
|
|
869
|
+
const transactionHash = monitorStatus.transactionHash;
|
|
870
|
+
if (!transactionHash) {
|
|
871
|
+
console.log(`[trails-sdk] MetaTxn ${operationKey}: No transaction hash, skipping`);
|
|
872
|
+
return;
|
|
873
|
+
}
|
|
874
|
+
console.log(`[trails-sdk] MetaTxn ${operationKey}: Processing transaction ${transactionHash}`);
|
|
875
|
+
processedTxns.current.add(operationKey);
|
|
876
|
+
try {
|
|
877
|
+
const chainId = parseInt(metaTxn.chainId);
|
|
878
|
+
if (Number.isNaN(chainId) || chainId <= 0) {
|
|
879
|
+
throw new Error(`Invalid chainId for meta transaction: ${metaTxn.chainId}`);
|
|
880
|
+
}
|
|
881
|
+
const chainConfig = getChainInfo(chainId);
|
|
882
|
+
const client = createPublicClient({
|
|
883
|
+
chain: chainConfig,
|
|
884
|
+
transport: http(),
|
|
885
|
+
});
|
|
886
|
+
const receipt = await client.getTransactionReceipt({
|
|
887
|
+
hash: transactionHash,
|
|
888
|
+
});
|
|
889
|
+
if (receipt && typeof receipt.blockNumber === "bigint") {
|
|
890
|
+
const block = await client.getBlock({
|
|
891
|
+
blockNumber: receipt.blockNumber,
|
|
892
|
+
});
|
|
893
|
+
console.log(`[trails-sdk] MetaTxn ${operationKey}: Got block timestamp ${block.timestamp}`);
|
|
894
|
+
setMetaTxnBlockTimestamps((prev) => ({
|
|
895
|
+
...prev,
|
|
896
|
+
[operationKey]: {
|
|
897
|
+
timestamp: Number(block.timestamp),
|
|
898
|
+
error: undefined,
|
|
899
|
+
},
|
|
900
|
+
}));
|
|
901
|
+
}
|
|
902
|
+
else {
|
|
903
|
+
console.warn(`[trails-sdk] MetaTxn ${operationKey}: No block number in receipt`);
|
|
904
|
+
setMetaTxnBlockTimestamps((prev) => ({
|
|
905
|
+
...prev,
|
|
906
|
+
[operationKey]: {
|
|
907
|
+
timestamp: null,
|
|
908
|
+
error: "Block number not found in receipt",
|
|
909
|
+
},
|
|
910
|
+
}));
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
catch (error) {
|
|
914
|
+
console.error(`[trails-sdk] MetaTxn ${operationKey}: Error:`, error);
|
|
915
|
+
setMetaTxnBlockTimestamps((prev) => ({
|
|
916
|
+
...prev,
|
|
917
|
+
[operationKey]: {
|
|
918
|
+
timestamp: null,
|
|
919
|
+
error: error.message || "Failed to fetch receipt/timestamp",
|
|
920
|
+
},
|
|
921
|
+
}));
|
|
922
|
+
}
|
|
923
|
+
});
|
|
924
|
+
}, [metaTxns, metaTxnMonitorStatuses, metaTxnBlockTimestamps]);
|
|
925
|
+
const updateAutoExecute = (enabled) => {
|
|
926
|
+
setIsAutoExecute(enabled);
|
|
927
|
+
};
|
|
928
|
+
function createIntent(args) {
|
|
929
|
+
createIntentMutation.mutate({
|
|
930
|
+
...args,
|
|
931
|
+
destinationSalt: Date.now().toString(),
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
function commitIntentConfig(args) {
|
|
935
|
+
console.log("[trails-sdk] commitIntentConfig", args);
|
|
936
|
+
commitIntentConfigMutation.mutate(args);
|
|
937
|
+
}
|
|
938
|
+
function updateOriginCallParams(args) {
|
|
939
|
+
if (!args) {
|
|
940
|
+
setOriginCallParams(null);
|
|
941
|
+
return;
|
|
942
|
+
}
|
|
943
|
+
const { originChainId, tokenAddress } = args;
|
|
944
|
+
setOriginChainId(originChainId);
|
|
945
|
+
setTokenAddress(tokenAddress);
|
|
946
|
+
}
|
|
947
|
+
function sendMetaTxn(selectedId) {
|
|
948
|
+
sendMetaTxnMutation.mutate({ selectedId });
|
|
949
|
+
}
|
|
950
|
+
const { chainId } = account;
|
|
951
|
+
const originChainIdFromParams = originCallParams?.chainId;
|
|
952
|
+
const createIntentPending = createIntentMutation.isPending;
|
|
953
|
+
const createIntentSuccess = createIntentMutation.isSuccess;
|
|
954
|
+
const createIntentError = createIntentMutation.error;
|
|
955
|
+
const createIntentArgs = createIntentMutation.variables;
|
|
956
|
+
const commitIntentConfigPending = commitIntentConfigMutation.isPending;
|
|
957
|
+
const commitIntentConfigSuccess = commitIntentConfigMutation.isSuccess;
|
|
958
|
+
const commitIntentConfigError = commitIntentConfigMutation.error;
|
|
959
|
+
const commitIntentConfigArgs = commitIntentConfigMutation.variables;
|
|
960
|
+
const sendMetaTxnPending = sendMetaTxnMutation.isPending;
|
|
961
|
+
const sendMetaTxnSuccess = sendMetaTxnMutation.isSuccess;
|
|
962
|
+
const sendMetaTxnError = sendMetaTxnMutation.error;
|
|
963
|
+
const sendMetaTxnArgs = sendMetaTxnMutation.variables;
|
|
964
|
+
return {
|
|
965
|
+
apiClient,
|
|
966
|
+
metaTxns,
|
|
967
|
+
intentCallsPayloads,
|
|
968
|
+
intentPreconditions,
|
|
969
|
+
trailsFee,
|
|
970
|
+
txnHash,
|
|
971
|
+
committedOriginIntentAddress,
|
|
972
|
+
committedDestinationIntentAddress,
|
|
973
|
+
verificationStatus,
|
|
974
|
+
getRelayer,
|
|
975
|
+
estimatedGas,
|
|
976
|
+
isEstimateError,
|
|
977
|
+
estimateError,
|
|
978
|
+
calculateIntentAddress,
|
|
979
|
+
calculateOriginAndDestinationIntentAddresses,
|
|
980
|
+
committedIntentConfig,
|
|
981
|
+
isLoadingCommittedConfig,
|
|
982
|
+
committedConfigError,
|
|
983
|
+
commitIntentConfig,
|
|
984
|
+
commitIntentConfigPending,
|
|
985
|
+
commitIntentConfigSuccess,
|
|
986
|
+
commitIntentConfigError,
|
|
987
|
+
commitIntentConfigArgs,
|
|
988
|
+
getIntentCallsPayloads,
|
|
989
|
+
operationHashes,
|
|
990
|
+
callIntentCallsPayload,
|
|
991
|
+
sendOriginTransaction,
|
|
992
|
+
switchChain,
|
|
993
|
+
isSwitchingChain,
|
|
994
|
+
switchChainError,
|
|
995
|
+
isTransactionInProgress,
|
|
996
|
+
isChainSwitchRequired: chainId !== originChainIdFromParams && !!originChainIdFromParams,
|
|
997
|
+
sendTransaction: sendOriginTxn.sendTransaction,
|
|
998
|
+
isSendingTransaction: sendOriginTxn.isPending,
|
|
999
|
+
originCallStatus,
|
|
1000
|
+
updateOriginCallStatus,
|
|
1001
|
+
isEstimatingGas,
|
|
1002
|
+
isAutoExecute,
|
|
1003
|
+
updateAutoExecute,
|
|
1004
|
+
receipt,
|
|
1005
|
+
isWaitingForReceipt,
|
|
1006
|
+
receiptIsSuccess,
|
|
1007
|
+
receiptIsError,
|
|
1008
|
+
receiptError,
|
|
1009
|
+
hasAutoExecuted,
|
|
1010
|
+
originCallSuccess: sendOriginTxn.isSuccess,
|
|
1011
|
+
sentMetaTxns,
|
|
1012
|
+
sendMetaTxn,
|
|
1013
|
+
sendMetaTxnPending,
|
|
1014
|
+
sendMetaTxnSuccess,
|
|
1015
|
+
sendMetaTxnError,
|
|
1016
|
+
sendMetaTxnArgs,
|
|
1017
|
+
clearIntent,
|
|
1018
|
+
metaTxnMonitorStatuses,
|
|
1019
|
+
createIntent,
|
|
1020
|
+
createIntentPending,
|
|
1021
|
+
createIntentSuccess,
|
|
1022
|
+
createIntentError,
|
|
1023
|
+
createIntentArgs,
|
|
1024
|
+
originCallParams,
|
|
1025
|
+
updateOriginCallParams,
|
|
1026
|
+
originBlockTimestamp,
|
|
1027
|
+
metaTxnBlockTimestamps,
|
|
1028
|
+
originIntentAddress,
|
|
1029
|
+
destinationIntentAddress,
|
|
1030
|
+
};
|
|
1031
|
+
}
|