@trustware/sdk-staging 1.1.10-staging.0 → 1.1.11-staging.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +54 -21
  2. package/dist/constants.cjs +1 -1
  3. package/dist/constants.mjs +1 -1
  4. package/dist/{core-BPLiD1UG.d.ts → core-B1WCJfDI.d.ts} +15 -2
  5. package/dist/{core-B7Ez-5-r.d.cts → core-CeNTuqPz.d.cts} +15 -2
  6. package/dist/core.cjs +365 -279
  7. package/dist/core.cjs.map +1 -1
  8. package/dist/core.d.cts +2 -2
  9. package/dist/core.d.ts +2 -2
  10. package/dist/core.mjs +363 -278
  11. package/dist/core.mjs.map +1 -1
  12. package/dist/index.cjs +375 -170
  13. package/dist/index.cjs.map +1 -1
  14. package/dist/index.d.cts +11 -5
  15. package/dist/index.d.ts +11 -5
  16. package/dist/index.mjs +373 -169
  17. package/dist/index.mjs.map +1 -1
  18. package/dist/{manager-B6NNV-E_.d.ts → manager-Bw8b1wSD.d.ts} +136 -21
  19. package/dist/{manager-BwjyFjjz.d.cts → manager-DNGk1YkR.d.cts} +136 -21
  20. package/dist/{metadata-BiTMMvlY.d.ts → metadata-C__KMeuz.d.ts} +1 -1
  21. package/dist/{metadata-HCflXcsF.d.cts → metadata-Dk4R8_-T.d.cts} +1 -1
  22. package/dist/smart-account.cjs +49 -44
  23. package/dist/smart-account.cjs.map +1 -1
  24. package/dist/smart-account.d.cts +17 -12
  25. package/dist/smart-account.d.ts +17 -12
  26. package/dist/smart-account.mjs +49 -44
  27. package/dist/smart-account.mjs.map +1 -1
  28. package/dist/wallet.cjs +54 -39
  29. package/dist/wallet.cjs.map +1 -1
  30. package/dist/wallet.d.cts +3 -3
  31. package/dist/wallet.d.ts +3 -3
  32. package/dist/wallet.mjs +54 -39
  33. package/dist/wallet.mjs.map +1 -1
  34. package/dist/widget.cjs +369 -170
  35. package/dist/widget.cjs.map +1 -1
  36. package/dist/widget.mjs +369 -169
  37. package/dist/widget.mjs.map +1 -1
  38. package/package.json +73 -5
package/dist/index.cjs CHANGED
@@ -47,18 +47,16 @@ var init_defaults = __esm({
47
47
  });
48
48
 
49
49
  // src/types/config.ts
50
- var DEFAULT_SLIPPAGE2, DEFAULT_AUTO_DETECT_PROVIDER2, DEFAULT_RETRY_CONFIG, DEFAULT_FEATURE_FLAGS;
50
+ var DEFAULT_SLIPPAGE2, DEFAULT_AUTO_DETECT_PROVIDER2, DEFAULT_RETRY_CONFIG, RATE_LIMIT_WAIT_BUDGET_MS, DEFAULT_FEATURE_FLAGS;
51
51
  var init_config = __esm({
52
52
  "src/types/config.ts"() {
53
53
  "use strict";
54
54
  DEFAULT_SLIPPAGE2 = 1;
55
55
  DEFAULT_AUTO_DETECT_PROVIDER2 = false;
56
56
  DEFAULT_RETRY_CONFIG = {
57
- autoRetry: true,
58
- maxRetries: 3,
59
- baseDelayMs: 1e3,
60
57
  approachingThreshold: 5
61
58
  };
59
+ RATE_LIMIT_WAIT_BUDGET_MS = 1e4;
62
60
  DEFAULT_FEATURE_FLAGS = {
63
61
  tokensPagination: true,
64
62
  balanceStreaming: false,
@@ -195,9 +193,6 @@ function resolveConfig(input) {
195
193
  const theme = input.theme ?? "system";
196
194
  const messages = deepMerge(DEFAULT_MESSAGES, input.messages);
197
195
  const retry = {
198
- autoRetry: input.retry?.autoRetry ?? DEFAULT_RETRY_CONFIG.autoRetry,
199
- maxRetries: input.retry?.maxRetries ?? DEFAULT_RETRY_CONFIG.maxRetries,
200
- baseDelayMs: input.retry?.baseDelayMs ?? DEFAULT_RETRY_CONFIG.baseDelayMs,
201
196
  approachingThreshold: input.retry?.approachingThreshold ?? DEFAULT_RETRY_CONFIG.approachingThreshold,
202
197
  onRateLimitInfo: input.retry?.onRateLimitInfo,
203
198
  onRateLimited: input.retry?.onRateLimited,
@@ -464,6 +459,20 @@ var init_eipWallets = __esm({
464
459
  "src/wallets/eipWallets.ts"() {
465
460
  "use strict";
466
461
  CHAIN_PARAMS = {
462
+ 1: {
463
+ chainIdHex: "0x1",
464
+ chainName: "Ethereum",
465
+ rpcUrls: ["https://eth.llamarpc.com"],
466
+ nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
467
+ blockExplorerUrls: ["https://etherscan.io"]
468
+ },
469
+ 137: {
470
+ chainIdHex: "0x89",
471
+ chainName: "Polygon",
472
+ rpcUrls: ["https://polygon-rpc.com"],
473
+ nativeCurrency: { name: "POL", symbol: "POL", decimals: 18 },
474
+ blockExplorerUrls: ["https://polygonscan.com"]
475
+ },
467
476
  8453: {
468
477
  chainIdHex: "0x2105",
469
478
  chainName: "Base",
@@ -495,7 +504,7 @@ var init_constants = __esm({
495
504
  "src/constants.ts"() {
496
505
  "use strict";
497
506
  SDK_NAME = "@trustware/sdk";
498
- SDK_VERSION = "1.1.10-staging.0";
507
+ SDK_VERSION = "1.1.11-staging.2";
499
508
  API_ROOT = "https://bv-staging-api.trustware.io";
500
509
  GTM_ID = "GTM-TZDGNCXB";
501
510
  API_PREFIX = "/api";
@@ -539,6 +548,9 @@ async function assertOK(r) {
539
548
  }
540
549
  throw new Error(`HTTP ${r.status}: ${msg}`);
541
550
  }
551
+ function isNotFoundError(err) {
552
+ return err instanceof Error && err.message.startsWith("HTTP 404");
553
+ }
542
554
  async function validateSdkAccess() {
543
555
  const r = await fetch(`${apiBase()}/sdk/validate`, {
544
556
  method: "GET",
@@ -579,50 +591,54 @@ function notifyRateLimitCallbacks(info, isRateLimited, retryCount) {
579
591
  retry.onRateLimitApproaching(info, retry.approachingThreshold);
580
592
  }
581
593
  }
582
- function calculateBackoffDelay(baseDelayMs, retryCount, retryAfter) {
583
- if (retryAfter && retryAfter > 0) {
584
- return retryAfter * 1e3;
594
+ function serverDirectedWaitMs(info) {
595
+ if (!info) return null;
596
+ if (typeof info.retryAfter === "number" && info.retryAfter > 0) {
597
+ return info.retryAfter * 1e3;
585
598
  }
586
- return baseDelayMs * Math.pow(2, retryCount);
599
+ if (typeof info.reset === "number" && info.reset > 0) {
600
+ const untilReset = info.reset * 1e3 - Date.now();
601
+ if (untilReset > 0) return untilReset;
602
+ }
603
+ return null;
587
604
  }
588
605
  function sleep(ms) {
589
606
  return new Promise((resolve) => setTimeout(resolve, ms));
590
607
  }
591
- async function rateLimitedFetch(url, options = {}) {
592
- const { skipRateLimit, ...fetchOptions } = options;
593
- const cfg = TrustwareConfigStore.get();
594
- if (!cfg.retry.autoRetry || skipRateLimit) {
595
- return fetch(url, fetchOptions);
596
- }
597
- const { maxRetries, baseDelayMs } = cfg.retry;
608
+ async function withRateLimitRetry(attempt) {
609
+ let waitedMs = 0;
598
610
  let retryCount = 0;
599
611
  while (true) {
600
- const response = await fetch(url, fetchOptions);
612
+ const response = await attempt();
601
613
  const rateLimitInfo = parseRateLimitHeaders(response);
602
- if (response.status === 429) {
614
+ if (response.status !== 429) {
603
615
  if (rateLimitInfo) {
604
- notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
616
+ notifyRateLimitCallbacks(rateLimitInfo, false, 0);
605
617
  }
606
- if (retryCount >= maxRetries) {
607
- throw new RateLimitError(
608
- rateLimitInfo || { limit: 0, remaining: 0, reset: 0 },
609
- true
610
- );
611
- }
612
- const delay = calculateBackoffDelay(
613
- baseDelayMs,
614
- retryCount,
615
- rateLimitInfo?.retryAfter
616
- );
617
- await sleep(delay);
618
- retryCount++;
619
- continue;
618
+ return response;
620
619
  }
621
620
  if (rateLimitInfo) {
622
- notifyRateLimitCallbacks(rateLimitInfo, false, 0);
621
+ notifyRateLimitCallbacks(rateLimitInfo, true, retryCount);
623
622
  }
624
- return response;
623
+ const waitMs = serverDirectedWaitMs(rateLimitInfo);
624
+ const info = rateLimitInfo || { limit: 0, remaining: 0, reset: 0 };
625
+ if (waitMs === null) {
626
+ throw new RateLimitError(info, true);
627
+ }
628
+ if (waitedMs + waitMs > RATE_LIMIT_WAIT_BUDGET_MS) {
629
+ throw new RateLimitError(info, false);
630
+ }
631
+ await sleep(waitMs);
632
+ waitedMs += waitMs;
633
+ retryCount++;
634
+ }
635
+ }
636
+ async function rateLimitedFetch(url, options = {}) {
637
+ const { skipRateLimit, ...fetchOptions } = options;
638
+ if (skipRateLimit) {
639
+ return fetch(url, fetchOptions);
625
640
  }
641
+ return withRateLimitRetry(() => fetch(url, fetchOptions));
626
642
  }
627
643
  var RateLimitError;
628
644
  var init_http = __esm({
@@ -630,9 +646,11 @@ var init_http = __esm({
630
646
  "use strict";
631
647
  init_constants();
632
648
  init_config2();
649
+ init_config();
633
650
  RateLimitError = class extends Error {
634
651
  constructor(info, retriesExhausted) {
635
- const message = retriesExhausted ? `Rate limit exceeded after max retries. Try again in ${info.retryAfter ?? Math.ceil((info.reset * 1e3 - Date.now()) / 1e3)} seconds.` : `Rate limit exceeded. Try again in ${info.retryAfter} seconds.`;
652
+ const seconds = info.retryAfter ?? (info.reset > 0 ? Math.max(0, Math.ceil((info.reset * 1e3 - Date.now()) / 1e3)) : null);
653
+ const message = seconds === null ? "Rate limit exceeded. The server did not say when to retry." : `Rate limit exceeded. Try again in ${seconds} seconds.`;
636
654
  super(message);
637
655
  this.name = "RateLimitError";
638
656
  this.rateLimitInfo = info;
@@ -4536,6 +4554,19 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress)
4536
4554
  const j = await r.json();
4537
4555
  return j.data;
4538
4556
  }
4557
+ async function submitStepReceipt(intentId, stepIndex, txHash) {
4558
+ const r = await rateLimitedFetch(
4559
+ `${apiBase()}/v1/route-intent/${intentId}/steps/${stepIndex}/receipt`,
4560
+ {
4561
+ method: "POST",
4562
+ headers: jsonHeaders({ "Idempotency-Key": txHash }),
4563
+ body: JSON.stringify({ txHash })
4564
+ }
4565
+ );
4566
+ await assertOK(r);
4567
+ const j = await r.json();
4568
+ return j.data;
4569
+ }
4539
4570
  async function getStatus(intentId) {
4540
4571
  const r = await rateLimitedFetch(
4541
4572
  `${apiBase()}/v1/route-intent/${intentId}/status`,
@@ -4545,7 +4576,18 @@ async function getStatus(intentId) {
4545
4576
  );
4546
4577
  await assertOK(r);
4547
4578
  const j = await r.json();
4548
- return j.data;
4579
+ return normalizeStatusPayload(j.data);
4580
+ }
4581
+ function normalizeStatusPayload(raw) {
4582
+ if (!raw || typeof raw !== "object") return raw;
4583
+ const wire = raw;
4584
+ const out = { ...wire };
4585
+ for (const [snake, camel] of Object.entries(STATUS_WIRE_TO_CAMEL)) {
4586
+ if (out[camel] !== void 0) continue;
4587
+ if (!(snake in wire)) continue;
4588
+ out[camel] = wire[snake];
4589
+ }
4590
+ return out;
4549
4591
  }
4550
4592
  async function pollStatus(intentId, { intervalMs = 2e3, timeoutMs = 5 * 6e4 } = {}) {
4551
4593
  const t0 = Date.now();
@@ -4556,12 +4598,39 @@ async function pollStatus(intentId, { intervalMs = 2e3, timeoutMs = 5 * 6e4 } =
4556
4598
  await new Promise((r) => setTimeout(r, intervalMs));
4557
4599
  }
4558
4600
  }
4601
+ var STATUS_WIRE_TO_CAMEL;
4559
4602
  var init_routes = __esm({
4560
4603
  "src/core/routes.ts"() {
4561
4604
  "use strict";
4562
4605
  init_http();
4563
4606
  init_store();
4564
4607
  init_address();
4608
+ STATUS_WIRE_TO_CAMEL = {
4609
+ intent_id: "intentId",
4610
+ from_address: "fromAddress",
4611
+ to_address: "toAddress",
4612
+ from_chain_id: "fromChainId",
4613
+ to_chain_id: "toChainId",
4614
+ source_tx_hash: "sourceTxHash",
4615
+ dest_tx_hash: "destTxHash",
4616
+ request_id: "requestId",
4617
+ provider_request_id: "providerRequestId",
4618
+ transaction_request: "transactionRequest",
4619
+ status_raw: "statusRaw",
4620
+ route_path: "routePath",
4621
+ route_status: "routeStatus",
4622
+ to_amount_wei: "toAmountWei",
4623
+ from_chain_block: "fromChainBlock",
4624
+ to_chain_block: "toChainBlock",
4625
+ from_chain_tx_url: "fromChainTxUrl",
4626
+ to_chain_tx_url: "toChainTxUrl",
4627
+ gas_status: "gasStatus",
4628
+ is_gmp_transaction: "isGMPTransaction",
4629
+ axelar_transaction_url: "axelarTransactionUrl",
4630
+ create_date: "createdDate",
4631
+ update_date: "updatedDate",
4632
+ time_spent_ms: "timeSpentMs"
4633
+ };
4565
4634
  }
4566
4635
  });
4567
4636
 
@@ -5110,7 +5179,7 @@ async function getBalances(chainRef, address, opts) {
5110
5179
  if (cached) return cached;
5111
5180
  }
5112
5181
  const url = `${apiBase()}/v1/data/wallets/${encodeURIComponent(chainKey)}/${trimmedAddress}/balances`;
5113
- const response = await fetch(url, {
5182
+ const response = await rateLimitedFetch(url, {
5114
5183
  method: "GET",
5115
5184
  credentials: "omit",
5116
5185
  headers: jsonHeaders()
@@ -5273,18 +5342,27 @@ async function waitForTxConfirmation(chainId, txHash) {
5273
5342
  }
5274
5343
  throw new Error("Timed out waiting for approval confirmation");
5275
5344
  }
5276
- async function ensureApprovals(w, approvals, fallbackChainId) {
5345
+ function requiredApprovalAmount(planAmountWei, routeAmountWei) {
5346
+ if (planAmountWei >= UNLIMITED_APPROVAL_FLOOR && routeAmountWei !== void 0 && routeAmountWei > 0n) {
5347
+ return routeAmountWei;
5348
+ }
5349
+ return planAmountWei;
5350
+ }
5351
+ function approvalSatisfied(currentAllowance, requiredWei) {
5352
+ if (requiredWei === 0n) return currentAllowance === 0n;
5353
+ return currentAllowance >= requiredWei;
5354
+ }
5355
+ async function ensureApprovals(w, approvals, fallbackChainId, intentId, routeAmountWei) {
5277
5356
  if (!approvals || approvals.length === 0) return;
5278
5357
  const owner = await w.getAddress();
5279
- for (const approval of approvals) {
5358
+ for (const [stepIndex, approval] of approvals.entries()) {
5280
5359
  const spender = approval.spender;
5281
5360
  const tokenAddress = approval.tokenAddress;
5282
5361
  const amount = approval.amount;
5283
5362
  if (!spender || !tokenAddress || !amount) continue;
5284
5363
  const chainId = approval.chainId || String(fallbackChainId ?? "");
5285
5364
  if (!chainId) continue;
5286
- const amountWei = BigInt(amount);
5287
- if (amountWei === 0n) continue;
5365
+ const amountWei = requiredApprovalAmount(BigInt(amount), routeAmountWei);
5288
5366
  let currentAllowance = 0n;
5289
5367
  try {
5290
5368
  const { allowance } = await getEVMAllowance({
@@ -5296,7 +5374,7 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
5296
5374
  currentAllowance = BigInt(allowance || "0");
5297
5375
  } catch {
5298
5376
  }
5299
- if (currentAllowance >= amountWei) continue;
5377
+ if (approvalSatisfied(currentAllowance, amountWei)) continue;
5300
5378
  const data = (0, import_viem2.encodeFunctionData)({
5301
5379
  abi: erc20ApproveAbi,
5302
5380
  functionName: "approve",
@@ -5308,6 +5386,10 @@ async function ensureApprovals(w, approvals, fallbackChainId) {
5308
5386
  value: 0n,
5309
5387
  chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
5310
5388
  });
5389
+ if (intentId) {
5390
+ void submitStepReceipt(intentId, stepIndex, hash).catch(() => {
5391
+ });
5392
+ }
5311
5393
  await waitForTxConfirmation(chainId, hash);
5312
5394
  }
5313
5395
  }
@@ -5317,7 +5399,7 @@ function isUserRejected(e2) {
5317
5399
  const msg = String(e2?.message || e2)?.toLowerCase?.() || "";
5318
5400
  return msg.includes("user rejected") || msg.includes("user denied");
5319
5401
  }
5320
- async function sendRouteTransaction(b, fallbackChainId) {
5402
+ async function sendRouteTransaction(b, fallbackChainId, options) {
5321
5403
  const w = walletManager.wallet;
5322
5404
  if (!w) throw new Error("Trustware.wallet not configured");
5323
5405
  const txReq = b.txReq;
@@ -5344,11 +5426,13 @@ async function sendRouteTransaction(b, fallbackChainId) {
5344
5426
  }
5345
5427
  }
5346
5428
  }
5347
- if (!validatedSponsorship) {
5429
+ if (!validatedSponsorship && !options?.approvalsEnsured) {
5348
5430
  await ensureApprovals(
5349
5431
  w,
5350
5432
  b.route?.execution?.approvals,
5351
- Number.isFinite(target) ? target : void 0
5433
+ Number.isFinite(target) ? target : void 0,
5434
+ b.intentId,
5435
+ BigInt(b.route?.estimate?.fromAmount ?? "0")
5352
5436
  );
5353
5437
  }
5354
5438
  if (w.type === "eip1193") {
@@ -5447,7 +5531,7 @@ async function runTopUp(params) {
5447
5531
  }
5448
5532
  }
5449
5533
  }
5450
- var import_viem2, erc20ApproveAbi;
5534
+ var import_viem2, erc20ApproveAbi, UNLIMITED_APPROVAL_FLOOR;
5451
5535
  var init_tx = __esm({
5452
5536
  "src/core/tx.ts"() {
5453
5537
  "use strict";
@@ -5458,6 +5542,7 @@ var init_tx = __esm({
5458
5542
  erc20ApproveAbi = (0, import_viem2.parseAbi)([
5459
5543
  "function approve(address spender, uint256 amount) returns (bool)"
5460
5544
  ]);
5545
+ UNLIMITED_APPROVAL_FLOOR = 1n << 255n;
5461
5546
  }
5462
5547
  });
5463
5548
 
@@ -7597,6 +7682,7 @@ var init_core = __esm({
7597
7682
  init_store();
7598
7683
  init_wallets();
7599
7684
  init_routes();
7685
+ init_routes();
7600
7686
  init_balances();
7601
7687
  init_tx();
7602
7688
  init_http();
@@ -7731,6 +7817,7 @@ var init_core = __esm({
7731
7817
  buildRoute,
7732
7818
  buildDepositAddress,
7733
7819
  submitReceipt,
7820
+ submitStepReceipt,
7734
7821
  getStatus,
7735
7822
  pollStatus,
7736
7823
  getBalances,
@@ -8198,12 +8285,9 @@ function useTrustwareConfig() {
8198
8285
  title: "Trustware SDK",
8199
8286
  description: "Seamlessly bridge assets across chains with Trustware."
8200
8287
  },
8201
- retry: {
8202
- autoRetry: true,
8203
- maxRetries: 3,
8204
- baseDelayMs: 1e3,
8205
- approachingThreshold: 5
8206
- },
8288
+ // Shared with the resolver rather than restated, so this placeholder
8289
+ // can't drift from the real defaults.
8290
+ retry: { ...DEFAULT_RETRY_CONFIG },
8207
8291
  features: {
8208
8292
  tokensPagination: true,
8209
8293
  balanceStreaming: false,
@@ -8230,6 +8314,7 @@ var init_useTrustwareConfig = __esm({
8230
8314
  "use strict";
8231
8315
  "use client";
8232
8316
  import_react10 = require("react");
8317
+ init_config();
8233
8318
  init_store();
8234
8319
  }
8235
8320
  });
@@ -8959,75 +9044,17 @@ var init_useTransactionSubmit = __esm({
8959
9044
  });
8960
9045
 
8961
9046
  // 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]);
9047
+ function isGA4Allowed() {
9048
+ try {
9049
+ return Trustware.getConfig().features.shouldAllowGA4;
9050
+ } catch {
9051
+ return false;
9052
+ }
9053
+ }
9054
+ function useGTMTracker() {
9028
9055
  const trackEvent = (0, import_react15.useCallback)(
9029
9056
  (eventName, eventParams = {}) => {
9030
- if (!isInitialized.current) {
9057
+ if (!isContainerInitialized) {
9031
9058
  console.warn(
9032
9059
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
9033
9060
  );
@@ -9054,7 +9081,7 @@ function useGTM(gtmId) {
9054
9081
  );
9055
9082
  const setUserProperty = (0, import_react15.useCallback)(
9056
9083
  (propertyName, value) => {
9057
- if (!isInitialized.current) {
9084
+ if (!isContainerInitialized) {
9058
9085
  console.warn(
9059
9086
  "useGTM: Not initialized. Ensure a valid GTM Container ID was provided."
9060
9087
  );
@@ -9080,22 +9107,78 @@ function useGTM(gtmId) {
9080
9107
  }
9081
9108
  window.gtag(command, ...args);
9082
9109
  },
9083
- [isGA4Allowed]
9110
+ []
9084
9111
  );
9085
- return {
9086
- trackEvent,
9087
- trackPageView,
9088
- setUserProperty,
9089
- directGtag,
9090
- addNoscriptIframe
9091
- };
9112
+ return { trackEvent, trackPageView, setUserProperty, directGtag };
9113
+ }
9114
+ function useGTM(gtmId) {
9115
+ const scriptRef = (0, import_react15.useRef)(null);
9116
+ const tracker = useGTMTracker();
9117
+ (0, import_react15.useEffect)(() => {
9118
+ if (!isGA4Allowed()) {
9119
+ console.warn(
9120
+ "useGTM: GA4 tracking is disabled or Trustware config not initialized."
9121
+ );
9122
+ return;
9123
+ }
9124
+ if (!gtmId || typeof gtmId !== "string") {
9125
+ console.error(
9126
+ "useGTM: A valid GTM Container ID is required (format: GTM-XXXXX)."
9127
+ );
9128
+ return;
9129
+ }
9130
+ if (isContainerInitialized) return;
9131
+ const alreadyLoaded = document.querySelector(
9132
+ `script[src*="googletagmanager.com/gtm.js?id=${gtmId}"]`
9133
+ );
9134
+ if (alreadyLoaded) {
9135
+ window.dataLayer = window.dataLayer || [];
9136
+ isContainerInitialized = true;
9137
+ return;
9138
+ }
9139
+ window.dataLayer = window.dataLayer || [];
9140
+ window.dataLayer.push({
9141
+ "gtm.start": (/* @__PURE__ */ new Date()).getTime(),
9142
+ event: "gtm.js"
9143
+ });
9144
+ const firstScript = document.getElementsByTagName("script")[0];
9145
+ const script = document.createElement("script");
9146
+ script.async = true;
9147
+ script.src = `https://www.googletagmanager.com/gtm.js?id=${gtmId}`;
9148
+ firstScript.parentNode?.insertBefore(script, firstScript);
9149
+ scriptRef.current = script;
9150
+ isContainerInitialized = true;
9151
+ return () => {
9152
+ if (scriptRef.current) {
9153
+ scriptRef.current.parentNode?.removeChild(scriptRef.current);
9154
+ scriptRef.current = null;
9155
+ }
9156
+ isContainerInitialized = false;
9157
+ };
9158
+ }, [gtmId]);
9159
+ const addNoscriptIframe = (0, import_react15.useCallback)(() => {
9160
+ if (!isGA4Allowed()) return;
9161
+ if (document.querySelector('iframe[src*="googletagmanager.com/ns.html"]'))
9162
+ return;
9163
+ const noscript = document.createElement("noscript");
9164
+ const iframe = document.createElement("iframe");
9165
+ iframe.src = `https://www.googletagmanager.com/ns.html?id=${gtmId}`;
9166
+ iframe.height = "0";
9167
+ iframe.width = "0";
9168
+ iframe.style.display = "none";
9169
+ iframe.style.visibility = "hidden";
9170
+ noscript.appendChild(iframe);
9171
+ document.body.insertBefore(noscript, document.body.firstChild);
9172
+ }, [gtmId]);
9173
+ return { ...tracker, addNoscriptIframe };
9092
9174
  }
9093
- var import_react15;
9175
+ var import_react15, isContainerInitialized;
9094
9176
  var init_useGTM = __esm({
9095
9177
  "src/hooks/useGTM.ts"() {
9096
9178
  "use strict";
9097
9179
  import_react15 = require("react");
9098
9180
  init_core2();
9181
+ isContainerInitialized = false;
9099
9182
  }
9100
9183
  });
9101
9184
 
@@ -9121,7 +9204,7 @@ function useTransactionPolling() {
9121
9204
  return void 0;
9122
9205
  }
9123
9206
  })();
9124
- const { trackEvent } = useGTM(GTM_ID);
9207
+ const { trackEvent } = useGTMTracker();
9125
9208
  const [state, setState] = (0, import_react16.useState)({
9126
9209
  isPolling: false,
9127
9210
  apiStatus: null,
@@ -9221,8 +9304,21 @@ function useTransactionPolling() {
9221
9304
  pollCountRef.current += 1;
9222
9305
  const pollInterval = pollCountRef.current <= 10 ? FAST_POLL_INTERVAL_MS : NORMAL_POLL_INTERVAL_MS;
9223
9306
  pollingRef.current = setTimeout(poll, pollInterval);
9224
- } catch {
9307
+ } catch (err) {
9225
9308
  if (abortRef.current) return;
9309
+ if (isNotFoundError(err)) {
9310
+ clearPolling();
9311
+ const notFoundError = "Transaction session expired. Please try again.";
9312
+ setState((prev) => ({
9313
+ ...prev,
9314
+ isPolling: false,
9315
+ error: notFoundError
9316
+ }));
9317
+ setErrorMessage(notFoundError);
9318
+ setTransactionStatus("error");
9319
+ setCurrentStep("error");
9320
+ return;
9321
+ }
9226
9322
  const elapsed = Date.now() - startTimeRef.current;
9227
9323
  if (elapsed > POLL_TIMEOUT_MS) {
9228
9324
  clearPolling();
@@ -9359,10 +9455,10 @@ var init_useTransactionPolling = __esm({
9359
9455
  "use client";
9360
9456
  import_react16 = require("react");
9361
9457
  init_routes();
9458
+ init_http();
9362
9459
  init_DepositContext();
9363
9460
  init_provider();
9364
9461
  init_core2();
9365
- init_constants();
9366
9462
  init_hooks();
9367
9463
  FAST_POLL_INTERVAL_MS = 1500;
9368
9464
  NORMAL_POLL_INTERVAL_MS = 2500;
@@ -30772,7 +30868,7 @@ var init_src = __esm({
30772
30868
  });
30773
30869
 
30774
30870
  // src/smart-account/client.ts
30775
- async function fetchWithTimeout(url, init) {
30871
+ async function fetchOnceWithTimeout(url, init) {
30776
30872
  const controller = new AbortController();
30777
30873
  const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
30778
30874
  try {
@@ -30793,6 +30889,9 @@ async function fetchWithTimeout(url, init) {
30793
30889
  clearTimeout(timer);
30794
30890
  }
30795
30891
  }
30892
+ async function fetchWithTimeout(url, init) {
30893
+ return withRateLimitRetry(() => fetchOnceWithTimeout(url, init));
30894
+ }
30796
30895
  function extractRevertHex(err) {
30797
30896
  if (typeof err.data === "string" && err.data.startsWith("0x"))
30798
30897
  return err.data;
@@ -31285,7 +31384,7 @@ async function estimateRelayFeeInToken(valueWei, fromAmountWei, fromAmountUSD, c
31285
31384
  tokenUnitsPerDollar = Number(fromAmountWei) / fromUSD;
31286
31385
  } else if (fromToken && fromDecimals !== void 0) {
31287
31386
  try {
31288
- const resp = await fetch(
31387
+ const resp = await rateLimitedFetch(
31289
31388
  `${apiBase()}/v1/price/token?chainId=${cid}&address=${fromToken}`,
31290
31389
  { headers: jsonHeaders() }
31291
31390
  );
@@ -31301,9 +31400,10 @@ async function estimateRelayFeeInToken(valueWei, fromAmountWei, fromAmountUSD, c
31301
31400
  return 0n;
31302
31401
  }
31303
31402
  try {
31304
- const resp = await fetch(`${apiBase()}/v1/price/native?chainId=${cid}`, {
31305
- headers: jsonHeaders()
31306
- });
31403
+ const resp = await rateLimitedFetch(
31404
+ `${apiBase()}/v1/price/native?chainId=${cid}`,
31405
+ { headers: jsonHeaders() }
31406
+ );
31307
31407
  if (!resp.ok) throw new Error(`native price HTTP ${resp.status}`);
31308
31408
  const json = await resp.json();
31309
31409
  const ethPriceUSD = parseFloat(json.data?.priceUSD ?? "0");
@@ -31810,7 +31910,7 @@ function useTransactionActionModel({
31810
31910
  }) {
31811
31911
  const feeDataCacheRef = (0, import_react37.useRef)({});
31812
31912
  const { isSubmitting, submitTransaction } = useTransactionSubmit();
31813
- const { trackEvent } = useGTM(GTM_ID);
31913
+ const { trackEvent } = useGTMTracker();
31814
31914
  const destinationConfig = (() => {
31815
31915
  try {
31816
31916
  return Trustware.getConfig();
@@ -32246,7 +32346,6 @@ var init_useTransactionActionModel = __esm({
32246
32346
  init_chainHelpers();
32247
32347
  init_utils();
32248
32348
  init_hooks();
32249
- init_constants();
32250
32349
  }
32251
32350
  });
32252
32351
 
@@ -33599,6 +33698,16 @@ async function waitForApprovalConfirmation(chainId, txHash) {
33599
33698
  }
33600
33699
  throw new Error("Timed out waiting for approval confirmation");
33601
33700
  }
33701
+ async function requireActiveAddress(wallet, plannedFor) {
33702
+ if (!wallet) throw new Error("Wallet not connected. Please reconnect.");
33703
+ const active = await wallet.getAddress();
33704
+ if (active?.toLowerCase() !== plannedFor?.toLowerCase()) {
33705
+ throw new Error(
33706
+ "Wallet account changed. Please review and confirm the swap again."
33707
+ );
33708
+ }
33709
+ return active;
33710
+ }
33602
33711
  function useSwapExecution(fromChain) {
33603
33712
  const [state, setState] = (0, import_react45.useState)({
33604
33713
  txStatus: "idle",
@@ -33655,7 +33764,15 @@ function useSwapExecution(fromChain) {
33655
33764
  if (tx.status === "bridging") {
33656
33765
  setState((p) => ({ ...p, txStatus: "bridging" }));
33657
33766
  }
33658
- } catch {
33767
+ } catch (err) {
33768
+ if (abortRef.current) return;
33769
+ if (isNotFoundError(err)) {
33770
+ clearPolling();
33771
+ const msg = "Transaction session expired. Please try again.";
33772
+ setState((p) => ({ ...p, txStatus: "error", errorMessage: msg }));
33773
+ onError(msg);
33774
+ return;
33775
+ }
33659
33776
  }
33660
33777
  if (abortRef.current) return;
33661
33778
  pollCountRef.current += 1;
@@ -33681,24 +33798,55 @@ function useSwapExecution(fromChain) {
33681
33798
  }
33682
33799
  const txReq = routeResult.txReq;
33683
33800
  const chainIdStr = String(txReq?.chainId ?? fromChain?.chainId ?? "");
33684
- const spender = txReq?.to ?? txReq?.target;
33685
33801
  const amountWei = BigInt(routeResult.route?.estimate?.fromAmount ?? "0");
33686
- if (!spender || !chainIdStr || amountWei === 0n) {
33802
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33803
+ const toCheck = plannedApprovals.length ? plannedApprovals.flatMap((a) => {
33804
+ const token = a.tokenAddress ?? fromTokenAddress;
33805
+ const required = requiredApprovalAmount(
33806
+ BigInt(a.amount || "0"),
33807
+ amountWei
33808
+ );
33809
+ if (!token || !a.spender) return [];
33810
+ return [
33811
+ {
33812
+ chainId: a.chainId || chainIdStr,
33813
+ token,
33814
+ spender: a.spender,
33815
+ required
33816
+ }
33817
+ ];
33818
+ }) : (() => {
33819
+ const spender = txReq?.to ?? txReq?.target;
33820
+ if (!spender) return [];
33821
+ return [
33822
+ {
33823
+ chainId: chainIdStr,
33824
+ token: fromTokenAddress,
33825
+ spender,
33826
+ required: amountWei
33827
+ }
33828
+ ];
33829
+ })();
33830
+ if (toCheck.length === 0 || !chainIdStr || amountWei === 0n) {
33687
33831
  setState((p) => ({ ...p, allowanceStatus: "unknown" }));
33688
33832
  return;
33689
33833
  }
33690
33834
  setState((p) => ({ ...p, allowanceStatus: "checking" }));
33691
33835
  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");
33836
+ const results = await Promise.all(
33837
+ toCheck.map(async (c) => {
33838
+ const { allowance } = await getEVMAllowance({
33839
+ chainId: c.chainId,
33840
+ tokenAddress: c.token,
33841
+ ownerAddress: walletAddress,
33842
+ spenderAddress: c.spender
33843
+ });
33844
+ return approvalSatisfied(BigInt(allowance || "0"), c.required);
33845
+ })
33846
+ );
33699
33847
  setState((p) => ({
33700
33848
  ...p,
33701
- allowanceStatus: allowanceWei >= amountWei ? "sufficient" : "needed"
33849
+ allowanceStatus: results.every(Boolean) ? "sufficient" : "needed"
33702
33850
  }));
33703
33851
  } catch {
33704
33852
  setState((p) => ({ ...p, allowanceStatus: "needed" }));
@@ -33802,19 +33950,49 @@ function useSwapExecution(fromChain) {
33802
33950
  }
33803
33951
  }
33804
33952
  try {
33805
- if (!isNative && walletAddress && spender && chainIdStr && fromTokenAddress) {
33953
+ const plannedApprovals = routeResult.route?.execution?.approvals ?? [];
33954
+ const requiredApprovals = plannedApprovals.length ? plannedApprovals.flatMap((a, index) => {
33955
+ const token = a.tokenAddress ?? fromTokenAddress;
33956
+ const approvalSpender = a.spender;
33957
+ if (!token || !approvalSpender) return [];
33958
+ const amountWei = requiredApprovalAmount(
33959
+ BigInt(a.amount || "0"),
33960
+ fromAmountWei
33961
+ );
33962
+ return [
33963
+ {
33964
+ stepIndex: index,
33965
+ token,
33966
+ spender: approvalSpender,
33967
+ amountWei,
33968
+ chainId: a.chainId || chainIdStr
33969
+ }
33970
+ ];
33971
+ }) : spender && fromTokenAddress ? [
33972
+ {
33973
+ stepIndex: null,
33974
+ token: fromTokenAddress,
33975
+ spender,
33976
+ amountWei: fromAmountWei,
33977
+ chainId: chainIdStr
33978
+ }
33979
+ ] : [];
33980
+ const ownsApprovals = !isNative && !!walletAddress && !!chainIdStr;
33981
+ const activeAddress = ownsApprovals ? await requireActiveAddress(wallet, walletAddress) : void 0;
33982
+ for (const required of requiredApprovals) {
33983
+ if (!ownsApprovals) break;
33806
33984
  let allowanceWei = 0n;
33807
33985
  try {
33808
33986
  const { allowance } = await getEVMAllowance({
33809
- chainId: chainIdStr,
33810
- tokenAddress: fromTokenAddress,
33811
- ownerAddress: walletAddress,
33812
- spenderAddress: spender
33987
+ chainId: required.chainId,
33988
+ tokenAddress: required.token,
33989
+ ownerAddress: activeAddress,
33990
+ spenderAddress: required.spender
33813
33991
  });
33814
33992
  allowanceWei = BigInt(allowance || "0");
33815
33993
  } catch {
33816
33994
  }
33817
- if (allowanceWei < fromAmountWei) {
33995
+ if (!approvalSatisfied(allowanceWei, required.amountWei)) {
33818
33996
  setState((p) => ({ ...p, txStatus: "approving" }));
33819
33997
  if (!wallet || wallet.ecosystem !== "evm") {
33820
33998
  throw new Error("EVM wallet required for token approval");
@@ -33822,7 +34000,7 @@ function useSwapExecution(fromChain) {
33822
34000
  if (!chainIdStr || chainIdStr === "0") {
33823
34001
  throw new Error("Invalid chain ID for token approval");
33824
34002
  }
33825
- const targetChain = Number(txReq.chainId ?? fromChain?.chainId);
34003
+ const targetChain = Number(required.chainId ?? txReq.chainId);
33826
34004
  if (Number.isFinite(targetChain)) {
33827
34005
  const current = await wallet.getChainId();
33828
34006
  if (current !== targetChain) {
@@ -33834,18 +34012,18 @@ function useSwapExecution(fromChain) {
33834
34012
  }
33835
34013
  const approveAmount = maxApproval ? BigInt(
33836
34014
  "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
33837
- ) : fromAmountWei;
34015
+ ) : required.amountWei;
33838
34016
  const data = (0, import_viem43.encodeFunctionData)({
33839
34017
  abi: import_viem43.erc20Abi,
33840
34018
  functionName: "approve",
33841
- args: [spender, approveAmount]
34019
+ args: [required.spender, approveAmount]
33842
34020
  });
33843
34021
  let approvalHash;
33844
34022
  if (wallet.type === "eip1193") {
33845
34023
  const from = await wallet.getAddress();
33846
34024
  const params = {
33847
34025
  from,
33848
- to: fromTokenAddress,
34026
+ to: required.token,
33849
34027
  data,
33850
34028
  value: "0x0"
33851
34029
  };
@@ -33858,14 +34036,22 @@ function useSwapExecution(fromChain) {
33858
34036
  });
33859
34037
  } else {
33860
34038
  const response = await wallet.sendTransaction({
33861
- to: fromTokenAddress,
34039
+ to: required.token,
33862
34040
  data,
33863
34041
  value: 0n,
33864
34042
  chainId: Number.isFinite(targetChain) ? targetChain : void 0
33865
34043
  });
33866
34044
  approvalHash = response.hash;
33867
34045
  }
33868
- await waitForApprovalConfirmation(chainIdStr, approvalHash);
34046
+ if (required.stepIndex !== null) {
34047
+ void submitStepReceipt(
34048
+ routeResult.intentId,
34049
+ required.stepIndex,
34050
+ approvalHash
34051
+ ).catch(() => {
34052
+ });
34053
+ }
34054
+ await waitForApprovalConfirmation(required.chainId, approvalHash);
33869
34055
  setState((p) => ({
33870
34056
  ...p,
33871
34057
  txStatus: "confirming",
@@ -33873,9 +34059,13 @@ function useSwapExecution(fromChain) {
33873
34059
  }));
33874
34060
  }
33875
34061
  }
34062
+ if (ownsApprovals) {
34063
+ await requireActiveAddress(wallet, walletAddress);
34064
+ }
33876
34065
  const hash = await Trustware.sendRouteTransaction(
33877
34066
  routeResult,
33878
- numericChainId
34067
+ numericChainId,
34068
+ { approvalsEnsured: ownsApprovals }
33879
34069
  );
33880
34070
  try {
33881
34071
  await submitReceipt(routeResult.intentId, hash);
@@ -33945,6 +34135,8 @@ var init_useSwapExecution = __esm({
33945
34135
  import_viem43 = require("viem");
33946
34136
  init_core2();
33947
34137
  init_routes();
34138
+ init_http();
34139
+ init_tx();
33948
34140
  init_sdkRpc();
33949
34141
  init_chainHelpers();
33950
34142
  FAST_POLL_MS = 1500;
@@ -33956,9 +34148,14 @@ var init_useSwapExecution = __esm({
33956
34148
 
33957
34149
  // src/core/forex.ts
33958
34150
  async function fetchForexRates(base2 = "USD") {
33959
- const r = await fetch(`${apiBase()}/v1/forex?base=${base2}`, {
33960
- headers: jsonHeaders()
33961
- });
34151
+ let r;
34152
+ try {
34153
+ r = await rateLimitedFetch(`${apiBase()}/v1/forex?base=${base2}`, {
34154
+ headers: jsonHeaders()
34155
+ });
34156
+ } catch {
34157
+ return {};
34158
+ }
33962
34159
  if (!r.ok) return {};
33963
34160
  const j = await r.json();
33964
34161
  const rates = j?.data?.rates ?? j?.rates ?? j?.data ?? {};
@@ -39894,6 +40091,7 @@ function WidgetInner({
39894
40091
  const { resolvedTheme } = useDepositUi();
39895
40092
  const { status, revalidate, errors } = useTrustware();
39896
40093
  const [showConfirmDialog, setShowConfirmDialog] = (0, import_react51.useState)(false);
40094
+ useGTM(GTM_ID);
39897
40095
  const handleCloseRequest = (0, import_react51.useCallback)(() => {
39898
40096
  if (ACTIVE_TRANSACTION_STATUSES.includes(transactionStatus)) {
39899
40097
  setShowConfirmDialog(true);
@@ -39968,6 +40166,8 @@ var init_TrustwareWidgetV2 = __esm({
39968
40166
  init_provider();
39969
40167
  init_manager();
39970
40168
  init_useTrustwareConfig();
40169
+ init_hooks();
40170
+ init_constants();
39971
40171
  init_swap();
39972
40172
  import_jsx_runtime60 = require("react/jsx-runtime");
39973
40173
  widgetContentContainerStyle = {
@@ -40115,6 +40315,7 @@ __export(index_exports, {
40115
40315
  GTM_ID: () => GTM_ID,
40116
40316
  IdentityStore: () => IdentityStore,
40117
40317
  POPULAR_ORDER: () => POPULAR_ORDER,
40318
+ RATE_LIMIT_WAIT_BUDGET_MS: () => RATE_LIMIT_WAIT_BUDGET_MS,
40118
40319
  RateLimitError: () => RateLimitError,
40119
40320
  SDK_NAME: () => SDK_NAME,
40120
40321
  SDK_VERSION: () => SDK_VERSION,
@@ -40124,6 +40325,7 @@ __export(index_exports, {
40124
40325
  TrustwareWidget: () => TrustwareWidgetV2,
40125
40326
  WALLETCONNECT_PROJECT_ID: () => WALLETCONNECT_PROJECT_ID,
40126
40327
  WALLETS: () => WALLETS,
40328
+ assertValidPostHook: () => assertValidPostHook,
40127
40329
  buildWalletIdentityAddress: () => buildWalletIdentityAddress,
40128
40330
  connectDetectedWallet: () => connectDetectedWallet,
40129
40331
  createWalletIdentity: () => createWalletIdentity,
@@ -40152,6 +40354,7 @@ var init_index = __esm({
40152
40354
  "src/index.ts"() {
40153
40355
  init_core2();
40154
40356
  init_http();
40357
+ init_core2();
40155
40358
  init_useWalletTokenState();
40156
40359
  init_wallets();
40157
40360
  init_widget();
@@ -40177,6 +40380,7 @@ init_index();
40177
40380
  GTM_ID,
40178
40381
  IdentityStore,
40179
40382
  POPULAR_ORDER,
40383
+ RATE_LIMIT_WAIT_BUDGET_MS,
40180
40384
  RateLimitError,
40181
40385
  SDK_NAME,
40182
40386
  SDK_VERSION,
@@ -40186,6 +40390,7 @@ init_index();
40186
40390
  TrustwareWidget,
40187
40391
  WALLETCONNECT_PROJECT_ID,
40188
40392
  WALLETS,
40393
+ assertValidPostHook,
40189
40394
  buildWalletIdentityAddress,
40190
40395
  connectDetectedWallet,
40191
40396
  createWalletIdentity,