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.
Files changed (359) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +42 -0
  3. package/dist/abi.d.ts +37 -0
  4. package/dist/abi.d.ts.map +1 -0
  5. package/dist/abi.js +36 -0
  6. package/dist/apiClient.d.ts +9 -0
  7. package/dist/apiClient.d.ts.map +1 -0
  8. package/dist/apiClient.js +18 -0
  9. package/dist/buffer.d.ts +3 -0
  10. package/dist/buffer.d.ts.map +1 -0
  11. package/dist/buffer.js +8 -0
  12. package/dist/cctp.d.ts +84 -0
  13. package/dist/cctp.d.ts.map +1 -0
  14. package/dist/cctp.js +401 -0
  15. package/dist/chainSwitch.d.ts +7 -0
  16. package/dist/chainSwitch.d.ts.map +1 -0
  17. package/dist/chainSwitch.js +33 -0
  18. package/dist/chains.d.ts +13 -0
  19. package/dist/chains.d.ts.map +1 -0
  20. package/dist/chains.js +95 -0
  21. package/dist/constants.d.ts +11 -0
  22. package/dist/constants.d.ts.map +1 -0
  23. package/dist/constants.js +16 -0
  24. package/dist/encoders.d.ts +7 -0
  25. package/dist/encoders.d.ts.map +1 -0
  26. package/dist/encoders.js +8 -0
  27. package/dist/error.d.ts +2 -0
  28. package/dist/error.d.ts.map +1 -0
  29. package/dist/error.js +12 -0
  30. package/dist/explorer.d.ts +12 -0
  31. package/dist/explorer.d.ts.map +1 -0
  32. package/dist/explorer.js +18 -0
  33. package/dist/gasless.d.ts +116 -0
  34. package/dist/gasless.d.ts.map +1 -0
  35. package/dist/gasless.js +297 -0
  36. package/dist/index.d.ts +13 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +9 -0
  39. package/dist/indexerClient.d.ts +9 -0
  40. package/dist/indexerClient.d.ts.map +1 -0
  41. package/dist/indexerClient.js +18 -0
  42. package/dist/intents.d.ts +83 -0
  43. package/dist/intents.d.ts.map +1 -0
  44. package/dist/intents.js +288 -0
  45. package/dist/metaTxnMonitor.d.ts +14 -0
  46. package/dist/metaTxnMonitor.d.ts.map +1 -0
  47. package/dist/metaTxnMonitor.js +121 -0
  48. package/dist/metaTxns.d.ts +6 -0
  49. package/dist/metaTxns.d.ts.map +1 -0
  50. package/dist/metaTxns.js +4 -0
  51. package/dist/paymasterSend.d.ts +90 -0
  52. package/dist/paymasterSend.d.ts.map +1 -0
  53. package/dist/paymasterSend.js +329 -0
  54. package/dist/preconditions.d.ts +11 -0
  55. package/dist/preconditions.d.ts.map +1 -0
  56. package/dist/preconditions.js +29 -0
  57. package/dist/prepareSend.d.ts +102 -0
  58. package/dist/prepareSend.d.ts.map +1 -0
  59. package/dist/prepareSend.js +1080 -0
  60. package/dist/prices.d.ts +18 -0
  61. package/dist/prices.d.ts.map +1 -0
  62. package/dist/prices.js +142 -0
  63. package/dist/queryParams.d.ts +9 -0
  64. package/dist/queryParams.d.ts.map +1 -0
  65. package/dist/queryParams.js +66 -0
  66. package/dist/relaySdk.d.ts +65 -0
  67. package/dist/relaySdk.d.ts.map +1 -0
  68. package/dist/relaySdk.js +314 -0
  69. package/dist/relayer.d.ts +23 -0
  70. package/dist/relayer.d.ts.map +1 -0
  71. package/dist/relayer.js +230 -0
  72. package/dist/sendUserOp.d.ts +140 -0
  73. package/dist/sendUserOp.d.ts.map +1 -0
  74. package/dist/sendUserOp.js +388 -0
  75. package/dist/sequenceWallet.d.ts +79 -0
  76. package/dist/sequenceWallet.d.ts.map +1 -0
  77. package/dist/sequenceWallet.js +374 -0
  78. package/dist/theme.d.ts +3 -0
  79. package/dist/theme.d.ts.map +1 -0
  80. package/dist/theme.js +1 -0
  81. package/dist/toSimpleSmartAccount.d.ts +95 -0
  82. package/dist/toSimpleSmartAccount.d.ts.map +1 -0
  83. package/dist/toSimpleSmartAccount.js +373 -0
  84. package/dist/tokenBalances.d.ts +118 -0
  85. package/dist/tokenBalances.d.ts.map +1 -0
  86. package/dist/tokenBalances.js +492 -0
  87. package/dist/tokens.d.ts +50 -0
  88. package/dist/tokens.d.ts.map +1 -0
  89. package/dist/tokens.js +356 -0
  90. package/dist/trails.d.ts +128 -0
  91. package/dist/trails.d.ts.map +1 -0
  92. package/dist/trails.js +1031 -0
  93. package/dist/umd/trails.min.js +12610 -0
  94. package/dist/umd/trails.min.js.map +1 -0
  95. package/dist/umd.d.ts +24 -0
  96. package/dist/umd.d.ts.map +1 -0
  97. package/dist/utils.d.ts +5 -0
  98. package/dist/utils.d.ts.map +1 -0
  99. package/dist/utils.js +9 -0
  100. package/dist/widget/ConstantsUtil-B-_-u8aQ.js +6 -0
  101. package/dist/widget/add-hVLs3ldJ.js +20 -0
  102. package/dist/widget/all-wallets-Cwxnx4BT.js +11 -0
  103. package/dist/widget/app-store-CAAVQjW0.js +22 -0
  104. package/dist/widget/apple-C3BSbglw.js +23 -0
  105. package/dist/widget/arrow-bottom-circle-BGU9MmsZ.js +16 -0
  106. package/dist/widget/arrow-bottom-hS_SA8Gp.js +13 -0
  107. package/dist/widget/arrow-left-CJZanWz7.js +13 -0
  108. package/dist/widget/arrow-right-C1qL8EMd.js +13 -0
  109. package/dist/widget/arrow-top-CbuCmbQs.js +13 -0
  110. package/dist/widget/bank-CXBEEGbb.js +19 -0
  111. package/dist/widget/bin-Dqzv3zCZ.js +9 -0
  112. package/dist/widget/bitcoin-4y3sovZp.js +18 -0
  113. package/dist/widget/browser-DyOl4_8m.js +1413 -0
  114. package/dist/widget/browser-t7Fh0sEU.js +19 -0
  115. package/dist/widget/card-Bo4CZkTs.js +19 -0
  116. package/dist/widget/ccip-BynehMIN.js +232 -0
  117. package/dist/widget/checkmark-DV6OKvnY.js +16 -0
  118. package/dist/widget/checkmark-bold-CAp1-IQ2.js +13 -0
  119. package/dist/widget/chevron-bottom-BjzsVzk9.js +13 -0
  120. package/dist/widget/chevron-left-CQZBDCiR.js +13 -0
  121. package/dist/widget/chevron-right-Dhg4zeZM.js +13 -0
  122. package/dist/widget/chevron-top-CDQmfJef.js +13 -0
  123. package/dist/widget/chrome-store-BNaC_b6w.js +66 -0
  124. package/dist/widget/circle-BC_GBj91.js +9 -0
  125. package/dist/widget/clock-BmF8-4a0.js +13 -0
  126. package/dist/widget/close-Bf61nZ8o.js +13 -0
  127. package/dist/widget/coinPlaceholder-7cZW2058.js +13 -0
  128. package/dist/widget/compass-CFC3yhnW.js +13 -0
  129. package/dist/widget/components/ChainImage.d.ts +8 -0
  130. package/dist/widget/components/ChainImage.d.ts.map +1 -0
  131. package/dist/widget/components/ChainImage.js +6 -0
  132. package/dist/widget/components/ConnectWallet.d.ts +18 -0
  133. package/dist/widget/components/ConnectWallet.d.ts.map +1 -0
  134. package/dist/widget/components/ConnectWallet.js +66 -0
  135. package/dist/widget/components/DebugScreensDropdown.d.ts +9 -0
  136. package/dist/widget/components/DebugScreensDropdown.d.ts.map +1 -0
  137. package/dist/widget/components/DebugScreensDropdown.js +40 -0
  138. package/dist/widget/components/FeeOptions.d.ts +17 -0
  139. package/dist/widget/components/FeeOptions.d.ts.map +1 -0
  140. package/dist/widget/components/FeeOptions.js +65 -0
  141. package/dist/widget/components/Footer.d.ts +9 -0
  142. package/dist/widget/components/Footer.d.ts.map +1 -0
  143. package/dist/widget/components/Footer.js +13 -0
  144. package/dist/widget/components/GreenCheckAnimation.d.ts +2 -0
  145. package/dist/widget/components/GreenCheckAnimation.d.ts.map +1 -0
  146. package/dist/widget/components/GreenCheckAnimation.js +74 -0
  147. package/dist/widget/components/Modal.d.ts +11 -0
  148. package/dist/widget/components/Modal.d.ts.map +1 -0
  149. package/dist/widget/components/Modal.js +36 -0
  150. package/dist/widget/components/Receipt.d.ts +13 -0
  151. package/dist/widget/components/Receipt.d.ts.map +1 -0
  152. package/dist/widget/components/Receipt.js +36 -0
  153. package/dist/widget/components/SendForm.d.ts +44 -0
  154. package/dist/widget/components/SendForm.d.ts.map +1 -0
  155. package/dist/widget/components/SendForm.js +177 -0
  156. package/dist/widget/components/TokenImage.d.ts +10 -0
  157. package/dist/widget/components/TokenImage.d.ts.map +1 -0
  158. package/dist/widget/components/TokenImage.js +8 -0
  159. package/dist/widget/components/TokenList.d.ts +16 -0
  160. package/dist/widget/components/TokenList.d.ts.map +1 -0
  161. package/dist/widget/components/TokenList.js +39 -0
  162. package/dist/widget/components/TransferPending.d.ts +11 -0
  163. package/dist/widget/components/TransferPending.d.ts.map +1 -0
  164. package/dist/widget/components/TransferPending.js +77 -0
  165. package/dist/widget/components/TransferPendingVertical.d.ts +18 -0
  166. package/dist/widget/components/TransferPendingVertical.d.ts.map +1 -0
  167. package/dist/widget/components/TransferPendingVertical.js +183 -0
  168. package/dist/widget/components/WalletConfirmation.d.ts +18 -0
  169. package/dist/widget/components/WalletConfirmation.d.ts.map +1 -0
  170. package/dist/widget/components/WalletConfirmation.js +22 -0
  171. package/dist/widget/config.d.ts +4 -0
  172. package/dist/widget/config.d.ts.map +1 -0
  173. package/dist/widget/config.js +3 -0
  174. package/dist/widget/copy-e0xXvKN0.js +20 -0
  175. package/dist/widget/cursor-CqM3v0xJ.js +8 -0
  176. package/dist/widget/cursor-transparent-CUQpdsCG.js +17 -0
  177. package/dist/widget/desktop-DUDGIRpM.js +14 -0
  178. package/dist/widget/disconnect-DUFST9QQ.js +13 -0
  179. package/dist/widget/discord-C1cj365Z.js +22 -0
  180. package/dist/widget/email-BHhmb_lX.js +703 -0
  181. package/dist/widget/embedded-wallet-CuuC4eah.js +467 -0
  182. package/dist/widget/ethereum-CfmBVfeB.js +15 -0
  183. package/dist/widget/etherscan-BSiynDhW.js +11 -0
  184. package/dist/widget/exclamation-triangle-DEiFNpHw.js +9 -0
  185. package/dist/widget/extension-mRmfCDxo.js +13 -0
  186. package/dist/widget/external-link-B4xMIVnW.js +13 -0
  187. package/dist/widget/facebook-CBAZStBR.js +31 -0
  188. package/dist/widget/farcaster-LHDEDf5S.js +17 -0
  189. package/dist/widget/filters-CBijuvFv.js +13 -0
  190. package/dist/widget/github-C3ILD420.js +23 -0
  191. package/dist/widget/google-CSj73POX.js +23 -0
  192. package/dist/widget/help-circle-2hdG5IdB.js +17 -0
  193. package/dist/widget/hooks/useAmountUsd.d.ts +13 -0
  194. package/dist/widget/hooks/useAmountUsd.d.ts.map +1 -0
  195. package/dist/widget/hooks/useAmountUsd.js +35 -0
  196. package/dist/widget/hooks/useSendForm.d.ts +125 -0
  197. package/dist/widget/hooks/useSendForm.d.ts.map +1 -0
  198. package/dist/widget/hooks/useSendForm.js +450 -0
  199. package/dist/widget/hooks/useTokenList.d.ts +52 -0
  200. package/dist/widget/hooks/useTokenList.d.ts.map +1 -0
  201. package/dist/widget/hooks/useTokenList.js +252 -0
  202. package/dist/widget/id-ByYSrwsd.js +17 -0
  203. package/dist/widget/if-defined-DRXJEhv7.js +752 -0
  204. package/dist/widget/image-C90L4Rf6.js +9 -0
  205. package/dist/widget/index-B3SlQ9v3.js +46 -0
  206. package/dist/widget/index-B8LPuLXQ.js +78 -0
  207. package/dist/widget/index-BDbworWA.js +171 -0
  208. package/dist/widget/index-BTlDgFSK.js +98 -0
  209. package/dist/widget/index-BUCcjXbd.js +306 -0
  210. package/dist/widget/index-BZ34edi2.js +1055 -0
  211. package/dist/widget/index-BiCU29wK.js +147 -0
  212. package/dist/widget/index-BlmqIKsY.js +266 -0
  213. package/dist/widget/index-BlviH5nG.js +55 -0
  214. package/dist/widget/index-Bwd5X3fS.js +8306 -0
  215. package/dist/widget/index-C5gmknHK.js +78 -0
  216. package/dist/widget/index-CD6dBcRj.js +76 -0
  217. package/dist/widget/index-CDlhy529.js +63 -0
  218. package/dist/widget/index-CHXa5ke-.js +59 -0
  219. package/dist/widget/index-CK94R-H7.js +22498 -0
  220. package/dist/widget/index-CQzo3m3x.js +182 -0
  221. package/dist/widget/index-CRT8cAwG.js +325 -0
  222. package/dist/widget/index-CY7Lt2Yu.js +310 -0
  223. package/dist/widget/index-CiKfAu1E.js +79 -0
  224. package/dist/widget/index-CkCu6rMi.js +258 -0
  225. package/dist/widget/index-CngLTu_R.js +517 -0
  226. package/dist/widget/index-CsMV8-em.js +2577 -0
  227. package/dist/widget/index-Cu2Wva8v.js +200 -0
  228. package/dist/widget/index-DKBxLTEF.js +240 -0
  229. package/dist/widget/index-DQEVT3dx.js +511 -0
  230. package/dist/widget/index-DU2HcCis.js +200 -0
  231. package/dist/widget/index-DutZGWNW.js +321 -0
  232. package/dist/widget/index-O0glArmc.js +182 -0
  233. package/dist/widget/index-O8FmRjKe.js +63719 -0
  234. package/dist/widget/index-RtKXrB6I.js +576 -0
  235. package/dist/widget/index-TIYtS0gE.js +88 -0
  236. package/dist/widget/index-dQNJvWHs.js +66 -0
  237. package/dist/widget/index-wmEwdsq7.js +909 -0
  238. package/dist/widget/index.d.ts +3 -0
  239. package/dist/widget/index.d.ts.map +1 -0
  240. package/dist/widget/index.js +2 -0
  241. package/dist/widget/info-DMPChDjV.js +8 -0
  242. package/dist/widget/info-circle-DAvS_7nY.js +17 -0
  243. package/dist/widget/lightbulb-DnZ9mNEs.js +8 -0
  244. package/dist/widget/lit-html-BRjl1r6K.js +243 -0
  245. package/dist/widget/mail-DpaVSOP8.js +13 -0
  246. package/dist/widget/mobile-CRvdyu7I.js +14 -0
  247. package/dist/widget/more-C5VqW9PR.js +16 -0
  248. package/dist/widget/network-placeholder-CZ0vApma.js +19 -0
  249. package/dist/widget/nftPlaceholder-7jjIK2bT.js +13 -0
  250. package/dist/widget/off-4mHjJLLX.js +9 -0
  251. package/dist/widget/onramp-Bc0ozVsw.js +929 -0
  252. package/dist/widget/play-store-Uocul8nC.js +37 -0
  253. package/dist/widget/plus-DrYF7siO.js +18 -0
  254. package/dist/widget/prepareSend-BQJmzM5B.js +54987 -0
  255. package/dist/widget/qr-code-DcnGMUB3.js +11 -0
  256. package/dist/widget/receive-fvIVd7R_.js +184 -0
  257. package/dist/widget/recycle-horizontal-DrDwXC4D.js +14 -0
  258. package/dist/widget/ref-CXNmEjML.js +41 -0
  259. package/dist/widget/refresh-OK9lIPLS.js +13 -0
  260. package/dist/widget/reown-logo-C-Qn7mS3.js +17 -0
  261. package/dist/widget/search-DZqv1oKg.js +13 -0
  262. package/dist/widget/send-CJlmI-xe.js +1039 -0
  263. package/dist/widget/send-otoEC8uU.js +20 -0
  264. package/dist/widget/socials-BJciurWF.js +599 -0
  265. package/dist/widget/solana-Bv5Hs_0T.js +18 -0
  266. package/dist/widget/swapHorizontal-BzOPGV37.js +13 -0
  267. package/dist/widget/swapHorizontalBold-axyHnSmj.js +13 -0
  268. package/dist/widget/swapHorizontalMedium-C6YOPfPz.js +21 -0
  269. package/dist/widget/swapHorizontalRoundedBold-yVcLbWNT.js +13 -0
  270. package/dist/widget/swapVertical-BDjxt9pE.js +13 -0
  271. package/dist/widget/swaps-DEWNj4kd.js +1637 -0
  272. package/dist/widget/telegram-BQJD7dlP.js +21 -0
  273. package/dist/widget/three-dots-DW9jmSMG.js +10 -0
  274. package/dist/widget/transactions-uCseGQQt.js +38 -0
  275. package/dist/widget/twitch-XugxDfOE.js +23 -0
  276. package/dist/widget/twitterIcon-DQVObQUL.js +11 -0
  277. package/dist/widget/types.d.ts +51 -0
  278. package/dist/widget/types.d.ts.map +1 -0
  279. package/dist/widget/types.js +1 -0
  280. package/dist/widget/verify-DpMYHxLf.js +13 -0
  281. package/dist/widget/verify-filled-KpEL6ZJ_.js +13 -0
  282. package/dist/widget/w3m-modal-C8e-6Kba.js +1047 -0
  283. package/dist/widget/wallet-D8ssEB0o.js +13 -0
  284. package/dist/widget/wallet-placeholder-HtAy21Wc.js +19 -0
  285. package/dist/widget/walletconnect-Bp_4XfrY.js +37 -0
  286. package/dist/widget/warning-circle-FgYS7P7n.js +17 -0
  287. package/dist/widget/widget/index.js +7 -0
  288. package/dist/widget/widget.d.ts +47 -0
  289. package/dist/widget/widget.d.ts.map +1 -0
  290. package/dist/widget/widget.js +932 -0
  291. package/dist/widget/x-DlZBoP9k.js +17 -0
  292. package/dist/widget/x-mark-Ba9pt-_h.js +8 -0
  293. package/package.json +102 -8
  294. package/src/abi.ts +38 -0
  295. package/src/apiClient.ts +32 -0
  296. package/src/buffer.ts +10 -0
  297. package/src/cctp.ts +579 -0
  298. package/src/chainSwitch.ts +55 -0
  299. package/src/chains.ts +124 -0
  300. package/src/constants.ts +26 -0
  301. package/src/encoders.ts +20 -0
  302. package/src/error.ts +15 -0
  303. package/src/explorer.ts +37 -0
  304. package/src/gasless.ts +545 -0
  305. package/src/index.ts +48 -0
  306. package/src/indexerClient.ts +36 -0
  307. package/src/intents.ts +537 -0
  308. package/src/metaTxnMonitor.ts +163 -0
  309. package/src/metaTxns.ts +21 -0
  310. package/src/paymasterSend.ts +503 -0
  311. package/src/preconditions.ts +52 -0
  312. package/src/prepareSend.ts +1849 -0
  313. package/src/prices.ts +186 -0
  314. package/src/queryParams.ts +80 -0
  315. package/src/relaySdk.ts +481 -0
  316. package/src/relayer.ts +255 -0
  317. package/src/sendUserOp.ts +570 -0
  318. package/src/sequenceWallet.ts +579 -0
  319. package/src/theme.ts +2 -0
  320. package/src/toSimpleSmartAccount.ts +567 -0
  321. package/src/tokenBalances.ts +760 -0
  322. package/src/tokens.ts +471 -0
  323. package/src/trails.ts +1591 -0
  324. package/src/types.d.ts +11 -0
  325. package/src/umd.tsx +49 -0
  326. package/src/utils.ts +16 -0
  327. package/src/vite-env.d.ts +4 -0
  328. package/src/widget/assets/MetaMask-icon-fox-with-margins.svg +31 -0
  329. package/src/widget/assets/MetaMask-icon-fox.svg +26 -0
  330. package/src/widget/assets/MetaMask-logo-black.svg +3 -0
  331. package/src/widget/assets/MetaMask-logo-white.svg +16 -0
  332. package/src/widget/assets/Privy_Brandmark_Black.svg +9 -0
  333. package/src/widget/assets/Privy_Brandmark_White.svg +9 -0
  334. package/src/widget/assets/Trails-logo-black.svg +11 -0
  335. package/src/widget/assets/Trails-logo-white.svg +11 -0
  336. package/src/widget/components/ChainImage.tsx +28 -0
  337. package/src/widget/components/ConnectWallet.tsx +206 -0
  338. package/src/widget/components/DebugScreensDropdown.tsx +88 -0
  339. package/src/widget/components/FeeOptions.tsx +199 -0
  340. package/src/widget/components/Footer.tsx +51 -0
  341. package/src/widget/components/GreenCheckAnimation.tsx +119 -0
  342. package/src/widget/components/Modal.tsx +97 -0
  343. package/src/widget/components/Receipt.tsx +237 -0
  344. package/src/widget/components/SendForm.tsx +695 -0
  345. package/src/widget/components/TokenImage.tsx +37 -0
  346. package/src/widget/components/TokenList.tsx +287 -0
  347. package/src/widget/components/TransferPending.tsx +204 -0
  348. package/src/widget/components/TransferPendingVertical.tsx +412 -0
  349. package/src/widget/components/WalletConfirmation.tsx +172 -0
  350. package/src/widget/config.ts +5 -0
  351. package/src/widget/hooks/useAmountUsd.ts +59 -0
  352. package/src/widget/hooks/useSendForm.ts +715 -0
  353. package/src/widget/hooks/useTokenList.ts +397 -0
  354. package/src/widget/index.css +2 -0
  355. package/src/widget/index.tsx +8 -0
  356. package/src/widget/types/svg.d.ts +8 -0
  357. package/src/widget/types.ts +59 -0
  358. package/src/widget/widget.tsx +1438 -0
  359. package/index.js +0 -1
@@ -0,0 +1,1438 @@
1
+ import "@0xsequence/design-system/preset"
2
+ import { SequenceHooksContext, SequenceHooksProvider } from "@0xsequence/hooks"
3
+ import type { MetaTxnReceipt } from "@0xsequence/trails-relayer"
4
+ import {
5
+ PrivyProvider,
6
+ useLogin,
7
+ usePrivy,
8
+ useWallets as usePrivyWallets,
9
+ } from "@privy-io/react-auth"
10
+ import {
11
+ createConfig as createPrivyWagmiConfig,
12
+ useSetActiveWallet,
13
+ WagmiProvider,
14
+ } from "@privy-io/wagmi"
15
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
16
+ import { AnimatePresence, motion } from "motion/react"
17
+ import React, {
18
+ forwardRef,
19
+ StrictMode,
20
+ useCallback,
21
+ useContext,
22
+ useEffect,
23
+ useImperativeHandle,
24
+ useRef,
25
+ useState,
26
+ } from "react"
27
+ import { createPortal } from "react-dom"
28
+ import type { Chain, TransactionReceipt, WalletClient } from "viem"
29
+ import { createWalletClient, custom, http } from "viem"
30
+ import { mainnet } from "viem/chains"
31
+ import type { Connector } from "wagmi"
32
+ import {
33
+ createConfig,
34
+ useAccount,
35
+ useConnect,
36
+ useDisconnect,
37
+ WagmiContext,
38
+ } from "wagmi"
39
+ import { injected } from "wagmi/connectors"
40
+ import { useAPIClient } from "../apiClient.js"
41
+ import { getChainInfo } from "../chains.js"
42
+ import { useIndexerGatewayClient } from "../indexerClient.js"
43
+ import type { TransactionState } from "../prepareSend.js"
44
+ import type { RelayerEnv } from "../relayer.js"
45
+ import type { ActiveTheme, Theme } from "../theme.js"
46
+ import type { WalletOption } from "./components/ConnectWallet.js"
47
+ import { ConnectWallet } from "./components/ConnectWallet.js"
48
+ import Footer from "./components/Footer.js"
49
+ import Modal from "./components/Modal.js"
50
+ import Receipt from "./components/Receipt.js"
51
+ import SendForm from "./components/SendForm.js"
52
+ import TokenList from "./components/TokenList.js"
53
+ import TransferPending from "./components/TransferPendingVertical.js"
54
+ import WalletConfirmation from "./components/WalletConfirmation.js"
55
+ import { defaultPrivyAppId, defaultPrivyClientId } from "./config.js"
56
+ import { useAmountUsd } from "./hooks/useAmountUsd.js"
57
+ import css from "./index.css?inline"
58
+
59
+ type Screen =
60
+ | "connect"
61
+ | "tokens"
62
+ | "send"
63
+ | "wallet-confirmation"
64
+ | "pending"
65
+ | "receipt"
66
+
67
+ export const defaultWalletOptions = ["injected", "privy"]
68
+
69
+ interface Token {
70
+ id: number
71
+ name: string
72
+ symbol: string
73
+ balance: string
74
+ imageUrl: string
75
+ chainId: number
76
+ contractAddress: string
77
+ contractInfo?: {
78
+ decimals: number
79
+ symbol: string
80
+ name: string
81
+ }
82
+ }
83
+
84
+ export type TrailsWidgetProps = {
85
+ appId: string
86
+ sequenceIndexerUrl?: string | null
87
+ sequenceApiUrl?: string | null
88
+ sequenceEnv?: RelayerEnv
89
+ toAddress?: string | null
90
+ toAmount?: string | null
91
+ toChainId?: number | string | null
92
+ toToken?: string | null
93
+ toCalldata?: string | null
94
+ children?: React.ReactNode
95
+ renderInline?: boolean
96
+ theme?: Theme
97
+ walletOptions?: string[]
98
+ onOriginConfirmation?: (txHash: string, chainId: number) => void
99
+ onDestinationConfirmation?: (txHash: string, chainId: number) => void
100
+ privyAppId?: string
101
+ privyClientId?: string
102
+ useSourceTokenForButtonText?: boolean
103
+ paymasterUrls?: Array<{ chainId: number; url: string }>
104
+ gasless?: boolean
105
+ buttonText?: string
106
+ }
107
+
108
+ export interface TrailsWidgetRef {
109
+ openModal: () => void
110
+ closeModal: () => void
111
+ isModalOpen: boolean
112
+ }
113
+
114
+ const queryClient = new QueryClient()
115
+
116
+ // Function to get system theme preference
117
+ const getSystemTheme = (): ActiveTheme => {
118
+ if (typeof window === "undefined") return "light"
119
+ return window.matchMedia("(prefers-color-scheme: dark)").matches
120
+ ? "dark"
121
+ : "light"
122
+ }
123
+
124
+ // Function to get initial theme based on mode
125
+ const getInitialTheme = (mode: Theme): ActiveTheme => {
126
+ if (mode === "auto") {
127
+ return getSystemTheme()
128
+ }
129
+ return mode as ActiveTheme
130
+ }
131
+
132
+ const WALLET_CONFIGS: Record<
133
+ string,
134
+ { id: string; name: string; connector: () => any }
135
+ > = {
136
+ injected: {
137
+ id: "injected",
138
+ name: "Injected Web3",
139
+ connector: injected,
140
+ },
141
+ privy: {
142
+ id: "privy",
143
+ name: "Privy",
144
+ connector: () => {},
145
+ },
146
+ } as const
147
+
148
+ // Create a custom hook for theme management
149
+ const useThemeManager = (initialTheme: Theme) => {
150
+ const [theme, setTheme] = useState<ActiveTheme>(getInitialTheme(initialTheme))
151
+ const [themeMode, setThemeMode] = useState<Theme>(initialTheme)
152
+
153
+ useEffect(() => {
154
+ if (themeMode !== "auto") return
155
+
156
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
157
+ const handleChange = (e: MediaQueryListEvent) => {
158
+ setTheme(e.matches ? "dark" : "light")
159
+ }
160
+
161
+ setTheme(mediaQuery.matches ? "dark" : "light")
162
+ mediaQuery.addEventListener("change", handleChange)
163
+ return () => mediaQuery.removeEventListener("change", handleChange)
164
+ }, [themeMode])
165
+
166
+ useEffect(() => {
167
+ setThemeMode(initialTheme)
168
+ setTheme(getInitialTheme(initialTheme))
169
+ }, [initialTheme])
170
+
171
+ return { theme, themeMode }
172
+ }
173
+
174
+ // Create a custom hook for wallet management
175
+ const useWalletManager = (
176
+ address: string | undefined,
177
+ chainId: number | undefined,
178
+ connector: Connector | undefined,
179
+ ) => {
180
+ const [walletClient, setWalletClient] = useState<WalletClient | null>(null)
181
+
182
+ useEffect(() => {
183
+ const connect = async () => {
184
+ try {
185
+ if (!connector) {
186
+ return
187
+ }
188
+ const activeProvider = await connector.getProvider?.()
189
+
190
+ if (activeProvider && address && chainId) {
191
+ const chain = getChainInfo(chainId)
192
+ if (!chain) {
193
+ return
194
+ }
195
+
196
+ const client = createWalletClient({
197
+ account: address as `0x${string}`,
198
+ chain,
199
+ transport: custom(activeProvider as any),
200
+ })
201
+
202
+ setWalletClient(client)
203
+ }
204
+ } catch (error) {
205
+ console.error("[trails-sdk] Failed to connect wallet", error)
206
+ }
207
+ }
208
+ connect().catch(console.error)
209
+ }, [address, chainId, connector])
210
+
211
+ return walletClient
212
+ }
213
+
214
+ // Create a custom hook for transaction state management
215
+ const useTransactionState = (
216
+ onOriginConfirmation?: (txHash: string, chainId: number) => void,
217
+ onDestinationConfirmation?: (txHash: string, chainId: number) => void,
218
+ ) => {
219
+ const [originTxHash, setOriginTxHash] = useState("")
220
+ const [originChainId, setOriginChainId] = useState<number | null>(null)
221
+ const [destinationTxHash, setDestinationTxHash] = useState("")
222
+ const [destinationChainId, setDestinationChainId] = useState<number | null>(
223
+ null,
224
+ )
225
+ const [transactionStates, setTransactionStates] = useState<
226
+ TransactionState[]
227
+ >([])
228
+
229
+ useEffect(() => {
230
+ if (onOriginConfirmation && originTxHash && originChainId) {
231
+ onOriginConfirmation(originTxHash, originChainId)
232
+ }
233
+ }, [originTxHash, onOriginConfirmation, originChainId])
234
+
235
+ useEffect(() => {
236
+ if (onDestinationConfirmation && destinationTxHash && destinationChainId) {
237
+ onDestinationConfirmation(destinationTxHash, destinationChainId)
238
+ }
239
+ }, [destinationTxHash, onDestinationConfirmation, destinationChainId])
240
+
241
+ return {
242
+ originTxHash,
243
+ setOriginTxHash,
244
+ originChainId,
245
+ setOriginChainId,
246
+ destinationTxHash,
247
+ setDestinationTxHash,
248
+ destinationChainId,
249
+ setDestinationChainId,
250
+ transactionStates,
251
+ setTransactionStates,
252
+ }
253
+ }
254
+
255
+ const WidgetInner = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
256
+ (
257
+ {
258
+ appId: sequenceProjectAccessKey,
259
+ sequenceIndexerUrl,
260
+ sequenceApiUrl,
261
+ sequenceEnv,
262
+ toAddress,
263
+ toAmount,
264
+ toChainId,
265
+ toToken,
266
+ toCalldata,
267
+ children,
268
+ renderInline = true,
269
+ theme: initialTheme = "auto",
270
+ walletOptions,
271
+ onOriginConfirmation,
272
+ onDestinationConfirmation,
273
+ useSourceTokenForButtonText,
274
+ paymasterUrls,
275
+ gasless,
276
+ buttonText,
277
+ },
278
+ ref,
279
+ ) => {
280
+ const { address, isConnected, chainId, connector } = useAccount()
281
+ const { disconnectAsync } = useDisconnect()
282
+ const { theme } = useThemeManager(initialTheme)
283
+ const [isModalOpen, setIsModalOpen] = useState(false)
284
+ const [currentScreen, setCurrentScreen] = useState<Screen>(
285
+ isConnected ? "tokens" : "connect",
286
+ )
287
+ const [selectedToken, setSelectedToken] = useState<Token | null>(null)
288
+ const [error, setError] = useState<string | null>(null)
289
+ const [intentAddress, setIntentAddress] = useState<string | null>(null)
290
+ const [originTokenInfo, setOriginTokenInfo] = useState<{
291
+ amount: string
292
+ amountUsd: string
293
+ tokenSymbol: string
294
+ tokenName: string
295
+ chainId: number
296
+ imageUrl: string
297
+ } | null>(null)
298
+ const [showWalletConfirmRetry, setShowWalletConfirmRetry] = useState(false)
299
+ const [walletConfirmRetryHandler, setWalletConfirmRetryHandler] = useState<
300
+ (() => Promise<void>) | null
301
+ >(null)
302
+ const { connect } = useConnect()
303
+
304
+ const {
305
+ connectWallet: privyConnectWallet,
306
+ ready: privyReady,
307
+ logout: privyLogout,
308
+ } = usePrivy()
309
+
310
+ const { login: loginPrivy } = useLogin()
311
+ const { wallets: privyWallets } = usePrivyWallets()
312
+ const { setActiveWallet: setPrivyActiveWallet } = useSetActiveWallet()
313
+ const usePrivyLogin = true // Set to true to use Privy email login options
314
+
315
+ const walletClient = useWalletManager(address, chainId, connector)
316
+
317
+ const {
318
+ setOriginTxHash,
319
+ setDestinationTxHash,
320
+ setDestinationChainId,
321
+ setOriginChainId,
322
+ transactionStates,
323
+ setTransactionStates,
324
+ } = useTransactionState(onOriginConfirmation, onDestinationConfirmation)
325
+
326
+ // Update screen based on connection state
327
+ useEffect(() => {
328
+ if (isConnected) {
329
+ if (currentScreen === "connect") {
330
+ setCurrentScreen("tokens")
331
+ }
332
+ } else {
333
+ if (currentScreen !== "connect") {
334
+ setTimeout(() => {
335
+ setCurrentScreen("connect")
336
+ }, 0)
337
+ }
338
+ }
339
+ }, [isConnected, currentScreen])
340
+
341
+ const indexerGatewayClient = useIndexerGatewayClient({
342
+ indexerGatewayUrl: sequenceIndexerUrl || undefined,
343
+ projectAccessKey: sequenceProjectAccessKey,
344
+ })
345
+
346
+ const apiClient = useAPIClient({
347
+ apiUrl: sequenceApiUrl || undefined,
348
+ projectAccessKey: sequenceProjectAccessKey,
349
+ })
350
+
351
+ const handleWalletConnect = async (walletId: string) => {
352
+ try {
353
+ setError(null)
354
+ const config = WALLET_CONFIGS[walletId as keyof typeof WALLET_CONFIGS]
355
+ if (!config) {
356
+ setError(`No configuration found for wallet: ${walletId}`)
357
+ return
358
+ }
359
+ if (walletId === "injected") {
360
+ await connect({ connector: config.connector() })
361
+ } else if (walletId === "privy") {
362
+ console.log("[trails-sdk] Privy ready", privyReady)
363
+ if (!privyReady) {
364
+ return
365
+ }
366
+ try {
367
+ await disconnectAsync()
368
+ } catch (error) {
369
+ console.error("[trails-sdk] Failed to disconnect", error)
370
+ }
371
+ if (usePrivyLogin) {
372
+ try {
373
+ await privyLogout()
374
+ } catch (error) {
375
+ console.error("[trails-sdk] Failed to logout Privy", error)
376
+ }
377
+ try {
378
+ await loginPrivy()
379
+ } catch (error) {
380
+ console.error("[trails-sdk] Failed to login Privy", error)
381
+ }
382
+ } else {
383
+ await privyConnectWallet()
384
+ }
385
+ }
386
+ console.log(`[trails-sdk] Connected to ${config.name}`)
387
+ } catch (error) {
388
+ console.error("[trails-sdk] Failed to connect:", error)
389
+ setError(
390
+ error instanceof Error ? error.message : "Failed to connect wallet",
391
+ )
392
+ }
393
+ }
394
+
395
+ useEffect(() => {
396
+ if (privyWallets?.length === 0 || !walletOptions?.includes("privy")) {
397
+ return
398
+ }
399
+ const latestWallet = privyWallets?.sort(
400
+ (a, b) => a.connectedAt - b.connectedAt,
401
+ )?.[0]
402
+ if (latestWallet) {
403
+ console.log("[trails-sdk] Setting Privy active wallet", latestWallet)
404
+ setPrivyActiveWallet(latestWallet)
405
+ }
406
+ }, [privyWallets, setPrivyActiveWallet, walletOptions])
407
+
408
+ const handleWalletDisconnect = () => {
409
+ setError(null)
410
+
411
+ if (connector?.name?.toLowerCase()?.includes("privy")) {
412
+ Promise.resolve()
413
+ .then(async () => {
414
+ try {
415
+ await disconnectAsync()
416
+ } catch (error) {
417
+ console.error("[trails-sdk] Failed to disconnect", error)
418
+ }
419
+ })
420
+ .then(async () => {
421
+ try {
422
+ await privyLogout()
423
+ } catch (error) {
424
+ console.error("[trails-sdk] Failed to logout Privy", error)
425
+ }
426
+ })
427
+ .then(async () => {
428
+ setPrivyActiveWallet(null as any)
429
+ })
430
+ .finally(() => {
431
+ setCurrentScreen("connect")
432
+ })
433
+ } else {
434
+ setCurrentScreen("connect")
435
+ }
436
+ }
437
+
438
+ const handleContinue = () => {
439
+ setCurrentScreen("tokens")
440
+ }
441
+
442
+ const getAvailableWallets = (): WalletOption[] => {
443
+ const requestedWallets = walletOptions || defaultWalletOptions
444
+ const availableWallets = requestedWallets
445
+ .filter((id) => WALLET_CONFIGS[id as keyof typeof WALLET_CONFIGS])
446
+ .map((id) => {
447
+ const config = WALLET_CONFIGS[id as keyof typeof WALLET_CONFIGS]
448
+ if (!config) return null
449
+ return {
450
+ id: config.id,
451
+ name: config.name,
452
+ }
453
+ })
454
+ .filter(Boolean)
455
+
456
+ return availableWallets as WalletOption[]
457
+ }
458
+
459
+ const handleTokenSelect = (token: Token) => {
460
+ try {
461
+ setError(null)
462
+ setSelectedToken(token)
463
+ setCurrentScreen("send")
464
+ } catch (err) {
465
+ setError(
466
+ err instanceof Error ? err.message : "An unknown error occurred",
467
+ )
468
+ }
469
+ }
470
+
471
+ const handleOnSend = async (amount: string, recipient: string) => {
472
+ console.log("[trails-sdk] handleOnSend", amount, recipient)
473
+ }
474
+
475
+ const handleSendAnother = () => {
476
+ setCurrentScreen("tokens")
477
+ resetState()
478
+ }
479
+
480
+ const resetState = useCallback(() => {
481
+ setCurrentScreen("connect")
482
+ setSelectedToken(null)
483
+ setOriginTxHash("")
484
+ setOriginChainId(null)
485
+ setDestinationTxHash("")
486
+ setDestinationChainId(null)
487
+ setTransactionStates([])
488
+ setIntentAddress(null)
489
+ setOriginTokenInfo(null)
490
+ }, [
491
+ setDestinationTxHash,
492
+ setDestinationChainId,
493
+ setTransactionStates,
494
+ setOriginTxHash,
495
+ setOriginChainId,
496
+ ])
497
+
498
+ // Expose modal control methods via ref
499
+ useImperativeHandle(
500
+ ref,
501
+ () => ({
502
+ openModal: () => {
503
+ setIsModalOpen(true)
504
+ },
505
+ closeModal: () => {
506
+ setIsModalOpen(false)
507
+ resetState()
508
+ },
509
+ isModalOpen,
510
+ }),
511
+ [isModalOpen, resetState],
512
+ )
513
+
514
+ const handleCloseModal = () => {
515
+ setIsModalOpen(false)
516
+ resetState()
517
+ }
518
+
519
+ const handleBack = () => {
520
+ setError(null)
521
+ switch (currentScreen) {
522
+ case "tokens":
523
+ setCurrentScreen("connect")
524
+ break
525
+ case "send":
526
+ setCurrentScreen("tokens")
527
+ setSelectedToken(null)
528
+ break
529
+ case "wallet-confirmation":
530
+ setCurrentScreen("send")
531
+ break
532
+ case "receipt":
533
+ setCurrentScreen("tokens")
534
+ setSelectedToken(null)
535
+ setDestinationTxHash("")
536
+ setDestinationChainId(null)
537
+ setOriginTxHash("")
538
+ setOriginChainId(null)
539
+ break
540
+ default:
541
+ break
542
+ }
543
+ }
544
+
545
+ function handleTransferComplete(data?: {
546
+ originChainId: number
547
+ destinationChainId: number
548
+ originUserTxReceipt: TransactionReceipt | null
549
+ originMetaTxnReceipt: MetaTxnReceipt | null
550
+ destinationMetaTxnReceipt: MetaTxnReceipt | null
551
+ }) {
552
+ if (data) {
553
+ if (data.originUserTxReceipt) {
554
+ setOriginTxHash(data.originUserTxReceipt.transactionHash)
555
+ }
556
+
557
+ if (data.originChainId) {
558
+ setOriginChainId(data.originChainId)
559
+ }
560
+
561
+ if (data.destinationMetaTxnReceipt || data.originUserTxReceipt) {
562
+ setDestinationTxHash(
563
+ (data.destinationMetaTxnReceipt as MetaTxnReceipt)?.txnHash ||
564
+ (data.originUserTxReceipt as TransactionReceipt)?.transactionHash,
565
+ )
566
+ }
567
+
568
+ if (data.destinationChainId) {
569
+ setDestinationChainId(data.destinationChainId)
570
+ }
571
+
572
+ setCurrentScreen("receipt")
573
+ }
574
+ }
575
+
576
+ function handleTransactionStateChange(
577
+ _transactionStates: TransactionState[],
578
+ ) {
579
+ console.log(
580
+ "[trails-sdk] transactionStates from widget",
581
+ _transactionStates,
582
+ )
583
+ setTransactionStates([..._transactionStates])
584
+ }
585
+
586
+ const handleDebugScreenSelect = (screen: string) => {
587
+ // Reset necessary state based on the target screen
588
+ setError(null)
589
+
590
+ switch (screen.toLowerCase()) {
591
+ case "connect":
592
+ setCurrentScreen("connect")
593
+ setSelectedToken(null)
594
+ setTransactionStates([])
595
+ break
596
+ case "tokens":
597
+ if (isConnected) {
598
+ setCurrentScreen("tokens")
599
+ setSelectedToken(null)
600
+ setTransactionStates([])
601
+ }
602
+ break
603
+ case "send":
604
+ // Set dummy USDC token for debug mode
605
+ setSelectedToken({
606
+ id: 1,
607
+ name: "USD Coin",
608
+ symbol: "USDC",
609
+ balance: "1000000000",
610
+ imageUrl:
611
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
612
+ chainId: 1,
613
+ contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
614
+ contractInfo: {
615
+ decimals: 6,
616
+ symbol: "USDC",
617
+ name: "USD Coin",
618
+ },
619
+ })
620
+
621
+ setCurrentScreen("send")
622
+ setTransactionStates([])
623
+
624
+ break
625
+ case "wallet confirmation":
626
+ // Set dummy USDC token for debug mode
627
+ setSelectedToken({
628
+ id: 1,
629
+ name: "USD Coin",
630
+ symbol: "USDC",
631
+ balance: "1000000000",
632
+ imageUrl:
633
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
634
+ chainId: 1,
635
+ contractAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
636
+ contractInfo: {
637
+ decimals: 6,
638
+ symbol: "USDC",
639
+ name: "USD Coin",
640
+ },
641
+ })
642
+
643
+ setCurrentScreen("wallet-confirmation")
644
+ setIntentAddress("0x5A0fb747531bC369367CB031472b89ea4D5c6Df7")
645
+ setOriginTokenInfo({
646
+ amount: "1",
647
+ amountUsd: "$0.01",
648
+ tokenSymbol: "USDC",
649
+ tokenName: "USD Coin",
650
+ chainId: 137,
651
+ imageUrl:
652
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
653
+ })
654
+ setTransactionStates([])
655
+ break
656
+ case "pending 1-item-0-confirmed":
657
+ // Set dummy transaction states for debug mode - showing all steps
658
+ setTransactionStates([
659
+ {
660
+ transactionHash:
661
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
662
+ explorerUrl:
663
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
664
+ chainId: 137,
665
+ state: "pending",
666
+ label: "Swap",
667
+ },
668
+ ])
669
+ setOriginTokenInfo({
670
+ amount: "10000",
671
+ amountUsd: "$0.01",
672
+ tokenSymbol: "USDC",
673
+ tokenName: "USD Coin",
674
+ chainId: 137,
675
+ imageUrl:
676
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
677
+ })
678
+ setCurrentScreen("pending")
679
+ break
680
+ case "pending 1-item-1-confirmed":
681
+ // Set dummy transaction states for debug mode - showing all steps
682
+ setTransactionStates([
683
+ {
684
+ transactionHash:
685
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
686
+ explorerUrl:
687
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
688
+ chainId: 137,
689
+ state: "confirmed",
690
+ label: "Swap",
691
+ },
692
+ ])
693
+ setOriginTokenInfo({
694
+ amount: "10000",
695
+ amountUsd: "$0.01",
696
+ tokenSymbol: "USDC",
697
+ tokenName: "USD Coin",
698
+ chainId: 137,
699
+ imageUrl:
700
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
701
+ })
702
+ setCurrentScreen("pending")
703
+ break
704
+ case "pending 2-item-0-confirmed":
705
+ // Set dummy transaction states for debug mode - showing all steps
706
+ setTransactionStates([
707
+ {
708
+ transactionHash:
709
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
710
+ explorerUrl:
711
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
712
+ chainId: 137,
713
+ state: "pending",
714
+ label: "Transfer",
715
+ },
716
+ {
717
+ transactionHash:
718
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
719
+ explorerUrl:
720
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
721
+ chainId: 137,
722
+ state: "pending",
723
+ label: "Swap",
724
+ },
725
+ ])
726
+ setOriginTokenInfo({
727
+ amount: "10000",
728
+ amountUsd: "$0.01",
729
+ tokenSymbol: "USDC",
730
+ tokenName: "USD Coin",
731
+ chainId: 137,
732
+ imageUrl:
733
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
734
+ })
735
+ setCurrentScreen("pending")
736
+ break
737
+ case "pending 2-item-1-confirmed":
738
+ // Set dummy transaction states for debug mode - showing all steps
739
+ setTransactionStates([
740
+ {
741
+ transactionHash:
742
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
743
+ explorerUrl:
744
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
745
+ chainId: 137,
746
+ state: "confirmed",
747
+ label: "Transfer",
748
+ },
749
+ {
750
+ transactionHash:
751
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
752
+ explorerUrl:
753
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
754
+ chainId: 137,
755
+ state: "pending",
756
+ label: "Swap",
757
+ },
758
+ ])
759
+ setOriginTokenInfo({
760
+ amount: "10000",
761
+ amountUsd: "$0.01",
762
+ tokenSymbol: "USDC",
763
+ tokenName: "USD Coin",
764
+ chainId: 137,
765
+ imageUrl:
766
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
767
+ })
768
+ setCurrentScreen("pending")
769
+ break
770
+ case "pending 2-item-2-confirmed":
771
+ // Set dummy transaction states for debug mode - showing all steps
772
+ setTransactionStates([
773
+ {
774
+ transactionHash:
775
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
776
+ explorerUrl:
777
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
778
+ chainId: 137,
779
+ state: "confirmed",
780
+ label: "Transfer",
781
+ },
782
+ {
783
+ transactionHash:
784
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
785
+ explorerUrl:
786
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
787
+ chainId: 137,
788
+ state: "confirmed",
789
+ label: "Swap",
790
+ },
791
+ ])
792
+ setOriginTokenInfo({
793
+ amount: "10000",
794
+ amountUsd: "$0.01",
795
+ tokenSymbol: "USDC",
796
+ tokenName: "USD Coin",
797
+ chainId: 137,
798
+ imageUrl:
799
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
800
+ })
801
+ setCurrentScreen("pending")
802
+ break
803
+ case "pending 3-item-0-confirmed":
804
+ // Set dummy transaction states for debug mode - showing all steps
805
+ setTransactionStates([
806
+ {
807
+ transactionHash:
808
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
809
+ explorerUrl:
810
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
811
+ chainId: 137,
812
+ state: "pending",
813
+ label: "Transfer",
814
+ },
815
+ {
816
+ transactionHash:
817
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
818
+ explorerUrl:
819
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
820
+ chainId: 137,
821
+ state: "pending",
822
+ label: "Swap & Bridge",
823
+ },
824
+ {
825
+ transactionHash:
826
+ "0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
827
+ explorerUrl:
828
+ "https://arbiscan.io/tx/0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
829
+ chainId: 42161,
830
+ state: "pending",
831
+ label: "Execute",
832
+ },
833
+ ])
834
+ setOriginTokenInfo({
835
+ amount: "10000",
836
+ amountUsd: "$0.01",
837
+ tokenSymbol: "USDC",
838
+ tokenName: "USD Coin",
839
+ chainId: 137,
840
+ imageUrl:
841
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
842
+ })
843
+ setCurrentScreen("pending")
844
+ break
845
+ case "pending 3-item-1-confirmed":
846
+ // Set dummy transaction states for debug mode - showing all steps
847
+ setTransactionStates([
848
+ {
849
+ transactionHash:
850
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
851
+ explorerUrl:
852
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
853
+ chainId: 137,
854
+ state: "confirmed",
855
+ label: "Transfer",
856
+ },
857
+ {
858
+ transactionHash:
859
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
860
+ explorerUrl:
861
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
862
+ chainId: 137,
863
+ state: "pending",
864
+ label: "Swap & Bridge",
865
+ },
866
+ {
867
+ transactionHash:
868
+ "0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
869
+ explorerUrl:
870
+ "https://arbiscan.io/tx/0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
871
+ chainId: 42161,
872
+ state: "pending",
873
+ label: "Execute",
874
+ },
875
+ ])
876
+ setOriginTokenInfo({
877
+ amount: "10000",
878
+ amountUsd: "$0.01",
879
+ tokenSymbol: "USDC",
880
+ tokenName: "USD Coin",
881
+ chainId: 137,
882
+ imageUrl:
883
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
884
+ })
885
+ setCurrentScreen("pending")
886
+ break
887
+ case "pending 3-item-2-confirmed":
888
+ // Set dummy transaction states for debug mode - showing all steps
889
+ setTransactionStates([
890
+ {
891
+ transactionHash:
892
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
893
+ explorerUrl:
894
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
895
+ chainId: 137,
896
+ state: "confirmed",
897
+ label: "Transfer",
898
+ },
899
+ {
900
+ transactionHash:
901
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
902
+ explorerUrl:
903
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
904
+ chainId: 137,
905
+ state: "confirmed",
906
+ label: "Swap & Bridge",
907
+ },
908
+ {
909
+ transactionHash:
910
+ "0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
911
+ explorerUrl:
912
+ "https://arbiscan.io/tx/0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
913
+ chainId: 42161,
914
+ state: "pending",
915
+ label: "Execute",
916
+ },
917
+ ])
918
+ setOriginTokenInfo({
919
+ amount: "10000",
920
+ amountUsd: "$0.01",
921
+ tokenSymbol: "USDC",
922
+ tokenName: "USD Coin",
923
+ chainId: 137,
924
+ imageUrl:
925
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
926
+ })
927
+ setCurrentScreen("pending")
928
+ break
929
+ case "pending 3-item-3-confirmed":
930
+ // Set dummy transaction states for debug mode - showing all steps
931
+ setTransactionStates([
932
+ {
933
+ transactionHash:
934
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
935
+ explorerUrl:
936
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
937
+ chainId: 137,
938
+ state: "confirmed",
939
+ label: "Transfer",
940
+ },
941
+ {
942
+ transactionHash:
943
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
944
+ explorerUrl:
945
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
946
+ chainId: 137,
947
+ state: "confirmed",
948
+ label: "Swap & Bridge",
949
+ },
950
+ {
951
+ transactionHash:
952
+ "0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
953
+ explorerUrl:
954
+ "https://arbiscan.io/tx/0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
955
+ chainId: 42161,
956
+ state: "confirmed",
957
+ label: "Execute",
958
+ },
959
+ ])
960
+ setOriginTokenInfo({
961
+ amount: "10000",
962
+ amountUsd: "$0.01",
963
+ tokenSymbol: "USDC",
964
+ tokenName: "USD Coin",
965
+ chainId: 137,
966
+ imageUrl:
967
+ "https://raw.githubusercontent.com/trustwallet/assets/master/blockchains/ethereum/assets/0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48/logo.png",
968
+ })
969
+ setCurrentScreen("pending")
970
+ break
971
+ case "receipt":
972
+ // Set dummy transaction states data for debug mode
973
+ setTransactionStates([
974
+ {
975
+ transactionHash:
976
+ "0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
977
+ explorerUrl:
978
+ "https://polygonscan.com/tx/0x45bb2259631e73f32841a6058b0a4008c75bca296942bec6326d188978d5353d",
979
+ chainId: 137,
980
+ state: "confirmed",
981
+ label: "Transfer",
982
+ },
983
+ {
984
+ transactionHash:
985
+ "0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
986
+ explorerUrl:
987
+ "https://polygonscan.com/tx/0x6ff30196ca0d4998cc6928bca2ec282766eb3c3997535e0a61e0d69c9c9b16b8",
988
+ chainId: 137,
989
+ state: "confirmed",
990
+ label: "Swap & Bridge",
991
+ },
992
+ {
993
+ transactionHash:
994
+ "0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
995
+ explorerUrl:
996
+ "https://arbiscan.io/tx/0xf3b172111d2e64e9d4940d91097f04a0bbd0acc816e2cf49eec664c6f8fcaf76",
997
+ chainId: 42161,
998
+ state: "confirmed",
999
+ label: "Execute",
1000
+ },
1001
+ ])
1002
+
1003
+ setCurrentScreen("receipt")
1004
+ break
1005
+ }
1006
+ }
1007
+
1008
+ const handleSendError = (error: Error | string | null) => {
1009
+ if (error) {
1010
+ console.error("[trails-sdk] Error sending transaction", error)
1011
+ }
1012
+ const errorMessage = error instanceof Error ? error.message : error
1013
+ if (errorMessage?.toLowerCase().includes("rejected")) {
1014
+ console.log("[trails-sdk] currentScreen", currentScreen)
1015
+ setShowWalletConfirmRetry(true)
1016
+ } else {
1017
+ setError(errorMessage)
1018
+ }
1019
+ }
1020
+
1021
+ const handleConnectError = (error: Error | string | null) => {
1022
+ if (error) {
1023
+ console.error("[trails-sdk] Error connecting wallet", error)
1024
+ }
1025
+ setError(error instanceof Error ? error.message : error)
1026
+ }
1027
+
1028
+ const handleTokenListError = (error: Error | string | null) => {
1029
+ if (error) {
1030
+ console.error("[trails-sdk] Error selecting token", error)
1031
+ }
1032
+ setError(error instanceof Error ? error.message : error)
1033
+ }
1034
+
1035
+ const handleWaitingForWalletConfirm = (
1036
+ intentAddress?: string,
1037
+ details?: {
1038
+ amount: string
1039
+ amountUsd: string
1040
+ tokenSymbol: string
1041
+ tokenName: string
1042
+ chainId: number
1043
+ imageUrl: string
1044
+ },
1045
+ ) => {
1046
+ setShowWalletConfirmRetry(false)
1047
+ setCurrentScreen("wallet-confirmation")
1048
+ setIntentAddress(intentAddress ?? null)
1049
+ setOriginTokenInfo(details ?? null)
1050
+ }
1051
+
1052
+ async function handleWalletConfirmRetry() {
1053
+ if (!walletConfirmRetryHandler) {
1054
+ return
1055
+ }
1056
+
1057
+ try {
1058
+ setShowWalletConfirmRetry(false)
1059
+ await walletConfirmRetryHandler()
1060
+ } catch (error) {
1061
+ console.error("[trails-sdk] Error retrying wallet confirmation", error)
1062
+ }
1063
+ }
1064
+
1065
+ const {
1066
+ amountUsd: targetAmountUsd,
1067
+ amountUsdFormatted: targetAmountUsdFormatted,
1068
+ } = useAmountUsd({
1069
+ amount: toAmount,
1070
+ token: toToken,
1071
+ chainId: Number(toChainId),
1072
+ apiClient: apiClient,
1073
+ })
1074
+
1075
+ const renderScreenContent = () => {
1076
+ switch (currentScreen) {
1077
+ case "connect":
1078
+ return (
1079
+ <ConnectWallet
1080
+ onConnect={handleWalletConnect}
1081
+ onDisconnect={handleWalletDisconnect}
1082
+ onContinue={handleContinue}
1083
+ theme={theme}
1084
+ walletOptions={getAvailableWallets()}
1085
+ onError={handleConnectError}
1086
+ />
1087
+ )
1088
+ case "tokens":
1089
+ return (
1090
+ <TokenList
1091
+ onContinue={handleTokenSelect}
1092
+ onBack={handleBack}
1093
+ indexerGatewayClient={indexerGatewayClient}
1094
+ theme={theme}
1095
+ targetAmountUsd={targetAmountUsd}
1096
+ targetAmountUsdFormatted={targetAmountUsdFormatted}
1097
+ onError={handleTokenListError}
1098
+ />
1099
+ )
1100
+ case "send":
1101
+ return selectedToken && walletClient?.account ? (
1102
+ <SendForm
1103
+ onSend={handleOnSend}
1104
+ onBack={handleBack}
1105
+ onWaitingForWalletConfirm={handleWaitingForWalletConfirm}
1106
+ onConfirm={() => setCurrentScreen("pending")}
1107
+ onComplete={handleTransferComplete}
1108
+ selectedToken={selectedToken}
1109
+ account={walletClient.account}
1110
+ sequenceProjectAccessKey={sequenceProjectAccessKey}
1111
+ apiUrl={sequenceApiUrl || undefined}
1112
+ env={sequenceEnv}
1113
+ toRecipient={toAddress || undefined}
1114
+ toAmount={toAmount || undefined}
1115
+ toChainId={toChainId ? Number(toChainId) : undefined}
1116
+ toToken={toToken || undefined}
1117
+ toCalldata={toCalldata || undefined}
1118
+ walletClient={walletClient}
1119
+ theme={theme}
1120
+ onTransactionStateChange={handleTransactionStateChange}
1121
+ useSourceTokenForButtonText={useSourceTokenForButtonText}
1122
+ onError={handleSendError}
1123
+ paymasterUrls={paymasterUrls}
1124
+ gasless={gasless}
1125
+ setWalletConfirmRetryHandler={setWalletConfirmRetryHandler}
1126
+ />
1127
+ ) : (
1128
+ <div
1129
+ className={`text-center p-4 rounded-lg ${
1130
+ theme === "dark"
1131
+ ? "text-gray-300 bg-gray-800"
1132
+ : "text-gray-600 bg-gray-50"
1133
+ }`}
1134
+ >
1135
+ Please connect wallet
1136
+ </div>
1137
+ )
1138
+ case "wallet-confirmation":
1139
+ return (
1140
+ <WalletConfirmation
1141
+ onBack={handleBack}
1142
+ onComplete={() => setCurrentScreen("pending")}
1143
+ theme={theme}
1144
+ amount={originTokenInfo?.amount ?? undefined}
1145
+ recipient={intentAddress ?? ""}
1146
+ tokenSymbol={selectedToken?.symbol}
1147
+ retryEnabled={showWalletConfirmRetry}
1148
+ onRetry={handleWalletConfirmRetry}
1149
+ fromTokenSymbol={originTokenInfo?.tokenSymbol || ""}
1150
+ fromChainId={originTokenInfo?.chainId || 0}
1151
+ fromTokenImageUrl={originTokenInfo?.imageUrl || ""}
1152
+ />
1153
+ )
1154
+ case "pending":
1155
+ return (
1156
+ <TransferPending
1157
+ onComplete={handleTransferComplete}
1158
+ theme={theme}
1159
+ transactionStates={transactionStates}
1160
+ fromAmount={originTokenInfo?.amount || ""}
1161
+ fromAmountUsd={originTokenInfo?.amountUsd || ""}
1162
+ fromTokenSymbol={originTokenInfo?.tokenSymbol || ""}
1163
+ fromTokenName={originTokenInfo?.tokenName || ""}
1164
+ fromChainId={originTokenInfo?.chainId || 0}
1165
+ fromTokenImageUrl={originTokenInfo?.imageUrl || ""}
1166
+ />
1167
+ )
1168
+ case "receipt":
1169
+ return (
1170
+ <Receipt
1171
+ onSendAnother={handleSendAnother}
1172
+ onClose={handleCloseModal}
1173
+ theme={theme}
1174
+ renderInline={renderInline}
1175
+ transactionStates={transactionStates}
1176
+ />
1177
+ )
1178
+ default:
1179
+ return null
1180
+ }
1181
+ }
1182
+
1183
+ const renderScreen = () => {
1184
+ return (
1185
+ <motion.div
1186
+ initial={{ opacity: 0, scale: 0.95 }}
1187
+ animate={{ opacity: 1, scale: 1 }}
1188
+ exit={{ opacity: 0, scale: 0.95 }}
1189
+ transition={{
1190
+ type: "spring",
1191
+ stiffness: 200,
1192
+ damping: 30,
1193
+ mass: 1,
1194
+ }}
1195
+ className={`flex flex-col min-h-[400px] rounded-[32px] shadow-xl p-4 sm:p-6 relative w-full sm:w-[400px] mx-auto ${
1196
+ theme === "dark"
1197
+ ? "bg-gray-900 text-white"
1198
+ : "bg-white text-gray-900"
1199
+ }`}
1200
+ layout
1201
+ layoutId="modal-container"
1202
+ onClick={(e) => e.stopPropagation()}
1203
+ >
1204
+ <AnimatePresence mode="wait">
1205
+ <motion.div
1206
+ key={currentScreen}
1207
+ initial={{ opacity: 0, x: 20 }}
1208
+ animate={{ opacity: 1, x: 0 }}
1209
+ exit={{ opacity: 0, x: -20 }}
1210
+ transition={{
1211
+ type: "spring",
1212
+ stiffness: 500,
1213
+ damping: 30,
1214
+ mass: 0.6,
1215
+ }}
1216
+ className="flex-1 flex flex-col w-full"
1217
+ layout
1218
+ >
1219
+ {renderScreenContent()}
1220
+ {error && (
1221
+ <div
1222
+ className={`border rounded-lg p-4 mt-4 ${
1223
+ theme === "dark"
1224
+ ? "bg-red-900/20 border-red-800"
1225
+ : "bg-red-50 border-red-200"
1226
+ }`}
1227
+ >
1228
+ <p
1229
+ className={`text-sm break-words ${theme === "dark" ? "text-red-200" : "text-red-600"}`}
1230
+ >
1231
+ {error}
1232
+ </p>
1233
+ </div>
1234
+ )}
1235
+ </motion.div>
1236
+ </AnimatePresence>
1237
+ <Footer theme={theme} onDebugScreenSelect={handleDebugScreenSelect} />
1238
+ </motion.div>
1239
+ )
1240
+ }
1241
+
1242
+ if (renderInline) {
1243
+ return renderScreen()
1244
+ }
1245
+
1246
+ return (
1247
+ <div className="flex flex-col items-center justify-center space-y-8 py-12">
1248
+ {!children ? (
1249
+ <motion.button
1250
+ whileHover={{ scale: 1.02 }}
1251
+ whileTap={{ scale: 0.98 }}
1252
+ onClick={() => setIsModalOpen(true)}
1253
+ className={`${
1254
+ theme === "dark"
1255
+ ? "bg-blue-600 hover:bg-blue-700"
1256
+ : "bg-blue-500 hover:bg-blue-600"
1257
+ } text-white cursor-pointer font-semibold py-3 px-6 rounded-[24px] shadow-sm transition-colors`}
1258
+ >
1259
+ {buttonText || "Pay"}
1260
+ </motion.button>
1261
+ ) : (
1262
+ <motion.div
1263
+ whileHover={{ scale: 1.02 }}
1264
+ whileTap={{ scale: 0.98 }}
1265
+ className="flex flex-col items-center justify-center"
1266
+ onClick={() => setIsModalOpen(true)}
1267
+ >
1268
+ {children}
1269
+ </motion.div>
1270
+ )}
1271
+
1272
+ <AnimatePresence>
1273
+ {isModalOpen && (
1274
+ <Modal
1275
+ isOpen={isModalOpen}
1276
+ onClose={handleCloseModal}
1277
+ theme={theme}
1278
+ >
1279
+ {renderScreen()}
1280
+ </Modal>
1281
+ )}
1282
+ </AnimatePresence>
1283
+ </div>
1284
+ )
1285
+ },
1286
+ )
1287
+
1288
+ export const TrailsWidget = forwardRef<TrailsWidgetRef, TrailsWidgetProps>(
1289
+ (props, ref) => {
1290
+ const wagmiContext = useContext(WagmiContext)
1291
+ const sequenceHooksContext = useContext(SequenceHooksContext)
1292
+
1293
+ // Check if privy is in walletOptions
1294
+ // const walletOptions = props.walletOptions || defaultWalletOptions
1295
+ const shouldUsePrivy = true // walletOptions.includes('privy') // TODO: need to disable all privy hooks if walletOptions.includes('privy') is false
1296
+
1297
+ const wagmiConfig = React.useMemo(() => {
1298
+ const chains = [mainnet] as const
1299
+ const baseConfig = {
1300
+ chains,
1301
+ transports: (Object.values(chains) as Array<Chain>).reduce(
1302
+ (acc, chain) => ({
1303
+ ...acc,
1304
+ [chain.id]: http(),
1305
+ }),
1306
+ {},
1307
+ ) as Record<number, ReturnType<typeof http>>,
1308
+ }
1309
+
1310
+ if (shouldUsePrivy) {
1311
+ return createPrivyWagmiConfig(baseConfig)
1312
+ } else {
1313
+ return createConfig({
1314
+ ...baseConfig,
1315
+ connectors: [injected()],
1316
+ })
1317
+ }
1318
+ }, [])
1319
+
1320
+ // Create content with only the providers that don't exist in parent
1321
+ const content = (() => {
1322
+ const widgetContent = <WidgetInner {...props} ref={ref} />
1323
+
1324
+ const baseContent = (
1325
+ <QueryClientProvider client={queryClient}>
1326
+ {sequenceHooksContext ? (
1327
+ // SequenceHooksProvider exists in parent, don't wrap
1328
+ wagmiContext ? (
1329
+ // Both providers exist in parent, just render widget
1330
+ widgetContent
1331
+ ) : (
1332
+ // Only WagmiProvider missing, wrap with it
1333
+ <WagmiProvider config={wagmiConfig}>
1334
+ {widgetContent}
1335
+ </WagmiProvider>
1336
+ )
1337
+ ) : (
1338
+ // SequenceHooksProvider missing, wrap with it
1339
+ <SequenceHooksProvider
1340
+ config={{
1341
+ projectAccessKey: props.appId,
1342
+ env: {
1343
+ indexerUrl: props.sequenceIndexerUrl || undefined,
1344
+ indexerGatewayUrl: props.sequenceIndexerUrl || undefined,
1345
+ apiUrl: props.sequenceApiUrl || undefined,
1346
+ },
1347
+ }}
1348
+ >
1349
+ {wagmiContext ? (
1350
+ // WagmiProvider exists in parent, don't wrap
1351
+ widgetContent
1352
+ ) : (
1353
+ // WagmiProvider missing, wrap with it
1354
+ <WagmiProvider config={wagmiConfig}>
1355
+ {widgetContent}
1356
+ </WagmiProvider>
1357
+ )}
1358
+ </SequenceHooksProvider>
1359
+ )}
1360
+ </QueryClientProvider>
1361
+ )
1362
+
1363
+ // Only wrap with PrivyProvider if privy is in walletOptions
1364
+ if (shouldUsePrivy) {
1365
+ return (
1366
+ <PrivyProvider
1367
+ appId={props.privyAppId || defaultPrivyAppId}
1368
+ clientId={props.privyClientId || defaultPrivyClientId}
1369
+ config={{
1370
+ embeddedWallets: {
1371
+ createOnLogin: "users-without-wallets",
1372
+ requireUserPasswordOnCreate: true,
1373
+ showWalletUIs: true,
1374
+ },
1375
+ loginMethods: ["google", "wallet", "email", "sms"],
1376
+ appearance: {
1377
+ showWalletLoginFirst: false,
1378
+ walletList: [
1379
+ "detected_wallets",
1380
+ "metamask",
1381
+ "coinbase_wallet",
1382
+ "rainbow",
1383
+ "zerion",
1384
+ "uniswap",
1385
+ "wallet_connect",
1386
+ ],
1387
+ },
1388
+ }}
1389
+ >
1390
+ {baseContent}
1391
+ </PrivyProvider>
1392
+ )
1393
+ }
1394
+
1395
+ return baseContent
1396
+ })()
1397
+
1398
+ return (
1399
+ <ShadowPortal>
1400
+ <StrictMode>{content}</StrictMode>
1401
+ </ShadowPortal>
1402
+ )
1403
+ },
1404
+ )
1405
+
1406
+ export function ShadowPortal({ children }: { children: React.ReactNode }) {
1407
+ const hostRef = useRef<HTMLDivElement>(null)
1408
+ const [shadowRoot, setShadowRoot] = useState<ShadowRoot | null>(null)
1409
+
1410
+ useEffect(() => {
1411
+ if (hostRef.current && !hostRef.current.shadowRoot) {
1412
+ const shadow = hostRef.current.attachShadow({ mode: "open" })
1413
+ setShadowRoot(shadow)
1414
+
1415
+ // Inject <style> tag with your widget's CSS
1416
+ const styleTag = document.createElement("style")
1417
+ styleTag.textContent = css
1418
+ shadow.appendChild(styleTag)
1419
+ }
1420
+ }, [])
1421
+
1422
+ return (
1423
+ <div ref={hostRef}>
1424
+ {shadowRoot ? createPortal(children, shadowRoot) : null}
1425
+ </div>
1426
+ )
1427
+ }
1428
+
1429
+ // Export standalone functions for modal control
1430
+ export const createModalController = (
1431
+ ref: React.RefObject<TrailsWidgetRef>,
1432
+ ) => ({
1433
+ openModal: () => ref.current?.openModal?.(),
1434
+ closeModal: () => ref.current?.closeModal?.(),
1435
+ isModalOpen: ref.current?.isModalOpen ?? false,
1436
+ })
1437
+
1438
+ export default TrailsWidget