@0xsquid/react-hooks 8.9.1-beta.0 → 8.10.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 (73) hide show
  1. package/dist/core/canton/cantonConnector.d.ts +28 -0
  2. package/dist/core/canton/cip103Client.d.ts +20 -0
  3. package/dist/core/client/index.d.ts +1 -0
  4. package/dist/core/connectors/bitcoin/errors/index.d.ts +0 -3
  5. package/dist/core/connectors/bitcoin/wallets/index.d.ts +0 -1
  6. package/dist/core/connectors/bitcoin/wallets/phantom.d.ts +26 -10
  7. package/dist/core/constants.d.ts +3 -0
  8. package/dist/core/fallbackWallets.d.ts +16 -0
  9. package/dist/core/providers/CantonProvider.d.ts +19 -0
  10. package/dist/core/types/canton.d.ts +58 -0
  11. package/dist/core/types/cosmos.d.ts +5 -0
  12. package/dist/core/types/wallet.d.ts +15 -7
  13. package/dist/core/wallets.d.ts +5 -0
  14. package/dist/hooks/canton/useCanton.d.ts +2 -0
  15. package/dist/hooks/canton/useCantonWallets.d.ts +8 -0
  16. package/dist/hooks/chains/useSquidChains.d.ts +1 -0
  17. package/dist/hooks/index.d.ts +1 -0
  18. package/dist/hooks/store/useDepositAddressStore.d.ts +18 -5
  19. package/dist/hooks/swap/useDepositAddress.d.ts +6 -7
  20. package/dist/hooks/tokens/useBalance.d.ts +1 -0
  21. package/dist/hooks/tokens/useNativeBalance.d.ts +1 -0
  22. package/dist/hooks/tokens/useSquidTokens.d.ts +1 -0
  23. package/dist/hooks/transaction/useDepositTransactionStatus.d.ts +20 -0
  24. package/dist/hooks/transaction/useSwapStatusQuery.d.ts +29 -0
  25. package/dist/hooks/wallet/useMultiChainWallet.d.ts +55 -29
  26. package/dist/hooks/wallet/useSigner.d.ts +1 -0
  27. package/dist/hooks/wallet/useWallet.d.ts +59 -29
  28. package/dist/hooks/xrpl/useXrplWallets.d.ts +2 -2
  29. package/dist/{index-Ypw6i6uY.js → index-BlB3yIoX.js} +1398 -294
  30. package/dist/index-BlB3yIoX.js.map +1 -0
  31. package/dist/{index-sCLxPcqi.js → index-Dzir2lUQ.js} +1383 -276
  32. package/dist/index-Dzir2lUQ.js.map +1 -0
  33. package/dist/{index.es-B2QD8f3q.js → index.es-BPXYaraD.js} +5 -4
  34. package/dist/index.es-BPXYaraD.js.map +1 -0
  35. package/dist/{index.es-Bot12hgd.js → index.es-DwtZr7bN.js} +5 -4
  36. package/dist/index.es-DwtZr7bN.js.map +1 -0
  37. package/dist/index.esm.js +4 -3
  38. package/dist/index.esm.js.map +1 -1
  39. package/dist/index.js +10 -6
  40. package/dist/index.js.map +1 -1
  41. package/dist/{secretService-C3jMjsK0.js → secretService-ICina23f.js} +5 -4
  42. package/dist/{secretService-C3jMjsK0.js.map → secretService-ICina23f.js.map} +1 -1
  43. package/dist/{secretService-BAK4sBb7.js → secretService-eiBnD7dI.js} +5 -4
  44. package/dist/{secretService-BAK4sBb7.js.map → secretService-eiBnD7dI.js.map} +1 -1
  45. package/dist/server.d.ts +1 -1
  46. package/dist/server.esm.js +7 -1
  47. package/dist/server.esm.js.map +1 -1
  48. package/dist/server.js +7 -0
  49. package/dist/server.js.map +1 -1
  50. package/dist/services/external/onrampAdapter.d.ts +3 -4
  51. package/dist/services/external/rpcService.d.ts +17 -0
  52. package/dist/services/internal/assetsService.d.ts +10 -1
  53. package/dist/services/internal/cantonDamlValue.d.ts +75 -0
  54. package/dist/services/internal/cantonService.d.ts +64 -0
  55. package/dist/services/internal/cantonTransferService.d.ts +93 -0
  56. package/dist/services/internal/transactionService.d.ts +5 -1
  57. package/dist/services/internal/walletService.d.ts +3 -6
  58. package/dist/{stellarService.client-SrhXgRGB.js → stellarService.client-Bjc92sC_.js} +6 -5
  59. package/dist/{stellarService.client-SrhXgRGB.js.map → stellarService.client-Bjc92sC_.js.map} +1 -1
  60. package/dist/{stellarService.client-DkJ6WAdl.js → stellarService.client-VOmCOPzL.js} +6 -5
  61. package/dist/{stellarService.client-DkJ6WAdl.js.map → stellarService.client-VOmCOPzL.js.map} +1 -1
  62. package/dist/tests/cantonService.test.d.ts +1 -0
  63. package/dist/tests/cantonTransferService.test.d.ts +1 -0
  64. package/dist/tests/cip103Client.test.d.ts +1 -0
  65. package/dist/tests/fallbackWallets.test.d.ts +1 -0
  66. package/dist/tests/wallets.test.d.ts +1 -0
  67. package/package.json +3 -2
  68. package/dist/core/connectors/bitcoin/bitcoinFeatures.d.ts +0 -53
  69. package/dist/core/connectors/bitcoin/wallets/standard.d.ts +0 -30
  70. package/dist/index-Ypw6i6uY.js.map +0 -1
  71. package/dist/index-sCLxPcqi.js.map +0 -1
  72. package/dist/index.es-B2QD8f3q.js.map +0 -1
  73. package/dist/index.es-Bot12hgd.js.map +0 -1
@@ -5,20 +5,19 @@ var viem = require('viem');
5
5
  var React = require('react');
6
6
  var reactQuery = require('@tanstack/react-query');
7
7
  var encoding = require('@cosmjs/encoding');
8
- var core$1 = require('@wallet-standard/core');
9
8
  var bitcoin = require('bitcoinjs-lib');
10
9
  var ecc = require('@bitcoinerlab/secp256k1');
11
10
  var axios = require('axios');
12
11
  var modal = require('@walletconnect/modal');
13
12
  var UniversalProvider = require('@walletconnect/universal-provider');
14
13
  var rippleAddressCodec = require('ripple-address-codec');
14
+ var BigNumber = require('bignumber.js');
15
15
  var splToken = require('@solana/spl-token');
16
16
  var walletStandardWalletAdapterBase = require('@solana/wallet-standard-wallet-adapter-base');
17
17
  var web3_js = require('@solana/web3.js');
18
18
  var stellarSdk = require('@stellar/stellar-sdk');
19
19
  var walletStandard = require('@mysten/wallet-standard');
20
20
  var ethers = require('ethers');
21
- var BigNumber = require('bignumber.js');
22
21
  var countriesList = require('countries-list');
23
22
  var getSymbolFromCurrency = require('currency-symbol-map');
24
23
  var Fuse = require('fuse.js');
@@ -26,6 +25,8 @@ var zustand = require('zustand');
26
25
  var middleware = require('zustand/middleware');
27
26
  var wagmi = require('wagmi');
28
27
  var SafeAppsSDK = require('@safe-global/safe-apps-sdk');
28
+ var dapp = require('@sigilry/dapp');
29
+ var core$1 = require('@wallet-standard/core');
29
30
  var slushWallet = require('@mysten/slush-wallet');
30
31
  var stargate = require('@cosmjs/stargate');
31
32
  var client = require('@mysten/sui/client');
@@ -78,6 +79,7 @@ const solanaZeroAddress = "11111111111111111111111111111111";
78
79
  const suiZeroAddress = "0x0000000000000000000000000000000000000000";
79
80
  const xrplZeroAddress = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
80
81
  const stellarZeroAddress = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
82
+ const cantonZeroAddress = "none::12200000000000000000000000000000000000000000000000000000000000000000";
81
83
  const chainTypeToZeroAddressMap = {
82
84
  [squidTypes.ChainType.EVM]: viem.zeroAddress,
83
85
  [squidTypes.ChainType.COSMOS]: cosmosZeroAddress,
@@ -86,6 +88,7 @@ const chainTypeToZeroAddressMap = {
86
88
  [squidTypes.ChainType.SUI]: suiZeroAddress,
87
89
  [squidTypes.ChainType.XRPL]: xrplZeroAddress,
88
90
  [squidTypes.ChainType.STELLAR]: stellarZeroAddress,
91
+ [squidTypes.ChainType.CANTON]: cantonZeroAddress,
89
92
  };
90
93
  const nativeEvmTokenAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
91
94
  const nativeCosmosTokenAddress = "uosmo";
@@ -94,6 +97,7 @@ const nativeBitcoinTokenAddress = "satoshi";
94
97
  const nativeSuiTokenAddress = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
95
98
  const nativeXrplTokenAddress = "xrp";
96
99
  const nativeStellarTokenAddress = "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA";
100
+ const nativeCantonTokenAddress = "DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc";
97
101
  // by setting slippage to undefined, it's set to "auto"
98
102
  const defaultSlippage = undefined;
99
103
  const destinationAddressResetValue = "null";
@@ -102,6 +106,7 @@ const gasRefundMultiplier = 25;
102
106
  const internalSquidApiBaseUrl = "https://app.squidrouter.com/api";
103
107
  const XAMAN_API_URL = `${internalSquidApiBaseUrl}/xaman/`;
104
108
  const TOKEN_PRICE_API_URL = `${internalSquidApiBaseUrl}/coingecko`;
109
+ const CANTON_AMULET_REGISTRY_URL = `${internalSquidApiBaseUrl}/canton/scan-proxy`;
105
110
  const DEFAULT_ROUTE_REFETCH_INTERVAL = 30_000;
106
111
  const SOLANA_RPC_URL = "https://meredith-ute2ko-fast-mainnet.helius-rpc.com";
107
112
  const INTEGRATOR_ID = "squid-widget-playground-local-cd33cba6-7e12-4fcc-8d5d-35e286f655ea";
@@ -157,6 +162,7 @@ const CHAIN_IDS = {
157
162
  XRPL_TESTNET: "xrpl-testnet",
158
163
  STELLAR: "stellar-mainnet",
159
164
  STELLAR_TESTNET: "stellar-testnet",
165
+ CANTON: "canton",
160
166
  };
161
167
  const chainTypeToDefaultChainIdMap = {
162
168
  [squidTypes.ChainType.EVM]: CHAIN_IDS.ETHEREUM,
@@ -166,6 +172,7 @@ const chainTypeToDefaultChainIdMap = {
166
172
  [squidTypes.ChainType.SUI]: CHAIN_IDS.SUI,
167
173
  [squidTypes.ChainType.XRPL]: CHAIN_IDS.XRPL,
168
174
  [squidTypes.ChainType.STELLAR]: CHAIN_IDS.STELLAR,
175
+ [squidTypes.ChainType.CANTON]: CHAIN_IDS.CANTON,
169
176
  };
170
177
  const chainTypeToNativeTokenAddressMap = {
171
178
  [squidTypes.ChainType.EVM]: nativeEvmTokenAddress,
@@ -175,6 +182,7 @@ const chainTypeToNativeTokenAddressMap = {
175
182
  [squidTypes.ChainType.SUI]: nativeSuiTokenAddress,
176
183
  [squidTypes.ChainType.XRPL]: nativeXrplTokenAddress,
177
184
  [squidTypes.ChainType.STELLAR]: nativeStellarTokenAddress,
185
+ [squidTypes.ChainType.CANTON]: nativeCantonTokenAddress,
178
186
  };
179
187
  const defaultConfigValues = {
180
188
  integratorId: INTEGRATOR_ID,
@@ -4730,11 +4738,6 @@ class BitcoinConnectorInvalidAccountError extends BitcoinConnectorError {
4730
4738
  super("Bitcoin account is invalid");
4731
4739
  }
4732
4740
  }
4733
- class BitcoinConnectorFeatureNotSupportedError extends BitcoinConnectorError {
4734
- constructor(providerName, feature) {
4735
- super(`Bitcoin provider ${providerName} does not support ${feature}`);
4736
- }
4737
- }
4738
4741
 
4739
4742
  class KeplrConnector {
4740
4743
  get getProvider() {
@@ -4763,20 +4766,6 @@ class KeplrConnector {
4763
4766
  }
4764
4767
  }
4765
4768
 
4766
- const BitcoinConnect = "bitcoin:connect";
4767
- const BitcoinSignTransaction = "bitcoin:signTransaction";
4768
- const REQUIRED_BITCOIN_FEATURES = [
4769
- BitcoinConnect,
4770
- BitcoinSignTransaction,
4771
- ];
4772
- /**
4773
- * Type guard: the wallet exposes the Bitcoin features this SDK needs (connect +
4774
- * signTransaction). Wallets advertising only a subset are treated as unsupported.
4775
- */
4776
- function hasBitcoinFeatures(wallet) {
4777
- return REQUIRED_BITCOIN_FEATURES.every((feature) => feature in wallet.features);
4778
- }
4779
-
4780
4769
  bitcoin__namespace.initEccLib(ecc__namespace);
4781
4770
  const network = bitcoin__namespace.networks.bitcoin;
4782
4771
  const fromHexString = (hexString) => {
@@ -4866,100 +4855,55 @@ async function getTransactionStatus$1(txHash) {
4866
4855
  }
4867
4856
 
4868
4857
  const MAINNET = bitcoin__namespace.networks.bitcoin;
4869
- /**
4870
- * Bitcoin connector backed by the Bitcoin Wallet Standard.
4871
- *
4872
- * Discovers the wallet from the Wallet Standard registry at call time (mirroring
4873
- * how Solana/Sui wallets are resolved) and connects/signs through the
4874
- * `bitcoin:connect` and `bitcoin:signTransaction` features instead of a
4875
- * wallet-specific injected provider. Configure it with a `walletName` to support
4876
- * any wallet exposing the Bitcoin Wallet Standard — Phantom is the first consumer.
4877
- */
4878
- class BitcoinStandardConnector {
4879
- walletName;
4880
- constructor({ walletName }) {
4881
- this.walletName = walletName;
4882
- }
4883
- getWallet() {
4884
- const wallet = core$1.getWallets()
4885
- .get()
4886
- .find((candidate) => candidate.name.toLowerCase() === this.walletName.toLowerCase());
4887
- if (!wallet) {
4888
- throw new BitcoinConnectorProviderNotFoundError(this.walletName);
4889
- }
4890
- const bitcoinWallet = wallet;
4891
- if (!hasBitcoinFeatures(bitcoinWallet)) {
4892
- throw new BitcoinConnectorFeatureNotSupportedError(this.walletName, "Bitcoin Wallet Standard");
4858
+ class PhantomConnector {
4859
+ get getProvider() {
4860
+ const provider = window?.phantom?.bitcoin;
4861
+ if (!provider) {
4862
+ throw new BitcoinConnectorProviderNotFoundError("Phantom");
4893
4863
  }
4894
- return bitcoinWallet;
4864
+ return provider;
4895
4865
  }
4896
- async connectAccount(purpose) {
4897
- const wallet = this.getWallet();
4898
- const connect = wallet.features[BitcoinConnect]?.connect;
4899
- if (!connect) {
4900
- throw new BitcoinConnectorFeatureNotSupportedError(this.walletName, BitcoinConnect);
4901
- }
4902
- const { accounts } = await connect({ purposes: [purpose] });
4903
- // `purpose` is a user preference, not a guarantee (per Phantom's docs), but
4904
- // requesting a single purpose returns the matching account first.
4905
- const account = accounts[0];
4906
- if (typeof account?.address !== "string") {
4866
+ async requestAccount() {
4867
+ const phantomAccounts = await this.getProvider.requestAccounts();
4868
+ if (!phantomAccounts)
4869
+ throw new BitcoinConnectorInvalidAccountError();
4870
+ const paymentAccount = phantomAccounts.find((account) => account.purpose === "payment");
4871
+ if (typeof paymentAccount?.address !== "string") {
4907
4872
  throw new BitcoinConnectorInvalidAccountError();
4908
4873
  }
4909
- return account;
4910
- }
4911
- async requestAccount() {
4912
- const account = await this.connectAccount("payment");
4913
4874
  return {
4914
- address: account.address,
4875
+ address: paymentAccount.address,
4915
4876
  };
4916
4877
  }
4917
4878
  async sendBTC(to, amount) {
4918
- const account = await this.connectAccount("payment");
4919
- const { psbtHex } = await createSendBtcPsbt(account.address, to, amount);
4920
- const txId = await this.signAndBroadcast(psbtHex, account);
4879
+ const { address } = await this.requestAccount();
4880
+ const { psbtHex } = await createSendBtcPsbt(address, to, amount);
4881
+ const { txId } = await this.signPsbt(psbtHex);
4921
4882
  if (!txId)
4922
4883
  throw new BitcoinConnectorTransactionFailedError();
4923
4884
  return { txHash: txId };
4924
4885
  }
4925
- async signAndBroadcast(psbtHex, account) {
4926
- const wallet = this.getWallet();
4927
- const signTransaction = wallet.features[BitcoinSignTransaction]?.signTransaction;
4928
- if (!signTransaction) {
4929
- throw new BitcoinConnectorFeatureNotSupportedError(this.walletName, BitcoinSignTransaction);
4930
- }
4931
- const unsignedPsbt = bitcoin__namespace.Psbt.fromHex(psbtHex, { network: MAINNET });
4932
- const signingIndexes = unsignedPsbt.data.inputs.map((_, index) => index);
4933
- const [result] = await signTransaction({
4934
- psbt: fromHexString(psbtHex),
4935
- inputsToSign: [
4936
- {
4937
- // All inputs are funded from the payment account.
4938
- account,
4939
- signingIndexes,
4940
- },
4941
- ],
4886
+ async signPsbt(psbtHex) {
4887
+ const { address: paymentAddress } = await this.requestAccount();
4888
+ const toSignPsbt = bitcoin__namespace.Psbt.fromHex(String(psbtHex), {
4889
+ network: MAINNET,
4942
4890
  });
4943
- if (!result?.signedPsbt) {
4944
- throw new BitcoinConnectorTransactionFailedError();
4945
- }
4946
- const signedPsbt = bitcoin__namespace.Psbt.fromBuffer(result.signedPsbt);
4891
+ const inputs = toSignPsbt.data.inputs;
4892
+ const inputsToSign = [
4893
+ {
4894
+ // Need to sign each input with the payment address
4895
+ address: paymentAddress,
4896
+ signingIndexes: inputs.map((_, index) => index),
4897
+ },
4898
+ ];
4899
+ const signedPsbtBytes = await this.getProvider.signPSBT(fromHexString(psbtHex), {
4900
+ inputsToSign,
4901
+ });
4902
+ const signedPsbt = bitcoin__namespace.Psbt.fromBuffer(signedPsbtBytes);
4947
4903
  signedPsbt.finalizeAllInputs();
4948
4904
  const tx = signedPsbt.extractTransaction();
4949
- return broadcastTx(tx.toHex());
4950
- }
4951
- }
4952
-
4953
- /**
4954
- * Phantom Bitcoin connector via the Bitcoin Wallet Standard.
4955
- *
4956
- * Phantom deprecated the injected `window.phantom.bitcoin` provider in favour of
4957
- * the Wallet Standard; this resolves Phantom from the registry by name and signs
4958
- * through the standard Bitcoin features. See {@link BitcoinStandardConnector}.
4959
- */
4960
- class PhantomConnector extends BitcoinStandardConnector {
4961
- constructor() {
4962
- super({ walletName: "Phantom" });
4905
+ const txId = await broadcastTx(tx.toHex());
4906
+ return { txId };
4963
4907
  }
4964
4908
  }
4965
4909
 
@@ -20621,6 +20565,17 @@ exports.WindowWalletFlag = void 0;
20621
20565
  })(exports.WindowWalletFlag || (exports.WindowWalletFlag = {}));
20622
20566
 
20623
20567
  const walletIconBaseUrl = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/wallets";
20568
+ /**
20569
+ * Dynamically accesses a nested property of an object based on a dot-separated string path.
20570
+ * Returns the value of the property if found, otherwise undefined.
20571
+ */
20572
+ const accessProperty = (object, path) => {
20573
+ const value = get$2(object, path);
20574
+ if (value === undefined) {
20575
+ console.error(`Property "${path}" not found while reading object`, object);
20576
+ }
20577
+ return value;
20578
+ };
20624
20579
  const bitcoinWallets = [
20625
20580
  {
20626
20581
  name: "Unisat",
@@ -20917,6 +20872,34 @@ const walletStoreLinks = {
20917
20872
  },
20918
20873
  };
20919
20874
 
20875
+ /**
20876
+ * Wallets to show regardless of whether they're detected.
20877
+ * Useful when we want to link to the browser extension store
20878
+ * for wallets that are automatically discovered (i.e. EVM, SOLANA, CANTON...)
20879
+ */
20880
+ const fallbackWallets = [
20881
+ {
20882
+ chainType: squidTypes.ChainType.CANTON,
20883
+ id: "ldmohiccoioolenadmogclhoklmanpgi",
20884
+ name: "Send Connect",
20885
+ connectorName: "Send Connect",
20886
+ icon: `${walletIconBaseUrl}/canton-send.webp`,
20887
+ links: {
20888
+ chrome: "https://chromewebstore.google.com/detail/send-connect/ldmohiccoioolenadmogclhoklmanpgi",
20889
+ },
20890
+ },
20891
+ {
20892
+ chainType: squidTypes.ChainType.CANTON,
20893
+ id: "lpnfhpbpmlobjlgkdmnjieeihjmihhjd",
20894
+ name: "Console Wallet",
20895
+ connectorName: "Console Wallet",
20896
+ icon: `${walletIconBaseUrl}/canton-console.webp`,
20897
+ links: {
20898
+ chrome: "https://chromewebstore.google.com/detail/console-wallet/lpnfhpbpmlobjlgkdmnjieeihjmihhjd",
20899
+ },
20900
+ },
20901
+ ];
20902
+
20920
20903
  // Validation taken from Squid API repo
20921
20904
  const isBitcoinAddressValid = (address) => {
20922
20905
  try {
@@ -20936,6 +20919,142 @@ const isBitcoinAddressValid = (address) => {
20936
20919
  }
20937
20920
  };
20938
20921
 
20922
+ // Canton PartyID = address
20923
+ const CANTON_PARTY_ID_SEPARATOR = "::";
20924
+ /** Canton Coin's well-known token-standard instrument id (its address carries no id prefix). */
20925
+ const CANTON_AMULET_INSTRUMENT_ID = "Amulet";
20926
+ function isCantonAddressValid(address) {
20927
+ // Canton address format: `name::fingerprint`, where name is an arbitrary string
20928
+ // and fingerprint is a 64-character hex string with a 1220 prefix (SHA-256 hash of the public key)
20929
+ const parts = address.split(CANTON_PARTY_ID_SEPARATOR);
20930
+ if (parts.length !== 2)
20931
+ return false;
20932
+ const [name, fingerprint] = parts;
20933
+ return name.length > 0 && /^1220[0-9a-f]{64}$/.test(fingerprint);
20934
+ }
20935
+ /**
20936
+ * Splice token-standard Holding interface id. A party's balance for an
20937
+ * instrument is the sum of `amount` across active contracts implementing this interface.
20938
+ */
20939
+ const CANTON_HOLDING_INTERFACE_ID = "#splice-api-token-holding-v1:Splice.Api.Token.HoldingV1:Holding";
20940
+ /**
20941
+ * Derive the token-standard instrument `{ admin, id }` from a Squid Canton token
20942
+ * address (use the case-sensitive `originalAddress`), or `null` when the address
20943
+ * is not a valid Canton token address.
20944
+ *
20945
+ * The admin party is the last two `::` segments (`name::fingerprint`); the
20946
+ * instrument id is everything before that. Canton Coin has no id prefix
20947
+ * (`DSO::1220…`) and uses the well-known id `Amulet`.
20948
+ * - `DSO::1220…` -> { admin: "DSO::1220…", id: "Amulet" }
20949
+ * - `USDCx::decentralized-usdc-…::12208…` -> { admin: "decentralized-usdc-…::12208…", id: "USDCx" }
20950
+ */
20951
+ function parseCantonInstrument(address) {
20952
+ const segments = address.split(CANTON_PARTY_ID_SEPARATOR);
20953
+ if (segments.length < 2) {
20954
+ return null;
20955
+ }
20956
+ const admin = segments.slice(-2).join(CANTON_PARTY_ID_SEPARATOR);
20957
+ const idPrefix = segments.slice(0, -2).join(CANTON_PARTY_ID_SEPARATOR);
20958
+ return {
20959
+ admin,
20960
+ id: idPrefix.length > 0 ? idPrefix : CANTON_AMULET_INSTRUMENT_ID,
20961
+ };
20962
+ }
20963
+ /**
20964
+ * Body for `POST /v2/state/active-contracts`, filtered to the party's Holding
20965
+ * contracts with the interface view included (so we can read amount/instrument).
20966
+ *
20967
+ * ACS: Active Contract Set — the ledger's currently-active contracts (created and
20968
+ * not yet archived) as of a ledger offset.
20969
+ */
20970
+ function buildHoldingsAcsRequestBody(partyId, activeAtOffset) {
20971
+ return {
20972
+ activeAtOffset,
20973
+ eventFormat: {
20974
+ verbose: true,
20975
+ filtersByParty: {
20976
+ [partyId]: {
20977
+ cumulative: [
20978
+ {
20979
+ identifierFilter: {
20980
+ InterfaceFilter: {
20981
+ value: {
20982
+ interfaceId: CANTON_HOLDING_INTERFACE_ID,
20983
+ includeInterfaceView: true,
20984
+ includeCreatedEventBlob: false,
20985
+ },
20986
+ },
20987
+ },
20988
+ },
20989
+ ],
20990
+ },
20991
+ },
20992
+ },
20993
+ };
20994
+ }
20995
+ /**
20996
+ * Parse the party's Holding contracts (with contract ids) from a raw
20997
+ * `/v2/state/active-contracts` response
20998
+ * Defensive: skips entries it can't parse.
20999
+ */
21000
+ function parseCantonHoldings(acsResponse) {
21001
+ if (!Array.isArray(acsResponse))
21002
+ return [];
21003
+ const holdings = [];
21004
+ for (const entry of acsResponse) {
21005
+ const createdEvent = entry?.contractEntry?.JsActiveContract
21006
+ ?.createdEvent;
21007
+ const contractId = createdEvent?.contractId;
21008
+ const views = createdEvent?.interfaceViews;
21009
+ if (!contractId || !Array.isArray(views))
21010
+ continue;
21011
+ for (const view of views) {
21012
+ const value = view?.viewValue;
21013
+ const instrumentId = value?.instrumentId;
21014
+ if (!instrumentId?.admin ||
21015
+ instrumentId.id == null ||
21016
+ value.amount == null) {
21017
+ continue;
21018
+ }
21019
+ holdings.push({
21020
+ contractId,
21021
+ instrument: { admin: instrumentId.admin, id: instrumentId.id },
21022
+ amount: String(value.amount),
21023
+ // Locked holdings are not spendable, skip them
21024
+ locked: value.lock != null,
21025
+ });
21026
+ }
21027
+ }
21028
+ return holdings;
21029
+ }
21030
+ /**
21031
+ * Key used to group holdings by instrument.
21032
+ */
21033
+ function instrumentKey(admin, id) {
21034
+ return `${admin}|${id}`;
21035
+ }
21036
+ function cantonInstrumentKey(instrument) {
21037
+ return instrumentKey(instrument.admin, instrument.id);
21038
+ }
21039
+ /**
21040
+ * Group the (unlocked) Holding amounts by instrument from a raw
21041
+ * `/v2/state/active-contracts` response. Returns a map of instrument key
21042
+ * (`admin|id`) -> human-readable decimal string (the token-standard `amount`
21043
+ * is already a Decimal, not base units).
21044
+ */
21045
+ function groupCantonHoldingBalances(acsResponse) {
21046
+ const totals = {};
21047
+ for (const holding of parseCantonHoldings(acsResponse)) {
21048
+ // Locked holdings are not spendable, skip them
21049
+ if (holding.locked)
21050
+ continue;
21051
+ const key = cantonInstrumentKey(holding.instrument);
21052
+ const total = totals[key] ?? new BigNumber(0);
21053
+ totals[key] = total.plus(new BigNumber(holding.amount));
21054
+ }
21055
+ return Object.fromEntries(Object.entries(totals).map(([key, total]) => [key, total.toString(10)]));
21056
+ }
21057
+
20939
21058
  const solanaTokenProgramIdByAddress = {
20940
21059
  [splToken.TOKEN_PROGRAM_ID.toBase58()]: splToken.TOKEN_PROGRAM_ID,
20941
21060
  [splToken.TOKEN_2022_PROGRAM_ID.toBase58()]: splToken.TOKEN_2022_PROGRAM_ID,
@@ -21075,6 +21194,7 @@ const getSourceExplorerTxUrl = (chain, txID) => {
21075
21194
  case CHAIN_IDS.AGORIC:
21076
21195
  case CHAIN_IDS.XRPL:
21077
21196
  case CHAIN_IDS.XRPL_TESTNET:
21197
+ case CHAIN_IDS.CANTON:
21078
21198
  txSuffix = "/transactions/";
21079
21199
  break;
21080
21200
  case CHAIN_IDS.HEDERA:
@@ -21184,10 +21304,16 @@ const simplifyRouteAction = (action) => {
21184
21304
  };
21185
21305
  const fetchSwapTransactionStatus = async ({ transaction, integratorId, apiUrl, }) => {
21186
21306
  const statusEndpoint = `${apiUrl}/v2/status`;
21307
+ const isCanton = transaction?.fromChain === CHAIN_IDS.CANTON;
21308
+ // For Canton, the backend handles all tx detection/submission from the quoteId
21309
+ // alone, so no transactionId is sent — only the quoteId param below.
21310
+ const transactionId = isCanton
21311
+ ? undefined
21312
+ : (transaction?.transactionIdForStatus ?? transaction?.transactionId);
21187
21313
  try {
21188
21314
  const response = await axios.get(statusEndpoint, {
21189
21315
  params: {
21190
- transactionId: transaction?.transactionIdForStatus ?? transaction?.transactionId,
21316
+ transactionId,
21191
21317
  fromChainId: transaction?.fromChain,
21192
21318
  toChainId: transaction?.toChain,
21193
21319
  bridgeType: transaction?.bridgeType,
@@ -21234,7 +21360,7 @@ function isActionCompletedOnSourceTx(action, fromChainId) {
21234
21360
  function sleep(ms) {
21235
21361
  return new Promise((resolve) => setTimeout(resolve, ms));
21236
21362
  }
21237
- const isDepositRoute = (route) => {
21363
+ const isChainflipDepositRoute = (route) => {
21238
21364
  return (!!route &&
21239
21365
  route.transactionRequest?.type === squidTypes.SquidDataType.ChainflipDepositAddress);
21240
21366
  };
@@ -21259,6 +21385,12 @@ function isOnChainTxData(squidData) {
21259
21385
  squidTypes.SquidDataType.DepositAddressWithMemo,
21260
21386
  ].includes(squidData.type);
21261
21387
  }
21388
+ /**
21389
+ * Checks if a route is of type DepositAddressDirectTransfer
21390
+ */
21391
+ function isDepositAddressDirectTransferRoute(squidData) {
21392
+ return squidData.type === squidTypes.SquidDataType.DepositAddressDirectTransfer;
21393
+ }
21262
21394
  function getHistoryTransactionId(tx) {
21263
21395
  switch (tx.txType) {
21264
21396
  case exports.HistoryTxType.SWAP:
@@ -21778,7 +21910,17 @@ const chainTypeToTrimLength = {
21778
21910
  start: 4,
21779
21911
  end: 4,
21780
21912
  },
21913
+ // abc...123::abc...123
21914
+ [squidTypes.ChainType.CANTON]: {
21915
+ start: 3,
21916
+ end: 3,
21917
+ },
21781
21918
  };
21919
+ const truncateWithEllipsis = (value, startLength, endLength) => value.length <= startLength + endLength
21920
+ ? value
21921
+ : value.slice(0, startLength) +
21922
+ "..." +
21923
+ value.slice(value.length - endLength);
21782
21924
  const formatHash = ({ chainType, hash }) => {
21783
21925
  if (!hash)
21784
21926
  return "";
@@ -21791,14 +21933,15 @@ const formatHash = ({ chainType, hash }) => {
21791
21933
  chainTypeFormat = squidTypes.ChainType.COSMOS;
21792
21934
  }
21793
21935
  }
21794
- const trimLengthStart = chainTypeToTrimLength[chainTypeFormat].start;
21795
- const trimLengthEnd = chainTypeToTrimLength[chainTypeFormat].end;
21796
- // return the same hash if its length is less than the trim length
21797
- if (hash.length <= trimLengthStart + trimLengthEnd)
21798
- return hash;
21799
- return (hash.slice(0, trimLengthStart) +
21800
- "..." +
21801
- hash.slice(hash.length - trimLengthEnd, hash.length));
21936
+ const { start, end } = chainTypeToTrimLength[chainTypeFormat];
21937
+ if (chainTypeFormat === squidTypes.ChainType.CANTON &&
21938
+ hash.includes(CANTON_PARTY_ID_SEPARATOR)) {
21939
+ const [namespace, identifier] = hash.split(CANTON_PARTY_ID_SEPARATOR);
21940
+ return (truncateWithEllipsis(namespace, start, end) +
21941
+ CANTON_PARTY_ID_SEPARATOR +
21942
+ truncateWithEllipsis(identifier, start, end));
21943
+ }
21944
+ return truncateWithEllipsis(hash, start, end);
21802
21945
  };
21803
21946
  const isWalletAddressValid = (chainData, address) => {
21804
21947
  if (!address || !chainData?.chainType)
@@ -21818,33 +21961,25 @@ const isWalletAddressValid = (chainData, address) => {
21818
21961
  return isXrplAddressValid(address);
21819
21962
  case squidTypes.ChainType.STELLAR:
21820
21963
  return isStellarAddressValid(address);
21964
+ case squidTypes.ChainType.CANTON:
21965
+ return isCantonAddressValid(address);
21821
21966
  }
21822
21967
  };
21823
21968
  const redirectToExtensionsStore = (wallet) => {
21824
21969
  const { userAgent } = navigator;
21825
21970
  let link;
21826
21971
  if (userAgent.indexOf("Firefox") > -1) {
21827
- link = wallet.url || walletStoreLinks[wallet.connectorId]?.firefox;
21972
+ link =
21973
+ wallet.links?.firefox || walletStoreLinks[wallet.connectorId]?.firefox;
21828
21974
  }
21829
21975
  else if (userAgent.indexOf("Chrome") > -1) {
21830
- link = wallet.url || walletStoreLinks[wallet.connectorId]?.chrome;
21976
+ link = wallet.links?.chrome || walletStoreLinks[wallet.connectorId]?.chrome;
21831
21977
  }
21978
+ link = link || wallet.links?.website;
21832
21979
  if (link && link !== "") {
21833
21980
  window?.open(link, "_blank")?.focus();
21834
21981
  }
21835
21982
  };
21836
- /**
21837
- * Dynamically accesses a nested property of an object based on a dot-separated string path.
21838
- * Returns the value of the property if found, otherwise undefined.
21839
- * e.g. "xfi.keplr" will return window.xfi.keplr
21840
- */
21841
- const accessProperty = (object, path) => {
21842
- const value = get$2(object, path);
21843
- if (value === undefined) {
21844
- console.error(`Property "${path}" not found while reading object`, object);
21845
- }
21846
- return value;
21847
- };
21848
21983
  const definedInWindow = (path, clientWindow) => {
21849
21984
  if (!path || !clientWindow)
21850
21985
  return false;
@@ -21873,6 +22008,32 @@ const populateWallets = (window, wallets) => {
21873
22008
  return wallet;
21874
22009
  });
21875
22010
  };
22011
+ const createUninstalledConnector = () => new Proxy({}, {
22012
+ get(_target, prop) {
22013
+ throw new Error(`Cannot use connector of an uninstalled wallet (accessed "${String(prop)}")`);
22014
+ },
22015
+ });
22016
+ const buildFallbackWallets = (discovered) => {
22017
+ const fallbackKey = (chainType, connectorId) => `${chainType}:${connectorId}`;
22018
+ const discoveredKeys = new Set(discovered.flatMap((wallet) => wallet.isMultiChain
22019
+ ? wallet.supportedNetworks.map((network) => fallbackKey(network.chainType, wallet.connectorId))
22020
+ : [fallbackKey(wallet.type, wallet.connectorId)]));
22021
+ return fallbackWallets
22022
+ .filter((config) => !discoveredKeys.has(fallbackKey(config.chainType, config.id)))
22023
+ .map((config) => ({
22024
+ name: config.name,
22025
+ connectorId: config.id,
22026
+ connectorName: config.connectorName,
22027
+ icon: config.icon,
22028
+ windowFlag: config.id,
22029
+ links: config.links,
22030
+ isInstalled: () => false,
22031
+ skipInstallCheck: false,
22032
+ isMultiChain: false,
22033
+ type: config.chainType,
22034
+ connector: createUninstalledConnector(),
22035
+ }));
22036
+ };
21876
22037
  /**
21877
22038
  * Get the base chain to connect to
21878
22039
  * If only one chain type is selected, use that chain type
@@ -22079,6 +22240,13 @@ const connectByChainType = async (chainType, wallet, defaultChain, params) => {
22079
22240
  connector,
22080
22241
  },
22081
22242
  });
22243
+ case squidTypes.ChainType.CANTON:
22244
+ return params.connectCanton.mutateAsync({
22245
+ wallet: {
22246
+ ...wallet,
22247
+ connector,
22248
+ },
22249
+ });
22082
22250
  }
22083
22251
  };
22084
22252
  const getChainTypesToConnect = (selectedChainTypes, defaultChain, supportedChains) => {
@@ -22115,6 +22283,7 @@ const connectMultiChainWallet = async (params) => {
22115
22283
  connectSui: params.connectSui,
22116
22284
  connectXrpl: params.connectXrpl,
22117
22285
  connectStellar: params.connectStellar,
22286
+ connectCanton: params.connectCanton,
22118
22287
  });
22119
22288
  if (result) {
22120
22289
  results.push({
@@ -22148,6 +22317,7 @@ const connectSingleChainWallet = async (params) => {
22148
22317
  connectSui: params.connectSui,
22149
22318
  connectXrpl: params.connectXrpl,
22150
22319
  connectStellar: params.connectStellar,
22320
+ connectCanton: params.connectCanton,
22151
22321
  });
22152
22322
  return result
22153
22323
  ? {
@@ -23061,7 +23231,7 @@ const handleDestinationAddressOnSwapChange = ({ fromChainId, fromTokenAddress, t
23061
23231
  });
23062
23232
  let destinationTokenAddress = toChainId && !toTokenAddress
23063
23233
  ? defaultToAddress
23064
- : toTokenAddress ?? swapRoute?.toTokenAddress;
23234
+ : (toTokenAddress ?? swapRoute?.toTokenAddress);
23065
23235
  const lowerCaseDestinationTokenAddress = destinationTokenAddress?.toLowerCase();
23066
23236
  if (destinationTokensFiltered.find((t) => t.address === lowerCaseDestinationTokenAddress) === undefined) {
23067
23237
  destinationTokenAddress = defaultToAddress;
@@ -23113,7 +23283,7 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
23113
23283
  toTokenAddress === initialSwapRoute?.fromTokenAddress;
23114
23284
  const sourceTokenAddress = sameNewDestAndInitialSource || onlySourceChainIdChanged
23115
23285
  ? defaultFromAddress
23116
- : fromTokenAddress ?? initialSwapRoute?.fromTokenAddress;
23286
+ : (fromTokenAddress ?? initialSwapRoute?.fromTokenAddress);
23117
23287
  let destinationTokenAddress = undefined;
23118
23288
  if (!sameNewSourceAndInitialDest) {
23119
23289
  if (onlySourceChainIdChanged) {
@@ -23153,7 +23323,10 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
23153
23323
  else {
23154
23324
  newFallbackAddress = fallbackAddress ?? initialSwapRoute?.fallbackAddress;
23155
23325
  }
23156
- const newDepositRefundAddress = depositRefundAddress || initialSwapRoute?.depositRefundAddress;
23326
+ const sourceChainChanged = fromChainId !== undefined && fromChainId !== initialSwapRoute?.fromChainId;
23327
+ const newDepositRefundAddress = sourceChainChanged
23328
+ ? undefined
23329
+ : depositRefundAddress || initialSwapRoute?.depositRefundAddress;
23157
23330
  return {
23158
23331
  fromChainId: srcChainId,
23159
23332
  fromTokenAddress: sourceTokenAddress,
@@ -23432,7 +23605,7 @@ const filterViewableTokens = (tokens, config, direction) => {
23432
23605
  };
23433
23606
  const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
23434
23607
  const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
23435
- const { fetchAllSecretBalances } = await Promise.resolve().then(function () { return require('./secretService-C3jMjsK0.js'); });
23608
+ const { fetchAllSecretBalances } = await Promise.resolve().then(function () { return require('./secretService-ICina23f.js'); });
23436
23609
  return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
23437
23610
  };
23438
23611
  function getTokenAssetsKey(token) {
@@ -23459,9 +23632,29 @@ async function fetchAssetsColors() {
23459
23632
  };
23460
23633
  }
23461
23634
  }
23462
- function initializeSquidWithAssetsColors(squid, assetsColors) {
23463
- const evmosChainIds = squid.chains.filter(isEvmosChain).map((c) => c.chainId);
23464
- squid.tokens = squid.tokens.map((token) => {
23635
+ const supportedChainTypes = new Set(Object.values(squidTypes.ChainType));
23636
+ function isSupportedChainType(chainType) {
23637
+ return supportedChainTypes.has(chainType);
23638
+ }
23639
+ /**
23640
+ * Normalizes SDK data after each init/refetch before the rest of hooks consumes it.
23641
+ *
23642
+ * - Removes chains whose chainType is not supported by the local package.
23643
+ * - Drops tokens for those removed chains.
23644
+ * - Converts Evmos chains/tokens to EVM.
23645
+ * - Applies optional asset colors.
23646
+ */
23647
+ function initializeSquidData(squid, assetsColors = {
23648
+ chains: {},
23649
+ tokens: {},
23650
+ }) {
23651
+ const supportedChains = squid.chains.filter((chain) => isSupportedChainType(chain.chainType));
23652
+ const supportedChainIds = new Set(supportedChains.map((chain) => chain.chainId));
23653
+ const evmosChainIds = supportedChains
23654
+ .filter(isEvmosChain)
23655
+ .map((c) => c.chainId);
23656
+ const supportedTokens = squid.tokens.filter((token) => supportedChainIds.has(token.chainId));
23657
+ squid.tokens = supportedTokens.map((token) => {
23465
23658
  const isEvmosToken = evmosChainIds.includes(token.chainId);
23466
23659
  return {
23467
23660
  ...token,
@@ -23470,7 +23663,7 @@ function initializeSquidWithAssetsColors(squid, assetsColors) {
23470
23663
  textColor: assetsColors.tokens[getTokenAssetsKey(token)]?.textColor,
23471
23664
  };
23472
23665
  });
23473
- squid.chains = squid.chains.map((chain) => {
23666
+ squid.chains = supportedChains.map((chain) => {
23474
23667
  const bgColor = assetsColors.chains[chain.chainId]?.bgColor;
23475
23668
  // convert evmos cosmos chains to evm chains
23476
23669
  // TODO: this will be fixed in the backend
@@ -25123,7 +25316,7 @@ class OnrampService {
25123
25316
  });
25124
25317
  return data;
25125
25318
  }
25126
- async getConfiguration({ chains, tokens, }) {
25319
+ async getConfiguration({ tokens, }) {
25127
25320
  const { data } = await axios.get(`${this.baseUrl}/config`);
25128
25321
  // Filter supportedCryptos to only include tokens that match our provided tokens
25129
25322
  const filteredCryptos = data.supportedCryptos.filter((supportedCrypto) => tokens.some((token) => token.address.toLowerCase() ===
@@ -25347,7 +25540,7 @@ const useSquid = () => {
25347
25540
  queryFn: async () => {
25348
25541
  if (squid) {
25349
25542
  await squid?.init();
25350
- initializeSquidWithAssetsColors(squid, assetsColors);
25543
+ initializeSquidData(squid, assetsColors);
25351
25544
  return squid;
25352
25545
  }
25353
25546
  return null;
@@ -25406,7 +25599,7 @@ const useSquidTokens = (direction) => {
25406
25599
  config.availableChains,
25407
25600
  direction,
25408
25601
  ]);
25409
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = React.useMemo(() => {
25602
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = React.useMemo(() => {
25410
25603
  return tokens?.reduce((acc, token) => {
25411
25604
  switch (token.type) {
25412
25605
  case squidTypes.ChainType.EVM:
@@ -25430,6 +25623,9 @@ const useSquidTokens = (direction) => {
25430
25623
  case squidTypes.ChainType.STELLAR:
25431
25624
  acc.stellarTokens.push(token);
25432
25625
  break;
25626
+ case squidTypes.ChainType.CANTON:
25627
+ acc.cantonTokens.push(token);
25628
+ break;
25433
25629
  }
25434
25630
  return acc;
25435
25631
  }, {
@@ -25440,6 +25636,7 @@ const useSquidTokens = (direction) => {
25440
25636
  suiTokens: [],
25441
25637
  xrplTokens: [],
25442
25638
  stellarTokens: [],
25639
+ cantonTokens: [],
25443
25640
  });
25444
25641
  }, [tokens]);
25445
25642
  const findToken = React.useCallback((address, chainId) => {
@@ -25457,6 +25654,7 @@ const useSquidTokens = (direction) => {
25457
25654
  suiTokens,
25458
25655
  xrplTokens,
25459
25656
  stellarTokens,
25657
+ cantonTokens,
25460
25658
  };
25461
25659
  };
25462
25660
 
@@ -25557,12 +25755,10 @@ const useGetFiatQuote = ({ fiatCurrency, cryptoCurrencyID, amount, region, payme
25557
25755
  */
25558
25756
  const useGetOnRampConfig = () => {
25559
25757
  const service = React.useMemo(() => new OnrampService(), []);
25560
- const { chains } = useSquidChains();
25561
25758
  const { tokens } = useSquidTokens();
25562
25759
  return reactQuery.useQuery({
25563
25760
  queryKey: keys().fiatToCryptoConfig(),
25564
25761
  queryFn: () => service.getConfiguration({
25565
- chains,
25566
25762
  tokens,
25567
25763
  }),
25568
25764
  cacheTime: 1000 * 60 * 60,
@@ -25994,6 +26190,7 @@ const chainTypeToRefetchInterval = {
25994
26190
  [squidTypes.ChainType.SUI]: 1_000,
25995
26191
  [squidTypes.ChainType.XRPL]: 1_000,
25996
26192
  [squidTypes.ChainType.STELLAR]: 1_000,
26193
+ [squidTypes.ChainType.CANTON]: 1_000,
25997
26194
  };
25998
26195
  /**
25999
26196
  * Returns the status refetch interval of a Send transaction
@@ -26260,7 +26457,7 @@ const useSquidChains = (direction) => {
26260
26457
  const chain = findChain(chainId);
26261
26458
  return chain?.chainType;
26262
26459
  }, [findChain]);
26263
- const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains } = React.useMemo(() => {
26460
+ const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains, cantonChains, } = React.useMemo(() => {
26264
26461
  return chains.reduce((acc, chain) => {
26265
26462
  switch (chain.chainType) {
26266
26463
  case squidTypes.ChainType.EVM:
@@ -26278,6 +26475,9 @@ const useSquidChains = (direction) => {
26278
26475
  case squidTypes.ChainType.STELLAR:
26279
26476
  acc.stellarChains.push(chain);
26280
26477
  break;
26478
+ case squidTypes.ChainType.CANTON:
26479
+ acc.cantonChains.push(chain);
26480
+ break;
26281
26481
  }
26282
26482
  return acc;
26283
26483
  }, {
@@ -26286,6 +26486,7 @@ const useSquidChains = (direction) => {
26286
26486
  suiChains: [],
26287
26487
  xrplChains: [],
26288
26488
  stellarChains: [],
26489
+ cantonChains: [],
26289
26490
  });
26290
26491
  }, [chains]);
26291
26492
  const { supportedSourceChains, supportedDestinationChains } = React.useMemo(() => {
@@ -26306,6 +26507,7 @@ const useSquidChains = (direction) => {
26306
26507
  suiChains,
26307
26508
  xrplChains,
26308
26509
  stellarChains,
26510
+ cantonChains,
26309
26511
  getChainType,
26310
26512
  findChain,
26311
26513
  };
@@ -26619,6 +26821,253 @@ const useBitcoinContext = () => {
26619
26821
  return context;
26620
26822
  };
26621
26823
 
26824
+ const REQUEST_TIMEOUT_MS = 60_000;
26825
+ function pickAddress(accounts) {
26826
+ return (accounts.find((a) => a.primary) ?? accounts[0])?.partyId;
26827
+ }
26828
+ /**
26829
+ * Browser-extension Canton connector: wraps one discovered CIP-103 provider
26830
+ * (bound to its announce `target`) and exposes the lifecycle methods.
26831
+ */
26832
+ class CantonBrowserConnector {
26833
+ providerId;
26834
+ name;
26835
+ target;
26836
+ client;
26837
+ listeners = { connect: new Set(), disconnect: new Set() };
26838
+ _accounts = [];
26839
+ constructor(provider, win = window) {
26840
+ this.providerId = provider.id;
26841
+ this.name = provider.name;
26842
+ this.target = provider.target ?? provider.id;
26843
+ this.client = dapp.createCantonClient(new dapp.WindowTransport(win, {
26844
+ target: this.target,
26845
+ timeout: REQUEST_TIMEOUT_MS,
26846
+ }));
26847
+ }
26848
+ get accounts() {
26849
+ return this._accounts;
26850
+ }
26851
+ get address() {
26852
+ return pickAddress(this._accounts);
26853
+ }
26854
+ async connect() {
26855
+ await this.client.connect();
26856
+ const result = await this.refreshAccounts();
26857
+ this.emit("connect", result.address);
26858
+ return result;
26859
+ }
26860
+ /** Silent connect: read accounts without prompting; throws if not connected. */
26861
+ async autoConnect() {
26862
+ const accounts = await this.client.listAccounts();
26863
+ if (!accounts.length) {
26864
+ throw new Error("Canton wallet not connected");
26865
+ }
26866
+ this._accounts = accounts;
26867
+ const address = pickAddress(accounts);
26868
+ this.emit("connect", address);
26869
+ return { address, accounts };
26870
+ }
26871
+ async disconnect() {
26872
+ try {
26873
+ await this.client.disconnect();
26874
+ }
26875
+ finally {
26876
+ this._accounts = [];
26877
+ this.emit("disconnect");
26878
+ }
26879
+ }
26880
+ async ledgerApi(params) {
26881
+ const result = await this.client.ledgerApi(params);
26882
+ return result;
26883
+ }
26884
+ async prepareExecuteAndWait(params) {
26885
+ return this.client.prepareExecuteAndWait(params);
26886
+ }
26887
+ async getAccounts() {
26888
+ this._accounts = await this.client.listAccounts();
26889
+ return this._accounts;
26890
+ }
26891
+ on(event, handler) {
26892
+ this.listeners[event].add(handler);
26893
+ }
26894
+ off(event, handler) {
26895
+ this.listeners[event].delete(handler);
26896
+ }
26897
+ emit(event, ...args) {
26898
+ this.listeners[event].forEach((handler) => handler(...args));
26899
+ }
26900
+ async refreshAccounts() {
26901
+ const accounts = await this.client.listAccounts();
26902
+ this._accounts = accounts;
26903
+ const address = pickAddress(accounts);
26904
+ if (!address) {
26905
+ throw new Error("Canton wallet returned no accounts");
26906
+ }
26907
+ return { address, accounts };
26908
+ }
26909
+ }
26910
+
26911
+ const CANTON_REQUEST_PROVIDER_EVENT = "canton:requestProvider";
26912
+ const CANTON_ANNOUNCE_PROVIDER_EVENT = "canton:announceProvider";
26913
+ const DEFAULT_DISCOVERY_TIMEOUT_MS = 300;
26914
+ /**
26915
+ * CIP-103 browser-wallet discovery (EIP-6963-style).
26916
+ * The wallet dispatches `canton:announceProvider` and dApps
26917
+ * dispatch `canton:requestProvider` to ask installed wallets to re-announce.
26918
+ * Each announcement carries a `target` we route through Sigilry's `WindowTransport`,
26919
+ * so multiple extensions coexist without contending on the `window.canton` global.
26920
+ */
26921
+ async function discoverCantonProviders(timeoutMs = DEFAULT_DISCOVERY_TIMEOUT_MS, win = window) {
26922
+ if (typeof win === "undefined")
26923
+ return [];
26924
+ const discovered = new Map();
26925
+ const handler = (event) => {
26926
+ const detail = event.detail;
26927
+ if (!detail?.id || !detail.name || discovered.has(detail.id))
26928
+ return;
26929
+ discovered.set(detail.id, {
26930
+ id: detail.id,
26931
+ name: detail.name,
26932
+ icon: detail.icon,
26933
+ target: detail.target ?? detail.id,
26934
+ });
26935
+ };
26936
+ win.addEventListener(CANTON_ANNOUNCE_PROVIDER_EVENT, handler);
26937
+ try {
26938
+ win.dispatchEvent(new CustomEvent(CANTON_REQUEST_PROVIDER_EVENT, { detail: {} }));
26939
+ await new Promise((resolve) => setTimeout(resolve, timeoutMs));
26940
+ }
26941
+ finally {
26942
+ win.removeEventListener(CANTON_ANNOUNCE_PROVIDER_EVENT, handler);
26943
+ }
26944
+ return Array.from(discovered.values());
26945
+ }
26946
+
26947
+ /**
26948
+ * Discovers Canton browser-extension wallets via the CIP-103 announce protocol
26949
+ * (on mount and on window focus) and maps each to a {@link CantonWallet}.
26950
+ */
26951
+ function useCantonWallets() {
26952
+ const [wallets, setWallets] = React.useState([]);
26953
+ const connectorCache = React.useRef(new Map());
26954
+ const toWallet = React.useCallback((provider) => {
26955
+ let connector = connectorCache.current.get(provider.id);
26956
+ if (!connector) {
26957
+ connector = new CantonBrowserConnector(provider);
26958
+ connectorCache.current.set(provider.id, connector);
26959
+ }
26960
+ return {
26961
+ name: provider.name,
26962
+ connectorId: provider.id,
26963
+ connectorName: provider.name,
26964
+ icon: provider.icon,
26965
+ windowFlag: provider.id,
26966
+ skipInstallCheck: true,
26967
+ isInstalled: () => true,
26968
+ isMultiChain: false,
26969
+ type: squidTypes.ChainType.CANTON,
26970
+ connector,
26971
+ };
26972
+ }, []);
26973
+ const refresh = React.useCallback(async () => {
26974
+ if (typeof window === "undefined")
26975
+ return;
26976
+ const providers = await discoverCantonProviders();
26977
+ setWallets(providers.map(toWallet));
26978
+ }, [toWallet]);
26979
+ React.useEffect(() => {
26980
+ refresh();
26981
+ if (typeof window === "undefined")
26982
+ return;
26983
+ const onFocus = () => refresh();
26984
+ window.addEventListener("focus", onFocus);
26985
+ return () => window.removeEventListener("focus", onFocus);
26986
+ }, [refresh]);
26987
+ return { wallets };
26988
+ }
26989
+
26990
+ function useCanton() {
26991
+ const disconnectWallet = useWalletStore((store) => store.disconnectWallet);
26992
+ const setConnectedWallet = useWalletStore((store) => store.setConnectedWallet);
26993
+ const { wallets } = useCantonWallets();
26994
+ const connectedCantonWallet = useWalletStore((store) => store.connectedWalletsByChainType[squidTypes.ChainType.CANTON]);
26995
+ const recentCantonWalletId = useWalletStore((store) => store.recentConnectorIds[squidTypes.ChainType.CANTON]);
26996
+ const connectCanton = reactQuery.useMutation(async ({ wallet, }) => {
26997
+ let result;
26998
+ try {
26999
+ // Try to reconnect silently first (existing session, no popup)
27000
+ result = await wallet.connector.autoConnect();
27001
+ }
27002
+ catch {
27003
+ // Otherwise prompt the wallet to connect
27004
+ result = await wallet.connector.connect();
27005
+ }
27006
+ return {
27007
+ wallet,
27008
+ address: result.address,
27009
+ };
27010
+ });
27011
+ const disconnectCanton = React.useCallback(async () => {
27012
+ await connectedCantonWallet.wallet?.connector.disconnect();
27013
+ }, [connectedCantonWallet.wallet?.connector]);
27014
+ const autoConnectCanton = React.useCallback(async () => {
27015
+ const recentCantonWallet = wallets.find((w) => w.connectorId === recentCantonWalletId);
27016
+ if (!recentCantonWallet) {
27017
+ return;
27018
+ }
27019
+ const { address } = await recentCantonWallet.connector.autoConnect();
27020
+ setConnectedWallet(squidTypes.ChainType.CANTON, {
27021
+ wallet: recentCantonWallet,
27022
+ address,
27023
+ });
27024
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27025
+ }, [wallets.map((w) => w.connectorId), recentCantonWalletId]);
27026
+ React.useEffect(() => {
27027
+ const wallet = connectedCantonWallet.wallet;
27028
+ if (!wallet) {
27029
+ return;
27030
+ }
27031
+ function onConnect(newAddress) {
27032
+ if (wallet) {
27033
+ setConnectedWallet(squidTypes.ChainType.CANTON, {
27034
+ wallet,
27035
+ address: newAddress,
27036
+ });
27037
+ }
27038
+ }
27039
+ function onDisconnect() {
27040
+ disconnectWallet(squidTypes.ChainType.CANTON);
27041
+ }
27042
+ wallet.connector.on("connect", onConnect);
27043
+ wallet.connector.on("disconnect", onDisconnect);
27044
+ return () => {
27045
+ wallet.connector.off("connect", onConnect);
27046
+ wallet.connector.off("disconnect", onDisconnect);
27047
+ };
27048
+ }, [disconnectWallet, setConnectedWallet, connectedCantonWallet.wallet]);
27049
+ return {
27050
+ connectCanton,
27051
+ disconnectCanton,
27052
+ autoConnectCanton,
27053
+ signer: connectedCantonWallet.wallet?.connector,
27054
+ wallets,
27055
+ };
27056
+ }
27057
+
27058
+ const CantonContext = React.createContext(undefined);
27059
+ const CantonProvider = ({ children, }) => {
27060
+ const cantonHook = useCanton();
27061
+ return (React.createElement(CantonContext.Provider, { value: cantonHook }, children));
27062
+ };
27063
+ const useCantonContext = () => {
27064
+ const context = React.useContext(CantonContext);
27065
+ if (!context) {
27066
+ throw new Error("useCantonContext must be used within a CantonProvider");
27067
+ }
27068
+ return context;
27069
+ };
27070
+
26622
27071
  function useEvmWallets() {
26623
27072
  const connectors = wagmi.useConnectors();
26624
27073
  const wallets = React.useMemo(() => {
@@ -26830,7 +27279,7 @@ function useStellarWallets() {
26830
27279
  try {
26831
27280
  const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
26832
27281
  const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module.mjs');
26833
- const { formatStellarWallet } = await Promise.resolve().then(function () { return require('./stellarService.client-SrhXgRGB.js'); });
27282
+ const { formatStellarWallet } = await Promise.resolve().then(function () { return require('./stellarService.client-Bjc92sC_.js'); });
26834
27283
  const modules = [...initializeAllModules(), new LedgerModule()];
26835
27284
  const promises = modules.map(async (module) => {
26836
27285
  const isAvailable = await module.isAvailable();
@@ -27303,17 +27752,24 @@ const useWallets = () => {
27303
27752
  const { wallets: suiWallets } = useSuiContext();
27304
27753
  const { wallets: xrplWallets } = useXrplContext();
27305
27754
  const { wallets: stellarWallets } = useStellarContext();
27755
+ const { wallets: cantonWallets } = useCantonContext();
27306
27756
  const wallets = React.useMemo(() => {
27307
27757
  const singleChainWallets$1 = populateWallets(clientWindow, singleChainWallets);
27308
27758
  const multiChainWallets$1 = populateWallets(clientWindow, multiChainWallets);
27759
+ const discoveredWallets = [
27760
+ ...evmWallets,
27761
+ ...solanaWallets,
27762
+ ...suiWallets,
27763
+ ...cantonWallets,
27764
+ ];
27765
+ const fallbackWallets = buildFallbackWallets(discoveredWallets);
27309
27766
  return mergeWallets({
27310
27767
  singleChainWallets: [
27311
27768
  ...singleChainWallets$1,
27312
- ...evmWallets,
27313
- ...solanaWallets,
27314
- ...suiWallets,
27769
+ ...discoveredWallets,
27315
27770
  ...xrplWallets,
27316
27771
  ...stellarWallets,
27772
+ ...fallbackWallets,
27317
27773
  ],
27318
27774
  multiChainWallets: multiChainWallets$1,
27319
27775
  });
@@ -27324,6 +27780,7 @@ const useWallets = () => {
27324
27780
  suiWallets,
27325
27781
  xrplWallets,
27326
27782
  stellarWallets,
27783
+ cantonWallets,
27327
27784
  ]);
27328
27785
  return {
27329
27786
  wallets,
@@ -27339,6 +27796,7 @@ const useWallet = () => {
27339
27796
  const { connectSui, disconnectSui } = useSuiContext();
27340
27797
  const { connectXrpl, disconnectXrpl } = useXrplContext();
27341
27798
  const { connectStellar, disconnectStellar } = useStellarContext();
27799
+ const { connectCanton, disconnectCanton } = useCantonContext();
27342
27800
  const { findChain } = useSquidChains();
27343
27801
  const { isGnosisConnected, gnosisAddress } = useGnosisContext();
27344
27802
  const destinationAddress = useSwapRoutePersistStore((state) => state.swapRoute?.destinationAddress);
@@ -27375,6 +27833,7 @@ const useWallet = () => {
27375
27833
  connectSui,
27376
27834
  connectXrpl,
27377
27835
  connectStellar,
27836
+ connectCanton,
27378
27837
  selectedChainTypes,
27379
27838
  findChain,
27380
27839
  });
@@ -27423,6 +27882,9 @@ const useWallet = () => {
27423
27882
  case squidTypes.ChainType.STELLAR:
27424
27883
  await disconnectStellar();
27425
27884
  break;
27885
+ case squidTypes.ChainType.CANTON:
27886
+ await disconnectCanton();
27887
+ break;
27426
27888
  default:
27427
27889
  // TODO: Implement disconnect for other chains
27428
27890
  break;
@@ -27529,6 +27991,7 @@ const useMultiChainWallet = (chain) => {
27529
27991
  const suiAddress = connectedAddresses[squidTypes.ChainType.SUI];
27530
27992
  const xrplAddress = connectedAddresses[squidTypes.ChainType.XRPL];
27531
27993
  const stellarAddress = connectedAddresses[squidTypes.ChainType.STELLAR];
27994
+ const cantonAddress = connectedAddresses[squidTypes.ChainType.CANTON];
27532
27995
  // Cosmos is a special case because the address changes on every chain
27533
27996
  // so we can't use the default cosmos connected address
27534
27997
  const { data: cosmosAddress } = useCosmosForChain(chain);
@@ -27616,6 +28079,16 @@ const useMultiChainWallet = (chain) => {
27616
28079
  chainType: chain.chainType,
27617
28080
  }),
27618
28081
  };
28082
+ case squidTypes.ChainType.CANTON:
28083
+ if (!cantonAddress)
28084
+ return {};
28085
+ return {
28086
+ address: cantonAddress,
28087
+ formatted: formatHash({
28088
+ hash: cantonAddress,
28089
+ chainType: chain.chainType,
28090
+ }),
28091
+ };
27619
28092
  }
27620
28093
  }, [
27621
28094
  chain?.chainType,
@@ -27627,6 +28100,7 @@ const useMultiChainWallet = (chain) => {
27627
28100
  suiAddress,
27628
28101
  xrplAddress,
27629
28102
  stellarAddress,
28103
+ cantonAddress,
27630
28104
  ]);
27631
28105
  /**
27632
28106
  * Change current network for desired chain
@@ -28451,6 +28925,8 @@ async function createClient(chain) {
28451
28925
  return new XrplRpcClient(chain.rpc);
28452
28926
  case squidTypes.ChainType.STELLAR:
28453
28927
  return new StellarRpcClient(chain.rpc);
28928
+ case squidTypes.ChainType.CANTON:
28929
+ return null;
28454
28930
  }
28455
28931
  }
28456
28932
 
@@ -29463,6 +29939,54 @@ const getAllStellarTokensBalance = async (userAddress, stellarTokens, stellarCha
29463
29939
  const allResults = await Promise.all(stellarChains.map(getBalancesForChain));
29464
29940
  return allResults.flat();
29465
29941
  };
29942
+ /**
29943
+ * Canton balances are private: they can only be read with a wallet-authorized
29944
+ * `ledgerApi` session (the connected wallet supplies a JWT that can read as the
29945
+ * party). So balance is fetchable only when a Canton wallet is connected, and
29946
+ * only for that wallet's party — there's no address-only read.
29947
+ */
29948
+ const getCantonTokenBalance = async (userAddress, token, cantonConnector) => {
29949
+ if (!token.originalAddress)
29950
+ return "0";
29951
+ const instrument = parseCantonInstrument(token.originalAddress);
29952
+ if (!instrument)
29953
+ return "0";
29954
+ const ledgerEnd = await cantonConnector.ledgerApi({ requestMethod: "get", resource: "/v2/state/ledger-end" });
29955
+ const activeContracts = await cantonConnector.ledgerApi({
29956
+ requestMethod: "post",
29957
+ resource: "/v2/state/active-contracts",
29958
+ body: buildHoldingsAcsRequestBody(userAddress, String(ledgerEnd.offset)),
29959
+ });
29960
+ const grouped = groupCantonHoldingBalances(activeContracts);
29961
+ return grouped[cantonInstrumentKey(instrument)] ?? "0";
29962
+ };
29963
+ /**
29964
+ * Fetch balances for all Canton tokens in one ACS query. Canton balances are
29965
+ * private, so this requires a connected wallet's authorized `ledgerApi`.
29966
+ */
29967
+ async function getAllCantonTokensBalance({ connector, partyId, tokens, }) {
29968
+ const ledgerEnd = await connector.ledgerApi({
29969
+ requestMethod: "get",
29970
+ resource: "/v2/state/ledger-end",
29971
+ });
29972
+ const activeContracts = await connector.ledgerApi({
29973
+ requestMethod: "post",
29974
+ resource: "/v2/state/active-contracts",
29975
+ body: buildHoldingsAcsRequestBody(partyId, String(ledgerEnd.offset)),
29976
+ });
29977
+ const grouped = groupCantonHoldingBalances(activeContracts);
29978
+ return tokens.map((token) => {
29979
+ const instrument = token.originalAddress
29980
+ ? parseCantonInstrument(token.originalAddress)
29981
+ : null;
29982
+ return {
29983
+ ...token,
29984
+ balance: instrument
29985
+ ? grouped[cantonInstrumentKey(instrument)] ?? "0"
29986
+ : "0",
29987
+ };
29988
+ });
29989
+ }
29466
29990
  /**
29467
29991
  * Returns a promise that resolves when the given promise resolves or after the given timeout
29468
29992
  * @param ms - timeout in milliseconds
@@ -29647,9 +30171,29 @@ const useStellarBalance = ({ userAddress, chain, enabled, token, refreshInterval
29647
30171
  });
29648
30172
  return { balance, isLoading };
29649
30173
  };
30174
+ const useCantonBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
30175
+ const cantonConnector = useWalletStore((store) => store.connectedWalletsByChainType[squidTypes.ChainType.CANTON]?.wallet?.connector);
30176
+ const { data: balance = "0", isLoading } = reactQuery.useQuery({
30177
+ queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
30178
+ queryFn: async () => {
30179
+ if (!cantonConnector || !userAddress || !token)
30180
+ return "0";
30181
+ return getCantonTokenBalance(userAddress, token, cantonConnector);
30182
+ },
30183
+ enabled: enabled &&
30184
+ !!cantonConnector &&
30185
+ !!userAddress &&
30186
+ !!token &&
30187
+ chain?.chainType === squidTypes.ChainType.CANTON &&
30188
+ isCantonAddressValid(userAddress),
30189
+ refetchInterval: refreshIntervalMs,
30190
+ retry: 2,
30191
+ });
30192
+ return { balance, isLoading };
30193
+ };
29650
30194
 
29651
30195
  function useNativeTokenForChain(chain) {
29652
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = useSquidTokens();
30196
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens();
29653
30197
  const getTokensForChainType = () => {
29654
30198
  if (!chain?.chainType)
29655
30199
  return [];
@@ -29668,6 +30212,8 @@ function useNativeTokenForChain(chain) {
29668
30212
  return xrplTokens;
29669
30213
  case squidTypes.ChainType.STELLAR:
29670
30214
  return stellarTokens;
30215
+ case squidTypes.ChainType.CANTON:
30216
+ return cantonTokens;
29671
30217
  }
29672
30218
  };
29673
30219
  const nativeTokenForChainType = React.useMemo(() => {
@@ -29849,6 +30395,24 @@ const useStellarNativeBalance = ({ address, chain, }) => {
29849
30395
  isLoading,
29850
30396
  };
29851
30397
  };
30398
+ const useCantonNativeBalance = ({ address, chain, }) => {
30399
+ const { nativeToken } = useNativeTokenForChain(chain);
30400
+ const { balance: rawBalance, isLoading } = useCantonBalance({
30401
+ chain,
30402
+ token: nativeToken,
30403
+ userAddress: address,
30404
+ enabled: chain?.chainType === squidTypes.ChainType.CANTON,
30405
+ });
30406
+ const balance = React.useMemo(() => {
30407
+ if (nativeToken?.decimals && rawBalance) {
30408
+ return {
30409
+ decimals: nativeToken.decimals,
30410
+ value: parseToBigInt(rawBalance, nativeToken.decimals),
30411
+ };
30412
+ }
30413
+ }, [nativeToken?.decimals, rawBalance]);
30414
+ return { balance, isLoading };
30415
+ };
29852
30416
  const useNativeBalance = (chain) => {
29853
30417
  const { connectedAddresses } = useWallet();
29854
30418
  const { data: cosmosAddressForChain } = useCosmosForChain(chain);
@@ -29879,6 +30443,10 @@ const useNativeBalance = (chain) => {
29879
30443
  address: connectedAddresses[squidTypes.ChainType.STELLAR],
29880
30444
  chain,
29881
30445
  });
30446
+ const { balance: nativeCantonBalance, isLoading: isCantonLoading } = useCantonNativeBalance({
30447
+ address: connectedAddresses[squidTypes.ChainType.CANTON],
30448
+ chain,
30449
+ });
29882
30450
  const { nativeBalance, nativeBalanceFormatted } = React.useMemo(() => {
29883
30451
  let balance;
29884
30452
  switch (chain?.chainType) {
@@ -29902,6 +30470,10 @@ const useNativeBalance = (chain) => {
29902
30470
  break;
29903
30471
  case squidTypes.ChainType.STELLAR:
29904
30472
  balance = nativeStellarBalance;
30473
+ break;
30474
+ case squidTypes.ChainType.CANTON:
30475
+ balance = nativeCantonBalance;
30476
+ break;
29905
30477
  }
29906
30478
  const balanceFormatted = !!balance
29907
30479
  ? formatBNToReadable(balance.value, balance.decimals)
@@ -29919,6 +30491,7 @@ const useNativeBalance = (chain) => {
29919
30491
  nativeSuiBalance,
29920
30492
  nativeXrplBalance,
29921
30493
  nativeStellarBalance,
30494
+ nativeCantonBalance,
29922
30495
  ]);
29923
30496
  const isLoading = React.useMemo(() => {
29924
30497
  if (!chain?.chainType)
@@ -29938,6 +30511,8 @@ const useNativeBalance = (chain) => {
29938
30511
  return isXrpLoading;
29939
30512
  case squidTypes.ChainType.STELLAR:
29940
30513
  return isStellarLoading;
30514
+ case squidTypes.ChainType.CANTON:
30515
+ return isCantonLoading;
29941
30516
  }
29942
30517
  }, [
29943
30518
  chain?.chainType,
@@ -29948,6 +30523,7 @@ const useNativeBalance = (chain) => {
29948
30523
  isSuiLoading,
29949
30524
  isXrpLoading,
29950
30525
  isStellarLoading,
30526
+ isCantonLoading,
29951
30527
  ]);
29952
30528
  return { nativeBalance, nativeBalanceFormatted, isLoading };
29953
30529
  };
@@ -30162,7 +30738,7 @@ function hederaWalletConnect(parameters) {
30162
30738
  const optionalChains = config.chains.map((x) => x.id);
30163
30739
  if (!optionalChains.length)
30164
30740
  return;
30165
- const { EthereumProvider } = await Promise.resolve().then(function () { return require('./index.es-B2QD8f3q.js'); });
30741
+ const { EthereumProvider } = await Promise.resolve().then(function () { return require('./index.es-BPXYaraD.js'); });
30166
30742
  const rawProvider = await EthereumProvider.init({
30167
30743
  ...restParameters,
30168
30744
  disableProviderPing: true,
@@ -30367,6 +30943,7 @@ const useSigner = ({ chain }) => {
30367
30943
  const { signer: suiSigner } = useSuiContext();
30368
30944
  const { signer: xrplSigner } = useXrplContext();
30369
30945
  const { signer: stellarSigner } = useStellarContext();
30946
+ const { signer: cantonSigner } = useCantonContext();
30370
30947
  const isEvmSignerReady = !!evmSigner;
30371
30948
  const isSolanaSignerReady = !!solanaSigner;
30372
30949
  const isCosmosSignerReady = !!cosmosSigner;
@@ -30374,6 +30951,7 @@ const useSigner = ({ chain }) => {
30374
30951
  const isSuiSignerReady = !!suiSigner;
30375
30952
  const isXrplSignerReady = !!xrplSigner;
30376
30953
  const isStellarSignerReady = !!stellarSigner;
30954
+ const isCantonSignerReady = !!cantonSigner;
30377
30955
  const isSignerReady = React.useMemo(() => {
30378
30956
  if (!chain?.chainType)
30379
30957
  return false;
@@ -30392,6 +30970,8 @@ const useSigner = ({ chain }) => {
30392
30970
  return isXrplSignerReady;
30393
30971
  case squidTypes.ChainType.STELLAR:
30394
30972
  return isStellarSignerReady;
30973
+ case squidTypes.ChainType.CANTON:
30974
+ return isCantonSignerReady;
30395
30975
  }
30396
30976
  }, [
30397
30977
  chain?.chainType,
@@ -30402,6 +30982,7 @@ const useSigner = ({ chain }) => {
30402
30982
  isSuiSignerReady,
30403
30983
  isXrplSignerReady,
30404
30984
  isStellarSignerReady,
30985
+ isCantonSignerReady,
30405
30986
  ]);
30406
30987
  return {
30407
30988
  isSignerReady,
@@ -30412,6 +30993,7 @@ const useSigner = ({ chain }) => {
30412
30993
  suiSigner,
30413
30994
  xrplSigner,
30414
30995
  stellarSigner,
30996
+ cantonSigner,
30415
30997
  };
30416
30998
  };
30417
30999
 
@@ -30841,21 +31423,21 @@ const useSendTransactionStore = zustand.create((set, get) => ({
30841
31423
 
30842
31424
  const useDepositAddressStore = zustand.create((set) => ({
30843
31425
  deposit: null,
30844
- isEnabled: false,
31426
+ selectedPaymentMethod: "connectedWallet",
30845
31427
  setDeposit: (data) => {
30846
31428
  set({ deposit: data });
30847
31429
  },
30848
- toggleDepositFlow: (enabled) => {
30849
- set({ isEnabled: enabled });
31430
+ setPaymentMethod: (method) => {
31431
+ set({ selectedPaymentMethod: method });
30850
31432
  },
30851
31433
  }));
30852
31434
 
30853
31435
  function useDepositAddress(squidRoute) {
30854
- const { isEnabled, depositAddress } = useDepositAddressStore((state) => ({
30855
- isEnabled: state.isEnabled,
31436
+ const { selectedPaymentMethod, depositAddress } = useDepositAddressStore((state) => ({
31437
+ selectedPaymentMethod: state.selectedPaymentMethod,
30856
31438
  depositAddress: state.deposit?.depositAddress,
30857
31439
  }));
30858
- const { setDeposit, toggleDepositFlow, deposit } = useDepositAddressStore();
31440
+ const { setDeposit, setPaymentMethod, deposit } = useDepositAddressStore();
30859
31441
  const { squid } = useSquidStore();
30860
31442
  const { fromChain } = useSwap();
30861
31443
  const isAvailableAsPaymentMethod = React.useMemo(() => {
@@ -30864,41 +31446,55 @@ function useDepositAddress(squidRoute) {
30864
31446
  const chainsSupportingDepositAddress = [
30865
31447
  CHAIN_IDS.BITCOIN,
30866
31448
  CHAIN_IDS.SOLANA,
31449
+ CHAIN_IDS.CANTON,
30867
31450
  ];
30868
31451
  return chainsSupportingDepositAddress.includes(fromChain.chainId);
30869
31452
  }, [fromChain?.chainId]);
30870
- const swapWillGenerateDepositAddress = React.useMemo(() => {
30871
- return (squidRoute?.transactionRequest?.type ===
30872
- squidTypes.SquidDataType.ChainflipDepositAddress);
30873
- }, [squidRoute?.transactionRequest?.type]);
30874
- const enable = React.useCallback(() => {
30875
- toggleDepositFlow(true);
30876
- }, [toggleDepositFlow]);
30877
- const disable = React.useCallback(() => {
30878
- toggleDepositFlow(false);
30879
- }, [toggleDepositFlow]);
31453
+ const routeProvidesDirectDepositAddress = !!squidRoute?.transactionRequest &&
31454
+ isDepositAddressDirectTransferRoute(squidRoute.transactionRequest);
31455
+ const swapWillGenerateDepositAddress = isChainflipDepositRoute(squidRoute) || routeProvidesDirectDepositAddress;
31456
+ const paymentMethod = isAvailableAsPaymentMethod
31457
+ ? selectedPaymentMethod
31458
+ : "connectedWallet";
31459
+ const routeSupportsDepositAddress = !squidRoute?.transactionRequest || swapWillGenerateDepositAddress;
31460
+ const isDepositAddressActive = paymentMethod === "depositAddress" && routeSupportsDepositAddress;
30880
31461
  const closeDepositChannel = React.useCallback(() => {
30881
- toggleDepositFlow(false);
30882
31462
  setDeposit(null);
30883
- }, [toggleDepositFlow, setDeposit]);
31463
+ }, [setDeposit]);
30884
31464
  const getRouteWithDeposit = reactQuery.useMutation(async ({ route }) => {
30885
- if (!squid)
30886
- throw new Error("Squid SDK not initialized");
30887
- const depositAddressResponse = (await squid.executeRoute({
30888
- signer: {},
30889
- route,
30890
- }));
30891
- setDeposit(depositAddressResponse);
30892
- return {
30893
- depositAddress: depositAddressResponse,
30894
- };
31465
+ if (!squid || !route.transactionRequest) {
31466
+ throw new Error("Missing required params");
31467
+ }
31468
+ if (isChainflipDepositRoute(route)) {
31469
+ const depositAddressResponse = (await squid.executeRoute({
31470
+ signer: {},
31471
+ route,
31472
+ }));
31473
+ setDeposit({
31474
+ amount: depositAddressResponse.amount,
31475
+ depositAddress: depositAddressResponse.depositAddress,
31476
+ statusTrackingId: depositAddressResponse.chainflipStatusTrackingId,
31477
+ });
31478
+ return;
31479
+ }
31480
+ else if (isDepositAddressDirectTransferRoute(route.transactionRequest)) {
31481
+ // Canton case
31482
+ const orderHash = route.transactionRequest.data;
31483
+ setDeposit({
31484
+ amount: route.params.fromAmount ?? "",
31485
+ depositAddress: route.transactionRequest.target,
31486
+ statusTrackingId: orderHash,
31487
+ memo: orderHash,
31488
+ });
31489
+ return;
31490
+ }
30895
31491
  });
30896
31492
  return {
30897
- isEnabled,
31493
+ paymentMethod,
31494
+ isDepositAddressActive,
30898
31495
  isAvailableAsPaymentMethod,
30899
31496
  swapWillGenerateDepositAddress,
30900
- enable,
30901
- disable,
31497
+ setPaymentMethod,
30902
31498
  getRouteWithDeposit,
30903
31499
  depositAddress,
30904
31500
  closeDepositChannel,
@@ -30930,8 +31526,9 @@ const useUrlSwapParams = () => {
30930
31526
 
30931
31527
  const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, queryOptions, }) => {
30932
31528
  const { evmChains, cosmosChains, suiChains, xrplChains, stellarChains } = useSquidChains(direction);
30933
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = useSquidTokens(direction);
31529
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens(direction);
30934
31530
  const { keplrTypeWallet } = useCosmosContext();
31531
+ const cantonConnector = useWalletStore((store) => store.connectedWalletsByChainType[squidTypes.ChainType.CANTON]?.wallet?.connector);
30935
31532
  const placeholderData = React.useMemo(() => {
30936
31533
  const tokens = {
30937
31534
  [squidTypes.ChainType.EVM]: evmTokens.map((t) => ({ ...t, balance: "0" })),
@@ -30941,6 +31538,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30941
31538
  [squidTypes.ChainType.SUI]: suiTokens.map((t) => ({ ...t, balance: "0" })),
30942
31539
  [squidTypes.ChainType.XRPL]: xrplTokens.map((t) => ({ ...t, balance: "0" })),
30943
31540
  [squidTypes.ChainType.STELLAR]: stellarTokens.map((t) => ({ ...t, balance: "0" })),
31541
+ [squidTypes.ChainType.CANTON]: cantonTokens.map((t) => ({ ...t, balance: "0" })),
30944
31542
  };
30945
31543
  if (!chainType) {
30946
31544
  // Return all tokens with zero balance
@@ -30962,6 +31560,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30962
31560
  suiTokens,
30963
31561
  xrplTokens,
30964
31562
  stellarTokens,
31563
+ cantonTokens,
30965
31564
  ]);
30966
31565
  const isQueryEnabled = React.useMemo(() => {
30967
31566
  // Respect the queryOptions.enabled override if provided
@@ -30984,6 +31583,8 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30984
31583
  return xrplTokens.length > 0;
30985
31584
  case squidTypes.ChainType.STELLAR:
30986
31585
  return stellarTokens.length > 0;
31586
+ case squidTypes.ChainType.CANTON:
31587
+ return cantonTokens.length > 0;
30987
31588
  }
30988
31589
  }, [
30989
31590
  chainType,
@@ -30996,6 +31597,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30996
31597
  suiTokens.length,
30997
31598
  xrplTokens.length,
30998
31599
  stellarTokens.length,
31600
+ cantonTokens.length,
30999
31601
  ]);
31000
31602
  const query = reactQuery.useQuery(keys().allTokensBalance(address, chainType, direction), async () => {
31001
31603
  // Return zero balances if no address
@@ -31035,6 +31637,15 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
31035
31637
  case squidTypes.ChainType.STELLAR:
31036
31638
  fetchedTokens = await getAllStellarTokensBalance(address, stellarTokens, stellarChains);
31037
31639
  break;
31640
+ case squidTypes.ChainType.CANTON:
31641
+ fetchedTokens = cantonConnector
31642
+ ? await getAllCantonTokensBalance({
31643
+ connector: cantonConnector,
31644
+ partyId: address,
31645
+ tokens: cantonTokens,
31646
+ })
31647
+ : placeholderData.tokens;
31648
+ break;
31038
31649
  default:
31039
31650
  fetchedTokens = placeholderData.tokens;
31040
31651
  break;
@@ -31105,6 +31716,12 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31105
31716
  direction,
31106
31717
  queryOptions,
31107
31718
  });
31719
+ const cantonBalancesQuery = useAllTokensWithBalanceForChainType({
31720
+ chainType: squidTypes.ChainType.CANTON,
31721
+ address: connectedAddresses?.[squidTypes.ChainType.CANTON],
31722
+ direction,
31723
+ queryOptions,
31724
+ });
31108
31725
  // Create a map of chain type to balance query results
31109
31726
  const balanceQueries = React.useMemo(() => ({
31110
31727
  [squidTypes.ChainType.EVM]: evmBalancesQuery,
@@ -31114,6 +31731,7 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31114
31731
  [squidTypes.ChainType.SUI]: suiBalancesQuery,
31115
31732
  [squidTypes.ChainType.XRPL]: xrplBalancesQuery,
31116
31733
  [squidTypes.ChainType.STELLAR]: stellarBalancesQuery,
31734
+ [squidTypes.ChainType.CANTON]: cantonBalancesQuery,
31117
31735
  }), [
31118
31736
  evmBalancesQuery,
31119
31737
  cosmosBalancesQuery,
@@ -31122,6 +31740,7 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31122
31740
  suiBalancesQuery,
31123
31741
  xrplBalancesQuery,
31124
31742
  stellarBalancesQuery,
31743
+ cantonBalancesQuery,
31125
31744
  ]);
31126
31745
  // Combine all tokens from different chains
31127
31746
  const allTokens = React.useMemo(() => Object.values(balanceQueries).flatMap((query) => query.data?.tokens ?? []), [balanceQueries]);
@@ -31203,6 +31822,12 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31203
31822
  userAddress,
31204
31823
  enabled: chain?.chainType === squidTypes.ChainType.STELLAR && enabled,
31205
31824
  });
31825
+ const { balance: cantonBalance } = useCantonBalance({
31826
+ chain,
31827
+ token,
31828
+ userAddress,
31829
+ enabled: chain?.chainType === squidTypes.ChainType.CANTON && enabled,
31830
+ });
31206
31831
  const balance = React.useMemo(() => {
31207
31832
  if (!chain?.chainType)
31208
31833
  return "0";
@@ -31221,6 +31846,8 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31221
31846
  return xrplBalance;
31222
31847
  case squidTypes.ChainType.STELLAR:
31223
31848
  return stellarBalance;
31849
+ case squidTypes.ChainType.CANTON:
31850
+ return cantonBalance;
31224
31851
  }
31225
31852
  }, [
31226
31853
  chain?.chainType,
@@ -31231,6 +31858,7 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31231
31858
  suiBalance,
31232
31859
  xrplBalance,
31233
31860
  stellarBalance,
31861
+ cantonBalance,
31234
31862
  ]);
31235
31863
  return { balance };
31236
31864
  };
@@ -31700,7 +32328,7 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31700
32328
  });
31701
32329
  // gas fees + fromAmount (if fromToken is gas token)
31702
32330
  const totalGasBalanceNeeded = networkFeesWei +
31703
- BigInt(chainFeeParams?.fromTokenPaysGasFees ? fromAmount ?? 0 : 0);
32331
+ BigInt(chainFeeParams?.fromTokenPaysGasFees ? (fromAmount ?? 0) : 0);
31704
32332
  const gasBalanceNeeded = gasToken
31705
32333
  ? formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals)
31706
32334
  : undefined;
@@ -31877,7 +32505,7 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31877
32505
  return undefined;
31878
32506
  // gas fees + fromAmount (if fromToken is gas token)
31879
32507
  const totalGasBalanceNeeded = estimatedGas +
31880
- parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? amount ?? "0" : "0", token.decimals);
32508
+ parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? (amount ?? "0") : "0", token.decimals);
31881
32509
  return formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals);
31882
32510
  }, [
31883
32511
  amount,
@@ -32329,6 +32957,9 @@ function useSendTransaction({ to, amount, token, chain, }) {
32329
32957
  chain,
32330
32958
  });
32331
32959
  break;
32960
+ case squidTypes.ChainType.CANTON: {
32961
+ throw new Error("Not implemented");
32962
+ }
32332
32963
  }
32333
32964
  return {
32334
32965
  amount,
@@ -32532,6 +33163,8 @@ async function getSendTransactionStatus({ chain, txHash, }) {
32532
33163
  txHash,
32533
33164
  chain,
32534
33165
  });
33166
+ case squidTypes.ChainType.CANTON:
33167
+ throw new Error("Not implemented");
32535
33168
  }
32536
33169
  }
32537
33170
 
@@ -32555,7 +33188,7 @@ const useHistory = (txType) => {
32555
33188
  fromChain: tx.params.fromChain,
32556
33189
  fromToken: tx.params.fromToken,
32557
33190
  fromAddress: tx.params.fromAddress,
32558
- fromAmount: tx.params.fromAmount,
33191
+ fromAmount: tx.params.fromAmount ?? "",
32559
33192
  toChain: tx.params.toChain,
32560
33193
  toToken: tx.params.toToken,
32561
33194
  toAddress: tx.params.toAddress,
@@ -32983,6 +33616,129 @@ const useApproval = ({ squidRoute, }) => {
32983
33616
  };
32984
33617
  };
32985
33618
 
33619
+ const useSwapStatusQuery = ({ transaction, retry = 25, refetchOnWindowFocus = "always", enabled = true, onStatus, onEndStatus, onNotFound, onError, }) => {
33620
+ const config = useConfigStore((state) => state.config);
33621
+ const isInitialized = useConfigStore((state) => state.isInitialized);
33622
+ const [isTransactionComplete, setIsTransactionComplete] = React.useState(false);
33623
+ const [refetchInterval, setRefetchInterval] = React.useState(getSwapTxStatusRefetchInterval(transaction));
33624
+ const { getChainType } = useSquidChains();
33625
+ const fetchTransactionStatusWithLatestConfig = React.useCallback(async () => {
33626
+ const latestConfig = useConfigStore.getState().config;
33627
+ return fetchSwapTransactionStatus({
33628
+ transaction,
33629
+ integratorId: latestConfig.integratorId,
33630
+ apiUrl: latestConfig.apiUrl,
33631
+ });
33632
+ }, [transaction]);
33633
+ const transactionStatusQuery = reactQuery.useQuery(keys().swapTransactionStatus(transaction?.transactionId), fetchTransactionStatusWithLatestConfig, {
33634
+ enabled: enabled &&
33635
+ transaction?.transactionId !== "0" &&
33636
+ !!transaction?.transactionId &&
33637
+ !!transaction.fromAddress &&
33638
+ !!config.apiUrl &&
33639
+ transaction !== undefined &&
33640
+ !isTransactionComplete &&
33641
+ isInitialized,
33642
+ refetchInterval(statusResponse) {
33643
+ if (statusResponse &&
33644
+ transactionEndStatuses.includes(getTransactionStatus(statusResponse) ?? "")) {
33645
+ return false;
33646
+ }
33647
+ return refetchInterval;
33648
+ },
33649
+ retryDelay: getChainType(transaction?.fromChain) === squidTypes.ChainType.COSMOS ? 5000 : 3000,
33650
+ retry: getChainType(transaction?.fromChain) === squidTypes.ChainType.COSMOS ? 6 : retry,
33651
+ refetchOnWindowFocus,
33652
+ onSuccess: (statusResponse) => {
33653
+ WidgetEvents.getInstance().dispatchSwapStatus(statusResponse.squidTransactionStatus ?? "");
33654
+ onStatus?.({
33655
+ status: getTransactionStatus(statusResponse) ?? "",
33656
+ statusResponse,
33657
+ });
33658
+ const endStatus = getTransactionEndStatus({ statusResponse });
33659
+ if (endStatus) {
33660
+ setIsTransactionComplete(true);
33661
+ onEndStatus?.({ status: endStatus, statusResponse });
33662
+ }
33663
+ },
33664
+ onError: (error) => {
33665
+ if (is404Error(error.cause)) {
33666
+ onNotFound?.();
33667
+ return;
33668
+ }
33669
+ setRefetchInterval(-1);
33670
+ setIsTransactionComplete(true);
33671
+ onError?.();
33672
+ },
33673
+ });
33674
+ return {
33675
+ transactionStatusQuery,
33676
+ };
33677
+ };
33678
+
33679
+ // Statuses that indicate the source deposit has been received
33680
+ // and the swap is now progressing.
33681
+ const sourceReceivedStatuses = [
33682
+ // Chainflip
33683
+ "DEPOSIT_RECEIVED",
33684
+ "BROADCAST_REQUESTED",
33685
+ "COMPLETE",
33686
+ "SWAPPING",
33687
+ // Canton (Squid Intents)
33688
+ "awaiting",
33689
+ "success",
33690
+ ];
33691
+ /**
33692
+ * Tracks a deposit address intent before it becomes a persisted swap history item.
33693
+ *
33694
+ * Once the source deposit is received, it registers the transaction in the transaction
33695
+ * and history stores, then signals the view via `onReceived` to navigate.
33696
+ */
33697
+ const useDepositTransactionStatus = ({ transaction, route, retry = 25, refetchOnWindowFocus = "always", enabled = true, onReceived, }) => {
33698
+ const { fromChain, toChain } = useSwap();
33699
+ const { addSwapTransaction } = useHistory();
33700
+ const getTransaction = useTransactionStore((state) => state.getTransaction);
33701
+ const setTransactionStoreState = useTransactionStore((state) => state.setTransactionState);
33702
+ return useSwapStatusQuery({
33703
+ transaction,
33704
+ retry,
33705
+ refetchOnWindowFocus,
33706
+ enabled,
33707
+ onStatus: ({ status }) => {
33708
+ if (!sourceReceivedStatuses.includes(status))
33709
+ return;
33710
+ if (!transaction?.transactionId || !route?.transactionRequest)
33711
+ return;
33712
+ const { transactionId } = transaction;
33713
+ if (getTransaction(transactionId))
33714
+ return;
33715
+ useTransactionStore.setState({
33716
+ txLocalId: transactionId,
33717
+ currentTransaction: undefined,
33718
+ });
33719
+ const tx = {
33720
+ routeType: route.transactionRequest.type,
33721
+ fromChain,
33722
+ toChain,
33723
+ fromAddress: transaction.fromAddress,
33724
+ transactionId,
33725
+ transactionIdForStatus: transaction.transactionIdForStatus,
33726
+ quoteId: transaction.quoteId ?? "",
33727
+ status: exports.TransactionStatus.ONGOING,
33728
+ sourceStatus: exports.TransactionStatus.SUCCESS,
33729
+ timestamp: Date.now(),
33730
+ };
33731
+ setTransactionStoreState(transactionId, tx);
33732
+ addSwapTransaction({
33733
+ ...tx,
33734
+ params: route.params,
33735
+ estimate: route.estimate,
33736
+ });
33737
+ onReceived?.();
33738
+ },
33739
+ });
33740
+ };
33741
+
32986
33742
  const DEFAULT_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/providers/squid.webp";
32987
33743
  const AXELAR_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/providers/axelar.webp";
32988
33744
  const useEstimate = (squidRoute) => {
@@ -36029,6 +36785,342 @@ coin.DecProto = {
36029
36785
 
36030
36786
  } (tx));
36031
36787
 
36788
+ const vParty = (party) => ({ party });
36789
+ const vText = (text) => ({ text });
36790
+ const vNumeric = (numeric) => ({ numeric });
36791
+ const vContractId = (contractId) => ({
36792
+ contractId,
36793
+ });
36794
+ const vList = (elements) => ({
36795
+ list: { elements },
36796
+ });
36797
+ const vRecord = (fields) => ({
36798
+ record: { fields: fields.map(([label, value]) => ({ label, value })) },
36799
+ });
36800
+ const vTextMap = (entries) => ({ textMap: { entries } });
36801
+ const vTimestamp = (isoString) => ({
36802
+ timestamp: String(Math.floor(new Date(isoString).getTime() * 1000)),
36803
+ });
36804
+ function isRecord(value) {
36805
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36806
+ }
36807
+ function normalizeChoiceContextValue(value) {
36808
+ if (typeof value === "string")
36809
+ return value;
36810
+ if (!isRecord(value) || typeof value.tag !== "string")
36811
+ return null;
36812
+ switch (value.tag) {
36813
+ case "AV_Text":
36814
+ case "AV_ContractId":
36815
+ return typeof value.value === "string"
36816
+ ? { tag: value.tag, value: value.value }
36817
+ : null;
36818
+ case "AV_Bool":
36819
+ return typeof value.value === "boolean"
36820
+ ? { tag: value.tag, value: value.value }
36821
+ : null;
36822
+ case "AV_List":
36823
+ if (!Array.isArray(value.value))
36824
+ return null;
36825
+ return {
36826
+ tag: value.tag,
36827
+ value: value.value.flatMap((entry) => {
36828
+ const normalized = normalizeChoiceContextValue(entry);
36829
+ return normalized ? [normalized] : [];
36830
+ }),
36831
+ };
36832
+ default: {
36833
+ const inner = value.value;
36834
+ if (typeof inner === "string" ||
36835
+ typeof inner === "number" ||
36836
+ typeof inner === "boolean" ||
36837
+ inner === null) {
36838
+ return { tag: value.tag, value: inner };
36839
+ }
36840
+ if (Array.isArray(inner)) {
36841
+ return {
36842
+ tag: value.tag,
36843
+ value: inner.flatMap((entry) => {
36844
+ const normalized = normalizeChoiceContextValue(entry);
36845
+ return normalized ? [normalized] : [];
36846
+ }),
36847
+ };
36848
+ }
36849
+ if (!isRecord(inner))
36850
+ return null;
36851
+ const normalizedObject = {};
36852
+ for (const [key, entry] of Object.entries(inner)) {
36853
+ if (typeof entry !== "string" &&
36854
+ typeof entry !== "number" &&
36855
+ typeof entry !== "boolean" &&
36856
+ entry !== null) {
36857
+ return null;
36858
+ }
36859
+ normalizedObject[key] = entry;
36860
+ }
36861
+ return { tag: value.tag, value: normalizedObject };
36862
+ }
36863
+ }
36864
+ }
36865
+ function stringifyChoiceContextValue(value) {
36866
+ return typeof value === "string" ? value : String(value);
36867
+ }
36868
+ function choiceContextValueToAnyValue(value) {
36869
+ if (typeof value === "string") {
36870
+ return {
36871
+ variant: { constructor: "AV_Text", value: vText(value) },
36872
+ };
36873
+ }
36874
+ switch (value.tag) {
36875
+ case "AV_ContractId":
36876
+ if (typeof value.value !== "string") {
36877
+ throw new TypeError("AV_ContractId values must be strings");
36878
+ }
36879
+ return {
36880
+ variant: { constructor: value.tag, value: vContractId(value.value) },
36881
+ };
36882
+ case "AV_Bool":
36883
+ if (typeof value.value !== "boolean") {
36884
+ throw new TypeError("AV_Bool values must be booleans");
36885
+ }
36886
+ return {
36887
+ variant: { constructor: value.tag, value: { bool: value.value } },
36888
+ };
36889
+ case "AV_List":
36890
+ if (!Array.isArray(value.value)) {
36891
+ throw new TypeError("AV_List values must be arrays");
36892
+ }
36893
+ return {
36894
+ variant: {
36895
+ constructor: value.tag,
36896
+ value: vList(value.value.map(choiceContextValueToAnyValue)),
36897
+ },
36898
+ };
36899
+ default:
36900
+ return {
36901
+ variant: {
36902
+ constructor: value.tag,
36903
+ value: vText(stringifyChoiceContextValue(value.value)),
36904
+ },
36905
+ };
36906
+ }
36907
+ }
36908
+
36909
+ /** Metadata key used by Splice token-standard transfers to carry our Squid orderhash memo. */
36910
+ const CANTON_MEMO_KEY = "splice.lfdecentralizedtrust.org/reason";
36911
+ /** Interface id for the transfer factory contract returned by the token registry. */
36912
+ const TRANSFER_FACTORY_INTERFACE_ID = "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory";
36913
+ /** Choice exercised on the transfer factory to create the token-standard transfer. */
36914
+ const TRANSFER_FACTORY_CHOICE = "TransferFactory_Transfer";
36915
+ /** CIP-056 (non-Amulet) tokens expose a registrar parameterized by admin party. */
36916
+ const CIP056_REGISTRAR_BASE = "https://api.utilities.digitalasset.com/api/token-standard/v0/registrars";
36917
+ const TRANSFER_REQUESTED_AT_SKEW_MS = 60_000;
36918
+ const TRANSFER_EXECUTE_WINDOW_MS = 24 * 60 * 60 * 1000;
36919
+ function resolveCantonRegistryUrl(instrument) {
36920
+ if (instrument.id === CANTON_AMULET_INSTRUMENT_ID) {
36921
+ return CANTON_AMULET_REGISTRY_URL;
36922
+ }
36923
+ return `${CIP056_REGISTRAR_BASE}/${encodeURIComponent(instrument.admin)}`;
36924
+ }
36925
+ /**
36926
+ * Build the plain JSON arguments expected by the registry transfer-factory
36927
+ * endpoint before it adds choice context and disclosed contracts.
36928
+ */
36929
+ function buildTransferChoiceArgs({ sender, receiver, amount, instrument, inputHoldingCids, memo, nowMs, }) {
36930
+ return {
36931
+ expectedAdmin: instrument.admin,
36932
+ transfer: {
36933
+ sender,
36934
+ receiver,
36935
+ amount,
36936
+ instrumentId: { admin: instrument.admin, id: instrument.id },
36937
+ requestedAt: new Date(nowMs - TRANSFER_REQUESTED_AT_SKEW_MS).toISOString(),
36938
+ executeBefore: new Date(nowMs + TRANSFER_EXECUTE_WINDOW_MS).toISOString(),
36939
+ inputHoldingCids,
36940
+ meta: { values: { [CANTON_MEMO_KEY]: memo } },
36941
+ },
36942
+ extraArgs: { context: { values: {} }, meta: { values: {} } },
36943
+ };
36944
+ }
36945
+ /**
36946
+ * Canton's Holding contracts follow Bitcoin-style UTXOs model.
36947
+ *
36948
+ * Pick Holding contract ids covering `amount` for the instrument: prefer a
36949
+ * single exact-amount holding, else accumulate largest-first.
36950
+ */
36951
+ function selectInputHoldingCids(holdings, instrument, amount) {
36952
+ const spendableHoldings = holdings.filter((h) => !h.locked &&
36953
+ h.instrument.admin === instrument.admin &&
36954
+ h.instrument.id === instrument.id);
36955
+ const target = new BigNumber(amount);
36956
+ const exact = spendableHoldings.find((h) => new BigNumber(h.amount).eq(target));
36957
+ if (exact)
36958
+ return [exact.contractId];
36959
+ const sorted = [...spendableHoldings].sort((a, b) => new BigNumber(b.amount).comparedTo(new BigNumber(a.amount)));
36960
+ const selected = [];
36961
+ let sum = new BigNumber(0);
36962
+ for (const holding of sorted) {
36963
+ selected.push(holding.contractId);
36964
+ sum = sum.plus(holding.amount);
36965
+ if (sum.gte(target))
36966
+ break;
36967
+ }
36968
+ if (sum.lt(target)) {
36969
+ throw new Error("Insufficient Canton holdings to cover transfer amount");
36970
+ }
36971
+ return selected;
36972
+ }
36973
+ async function fetchInputHoldingCids(connector, party, instrument, amount) {
36974
+ const ledgerEnd = await connector.ledgerApi({
36975
+ requestMethod: "get",
36976
+ resource: "/v2/state/ledger-end",
36977
+ });
36978
+ const activeContracts = await connector.ledgerApi({
36979
+ requestMethod: "post",
36980
+ resource: "/v2/state/active-contracts",
36981
+ body: buildHoldingsAcsRequestBody(party, String(ledgerEnd.offset)),
36982
+ });
36983
+ return selectInputHoldingCids(parseCantonHoldings(activeContracts), instrument, amount);
36984
+ }
36985
+ /**
36986
+ * Ask the token registry for the transfer factory contract and extra context
36987
+ * required to exercise its transfer choice.
36988
+ */
36989
+ async function fetchTransferFactory(registryUrl, choiceArgs) {
36990
+ const response = await fetch(`${registryUrl}/registry/transfer-instruction/v1/transfer-factory`, {
36991
+ method: "POST",
36992
+ headers: { "Content-Type": "application/json" },
36993
+ body: JSON.stringify({
36994
+ choiceArguments: choiceArgs,
36995
+ excludeDebugFields: true,
36996
+ }),
36997
+ });
36998
+ if (!response.ok) {
36999
+ throw new Error(`Canton transfer-factory request failed (${response.status})`);
37000
+ }
37001
+ return response.json();
37002
+ }
37003
+ /**
37004
+ * Convert transfer choice args into strict Daml Value JSON for the wallet's
37005
+ * prepareExecute ExerciseCommand.
37006
+ */
37007
+ function buildPrepareChoiceArgument(choiceArgs) {
37008
+ const contextValues = Object.entries(choiceArgs.extraArgs.context?.values ?? {})
37009
+ .map(([key, value]) => {
37010
+ const normalized = normalizeChoiceContextValue(value);
37011
+ return normalized
37012
+ ? { key, value: choiceContextValueToAnyValue(normalized) }
37013
+ : undefined;
37014
+ })
37015
+ .filter((entry) => Boolean(entry));
37016
+ return vRecord([
37017
+ ["expectedAdmin", vParty(choiceArgs.expectedAdmin)],
37018
+ [
37019
+ "transfer",
37020
+ vRecord([
37021
+ ["sender", vParty(choiceArgs.transfer.sender)],
37022
+ ["receiver", vParty(choiceArgs.transfer.receiver)],
37023
+ ["amount", vNumeric(choiceArgs.transfer.amount)],
37024
+ [
37025
+ "instrumentId",
37026
+ vRecord([
37027
+ ["admin", vParty(choiceArgs.transfer.instrumentId.admin)],
37028
+ ["id", vText(choiceArgs.transfer.instrumentId.id)],
37029
+ ]),
37030
+ ],
37031
+ ["requestedAt", vTimestamp(choiceArgs.transfer.requestedAt)],
37032
+ ["executeBefore", vTimestamp(choiceArgs.transfer.executeBefore)],
37033
+ [
37034
+ "inputHoldingCids",
37035
+ vList(choiceArgs.transfer.inputHoldingCids.map(vContractId)),
37036
+ ],
37037
+ [
37038
+ "meta",
37039
+ vRecord([
37040
+ [
37041
+ "values",
37042
+ vTextMap(Object.entries(choiceArgs.transfer.meta.values).map(([key, value]) => ({ key, value: vText(value) }))),
37043
+ ],
37044
+ ]),
37045
+ ],
37046
+ ]),
37047
+ ],
37048
+ [
37049
+ "extraArgs",
37050
+ vRecord([
37051
+ ["context", vRecord([["values", vTextMap(contextValues)]])],
37052
+ ["meta", vRecord([["values", vTextMap([])]])],
37053
+ ]),
37054
+ ],
37055
+ ]);
37056
+ }
37057
+ /**
37058
+ * Convert a registry disclosed contract into the wallet submission shape,
37059
+ * dropping debug fields and entries without a usable createdEventBlob.
37060
+ */
37061
+ function toDisclosedContract(raw) {
37062
+ if (typeof raw.createdEventBlob !== "string")
37063
+ return null;
37064
+ return {
37065
+ createdEventBlob: raw.createdEventBlob,
37066
+ contractId: typeof raw.contractId === "string" ? raw.contractId : undefined,
37067
+ synchronizerId: typeof raw.synchronizerId === "string" ? raw.synchronizerId : undefined,
37068
+ };
37069
+ }
37070
+ /**
37071
+ * Build a Splice token-standard transfer of `amount` of `token` from `sender`
37072
+ * to `receiver`, carrying `memo`, ready to hand to a wallet's prepareExecute.
37073
+ * Returns the full prepareExecute params (commandId + commands + actAs +
37074
+ * disclosedContracts).
37075
+ */
37076
+ async function buildCantonTransfer(connector, { sender, receiver, amount, token, memo, nowMs, }) {
37077
+ if (!token.originalAddress) {
37078
+ throw new Error("Canton token originalAddress is required");
37079
+ }
37080
+ const instrument = parseCantonInstrument(token.originalAddress);
37081
+ if (!instrument) {
37082
+ throw new Error(`Invalid Canton token address: ${token.originalAddress}`);
37083
+ }
37084
+ const registryUrl = resolveCantonRegistryUrl(instrument);
37085
+ const inputHoldingCids = await fetchInputHoldingCids(connector, sender, instrument, amount);
37086
+ const choiceArgs = buildTransferChoiceArgs({
37087
+ sender,
37088
+ receiver,
37089
+ amount,
37090
+ instrument,
37091
+ inputHoldingCids,
37092
+ memo,
37093
+ nowMs,
37094
+ });
37095
+ const factory = await fetchTransferFactory(registryUrl, choiceArgs);
37096
+ const choiceContextData = factory.choiceContext.choiceContextData;
37097
+ if (!choiceContextData) {
37098
+ throw new Error("Transfer factory choice context is missing");
37099
+ }
37100
+ choiceArgs.extraArgs.context = choiceContextData;
37101
+ const disclosedContracts = (factory.choiceContext?.disclosedContracts ?? []).flatMap((raw) => {
37102
+ const disclosedContract = toDisclosedContract(raw);
37103
+ return disclosedContract ? [disclosedContract] : [];
37104
+ });
37105
+ // Command ID: client-supplied identifier used to deduplicate submissions
37106
+ const commandId = `canton-${memo}`;
37107
+ return {
37108
+ commandId,
37109
+ commands: [
37110
+ {
37111
+ ExerciseCommand: {
37112
+ templateId: TRANSFER_FACTORY_INTERFACE_ID,
37113
+ contractId: factory.factoryId,
37114
+ choice: TRANSFER_FACTORY_CHOICE,
37115
+ choiceArgument: buildPrepareChoiceArgument(choiceArgs),
37116
+ },
37117
+ },
37118
+ ],
37119
+ actAs: [sender],
37120
+ disclosedContracts,
37121
+ };
37122
+ }
37123
+
36032
37124
  const useExecuteTransaction = (squidRoute) => {
36033
37125
  const { fromChain, toChain, fromToken, toToken, isSameChain } = useSwap();
36034
37126
  // A route completes on source tx only if it's same-chain AND
@@ -36037,7 +37129,7 @@ const useExecuteTransaction = (squidRoute) => {
36037
37129
  !!fromChain &&
36038
37130
  !!squidRoute &&
36039
37131
  squidRoute.estimate.actions.every((a) => isActionCompletedOnSourceTx(a, fromChain.chainId));
36040
- const { evmSigner, cosmosSigner, solanaSigner, bitcoinSigner, suiSigner, xrplSigner, stellarSigner, } = useSigner({
37132
+ const { evmSigner, cosmosSigner, solanaSigner, bitcoinSigner, suiSigner, xrplSigner, stellarSigner, cantonSigner, } = useSigner({
36041
37133
  chain: fromChain,
36042
37134
  });
36043
37135
  const { findToken } = useSquidTokens();
@@ -36292,7 +37384,7 @@ const useExecuteTransaction = (squidRoute) => {
36292
37384
  });
36293
37385
  const swapMutationSolana = reactQuery.useMutation(async ({ id, route }) => {
36294
37386
  try {
36295
- if (!route) {
37387
+ if (!route?.transactionRequest) {
36296
37388
  throw new Error("Route is required");
36297
37389
  }
36298
37390
  if (!solanaSigner) {
@@ -36301,10 +37393,10 @@ const useExecuteTransaction = (squidRoute) => {
36301
37393
  if (!route.params.fromAddress || !route.params.toAddress) {
36302
37394
  throw new Error("From or to address is required");
36303
37395
  }
36304
- const isDirectTransfer = isDepositRoute(route);
37396
+ const isChainflipDirectTransfer = isChainflipDepositRoute(route);
36305
37397
  // Means it's a transfer to a deposit address
36306
37398
  // Instead of a Swap/Contract call using a DEX like Jupiter
36307
- if (isDirectTransfer) {
37399
+ if (isChainflipDirectTransfer) {
36308
37400
  // Get the deposit address from the squidRoute
36309
37401
  const depositData = useDepositAddressStore.getState().deposit;
36310
37402
  // Validate params
@@ -36312,7 +37404,7 @@ const useExecuteTransaction = (squidRoute) => {
36312
37404
  throw new Error("Deposit address is required");
36313
37405
  }
36314
37406
  const signature = await executeSolanaTransfer({
36315
- amount: BigInt(route.params.fromAmount),
37407
+ amount: BigInt(route.params.fromAmount ?? ""),
36316
37408
  target: depositData.depositAddress,
36317
37409
  signer: solanaSigner,
36318
37410
  connection: solanaConnection,
@@ -36322,7 +37414,7 @@ const useExecuteTransaction = (squidRoute) => {
36322
37414
  const txParams = setTransactionState({
36323
37415
  route,
36324
37416
  txHash,
36325
- transactionIdForStatus: depositData.chainflipStatusTrackingId,
37417
+ transactionIdForStatus: depositData.statusTrackingId,
36326
37418
  userAddress: sourceUserAddress,
36327
37419
  status: exports.TransactionStatus.INITIAL_LOADING,
36328
37420
  sourceStatus: exports.TransactionStatus.ONGOING,
@@ -36373,7 +37465,7 @@ const useExecuteTransaction = (squidRoute) => {
36373
37465
  }
36374
37466
  });
36375
37467
  const swapMutationBitcoin = reactQuery.useMutation(async ({ id, route }) => {
36376
- const { depositAddress, amount: sendAmount, chainflipStatusTrackingId, } = useDepositAddressStore.getState().deposit ?? {};
37468
+ const { depositAddress, amount: sendAmount, statusTrackingId, } = useDepositAddressStore.getState().deposit ?? {};
36377
37469
  if (!depositAddress) {
36378
37470
  throw new Error(`Invalid deposit address: ${depositAddress}`);
36379
37471
  }
@@ -36396,7 +37488,7 @@ const useExecuteTransaction = (squidRoute) => {
36396
37488
  txHash,
36397
37489
  // When bridging from Bitcoin we need to send the chainflipId to the status endpoint
36398
37490
  // instead of the Bitcoin transaction hash
36399
- transactionIdForStatus: chainflipStatusTrackingId,
37491
+ transactionIdForStatus: statusTrackingId,
36400
37492
  userAddress: sourceUserAddress,
36401
37493
  status: exports.TransactionStatus.INITIAL_LOADING,
36402
37494
  sourceStatus: exports.TransactionStatus.ONGOING,
@@ -36588,6 +37680,56 @@ const useExecuteTransaction = (squidRoute) => {
36588
37680
  const sentTransaction = await client.sendTransaction(signedTransaction);
36589
37681
  await client.waitForTransaction(sentTransaction.hash);
36590
37682
  }, {});
37683
+ const swapMutationCanton = reactQuery.useMutation(async ({ id, route }) => {
37684
+ if (!route?.transactionRequest) {
37685
+ throw new Error("Route is required");
37686
+ }
37687
+ if (!cantonSigner) {
37688
+ throw new Error("Canton signer is required");
37689
+ }
37690
+ if (!isDepositAddressDirectTransferRoute(route.transactionRequest)) {
37691
+ throw new Error("Invalid Canton route type");
37692
+ }
37693
+ const receiver = route.transactionRequest.target;
37694
+ const orderHash = route.transactionRequest.data;
37695
+ const fromAmount = route.params.fromAmount;
37696
+ const token = findToken(route.params.fromToken, route.params.fromChain);
37697
+ if (!sourceUserAddress || !fromAmount || !token) {
37698
+ throw new Error("Need all parameters");
37699
+ }
37700
+ const amount = formatBNToReadable(fromAmount, token.decimals);
37701
+ dispatchSignatureRequestEvent(route);
37702
+ const transferParams = await buildCantonTransfer(cantonSigner, {
37703
+ sender: sourceUserAddress,
37704
+ receiver,
37705
+ amount,
37706
+ token,
37707
+ memo: orderHash,
37708
+ nowMs: Date.now(),
37709
+ });
37710
+ const result = await cantonSigner.prepareExecuteAndWait(transferParams);
37711
+ const txHash = result.tx?.payload?.updateId ?? "";
37712
+ if (txHash) {
37713
+ resetQueriesAfterTxSigned();
37714
+ }
37715
+ WidgetEvents.getInstance().dispatchSwapExecuteCall(route, txHash);
37716
+ const txParams = setTransactionState({
37717
+ route,
37718
+ txHash: txHash,
37719
+ userAddress: sourceUserAddress,
37720
+ status: exports.TransactionStatus.INITIAL_LOADING,
37721
+ sourceStatus: exports.TransactionStatus.ONGOING,
37722
+ id,
37723
+ });
37724
+ if (txParams) {
37725
+ addSwapTransaction({
37726
+ ...txParams,
37727
+ params: route.params,
37728
+ estimate: route.estimate,
37729
+ });
37730
+ }
37731
+ return txHash;
37732
+ });
36591
37733
  const handleTransactionSuccess = React.useCallback((id) => {
36592
37734
  const currentTx = getTransaction(id);
36593
37735
  queryClient.invalidateQueries(getPrefixKey(exports.QueryKeys.Balances));
@@ -36646,7 +37788,7 @@ const useExecuteTransaction = (squidRoute) => {
36646
37788
  if (!mutationParams.route?.transactionRequest) {
36647
37789
  throw new Error("Route is required");
36648
37790
  }
36649
- const sourceChain = findChain(mutationParams.route.params?.fromChain);
37791
+ const sourceChain = findChain(mutationParams.route.params.fromChain);
36650
37792
  if (!sourceChain)
36651
37793
  throw new Error("Could not find source chain");
36652
37794
  // After getting signature (if needed), continue with the swap flow
@@ -36672,6 +37814,9 @@ const useExecuteTransaction = (squidRoute) => {
36672
37814
  case squidTypes.ChainType.STELLAR: {
36673
37815
  return swapMutationStellar.mutateAsync(mutationParams);
36674
37816
  }
37817
+ case squidTypes.ChainType.CANTON: {
37818
+ return swapMutationCanton.mutateAsync(mutationParams);
37819
+ }
36675
37820
  default:
36676
37821
  throw new Error(`Swap mutation not implemented for chain type: ${sourceChain.chainType}`);
36677
37822
  }
@@ -36844,7 +37989,7 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36844
37989
  const squid = useSquidStore((state) => state.squid);
36845
37990
  const fallbackAddress = useSwapRoutePersistStore((store) => store.swapRoute?.fallbackAddress);
36846
37991
  const depositRefundAddress = useSwapRoutePersistStore((store) => store.swapRoute?.depositRefundAddress);
36847
- const { isAvailableAsPaymentMethod, isEnabled: isDepositAddressEnabled } = useDepositAddress();
37992
+ const { isDepositAddressActive } = useDepositAddress();
36848
37993
  const getRouteMutation = useGetRoute();
36849
37994
  const { fromChain, toChain, fromPrice, destinationAddress: { address: destinationAddress } = {}, fromToken, toToken, } = useSwap();
36850
37995
  const { connectedAddress: { address: sourceConnectedAddress }, } = useMultiChainWallet(fromChain);
@@ -36852,8 +37997,8 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36852
37997
  // Tokens will be sent to this address in case of swap failure
36853
37998
  //
36854
37999
  // If deposit address is not selected, we use the connected address as the source address instead
36855
- const sourceUserAddress = isDepositAddressEnabled && isAvailableAsPaymentMethod
36856
- ? depositRefundAddress ?? sourceConnectedAddress
38000
+ const sourceUserAddress = isDepositAddressActive
38001
+ ? (depositRefundAddress ?? sourceConnectedAddress)
36857
38002
  : sourceConnectedAddress;
36858
38003
  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), [
36859
38004
  fromChain?.chainId,
@@ -36997,94 +38142,50 @@ function useSendTransactionStatus({ chain, txHash, }) {
36997
38142
  * Fetch status of a Swap transaction
36998
38143
  */
36999
38144
  const useSwapTransactionStatus = ({ transaction, retry = 25, refetchOnWindowFocus = "always", enabled = true, }) => {
37000
- const config = useConfigStore((state) => state.config);
37001
- const isInitialized = useConfigStore((state) => state.isInitialized);
37002
38145
  const { replaceSwapTransactionStatus } = useHistory();
37003
38146
  const findTransaction = useHistoryStore((state) => state.findTransaction);
37004
- const [isTransactionComplete, setIsTransactionComplete] = React.useState(false);
37005
- const [refetchInterval, setRefetchInterval] = React.useState(getSwapTxStatusRefetchInterval(transaction));
37006
- const { getChainType } = useSquidChains();
37007
38147
  const currentHistoryItem = React.useMemo(() => findTransaction({
37008
38148
  transactionId: transaction?.transactionId,
37009
38149
  txType: exports.HistoryTxType.SWAP,
37010
38150
  }), [findTransaction, transaction?.transactionId]);
37011
- /**
37012
- * Transaction status endpoint
37013
- * Squid api is using axelar endpoint and parsing the response
37014
- * @returns {StatusResponse} Status response
37015
- */
37016
- const fetchTransactionStatusWithLatestConfig = React.useCallback(async () => {
37017
- const latestConfig = useConfigStore.getState().config;
37018
- return fetchSwapTransactionStatus({
37019
- transaction,
37020
- integratorId: latestConfig.integratorId,
37021
- apiUrl: latestConfig.apiUrl,
37022
- });
37023
- }, [transaction]);
37024
- const transactionStatusQuery = reactQuery.useQuery(keys().swapTransactionStatus(transaction?.transactionId), fetchTransactionStatusWithLatestConfig, {
38151
+ const transactionStatusQuery = useSwapStatusQuery({
38152
+ transaction,
38153
+ retry,
38154
+ refetchOnWindowFocus,
37025
38155
  enabled: enabled &&
37026
- transaction?.transactionId !== "0" &&
37027
- !!transaction?.transactionId &&
37028
- !!transaction.fromAddress &&
37029
- !!config.apiUrl &&
37030
- transaction !== undefined &&
37031
- !isTransactionComplete &&
37032
- isInitialized &&
37033
38156
  !!currentHistoryItem &&
37034
38157
  !isHistoryTransactionEnded({
37035
38158
  data: currentHistoryItem?.data,
37036
38159
  txType: exports.HistoryTxType.SWAP,
37037
38160
  }),
37038
- refetchInterval(statusResponse) {
37039
- // If the status response is something telling that the transaction
37040
- // is finished, then store transaction history state if success
37041
- // And return false to indicate refetcher to stop
37042
- if (statusResponse &&
37043
- transactionEndStatuses.includes(getTransactionStatus(statusResponse) ?? "")) {
37044
- return false;
37045
- }
37046
- return refetchInterval; // Had to handle a variable here because after onError, we want the interval to stop
38161
+ onEndStatus: ({ status, statusResponse }) => {
38162
+ if (!transaction?.transactionId)
38163
+ return;
38164
+ replaceSwapTransactionStatus({
38165
+ transactionId: transaction.transactionId,
38166
+ statusResponse,
38167
+ status,
38168
+ });
37047
38169
  },
37048
- // At the moment Cosmos indexing takes more time, so need more time between retries
37049
- retryDelay: getChainType(transaction?.fromChain) === squidTypes.ChainType.COSMOS ? 5000 : 3000,
37050
- retry: getChainType(transaction?.fromChain) === squidTypes.ChainType.COSMOS ? 6 : retry,
37051
- refetchOnWindowFocus,
37052
- onSuccess: (statusResponse) => {
37053
- // Dispatch event
37054
- WidgetEvents.getInstance().dispatchSwapStatus(statusResponse.squidTransactionStatus ?? "");
37055
- const endStatus = getTransactionEndStatus({ statusResponse });
37056
- if (endStatus && transaction?.transactionId) {
37057
- setIsTransactionComplete(true);
37058
- replaceSwapTransactionStatus({
37059
- transactionId: transaction.transactionId,
37060
- statusResponse,
37061
- status: endStatus,
37062
- });
37063
- }
38170
+ onNotFound: () => {
38171
+ if (!transaction?.transactionId)
38172
+ return;
38173
+ replaceSwapTransactionStatus({
38174
+ transactionId: transaction.transactionId,
38175
+ statusResponse: undefined,
38176
+ status: exports.TransactionStatus.NOT_FOUND,
38177
+ });
37064
38178
  },
37065
- onError: (error) => {
37066
- // `fetchTransactionStatus` throws an error with a cause being an AxiosError
37067
- const is404 = is404Error(error.cause);
38179
+ onError: () => {
37068
38180
  if (!transaction?.transactionId)
37069
38181
  return;
37070
- if (is404) {
37071
- replaceSwapTransactionStatus({
37072
- transactionId: transaction.transactionId,
37073
- statusResponse: undefined,
37074
- status: exports.TransactionStatus.NOT_FOUND,
37075
- });
37076
- }
37077
- else {
37078
- setRefetchInterval(-1);
37079
- setIsTransactionComplete(true);
37080
- replaceSwapTransactionStatus({
37081
- transactionId: transaction.transactionId,
37082
- statusResponse: undefined,
37083
- status: exports.TransactionStatus.ERROR,
37084
- });
37085
- }
38182
+ replaceSwapTransactionStatus({
38183
+ transactionId: transaction.transactionId,
38184
+ statusResponse: undefined,
38185
+ status: exports.TransactionStatus.ERROR,
38186
+ });
37086
38187
  },
37087
- });
38188
+ }).transactionStatusQuery;
37088
38189
  return {
37089
38190
  transactionStatusQuery,
37090
38191
  latestStatus: transactionStatusQuery.data
@@ -37483,8 +38584,10 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37483
38584
  }
37484
38585
  if (assetsColorsResponse.status === "fulfilled") {
37485
38586
  useAssetsColorsStore.setState(assetsColorsResponse.value);
37486
- initializeSquidWithAssetsColors(squid, assetsColorsResponse.value);
37487
38587
  }
38588
+ initializeSquidData(squid, assetsColorsResponse.status === "fulfilled"
38589
+ ? assetsColorsResponse.value
38590
+ : undefined);
37488
38591
  const shouldResetSwapRouteStore =
37489
38592
  // reset swap route if specified in config
37490
38593
  !config?.loadPreviousStateFromLocalStorage ||
@@ -37516,8 +38619,8 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37516
38619
  error instanceof Error;
37517
38620
  if (isBackendDown) {
37518
38621
  const maintenanceMessage = isAxios503Error
37519
- ? error.response?.data
37520
- ?.message ?? undefined
38622
+ ? (error.response?.data
38623
+ ?.message ?? undefined)
37521
38624
  : "Unable to connect to Squid. Please check your connection or try again later.";
37522
38625
  // Even with an error, we want wagmi to be defined so that we can display the maintenance mode layout
37523
38626
  // Create wagmi config with mainnet as fallback in maintenance mode
@@ -37552,13 +38655,14 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37552
38655
  }, [initializeSdk]);
37553
38656
  return wagmiConfig ? (React.createElement(wagmi.WagmiProvider, { reconnectOnMount: false, config: wagmiConfig },
37554
38657
  React.createElement(reactQuery.QueryClientProvider, { client: queryClient },
37555
- React.createElement(StellarProvider, null,
37556
- React.createElement(EvmProvider, null,
37557
- React.createElement(XrplProvider, null,
37558
- React.createElement(SuiProvider, null,
37559
- React.createElement(SolanaProvider, null,
37560
- React.createElement(BitcoinProvider, null,
37561
- React.createElement(CosmosProvider, null, children)))))))))) : (placeholder);
38658
+ React.createElement(CantonProvider, null,
38659
+ React.createElement(StellarProvider, null,
38660
+ React.createElement(EvmProvider, null,
38661
+ React.createElement(XrplProvider, null,
38662
+ React.createElement(SuiProvider, null,
38663
+ React.createElement(SolanaProvider, null,
38664
+ React.createElement(BitcoinProvider, null,
38665
+ React.createElement(CosmosProvider, null, children))))))))))) : (placeholder);
37562
38666
  };
37563
38667
 
37564
38668
  exports.CHAIN_IDS = CHAIN_IDS;
@@ -37574,13 +38678,13 @@ exports.SquidProvider = SquidProvider;
37574
38678
  exports.TX_STATUS_CONSTANTS = TX_STATUS_CONSTANTS;
37575
38679
  exports.WidgetEvents = WidgetEvents;
37576
38680
  exports.Wo = Wo;
37577
- exports.accessProperty = accessProperty;
37578
38681
  exports.adaptiveRound = adaptiveRound;
37579
38682
  exports.addEthereumChain = addEthereumChain;
37580
38683
  exports.addTokenToWallet = addTokenToWallet;
37581
38684
  exports.areSameAddress = areSameAddress;
37582
38685
  exports.areTokenSymbolsCompatible = areTokenSymbolsCompatible;
37583
38686
  exports.assetsBaseUrl = assetsBaseUrl;
38687
+ exports.buildFallbackWallets = buildFallbackWallets;
37584
38688
  exports.buildUrlSearchParamsFromSwapEvent = buildUrlSearchParamsFromSwapEvent;
37585
38689
  exports.buildXrplTrustSetTx = buildXrplTrustSetTx;
37586
38690
  exports.calculateTotal24hChange = calculateTotal24hChange;
@@ -37673,13 +38777,14 @@ exports.getXummClient = getXummClient;
37673
38777
  exports.groupTokensByChainId = groupTokensByChainId;
37674
38778
  exports.groupTokensBySymbol = groupTokensBySymbol;
37675
38779
  exports.handleTransactionErrorEvents = handleTransactionErrorEvents;
37676
- exports.initializeSquidWithAssetsColors = initializeSquidWithAssetsColors;
38780
+ exports.initializeSquidData = initializeSquidData;
37677
38781
  exports.is404Error = is404Error;
37678
38782
  exports.isActionCompletedOnSourceTx = isActionCompletedOnSourceTx;
37679
38783
  exports.isChainflipBridgeTransaction = isChainflipBridgeTransaction;
38784
+ exports.isChainflipDepositRoute = isChainflipDepositRoute;
37680
38785
  exports.isCoralBridgeAction = isCoralBridgeAction;
37681
38786
  exports.isCosmosAddressValid = isCosmosAddressValid;
37682
- exports.isDepositRoute = isDepositRoute;
38787
+ exports.isDepositAddressDirectTransferRoute = isDepositAddressDirectTransferRoute;
37683
38788
  exports.isEmptyObject = isEmptyObject;
37684
38789
  exports.isEvmChainNotSupportedError = isEvmChainNotSupportedError;
37685
38790
  exports.isEvmosChain = isEvmosChain;
@@ -37695,6 +38800,7 @@ exports.isStatusError = isStatusError;
37695
38800
  exports.isStellarAddressValid = isStellarAddressValid;
37696
38801
  exports.isStellarIssuedToken = isStellarIssuedToken;
37697
38802
  exports.isStellarToken = isStellarToken;
38803
+ exports.isSupportedChainType = isSupportedChainType;
37698
38804
  exports.isSwapRouteError = isSwapRouteError;
37699
38805
  exports.isUserRejectionError = isUserRejectionError;
37700
38806
  exports.isValidHorizonAsset = isValidHorizonAsset;
@@ -37759,6 +38865,7 @@ exports.useCountryDetails = useCountryDetails;
37759
38865
  exports.useCurrencyDetails = useCurrencyDetails;
37760
38866
  exports.useDebouncedValue = useDebouncedValue;
37761
38867
  exports.useDepositAddress = useDepositAddress;
38868
+ exports.useDepositTransactionStatus = useDepositTransactionStatus;
37762
38869
  exports.useEnsDataForAddress = useEnsDataForAddress;
37763
38870
  exports.useEnsSearch = useEnsSearch;
37764
38871
  exports.useEstimate = useEstimate;
@@ -37825,4 +38932,4 @@ exports.useXrplTrustLine = useXrplTrustLine;
37825
38932
  exports.waitForReceiptWithRetry = waitForReceiptWithRetry;
37826
38933
  exports.walletIconBaseUrl = walletIconBaseUrl;
37827
38934
  exports.walletSupportsChainType = walletSupportsChainType;
37828
- //# sourceMappingURL=index-sCLxPcqi.js.map
38935
+ //# sourceMappingURL=index-Dzir2lUQ.js.map