@trustware/sdk-staging 1.1.9-staging.7 → 1.1.11-staging.1

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/dist/widget.mjs CHANGED
@@ -563,7 +563,7 @@ var init_constants = __esm({
563
563
  "src/constants.ts"() {
564
564
  "use strict";
565
565
  SDK_NAME = "@trustware/sdk";
566
- SDK_VERSION = "1.1.9-staging.7";
566
+ SDK_VERSION = "1.1.11-staging.1";
567
567
  API_ROOT = "https://bv-staging-api.trustware.io";
568
568
  GTM_ID = "GTM-TZDGNCXB";
569
569
  API_PREFIX = "/api";
@@ -607,6 +607,9 @@ async function assertOK(r) {
607
607
  }
608
608
  throw new Error(`HTTP ${r.status}: ${msg}`);
609
609
  }
610
+ function isNotFoundError(err) {
611
+ return err instanceof Error && err.message.startsWith("HTTP 404");
612
+ }
610
613
  async function validateSdkAccess() {
611
614
  const r = await fetch(`${apiBase()}/sdk/validate`, {
612
615
  method: "GET",
@@ -2442,6 +2445,27 @@ var init_balances = __esm({
2442
2445
  });
2443
2446
 
2444
2447
  // src/core/routes.ts
2448
+ function assertValidPostHook(hooks) {
2449
+ const postHook = hooks?.postHook;
2450
+ if (!postHook) return;
2451
+ if (!postHook.target?.trim()) {
2452
+ throw new Error("hooks.postHook.target is required.");
2453
+ }
2454
+ if (!postHook.callData?.trim()) {
2455
+ throw new Error("hooks.postHook.callData is required.");
2456
+ }
2457
+ if (postHook.fullAmount) {
2458
+ if (postHook.amountInputPos === void 0) {
2459
+ throw new Error(
2460
+ "hooks.postHook.amountInputPos is required when fullAmount is true."
2461
+ );
2462
+ }
2463
+ } else if (!postHook.fundAmount?.trim()) {
2464
+ throw new Error(
2465
+ "hooks.postHook.fundAmount is required unless fullAmount is set."
2466
+ );
2467
+ }
2468
+ }
2445
2469
  function isEvmTxRequest(txReq) {
2446
2470
  return Boolean(txReq?.data && (txReq.to || txReq.target));
2447
2471
  }
@@ -2460,6 +2484,7 @@ async function buildRoute(body, signal) {
2460
2484
  if (!addressValidation.isValid) {
2461
2485
  throw new Error(addressValidation.error || "Invalid route addresses.");
2462
2486
  }
2487
+ assertValidPostHook(body.hooks);
2463
2488
  const cfg = TrustwareConfigStore.get();
2464
2489
  const url = `${apiBase()}/v1/routes/route`;
2465
2490
  const payload = {
@@ -2498,6 +2523,7 @@ async function buildRoute(body, signal) {
2498
2523
  return { intentId, txReq, actions, finalExchangeRate, route, sponsorship };
2499
2524
  }
2500
2525
  async function buildDepositAddress(body, signal) {
2526
+ assertValidPostHook(body.hooks);
2501
2527
  const cfg = TrustwareConfigStore.get();
2502
2528
  const url = `${apiBase()}/v1/routes/deposit-address`;
2503
2529
  const payload = {
@@ -2556,6 +2582,19 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress)
2556
2582
  const j = await r.json();
2557
2583
  return j.data;
2558
2584
  }
2585
+ async function submitStepReceipt(intentId, stepIndex, txHash) {
2586
+ const r = await rateLimitedFetch(
2587
+ `${apiBase()}/v1/route-intent/${intentId}/steps/${stepIndex}/receipt`,
2588
+ {
2589
+ method: "POST",
2590
+ headers: jsonHeaders({ "Idempotency-Key": txHash }),
2591
+ body: JSON.stringify({ txHash })
2592
+ }
2593
+ );
2594
+ await assertOK(r);
2595
+ const j = await r.json();
2596
+ return j.data;
2597
+ }
2559
2598
  async function getStatus(intentId) {
2560
2599
  const r = await rateLimitedFetch(
2561
2600
  `${apiBase()}/v1/route-intent/${intentId}/status`,
@@ -5277,75 +5316,17 @@ var init_useTransactionSubmit = __esm({
5277
5316
 
5278
5317
  // src/hooks/useGTM.ts
5279
5318
  import { useEffect as useEffect5, useRef as useRef2, useCallback as useCallback2 } from "react";
5280
- function useGTM(gtmId) {
5281
- const isInitialized = useRef2(false);
5282
- const scriptRef = useRef2(null);
5283
- const isGA4Allowed = useCallback2(() => {
5284
- try {
5285
- return Trustware.getConfig().features.shouldAllowGA4;
5286
- } catch {
5287
- return false;
5288
- }
5289
- }, []);
5290
- useEffect5(() => {
5291
- if (!isGA4Allowed()) {
5292
- console.warn(
5293
- "useGTM: GA4 tracking is disabled or Trustware config not initialized."
5294
- );
5295
- return;
5296
- }
5297
- if (!gtmId || typeof gtmId !== "string") {
5298
- console.error(
5299
- "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
5300
- );
5301
- return;
5302
- }
5303
- if (isInitialized.current) return;
5304
- const alreadyLoaded = document.querySelector(
5305
- `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
5306
- );
5307
- if (alreadyLoaded) {
5308
- window.dataLayer = window.dataLayer || [];
5309
- isInitialized.current = true;
5310
- return;
5311
- }
5312
- window.dataLayer = window.dataLayer || [];
5313
- window.dataLayer.push({
5314
- "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
5315
- event: "gtm.js"
5316
- });
5317
- const firstScript = document.getElementsByTagName("script")[0];
5318
- const script = document.createElement("script");
5319
- script.async = true;
5320
- script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
5321
- firstScript.parentNode?.insertBefore(script, firstScript);
5322
- scriptRef.current = script;
5323
- isInitialized.current = true;
5324
- return () => {
5325
- if (scriptRef.current) {
5326
- scriptRef.current.parentNode?.removeChild(scriptRef.current);
5327
- scriptRef.current = null;
5328
- }
5329
- isInitialized.current = false;
5330
- };
5331
- }, [gtmId, isGA4Allowed]);
5332
- const addNoscriptIframe = useCallback2(() => {
5333
- if (!isGA4Allowed()) return;
5334
- if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
5335
- return;
5336
- const noscript = document.createElement("noscript");
5337
- const iframe = document.createElement("iframe");
5338
- iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
5339
- iframe.height = "0";
5340
- iframe.width = "0";
5341
- iframe.style.display = "none";
5342
- iframe.style.visibility = "hidden";
5343
- noscript.appendChild(iframe);
5344
- document.body.insertBefore(noscript, document.body.firstChild);
5345
- }, [gtmId, isGA4Allowed]);
5319
+ function isGA4Allowed() {
5320
+ try {
5321
+ return Trustware.getConfig().features.shouldAllowGA4;
5322
+ } catch {
5323
+ return false;
5324
+ }
5325
+ }
5326
+ function useGTMTracker() {
5346
5327
  const trackEvent = useCallback2(
5347
5328
  (eventName, eventParams = {}) => {
5348
- if (!isInitialized.current) {
5329
+ if (!isContainerInitialized) {
5349
5330
  console.warn(
5350
5331
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
5351
5332
  );
@@ -5372,7 +5353,7 @@ function useGTM(gtmId) {
5372
5353
  );
5373
5354
  const setUserProperty = useCallback2(
5374
5355
  (propertyName, value) => {
5375
- if (!isInitialized.current) {
5356
+ if (!isContainerInitialized) {
5376
5357
  console.warn(
5377
5358
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
5378
5359
  );
@@ -5398,20 +5379,77 @@ function useGTM(gtmId) {
5398
5379
  }
5399
5380
  window.gtag(command, ...args);
5400
5381
  },
5401
- [isGA4Allowed]
5382
+ []
5402
5383
  );
5403
- return {
5404
- trackEvent,
5405
- trackPageView,
5406
- setUserProperty,
5407
- directGtag,
5408
- addNoscriptIframe
5409
- };
5384
+ return { trackEvent, trackPageView, setUserProperty, directGtag };
5385
+ }
5386
+ function useGTM(gtmId) {
5387
+ const scriptRef = useRef2(null);
5388
+ const tracker = useGTMTracker();
5389
+ useEffect5(() => {
5390
+ if (!isGA4Allowed()) {
5391
+ console.warn(
5392
+ "useGTM: GA4 tracking is disabled or Trustware config not initialized."
5393
+ );
5394
+ return;
5395
+ }
5396
+ if (!gtmId || typeof gtmId !== "string") {
5397
+ console.error(
5398
+ "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
5399
+ );
5400
+ return;
5401
+ }
5402
+ if (isContainerInitialized) return;
5403
+ const alreadyLoaded = document.querySelector(
5404
+ `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
5405
+ );
5406
+ if (alreadyLoaded) {
5407
+ window.dataLayer = window.dataLayer || [];
5408
+ isContainerInitialized = true;
5409
+ return;
5410
+ }
5411
+ window.dataLayer = window.dataLayer || [];
5412
+ window.dataLayer.push({
5413
+ "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
5414
+ event: "gtm.js"
5415
+ });
5416
+ const firstScript = document.getElementsByTagName("script")[0];
5417
+ const script = document.createElement("script");
5418
+ script.async = true;
5419
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
5420
+ firstScript.parentNode?.insertBefore(script, firstScript);
5421
+ scriptRef.current = script;
5422
+ isContainerInitialized = true;
5423
+ return () => {
5424
+ if (scriptRef.current) {
5425
+ scriptRef.current.parentNode?.removeChild(scriptRef.current);
5426
+ scriptRef.current = null;
5427
+ }
5428
+ isContainerInitialized = false;
5429
+ };
5430
+ }, [gtmId]);
5431
+ const addNoscriptIframe = useCallback2(() => {
5432
+ if (!isGA4Allowed()) return;
5433
+ if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
5434
+ return;
5435
+ const noscript = document.createElement("noscript");
5436
+ const iframe = document.createElement("iframe");
5437
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
5438
+ iframe.height = "0";
5439
+ iframe.width = "0";
5440
+ iframe.style.display = "none";
5441
+ iframe.style.visibility = "hidden";
5442
+ noscript.appendChild(iframe);
5443
+ document.body.insertBefore(noscript, document.body.firstChild);
5444
+ }, [gtmId]);
5445
+ return { ...tracker, addNoscriptIframe };
5410
5446
  }
5447
+ var isContainerInitialized;
5411
5448
  var init_useGTM = __esm({
5412
5449
  "src/hooks/useGTM.ts"() {
5413
5450
  "use strict";
5414
5451
  init_core2();
5452
+ isContainerInitialized = false;
5415
5453
  }
5416
5454
  });
5417
5455
 
@@ -5438,7 +5476,7 @@ function useTransactionPolling() {
5438
5476
  return void 0;
5439
5477
  }
5440
5478
  })();
5441
- const { trackEvent } = useGTM(GTM_ID);
5479
+ const { trackEvent } = useGTMTracker();
5442
5480
  const [state, setState] = useState6({
5443
5481
  isPolling: false,
5444
5482
  apiStatus: null,
@@ -5538,8 +5576,21 @@ function useTransactionPolling() {
5538
5576
  pollCountRef.current += 1;
5539
5577
  const pollInterval = pollCountRef.current <= 10 ? FAST_POLL_INTERVAL_MS : NORMAL_POLL_INTERVAL_MS;
5540
5578
  pollingRef.current = setTimeout(poll, pollInterval);
5541
- } catch {
5579
+ } catch (err) {
5542
5580
  if (abortRef.current) return;
5581
+ if (isNotFoundError(err)) {
5582
+ clearPolling();
5583
+ const notFoundError = "Transaction session expired. Please try again.";
5584
+ setState((prev) => ({
5585
+ ...prev,
5586
+ isPolling: false,
5587
+ error: notFoundError
5588
+ }));
5589
+ setErrorMessage(notFoundError);
5590
+ setTransactionStatus("error");
5591
+ setCurrentStep("error");
5592
+ return;
5593
+ }
5543
5594
  const elapsed = Date.now() - startTimeRef.current;
5544
5595
  if (elapsed > POLL_TIMEOUT_MS) {
5545
5596
  clearPolling();
@@ -5675,10 +5726,10 @@ var init_useTransactionPolling = __esm({
5675
5726
  "use strict";
5676
5727
  "use client";
5677
5728
  init_routes();
5729
+ init_http();
5678
5730
  init_DepositContext();
5679
5731
  init_provider();
5680
5732
  init_core2();
5681
- init_constants();
5682
5733
  init_hooks();
5683
5734
  FAST_POLL_INTERVAL_MS = 1500;
5684
5735
  NORMAL_POLL_INTERVAL_MS = 2500;
@@ -5760,6 +5811,20 @@ var init_eipWallets = __esm({
5760
5811
  "src/wallets/eipWallets.ts"() {
5761
5812
  "use strict";
5762
5813
  CHAIN_PARAMS = {
5814
+ 1: {
5815
+ chainIdHex: "0x1",
5816
+ chainName: "Ethereum",
5817
+ rpcUrls: ["https://eth.llamarpc.com"],
5818
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
5819
+ blockExplorerUrls: ["https://etherscan.io"]
5820
+ },
5821
+ 137: {
5822
+ chainIdHex: "0x89",
5823
+ chainName: "Polygon",
5824
+ rpcUrls: ["https://polygon-rpc.com"],
5825
+ nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
5826
+ blockExplorerUrls: ["https://polygonscan.com"]
5827
+ },
5763
5828
  8453: {
5764
5829
  chainIdHex: "0x2105",
5765
5830
  chainName: "Base",
@@ -8992,18 +9057,112 @@ var init_store = __esm({
8992
9057
  });
8993
9058
 
8994
9059
  // src/core/tx.ts
8995
- import { keccak256 } from "viem";
9060
+ import { keccak256, encodeFunctionData, parseAbi } from "viem";
8996
9061
  function backendChainId(chain, fallback) {
8997
9062
  const preferred = chain?.networkIdentifier ?? chain?.chainId ?? chain?.id;
8998
9063
  return String(preferred ?? fallback ?? "");
8999
9064
  }
9065
+ function sleep2(ms) {
9066
+ return new Promise((resolve) => setTimeout(resolve, ms));
9067
+ }
9068
+ async function sendEvmTx(w, tx) {
9069
+ if (w.type === "eip1193") {
9070
+ const from = await w.getAddress();
9071
+ const params = {
9072
+ from,
9073
+ to: tx.to,
9074
+ data: tx.data,
9075
+ value: tx.value ? `0x${tx.value.toString(16)}` : "0x0"
9076
+ };
9077
+ if (tx.chainId !== void 0) {
9078
+ params.chainId = `0x${tx.chainId.toString(16)}`;
9079
+ }
9080
+ const hash = await w.request({
9081
+ method: "eth_sendTransaction",
9082
+ params: [params]
9083
+ });
9084
+ return hash;
9085
+ }
9086
+ const response = await w.sendTransaction({
9087
+ to: tx.to,
9088
+ data: tx.data,
9089
+ value: tx.value,
9090
+ chainId: tx.chainId
9091
+ });
9092
+ return response.hash;
9093
+ }
9094
+ async function waitForTxConfirmation(chainId, txHash) {
9095
+ const timeoutMs = 12e4;
9096
+ const intervalMs = 2e3;
9097
+ const started = Date.now();
9098
+ while (Date.now() - started < timeoutMs) {
9099
+ const status = await getEVMTxStatus({ chainId, txHash });
9100
+ if (status.status === "success") return;
9101
+ if (status.status === "reverted") {
9102
+ throw new Error("Approval transaction reverted");
9103
+ }
9104
+ await sleep2(intervalMs);
9105
+ }
9106
+ throw new Error("Timed out waiting for approval confirmation");
9107
+ }
9108
+ function requiredApprovalAmount(planAmountWei, routeAmountWei) {
9109
+ if (planAmountWei >= UNLIMITED_APPROVAL_FLOOR && routeAmountWei !== void 0 && routeAmountWei > 0n) {
9110
+ return routeAmountWei;
9111
+ }
9112
+ return planAmountWei;
9113
+ }
9114
+ function approvalSatisfied(currentAllowance, requiredWei) {
9115
+ if (requiredWei === 0n) return currentAllowance === 0n;
9116
+ return currentAllowance >= requiredWei;
9117
+ }
9118
+ async function ensureApprovals(w, approvals, fallbackChainId, intentId, routeAmountWei) {
9119
+ if (!approvals || approvals.length === 0) return;
9120
+ const owner = await w.getAddress();
9121
+ for (const [stepIndex, approval] of approvals.entries()) {
9122
+ const spender = approval.spender;
9123
+ const tokenAddress = approval.tokenAddress;
9124
+ const amount = approval.amount;
9125
+ if (!spender || !tokenAddress || !amount) continue;
9126
+ const chainId = approval.chainId || String(fallbackChainId ?? "");
9127
+ if (!chainId) continue;
9128
+ const amountWei = requiredApprovalAmount(BigInt(amount), routeAmountWei);
9129
+ let currentAllowance = 0n;
9130
+ try {
9131
+ const { allowance } = await getEVMAllowance({
9132
+ chainId,
9133
+ tokenAddress,
9134
+ ownerAddress: owner,
9135
+ spenderAddress: spender
9136
+ });
9137
+ currentAllowance = BigInt(allowance || "0");
9138
+ } catch {
9139
+ }
9140
+ if (approvalSatisfied(currentAllowance, amountWei)) continue;
9141
+ const data = encodeFunctionData({
9142
+ abi: erc20ApproveAbi,
9143
+ functionName: "approve",
9144
+ args: [spender, amountWei]
9145
+ });
9146
+ const hash = await sendEvmTx(w, {
9147
+ to: tokenAddress,
9148
+ data,
9149
+ value: 0n,
9150
+ chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
9151
+ });
9152
+ if (intentId) {
9153
+ void submitStepReceipt(intentId, stepIndex, hash).catch(() => {
9154
+ });
9155
+ }
9156
+ await waitForTxConfirmation(chainId, hash);
9157
+ }
9158
+ }
9000
9159
  function isUserRejected(e2) {
9001
9160
  const code = e2?.code ?? e2?.data?.code;
9002
9161
  if (code === 4001) return true;
9003
9162
  const msg = String(e2?.message || e2)?.toLowerCase?.() || "";
9004
9163
  return msg.includes("user rejected") || msg.includes("user denied");
9005
9164
  }
9006
- async function sendRouteTransaction(b, fallbackChainId) {
9165
+ async function sendRouteTransaction(b, fallbackChainId, options) {
9007
9166
  const w = walletManager.wallet;
9008
9167
  if (!w) throw new Error("Trustware.wallet not configured");
9009
9168
  const txReq = b.txReq;
@@ -9030,6 +9189,15 @@ async function sendRouteTransaction(b, fallbackChainId) {
9030
9189
  }
9031
9190
  }
9032
9191
  }
9192
+ if (!validatedSponsorship && !options?.approvalsEnsured) {
9193
+ await ensureApprovals(
9194
+ w,
9195
+ b.route?.execution?.approvals,
9196
+ Number.isFinite(target) ? target : void 0,
9197
+ b.intentId,
9198
+ BigInt(b.route?.estimate?.fromAmount ?? "0")
9199
+ );
9200
+ }
9033
9201
  if (w.type === "eip1193") {
9034
9202
  const from = await w.getAddress();
9035
9203
  const hexValue = value ? `0x${value.toString(16)}` : "0x0";
@@ -9126,11 +9294,17 @@ async function runTopUp(params) {
9126
9294
  }
9127
9295
  }
9128
9296
  }
9297
+ var erc20ApproveAbi, UNLIMITED_APPROVAL_FLOOR;
9129
9298
  var init_tx = __esm({
9130
9299
  "src/core/tx.ts"() {
9131
9300
  "use strict";
9132
9301
  init_wallets();
9133
9302
  init_routes();
9303
+ init_sdkRpc();
9304
+ erc20ApproveAbi = parseAbi([
9305
+ "function approve(address spender, uint256 amount) returns (bool)"
9306
+ ]);
9307
+ UNLIMITED_APPROVAL_FLOOR = 1n << 255n;
9134
9308
  }
9135
9309
  });
9136
9310
 
@@ -9276,6 +9450,7 @@ var init_core = __esm({
9276
9450
  buildRoute,
9277
9451
  buildDepositAddress,
9278
9452
  submitReceipt,
9453
+ submitStepReceipt,
9279
9454
  getStatus,
9280
9455
  pollStatus,
9281
9456
  getBalances,
@@ -28244,7 +28419,7 @@ var init_utils5 = __esm({
28244
28419
  });
28245
28420
 
28246
28421
  // node_modules/@account-kit/smart-contracts/dist/esm/src/light-account/accounts/base.js
28247
- import { concat as concat5, encodeFunctionData, fromHex as fromHex4, hashMessage, hashTypedData, trim } from "viem";
28422
+ import { concat as concat5, encodeFunctionData as encodeFunctionData2, fromHex as fromHex4, hashMessage, hashTypedData, trim } from "viem";
28248
28423
  async function createLightAccountBase({ transport, chain, signer, abi, version, type, entryPoint, accountAddress, getAccountInitCode }) {
28249
28424
  const client = createBundlerClient({
28250
28425
  transport,
@@ -28263,7 +28438,7 @@ async function createLightAccountBase({ transport, chain, signer, abi, version,
28263
28438
  if (fromHex4(storage, "number") !== 0 && !implementationAddresses.some((x) => x === trim(storage))) {
28264
28439
  throw new Error(`could not determine if smart account implementation is ${type} ${String(version)}`);
28265
28440
  }
28266
- return encodeFunctionData({
28441
+ return encodeFunctionData2({
28267
28442
  abi,
28268
28443
  functionName: "upgradeToAndCall",
28269
28444
  args: [upgradeToAddress, upgradeToInitData]
@@ -28322,7 +28497,7 @@ async function createLightAccountBase({ transport, chain, signer, abi, version,
28322
28497
  prepareSign,
28323
28498
  formatSign,
28324
28499
  encodeExecute: async ({ target, data, value }) => {
28325
- return encodeFunctionData({
28500
+ return encodeFunctionData2({
28326
28501
  abi,
28327
28502
  functionName: "execute",
28328
28503
  args: [target, value ?? 0n, data]
@@ -28335,7 +28510,7 @@ async function createLightAccountBase({ transport, chain, signer, abi, version,
28335
28510
  accum[2].push(curr.data);
28336
28511
  return accum;
28337
28512
  }, [[], [], []]);
28338
- return encodeFunctionData({
28513
+ return encodeFunctionData2({
28339
28514
  abi,
28340
28515
  functionName: "executeBatch",
28341
28516
  args: [targets, values, datas]
@@ -28429,7 +28604,7 @@ var init_OZ_ERC1967Proxy = __esm({
28429
28604
  });
28430
28605
 
28431
28606
  // node_modules/@account-kit/smart-contracts/dist/esm/src/light-account/accounts/predictAddress.js
28432
- import { encodeAbiParameters as encodeAbiParameters4, encodeDeployData, keccak256 as keccak2565, getContractAddress, toHex as toHex6, encodeFunctionData as encodeFunctionData2 } from "viem";
28607
+ import { encodeAbiParameters as encodeAbiParameters4, encodeDeployData, keccak256 as keccak2565, getContractAddress, toHex as toHex6, encodeFunctionData as encodeFunctionData3 } from "viem";
28433
28608
  function predictLightAccountAddress({ factoryAddress, salt, ownerAddress, version }) {
28434
28609
  const implementationAddress = (
28435
28610
  // If we aren't using the default factory address, we compute the implementation address from the factory's `create` deployment.
@@ -28453,7 +28628,7 @@ function predictLightAccountAddress({ factoryAddress, salt, ownerAddress, versio
28453
28628
  abi: OZ_ERC1967Proxy_ConstructorAbi,
28454
28629
  args: [
28455
28630
  implementationAddress,
28456
- encodeFunctionData2({
28631
+ encodeFunctionData3({
28457
28632
  abi: LightAccountAbi_v1,
28458
28633
  functionName: "initialize",
28459
28634
  args: [ownerAddress]
@@ -28490,7 +28665,7 @@ var init_predictAddress = __esm({
28490
28665
  });
28491
28666
 
28492
28667
  // node_modules/@account-kit/smart-contracts/dist/esm/src/light-account/accounts/account.js
28493
- import { concatHex as concatHex2, encodeFunctionData as encodeFunctionData3 } from "viem";
28668
+ import { concatHex as concatHex2, encodeFunctionData as encodeFunctionData4 } from "viem";
28494
28669
  async function createLightAccount({ transport, chain, signer, initCode, version = defaultLightAccountVersion(), entryPoint = getEntryPoint(chain, {
28495
28670
  version: AccountVersionRegistry["LightAccount"][version].entryPointVersion
28496
28671
  }), accountAddress, factoryAddress = getDefaultLightAccountFactoryAddress(chain, version), salt: salt_ = 0n }) {
@@ -28507,7 +28682,7 @@ async function createLightAccount({ transport, chain, signer, initCode, version
28507
28682
  return initCode;
28508
28683
  return concatHex2([
28509
28684
  factoryAddress,
28510
- encodeFunctionData3({
28685
+ encodeFunctionData4({
28511
28686
  abi: factoryAbi,
28512
28687
  functionName: "createAccount",
28513
28688
  args: [signerAddress, salt]
@@ -28534,7 +28709,7 @@ async function createLightAccount({ transport, chain, signer, initCode, version
28534
28709
  return {
28535
28710
  ...account,
28536
28711
  encodeTransferOwnership: (newOwner) => {
28537
- return encodeFunctionData3({
28712
+ return encodeFunctionData4({
28538
28713
  abi: accountAbi,
28539
28714
  functionName: "transferOwnership",
28540
28715
  args: [newOwner]
@@ -29842,7 +30017,7 @@ var init_feeEstimator2 = __esm({
29842
30017
  });
29843
30018
 
29844
30019
  // node_modules/@account-kit/infra/dist/esm/gas-manager.js
29845
- import { encodeFunctionData as encodeFunctionData4 } from "viem";
30020
+ import { encodeFunctionData as encodeFunctionData5 } from "viem";
29846
30021
  var AlchemyPaymasterAddressV06Unify, AlchemyPaymasterAddressV07Unify, AlchemyPaymasterAddressV4, AlchemyPaymasterAddressV3, AlchemyPaymasterAddressV2, ArbSepoliaPaymasterAddress, AlchemyPaymasterAddressV1, AlchemyPaymasterAddressV07V2, AlchemyPaymasterAddressV07V1, getAlchemyPaymasterAddress, PermitTypes, ERC20Abis, EIP7597Abis;
29847
30022
  var init_gas_manager = __esm({
29848
30023
  "node_modules/@account-kit/infra/dist/esm/gas-manager.js"() {
@@ -30031,7 +30206,7 @@ var init_invalidSignedPermit = __esm({
30031
30206
  });
30032
30207
 
30033
30208
  // node_modules/@account-kit/infra/dist/esm/middleware/gasManager.js
30034
- import { fromHex as fromHex5, isHex as isHex2, encodeAbiParameters as encodeAbiParameters5, encodeFunctionData as encodeFunctionData5, parseAbi } from "viem";
30209
+ import { fromHex as fromHex5, isHex as isHex2, encodeAbiParameters as encodeAbiParameters5, encodeFunctionData as encodeFunctionData6, parseAbi as parseAbi2 } from "viem";
30035
30210
  function alchemyGasManagerMiddleware(policyId, policyToken, webhookData) {
30036
30211
  const buildContext = async (args) => {
30037
30212
  const context = { policyId };
@@ -30213,16 +30388,16 @@ var init_gasManager = __esm({
30213
30388
  }
30214
30389
  let allowanceFuture = client.call({
30215
30390
  to: policyToken.address,
30216
- data: encodeFunctionData5({
30217
- abi: parseAbi(ERC20Abis),
30391
+ data: encodeFunctionData6({
30392
+ abi: parseAbi2(ERC20Abis),
30218
30393
  functionName: "allowance",
30219
30394
  args: [account.address, paymasterAddress]
30220
30395
  })
30221
30396
  });
30222
30397
  let nonceFuture = client.call({
30223
30398
  to: policyToken.address,
30224
- data: encodeFunctionData5({
30225
- abi: parseAbi(EIP7597Abis),
30399
+ data: encodeFunctionData6({
30400
+ abi: parseAbi2(EIP7597Abis),
30226
30401
  functionName: "nonces",
30227
30402
  args: [account.address]
30228
30403
  })
@@ -30675,7 +30850,7 @@ var init_fee_utils = __esm({
30675
30850
 
30676
30851
  // src/smart-account/permit2.ts
30677
30852
  import {
30678
- encodeFunctionData as encodeFunctionData6,
30853
+ encodeFunctionData as encodeFunctionData7,
30679
30854
  keccak256 as keccak2567,
30680
30855
  encodeAbiParameters as encodeAbiParameters6,
30681
30856
  concat as concat6,
@@ -30799,7 +30974,7 @@ async function signPermit2(eip1193Request, params) {
30799
30974
  return sig;
30800
30975
  }
30801
30976
  function encodePermitTransferFrom(token, amount, nonce, deadline, saAddress, eoaAddress, sig) {
30802
- return encodeFunctionData6({
30977
+ return encodeFunctionData7({
30803
30978
  abi: PERMIT2_ABI,
30804
30979
  functionName: "permitTransferFrom",
30805
30980
  args: [
@@ -30811,28 +30986,28 @@ function encodePermitTransferFrom(token, amount, nonce, deadline, saAddress, eoa
30811
30986
  });
30812
30987
  }
30813
30988
  function encodeErc20Approve(spender, amount) {
30814
- return encodeFunctionData6({
30989
+ return encodeFunctionData7({
30815
30990
  abi: ERC20_APPROVE_ABI,
30816
30991
  functionName: "approve",
30817
30992
  args: [spender, amount]
30818
30993
  });
30819
30994
  }
30820
30995
  function encodeErc20Allowance(owner, spender) {
30821
- return encodeFunctionData6({
30996
+ return encodeFunctionData7({
30822
30997
  abi: ERC20_ALLOWANCE_ABI,
30823
30998
  functionName: "allowance",
30824
30999
  args: [owner, spender]
30825
31000
  });
30826
31001
  }
30827
31002
  function encodeErc20BalanceOf(owner) {
30828
- return encodeFunctionData6({
31003
+ return encodeFunctionData7({
30829
31004
  abi: ERC20_BALANCE_OF_ABI,
30830
31005
  functionName: "balanceOf",
30831
31006
  args: [owner]
30832
31007
  });
30833
31008
  }
30834
31009
  function encodeWethWithdraw(amount) {
30835
- return encodeFunctionData6({
31010
+ return encodeFunctionData7({
30836
31011
  abi: WETH_ABI,
30837
31012
  functionName: "withdraw",
30838
31013
  args: [amount]
@@ -30925,9 +31100,9 @@ var init_permit2 = __esm({
30925
31100
  });
30926
31101
 
30927
31102
  // src/smart-account/uniswap.ts
30928
- import { encodeFunctionData as encodeFunctionData7 } from "viem";
31103
+ import { encodeFunctionData as encodeFunctionData8 } from "viem";
30929
31104
  function encodeUniswapExactOutputSingle(tokenIn, tokenOut, fee, recipient, amountOut, amountInMaximum) {
30930
- return encodeFunctionData7({
31105
+ return encodeFunctionData8({
30931
31106
  abi: SWAP_ROUTER_ABI,
30932
31107
  functionName: "exactOutputSingle",
30933
31108
  args: [
@@ -31455,14 +31630,14 @@ var init_smart_account2 = __esm({
31455
31630
 
31456
31631
  // src/widget/features/transaction/hooks/useTransactionActionModel.ts
31457
31632
  import { useCallback as useCallback19, useEffect as useEffect26, useMemo as useMemo20, useRef as useRef13, useState as useState26 } from "react";
31458
- import { encodeFunctionData as encodeFunctionData8, erc20Abi } from "viem";
31633
+ import { encodeFunctionData as encodeFunctionData9, erc20Abi } from "viem";
31459
31634
  function normalizeTokenAddressForCompare(chain, addr) {
31460
31635
  const chainType = (chain.type ?? chain.chainType ?? "").toLowerCase();
31461
31636
  const value = (addr ?? "").trim();
31462
31637
  if (chainType === "solana") return value;
31463
31638
  return value.toLowerCase();
31464
31639
  }
31465
- function sleep2(ms) {
31640
+ function sleep3(ms) {
31466
31641
  return new Promise((resolve) => setTimeout(resolve, ms));
31467
31642
  }
31468
31643
  function useTransactionActionModel({
@@ -31478,7 +31653,7 @@ function useTransactionActionModel({
31478
31653
  }) {
31479
31654
  const feeDataCacheRef = useRef13({});
31480
31655
  const { isSubmitting, submitTransaction } = useTransactionSubmit();
31481
- const { trackEvent } = useGTM(GTM_ID);
31656
+ const { trackEvent } = useGTMTracker();
31482
31657
  const destinationConfig = (() => {
31483
31658
  try {
31484
31659
  return Trustware.getConfig();
@@ -31580,7 +31755,7 @@ function useTransactionActionModel({
31580
31755
  if (status.status === "reverted") {
31581
31756
  throw new Error("Approval transaction reverted");
31582
31757
  }
31583
- await sleep2(intervalMs);
31758
+ await sleep3(intervalMs);
31584
31759
  }
31585
31760
  throw new Error("Timed out waiting for approval confirmation");
31586
31761
  },
@@ -31620,7 +31795,7 @@ function useTransactionActionModel({
31620
31795
  }
31621
31796
  }
31622
31797
  }
31623
- const data = encodeFunctionData8({
31798
+ const data = encodeFunctionData9({
31624
31799
  abi: erc20Abi,
31625
31800
  functionName: "approve",
31626
31801
  args: [spender, amountWei]
@@ -31911,7 +32086,6 @@ var init_useTransactionActionModel = __esm({
31911
32086
  init_chainHelpers();
31912
32087
  init_utils2();
31913
32088
  init_hooks();
31914
- init_constants();
31915
32089
  }
31916
32090
  });
31917
32091
 
@@ -33230,7 +33404,7 @@ var init_useSwapRoute = __esm({
33230
33404
 
33231
33405
  // src/modes/swap/hooks/useSwapExecution.ts
33232
33406
  import { useCallback as useCallback21, useRef as useRef16, useState as useState29 } from "react";
33233
- import { encodeFunctionData as encodeFunctionData9, erc20Abi as erc20Abi2 } from "viem";
33407
+ import { encodeFunctionData as encodeFunctionData10, erc20Abi as erc20Abi2 } from "viem";
33234
33408
  function normalizeTx(raw) {
33235
33409
  const r = raw;
33236
33410
  return {
@@ -33241,7 +33415,7 @@ function normalizeTx(raw) {
33241
33415
  toChainTxUrl: r.toChainTxUrl || r.to_chain_tx_url || void 0
33242
33416
  };
33243
33417
  }
33244
- function sleep3(ms) {
33418
+ function sleep4(ms) {
33245
33419
  return new Promise((resolve) => setTimeout(resolve, ms));
33246
33420
  }
33247
33421
  function isUserRejection(err) {
@@ -33259,10 +33433,20 @@ async function waitForApprovalConfirmation(chainId, txHash) {
33259
33433
  if (status.status === "success") return;
33260
33434
  if (status.status === "reverted")
33261
33435
  throw new Error("Approval transaction reverted");
33262
- await sleep3(2e3);
33436
+ await sleep4(2e3);
33263
33437
  }
33264
33438
  throw new Error("Timed out waiting for approval confirmation");
33265
33439
  }
33440
+ async function requireActiveAddress(wallet, plannedFor) {
33441
+ if (!wallet) throw new Error("Wallet not connected. Please reconnect.");
33442
+ const active = await wallet.getAddress();
33443
+ if (active?.toLowerCase() !== plannedFor?.toLowerCase()) {
33444
+ throw new Error(
33445
+ "Wallet account changed. Please review and confirm the swap again."
33446
+ );
33447
+ }
33448
+ return active;
33449
+ }
33266
33450
  function useSwapExecution(fromChain) {
33267
33451
  const [state, setState] = useState29({
33268
33452
  txStatus: "idle",
@@ -33319,7 +33503,15 @@ function useSwapExecution(fromChain) {
33319
33503
  if (tx.status === "bridging") {
33320
33504
  setState((p) => ({ ...p, txStatus: "bridging" }));
33321
33505
  }
33322
- } catch {
33506
+ } catch (err) {
33507
+ if (abortRef.current) return;
33508
+ if (isNotFoundError(err)) {
33509
+ clearPolling();
33510
+ const msg = "Transaction session expired. Please try again.";
33511
+ setState((p) => ({ ...p, txStatus: "error", errorMessage: msg }));
33512
+ onError(msg);
33513
+ return;
33514
+ }
33323
33515
  }
33324
33516
  if (abortRef.current) return;
33325
33517
  pollCountRef.current += 1;
@@ -33345,24 +33537,55 @@ function useSwapExecution(fromChain) {
33345
33537
  }
33346
33538
  const txReq = routeResult.txReq;
33347
33539
  const chainIdStr = String(txReq?.chainId ?? fromChain?.chainId ?? "");
33348
- const spender = txReq?.to ?? txReq?.target;
33349
33540
  const amountWei = BigInt(routeResult.route?.estimate?.fromAmount ?? "0");
33350
- if (!spender || !chainIdStr || amountWei === 0n) {
33541
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33542
+ const toCheck = plannedApprovals.length ? plannedApprovals.flatMap((a) => {
33543
+ const token = a.tokenAddress ?? fromTokenAddress;
33544
+ const required = requiredApprovalAmount(
33545
+ BigInt(a.amount || "0"),
33546
+ amountWei
33547
+ );
33548
+ if (!token || !a.spender) return [];
33549
+ return [
33550
+ {
33551
+ chainId: a.chainId || chainIdStr,
33552
+ token,
33553
+ spender: a.spender,
33554
+ required
33555
+ }
33556
+ ];
33557
+ }) : (() => {
33558
+ const spender = txReq?.to ?? txReq?.target;
33559
+ if (!spender) return [];
33560
+ return [
33561
+ {
33562
+ chainId: chainIdStr,
33563
+ token: fromTokenAddress,
33564
+ spender,
33565
+ required: amountWei
33566
+ }
33567
+ ];
33568
+ })();
33569
+ if (toCheck.length === 0 || !chainIdStr || amountWei === 0n) {
33351
33570
  setState((p) => ({ ...p, allowanceStatus: "unknown" }));
33352
33571
  return;
33353
33572
  }
33354
33573
  setState((p) => ({ ...p, allowanceStatus: "checking" }));
33355
33574
  try {
33356
- const { allowance } = await getEVMAllowance({
33357
- chainId: chainIdStr,
33358
- tokenAddress: fromTokenAddress,
33359
- ownerAddress: walletAddress,
33360
- spenderAddress: spender
33361
- });
33362
- const allowanceWei = BigInt(allowance || "0");
33575
+ const results = await Promise.all(
33576
+ toCheck.map(async (c) => {
33577
+ const { allowance } = await getEVMAllowance({
33578
+ chainId: c.chainId,
33579
+ tokenAddress: c.token,
33580
+ ownerAddress: walletAddress,
33581
+ spenderAddress: c.spender
33582
+ });
33583
+ return approvalSatisfied(BigInt(allowance || "0"), c.required);
33584
+ })
33585
+ );
33363
33586
  setState((p) => ({
33364
33587
  ...p,
33365
- allowanceStatus: allowanceWei >= amountWei ? "sufficient" : "needed"
33588
+ allowanceStatus: results.every(Boolean) ? "sufficient" : "needed"
33366
33589
  }));
33367
33590
  } catch {
33368
33591
  setState((p) => ({ ...p, allowanceStatus: "needed" }));
@@ -33466,19 +33689,49 @@ function useSwapExecution(fromChain) {
33466
33689
  }
33467
33690
  }
33468
33691
  try {
33469
- if (!isNative && walletAddress && spender && chainIdStr && fromTokenAddress) {
33692
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33693
+ const requiredApprovals = plannedApprovals.length ? plannedApprovals.flatMap((a, index) => {
33694
+ const token = a.tokenAddress ?? fromTokenAddress;
33695
+ const approvalSpender = a.spender;
33696
+ if (!token || !approvalSpender) return [];
33697
+ const amountWei = requiredApprovalAmount(
33698
+ BigInt(a.amount || "0"),
33699
+ fromAmountWei
33700
+ );
33701
+ return [
33702
+ {
33703
+ stepIndex: index,
33704
+ token,
33705
+ spender: approvalSpender,
33706
+ amountWei,
33707
+ chainId: a.chainId || chainIdStr
33708
+ }
33709
+ ];
33710
+ }) : spender && fromTokenAddress ? [
33711
+ {
33712
+ stepIndex: null,
33713
+ token: fromTokenAddress,
33714
+ spender,
33715
+ amountWei: fromAmountWei,
33716
+ chainId: chainIdStr
33717
+ }
33718
+ ] : [];
33719
+ const ownsApprovals = !isNative && !!walletAddress && !!chainIdStr;
33720
+ const activeAddress = ownsApprovals ? await requireActiveAddress(wallet, walletAddress) : void 0;
33721
+ for (const required of requiredApprovals) {
33722
+ if (!ownsApprovals) break;
33470
33723
  let allowanceWei = 0n;
33471
33724
  try {
33472
33725
  const { allowance } = await getEVMAllowance({
33473
- chainId: chainIdStr,
33474
- tokenAddress: fromTokenAddress,
33475
- ownerAddress: walletAddress,
33476
- spenderAddress: spender
33726
+ chainId: required.chainId,
33727
+ tokenAddress: required.token,
33728
+ ownerAddress: activeAddress,
33729
+ spenderAddress: required.spender
33477
33730
  });
33478
33731
  allowanceWei = BigInt(allowance || "0");
33479
33732
  } catch {
33480
33733
  }
33481
- if (allowanceWei < fromAmountWei) {
33734
+ if (!approvalSatisfied(allowanceWei, required.amountWei)) {
33482
33735
  setState((p) => ({ ...p, txStatus: "approving" }));
33483
33736
  if (!wallet || wallet.ecosystem !== "evm") {
33484
33737
  throw new Error("EVM wallet required for token approval");
@@ -33486,7 +33739,7 @@ function useSwapExecution(fromChain) {
33486
33739
  if (!chainIdStr || chainIdStr === "0") {
33487
33740
  throw new Error("Invalid chain ID for token approval");
33488
33741
  }
33489
- const targetChain = Number(txReq.chainId ?? fromChain?.chainId);
33742
+ const targetChain = Number(required.chainId ?? txReq.chainId);
33490
33743
  if (Number.isFinite(targetChain)) {
33491
33744
  const current = await wallet.getChainId();
33492
33745
  if (current !== targetChain) {
@@ -33498,18 +33751,18 @@ function useSwapExecution(fromChain) {
33498
33751
  }
33499
33752
  const approveAmount = maxApproval ? BigInt(
33500
33753
  "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
33501
- ) : fromAmountWei;
33502
- const data = encodeFunctionData9({
33754
+ ) : required.amountWei;
33755
+ const data = encodeFunctionData10({
33503
33756
  abi: erc20Abi2,
33504
33757
  functionName: "approve",
33505
- args: [spender, approveAmount]
33758
+ args: [required.spender, approveAmount]
33506
33759
  });
33507
33760
  let approvalHash;
33508
33761
  if (wallet.type === "eip1193") {
33509
33762
  const from = await wallet.getAddress();
33510
33763
  const params = {
33511
33764
  from,
33512
- to: fromTokenAddress,
33765
+ to: required.token,
33513
33766
  data,
33514
33767
  value: "0x0"
33515
33768
  };
@@ -33522,14 +33775,22 @@ function useSwapExecution(fromChain) {
33522
33775
  });
33523
33776
  } else {
33524
33777
  const response = await wallet.sendTransaction({
33525
- to: fromTokenAddress,
33778
+ to: required.token,
33526
33779
  data,
33527
33780
  value: 0n,
33528
33781
  chainId: Number.isFinite(targetChain) ? targetChain : void 0
33529
33782
  });
33530
33783
  approvalHash = response.hash;
33531
33784
  }
33532
- await waitForApprovalConfirmation(chainIdStr, approvalHash);
33785
+ if (required.stepIndex !== null) {
33786
+ void submitStepReceipt(
33787
+ routeResult.intentId,
33788
+ required.stepIndex,
33789
+ approvalHash
33790
+ ).catch(() => {
33791
+ });
33792
+ }
33793
+ await waitForApprovalConfirmation(required.chainId, approvalHash);
33533
33794
  setState((p) => ({
33534
33795
  ...p,
33535
33796
  txStatus: "confirming",
@@ -33537,9 +33798,13 @@ function useSwapExecution(fromChain) {
33537
33798
  }));
33538
33799
  }
33539
33800
  }
33801
+ if (ownsApprovals) {
33802
+ await requireActiveAddress(wallet, walletAddress);
33803
+ }
33540
33804
  const hash = await Trustware.sendRouteTransaction(
33541
33805
  routeResult,
33542
- numericChainId
33806
+ numericChainId,
33807
+ { approvalsEnsured: ownsApprovals }
33543
33808
  );
33544
33809
  try {
33545
33810
  await submitReceipt(routeResult.intentId, hash);
@@ -33607,6 +33872,8 @@ var init_useSwapExecution = __esm({
33607
33872
  "use client";
33608
33873
  init_core2();
33609
33874
  init_routes();
33875
+ init_http();
33876
+ init_tx();
33610
33877
  init_sdkRpc();
33611
33878
  init_chainHelpers();
33612
33879
  FAST_POLL_MS = 1500;
@@ -39571,6 +39838,7 @@ function WidgetInner({
39571
39838
  const { resolvedTheme } = useDepositUi();
39572
39839
  const { status, revalidate, errors } = useTrustware();
39573
39840
  const [showConfirmDialog, setShowConfirmDialog] = useState35(false);
39841
+ useGTM(GTM_ID);
39574
39842
  const handleCloseRequest = useCallback23(() => {
39575
39843
  if (ACTIVE_TRANSACTION_STATUSES.includes(transactionStatus)) {
39576
39844
  setShowConfirmDialog(true);
@@ -39644,6 +39912,8 @@ var init_TrustwareWidgetV2 = __esm({
39644
39912
  init_provider();
39645
39913
  init_manager();
39646
39914
  init_useTrustwareConfig();
39915
+ init_hooks();
39916
+ init_constants();
39647
39917
  init_swap();
39648
39918
  widgetContentContainerStyle = {
39649
39919
  position: "relative",