@trustware/sdk-staging 1.1.10-staging.0 → 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/index.cjs CHANGED
@@ -464,6 +464,20 @@ var init_eipWallets = __esm({
464
464
  "src/wallets/eipWallets.ts"() {
465
465
  "use strict";
466
466
  CHAIN_PARAMS = {
467
+ 1: {
468
+ chainIdHex: "0x1",
469
+ chainName: "Ethereum",
470
+ rpcUrls: ["https://eth.llamarpc.com"],
471
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
472
+ blockExplorerUrls: ["https://etherscan.io"]
473
+ },
474
+ 137: {
475
+ chainIdHex: "0x89",
476
+ chainName: "Polygon",
477
+ rpcUrls: ["https://polygon-rpc.com"],
478
+ nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
479
+ blockExplorerUrls: ["https://polygonscan.com"]
480
+ },
467
481
  8453: {
468
482
  chainIdHex: "0x2105",
469
483
  chainName: "Base",
@@ -495,7 +509,7 @@ var init_constants = __esm({
495
509
  "src/constants.ts"() {
496
510
  "use strict";
497
511
  SDK_NAME = "@trustware/sdk";
498
- SDK_VERSION = "1.1.10-staging.0";
512
+ SDK_VERSION = "1.1.11-staging.1";
499
513
  API_ROOT = "https://bv-staging-api.trustware.io";
500
514
  GTM_ID = "GTM-TZDGNCXB";
501
515
  API_PREFIX = "/api";
@@ -539,6 +553,9 @@ async function assertOK(r) {
539
553
  }
540
554
  throw new Error(`HTTP ${r.status}: ${msg}`);
541
555
  }
556
+ function isNotFoundError(err) {
557
+ return err instanceof Error && err.message.startsWith("HTTP 404");
558
+ }
542
559
  async function validateSdkAccess() {
543
560
  const r = await fetch(`${apiBase()}/sdk/validate`, {
544
561
  method: "GET",
@@ -4536,6 +4553,19 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress)
4536
4553
  const j = await r.json();
4537
4554
  return j.data;
4538
4555
  }
4556
+ async function submitStepReceipt(intentId, stepIndex, txHash) {
4557
+ const r = await rateLimitedFetch(
4558
+ `${apiBase()}/v1/route-intent/${intentId}/steps/${stepIndex}/receipt`,
4559
+ {
4560
+ method: "POST",
4561
+ headers: jsonHeaders({ "Idempotency-Key": txHash }),
4562
+ body: JSON.stringify({ txHash })
4563
+ }
4564
+ );
4565
+ await assertOK(r);
4566
+ const j = await r.json();
4567
+ return j.data;
4568
+ }
4539
4569
  async function getStatus(intentId) {
4540
4570
  const r = await rateLimitedFetch(
4541
4571
  `${apiBase()}/v1/route-intent/${intentId}/status`,
@@ -5273,18 +5303,27 @@ async function waitForTxConfirmation(chainId, txHash) {
5273
5303
  }
5274
5304
  throw new Error("Timed out waiting for approval confirmation");
5275
5305
  }
5276
- async function ensureApprovals(w, approvals, fallbackChainId) {
5306
+ function requiredApprovalAmount(planAmountWei, routeAmountWei) {
5307
+ if (planAmountWei >= UNLIMITED_APPROVAL_FLOOR && routeAmountWei !== void 0 && routeAmountWei > 0n) {
5308
+ return routeAmountWei;
5309
+ }
5310
+ return planAmountWei;
5311
+ }
5312
+ function approvalSatisfied(currentAllowance, requiredWei) {
5313
+ if (requiredWei === 0n) return currentAllowance === 0n;
5314
+ return currentAllowance >= requiredWei;
5315
+ }
5316
+ async function ensureApprovals(w, approvals, fallbackChainId, intentId, routeAmountWei) {
5277
5317
  if (!approvals || approvals.length === 0) return;
5278
5318
  const owner = await w.getAddress();
5279
- for (const approval of approvals) {
5319
+ for (const [stepIndex, approval] of approvals.entries()) {
5280
5320
  const spender = approval.spender;
5281
5321
  const tokenAddress = approval.tokenAddress;
5282
5322
  const amount = approval.amount;
5283
5323
  if (!spender || !tokenAddress || !amount) continue;
5284
5324
  const chainId = approval.chainId || String(fallbackChainId ?? "");
5285
5325
  if (!chainId) continue;
5286
- const amountWei = BigInt(amount);
5287
- if (amountWei === 0n) continue;
5326
+ const amountWei = requiredApprovalAmount(BigInt(amount), routeAmountWei);
5288
5327
  let currentAllowance = 0n;
5289
5328
  try {
5290
5329
  const { allowance } = await getEVMAllowance({
@@ -5296,7 +5335,7 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
5296
5335
  currentAllowance = BigInt(allowance || "0");
5297
5336
  } catch {
5298
5337
  }
5299
- if (currentAllowance >= amountWei) continue;
5338
+ if (approvalSatisfied(currentAllowance, amountWei)) continue;
5300
5339
  const data = (0, import_viem2.encodeFunctionData)({
5301
5340
  abi: erc20ApproveAbi,
5302
5341
  functionName: "approve",
@@ -5308,6 +5347,10 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
5308
5347
  value: 0n,
5309
5348
  chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
5310
5349
  });
5350
+ if (intentId) {
5351
+ void submitStepReceipt(intentId, stepIndex, hash).catch(() => {
5352
+ });
5353
+ }
5311
5354
  await waitForTxConfirmation(chainId, hash);
5312
5355
  }
5313
5356
  }
@@ -5317,7 +5360,7 @@ function isUserRejected(e2) {
5317
5360
  const msg = String(e2?.message || e2)?.toLowerCase?.() || "";
5318
5361
  return msg.includes("user rejected") || msg.includes("user denied");
5319
5362
  }
5320
- async function sendRouteTransaction(b, fallbackChainId) {
5363
+ async function sendRouteTransaction(b, fallbackChainId, options) {
5321
5364
  const w = walletManager.wallet;
5322
5365
  if (!w) throw new Error("Trustware.wallet not configured");
5323
5366
  const txReq = b.txReq;
@@ -5344,11 +5387,13 @@ async function sendRouteTransaction(b, fallbackChainId) {
5344
5387
  }
5345
5388
  }
5346
5389
  }
5347
- if (!validatedSponsorship) {
5390
+ if (!validatedSponsorship && !options?.approvalsEnsured) {
5348
5391
  await ensureApprovals(
5349
5392
  w,
5350
5393
  b.route?.execution?.approvals,
5351
- Number.isFinite(target) ? target : void 0
5394
+ Number.isFinite(target) ? target : void 0,
5395
+ b.intentId,
5396
+ BigInt(b.route?.estimate?.fromAmount ?? "0")
5352
5397
  );
5353
5398
  }
5354
5399
  if (w.type === "eip1193") {
@@ -5447,7 +5492,7 @@ async function runTopUp(params) {
5447
5492
  }
5448
5493
  }
5449
5494
  }
5450
- var import_viem2, erc20ApproveAbi;
5495
+ var import_viem2, erc20ApproveAbi, UNLIMITED_APPROVAL_FLOOR;
5451
5496
  var init_tx = __esm({
5452
5497
  "src/core/tx.ts"() {
5453
5498
  "use strict";
@@ -5458,6 +5503,7 @@ var init_tx = __esm({
5458
5503
  erc20ApproveAbi = (0, import_viem2.parseAbi)([
5459
5504
  "function approve(address spender, uint256 amount) returns (bool)"
5460
5505
  ]);
5506
+ UNLIMITED_APPROVAL_FLOOR = 1n << 255n;
5461
5507
  }
5462
5508
  });
5463
5509
 
@@ -7731,6 +7777,7 @@ var init_core = __esm({
7731
7777
  buildRoute,
7732
7778
  buildDepositAddress,
7733
7779
  submitReceipt,
7780
+ submitStepReceipt,
7734
7781
  getStatus,
7735
7782
  pollStatus,
7736
7783
  getBalances,
@@ -8959,75 +9006,17 @@ var init_useTransactionSubmit = __esm({
8959
9006
  });
8960
9007
 
8961
9008
  // src/hooks/useGTM.ts
8962
- function useGTM(gtmId) {
8963
- const isInitialized = (0, import_react15.useRef)(false);
8964
- const scriptRef = (0, import_react15.useRef)(null);
8965
- const isGA4Allowed = (0, import_react15.useCallback)(() => {
8966
- try {
8967
- return Trustware.getConfig().features.shouldAllowGA4;
8968
- } catch {
8969
- return false;
8970
- }
8971
- }, []);
8972
- (0, import_react15.useEffect)(() => {
8973
- if (!isGA4Allowed()) {
8974
- console.warn(
8975
- "useGTM: GA4 tracking is disabled or Trustware config not initialized."
8976
- );
8977
- return;
8978
- }
8979
- if (!gtmId || typeof gtmId !== "string") {
8980
- console.error(
8981
- "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
8982
- );
8983
- return;
8984
- }
8985
- if (isInitialized.current) return;
8986
- const alreadyLoaded = document.querySelector(
8987
- `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
8988
- );
8989
- if (alreadyLoaded) {
8990
- window.dataLayer = window.dataLayer || [];
8991
- isInitialized.current = true;
8992
- return;
8993
- }
8994
- window.dataLayer = window.dataLayer || [];
8995
- window.dataLayer.push({
8996
- "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
8997
- event: "gtm.js"
8998
- });
8999
- const firstScript = document.getElementsByTagName("script")[0];
9000
- const script = document.createElement("script");
9001
- script.async = true;
9002
- script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
9003
- firstScript.parentNode?.insertBefore(script, firstScript);
9004
- scriptRef.current = script;
9005
- isInitialized.current = true;
9006
- return () => {
9007
- if (scriptRef.current) {
9008
- scriptRef.current.parentNode?.removeChild(scriptRef.current);
9009
- scriptRef.current = null;
9010
- }
9011
- isInitialized.current = false;
9012
- };
9013
- }, [gtmId, isGA4Allowed]);
9014
- const addNoscriptIframe = (0, import_react15.useCallback)(() => {
9015
- if (!isGA4Allowed()) return;
9016
- if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
9017
- return;
9018
- const noscript = document.createElement("noscript");
9019
- const iframe = document.createElement("iframe");
9020
- iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
9021
- iframe.height = "0";
9022
- iframe.width = "0";
9023
- iframe.style.display = "none";
9024
- iframe.style.visibility = "hidden";
9025
- noscript.appendChild(iframe);
9026
- document.body.insertBefore(noscript, document.body.firstChild);
9027
- }, [gtmId, isGA4Allowed]);
9009
+ function isGA4Allowed() {
9010
+ try {
9011
+ return Trustware.getConfig().features.shouldAllowGA4;
9012
+ } catch {
9013
+ return false;
9014
+ }
9015
+ }
9016
+ function useGTMTracker() {
9028
9017
  const trackEvent = (0, import_react15.useCallback)(
9029
9018
  (eventName, eventParams = {}) => {
9030
- if (!isInitialized.current) {
9019
+ if (!isContainerInitialized) {
9031
9020
  console.warn(
9032
9021
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
9033
9022
  );
@@ -9054,7 +9043,7 @@ function useGTM(gtmId) {
9054
9043
  );
9055
9044
  const setUserProperty = (0, import_react15.useCallback)(
9056
9045
  (propertyName, value) => {
9057
- if (!isInitialized.current) {
9046
+ if (!isContainerInitialized) {
9058
9047
  console.warn(
9059
9048
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
9060
9049
  );
@@ -9080,22 +9069,78 @@ function useGTM(gtmId) {
9080
9069
  }
9081
9070
  window.gtag(command, ...args);
9082
9071
  },
9083
- [isGA4Allowed]
9072
+ []
9084
9073
  );
9085
- return {
9086
- trackEvent,
9087
- trackPageView,
9088
- setUserProperty,
9089
- directGtag,
9090
- addNoscriptIframe
9091
- };
9074
+ return { trackEvent, trackPageView, setUserProperty, directGtag };
9075
+ }
9076
+ function useGTM(gtmId) {
9077
+ const scriptRef = (0, import_react15.useRef)(null);
9078
+ const tracker = useGTMTracker();
9079
+ (0, import_react15.useEffect)(() => {
9080
+ if (!isGA4Allowed()) {
9081
+ console.warn(
9082
+ "useGTM: GA4 tracking is disabled or Trustware config not initialized."
9083
+ );
9084
+ return;
9085
+ }
9086
+ if (!gtmId || typeof gtmId !== "string") {
9087
+ console.error(
9088
+ "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
9089
+ );
9090
+ return;
9091
+ }
9092
+ if (isContainerInitialized) return;
9093
+ const alreadyLoaded = document.querySelector(
9094
+ `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
9095
+ );
9096
+ if (alreadyLoaded) {
9097
+ window.dataLayer = window.dataLayer || [];
9098
+ isContainerInitialized = true;
9099
+ return;
9100
+ }
9101
+ window.dataLayer = window.dataLayer || [];
9102
+ window.dataLayer.push({
9103
+ "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
9104
+ event: "gtm.js"
9105
+ });
9106
+ const firstScript = document.getElementsByTagName("script")[0];
9107
+ const script = document.createElement("script");
9108
+ script.async = true;
9109
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
9110
+ firstScript.parentNode?.insertBefore(script, firstScript);
9111
+ scriptRef.current = script;
9112
+ isContainerInitialized = true;
9113
+ return () => {
9114
+ if (scriptRef.current) {
9115
+ scriptRef.current.parentNode?.removeChild(scriptRef.current);
9116
+ scriptRef.current = null;
9117
+ }
9118
+ isContainerInitialized = false;
9119
+ };
9120
+ }, [gtmId]);
9121
+ const addNoscriptIframe = (0, import_react15.useCallback)(() => {
9122
+ if (!isGA4Allowed()) return;
9123
+ if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
9124
+ return;
9125
+ const noscript = document.createElement("noscript");
9126
+ const iframe = document.createElement("iframe");
9127
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
9128
+ iframe.height = "0";
9129
+ iframe.width = "0";
9130
+ iframe.style.display = "none";
9131
+ iframe.style.visibility = "hidden";
9132
+ noscript.appendChild(iframe);
9133
+ document.body.insertBefore(noscript, document.body.firstChild);
9134
+ }, [gtmId]);
9135
+ return { ...tracker, addNoscriptIframe };
9092
9136
  }
9093
- var import_react15;
9137
+ var import_react15, isContainerInitialized;
9094
9138
  var init_useGTM = __esm({
9095
9139
  "src/hooks/useGTM.ts"() {
9096
9140
  "use strict";
9097
9141
  import_react15 = require("react");
9098
9142
  init_core2();
9143
+ isContainerInitialized = false;
9099
9144
  }
9100
9145
  });
9101
9146
 
@@ -9121,7 +9166,7 @@ function useTransactionPolling() {
9121
9166
  return void 0;
9122
9167
  }
9123
9168
  })();
9124
- const { trackEvent } = useGTM(GTM_ID);
9169
+ const { trackEvent } = useGTMTracker();
9125
9170
  const [state, setState] = (0, import_react16.useState)({
9126
9171
  isPolling: false,
9127
9172
  apiStatus: null,
@@ -9221,8 +9266,21 @@ function useTransactionPolling() {
9221
9266
  pollCountRef.current += 1;
9222
9267
  const pollInterval = pollCountRef.current <= 10 ? FAST_POLL_INTERVAL_MS : NORMAL_POLL_INTERVAL_MS;
9223
9268
  pollingRef.current = setTimeout(poll, pollInterval);
9224
- } catch {
9269
+ } catch (err) {
9225
9270
  if (abortRef.current) return;
9271
+ if (isNotFoundError(err)) {
9272
+ clearPolling();
9273
+ const notFoundError = "Transaction session expired. Please try again.";
9274
+ setState((prev) => ({
9275
+ ...prev,
9276
+ isPolling: false,
9277
+ error: notFoundError
9278
+ }));
9279
+ setErrorMessage(notFoundError);
9280
+ setTransactionStatus("error");
9281
+ setCurrentStep("error");
9282
+ return;
9283
+ }
9226
9284
  const elapsed = Date.now() - startTimeRef.current;
9227
9285
  if (elapsed > POLL_TIMEOUT_MS) {
9228
9286
  clearPolling();
@@ -9359,10 +9417,10 @@ var init_useTransactionPolling = __esm({
9359
9417
  "use client";
9360
9418
  import_react16 = require("react");
9361
9419
  init_routes();
9420
+ init_http();
9362
9421
  init_DepositContext();
9363
9422
  init_provider();
9364
9423
  init_core2();
9365
- init_constants();
9366
9424
  init_hooks();
9367
9425
  FAST_POLL_INTERVAL_MS = 1500;
9368
9426
  NORMAL_POLL_INTERVAL_MS = 2500;
@@ -31810,7 +31868,7 @@ function useTransactionActionModel({
31810
31868
  }) {
31811
31869
  const feeDataCacheRef = (0, import_react37.useRef)({});
31812
31870
  const { isSubmitting, submitTransaction } = useTransactionSubmit();
31813
- const { trackEvent } = useGTM(GTM_ID);
31871
+ const { trackEvent } = useGTMTracker();
31814
31872
  const destinationConfig = (() => {
31815
31873
  try {
31816
31874
  return Trustware.getConfig();
@@ -32246,7 +32304,6 @@ var init_useTransactionActionModel = __esm({
32246
32304
  init_chainHelpers();
32247
32305
  init_utils();
32248
32306
  init_hooks();
32249
- init_constants();
32250
32307
  }
32251
32308
  });
32252
32309
 
@@ -33599,6 +33656,16 @@ async function waitForApprovalConfirmation(chainId, txHash) {
33599
33656
  }
33600
33657
  throw new Error("Timed out waiting for approval confirmation");
33601
33658
  }
33659
+ async function requireActiveAddress(wallet, plannedFor) {
33660
+ if (!wallet) throw new Error("Wallet not connected. Please reconnect.");
33661
+ const active = await wallet.getAddress();
33662
+ if (active?.toLowerCase() !== plannedFor?.toLowerCase()) {
33663
+ throw new Error(
33664
+ "Wallet account changed. Please review and confirm the swap again."
33665
+ );
33666
+ }
33667
+ return active;
33668
+ }
33602
33669
  function useSwapExecution(fromChain) {
33603
33670
  const [state, setState] = (0, import_react45.useState)({
33604
33671
  txStatus: "idle",
@@ -33655,7 +33722,15 @@ function useSwapExecution(fromChain) {
33655
33722
  if (tx.status === "bridging") {
33656
33723
  setState((p) => ({ ...p, txStatus: "bridging" }));
33657
33724
  }
33658
- } catch {
33725
+ } catch (err) {
33726
+ if (abortRef.current) return;
33727
+ if (isNotFoundError(err)) {
33728
+ clearPolling();
33729
+ const msg = "Transaction session expired. Please try again.";
33730
+ setState((p) => ({ ...p, txStatus: "error", errorMessage: msg }));
33731
+ onError(msg);
33732
+ return;
33733
+ }
33659
33734
  }
33660
33735
  if (abortRef.current) return;
33661
33736
  pollCountRef.current += 1;
@@ -33681,24 +33756,55 @@ function useSwapExecution(fromChain) {
33681
33756
  }
33682
33757
  const txReq = routeResult.txReq;
33683
33758
  const chainIdStr = String(txReq?.chainId ?? fromChain?.chainId ?? "");
33684
- const spender = txReq?.to ?? txReq?.target;
33685
33759
  const amountWei = BigInt(routeResult.route?.estimate?.fromAmount ?? "0");
33686
- if (!spender || !chainIdStr || amountWei === 0n) {
33760
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33761
+ const toCheck = plannedApprovals.length ? plannedApprovals.flatMap((a) => {
33762
+ const token = a.tokenAddress ?? fromTokenAddress;
33763
+ const required = requiredApprovalAmount(
33764
+ BigInt(a.amount || "0"),
33765
+ amountWei
33766
+ );
33767
+ if (!token || !a.spender) return [];
33768
+ return [
33769
+ {
33770
+ chainId: a.chainId || chainIdStr,
33771
+ token,
33772
+ spender: a.spender,
33773
+ required
33774
+ }
33775
+ ];
33776
+ }) : (() => {
33777
+ const spender = txReq?.to ?? txReq?.target;
33778
+ if (!spender) return [];
33779
+ return [
33780
+ {
33781
+ chainId: chainIdStr,
33782
+ token: fromTokenAddress,
33783
+ spender,
33784
+ required: amountWei
33785
+ }
33786
+ ];
33787
+ })();
33788
+ if (toCheck.length === 0 || !chainIdStr || amountWei === 0n) {
33687
33789
  setState((p) => ({ ...p, allowanceStatus: "unknown" }));
33688
33790
  return;
33689
33791
  }
33690
33792
  setState((p) => ({ ...p, allowanceStatus: "checking" }));
33691
33793
  try {
33692
- const { allowance } = await getEVMAllowance({
33693
- chainId: chainIdStr,
33694
- tokenAddress: fromTokenAddress,
33695
- ownerAddress: walletAddress,
33696
- spenderAddress: spender
33697
- });
33698
- const allowanceWei = BigInt(allowance || "0");
33794
+ const results = await Promise.all(
33795
+ toCheck.map(async (c) => {
33796
+ const { allowance } = await getEVMAllowance({
33797
+ chainId: c.chainId,
33798
+ tokenAddress: c.token,
33799
+ ownerAddress: walletAddress,
33800
+ spenderAddress: c.spender
33801
+ });
33802
+ return approvalSatisfied(BigInt(allowance || "0"), c.required);
33803
+ })
33804
+ );
33699
33805
  setState((p) => ({
33700
33806
  ...p,
33701
- allowanceStatus: allowanceWei >= amountWei ? "sufficient" : "needed"
33807
+ allowanceStatus: results.every(Boolean) ? "sufficient" : "needed"
33702
33808
  }));
33703
33809
  } catch {
33704
33810
  setState((p) => ({ ...p, allowanceStatus: "needed" }));
@@ -33802,19 +33908,49 @@ function useSwapExecution(fromChain) {
33802
33908
  }
33803
33909
  }
33804
33910
  try {
33805
- if (!isNative && walletAddress && spender && chainIdStr && fromTokenAddress) {
33911
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33912
+ const requiredApprovals = plannedApprovals.length ? plannedApprovals.flatMap((a, index) => {
33913
+ const token = a.tokenAddress ?? fromTokenAddress;
33914
+ const approvalSpender = a.spender;
33915
+ if (!token || !approvalSpender) return [];
33916
+ const amountWei = requiredApprovalAmount(
33917
+ BigInt(a.amount || "0"),
33918
+ fromAmountWei
33919
+ );
33920
+ return [
33921
+ {
33922
+ stepIndex: index,
33923
+ token,
33924
+ spender: approvalSpender,
33925
+ amountWei,
33926
+ chainId: a.chainId || chainIdStr
33927
+ }
33928
+ ];
33929
+ }) : spender && fromTokenAddress ? [
33930
+ {
33931
+ stepIndex: null,
33932
+ token: fromTokenAddress,
33933
+ spender,
33934
+ amountWei: fromAmountWei,
33935
+ chainId: chainIdStr
33936
+ }
33937
+ ] : [];
33938
+ const ownsApprovals = !isNative && !!walletAddress && !!chainIdStr;
33939
+ const activeAddress = ownsApprovals ? await requireActiveAddress(wallet, walletAddress) : void 0;
33940
+ for (const required of requiredApprovals) {
33941
+ if (!ownsApprovals) break;
33806
33942
  let allowanceWei = 0n;
33807
33943
  try {
33808
33944
  const { allowance } = await getEVMAllowance({
33809
- chainId: chainIdStr,
33810
- tokenAddress: fromTokenAddress,
33811
- ownerAddress: walletAddress,
33812
- spenderAddress: spender
33945
+ chainId: required.chainId,
33946
+ tokenAddress: required.token,
33947
+ ownerAddress: activeAddress,
33948
+ spenderAddress: required.spender
33813
33949
  });
33814
33950
  allowanceWei = BigInt(allowance || "0");
33815
33951
  } catch {
33816
33952
  }
33817
- if (allowanceWei < fromAmountWei) {
33953
+ if (!approvalSatisfied(allowanceWei, required.amountWei)) {
33818
33954
  setState((p) => ({ ...p, txStatus: "approving" }));
33819
33955
  if (!wallet || wallet.ecosystem !== "evm") {
33820
33956
  throw new Error("EVM wallet required for token approval");
@@ -33822,7 +33958,7 @@ function useSwapExecution(fromChain) {
33822
33958
  if (!chainIdStr || chainIdStr === "0") {
33823
33959
  throw new Error("Invalid chain ID for token approval");
33824
33960
  }
33825
- const targetChain = Number(txReq.chainId ?? fromChain?.chainId);
33961
+ const targetChain = Number(required.chainId ?? txReq.chainId);
33826
33962
  if (Number.isFinite(targetChain)) {
33827
33963
  const current = await wallet.getChainId();
33828
33964
  if (current !== targetChain) {
@@ -33834,18 +33970,18 @@ function useSwapExecution(fromChain) {
33834
33970
  }
33835
33971
  const approveAmount = maxApproval ? BigInt(
33836
33972
  "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
33837
- ) : fromAmountWei;
33973
+ ) : required.amountWei;
33838
33974
  const data = (0, import_viem43.encodeFunctionData)({
33839
33975
  abi: import_viem43.erc20Abi,
33840
33976
  functionName: "approve",
33841
- args: [spender, approveAmount]
33977
+ args: [required.spender, approveAmount]
33842
33978
  });
33843
33979
  let approvalHash;
33844
33980
  if (wallet.type === "eip1193") {
33845
33981
  const from = await wallet.getAddress();
33846
33982
  const params = {
33847
33983
  from,
33848
- to: fromTokenAddress,
33984
+ to: required.token,
33849
33985
  data,
33850
33986
  value: "0x0"
33851
33987
  };
@@ -33858,14 +33994,22 @@ function useSwapExecution(fromChain) {
33858
33994
  });
33859
33995
  } else {
33860
33996
  const response = await wallet.sendTransaction({
33861
- to: fromTokenAddress,
33997
+ to: required.token,
33862
33998
  data,
33863
33999
  value: 0n,
33864
34000
  chainId: Number.isFinite(targetChain) ? targetChain : void 0
33865
34001
  });
33866
34002
  approvalHash = response.hash;
33867
34003
  }
33868
- await waitForApprovalConfirmation(chainIdStr, approvalHash);
34004
+ if (required.stepIndex !== null) {
34005
+ void submitStepReceipt(
34006
+ routeResult.intentId,
34007
+ required.stepIndex,
34008
+ approvalHash
34009
+ ).catch(() => {
34010
+ });
34011
+ }
34012
+ await waitForApprovalConfirmation(required.chainId, approvalHash);
33869
34013
  setState((p) => ({
33870
34014
  ...p,
33871
34015
  txStatus: "confirming",
@@ -33873,9 +34017,13 @@ function useSwapExecution(fromChain) {
33873
34017
  }));
33874
34018
  }
33875
34019
  }
34020
+ if (ownsApprovals) {
34021
+ await requireActiveAddress(wallet, walletAddress);
34022
+ }
33876
34023
  const hash = await Trustware.sendRouteTransaction(
33877
34024
  routeResult,
33878
- numericChainId
34025
+ numericChainId,
34026
+ { approvalsEnsured: ownsApprovals }
33879
34027
  );
33880
34028
  try {
33881
34029
  await submitReceipt(routeResult.intentId, hash);
@@ -33945,6 +34093,8 @@ var init_useSwapExecution = __esm({
33945
34093
  import_viem43 = require("viem");
33946
34094
  init_core2();
33947
34095
  init_routes();
34096
+ init_http();
34097
+ init_tx();
33948
34098
  init_sdkRpc();
33949
34099
  init_chainHelpers();
33950
34100
  FAST_POLL_MS = 1500;
@@ -39894,6 +40044,7 @@ function WidgetInner({
39894
40044
  const { resolvedTheme } = useDepositUi();
39895
40045
  const { status, revalidate, errors } = useTrustware();
39896
40046
  const [showConfirmDialog, setShowConfirmDialog] = (0, import_react51.useState)(false);
40047
+ useGTM(GTM_ID);
39897
40048
  const handleCloseRequest = (0, import_react51.useCallback)(() => {
39898
40049
  if (ACTIVE_TRANSACTION_STATUSES.includes(transactionStatus)) {
39899
40050
  setShowConfirmDialog(true);
@@ -39968,6 +40119,8 @@ var init_TrustwareWidgetV2 = __esm({
39968
40119
  init_provider();
39969
40120
  init_manager();
39970
40121
  init_useTrustwareConfig();
40122
+ init_hooks();
40123
+ init_constants();
39971
40124
  init_swap();
39972
40125
  import_jsx_runtime60 = require("react/jsx-runtime");
39973
40126
  widgetContentContainerStyle = {