@trustware/sdk-staging 1.1.9-staging.6 → 1.1.10-staging.0

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 (40) hide show
  1. package/LICENSE +5 -4
  2. package/README.md +32 -1
  3. package/THIRD_PARTY_NOTICES.md +118 -0
  4. package/dist/constants.cjs +1 -1
  5. package/dist/constants.mjs +1 -1
  6. package/dist/{core-BTPkApRH.d.cts → core-B7Ez-5-r.d.cts} +3 -2
  7. package/dist/{core-2oZuxC1J.d.ts → core-BPLiD1UG.d.ts} +3 -2
  8. package/dist/core.cjs +246 -48
  9. package/dist/core.cjs.map +1 -1
  10. package/dist/core.d.cts +2 -2
  11. package/dist/core.d.ts +2 -2
  12. package/dist/core.mjs +247 -48
  13. package/dist/core.mjs.map +1 -1
  14. package/dist/index.cjs +300 -76
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.d.cts +5 -5
  17. package/dist/index.d.ts +5 -5
  18. package/dist/index.mjs +325 -103
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/{manager-BMO1O-cW.d.ts → manager-B6NNV-E_.d.ts} +129 -18
  21. package/dist/{manager-BZwbtOyf.d.cts → manager-BwjyFjjz.d.cts} +129 -18
  22. package/dist/{detect-B8xXLwHK.d.ts → metadata-BiTMMvlY.d.ts} +5 -2
  23. package/dist/{detect-C8xpZRrL.d.cts → metadata-HCflXcsF.d.cts} +5 -2
  24. package/dist/smart-account.cjs +117 -39
  25. package/dist/smart-account.cjs.map +1 -1
  26. package/dist/smart-account.d.cts +235 -222
  27. package/dist/smart-account.d.ts +235 -222
  28. package/dist/smart-account.mjs +117 -39
  29. package/dist/smart-account.mjs.map +1 -1
  30. package/dist/wallet.cjs +113 -36
  31. package/dist/wallet.cjs.map +1 -1
  32. package/dist/wallet.d.cts +4 -7
  33. package/dist/wallet.d.ts +4 -7
  34. package/dist/wallet.mjs +113 -36
  35. package/dist/wallet.mjs.map +1 -1
  36. package/dist/widget.cjs +239 -54
  37. package/dist/widget.cjs.map +1 -1
  38. package/dist/widget.mjs +267 -81
  39. package/dist/widget.mjs.map +1 -1
  40. package/package.json +3 -2
package/dist/core.cjs CHANGED
@@ -75,7 +75,7 @@ var init_constants = __esm({
75
75
  "src/constants.ts"() {
76
76
  "use strict";
77
77
  SDK_NAME = "@trustware/sdk";
78
- SDK_VERSION = "1.1.9-staging.6";
78
+ SDK_VERSION = "1.1.10-staging.0";
79
79
  API_ROOT = "https://bv-staging-api.trustware.io";
80
80
  API_PREFIX = "/api";
81
81
  WALLETCONNECT_PROJECT_ID = "72ea74c400f5111d43aea638d7d83a24";
@@ -284,7 +284,9 @@ var init_chains = __esm({
284
284
  btc: "bitcoin",
285
285
  bitcoin: "bitcoin",
286
286
  sei: "cosmos",
287
- "pacific-1": "cosmos"
287
+ "pacific-1": "cosmos",
288
+ nibiru: "cosmos",
289
+ "cataclysm-1": "cosmos"
288
290
  };
289
291
  }
290
292
  });
@@ -1480,16 +1482,23 @@ function validateEvmAddress(address) {
1480
1482
  }
1481
1483
  return { isValid: true };
1482
1484
  }
1483
- function validateSeiAddress(address) {
1485
+ function resolveCosmosBech32Prefix(chain) {
1486
+ const chainDef = typeof chain === "object" && chain ? chain : void 0;
1487
+ const identifier = chainDef?.networkIdentifier ?? chainDef?.chainId ?? chainDef?.id ?? (typeof chain === "string" ? chain : void 0);
1488
+ const normalized = String(identifier ?? "").trim().toLowerCase();
1489
+ return COSMOS_BECH32_PREFIX_BY_CHAIN_ID[normalized] ?? "sei";
1490
+ }
1491
+ function validateCosmosAddress(address, chain) {
1484
1492
  const trimmed = address.trim();
1485
- if ((0, import_viem.isAddress)(trimmed)) {
1493
+ const prefix = resolveCosmosBech32Prefix(chain);
1494
+ if (prefix === "sei" && (0, import_viem.isAddress)(trimmed)) {
1486
1495
  return { isValid: true };
1487
1496
  }
1488
- const result = validateBech32LikeAddress(trimmed, "sei");
1497
+ const result = validateBech32LikeAddress(trimmed, prefix);
1489
1498
  if (result.isValid) return result;
1490
1499
  return {
1491
1500
  isValid: false,
1492
- error: "SEI addresses must be 0x-prefixed EVM or sei1 bech32 strings."
1501
+ error: prefix === "sei" ? "SEI addresses must be 0x-prefixed EVM or sei1 bech32 strings." : `Address must be a valid ${prefix}1 bech32 string.`
1493
1502
  };
1494
1503
  }
1495
1504
  function validateSolanaAddress(address) {
@@ -1539,15 +1548,12 @@ function validateAddressForChain(address, chain) {
1539
1548
  case "bitcoin":
1540
1549
  return validateBtcAddress(trimmed);
1541
1550
  case "cosmos":
1542
- if (chainDef?.networkIdentifier?.toLowerCase() === "sei") {
1543
- return validateSeiAddress(trimmed);
1544
- }
1545
- return validateBech32LikeAddress(trimmed, "sei");
1551
+ return validateCosmosAddress(trimmed, chainDef ?? chain);
1546
1552
  default:
1547
1553
  return { isValid: false, error: "Unsupported or unknown chain type." };
1548
1554
  }
1549
1555
  }
1550
- function validateAddressForRouteChain(address, chainType) {
1556
+ function validateAddressForRouteChain(address, chainType, chainRef) {
1551
1557
  switch (normalizeChainType(chainType)) {
1552
1558
  case "evm":
1553
1559
  return validateEvmAddress(address);
@@ -1556,7 +1562,7 @@ function validateAddressForRouteChain(address, chainType) {
1556
1562
  case "bitcoin":
1557
1563
  return validateBtcAddress(address);
1558
1564
  case "cosmos":
1559
- return validateSeiAddress(address);
1565
+ return validateCosmosAddress(address, chainRef ?? chainType);
1560
1566
  default:
1561
1567
  return { isValid: false, error: "Unsupported chain type." };
1562
1568
  }
@@ -1578,14 +1584,18 @@ function validateRouteAddresses(params) {
1578
1584
  const normalizedDirection = params.direction?.trim().toLowerCase();
1579
1585
  const isDepositFlow = normalizedDirection === "deposit" || (toType === "evm" || toType === "cosmos") && (fromType === "bitcoin" || fromType === "solana");
1580
1586
  if (isDepositFlow) {
1581
- const fromResult2 = validateAddressForRouteChain(fromAddress, fromType);
1587
+ const fromResult2 = validateAddressForRouteChain(
1588
+ fromAddress,
1589
+ fromType,
1590
+ params.fromChain
1591
+ );
1582
1592
  if (!fromResult2.isValid) {
1583
1593
  return {
1584
1594
  isValid: false,
1585
1595
  error: `From address: ${fromResult2.error ?? "Invalid address."}`
1586
1596
  };
1587
1597
  }
1588
- const toResult2 = toType === "cosmos" ? validateSeiAddress(toAddress) : validateEvmAddress(toAddress);
1598
+ const toResult2 = toType === "cosmos" ? validateCosmosAddress(toAddress, params.toChain) : validateEvmAddress(toAddress);
1589
1599
  if (!toResult2.isValid) {
1590
1600
  return {
1591
1601
  isValid: false,
@@ -1610,14 +1620,22 @@ function validateRouteAddresses(params) {
1610
1620
  }
1611
1621
  return { isValid: true };
1612
1622
  }
1613
- const fromResult = validateAddressForRouteChain(fromAddress, fromType);
1623
+ const fromResult = validateAddressForRouteChain(
1624
+ fromAddress,
1625
+ fromType,
1626
+ params.fromChain
1627
+ );
1614
1628
  if (!fromResult.isValid) {
1615
1629
  return {
1616
1630
  isValid: false,
1617
1631
  error: `From address: ${fromResult.error ?? "Invalid address."}`
1618
1632
  };
1619
1633
  }
1620
- const toResult = validateAddressForRouteChain(toAddress, toType);
1634
+ const toResult = validateAddressForRouteChain(
1635
+ toAddress,
1636
+ toType,
1637
+ params.toChain
1638
+ );
1621
1639
  if (!toResult.isValid) {
1622
1640
  return {
1623
1641
  isValid: false,
@@ -1626,7 +1644,7 @@ function validateRouteAddresses(params) {
1626
1644
  }
1627
1645
  return { isValid: true };
1628
1646
  }
1629
- var import_viem, BECH32_CHARSET;
1647
+ var import_viem, BECH32_CHARSET, COSMOS_BECH32_PREFIX_BY_CHAIN_ID;
1630
1648
  var init_address = __esm({
1631
1649
  "src/validation/address.ts"() {
1632
1650
  "use strict";
@@ -1634,6 +1652,12 @@ var init_address = __esm({
1634
1652
  init_index_node4();
1635
1653
  init_chains();
1636
1654
  BECH32_CHARSET = /^[023456789acdefghjklmnpqrstuvwxyz]+$/i;
1655
+ COSMOS_BECH32_PREFIX_BY_CHAIN_ID = {
1656
+ "pacific-1": "sei",
1657
+ sei: "sei",
1658
+ "cataclysm-1": "nibi",
1659
+ nibiru: "nibi"
1660
+ };
1637
1661
  }
1638
1662
  });
1639
1663
 
@@ -2031,6 +2055,20 @@ async function requestSDKRPC(path, init = {}) {
2031
2055
  }
2032
2056
  );
2033
2057
  }
2058
+ async function getEVMAllowance(params) {
2059
+ const search = new URLSearchParams(params);
2060
+ return requestSDKRPC(
2061
+ `/evm/allowance?${search.toString()}`,
2062
+ { method: "GET" }
2063
+ );
2064
+ }
2065
+ async function getEVMTxStatus(params) {
2066
+ const search = new URLSearchParams(params);
2067
+ return requestSDKRPC(
2068
+ `/evm/tx-status?${search.toString()}`,
2069
+ { method: "GET" }
2070
+ );
2071
+ }
2034
2072
  async function sendSolanaSerialized(body) {
2035
2073
  return requestSDKRPC(
2036
2074
  "/solana/send-serialized",
@@ -3904,6 +3942,27 @@ var init_wallets = __esm({
3904
3942
  });
3905
3943
 
3906
3944
  // src/core/routes.ts
3945
+ function assertValidPostHook(hooks) {
3946
+ const postHook = hooks?.postHook;
3947
+ if (!postHook) return;
3948
+ if (!postHook.target?.trim()) {
3949
+ throw new Error("hooks.postHook.target is required.");
3950
+ }
3951
+ if (!postHook.callData?.trim()) {
3952
+ throw new Error("hooks.postHook.callData is required.");
3953
+ }
3954
+ if (postHook.fullAmount) {
3955
+ if (postHook.amountInputPos === void 0) {
3956
+ throw new Error(
3957
+ "hooks.postHook.amountInputPos is required when fullAmount is true."
3958
+ );
3959
+ }
3960
+ } else if (!postHook.fundAmount?.trim()) {
3961
+ throw new Error(
3962
+ "hooks.postHook.fundAmount is required unless fullAmount is set."
3963
+ );
3964
+ }
3965
+ }
3907
3966
  function isEvmTxRequest(txReq) {
3908
3967
  return Boolean(txReq?.data && (txReq.to || txReq.target));
3909
3968
  }
@@ -3922,6 +3981,7 @@ async function buildRoute(body, signal) {
3922
3981
  if (!addressValidation.isValid) {
3923
3982
  throw new Error(addressValidation.error || "Invalid route addresses.");
3924
3983
  }
3984
+ assertValidPostHook(body.hooks);
3925
3985
  const cfg = TrustwareConfigStore.get();
3926
3986
  const url = `${apiBase()}/v1/routes/route`;
3927
3987
  const payload = {
@@ -3960,6 +4020,7 @@ async function buildRoute(body, signal) {
3960
4020
  return { intentId, txReq, actions, finalExchangeRate, route, sponsorship };
3961
4021
  }
3962
4022
  async function buildDepositAddress(body, signal) {
4023
+ assertValidPostHook(body.hooks);
3963
4024
  const cfg = TrustwareConfigStore.get();
3964
4025
  const url = `${apiBase()}/v1/routes/deposit-address`;
3965
4026
  const payload = {
@@ -4001,7 +4062,7 @@ async function buildDepositAddress(body, signal) {
4001
4062
  route
4002
4063
  };
4003
4064
  }
4004
- async function submitReceipt(intentId, txHash, sponsorshipRequestId) {
4065
+ async function submitReceipt(intentId, txHash, sponsorshipRequestId, eoaAddress) {
4005
4066
  const r = await rateLimitedFetch(
4006
4067
  `${apiBase()}/v1/route-intent/${intentId}/receipt`,
4007
4068
  {
@@ -4009,7 +4070,8 @@ async function submitReceipt(intentId, txHash, sponsorshipRequestId) {
4009
4070
  headers: jsonHeaders({ "Idempotency-Key": txHash }),
4010
4071
  body: JSON.stringify({
4011
4072
  txHash,
4012
- ...sponsorshipRequestId ? { sponsorshipRequestId } : {}
4073
+ ...sponsorshipRequestId ? { sponsorshipRequestId } : {},
4074
+ ...eoaAddress ? { eoaAddress } : {}
4013
4075
  })
4014
4076
  }
4015
4077
  );
@@ -4131,7 +4193,9 @@ var init_chainHelpers = __esm({
4131
4193
  btc: "bitcoin",
4132
4194
  bitcoin: "bitcoin",
4133
4195
  sei: "cosmos",
4134
- "pacific-1": "cosmos"
4196
+ "pacific-1": "cosmos",
4197
+ nibiru: "cosmos",
4198
+ "cataclysm-1": "cosmos"
4135
4199
  };
4136
4200
  SEI_EVM_CHAIN_ID = "1329";
4137
4201
  SEI_COSMOS_CHAIN_ID = "pacific-1";
@@ -4285,7 +4349,8 @@ function filterSupportedChains(chains) {
4285
4349
  }
4286
4350
  if (chainType === "cosmos") {
4287
4351
  const seiKey = canonicalSeiChainKey(chain.chainId ?? chain.id);
4288
- if (seiKey !== "sei" && seiKey !== "pacific-1") {
4352
+ const isNibiru = normalizeChainKey2(chain.chainId ?? chain.id) === NIBIRU_COSMOS_CHAIN_ID;
4353
+ if (seiKey !== "sei" && !isNibiru) {
4289
4354
  return false;
4290
4355
  }
4291
4356
  }
@@ -4385,7 +4450,7 @@ function useChains() {
4385
4450
  error
4386
4451
  };
4387
4452
  }
4388
- var import_react2, POPULAR_CHAINS_BY_TVL, POPULAR_LIMIT;
4453
+ var import_react2, POPULAR_CHAINS_BY_TVL, POPULAR_LIMIT, NIBIRU_COSMOS_CHAIN_ID;
4389
4454
  var init_useChains = __esm({
4390
4455
  "src/core/useChains.ts"() {
4391
4456
  "use strict";
@@ -4396,6 +4461,7 @@ var init_useChains = __esm({
4396
4461
  init_popularChains();
4397
4462
  POPULAR_CHAINS_BY_TVL = popularChains_default.byTvl;
4398
4463
  POPULAR_LIMIT = popularChains_default.popularLimit;
4464
+ NIBIRU_COSMOS_CHAIN_ID = "cataclysm-1";
4399
4465
  }
4400
4466
  });
4401
4467
 
@@ -6180,46 +6246,80 @@ function normalizeSlippage(v) {
6180
6246
  if (n > 5) return 5;
6181
6247
  return n;
6182
6248
  }
6249
+ function warnDeprecatedSwapModeFlag() {
6250
+ if (hasWarnedDeprecatedSwapModeFlag) return;
6251
+ hasWarnedDeprecatedSwapModeFlag = true;
6252
+ console.warn(
6253
+ '[Trustware SDK] `features.swapMode` is deprecated \u2014 use `mode: "swap"` on the top-level config instead.'
6254
+ );
6255
+ }
6256
+ function resolveMode(input) {
6257
+ if (input.mode === "swap") return "swap";
6258
+ if (input.mode === "deposit") return "deposit";
6259
+ if (input.features?.swapMode) {
6260
+ warnDeprecatedSwapModeFlag();
6261
+ return "swap";
6262
+ }
6263
+ return "deposit";
6264
+ }
6183
6265
  function resolveConfig(input) {
6184
6266
  if (!input?.apiKey) {
6185
- throw new Error("TrustwareConfig: 'apiKey' is required.");
6267
+ throw new TrustwareError({
6268
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
6269
+ message: "TrustwareConfig: 'apiKey' is required.",
6270
+ userMessage: "Missing required API key configuration."
6271
+ });
6186
6272
  }
6187
- if (!input.routes?.toChain || !input.routes?.toToken) {
6188
- throw new Error(
6189
- "TrustwareConfig: 'routes.toChain' and 'routes.toToken' are required."
6190
- );
6273
+ const mode = resolveMode(input);
6274
+ if (mode === "deposit" && (!input.routes?.toChain || !input.routes?.toToken)) {
6275
+ throw new TrustwareError({
6276
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
6277
+ message: "TrustwareConfig: 'routes.toChain' and 'routes.toToken' are required in deposit mode.",
6278
+ userMessage: "Missing required destination chain/token configuration."
6279
+ });
6191
6280
  }
6192
- const toChain = input.routes.toChain;
6193
- if (input.routes.toAddress) {
6281
+ const toChain = input.routes?.toChain;
6282
+ if (input.routes?.toAddress && toChain) {
6194
6283
  const result = validateAddressForChain(input.routes.toAddress, toChain);
6195
6284
  if (!result.isValid) {
6196
6285
  console.error(`[Trustware SDK] Invalid toAddress: ${result.error}`);
6197
- throw new Error(`Invalid toAddress: ${result.error}`);
6286
+ throw new TrustwareError({
6287
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
6288
+ message: `Invalid toAddress: ${result.error}`,
6289
+ userMessage: "The configured destination address is invalid."
6290
+ });
6198
6291
  }
6199
6292
  }
6200
- if (input.routes.fromAddress) {
6201
- const result = validateAddressForChain(
6202
- input.routes.fromAddress,
6203
- input.routes.fromChain ?? toChain
6204
- );
6205
- if (!result.isValid) {
6206
- console.error(`[Trustware SDK] Invalid fromAddress: ${result.error}`);
6207
- throw new Error(`Invalid fromAddress: ${result.error}`);
6293
+ if (input.routes?.fromAddress) {
6294
+ const fromChain = input.routes.fromChain ?? toChain;
6295
+ if (fromChain) {
6296
+ const result = validateAddressForChain(
6297
+ input.routes.fromAddress,
6298
+ fromChain
6299
+ );
6300
+ if (!result.isValid) {
6301
+ console.error(`[Trustware SDK] Invalid fromAddress: ${result.error}`);
6302
+ throw new TrustwareError({
6303
+ code: "INVALID_CONFIG" /* INVALID_CONFIG */,
6304
+ message: `Invalid fromAddress: ${result.error}`,
6305
+ userMessage: "The configured source address is invalid."
6306
+ });
6307
+ }
6208
6308
  }
6209
6309
  }
6210
6310
  const autoDetectProvider = typeof input.autoDetectProvider === "boolean" ? input.autoDetectProvider : DEFAULT_AUTO_DETECT_PROVIDER;
6211
6311
  const routes = {
6212
- toChain: input.routes.toChain,
6213
- toToken: input.routes.toToken,
6214
- fromToken: input.routes.fromToken,
6215
- fromAddress: input.routes.fromAddress,
6216
- fromChain: input.routes.fromChain,
6217
- toAddress: input.routes.toAddress,
6312
+ toChain: input.routes?.toChain ?? "",
6313
+ toToken: input.routes?.toToken ?? "",
6314
+ fromToken: input.routes?.fromToken,
6315
+ fromAddress: input.routes?.fromAddress,
6316
+ fromChain: input.routes?.fromChain,
6317
+ toAddress: input.routes?.toAddress,
6218
6318
  defaultSlippage: normalizeSlippage(
6219
- input.routes.defaultSlippage ?? DEFAULT_SLIPPAGE
6319
+ input.routes?.defaultSlippage ?? DEFAULT_SLIPPAGE
6220
6320
  ),
6221
6321
  options: {
6222
- ...input.routes.options
6322
+ ...input.routes?.options
6223
6323
  }
6224
6324
  };
6225
6325
  const theme = input.theme ?? "system";
@@ -6238,13 +6338,16 @@ function resolveConfig(input) {
6238
6338
  tokensPagination: input.features?.tokensPagination ?? DEFAULT_FEATURE_FLAGS.tokensPagination,
6239
6339
  balanceStreaming: input.features?.balanceStreaming ?? DEFAULT_FEATURE_FLAGS.balanceStreaming,
6240
6340
  shouldAllowGA4: input.features?.shouldAllowGA4 ?? DEFAULT_FEATURE_FLAGS.shouldAllowGA4,
6241
- swapMode: input.features?.swapMode ?? DEFAULT_FEATURE_FLAGS.swapMode,
6341
+ // Always mirrors the canonical `mode`, however the caller set it (new `mode` field
6342
+ // or the deprecated `features.swapMode` flag).
6343
+ swapMode: mode === "swap",
6242
6344
  swapDefaultDestToken: input.features?.swapDefaultDestToken ?? DEFAULT_FEATURE_FLAGS.swapDefaultDestToken,
6243
6345
  swapLockDestToken: input.features?.swapLockDestToken ?? DEFAULT_FEATURE_FLAGS.swapLockDestToken,
6244
6346
  swapAllowedDestTokens: input.features?.swapAllowedDestTokens ?? DEFAULT_FEATURE_FLAGS.swapAllowedDestTokens
6245
6347
  };
6246
6348
  return {
6247
6349
  apiKey: input.apiKey,
6350
+ mode,
6248
6351
  routes,
6249
6352
  autoDetectProvider,
6250
6353
  theme,
@@ -6257,12 +6360,15 @@ function resolveConfig(input) {
6257
6360
  onEvent: input.onEvent
6258
6361
  };
6259
6362
  }
6363
+ var hasWarnedDeprecatedSwapModeFlag;
6260
6364
  var init_merge = __esm({
6261
6365
  "src/config/merge.ts"() {
6262
6366
  "use strict";
6263
6367
  init_defaults();
6264
6368
  init_config();
6265
6369
  init_index();
6370
+ init_TrustwareError();
6371
+ hasWarnedDeprecatedSwapModeFlag = false;
6266
6372
  }
6267
6373
  });
6268
6374
 
@@ -6351,6 +6457,87 @@ function backendChainId(chain, fallback) {
6351
6457
  const preferred = chain?.networkIdentifier ?? chain?.chainId ?? chain?.id;
6352
6458
  return String(preferred ?? fallback ?? "");
6353
6459
  }
6460
+ function sleep2(ms) {
6461
+ return new Promise((resolve) => setTimeout(resolve, ms));
6462
+ }
6463
+ async function sendEvmTx(w, tx) {
6464
+ if (w.type === "eip1193") {
6465
+ const from = await w.getAddress();
6466
+ const params = {
6467
+ from,
6468
+ to: tx.to,
6469
+ data: tx.data,
6470
+ value: tx.value ? `0x${tx.value.toString(16)}` : "0x0"
6471
+ };
6472
+ if (tx.chainId !== void 0) {
6473
+ params.chainId = `0x${tx.chainId.toString(16)}`;
6474
+ }
6475
+ const hash = await w.request({
6476
+ method: "eth_sendTransaction",
6477
+ params: [params]
6478
+ });
6479
+ return hash;
6480
+ }
6481
+ const response = await w.sendTransaction({
6482
+ to: tx.to,
6483
+ data: tx.data,
6484
+ value: tx.value,
6485
+ chainId: tx.chainId
6486
+ });
6487
+ return response.hash;
6488
+ }
6489
+ async function waitForTxConfirmation(chainId, txHash) {
6490
+ const timeoutMs = 12e4;
6491
+ const intervalMs = 2e3;
6492
+ const started = Date.now();
6493
+ while (Date.now() - started < timeoutMs) {
6494
+ const status = await getEVMTxStatus({ chainId, txHash });
6495
+ if (status.status === "success") return;
6496
+ if (status.status === "reverted") {
6497
+ throw new Error("Approval transaction reverted");
6498
+ }
6499
+ await sleep2(intervalMs);
6500
+ }
6501
+ throw new Error("Timed out waiting for approval confirmation");
6502
+ }
6503
+ async function ensureApprovals(w, approvals, fallbackChainId) {
6504
+ if (!approvals || approvals.length === 0) return;
6505
+ const owner = await w.getAddress();
6506
+ for (const approval of approvals) {
6507
+ const spender = approval.spender;
6508
+ const tokenAddress = approval.tokenAddress;
6509
+ const amount = approval.amount;
6510
+ if (!spender || !tokenAddress || !amount) continue;
6511
+ const chainId = approval.chainId || String(fallbackChainId ?? "");
6512
+ if (!chainId) continue;
6513
+ const amountWei = BigInt(amount);
6514
+ if (amountWei === 0n) continue;
6515
+ let currentAllowance = 0n;
6516
+ try {
6517
+ const { allowance } = await getEVMAllowance({
6518
+ chainId,
6519
+ tokenAddress,
6520
+ ownerAddress: owner,
6521
+ spenderAddress: spender
6522
+ });
6523
+ currentAllowance = BigInt(allowance || "0");
6524
+ } catch {
6525
+ }
6526
+ if (currentAllowance >= amountWei) continue;
6527
+ const data = (0, import_viem2.encodeFunctionData)({
6528
+ abi: erc20ApproveAbi,
6529
+ functionName: "approve",
6530
+ args: [spender, amountWei]
6531
+ });
6532
+ const hash = await sendEvmTx(w, {
6533
+ to: tokenAddress,
6534
+ data,
6535
+ value: 0n,
6536
+ chainId: Number.isFinite(Number(chainId)) ? Number(chainId) : void 0
6537
+ });
6538
+ await waitForTxConfirmation(chainId, hash);
6539
+ }
6540
+ }
6354
6541
  function isUserRejected(e2) {
6355
6542
  const code = e2?.code ?? e2?.data?.code;
6356
6543
  if (code === 4001) return true;
@@ -6384,6 +6571,13 @@ async function sendRouteTransaction(b, fallbackChainId) {
6384
6571
  }
6385
6572
  }
6386
6573
  }
6574
+ if (!validatedSponsorship) {
6575
+ await ensureApprovals(
6576
+ w,
6577
+ b.route?.execution?.approvals,
6578
+ Number.isFinite(target) ? target : void 0
6579
+ );
6580
+ }
6387
6581
  if (w.type === "eip1193") {
6388
6582
  const from = await w.getAddress();
6389
6583
  const hexValue = value ? `0x${value.toString(16)}` : "0x0";
@@ -6480,13 +6674,17 @@ async function runTopUp(params) {
6480
6674
  }
6481
6675
  }
6482
6676
  }
6483
- var import_viem2;
6677
+ var import_viem2, erc20ApproveAbi;
6484
6678
  var init_tx = __esm({
6485
6679
  "src/core/tx.ts"() {
6486
6680
  "use strict";
6487
6681
  init_wallets();
6488
6682
  init_routes();
6683
+ init_sdkRpc();
6489
6684
  import_viem2 = require("viem");
6685
+ erc20ApproveAbi = (0, import_viem2.parseAbi)([
6686
+ "function approve(address spender, uint256 amount) returns (bool)"
6687
+ ]);
6490
6688
  }
6491
6689
  });
6492
6690