@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/widget.cjs CHANGED
@@ -585,7 +585,7 @@ var init_constants = __esm({
585
585
  "src/constants.ts"() {
586
586
  "use strict";
587
587
  SDK_NAME = "@trustware/sdk";
588
- SDK_VERSION = "1.1.10-staging.0";
588
+ SDK_VERSION = "1.1.11-staging.1";
589
589
  API_ROOT = "https://bv-staging-api.trustware.io";
590
590
  GTM_ID = "GTM-TZDGNCXB";
591
591
  API_PREFIX = "/api";
@@ -629,6 +629,9 @@ async function assertOK(r) {
629
629
  }
630
630
  throw new Error(`HTTP ${r.status}: ${msg}`);
631
631
  }
632
+ function isNotFoundError(err) {
633
+ return err instanceof Error && err.message.startsWith("HTTP 404");
634
+ }
632
635
  async function validateSdkAccess() {
633
636
  const r = await fetch(`${apiBase()}/sdk/validate`, {
634
637
  method: "GET",
@@ -2601,6 +2604,19 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress)
2601
2604
  const j = await r.json();
2602
2605
  return j.data;
2603
2606
  }
2607
+ async function submitStepReceipt(intentId, stepIndex, txHash) {
2608
+ const r = await rateLimitedFetch(
2609
+ `${apiBase()}/v1/route-intent/${intentId}/steps/${stepIndex}/receipt`,
2610
+ {
2611
+ method: "POST",
2612
+ headers: jsonHeaders({ "Idempotency-Key": txHash }),
2613
+ body: JSON.stringify({ txHash })
2614
+ }
2615
+ );
2616
+ await assertOK(r);
2617
+ const j = await r.json();
2618
+ return j.data;
2619
+ }
2604
2620
  async function getStatus(intentId) {
2605
2621
  const r = await rateLimitedFetch(
2606
2622
  `${apiBase()}/v1/route-intent/${intentId}/status`,
@@ -5325,75 +5341,17 @@ var init_useTransactionSubmit = __esm({
5325
5341
  });
5326
5342
 
5327
5343
  // src/hooks/useGTM.ts
5328
- function useGTM(gtmId) {
5329
- const isInitialized = (0, import_react7.useRef)(false);
5330
- const scriptRef = (0, import_react7.useRef)(null);
5331
- const isGA4Allowed = (0, import_react7.useCallback)(() => {
5332
- try {
5333
- return Trustware.getConfig().features.shouldAllowGA4;
5334
- } catch {
5335
- return false;
5336
- }
5337
- }, []);
5338
- (0, import_react7.useEffect)(() => {
5339
- if (!isGA4Allowed()) {
5340
- console.warn(
5341
- "useGTM: GA4 tracking is disabled or Trustware config not initialized."
5342
- );
5343
- return;
5344
- }
5345
- if (!gtmId || typeof gtmId !== "string") {
5346
- console.error(
5347
- "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
5348
- );
5349
- return;
5350
- }
5351
- if (isInitialized.current) return;
5352
- const alreadyLoaded = document.querySelector(
5353
- `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
5354
- );
5355
- if (alreadyLoaded) {
5356
- window.dataLayer = window.dataLayer || [];
5357
- isInitialized.current = true;
5358
- return;
5359
- }
5360
- window.dataLayer = window.dataLayer || [];
5361
- window.dataLayer.push({
5362
- "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
5363
- event: "gtm.js"
5364
- });
5365
- const firstScript = document.getElementsByTagName("script")[0];
5366
- const script = document.createElement("script");
5367
- script.async = true;
5368
- script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
5369
- firstScript.parentNode?.insertBefore(script, firstScript);
5370
- scriptRef.current = script;
5371
- isInitialized.current = true;
5372
- return () => {
5373
- if (scriptRef.current) {
5374
- scriptRef.current.parentNode?.removeChild(scriptRef.current);
5375
- scriptRef.current = null;
5376
- }
5377
- isInitialized.current = false;
5378
- };
5379
- }, [gtmId, isGA4Allowed]);
5380
- const addNoscriptIframe = (0, import_react7.useCallback)(() => {
5381
- if (!isGA4Allowed()) return;
5382
- if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
5383
- return;
5384
- const noscript = document.createElement("noscript");
5385
- const iframe = document.createElement("iframe");
5386
- iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
5387
- iframe.height = "0";
5388
- iframe.width = "0";
5389
- iframe.style.display = "none";
5390
- iframe.style.visibility = "hidden";
5391
- noscript.appendChild(iframe);
5392
- document.body.insertBefore(noscript, document.body.firstChild);
5393
- }, [gtmId, isGA4Allowed]);
5344
+ function isGA4Allowed() {
5345
+ try {
5346
+ return Trustware.getConfig().features.shouldAllowGA4;
5347
+ } catch {
5348
+ return false;
5349
+ }
5350
+ }
5351
+ function useGTMTracker() {
5394
5352
  const trackEvent = (0, import_react7.useCallback)(
5395
5353
  (eventName, eventParams = {}) => {
5396
- if (!isInitialized.current) {
5354
+ if (!isContainerInitialized) {
5397
5355
  console.warn(
5398
5356
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
5399
5357
  );
@@ -5420,7 +5378,7 @@ function useGTM(gtmId) {
5420
5378
  );
5421
5379
  const setUserProperty = (0, import_react7.useCallback)(
5422
5380
  (propertyName, value) => {
5423
- if (!isInitialized.current) {
5381
+ if (!isContainerInitialized) {
5424
5382
  console.warn(
5425
5383
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
5426
5384
  );
@@ -5446,22 +5404,78 @@ function useGTM(gtmId) {
5446
5404
  }
5447
5405
  window.gtag(command, ...args);
5448
5406
  },
5449
- [isGA4Allowed]
5407
+ []
5450
5408
  );
5451
- return {
5452
- trackEvent,
5453
- trackPageView,
5454
- setUserProperty,
5455
- directGtag,
5456
- addNoscriptIframe
5457
- };
5409
+ return { trackEvent, trackPageView, setUserProperty, directGtag };
5410
+ }
5411
+ function useGTM(gtmId) {
5412
+ const scriptRef = (0, import_react7.useRef)(null);
5413
+ const tracker = useGTMTracker();
5414
+ (0, import_react7.useEffect)(() => {
5415
+ if (!isGA4Allowed()) {
5416
+ console.warn(
5417
+ "useGTM: GA4 tracking is disabled or Trustware config not initialized."
5418
+ );
5419
+ return;
5420
+ }
5421
+ if (!gtmId || typeof gtmId !== "string") {
5422
+ console.error(
5423
+ "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
5424
+ );
5425
+ return;
5426
+ }
5427
+ if (isContainerInitialized) return;
5428
+ const alreadyLoaded = document.querySelector(
5429
+ `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
5430
+ );
5431
+ if (alreadyLoaded) {
5432
+ window.dataLayer = window.dataLayer || [];
5433
+ isContainerInitialized = true;
5434
+ return;
5435
+ }
5436
+ window.dataLayer = window.dataLayer || [];
5437
+ window.dataLayer.push({
5438
+ "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
5439
+ event: "gtm.js"
5440
+ });
5441
+ const firstScript = document.getElementsByTagName("script")[0];
5442
+ const script = document.createElement("script");
5443
+ script.async = true;
5444
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
5445
+ firstScript.parentNode?.insertBefore(script, firstScript);
5446
+ scriptRef.current = script;
5447
+ isContainerInitialized = true;
5448
+ return () => {
5449
+ if (scriptRef.current) {
5450
+ scriptRef.current.parentNode?.removeChild(scriptRef.current);
5451
+ scriptRef.current = null;
5452
+ }
5453
+ isContainerInitialized = false;
5454
+ };
5455
+ }, [gtmId]);
5456
+ const addNoscriptIframe = (0, import_react7.useCallback)(() => {
5457
+ if (!isGA4Allowed()) return;
5458
+ if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
5459
+ return;
5460
+ const noscript = document.createElement("noscript");
5461
+ const iframe = document.createElement("iframe");
5462
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
5463
+ iframe.height = "0";
5464
+ iframe.width = "0";
5465
+ iframe.style.display = "none";
5466
+ iframe.style.visibility = "hidden";
5467
+ noscript.appendChild(iframe);
5468
+ document.body.insertBefore(noscript, document.body.firstChild);
5469
+ }, [gtmId]);
5470
+ return { ...tracker, addNoscriptIframe };
5458
5471
  }
5459
- var import_react7;
5472
+ var import_react7, isContainerInitialized;
5460
5473
  var init_useGTM = __esm({
5461
5474
  "src/hooks/useGTM.ts"() {
5462
5475
  "use strict";
5463
5476
  import_react7 = require("react");
5464
5477
  init_core2();
5478
+ isContainerInitialized = false;
5465
5479
  }
5466
5480
  });
5467
5481
 
@@ -5487,7 +5501,7 @@ function useTransactionPolling() {
5487
5501
  return void 0;
5488
5502
  }
5489
5503
  })();
5490
- const { trackEvent } = useGTM(GTM_ID);
5504
+ const { trackEvent } = useGTMTracker();
5491
5505
  const [state, setState] = (0, import_react8.useState)({
5492
5506
  isPolling: false,
5493
5507
  apiStatus: null,
@@ -5587,8 +5601,21 @@ function useTransactionPolling() {
5587
5601
  pollCountRef.current += 1;
5588
5602
  const pollInterval = pollCountRef.current <= 10 ? FAST_POLL_INTERVAL_MS : NORMAL_POLL_INTERVAL_MS;
5589
5603
  pollingRef.current = setTimeout(poll, pollInterval);
5590
- } catch {
5604
+ } catch (err) {
5591
5605
  if (abortRef.current) return;
5606
+ if (isNotFoundError(err)) {
5607
+ clearPolling();
5608
+ const notFoundError = "Transaction session expired. Please try again.";
5609
+ setState((prev) => ({
5610
+ ...prev,
5611
+ isPolling: false,
5612
+ error: notFoundError
5613
+ }));
5614
+ setErrorMessage(notFoundError);
5615
+ setTransactionStatus("error");
5616
+ setCurrentStep("error");
5617
+ return;
5618
+ }
5592
5619
  const elapsed = Date.now() - startTimeRef.current;
5593
5620
  if (elapsed > POLL_TIMEOUT_MS) {
5594
5621
  clearPolling();
@@ -5725,10 +5752,10 @@ var init_useTransactionPolling = __esm({
5725
5752
  "use client";
5726
5753
  import_react8 = require("react");
5727
5754
  init_routes();
5755
+ init_http();
5728
5756
  init_DepositContext();
5729
5757
  init_provider();
5730
5758
  init_core2();
5731
- init_constants();
5732
5759
  init_hooks();
5733
5760
  FAST_POLL_INTERVAL_MS = 1500;
5734
5761
  NORMAL_POLL_INTERVAL_MS = 2500;
@@ -5810,6 +5837,20 @@ var init_eipWallets = __esm({
5810
5837
  "src/wallets/eipWallets.ts"() {
5811
5838
  "use strict";
5812
5839
  CHAIN_PARAMS = {
5840
+ 1: {
5841
+ chainIdHex: "0x1",
5842
+ chainName: "Ethereum",
5843
+ rpcUrls: ["https://eth.llamarpc.com"],
5844
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
5845
+ blockExplorerUrls: ["https://etherscan.io"]
5846
+ },
5847
+ 137: {
5848
+ chainIdHex: "0x89",
5849
+ chainName: "Polygon",
5850
+ rpcUrls: ["https://polygon-rpc.com"],
5851
+ nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
5852
+ blockExplorerUrls: ["https://polygonscan.com"]
5853
+ },
5813
5854
  8453: {
5814
5855
  chainIdHex: "0x2105",
5815
5856
  chainName: "Base",
@@ -9090,18 +9131,27 @@ async function waitForTxConfirmation(chainId, txHash) {
9090
9131
  }
9091
9132
  throw new Error("Timed out waiting for approval confirmation");
9092
9133
  }
9093
- async function ensureApprovals(w, approvals, fallbackChainId) {
9134
+ function requiredApprovalAmount(planAmountWei, routeAmountWei) {
9135
+ if (planAmountWei >= UNLIMITED_APPROVAL_FLOOR && routeAmountWei !== void 0 && routeAmountWei > 0n) {
9136
+ return routeAmountWei;
9137
+ }
9138
+ return planAmountWei;
9139
+ }
9140
+ function approvalSatisfied(currentAllowance, requiredWei) {
9141
+ if (requiredWei === 0n) return currentAllowance === 0n;
9142
+ return currentAllowance >= requiredWei;
9143
+ }
9144
+ async function ensureApprovals(w, approvals, fallbackChainId, intentId, routeAmountWei) {
9094
9145
  if (!approvals || approvals.length === 0) return;
9095
9146
  const owner = await w.getAddress();
9096
- for (const approval of approvals) {
9147
+ for (const [stepIndex, approval] of approvals.entries()) {
9097
9148
  const spender = approval.spender;
9098
9149
  const tokenAddress = approval.tokenAddress;
9099
9150
  const amount = approval.amount;
9100
9151
  if (!spender || !tokenAddress || !amount) continue;
9101
9152
  const chainId = approval.chainId || String(fallbackChainId ?? "");
9102
9153
  if (!chainId) continue;
9103
- const amountWei = BigInt(amount);
9104
- if (amountWei === 0n) continue;
9154
+ const amountWei = requiredApprovalAmount(BigInt(amount), routeAmountWei);
9105
9155
  let currentAllowance = 0n;
9106
9156
  try {
9107
9157
  const { allowance } = await getEVMAllowance({
@@ -9113,7 +9163,7 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
9113
9163
  currentAllowance = BigInt(allowance || "0");
9114
9164
  } catch {
9115
9165
  }
9116
- if (currentAllowance >= amountWei) continue;
9166
+ if (approvalSatisfied(currentAllowance, amountWei)) continue;
9117
9167
  const data = (0, import_viem2.encodeFunctionData)({
9118
9168
  abi: erc20ApproveAbi,
9119
9169
  functionName: "approve",
@@ -9125,6 +9175,10 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
9125
9175
  value: 0n,
9126
9176
  chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
9127
9177
  });
9178
+ if (intentId) {
9179
+ void submitStepReceipt(intentId, stepIndex, hash).catch(() => {
9180
+ });
9181
+ }
9128
9182
  await waitForTxConfirmation(chainId, hash);
9129
9183
  }
9130
9184
  }
@@ -9134,7 +9188,7 @@ function isUserRejected(e2) {
9134
9188
  const msg = String(e2?.message || e2)?.toLowerCase?.() || "";
9135
9189
  return msg.includes("user rejected") || msg.includes("user denied");
9136
9190
  }
9137
- async function sendRouteTransaction(b, fallbackChainId) {
9191
+ async function sendRouteTransaction(b, fallbackChainId, options) {
9138
9192
  const w = walletManager.wallet;
9139
9193
  if (!w) throw new Error("Trustware.wallet not configured");
9140
9194
  const txReq = b.txReq;
@@ -9161,11 +9215,13 @@ async function sendRouteTransaction(b, fallbackChainId) {
9161
9215
  }
9162
9216
  }
9163
9217
  }
9164
- if (!validatedSponsorship) {
9218
+ if (!validatedSponsorship && !options?.approvalsEnsured) {
9165
9219
  await ensureApprovals(
9166
9220
  w,
9167
9221
  b.route?.execution?.approvals,
9168
- Number.isFinite(target) ? target : void 0
9222
+ Number.isFinite(target) ? target : void 0,
9223
+ b.intentId,
9224
+ BigInt(b.route?.estimate?.fromAmount ?? "0")
9169
9225
  );
9170
9226
  }
9171
9227
  if (w.type === "eip1193") {
@@ -9264,7 +9320,7 @@ async function runTopUp(params) {
9264
9320
  }
9265
9321
  }
9266
9322
  }
9267
- var import_viem2, erc20ApproveAbi;
9323
+ var import_viem2, erc20ApproveAbi, UNLIMITED_APPROVAL_FLOOR;
9268
9324
  var init_tx = __esm({
9269
9325
  "src/core/tx.ts"() {
9270
9326
  "use strict";
@@ -9275,6 +9331,7 @@ var init_tx = __esm({
9275
9331
  erc20ApproveAbi = (0, import_viem2.parseAbi)([
9276
9332
  "function approve(address spender, uint256 amount) returns (bool)"
9277
9333
  ]);
9334
+ UNLIMITED_APPROVAL_FLOOR = 1n << 255n;
9278
9335
  }
9279
9336
  });
9280
9337
 
@@ -9420,6 +9477,7 @@ var init_core = __esm({
9420
9477
  buildRoute,
9421
9478
  buildDepositAddress,
9422
9479
  submitReceipt,
9480
+ submitStepReceipt,
9423
9481
  getStatus,
9424
9482
  pollStatus,
9425
9483
  getBalances,
@@ -31648,7 +31706,7 @@ function useTransactionActionModel({
31648
31706
  }) {
31649
31707
  const feeDataCacheRef = (0, import_react37.useRef)({});
31650
31708
  const { isSubmitting, submitTransaction } = useTransactionSubmit();
31651
- const { trackEvent } = useGTM(GTM_ID);
31709
+ const { trackEvent } = useGTMTracker();
31652
31710
  const destinationConfig = (() => {
31653
31711
  try {
31654
31712
  return Trustware.getConfig();
@@ -32084,7 +32142,6 @@ var init_useTransactionActionModel = __esm({
32084
32142
  init_chainHelpers();
32085
32143
  init_utils2();
32086
32144
  init_hooks();
32087
- init_constants();
32088
32145
  }
32089
32146
  });
32090
32147
 
@@ -33437,6 +33494,16 @@ async function waitForApprovalConfirmation(chainId, txHash) {
33437
33494
  }
33438
33495
  throw new Error("Timed out waiting for approval confirmation");
33439
33496
  }
33497
+ async function requireActiveAddress(wallet, plannedFor) {
33498
+ if (!wallet) throw new Error("Wallet not connected. Please reconnect.");
33499
+ const active = await wallet.getAddress();
33500
+ if (active?.toLowerCase() !== plannedFor?.toLowerCase()) {
33501
+ throw new Error(
33502
+ "Wallet account changed. Please review and confirm the swap again."
33503
+ );
33504
+ }
33505
+ return active;
33506
+ }
33440
33507
  function useSwapExecution(fromChain) {
33441
33508
  const [state, setState] = (0, import_react45.useState)({
33442
33509
  txStatus: "idle",
@@ -33493,7 +33560,15 @@ function useSwapExecution(fromChain) {
33493
33560
  if (tx.status === "bridging") {
33494
33561
  setState((p) => ({ ...p, txStatus: "bridging" }));
33495
33562
  }
33496
- } catch {
33563
+ } catch (err) {
33564
+ if (abortRef.current) return;
33565
+ if (isNotFoundError(err)) {
33566
+ clearPolling();
33567
+ const msg = "Transaction session expired. Please try again.";
33568
+ setState((p) => ({ ...p, txStatus: "error", errorMessage: msg }));
33569
+ onError(msg);
33570
+ return;
33571
+ }
33497
33572
  }
33498
33573
  if (abortRef.current) return;
33499
33574
  pollCountRef.current += 1;
@@ -33519,24 +33594,55 @@ function useSwapExecution(fromChain) {
33519
33594
  }
33520
33595
  const txReq = routeResult.txReq;
33521
33596
  const chainIdStr = String(txReq?.chainId ?? fromChain?.chainId ?? "");
33522
- const spender = txReq?.to ?? txReq?.target;
33523
33597
  const amountWei = BigInt(routeResult.route?.estimate?.fromAmount ?? "0");
33524
- if (!spender || !chainIdStr || amountWei === 0n) {
33598
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33599
+ const toCheck = plannedApprovals.length ? plannedApprovals.flatMap((a) => {
33600
+ const token = a.tokenAddress ?? fromTokenAddress;
33601
+ const required = requiredApprovalAmount(
33602
+ BigInt(a.amount || "0"),
33603
+ amountWei
33604
+ );
33605
+ if (!token || !a.spender) return [];
33606
+ return [
33607
+ {
33608
+ chainId: a.chainId || chainIdStr,
33609
+ token,
33610
+ spender: a.spender,
33611
+ required
33612
+ }
33613
+ ];
33614
+ }) : (() => {
33615
+ const spender = txReq?.to ?? txReq?.target;
33616
+ if (!spender) return [];
33617
+ return [
33618
+ {
33619
+ chainId: chainIdStr,
33620
+ token: fromTokenAddress,
33621
+ spender,
33622
+ required: amountWei
33623
+ }
33624
+ ];
33625
+ })();
33626
+ if (toCheck.length === 0 || !chainIdStr || amountWei === 0n) {
33525
33627
  setState((p) => ({ ...p, allowanceStatus: "unknown" }));
33526
33628
  return;
33527
33629
  }
33528
33630
  setState((p) => ({ ...p, allowanceStatus: "checking" }));
33529
33631
  try {
33530
- const { allowance } = await getEVMAllowance({
33531
- chainId: chainIdStr,
33532
- tokenAddress: fromTokenAddress,
33533
- ownerAddress: walletAddress,
33534
- spenderAddress: spender
33535
- });
33536
- const allowanceWei = BigInt(allowance || "0");
33632
+ const results = await Promise.all(
33633
+ toCheck.map(async (c) => {
33634
+ const { allowance } = await getEVMAllowance({
33635
+ chainId: c.chainId,
33636
+ tokenAddress: c.token,
33637
+ ownerAddress: walletAddress,
33638
+ spenderAddress: c.spender
33639
+ });
33640
+ return approvalSatisfied(BigInt(allowance || "0"), c.required);
33641
+ })
33642
+ );
33537
33643
  setState((p) => ({
33538
33644
  ...p,
33539
- allowanceStatus: allowanceWei >= amountWei ? "sufficient" : "needed"
33645
+ allowanceStatus: results.every(Boolean) ? "sufficient" : "needed"
33540
33646
  }));
33541
33647
  } catch {
33542
33648
  setState((p) => ({ ...p, allowanceStatus: "needed" }));
@@ -33640,19 +33746,49 @@ function useSwapExecution(fromChain) {
33640
33746
  }
33641
33747
  }
33642
33748
  try {
33643
- if (!isNative && walletAddress && spender && chainIdStr && fromTokenAddress) {
33749
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33750
+ const requiredApprovals = plannedApprovals.length ? plannedApprovals.flatMap((a, index) => {
33751
+ const token = a.tokenAddress ?? fromTokenAddress;
33752
+ const approvalSpender = a.spender;
33753
+ if (!token || !approvalSpender) return [];
33754
+ const amountWei = requiredApprovalAmount(
33755
+ BigInt(a.amount || "0"),
33756
+ fromAmountWei
33757
+ );
33758
+ return [
33759
+ {
33760
+ stepIndex: index,
33761
+ token,
33762
+ spender: approvalSpender,
33763
+ amountWei,
33764
+ chainId: a.chainId || chainIdStr
33765
+ }
33766
+ ];
33767
+ }) : spender && fromTokenAddress ? [
33768
+ {
33769
+ stepIndex: null,
33770
+ token: fromTokenAddress,
33771
+ spender,
33772
+ amountWei: fromAmountWei,
33773
+ chainId: chainIdStr
33774
+ }
33775
+ ] : [];
33776
+ const ownsApprovals = !isNative && !!walletAddress && !!chainIdStr;
33777
+ const activeAddress = ownsApprovals ? await requireActiveAddress(wallet, walletAddress) : void 0;
33778
+ for (const required of requiredApprovals) {
33779
+ if (!ownsApprovals) break;
33644
33780
  let allowanceWei = 0n;
33645
33781
  try {
33646
33782
  const { allowance } = await getEVMAllowance({
33647
- chainId: chainIdStr,
33648
- tokenAddress: fromTokenAddress,
33649
- ownerAddress: walletAddress,
33650
- spenderAddress: spender
33783
+ chainId: required.chainId,
33784
+ tokenAddress: required.token,
33785
+ ownerAddress: activeAddress,
33786
+ spenderAddress: required.spender
33651
33787
  });
33652
33788
  allowanceWei = BigInt(allowance || "0");
33653
33789
  } catch {
33654
33790
  }
33655
- if (allowanceWei < fromAmountWei) {
33791
+ if (!approvalSatisfied(allowanceWei, required.amountWei)) {
33656
33792
  setState((p) => ({ ...p, txStatus: "approving" }));
33657
33793
  if (!wallet || wallet.ecosystem !== "evm") {
33658
33794
  throw new Error("EVM wallet required for token approval");
@@ -33660,7 +33796,7 @@ function useSwapExecution(fromChain) {
33660
33796
  if (!chainIdStr || chainIdStr === "0") {
33661
33797
  throw new Error("Invalid chain ID for token approval");
33662
33798
  }
33663
- const targetChain = Number(txReq.chainId ?? fromChain?.chainId);
33799
+ const targetChain = Number(required.chainId ?? txReq.chainId);
33664
33800
  if (Number.isFinite(targetChain)) {
33665
33801
  const current = await wallet.getChainId();
33666
33802
  if (current !== targetChain) {
@@ -33672,18 +33808,18 @@ function useSwapExecution(fromChain) {
33672
33808
  }
33673
33809
  const approveAmount = maxApproval ? BigInt(
33674
33810
  "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
33675
- ) : fromAmountWei;
33811
+ ) : required.amountWei;
33676
33812
  const data = (0, import_viem43.encodeFunctionData)({
33677
33813
  abi: import_viem43.erc20Abi,
33678
33814
  functionName: "approve",
33679
- args: [spender, approveAmount]
33815
+ args: [required.spender, approveAmount]
33680
33816
  });
33681
33817
  let approvalHash;
33682
33818
  if (wallet.type === "eip1193") {
33683
33819
  const from = await wallet.getAddress();
33684
33820
  const params = {
33685
33821
  from,
33686
- to: fromTokenAddress,
33822
+ to: required.token,
33687
33823
  data,
33688
33824
  value: "0x0"
33689
33825
  };
@@ -33696,14 +33832,22 @@ function useSwapExecution(fromChain) {
33696
33832
  });
33697
33833
  } else {
33698
33834
  const response = await wallet.sendTransaction({
33699
- to: fromTokenAddress,
33835
+ to: required.token,
33700
33836
  data,
33701
33837
  value: 0n,
33702
33838
  chainId: Number.isFinite(targetChain) ? targetChain : void 0
33703
33839
  });
33704
33840
  approvalHash = response.hash;
33705
33841
  }
33706
- await waitForApprovalConfirmation(chainIdStr, approvalHash);
33842
+ if (required.stepIndex !== null) {
33843
+ void submitStepReceipt(
33844
+ routeResult.intentId,
33845
+ required.stepIndex,
33846
+ approvalHash
33847
+ ).catch(() => {
33848
+ });
33849
+ }
33850
+ await waitForApprovalConfirmation(required.chainId, approvalHash);
33707
33851
  setState((p) => ({
33708
33852
  ...p,
33709
33853
  txStatus: "confirming",
@@ -33711,9 +33855,13 @@ function useSwapExecution(fromChain) {
33711
33855
  }));
33712
33856
  }
33713
33857
  }
33858
+ if (ownsApprovals) {
33859
+ await requireActiveAddress(wallet, walletAddress);
33860
+ }
33714
33861
  const hash = await Trustware.sendRouteTransaction(
33715
33862
  routeResult,
33716
- numericChainId
33863
+ numericChainId,
33864
+ { approvalsEnsured: ownsApprovals }
33717
33865
  );
33718
33866
  try {
33719
33867
  await submitReceipt(routeResult.intentId, hash);
@@ -33783,6 +33931,8 @@ var init_useSwapExecution = __esm({
33783
33931
  import_viem43 = require("viem");
33784
33932
  init_core2();
33785
33933
  init_routes();
33934
+ init_http();
33935
+ init_tx();
33786
33936
  init_sdkRpc();
33787
33937
  init_chainHelpers();
33788
33938
  FAST_POLL_MS = 1500;
@@ -39732,6 +39882,7 @@ function WidgetInner({
39732
39882
  const { resolvedTheme } = useDepositUi();
39733
39883
  const { status, revalidate, errors } = useTrustware();
39734
39884
  const [showConfirmDialog, setShowConfirmDialog] = (0, import_react51.useState)(false);
39885
+ useGTM(GTM_ID);
39735
39886
  const handleCloseRequest = (0, import_react51.useCallback)(() => {
39736
39887
  if (ACTIVE_TRANSACTION_STATUSES.includes(transactionStatus)) {
39737
39888
  setShowConfirmDialog(true);
@@ -39806,6 +39957,8 @@ var init_TrustwareWidgetV2 = __esm({
39806
39957
  init_provider();
39807
39958
  init_manager();
39808
39959
  init_useTrustwareConfig();
39960
+ init_hooks();
39961
+ init_constants();
39809
39962
  init_swap();
39810
39963
  import_jsx_runtime60 = require("react/jsx-runtime");
39811
39964
  widgetContentContainerStyle = {