@0xsquid/react-hooks 8.6.1 → 8.7.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.
Files changed (38) hide show
  1. package/dist/core/constants.d.ts +3 -0
  2. package/dist/core/queries/queries-keys.d.ts +1 -1
  3. package/dist/core/types/config.d.ts +0 -1
  4. package/dist/core/types/history.d.ts +1 -1
  5. package/dist/hooks/index.d.ts +1 -1
  6. package/dist/hooks/tokens/useSourceChainGasToken.d.ts +13 -0
  7. package/dist/hooks/transaction/send/useEstimateSendTransactionGas.d.ts +11 -2
  8. package/dist/hooks/transaction/useEstimate.d.ts +7 -12
  9. package/dist/hooks/transaction/useTempoFeeCheck.d.ts +11 -0
  10. package/dist/{index-uxBoqobR.js → index-DQERpZr8.js} +280 -155
  11. package/dist/index-DQERpZr8.js.map +1 -0
  12. package/dist/{index--gt66OVO.js → index-Dgqm3ZeG.js} +280 -155
  13. package/dist/index-Dgqm3ZeG.js.map +1 -0
  14. package/dist/{index.es-DXYyLkwM.js → index.es-BKxEl9R1.js} +2 -2
  15. package/dist/{index.es-DXYyLkwM.js.map → index.es-BKxEl9R1.js.map} +1 -1
  16. package/dist/{index.es-zgttb4RJ.js → index.es-DOFFrTzb.js} +2 -2
  17. package/dist/{index.es-zgttb4RJ.js.map → index.es-DOFFrTzb.js.map} +1 -1
  18. package/dist/index.esm.js +1 -1
  19. package/dist/index.js +2 -2
  20. package/dist/{secretService-BoIRJAyQ.js → secretService-CqdaN_la.js} +2 -2
  21. package/dist/{secretService-BoIRJAyQ.js.map → secretService-CqdaN_la.js.map} +1 -1
  22. package/dist/{secretService-C3pLXo0u.js → secretService-DXExZJnA.js} +2 -2
  23. package/dist/{secretService-C3pLXo0u.js.map → secretService-DXExZJnA.js.map} +1 -1
  24. package/dist/server.esm.js +3 -0
  25. package/dist/server.esm.js.map +1 -1
  26. package/dist/server.js +3 -0
  27. package/dist/server.js.map +1 -1
  28. package/dist/services/internal/assetsService.d.ts +2 -2
  29. package/dist/services/internal/estimateService.d.ts +15 -28
  30. package/dist/services/internal/tempoService.d.ts +42 -0
  31. package/dist/{stellarService.client-DYLHIsR1.js → stellarService.client-BmkrPHkP.js} +2 -2
  32. package/dist/{stellarService.client-DYLHIsR1.js.map → stellarService.client-BmkrPHkP.js.map} +1 -1
  33. package/dist/{stellarService.client-8vhPwFQb.js → stellarService.client-eK7yYyOR.js} +2 -2
  34. package/dist/{stellarService.client-8vhPwFQb.js.map → stellarService.client-eK7yYyOR.js.map} +1 -1
  35. package/package.json +1 -1
  36. package/dist/hooks/user/useUserParams.d.ts +0 -4
  37. package/dist/index--gt66OVO.js.map +0 -1
  38. package/dist/index-uxBoqobR.js.map +0 -1
@@ -145,6 +145,9 @@ const CHAIN_IDS = {
145
145
  SONEIUM: "1868",
146
146
  PEAQ: "3338",
147
147
  HEDERA: "295",
148
+ MANTRA: "5888",
149
+ CITREA: "4114",
150
+ TEMPO: "4217",
148
151
  // others
149
152
  BITCOIN: "bitcoin",
150
153
  SOLANA: "solana-mainnet-beta",
@@ -21071,6 +21074,7 @@ const formatSwapTxStatusResponseForStorage = (sr) => {
21071
21074
  }
21072
21075
  return {
21073
21076
  axelarTransactionUrl: sr.axelarTransactionUrl,
21077
+ coralTransactionUrl: sr.coralTransactionUrl,
21074
21078
  toChain: sr.toChain?.transactionUrl
21075
21079
  ? {
21076
21080
  transactionUrl: sr.toChain?.transactionUrl,
@@ -22409,7 +22413,7 @@ const keys = () => ({
22409
22413
  // ============
22410
22414
  // Transactions
22411
22415
  // ============
22412
- transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, price, slippage, getGasOnDestination, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22416
+ transaction: (fromChainId, toChainId, toTokenAddress, fromTokenAddress, price, slippage, sourceUserAddress, degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChainType, preHook, postHook, overrideGasRefundAddress) => [
22413
22417
  ...keys().transactions(),
22414
22418
  exports.QueryKeys.Transaction,
22415
22419
  fromChainId,
@@ -22418,7 +22422,6 @@ const keys = () => ({
22418
22422
  fromTokenAddress,
22419
22423
  price,
22420
22424
  slippage,
22421
- getGasOnDestination,
22422
22425
  sourceUserAddress,
22423
22426
  degenMode,
22424
22427
  destinationAddress,
@@ -22607,7 +22610,6 @@ const getConfigWithDefaults = (config) => {
22607
22610
  integratorId: get$2(config, "integratorId", defaultConfigValues.integratorId),
22608
22611
  slippage: get$2(config, "slippage", defaultConfigValues.slippage),
22609
22612
  collectFees: get$2(config, "collectFees", defaultConfigValues.collectFees),
22610
- enableGetGasOnDestination: get$2(config, "enableGetGasOnDestination", defaultConfigValues.enableGetGasOnDestination),
22611
22613
  apiUrl: get$2(config, "apiUrl", defaultConfigValues.apiUrl),
22612
22614
  priceImpactWarnings: get$2(config, "priceImpactWarnings", defaultConfigValues.priceImpactWarnings),
22613
22615
  initialAssets: get$2(config, "initialAssets", defaultConfigValues.initialAssets),
@@ -23101,8 +23103,8 @@ const sortAllTokens = (tokenA, tokenB) => {
23101
23103
  return 0;
23102
23104
  };
23103
23105
  const findToken = (tokens, chainId, address) => tokens.find((t) => t.chainId === chainId && t.address === address);
23104
- const findNativeToken = (tokens, chain) => tokens.find((t) => t.symbol.toUpperCase() === chain?.nativeCurrency.symbol.toUpperCase() &&
23105
- t.chainId == chain?.chainId);
23106
+ const findNativeToken = (tokens, chain) => tokens.find((t) => t.symbol.toUpperCase() === chain.nativeCurrency.symbol.toUpperCase() &&
23107
+ t.chainId == chain.chainId);
23106
23108
  const normalizeIbcAddress = (address) => {
23107
23109
  if (!address.toLowerCase().startsWith("ibc/")) {
23108
23110
  return address;
@@ -23313,7 +23315,7 @@ const filterViewableTokens = (tokens, config, direction) => {
23313
23315
  };
23314
23316
  const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
23315
23317
  const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
23316
- const { fetchAllSecretBalances } = await Promise.resolve().then(function () { return require('./secretService-C3pLXo0u.js'); });
23318
+ const { fetchAllSecretBalances } = await Promise.resolve().then(function () { return require('./secretService-DXExZJnA.js'); });
23317
23319
  return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
23318
23320
  };
23319
23321
  function getTokenAssetsKey(token) {
@@ -26711,7 +26713,7 @@ function useStellarWallets() {
26711
26713
  try {
26712
26714
  const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
26713
26715
  const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module');
26714
- const { formatStellarWallet } = await Promise.resolve().then(function () { return require('./stellarService.client-8vhPwFQb.js'); });
26716
+ const { formatStellarWallet } = await Promise.resolve().then(function () { return require('./stellarService.client-eK7yYyOR.js'); });
26715
26717
  const modules = [...initializeAllModules(), new LedgerModule()];
26716
26718
  const promises = modules.map(async (module) => {
26717
26719
  const isAvailable = await module.isAvailable();
@@ -29352,8 +29354,8 @@ function timeout(ms, promise) {
29352
29354
  return Promise.race([promise, timeoutPromise]);
29353
29355
  }
29354
29356
 
29355
- const DEFAULT_REFRESH_INTERVAL_MS = 15000;
29356
- const useEvmBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29357
+ const DEFAULT_REFRESH_INTERVAL_MS$1 = 15000;
29358
+ const useEvmBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29357
29359
  const { isChainTypeConnected } = useWallet();
29358
29360
  const isNativeToken = token?.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase();
29359
29361
  const userAddressParsed = userAddress;
@@ -29404,7 +29406,7 @@ const useEvmBalance = ({ chain, token, userAddress, enabled = true, refreshInter
29404
29406
  isLoading: isErc20Loading,
29405
29407
  };
29406
29408
  };
29407
- const useCosmosBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29409
+ const useCosmosBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29408
29410
  const { isConnected } = useCosmosContext();
29409
29411
  const { data: balance = "0", isLoading } = reactQuery.useQuery({
29410
29412
  queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
@@ -29428,7 +29430,7 @@ const useCosmosBalance = ({ chain, token, userAddress, enabled = true, refreshIn
29428
29430
  });
29429
29431
  return { balance, isLoading };
29430
29432
  };
29431
- const useSolanaBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29433
+ const useSolanaBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29432
29434
  const { data: balance = "0", isLoading } = reactQuery.useQuery({
29433
29435
  queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
29434
29436
  queryFn: async () => {
@@ -29459,7 +29461,7 @@ const useBitcoinBalance = ({ userAddress, chain, }) => {
29459
29461
  }, [balanceBn]);
29460
29462
  return { balance, isLoading };
29461
29463
  };
29462
- const useSuiBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29464
+ const useSuiBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29463
29465
  const { data: balance = "0", isLoading } = reactQuery.useQuery({
29464
29466
  queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
29465
29467
  queryFn: async () => {
@@ -29482,7 +29484,7 @@ const useSuiBalance = ({ chain, token, userAddress, enabled = true, refreshInter
29482
29484
  });
29483
29485
  return { balance, isLoading };
29484
29486
  };
29485
- const useXrplBalance = ({ userAddress, chain, enabled, token, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29487
+ const useXrplBalance = ({ userAddress, chain, enabled, token, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29486
29488
  const { data: balance = "0", isLoading } = reactQuery.useQuery({
29487
29489
  queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
29488
29490
  queryFn: async () => {
@@ -29502,7 +29504,7 @@ const useXrplBalance = ({ userAddress, chain, enabled, token, refreshIntervalMs
29502
29504
  });
29503
29505
  return { balance, isLoading };
29504
29506
  };
29505
- const useStellarBalance = ({ userAddress, chain, enabled, token, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS, }) => {
29507
+ const useStellarBalance = ({ userAddress, chain, enabled, token, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
29506
29508
  const { data: balance = "0", isLoading } = reactQuery.useQuery({
29507
29509
  queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
29508
29510
  queryFn: async () => {
@@ -29546,6 +29548,8 @@ function useNativeTokenForChain(chain) {
29546
29548
  }
29547
29549
  };
29548
29550
  const nativeTokenForChainType = React.useMemo(() => {
29551
+ if (!chain)
29552
+ return undefined;
29549
29553
  return findNativeToken(getTokensForChainType(), chain);
29550
29554
  }, [chain]);
29551
29555
  return { nativeToken: nativeTokenForChainType };
@@ -30029,7 +30033,7 @@ function hederaWalletConnect(parameters) {
30029
30033
  const optionalChains = config.chains.map((x) => x.id);
30030
30034
  if (!optionalChains.length)
30031
30035
  return;
30032
- const { EthereumProvider } = await Promise.resolve().then(function () { return require('./index.es-DXYyLkwM.js'); });
30036
+ const { EthereumProvider } = await Promise.resolve().then(function () { return require('./index.es-BKxEl9R1.js'); });
30033
30037
  const rawProvider = await EthereumProvider.init({
30034
30038
  ...restParameters,
30035
30039
  disableProviderPing: true,
@@ -31178,6 +31182,155 @@ const useSingleTokenPrice = (tokenData) => {
31178
31182
  return { tokenPrice, getUSDValue };
31179
31183
  };
31180
31184
 
31185
+ /**
31186
+ * @docs https://docs.tempo.xyz/protocol/fees/spec-fee-amm#2-feemanager-contract
31187
+ */
31188
+ const TEMPO_FEE_MANAGER_ADDRESS = "0xfeec000000000000000000000000000000000000";
31189
+ const feeManagerAbi = [
31190
+ {
31191
+ name: "userTokens",
31192
+ type: "function",
31193
+ stateMutability: "view",
31194
+ inputs: [{ type: "address", name: "user" }],
31195
+ outputs: [{ type: "address" }],
31196
+ },
31197
+ ];
31198
+ const isTempoChain = (chainId) => chainId === CHAIN_IDS.TEMPO;
31199
+ /**
31200
+ * Convert a gas fee amount from 18 decimals (attodollars)
31201
+ * to 6-decimal TIP-20 stablecoin units (microdollars).
31202
+ * All TIP-20 tokens on Tempo have 6 decimals.
31203
+ * @docs https://docs.tempo.xyz/protocol/fees/spec-fee#fee-units
31204
+ */
31205
+ const convertTempoFeeToStablecoinUnits = (feeIn18Dec) => feeIn18Dec / BigInt(10 ** 12);
31206
+
31207
+ const DEFAULT_REFRESH_INTERVAL_MS = 15000;
31208
+ /**
31209
+ * Returns raw on-chain gas token data for Tempo chains, or null when the source
31210
+ * chain is not Tempo.
31211
+ */
31212
+ const useTempoFeeCheck = ({ fromChain, fromToken, }) => {
31213
+ const { connectedAddresses } = useWallet();
31214
+ const evmAddress = parseEvmAddress(connectedAddresses[squidTypes.ChainType.EVM]);
31215
+ const isTempo = isTempoChain(fromChain?.chainId);
31216
+ const chainId = Number(fromChain?.chainId);
31217
+ // Read account-level gas token preference from FeeManager precompile
31218
+ // See docs: https://docs.tempo.xyz/protocol/fees/spec-fee#account-level
31219
+ const { data: accountGasTokenAddress } = wagmi.useReadContract({
31220
+ address: TEMPO_FEE_MANAGER_ADDRESS,
31221
+ abi: feeManagerAbi,
31222
+ functionName: "userTokens",
31223
+ args: evmAddress ? [evmAddress] : undefined,
31224
+ chainId,
31225
+ query: {
31226
+ enabled: isTempo && !!evmAddress,
31227
+ staleTime: 30_000,
31228
+ },
31229
+ });
31230
+ const hasAccountFeePreference = !!accountGasTokenAddress &&
31231
+ // By default, the zero address is returned when the user has no preference set
31232
+ viem.zeroAddress.toLowerCase() !== accountGasTokenAddress.toLowerCase();
31233
+ // Fetch balance of the account-preferred gas token (if set)
31234
+ const { data: accountGasTokenBalance } = wagmi.useBalance({
31235
+ address: evmAddress,
31236
+ token: hasAccountFeePreference ? accountGasTokenAddress : undefined,
31237
+ chainId,
31238
+ query: {
31239
+ enabled: isTempo && hasAccountFeePreference && !!evmAddress,
31240
+ refetchInterval: DEFAULT_REFRESH_INTERVAL_MS,
31241
+ retry: 2,
31242
+ },
31243
+ });
31244
+ const fromTokenAddress = parseEvmAddress(fromToken?.address);
31245
+ const { data: fromTokenBalance } = wagmi.useBalance({
31246
+ address: evmAddress,
31247
+ token: fromTokenAddress,
31248
+ chainId,
31249
+ query: {
31250
+ enabled: isTempo && !!evmAddress,
31251
+ refetchInterval: DEFAULT_REFRESH_INTERVAL_MS,
31252
+ retry: 2,
31253
+ },
31254
+ });
31255
+ if (!isTempo)
31256
+ return null;
31257
+ if (hasAccountFeePreference) {
31258
+ if (!accountGasTokenAddress || !accountGasTokenBalance)
31259
+ return null;
31260
+ return {
31261
+ gasTokenAddress: accountGasTokenAddress,
31262
+ gasBalance: accountGasTokenBalance.value,
31263
+ };
31264
+ }
31265
+ if (!fromTokenAddress || !fromTokenBalance)
31266
+ return null;
31267
+ return {
31268
+ gasTokenAddress: fromTokenAddress,
31269
+ gasBalance: fromTokenBalance.value,
31270
+ };
31271
+ };
31272
+
31273
+ /**
31274
+ * Hook that returns the gas token and chain fee params for a given source chain and token.
31275
+ */
31276
+ function useSourceChainGasToken({ fromChain, fromToken, }) {
31277
+ const { nativeToken } = useNativeTokenForChain(fromChain);
31278
+ const { evmTokens } = useSquidTokens();
31279
+ const { nativeBalance } = useNativeBalance(fromChain);
31280
+ const tempoFeeData = useTempoFeeCheck({ fromChain, fromToken });
31281
+ const chainFeeParams = React.useMemo(() => {
31282
+ if (fromToken?.address == null ||
31283
+ fromChain?.chainId == null ||
31284
+ nativeBalance?.value == null) {
31285
+ return null;
31286
+ }
31287
+ if (isTempoChain(fromChain.chainId)) {
31288
+ if (!tempoFeeData)
31289
+ return null;
31290
+ const fromTokenPaysGasFees = tempoFeeData.gasTokenAddress.toLowerCase() ===
31291
+ fromToken.address.toLowerCase();
31292
+ return {
31293
+ fromTokenPaysGasFees,
31294
+ gasTokenBalanceWei: tempoFeeData.gasBalance,
31295
+ normalizeFee: convertTempoFeeToStablecoinUnits,
31296
+ };
31297
+ }
31298
+ return {
31299
+ fromTokenPaysGasFees: fromToken.address.toLowerCase() ===
31300
+ chainTypeToNativeTokenAddressMap[fromToken.type].toLowerCase(),
31301
+ gasTokenBalanceWei: nativeBalance.value,
31302
+ normalizeFee: (fee) => fee,
31303
+ };
31304
+ }, [
31305
+ fromToken?.address,
31306
+ fromToken?.type,
31307
+ fromChain?.chainId,
31308
+ nativeBalance?.value,
31309
+ tempoFeeData,
31310
+ ]);
31311
+ /**
31312
+ * The token to pay for gas on the source chain.
31313
+ */
31314
+ const gasToken = React.useMemo(() => {
31315
+ if (fromChain?.chainId == null || fromToken?.address == null)
31316
+ return undefined;
31317
+ if (isTempoChain(fromChain.chainId)) {
31318
+ if (!tempoFeeData)
31319
+ return undefined;
31320
+ return evmTokens.find((t) => t.chainId === fromChain.chainId &&
31321
+ t.address.toLowerCase() === tempoFeeData.gasTokenAddress.toLowerCase());
31322
+ }
31323
+ return nativeToken;
31324
+ }, [
31325
+ fromChain?.chainId,
31326
+ fromToken?.address,
31327
+ nativeToken,
31328
+ tempoFeeData,
31329
+ evmTokens,
31330
+ ]);
31331
+ return { gasToken, chainFeeParams };
31332
+ }
31333
+
31181
31334
  const MAX_COINGECKO_QUERY_TOKENS = 100;
31182
31335
  const fetchHistoricalData = async (coingeckoId, timeFrame) => {
31183
31336
  const now = Math.floor(Date.now() / 1000);
@@ -31328,24 +31481,23 @@ const calculateTotalNativeFees = ({ expressFeeCost, firstFeeCost, firstGasCost,
31328
31481
  (sameTokenBetweenFees
31329
31482
  ? BigInt(firstFeeCost?.amount ?? "0") + BigInt(firstGasCost?.amount ?? "0")
31330
31483
  : BigInt(firstGasCost?.amount ?? "0"));
31331
- const isFromBalanceEnoughToSwap = ({ isFromTokenNative, fromAmount, totalFeesInNativeTokenPlusRatio, nativeTokenBalanceFromChainWei, }) => {
31332
- const fromAmountBigInt = BigInt(fromAmount ?? "0");
31333
- const totalFeesInNativeTokenPlusRatioBigInt = totalFeesInNativeTokenPlusRatio;
31334
- const nativeTokenBalanceFromChainWeiBigInt = nativeTokenBalanceFromChainWei;
31335
- return isFromTokenNative
31336
- ? fromAmountBigInt + totalFeesInNativeTokenPlusRatioBigInt <=
31337
- nativeTokenBalanceFromChainWeiBigInt
31338
- : totalFeesInNativeTokenPlusRatioBigInt <=
31339
- nativeTokenBalanceFromChainWeiBigInt;
31340
- };
31341
- const calculateMinAmountValueWarnMsg = ({ isFromTokenNative, nativeTokenBalanceFromChainWei, sourceChainNativeTokenDecimals, totalFeesInNativeTokenPlusRatio, }) => isFromTokenNative
31342
- ? (() => {
31343
- const minAmount = nativeTokenBalanceFromChainWei - totalFeesInNativeTokenPlusRatio;
31344
- return minAmount > BigInt(0)
31345
- ? formatBNToReadable(minAmount, sourceChainNativeTokenDecimals)
31346
- : "0";
31347
- })()
31348
- : undefined;
31484
+ const checkIsGasBalanceEnough = ({ fromAmount, networkFeesWei, chainFeeParams, }) => {
31485
+ if (!chainFeeParams)
31486
+ return false;
31487
+ if (chainFeeParams.fromTokenPaysGasFees) {
31488
+ return (BigInt(fromAmount ?? "0") + networkFeesWei <=
31489
+ chainFeeParams.gasTokenBalanceWei);
31490
+ }
31491
+ return networkFeesWei <= chainFeeParams.gasTokenBalanceWei;
31492
+ };
31493
+ const calculateMinAmountValueWarnMsg = ({ networkFeesWei, chainFeeParams, fromTokenDecimals, }) => {
31494
+ if (!chainFeeParams?.fromTokenPaysGasFees)
31495
+ return undefined;
31496
+ const minAmount = chainFeeParams.gasTokenBalanceWei - networkFeesWei;
31497
+ if (minAmount <= BigInt(0))
31498
+ return undefined;
31499
+ return formatBNToReadable(minAmount, fromTokenDecimals);
31500
+ };
31349
31501
  /**
31350
31502
  * Calculates the estimated duration of a route
31351
31503
  *
@@ -31384,12 +31536,10 @@ const formatEstimatedRouteDuration = ({ estimatedRouteDuration, isSingleChainRou
31384
31536
  * @returns {Object} An object containing various estimate results and calculations, including token information,
31385
31537
  * amounts, fees, gas costs, and other relevant data for the transaction.
31386
31538
  */
31387
- const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, nativeTokenBalanceFromChainWei, }) => {
31539
+ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, collectFees, chainFeeParams, gasToken, }) => {
31388
31540
  const fromToken = findToken(tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken);
31389
31541
  const fromAmount = squidRoute?.estimate?.fromAmount;
31390
31542
  const fromAmountFormatted = formatAmount(fromAmount, fromToken?.decimals);
31391
- const sourceChainNativeToken = findNativeToken(tokens, fromChain);
31392
- const destChainNativeToken = findNativeToken(tokens, toChain);
31393
31543
  const toAmountUSD = squidRoute?.estimate?.toAmountUSD;
31394
31544
  const exchangeRate = squidRoute?.estimate.exchangeRate ?? "0";
31395
31545
  const toAmountMinUSD = squidRoute?.estimate.toAmountMinUSD ?? "0";
@@ -31408,10 +31558,6 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31408
31558
  const expectedGasRefundCostUSD = convertTokenAmountToUSD(formatBNToReadable(expectedGasRefundCost, firstFeeCost?.token.decimals ?? 18), firstFeeCost?.token.usdPrice ?? "0");
31409
31559
  const sameTokenBetweenFees = firstFeeCost?.token.address === firstGasCost?.token.address &&
31410
31560
  firstFeeCost?.token.chainId === firstGasCost?.token.chainId;
31411
- const isFromTokenNative =
31412
- // TODO: temporary fix, currently nativeCurrency.symbol is not always in uppercase
31413
- fromToken?.symbol.toUpperCase() ===
31414
- fromChain?.nativeCurrency.symbol.toUpperCase();
31415
31561
  const totalNativeFees = calculateTotalNativeFees({
31416
31562
  expressFeeCost,
31417
31563
  firstFeeCost,
@@ -31419,30 +31565,32 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31419
31565
  sameTokenBetweenFees,
31420
31566
  });
31421
31567
  const totalFeesInNativeTokenPlusRatio = (totalNativeFees * BigInt(110)) / BigInt(100);
31422
- const fromBalanceEnoughToSwap = isFromBalanceEnoughToSwap({
31423
- isFromTokenNative,
31568
+ const networkFeesWei = chainFeeParams?.normalizeFee(totalFeesInNativeTokenPlusRatio) ?? BigInt(0);
31569
+ const isGasBalanceEnough = checkIsGasBalanceEnough({
31570
+ chainFeeParams,
31424
31571
  fromAmount,
31425
- fromTokenDecimals: fromToken?.decimals,
31426
- totalFeesInNativeTokenPlusRatio,
31427
- nativeTokenBalanceFromChainWei,
31572
+ networkFeesWei,
31428
31573
  });
31429
31574
  const minAmountValueWarnMsg = calculateMinAmountValueWarnMsg({
31430
- isFromTokenNative,
31431
- nativeTokenBalanceFromChainWei,
31432
- sourceChainNativeTokenDecimals: sourceChainNativeToken?.decimals,
31433
- totalFeesInNativeTokenPlusRatio,
31575
+ chainFeeParams,
31576
+ networkFeesWei,
31577
+ fromTokenDecimals: fromToken?.decimals,
31434
31578
  });
31435
31579
  const isSingleChainRoute = fromChain?.chainId === toChain?.chainId;
31436
31580
  const estimatedRouteDuration = formatEstimatedRouteDuration({
31437
31581
  estimatedRouteDuration: squidRoute?.estimate?.estimatedRouteDuration,
31438
31582
  isSingleChainRoute,
31439
31583
  });
31584
+ // gas fees + fromAmount (if fromToken is gas token)
31585
+ const totalGasBalanceNeeded = networkFeesWei +
31586
+ BigInt(chainFeeParams?.fromTokenPaysGasFees ? fromAmount ?? 0 : 0);
31587
+ const gasBalanceNeeded = gasToken
31588
+ ? formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals)
31589
+ : undefined;
31440
31590
  return {
31441
31591
  fromToken,
31442
31592
  fromAmount,
31443
31593
  fromAmountFormatted,
31444
- sourceChainNativeToken,
31445
- destChainNativeToken,
31446
31594
  toAmountUSD,
31447
31595
  exchangeRate,
31448
31596
  toAmountMinUSD,
@@ -31457,12 +31605,12 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31457
31605
  expectedGasRefundCost,
31458
31606
  expectedGasRefundCostUSD,
31459
31607
  sameTokenBetweenFees,
31460
- isFromTokenNative,
31608
+ fromTokenPaysGasFees: chainFeeParams?.fromTokenPaysGasFees ?? false,
31461
31609
  totalNativeFees,
31462
- totalFeesInNativeTokenPlusRatio,
31463
- fromBalanceEnoughToSwap,
31610
+ isGasBalanceEnough,
31464
31611
  minAmountValueWarnMsg,
31465
31612
  estimatedRouteDuration,
31613
+ gasBalanceNeeded,
31466
31614
  };
31467
31615
  };
31468
31616
  /**
@@ -31496,28 +31644,6 @@ const calculateTotalWithRefundEstimate = (allFeeCosts, expectedGasRefundCost, ge
31496
31644
  feeToken: firstFeeCost?.token,
31497
31645
  };
31498
31646
  };
31499
- /**
31500
- * Calculates the proposed gas amount for the destination chain.
31501
- *
31502
- * @param destChainNativeToken - The symbol of the native token for the destination chain.
31503
- * @returns An object containing the proposed gas amount value and the currency symbol.
31504
- */
31505
- const getProposedGasDestinationAmount = (destChainNativeToken) => {
31506
- const gasAmounts = {
31507
- GLMR: 5.289,
31508
- ETH: 0.0009,
31509
- AVAX: 0.115,
31510
- BNB: 0.00425,
31511
- FTM: 4.45,
31512
- CELO: 3.052,
31513
- KAVA: 2.339,
31514
- MATIC: 1.795,
31515
- };
31516
- return {
31517
- value: gasAmounts[destChainNativeToken ?? ""] ?? 0,
31518
- currency: destChainNativeToken,
31519
- };
31520
- };
31521
31647
 
31522
31648
  function useSendTransactionGas({ chain, token, from, }) {
31523
31649
  return reactQuery.useQuery({
@@ -31539,7 +31665,11 @@ function useSendTransactionGas({ chain, token, from, }) {
31539
31665
  // Some RPC providers require the sender to have enough balance, otherwise estimation reverts
31540
31666
  // so we'll try to use the user provided address when possible
31541
31667
  const sender = from || dummyAddress;
31542
- if (token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase()) {
31668
+ // Tempo has no native token, so `value` transfers are rejected by the EVM.
31669
+ // All transfers are ERC20 transfers
31670
+ const supportsNativeTransfers = chain.chainId !== CHAIN_IDS.TEMPO;
31671
+ const isNativeToken = token.address.toLowerCase() === nativeEvmTokenAddress.toLowerCase();
31672
+ if (isNativeToken && supportsNativeTransfers) {
31543
31673
  const gas = await client.estimateGas({
31544
31674
  from: sender,
31545
31675
  to: dummyAddress,
@@ -31559,7 +31689,13 @@ function useSendTransactionGas({ chain, token, from, }) {
31559
31689
  data,
31560
31690
  chainId: chain.chainId,
31561
31691
  });
31562
- return gas * maxFeePerGas;
31692
+ const feeWei = gas * maxFeePerGas;
31693
+ // Tempo gas fees are denominated 18 units,
31694
+ // this value needs to be scaled to 6 decimals
31695
+ if (chain.chainId === CHAIN_IDS.TEMPO) {
31696
+ return convertTempoFeeToStablecoinUnits(feeWei);
31697
+ }
31698
+ return feeWei;
31563
31699
  }
31564
31700
  case squidTypes.ChainType.COSMOS: {
31565
31701
  // TODO: get gas estimation from backend
@@ -31606,19 +31742,33 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31606
31742
  token,
31607
31743
  from,
31608
31744
  });
31609
- const { nativeBalance } = useNativeBalance(chain);
31610
- const isNativeBalanceEnoughToPayGasFees = React.useMemo(() => {
31611
- if (!nativeBalance?.value || !amount || !token?.decimals) {
31745
+ const { chainFeeParams, gasToken } = useSourceChainGasToken({
31746
+ fromChain: chain,
31747
+ fromToken: token,
31748
+ });
31749
+ const isGasBalanceEnough = React.useMemo(() => {
31750
+ if (!amount || !token?.decimals)
31612
31751
  return false;
31613
- }
31614
- const isTokenNative = token.address.toLowerCase() ===
31615
- chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31616
- if (isTokenNative) {
31617
- return (parseToBigInt(amount, token.decimals) + estimatedGas <=
31618
- nativeBalance.value);
31619
- }
31620
- return estimatedGas <= nativeBalance.value;
31621
- }, [amount, estimatedGas, nativeBalance?.value, token]);
31752
+ return checkIsGasBalanceEnough({
31753
+ fromAmount: parseToBigInt(amount, token.decimals).toString(),
31754
+ networkFeesWei: estimatedGas,
31755
+ chainFeeParams,
31756
+ });
31757
+ }, [amount, estimatedGas, token, chainFeeParams]);
31758
+ const gasBalanceNeeded = React.useMemo(() => {
31759
+ if (!amount || !token?.decimals || !gasToken?.decimals)
31760
+ return undefined;
31761
+ // gas fees + fromAmount (if fromToken is gas token)
31762
+ const totalGasBalanceNeeded = estimatedGas +
31763
+ parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? amount ?? "0" : "0", token.decimals);
31764
+ return formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals);
31765
+ }, [
31766
+ amount,
31767
+ chainFeeParams?.fromTokenPaysGasFees,
31768
+ estimatedGas,
31769
+ gasToken?.decimals,
31770
+ token?.decimals,
31771
+ ]);
31622
31772
  const isBalanceEnough = React.useMemo(() => {
31623
31773
  if (token?.decimals == null || !balance || !amount)
31624
31774
  return false;
@@ -31626,28 +31776,21 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31626
31776
  parseToBigInt(amount, token.decimals));
31627
31777
  }, [amount, balance, token?.decimals]);
31628
31778
  const minAmountValueWarnMsg = React.useMemo(() => {
31629
- if (!token?.address || !nativeBalance?.value || !estimatedGas)
31779
+ if (!token?.address || !estimatedGas || !chainFeeParams)
31630
31780
  return undefined;
31631
- const isFromTokenNative = token.address.toLowerCase() ===
31632
- chainTypeToNativeTokenAddressMap[token.type].toLowerCase();
31633
31781
  return calculateMinAmountValueWarnMsg({
31634
- isFromTokenNative,
31635
- nativeTokenBalanceFromChainWei: nativeBalance.value,
31636
- sourceChainNativeTokenDecimals: nativeBalance.decimals,
31637
- totalFeesInNativeTokenPlusRatio: estimatedGas,
31782
+ chainFeeParams,
31783
+ networkFeesWei: estimatedGas,
31784
+ fromTokenDecimals: token.decimals,
31638
31785
  });
31639
- }, [
31640
- estimatedGas,
31641
- nativeBalance?.decimals,
31642
- nativeBalance?.value,
31643
- token?.address,
31644
- token?.type,
31645
- ]);
31786
+ }, [estimatedGas, token, chainFeeParams]);
31646
31787
  return {
31647
31788
  estimatedGas,
31789
+ gasBalanceNeeded,
31648
31790
  isBalanceEnough,
31791
+ tokenPaysGasFees: chainFeeParams?.fromTokenPaysGasFees ?? false,
31649
31792
  isLoading,
31650
- isNativeBalanceEnoughToPayGasFees,
31793
+ isGasBalanceEnough,
31651
31794
  minAmountValueWarnMsg,
31652
31795
  };
31653
31796
  }
@@ -32709,7 +32852,7 @@ const useApproval = ({ squidRoute, }) => {
32709
32852
  // This is to ensure we're using the latest expiry timestamp
32710
32853
  if (squidRoute) {
32711
32854
  queryClient.refetchQueries({
32712
- queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromPrice, squidRoute.params.slippage, squidRoute.params.receiveGasOnDestination, squidRoute.params.fromAddress, squidRoute.params.bypassGuardrails, squidRoute.params.toAddress, squidRoute.params.fallbackAddresses?.[0]?.address, squidRoute.params.quoteOnly, getChainType(squidRoute.params.fromChain), squidRoute.params.preHook, squidRoute.params.postHook,
32855
+ queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromPrice, squidRoute.params.slippage, squidRoute.params.fromAddress, squidRoute.params.bypassGuardrails, squidRoute.params.toAddress, squidRoute.params.fallbackAddresses?.[0]?.address, squidRoute.params.quoteOnly, getChainType(squidRoute.params.fromChain), squidRoute.params.preHook, squidRoute.params.postHook,
32713
32856
  // TODO: update types
32714
32857
  squidRoute.params?.overrideGasRefundAddress),
32715
32858
  });
@@ -32728,17 +32871,30 @@ const AXELAR_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/ass
32728
32871
  const useEstimate = (squidRoute) => {
32729
32872
  const collectFees = useConfigStore((state) => state.config.collectFees);
32730
32873
  const { tokens } = useSquidTokens();
32731
- const { fromChain, toChain } = useSwap();
32732
- const { nativeBalance } = useNativeBalance(fromChain);
32874
+ const { fromChain, toChain, fromPrice } = useSwap();
32875
+ const fromToken = React.useMemo(() => findToken(tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken), [tokens, squidRoute?.params.fromChain, squidRoute?.params.fromToken]);
32876
+ const { chainFeeParams, gasToken } = useSourceChainGasToken({
32877
+ fromChain,
32878
+ fromToken,
32879
+ });
32733
32880
  const estimateResults = React.useMemo(() => calculateEstimateResults({
32734
32881
  squidRoute,
32735
32882
  tokens,
32736
32883
  fromChain,
32737
32884
  toChain,
32738
32885
  collectFees: !!collectFees && collectFees.fee > 0,
32739
- nativeTokenBalanceFromChainWei: nativeBalance?.value ?? BigInt("0"),
32740
- }), [squidRoute, tokens, fromChain, toChain, collectFees, nativeBalance]);
32741
- const balanceFormatted = useMultiChainBalance({
32886
+ chainFeeParams,
32887
+ gasToken,
32888
+ }), [
32889
+ squidRoute,
32890
+ tokens,
32891
+ fromChain,
32892
+ toChain,
32893
+ collectFees,
32894
+ chainFeeParams,
32895
+ gasToken,
32896
+ ]);
32897
+ const fromBalanceFormatted = useMultiChainBalance({
32742
32898
  chain: fromChain,
32743
32899
  token: estimateResults.fromToken,
32744
32900
  userAddress: squidRoute?.params.fromAddress ?? "",
@@ -32750,7 +32906,6 @@ const useEstimate = (squidRoute) => {
32750
32906
  estimateResults.expectedGasRefundCost,
32751
32907
  getUSDValue,
32752
32908
  ]);
32753
- const proposedGasDestinationAmount = React.useMemo(() => getProposedGasDestinationAmount(estimateResults.destChainNativeToken?.symbol), [estimateResults.destChainNativeToken]);
32754
32909
  const { feeCostsFormatted, totalFeeCostsUsd } = React.useMemo(() => {
32755
32910
  const feeCosts = squidRoute?.estimate.feeCosts ?? [];
32756
32911
  const feeCostsRenamed = [];
@@ -32809,21 +32964,21 @@ const useEstimate = (squidRoute) => {
32809
32964
  totalFeeCostsUsd: totalFeeCostsUsdFormatted,
32810
32965
  };
32811
32966
  }, [squidRoute?.estimate.feeCosts]);
32812
- const slippageFormatted =
32813
- // TODO: update types
32814
- Number(squidRoute?.estimate?.aggregateSlippage ?? 0).toFixed(2) +
32815
- "%";
32816
- const enoughBalanceToSwap = +balanceFormatted >= 0 &&
32817
- +balanceFormatted > +estimateResults.fromAmountFormatted;
32967
+ const slippageFormatted = Number(squidRoute?.estimate?.aggregateSlippage ?? 0).toFixed(2) + "%";
32968
+ const fromBalanceEnoughToSwap = React.useMemo(() => {
32969
+ const fromBalanceNum = Number(fromBalanceFormatted ?? 0);
32970
+ const fromPriceNum = Number(fromPrice ?? 0);
32971
+ return fromBalanceNum >= fromPriceNum;
32972
+ }, [fromBalanceFormatted, fromPrice]);
32818
32973
  return {
32819
32974
  ...estimateResults,
32820
- balanceFormatted,
32975
+ fromBalanceFormatted,
32821
32976
  slippageFormatted,
32822
32977
  totalWithRefundEstimate,
32823
- proposedGasDestinationAmount,
32824
- enoughBalanceToSwap,
32978
+ fromBalanceEnoughToSwap,
32825
32979
  feeCostsFormatted,
32826
32980
  totalFeeCostsUsd,
32981
+ gasToken,
32827
32982
  };
32828
32983
  };
32829
32984
 
@@ -36591,7 +36746,7 @@ const useGetRoute = () => {
36591
36746
  });
36592
36747
  // Cache the route data
36593
36748
  // Useful when the getRoute mutation is called from another hook
36594
- queryClient.setQueryData(keys().transaction(fromChain, toChain, toToken.address, fromToken.address, fromPrice, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, swapRoute?.fallbackAddress, quoteOnly, fromChainType, config.preHook, config.postHook, overrideGasRefundAddress), route);
36749
+ queryClient.setQueryData(keys().transaction(fromChain, toChain, toToken.address, fromToken.address, fromPrice, config.slippage, sourceUserAddress, config.degenMode, destinationAddress, swapRoute?.fallbackAddress, quoteOnly, fromChainType, config.preHook, config.postHook, overrideGasRefundAddress), route);
36595
36750
  return route;
36596
36751
  });
36597
36752
  };
@@ -36614,14 +36769,13 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36614
36769
  const sourceUserAddress = isDepositAddressEnabled && isAvailableAsPaymentMethod
36615
36770
  ? depositRefundAddress ?? sourceConnectedAddress
36616
36771
  : sourceConnectedAddress;
36617
- const squidRouteQueryKeys = React.useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromPrice, config.slippage, config.enableGetGasOnDestination, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
36772
+ const squidRouteQueryKeys = React.useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromPrice, config.slippage, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
36618
36773
  fromChain?.chainId,
36619
36774
  toChain?.chainId,
36620
36775
  toToken?.address,
36621
36776
  fromToken?.address,
36622
36777
  fromPrice,
36623
36778
  config.slippage,
36624
- config.enableGetGasOnDestination,
36625
36779
  sourceUserAddress,
36626
36780
  config.degenMode,
36627
36781
  destinationAddress,
@@ -36893,35 +37047,6 @@ const useAvatar = (seed = zeroAddress) => {
36893
37047
  return avatar || "";
36894
37048
  };
36895
37049
 
36896
- const useUserParams = () => {
36897
- const enableGetGasOnDestination = useConfigStore((state) => state.config.enableGetGasOnDestination);
36898
- const { fromToken, toToken, toChain, fromChain } = useSwap();
36899
- // =============
36900
- // GAS
36901
- // =============
36902
- const getGasOnDestSupportedForThisRoute = React.useMemo(() =>
36903
- // Not supporting get gas on dest for same chains
36904
- fromChain?.chainId !== toChain?.chainId &&
36905
- // If the destination chain is cosmos, we don't support getting gas there
36906
- toChain?.chainType !== squidTypes.ChainType.COSMOS &&
36907
- // Not supporting get gas on dest for same tokens (bridge)
36908
- ((fromToken?.subGraphIds?.some((sgi) => !!toToken?.subGraphIds?.includes(sgi)) &&
36909
- toToken?.subGraphIds?.some((sgi) => !!fromToken?.subGraphIds?.includes(sgi))) ||
36910
- // Except for uusdc -> uusdc
36911
- (fromToken?.subGraphIds?.includes("uusdc") &&
36912
- toToken?.subGraphIds?.includes("uusdc"))), [
36913
- fromChain?.chainId,
36914
- fromToken?.subGraphIds,
36915
- toChain?.chainId,
36916
- toToken?.subGraphIds,
36917
- toChain?.chainType,
36918
- ]);
36919
- return {
36920
- gasEnabled: enableGetGasOnDestination && getGasOnDestSupportedForThisRoute,
36921
- getGasOnDestSupportedForThisRoute,
36922
- };
36923
- };
36924
-
36925
37050
  const useAddToken = (chainToCompare, tokenToCompare) => {
36926
37051
  const { chain: currentEvmChain } = wagmi.useAccount();
36927
37052
  const { connector } = wagmi.useAccount();
@@ -37586,6 +37711,7 @@ exports.useSendTransactionStore = useSendTransactionStore;
37586
37711
  exports.useSigner = useSigner;
37587
37712
  exports.useSingleTokenPrice = useSingleTokenPrice;
37588
37713
  exports.useSolanaNativeBalance = useSolanaNativeBalance;
37714
+ exports.useSourceChainGasToken = useSourceChainGasToken;
37589
37715
  exports.useSquid = useSquid;
37590
37716
  exports.useSquidChains = useSquidChains;
37591
37717
  exports.useSquidQueryClient = useSquidQueryClient;
@@ -37603,7 +37729,6 @@ exports.useTokensData = useTokensData;
37603
37729
  exports.useTrackSearchEmpty = useTrackSearchEmpty;
37604
37730
  exports.useTransactionStore = useTransactionStore;
37605
37731
  exports.useUrlSwapParams = useUrlSwapParams;
37606
- exports.useUserParams = useUserParams;
37607
37732
  exports.useWallet = useWallet;
37608
37733
  exports.useWalletStore = useWalletStore;
37609
37734
  exports.useWallets = useWallets;
@@ -37612,4 +37737,4 @@ exports.useXrplTrustLine = useXrplTrustLine;
37612
37737
  exports.waitForReceiptWithRetry = waitForReceiptWithRetry;
37613
37738
  exports.walletIconBaseUrl = walletIconBaseUrl;
37614
37739
  exports.walletSupportsChainType = walletSupportsChainType;
37615
- //# sourceMappingURL=index-uxBoqobR.js.map
37740
+ //# sourceMappingURL=index-DQERpZr8.js.map