@0xsquid/react-hooks 8.9.0 → 8.9.1-beta-canton-wallet-connection.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 (68) 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/constants.d.ts +3 -0
  5. package/dist/core/fallbackWallets.d.ts +16 -0
  6. package/dist/core/providers/CantonProvider.d.ts +19 -0
  7. package/dist/core/types/canton.d.ts +58 -0
  8. package/dist/core/types/cosmos.d.ts +5 -0
  9. package/dist/core/types/wallet.d.ts +15 -7
  10. package/dist/core/wallets.d.ts +5 -0
  11. package/dist/hooks/canton/useCanton.d.ts +2 -0
  12. package/dist/hooks/canton/useCantonWallets.d.ts +8 -0
  13. package/dist/hooks/chains/useSquidChains.d.ts +1 -0
  14. package/dist/hooks/index.d.ts +1 -0
  15. package/dist/hooks/store/useDepositAddressStore.d.ts +18 -5
  16. package/dist/hooks/swap/useDepositAddress.d.ts +6 -7
  17. package/dist/hooks/tokens/useBalance.d.ts +1 -0
  18. package/dist/hooks/tokens/useNativeBalance.d.ts +1 -0
  19. package/dist/hooks/tokens/useSquidTokens.d.ts +1 -0
  20. package/dist/hooks/transaction/useDepositTransactionStatus.d.ts +20 -0
  21. package/dist/hooks/transaction/useSwapStatusQuery.d.ts +29 -0
  22. package/dist/hooks/wallet/useMultiChainWallet.d.ts +55 -29
  23. package/dist/hooks/wallet/useSigner.d.ts +1 -0
  24. package/dist/hooks/wallet/useWallet.d.ts +59 -29
  25. package/dist/hooks/xrpl/useXrplWallets.d.ts +2 -2
  26. package/dist/{index-BL_AUWQg.js → index-B8h1ypYK.js} +1364 -195
  27. package/dist/index-B8h1ypYK.js.map +1 -0
  28. package/dist/{index-DcBFug8t.js → index-doLvokYY.js} +1349 -177
  29. package/dist/index-doLvokYY.js.map +1 -0
  30. package/dist/{index.es-1XEAWjab.js → index.es-CuIvGVFi.js} +4 -3
  31. package/dist/index.es-CuIvGVFi.js.map +1 -0
  32. package/dist/{index.es-DSQHpime.js → index.es-reWGC10l.js} +4 -3
  33. package/dist/index.es-reWGC10l.js.map +1 -0
  34. package/dist/index.esm.js +3 -2
  35. package/dist/index.esm.js.map +1 -1
  36. package/dist/index.js +9 -5
  37. package/dist/index.js.map +1 -1
  38. package/dist/{secretService-B1SDXLS1.js → secretService-3g7QoMaM.js} +4 -3
  39. package/dist/{secretService-B1SDXLS1.js.map → secretService-3g7QoMaM.js.map} +1 -1
  40. package/dist/{secretService-DxQ78j5I.js → secretService-DMcFUD-e.js} +4 -3
  41. package/dist/{secretService-DxQ78j5I.js.map → secretService-DMcFUD-e.js.map} +1 -1
  42. package/dist/server.d.ts +1 -1
  43. package/dist/server.esm.js +7 -1
  44. package/dist/server.esm.js.map +1 -1
  45. package/dist/server.js +7 -0
  46. package/dist/server.js.map +1 -1
  47. package/dist/services/external/onrampAdapter.d.ts +3 -4
  48. package/dist/services/external/rpcService.d.ts +17 -0
  49. package/dist/services/internal/assetsService.d.ts +10 -1
  50. package/dist/services/internal/cantonDamlValue.d.ts +75 -0
  51. package/dist/services/internal/cantonService.d.ts +64 -0
  52. package/dist/services/internal/cantonTransferService.d.ts +93 -0
  53. package/dist/services/internal/transactionService.d.ts +5 -1
  54. package/dist/services/internal/walletService.d.ts +3 -6
  55. package/dist/{stellarService.client-C4TLBEpm.js → stellarService.client-DLPxIX3n.js} +5 -4
  56. package/dist/{stellarService.client-C4TLBEpm.js.map → stellarService.client-DLPxIX3n.js.map} +1 -1
  57. package/dist/{stellarService.client-CkP5ng2n.js → stellarService.client-DMdUVPJ8.js} +5 -4
  58. package/dist/{stellarService.client-CkP5ng2n.js.map → stellarService.client-DMdUVPJ8.js.map} +1 -1
  59. package/dist/tests/cantonService.test.d.ts +1 -0
  60. package/dist/tests/cantonTransferService.test.d.ts +1 -0
  61. package/dist/tests/cip103Client.test.d.ts +1 -0
  62. package/dist/tests/fallbackWallets.test.d.ts +1 -0
  63. package/dist/tests/wallets.test.d.ts +1 -0
  64. package/package.json +3 -2
  65. package/dist/index-BL_AUWQg.js.map +0 -1
  66. package/dist/index-DcBFug8t.js.map +0 -1
  67. package/dist/index.es-1XEAWjab.js.map +0 -1
  68. package/dist/index.es-DSQHpime.js.map +0 -1
@@ -10,13 +10,13 @@ import axios, { AxiosError } from 'axios';
10
10
  import { WalletConnectModal } from '@walletconnect/modal';
11
11
  import UniversalProvider from '@walletconnect/universal-provider';
12
12
  import { isValidXAddress, isValidClassicAddress } from 'ripple-address-codec';
13
+ import BigNumber, { BigNumber as BigNumber$1 } from 'bignumber.js';
13
14
  import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID, getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, createTransferInstruction } from '@solana/spl-token';
14
15
  import { StandardWalletAdapter } from '@solana/wallet-standard-wallet-adapter-base';
15
16
  import { PublicKey, Transaction, SystemProgram, VersionedTransaction, Connection } from '@solana/web3.js';
16
17
  import { StrKey, Networks, nativeToScVal, Address, rpc, TransactionBuilder, BASE_FEE, Contract, TimeoutInfinite, scValToNative, Asset, Operation, Transaction as Transaction$1, xdr } from '@stellar/stellar-sdk';
17
18
  import { SUI_TESTNET_CHAIN, SUI_MAINNET_CHAIN } from '@mysten/wallet-standard';
18
19
  import { CloudflareProvider, JsonRpcProvider, ethers, Interface, BrowserProvider, JsonRpcSigner, Contract as Contract$1, isError } from 'ethers';
19
- import BigNumber$1, { BigNumber } from 'bignumber.js';
20
20
  import { countries } from 'countries-list';
21
21
  import getSymbolFromCurrency from 'currency-symbol-map';
22
22
  import Fuse from 'fuse.js';
@@ -24,6 +24,7 @@ import { create } from 'zustand';
24
24
  import { persist } from 'zustand/middleware';
25
25
  import { useAccount, useConnectors, useConnect, useDisconnect, useSwitchChain, useBalance, useReadContract, createConfig, http, useWalletClient, usePublicClient, WagmiProvider } from 'wagmi';
26
26
  import SafeAppsSDK, { TransactionStatus as TransactionStatus$1 } from '@safe-global/safe-apps-sdk';
27
+ import { createCantonClient, WindowTransport } from '@sigilry/dapp';
27
28
  import { getWallets } from '@wallet-standard/core';
28
29
  import { SlushWallet } from '@mysten/slush-wallet';
29
30
  import { StargateClient, SigningStargateClient } from '@cosmjs/stargate';
@@ -57,6 +58,7 @@ const solanaZeroAddress = "11111111111111111111111111111111";
57
58
  const suiZeroAddress = "0x0000000000000000000000000000000000000000";
58
59
  const xrplZeroAddress = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
59
60
  const stellarZeroAddress = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
61
+ const cantonZeroAddress = "none::12200000000000000000000000000000000000000000000000000000000000000000";
60
62
  const chainTypeToZeroAddressMap = {
61
63
  [ChainType.EVM]: zeroAddress$1,
62
64
  [ChainType.COSMOS]: cosmosZeroAddress,
@@ -65,6 +67,7 @@ const chainTypeToZeroAddressMap = {
65
67
  [ChainType.SUI]: suiZeroAddress,
66
68
  [ChainType.XRPL]: xrplZeroAddress,
67
69
  [ChainType.STELLAR]: stellarZeroAddress,
70
+ [ChainType.CANTON]: cantonZeroAddress,
68
71
  };
69
72
  const nativeEvmTokenAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
70
73
  const nativeCosmosTokenAddress = "uosmo";
@@ -73,6 +76,7 @@ const nativeBitcoinTokenAddress = "satoshi";
73
76
  const nativeSuiTokenAddress = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI";
74
77
  const nativeXrplTokenAddress = "xrp";
75
78
  const nativeStellarTokenAddress = "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA";
79
+ const nativeCantonTokenAddress = "DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc";
76
80
  // by setting slippage to undefined, it's set to "auto"
77
81
  const defaultSlippage = undefined;
78
82
  const destinationAddressResetValue = "null";
@@ -85,6 +89,8 @@ const DEFAULT_ROUTE_REFETCH_INTERVAL = 30_000;
85
89
  const SOLANA_RPC_URL = "https://meredith-ute2ko-fast-mainnet.helius-rpc.com";
86
90
  const INTEGRATOR_ID = "squid-widget-playground-local-cd33cba6-7e12-4fcc-8d5d-35e286f655ea";
87
91
  const DEFAULT_COUNTRY_CODE = "US";
92
+ // TODO: pending confirmation with Backend team on final URL
93
+ const CANTON_AMULET_REGISTRY_URL = "/api/canton/scan-proxy";
88
94
  const CHAIN_IDS = {
89
95
  // Cosmos
90
96
  OSMOSIS: "osmosis-1",
@@ -136,6 +142,7 @@ const CHAIN_IDS = {
136
142
  XRPL_TESTNET: "xrpl-testnet",
137
143
  STELLAR: "stellar-mainnet",
138
144
  STELLAR_TESTNET: "stellar-testnet",
145
+ CANTON: "canton",
139
146
  };
140
147
  const chainTypeToDefaultChainIdMap = {
141
148
  [ChainType.EVM]: CHAIN_IDS.ETHEREUM,
@@ -145,6 +152,7 @@ const chainTypeToDefaultChainIdMap = {
145
152
  [ChainType.SUI]: CHAIN_IDS.SUI,
146
153
  [ChainType.XRPL]: CHAIN_IDS.XRPL,
147
154
  [ChainType.STELLAR]: CHAIN_IDS.STELLAR,
155
+ [ChainType.CANTON]: CHAIN_IDS.CANTON,
148
156
  };
149
157
  const chainTypeToNativeTokenAddressMap = {
150
158
  [ChainType.EVM]: nativeEvmTokenAddress,
@@ -154,6 +162,7 @@ const chainTypeToNativeTokenAddressMap = {
154
162
  [ChainType.SUI]: nativeSuiTokenAddress,
155
163
  [ChainType.XRPL]: nativeXrplTokenAddress,
156
164
  [ChainType.STELLAR]: nativeStellarTokenAddress,
165
+ [ChainType.CANTON]: nativeCantonTokenAddress,
157
166
  };
158
167
  const defaultConfigValues = {
159
168
  integratorId: INTEGRATOR_ID,
@@ -20536,6 +20545,17 @@ var WindowWalletFlag;
20536
20545
  })(WindowWalletFlag || (WindowWalletFlag = {}));
20537
20546
 
20538
20547
  const walletIconBaseUrl = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/wallets";
20548
+ /**
20549
+ * Dynamically accesses a nested property of an object based on a dot-separated string path.
20550
+ * Returns the value of the property if found, otherwise undefined.
20551
+ */
20552
+ const accessProperty = (object, path) => {
20553
+ const value = get$2(object, path);
20554
+ if (value === undefined) {
20555
+ console.error(`Property "${path}" not found while reading object`, object);
20556
+ }
20557
+ return value;
20558
+ };
20539
20559
  const bitcoinWallets = [
20540
20560
  {
20541
20561
  name: "Unisat",
@@ -20832,6 +20852,34 @@ const walletStoreLinks = {
20832
20852
  },
20833
20853
  };
20834
20854
 
20855
+ /**
20856
+ * Wallets to show regardless of whether they're detected.
20857
+ * Useful when we want to link to the browser extension store
20858
+ * for wallets that are automatically discovered (i.e. EVM, SOLANA, CANTON...)
20859
+ */
20860
+ const fallbackWallets = [
20861
+ {
20862
+ chainType: ChainType.CANTON,
20863
+ id: "ldmohiccoioolenadmogclhoklmanpgi",
20864
+ name: "Send Connect",
20865
+ connectorName: "Send Connect",
20866
+ icon: `${walletIconBaseUrl}/canton-send.webp`,
20867
+ links: {
20868
+ chrome: "https://chromewebstore.google.com/detail/send-connect/ldmohiccoioolenadmogclhoklmanpgi",
20869
+ },
20870
+ },
20871
+ {
20872
+ chainType: ChainType.CANTON,
20873
+ id: "lpnfhpbpmlobjlgkdmnjieeihjmihhjd",
20874
+ name: "Console Wallet",
20875
+ connectorName: "Console Wallet",
20876
+ icon: `${walletIconBaseUrl}/canton-console.webp`,
20877
+ links: {
20878
+ chrome: "https://chromewebstore.google.com/detail/console-wallet/lpnfhpbpmlobjlgkdmnjieeihjmihhjd",
20879
+ },
20880
+ },
20881
+ ];
20882
+
20835
20883
  // Validation taken from Squid API repo
20836
20884
  const isBitcoinAddressValid = (address$1) => {
20837
20885
  try {
@@ -20851,6 +20899,142 @@ const isBitcoinAddressValid = (address$1) => {
20851
20899
  }
20852
20900
  };
20853
20901
 
20902
+ // Canton PartyID = address
20903
+ const CANTON_PARTY_ID_SEPARATOR = "::";
20904
+ /** Canton Coin's well-known token-standard instrument id (its address carries no id prefix). */
20905
+ const CANTON_AMULET_INSTRUMENT_ID = "Amulet";
20906
+ function isCantonAddressValid(address) {
20907
+ // Canton address format: `name::fingerprint`, where name is an arbitrary string
20908
+ // and fingerprint is a 64-character hex string with a 1220 prefix (SHA-256 hash of the public key)
20909
+ const parts = address.split(CANTON_PARTY_ID_SEPARATOR);
20910
+ if (parts.length !== 2)
20911
+ return false;
20912
+ const [name, fingerprint] = parts;
20913
+ return name.length > 0 && /^1220[0-9a-f]{64}$/.test(fingerprint);
20914
+ }
20915
+ /**
20916
+ * Splice token-standard Holding interface id. A party's balance for an
20917
+ * instrument is the sum of `amount` across active contracts implementing this interface.
20918
+ */
20919
+ const CANTON_HOLDING_INTERFACE_ID = "#splice-api-token-holding-v1:Splice.Api.Token.HoldingV1:Holding";
20920
+ /**
20921
+ * Derive the token-standard instrument `{ admin, id }` from a Squid Canton token
20922
+ * address (use the case-sensitive `originalAddress`), or `null` when the address
20923
+ * is not a valid Canton token address.
20924
+ *
20925
+ * The admin party is the last two `::` segments (`name::fingerprint`); the
20926
+ * instrument id is everything before that. Canton Coin has no id prefix
20927
+ * (`DSO::1220…`) and uses the well-known id `Amulet`.
20928
+ * - `DSO::1220…` -> { admin: "DSO::1220…", id: "Amulet" }
20929
+ * - `USDCx::decentralized-usdc-…::12208…` -> { admin: "decentralized-usdc-…::12208…", id: "USDCx" }
20930
+ */
20931
+ function parseCantonInstrument(address) {
20932
+ const segments = address.split(CANTON_PARTY_ID_SEPARATOR);
20933
+ if (segments.length < 2) {
20934
+ return null;
20935
+ }
20936
+ const admin = segments.slice(-2).join(CANTON_PARTY_ID_SEPARATOR);
20937
+ const idPrefix = segments.slice(0, -2).join(CANTON_PARTY_ID_SEPARATOR);
20938
+ return {
20939
+ admin,
20940
+ id: idPrefix.length > 0 ? idPrefix : CANTON_AMULET_INSTRUMENT_ID,
20941
+ };
20942
+ }
20943
+ /**
20944
+ * Body for `POST /v2/state/active-contracts`, filtered to the party's Holding
20945
+ * contracts with the interface view included (so we can read amount/instrument).
20946
+ *
20947
+ * ACS: Active Contract Set — the ledger's currently-active contracts (created and
20948
+ * not yet archived) as of a ledger offset.
20949
+ */
20950
+ function buildHoldingsAcsRequestBody(partyId, activeAtOffset) {
20951
+ return {
20952
+ activeAtOffset,
20953
+ eventFormat: {
20954
+ verbose: true,
20955
+ filtersByParty: {
20956
+ [partyId]: {
20957
+ cumulative: [
20958
+ {
20959
+ identifierFilter: {
20960
+ InterfaceFilter: {
20961
+ value: {
20962
+ interfaceId: CANTON_HOLDING_INTERFACE_ID,
20963
+ includeInterfaceView: true,
20964
+ includeCreatedEventBlob: false,
20965
+ },
20966
+ },
20967
+ },
20968
+ },
20969
+ ],
20970
+ },
20971
+ },
20972
+ },
20973
+ };
20974
+ }
20975
+ /**
20976
+ * Parse the party's Holding contracts (with contract ids) from a raw
20977
+ * `/v2/state/active-contracts` response
20978
+ * Defensive: skips entries it can't parse.
20979
+ */
20980
+ function parseCantonHoldings(acsResponse) {
20981
+ if (!Array.isArray(acsResponse))
20982
+ return [];
20983
+ const holdings = [];
20984
+ for (const entry of acsResponse) {
20985
+ const createdEvent = entry?.contractEntry?.JsActiveContract
20986
+ ?.createdEvent;
20987
+ const contractId = createdEvent?.contractId;
20988
+ const views = createdEvent?.interfaceViews;
20989
+ if (!contractId || !Array.isArray(views))
20990
+ continue;
20991
+ for (const view of views) {
20992
+ const value = view?.viewValue;
20993
+ const instrumentId = value?.instrumentId;
20994
+ if (!instrumentId?.admin ||
20995
+ instrumentId.id == null ||
20996
+ value.amount == null) {
20997
+ continue;
20998
+ }
20999
+ holdings.push({
21000
+ contractId,
21001
+ instrument: { admin: instrumentId.admin, id: instrumentId.id },
21002
+ amount: String(value.amount),
21003
+ // Locked holdings are not spendable, skip them
21004
+ locked: value.lock != null,
21005
+ });
21006
+ }
21007
+ }
21008
+ return holdings;
21009
+ }
21010
+ /**
21011
+ * Key used to group holdings by instrument.
21012
+ */
21013
+ function instrumentKey(admin, id) {
21014
+ return `${admin}|${id}`;
21015
+ }
21016
+ function cantonInstrumentKey(instrument) {
21017
+ return instrumentKey(instrument.admin, instrument.id);
21018
+ }
21019
+ /**
21020
+ * Group the (unlocked) Holding amounts by instrument from a raw
21021
+ * `/v2/state/active-contracts` response. Returns a map of instrument key
21022
+ * (`admin|id`) -> human-readable decimal string (the token-standard `amount`
21023
+ * is already a Decimal, not base units).
21024
+ */
21025
+ function groupCantonHoldingBalances(acsResponse) {
21026
+ const totals = {};
21027
+ for (const holding of parseCantonHoldings(acsResponse)) {
21028
+ // Locked holdings are not spendable, skip them
21029
+ if (holding.locked)
21030
+ continue;
21031
+ const key = cantonInstrumentKey(holding.instrument);
21032
+ const total = totals[key] ?? new BigNumber(0);
21033
+ totals[key] = total.plus(new BigNumber(holding.amount));
21034
+ }
21035
+ return Object.fromEntries(Object.entries(totals).map(([key, total]) => [key, total.toString(10)]));
21036
+ }
21037
+
20854
21038
  const solanaTokenProgramIdByAddress = {
20855
21039
  [TOKEN_PROGRAM_ID.toBase58()]: TOKEN_PROGRAM_ID,
20856
21040
  [TOKEN_2022_PROGRAM_ID.toBase58()]: TOKEN_2022_PROGRAM_ID,
@@ -20990,6 +21174,7 @@ const getSourceExplorerTxUrl = (chain, txID) => {
20990
21174
  case CHAIN_IDS.AGORIC:
20991
21175
  case CHAIN_IDS.XRPL:
20992
21176
  case CHAIN_IDS.XRPL_TESTNET:
21177
+ case CHAIN_IDS.CANTON:
20993
21178
  txSuffix = "/transactions/";
20994
21179
  break;
20995
21180
  case CHAIN_IDS.HEDERA:
@@ -21099,10 +21284,16 @@ const simplifyRouteAction = (action) => {
21099
21284
  };
21100
21285
  const fetchSwapTransactionStatus = async ({ transaction, integratorId, apiUrl, }) => {
21101
21286
  const statusEndpoint = `${apiUrl}/v2/status`;
21287
+ const isCanton = transaction?.fromChain === CHAIN_IDS.CANTON;
21288
+ // For Canton, the backend handles all tx detection/submission from the quoteId
21289
+ // alone, so no transactionId is sent — only the quoteId param below.
21290
+ const transactionId = isCanton
21291
+ ? undefined
21292
+ : (transaction?.transactionIdForStatus ?? transaction?.transactionId);
21102
21293
  try {
21103
21294
  const response = await axios.get(statusEndpoint, {
21104
21295
  params: {
21105
- transactionId: transaction?.transactionIdForStatus ?? transaction?.transactionId,
21296
+ transactionId,
21106
21297
  fromChainId: transaction?.fromChain,
21107
21298
  toChainId: transaction?.toChain,
21108
21299
  bridgeType: transaction?.bridgeType,
@@ -21149,7 +21340,7 @@ function isActionCompletedOnSourceTx(action, fromChainId) {
21149
21340
  function sleep(ms) {
21150
21341
  return new Promise((resolve) => setTimeout(resolve, ms));
21151
21342
  }
21152
- const isDepositRoute = (route) => {
21343
+ const isChainflipDepositRoute = (route) => {
21153
21344
  return (!!route &&
21154
21345
  route.transactionRequest?.type === SquidDataType.ChainflipDepositAddress);
21155
21346
  };
@@ -21174,6 +21365,12 @@ function isOnChainTxData(squidData) {
21174
21365
  SquidDataType.DepositAddressWithMemo,
21175
21366
  ].includes(squidData.type);
21176
21367
  }
21368
+ /**
21369
+ * Checks if a route is of type DepositAddressDirectTransfer
21370
+ */
21371
+ function isDepositAddressDirectTransferRoute(squidData) {
21372
+ return squidData.type === SquidDataType.DepositAddressDirectTransfer;
21373
+ }
21177
21374
  function getHistoryTransactionId(tx) {
21178
21375
  switch (tx.txType) {
21179
21376
  case HistoryTxType.SWAP:
@@ -21693,7 +21890,17 @@ const chainTypeToTrimLength = {
21693
21890
  start: 4,
21694
21891
  end: 4,
21695
21892
  },
21893
+ // abc...123::abc...123
21894
+ [ChainType.CANTON]: {
21895
+ start: 3,
21896
+ end: 3,
21897
+ },
21696
21898
  };
21899
+ const truncateWithEllipsis = (value, startLength, endLength) => value.length <= startLength + endLength
21900
+ ? value
21901
+ : value.slice(0, startLength) +
21902
+ "..." +
21903
+ value.slice(value.length - endLength);
21697
21904
  const formatHash = ({ chainType, hash }) => {
21698
21905
  if (!hash)
21699
21906
  return "";
@@ -21706,14 +21913,15 @@ const formatHash = ({ chainType, hash }) => {
21706
21913
  chainTypeFormat = ChainType.COSMOS;
21707
21914
  }
21708
21915
  }
21709
- const trimLengthStart = chainTypeToTrimLength[chainTypeFormat].start;
21710
- const trimLengthEnd = chainTypeToTrimLength[chainTypeFormat].end;
21711
- // return the same hash if its length is less than the trim length
21712
- if (hash.length <= trimLengthStart + trimLengthEnd)
21713
- return hash;
21714
- return (hash.slice(0, trimLengthStart) +
21715
- "..." +
21716
- hash.slice(hash.length - trimLengthEnd, hash.length));
21916
+ const { start, end } = chainTypeToTrimLength[chainTypeFormat];
21917
+ if (chainTypeFormat === ChainType.CANTON &&
21918
+ hash.includes(CANTON_PARTY_ID_SEPARATOR)) {
21919
+ const [namespace, identifier] = hash.split(CANTON_PARTY_ID_SEPARATOR);
21920
+ return (truncateWithEllipsis(namespace, start, end) +
21921
+ CANTON_PARTY_ID_SEPARATOR +
21922
+ truncateWithEllipsis(identifier, start, end));
21923
+ }
21924
+ return truncateWithEllipsis(hash, start, end);
21717
21925
  };
21718
21926
  const isWalletAddressValid = (chainData, address) => {
21719
21927
  if (!address || !chainData?.chainType)
@@ -21733,33 +21941,25 @@ const isWalletAddressValid = (chainData, address) => {
21733
21941
  return isXrplAddressValid(address);
21734
21942
  case ChainType.STELLAR:
21735
21943
  return isStellarAddressValid(address);
21944
+ case ChainType.CANTON:
21945
+ return isCantonAddressValid(address);
21736
21946
  }
21737
21947
  };
21738
21948
  const redirectToExtensionsStore = (wallet) => {
21739
21949
  const { userAgent } = navigator;
21740
21950
  let link;
21741
21951
  if (userAgent.indexOf("Firefox") > -1) {
21742
- link = wallet.url || walletStoreLinks[wallet.connectorId]?.firefox;
21952
+ link =
21953
+ wallet.links?.firefox || walletStoreLinks[wallet.connectorId]?.firefox;
21743
21954
  }
21744
21955
  else if (userAgent.indexOf("Chrome") > -1) {
21745
- link = wallet.url || walletStoreLinks[wallet.connectorId]?.chrome;
21956
+ link = wallet.links?.chrome || walletStoreLinks[wallet.connectorId]?.chrome;
21746
21957
  }
21958
+ link = link || wallet.links?.website;
21747
21959
  if (link && link !== "") {
21748
21960
  window?.open(link, "_blank")?.focus();
21749
21961
  }
21750
21962
  };
21751
- /**
21752
- * Dynamically accesses a nested property of an object based on a dot-separated string path.
21753
- * Returns the value of the property if found, otherwise undefined.
21754
- * e.g. "xfi.keplr" will return window.xfi.keplr
21755
- */
21756
- const accessProperty = (object, path) => {
21757
- const value = get$2(object, path);
21758
- if (value === undefined) {
21759
- console.error(`Property "${path}" not found while reading object`, object);
21760
- }
21761
- return value;
21762
- };
21763
21963
  const definedInWindow = (path, clientWindow) => {
21764
21964
  if (!path || !clientWindow)
21765
21965
  return false;
@@ -21788,6 +21988,32 @@ const populateWallets = (window, wallets) => {
21788
21988
  return wallet;
21789
21989
  });
21790
21990
  };
21991
+ const createUninstalledConnector = () => new Proxy({}, {
21992
+ get(_target, prop) {
21993
+ throw new Error(`Cannot use connector of an uninstalled wallet (accessed "${String(prop)}")`);
21994
+ },
21995
+ });
21996
+ const buildFallbackWallets = (discovered) => {
21997
+ const fallbackKey = (chainType, connectorId) => `${chainType}:${connectorId}`;
21998
+ const discoveredKeys = new Set(discovered.flatMap((wallet) => wallet.isMultiChain
21999
+ ? wallet.supportedNetworks.map((network) => fallbackKey(network.chainType, wallet.connectorId))
22000
+ : [fallbackKey(wallet.type, wallet.connectorId)]));
22001
+ return fallbackWallets
22002
+ .filter((config) => !discoveredKeys.has(fallbackKey(config.chainType, config.id)))
22003
+ .map((config) => ({
22004
+ name: config.name,
22005
+ connectorId: config.id,
22006
+ connectorName: config.connectorName,
22007
+ icon: config.icon,
22008
+ windowFlag: config.id,
22009
+ links: config.links,
22010
+ isInstalled: () => false,
22011
+ skipInstallCheck: false,
22012
+ isMultiChain: false,
22013
+ type: config.chainType,
22014
+ connector: createUninstalledConnector(),
22015
+ }));
22016
+ };
21791
22017
  /**
21792
22018
  * Get the base chain to connect to
21793
22019
  * If only one chain type is selected, use that chain type
@@ -21994,6 +22220,13 @@ const connectByChainType = async (chainType, wallet, defaultChain, params) => {
21994
22220
  connector,
21995
22221
  },
21996
22222
  });
22223
+ case ChainType.CANTON:
22224
+ return params.connectCanton.mutateAsync({
22225
+ wallet: {
22226
+ ...wallet,
22227
+ connector,
22228
+ },
22229
+ });
21997
22230
  }
21998
22231
  };
21999
22232
  const getChainTypesToConnect = (selectedChainTypes, defaultChain, supportedChains) => {
@@ -22030,6 +22263,7 @@ const connectMultiChainWallet = async (params) => {
22030
22263
  connectSui: params.connectSui,
22031
22264
  connectXrpl: params.connectXrpl,
22032
22265
  connectStellar: params.connectStellar,
22266
+ connectCanton: params.connectCanton,
22033
22267
  });
22034
22268
  if (result) {
22035
22269
  results.push({
@@ -22063,6 +22297,7 @@ const connectSingleChainWallet = async (params) => {
22063
22297
  connectSui: params.connectSui,
22064
22298
  connectXrpl: params.connectXrpl,
22065
22299
  connectStellar: params.connectStellar,
22300
+ connectCanton: params.connectCanton,
22066
22301
  });
22067
22302
  return result
22068
22303
  ? {
@@ -22853,8 +23088,8 @@ function convertTokenAmountToUSD(tokenAmount, tokenPrice, maxDecimals = 4) {
22853
23088
  if (!tokenAmount || !tokenPrice)
22854
23089
  return "";
22855
23090
  try {
22856
- const amount = new BigNumber(cleanAmount(tokenAmount));
22857
- const price = new BigNumber(cleanAmount(tokenPrice));
23091
+ const amount = new BigNumber$1(cleanAmount(tokenAmount));
23092
+ const price = new BigNumber$1(cleanAmount(tokenPrice));
22858
23093
  return amount.multipliedBy(price).decimalPlaces(maxDecimals).toString();
22859
23094
  }
22860
23095
  catch {
@@ -22871,8 +23106,8 @@ function convertTokenAmountToUSD(tokenAmount, tokenPrice, maxDecimals = 4) {
22871
23106
  function convertUSDToTokenAmount(usdAmount, tokenPrice, maxDecimals) {
22872
23107
  if (!usdAmount || !tokenPrice || !maxDecimals)
22873
23108
  return "0";
22874
- const amount = new BigNumber(cleanAmount(usdAmount));
22875
- const price = new BigNumber(cleanAmount(tokenPrice));
23109
+ const amount = new BigNumber$1(cleanAmount(usdAmount));
23110
+ const price = new BigNumber$1(cleanAmount(tokenPrice));
22876
23111
  return amount.dividedBy(price).decimalPlaces(maxDecimals).toString();
22877
23112
  }
22878
23113
  const calculateTotal24hChange = (tokensWithBalance, totalUSDAmount) => {
@@ -22976,7 +23211,7 @@ const handleDestinationAddressOnSwapChange = ({ fromChainId, fromTokenAddress, t
22976
23211
  });
22977
23212
  let destinationTokenAddress = toChainId && !toTokenAddress
22978
23213
  ? defaultToAddress
22979
- : toTokenAddress ?? swapRoute?.toTokenAddress;
23214
+ : (toTokenAddress ?? swapRoute?.toTokenAddress);
22980
23215
  const lowerCaseDestinationTokenAddress = destinationTokenAddress?.toLowerCase();
22981
23216
  if (destinationTokensFiltered.find((t) => t.address === lowerCaseDestinationTokenAddress) === undefined) {
22982
23217
  destinationTokenAddress = defaultToAddress;
@@ -23028,7 +23263,7 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
23028
23263
  toTokenAddress === initialSwapRoute?.fromTokenAddress;
23029
23264
  const sourceTokenAddress = sameNewDestAndInitialSource || onlySourceChainIdChanged
23030
23265
  ? defaultFromAddress
23031
- : fromTokenAddress ?? initialSwapRoute?.fromTokenAddress;
23266
+ : (fromTokenAddress ?? initialSwapRoute?.fromTokenAddress);
23032
23267
  let destinationTokenAddress = undefined;
23033
23268
  if (!sameNewSourceAndInitialDest) {
23034
23269
  if (onlySourceChainIdChanged) {
@@ -23068,7 +23303,10 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
23068
23303
  else {
23069
23304
  newFallbackAddress = fallbackAddress ?? initialSwapRoute?.fallbackAddress;
23070
23305
  }
23071
- const newDepositRefundAddress = depositRefundAddress || initialSwapRoute?.depositRefundAddress;
23306
+ const sourceChainChanged = fromChainId !== undefined && fromChainId !== initialSwapRoute?.fromChainId;
23307
+ const newDepositRefundAddress = sourceChainChanged
23308
+ ? undefined
23309
+ : depositRefundAddress || initialSwapRoute?.depositRefundAddress;
23072
23310
  return {
23073
23311
  fromChainId: srcChainId,
23074
23312
  fromTokenAddress: sourceTokenAddress,
@@ -23226,11 +23464,11 @@ const groupTokensBySymbol = (tokens, chainType) => {
23226
23464
  };
23227
23465
  }
23228
23466
  groups[groupKey].tokens.push(token);
23229
- groups[groupKey].totalBalance = new BigNumber$1(groups[groupKey].totalBalance)
23467
+ groups[groupKey].totalBalance = new BigNumber(groups[groupKey].totalBalance)
23230
23468
  .plus(token.balance)
23231
23469
  .toString();
23232
23470
  const tokenUsdValue = convertTokenAmountToUSD(token.balance, token.usdPrice || 0);
23233
- groups[groupKey].totalBalanceUsd = new BigNumber$1(groups[groupKey].totalBalanceUsd ?? "0")
23471
+ groups[groupKey].totalBalanceUsd = new BigNumber(groups[groupKey].totalBalanceUsd ?? "0")
23234
23472
  .plus(tokenUsdValue)
23235
23473
  .toString();
23236
23474
  });
@@ -23252,11 +23490,11 @@ const groupTokensBySymbol = (tokens, chainType) => {
23252
23490
  else {
23253
23491
  // Combine tokens and sum up total balance for existing groups
23254
23492
  mergedGroups[mergeKey].tokens.push(...group.tokens);
23255
- mergedGroups[mergeKey].totalBalance = new BigNumber$1(mergedGroups[mergeKey].totalBalance)
23493
+ mergedGroups[mergeKey].totalBalance = new BigNumber(mergedGroups[mergeKey].totalBalance)
23256
23494
  .plus(group.totalBalance)
23257
23495
  .toString();
23258
23496
  // Add this line to properly merge USD values
23259
- mergedGroups[mergeKey].totalBalanceUsd = new BigNumber$1(mergedGroups[mergeKey].totalBalanceUsd ?? "0")
23497
+ mergedGroups[mergeKey].totalBalanceUsd = new BigNumber(mergedGroups[mergeKey].totalBalanceUsd ?? "0")
23260
23498
  .plus(group.totalBalanceUsd ?? "0")
23261
23499
  .toString();
23262
23500
  }
@@ -23301,13 +23539,13 @@ const groupTokensByChainId = (tokens, chains) => {
23301
23539
  };
23302
23540
  }
23303
23541
  groups[groupKey].tokens.push(token);
23304
- groups[groupKey].totalBalance = new BigNumber$1(groups[groupKey].totalBalance)
23542
+ groups[groupKey].totalBalance = new BigNumber(groups[groupKey].totalBalance)
23305
23543
  .plus(token.balance)
23306
23544
  .toString();
23307
23545
  // Only add to USD total if token has a valid price
23308
23546
  if (token.usdPrice && token.usdPrice > 0) {
23309
23547
  const tokenUsdValue = convertTokenAmountToUSD(token.balance, token.usdPrice);
23310
- groups[groupKey].totalBalanceUsd = new BigNumber$1(groups[groupKey].totalBalanceUsd ?? "0")
23548
+ groups[groupKey].totalBalanceUsd = new BigNumber(groups[groupKey].totalBalanceUsd ?? "0")
23311
23549
  .plus(tokenUsdValue)
23312
23550
  .toString();
23313
23551
  }
@@ -23347,7 +23585,7 @@ const filterViewableTokens = (tokens, config, direction) => {
23347
23585
  };
23348
23586
  const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
23349
23587
  const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
23350
- const { fetchAllSecretBalances } = await import('./secretService-DxQ78j5I.js');
23588
+ const { fetchAllSecretBalances } = await import('./secretService-DMcFUD-e.js');
23351
23589
  return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
23352
23590
  };
23353
23591
  function getTokenAssetsKey(token) {
@@ -23374,9 +23612,29 @@ async function fetchAssetsColors() {
23374
23612
  };
23375
23613
  }
23376
23614
  }
23377
- function initializeSquidWithAssetsColors(squid, assetsColors) {
23378
- const evmosChainIds = squid.chains.filter(isEvmosChain).map((c) => c.chainId);
23379
- squid.tokens = squid.tokens.map((token) => {
23615
+ const supportedChainTypes = new Set(Object.values(ChainType));
23616
+ function isSupportedChainType(chainType) {
23617
+ return supportedChainTypes.has(chainType);
23618
+ }
23619
+ /**
23620
+ * Normalizes SDK data after each init/refetch before the rest of hooks consumes it.
23621
+ *
23622
+ * - Removes chains whose chainType is not supported by the local package.
23623
+ * - Drops tokens for those removed chains.
23624
+ * - Converts Evmos chains/tokens to EVM.
23625
+ * - Applies optional asset colors.
23626
+ */
23627
+ function initializeSquidData(squid, assetsColors = {
23628
+ chains: {},
23629
+ tokens: {},
23630
+ }) {
23631
+ const supportedChains = squid.chains.filter((chain) => isSupportedChainType(chain.chainType));
23632
+ const supportedChainIds = new Set(supportedChains.map((chain) => chain.chainId));
23633
+ const evmosChainIds = supportedChains
23634
+ .filter(isEvmosChain)
23635
+ .map((c) => c.chainId);
23636
+ const supportedTokens = squid.tokens.filter((token) => supportedChainIds.has(token.chainId));
23637
+ squid.tokens = supportedTokens.map((token) => {
23380
23638
  const isEvmosToken = evmosChainIds.includes(token.chainId);
23381
23639
  return {
23382
23640
  ...token,
@@ -23385,7 +23643,7 @@ function initializeSquidWithAssetsColors(squid, assetsColors) {
23385
23643
  textColor: assetsColors.tokens[getTokenAssetsKey(token)]?.textColor,
23386
23644
  };
23387
23645
  });
23388
- squid.chains = squid.chains.map((chain) => {
23646
+ squid.chains = supportedChains.map((chain) => {
23389
23647
  const bgColor = assetsColors.chains[chain.chainId]?.bgColor;
23390
23648
  // convert evmos cosmos chains to evm chains
23391
23649
  // TODO: this will be fixed in the backend
@@ -25038,7 +25296,7 @@ class OnrampService {
25038
25296
  });
25039
25297
  return data;
25040
25298
  }
25041
- async getConfiguration({ chains, tokens, }) {
25299
+ async getConfiguration({ tokens, }) {
25042
25300
  const { data } = await axios.get(`${this.baseUrl}/config`);
25043
25301
  // Filter supportedCryptos to only include tokens that match our provided tokens
25044
25302
  const filteredCryptos = data.supportedCryptos.filter((supportedCrypto) => tokens.some((token) => token.address.toLowerCase() ===
@@ -25262,7 +25520,7 @@ const useSquid = () => {
25262
25520
  queryFn: async () => {
25263
25521
  if (squid) {
25264
25522
  await squid?.init();
25265
- initializeSquidWithAssetsColors(squid, assetsColors);
25523
+ initializeSquidData(squid, assetsColors);
25266
25524
  return squid;
25267
25525
  }
25268
25526
  return null;
@@ -25321,7 +25579,7 @@ const useSquidTokens = (direction) => {
25321
25579
  config.availableChains,
25322
25580
  direction,
25323
25581
  ]);
25324
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = useMemo(() => {
25582
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useMemo(() => {
25325
25583
  return tokens?.reduce((acc, token) => {
25326
25584
  switch (token.type) {
25327
25585
  case ChainType.EVM:
@@ -25345,6 +25603,9 @@ const useSquidTokens = (direction) => {
25345
25603
  case ChainType.STELLAR:
25346
25604
  acc.stellarTokens.push(token);
25347
25605
  break;
25606
+ case ChainType.CANTON:
25607
+ acc.cantonTokens.push(token);
25608
+ break;
25348
25609
  }
25349
25610
  return acc;
25350
25611
  }, {
@@ -25355,6 +25616,7 @@ const useSquidTokens = (direction) => {
25355
25616
  suiTokens: [],
25356
25617
  xrplTokens: [],
25357
25618
  stellarTokens: [],
25619
+ cantonTokens: [],
25358
25620
  });
25359
25621
  }, [tokens]);
25360
25622
  const findToken = useCallback((address, chainId) => {
@@ -25372,6 +25634,7 @@ const useSquidTokens = (direction) => {
25372
25634
  suiTokens,
25373
25635
  xrplTokens,
25374
25636
  stellarTokens,
25637
+ cantonTokens,
25375
25638
  };
25376
25639
  };
25377
25640
 
@@ -25472,12 +25735,10 @@ const useGetFiatQuote = ({ fiatCurrency, cryptoCurrencyID, amount, region, payme
25472
25735
  */
25473
25736
  const useGetOnRampConfig = () => {
25474
25737
  const service = useMemo(() => new OnrampService(), []);
25475
- const { chains } = useSquidChains();
25476
25738
  const { tokens } = useSquidTokens();
25477
25739
  return useQuery({
25478
25740
  queryKey: keys().fiatToCryptoConfig(),
25479
25741
  queryFn: () => service.getConfiguration({
25480
- chains,
25481
25742
  tokens,
25482
25743
  }),
25483
25744
  cacheTime: 1000 * 60 * 60,
@@ -25909,6 +26170,7 @@ const chainTypeToRefetchInterval = {
25909
26170
  [ChainType.SUI]: 1_000,
25910
26171
  [ChainType.XRPL]: 1_000,
25911
26172
  [ChainType.STELLAR]: 1_000,
26173
+ [ChainType.CANTON]: 1_000,
25912
26174
  };
25913
26175
  /**
25914
26176
  * Returns the status refetch interval of a Send transaction
@@ -26175,7 +26437,7 @@ const useSquidChains = (direction) => {
26175
26437
  const chain = findChain(chainId);
26176
26438
  return chain?.chainType;
26177
26439
  }, [findChain]);
26178
- const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains } = useMemo(() => {
26440
+ const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains, cantonChains, } = useMemo(() => {
26179
26441
  return chains.reduce((acc, chain) => {
26180
26442
  switch (chain.chainType) {
26181
26443
  case ChainType.EVM:
@@ -26193,6 +26455,9 @@ const useSquidChains = (direction) => {
26193
26455
  case ChainType.STELLAR:
26194
26456
  acc.stellarChains.push(chain);
26195
26457
  break;
26458
+ case ChainType.CANTON:
26459
+ acc.cantonChains.push(chain);
26460
+ break;
26196
26461
  }
26197
26462
  return acc;
26198
26463
  }, {
@@ -26201,6 +26466,7 @@ const useSquidChains = (direction) => {
26201
26466
  suiChains: [],
26202
26467
  xrplChains: [],
26203
26468
  stellarChains: [],
26469
+ cantonChains: [],
26204
26470
  });
26205
26471
  }, [chains]);
26206
26472
  const { supportedSourceChains, supportedDestinationChains } = useMemo(() => {
@@ -26221,6 +26487,7 @@ const useSquidChains = (direction) => {
26221
26487
  suiChains,
26222
26488
  xrplChains,
26223
26489
  stellarChains,
26490
+ cantonChains,
26224
26491
  getChainType,
26225
26492
  findChain,
26226
26493
  };
@@ -26534,6 +26801,253 @@ const useBitcoinContext = () => {
26534
26801
  return context;
26535
26802
  };
26536
26803
 
26804
+ const REQUEST_TIMEOUT_MS = 60_000;
26805
+ function pickAddress(accounts) {
26806
+ return (accounts.find((a) => a.primary) ?? accounts[0])?.partyId;
26807
+ }
26808
+ /**
26809
+ * Browser-extension Canton connector: wraps one discovered CIP-103 provider
26810
+ * (bound to its announce `target`) and exposes the lifecycle methods.
26811
+ */
26812
+ class CantonBrowserConnector {
26813
+ providerId;
26814
+ name;
26815
+ target;
26816
+ client;
26817
+ listeners = { connect: new Set(), disconnect: new Set() };
26818
+ _accounts = [];
26819
+ constructor(provider, win = window) {
26820
+ this.providerId = provider.id;
26821
+ this.name = provider.name;
26822
+ this.target = provider.target ?? provider.id;
26823
+ this.client = createCantonClient(new WindowTransport(win, {
26824
+ target: this.target,
26825
+ timeout: REQUEST_TIMEOUT_MS,
26826
+ }));
26827
+ }
26828
+ get accounts() {
26829
+ return this._accounts;
26830
+ }
26831
+ get address() {
26832
+ return pickAddress(this._accounts);
26833
+ }
26834
+ async connect() {
26835
+ await this.client.connect();
26836
+ const result = await this.refreshAccounts();
26837
+ this.emit("connect", result.address);
26838
+ return result;
26839
+ }
26840
+ /** Silent connect: read accounts without prompting; throws if not connected. */
26841
+ async autoConnect() {
26842
+ const accounts = await this.client.listAccounts();
26843
+ if (!accounts.length) {
26844
+ throw new Error("Canton wallet not connected");
26845
+ }
26846
+ this._accounts = accounts;
26847
+ const address = pickAddress(accounts);
26848
+ this.emit("connect", address);
26849
+ return { address, accounts };
26850
+ }
26851
+ async disconnect() {
26852
+ try {
26853
+ await this.client.disconnect();
26854
+ }
26855
+ finally {
26856
+ this._accounts = [];
26857
+ this.emit("disconnect");
26858
+ }
26859
+ }
26860
+ async ledgerApi(params) {
26861
+ const result = await this.client.ledgerApi(params);
26862
+ return result;
26863
+ }
26864
+ async prepareExecuteAndWait(params) {
26865
+ return this.client.prepareExecuteAndWait(params);
26866
+ }
26867
+ async getAccounts() {
26868
+ this._accounts = await this.client.listAccounts();
26869
+ return this._accounts;
26870
+ }
26871
+ on(event, handler) {
26872
+ this.listeners[event].add(handler);
26873
+ }
26874
+ off(event, handler) {
26875
+ this.listeners[event].delete(handler);
26876
+ }
26877
+ emit(event, ...args) {
26878
+ this.listeners[event].forEach((handler) => handler(...args));
26879
+ }
26880
+ async refreshAccounts() {
26881
+ const accounts = await this.client.listAccounts();
26882
+ this._accounts = accounts;
26883
+ const address = pickAddress(accounts);
26884
+ if (!address) {
26885
+ throw new Error("Canton wallet returned no accounts");
26886
+ }
26887
+ return { address, accounts };
26888
+ }
26889
+ }
26890
+
26891
+ const CANTON_REQUEST_PROVIDER_EVENT = "canton:requestProvider";
26892
+ const CANTON_ANNOUNCE_PROVIDER_EVENT = "canton:announceProvider";
26893
+ const DEFAULT_DISCOVERY_TIMEOUT_MS = 300;
26894
+ /**
26895
+ * CIP-103 browser-wallet discovery (EIP-6963-style).
26896
+ * The wallet dispatches `canton:announceProvider` and dApps
26897
+ * dispatch `canton:requestProvider` to ask installed wallets to re-announce.
26898
+ * Each announcement carries a `target` we route through Sigilry's `WindowTransport`,
26899
+ * so multiple extensions coexist without contending on the `window.canton` global.
26900
+ */
26901
+ async function discoverCantonProviders(timeoutMs = DEFAULT_DISCOVERY_TIMEOUT_MS, win = window) {
26902
+ if (typeof win === "undefined")
26903
+ return [];
26904
+ const discovered = new Map();
26905
+ const handler = (event) => {
26906
+ const detail = event.detail;
26907
+ if (!detail?.id || !detail.name || discovered.has(detail.id))
26908
+ return;
26909
+ discovered.set(detail.id, {
26910
+ id: detail.id,
26911
+ name: detail.name,
26912
+ icon: detail.icon,
26913
+ target: detail.target ?? detail.id,
26914
+ });
26915
+ };
26916
+ win.addEventListener(CANTON_ANNOUNCE_PROVIDER_EVENT, handler);
26917
+ try {
26918
+ win.dispatchEvent(new CustomEvent(CANTON_REQUEST_PROVIDER_EVENT, { detail: {} }));
26919
+ await new Promise((resolve) => setTimeout(resolve, timeoutMs));
26920
+ }
26921
+ finally {
26922
+ win.removeEventListener(CANTON_ANNOUNCE_PROVIDER_EVENT, handler);
26923
+ }
26924
+ return Array.from(discovered.values());
26925
+ }
26926
+
26927
+ /**
26928
+ * Discovers Canton browser-extension wallets via the CIP-103 announce protocol
26929
+ * (on mount and on window focus) and maps each to a {@link CantonWallet}.
26930
+ */
26931
+ function useCantonWallets() {
26932
+ const [wallets, setWallets] = useState([]);
26933
+ const connectorCache = useRef(new Map());
26934
+ const toWallet = useCallback((provider) => {
26935
+ let connector = connectorCache.current.get(provider.id);
26936
+ if (!connector) {
26937
+ connector = new CantonBrowserConnector(provider);
26938
+ connectorCache.current.set(provider.id, connector);
26939
+ }
26940
+ return {
26941
+ name: provider.name,
26942
+ connectorId: provider.id,
26943
+ connectorName: provider.name,
26944
+ icon: provider.icon,
26945
+ windowFlag: provider.id,
26946
+ skipInstallCheck: true,
26947
+ isInstalled: () => true,
26948
+ isMultiChain: false,
26949
+ type: ChainType.CANTON,
26950
+ connector,
26951
+ };
26952
+ }, []);
26953
+ const refresh = useCallback(async () => {
26954
+ if (typeof window === "undefined")
26955
+ return;
26956
+ const providers = await discoverCantonProviders();
26957
+ setWallets(providers.map(toWallet));
26958
+ }, [toWallet]);
26959
+ useEffect(() => {
26960
+ refresh();
26961
+ if (typeof window === "undefined")
26962
+ return;
26963
+ const onFocus = () => refresh();
26964
+ window.addEventListener("focus", onFocus);
26965
+ return () => window.removeEventListener("focus", onFocus);
26966
+ }, [refresh]);
26967
+ return { wallets };
26968
+ }
26969
+
26970
+ function useCanton() {
26971
+ const disconnectWallet = useWalletStore((store) => store.disconnectWallet);
26972
+ const setConnectedWallet = useWalletStore((store) => store.setConnectedWallet);
26973
+ const { wallets } = useCantonWallets();
26974
+ const connectedCantonWallet = useWalletStore((store) => store.connectedWalletsByChainType[ChainType.CANTON]);
26975
+ const recentCantonWalletId = useWalletStore((store) => store.recentConnectorIds[ChainType.CANTON]);
26976
+ const connectCanton = useMutation(async ({ wallet, }) => {
26977
+ let result;
26978
+ try {
26979
+ // Try to reconnect silently first (existing session, no popup)
26980
+ result = await wallet.connector.autoConnect();
26981
+ }
26982
+ catch {
26983
+ // Otherwise prompt the wallet to connect
26984
+ result = await wallet.connector.connect();
26985
+ }
26986
+ return {
26987
+ wallet,
26988
+ address: result.address,
26989
+ };
26990
+ });
26991
+ const disconnectCanton = useCallback(async () => {
26992
+ await connectedCantonWallet.wallet?.connector.disconnect();
26993
+ }, [connectedCantonWallet.wallet?.connector]);
26994
+ const autoConnectCanton = useCallback(async () => {
26995
+ const recentCantonWallet = wallets.find((w) => w.connectorId === recentCantonWalletId);
26996
+ if (!recentCantonWallet) {
26997
+ return;
26998
+ }
26999
+ const { address } = await recentCantonWallet.connector.autoConnect();
27000
+ setConnectedWallet(ChainType.CANTON, {
27001
+ wallet: recentCantonWallet,
27002
+ address,
27003
+ });
27004
+ // eslint-disable-next-line react-hooks/exhaustive-deps
27005
+ }, [wallets.map((w) => w.connectorId), recentCantonWalletId]);
27006
+ useEffect(() => {
27007
+ const wallet = connectedCantonWallet.wallet;
27008
+ if (!wallet) {
27009
+ return;
27010
+ }
27011
+ function onConnect(newAddress) {
27012
+ if (wallet) {
27013
+ setConnectedWallet(ChainType.CANTON, {
27014
+ wallet,
27015
+ address: newAddress,
27016
+ });
27017
+ }
27018
+ }
27019
+ function onDisconnect() {
27020
+ disconnectWallet(ChainType.CANTON);
27021
+ }
27022
+ wallet.connector.on("connect", onConnect);
27023
+ wallet.connector.on("disconnect", onDisconnect);
27024
+ return () => {
27025
+ wallet.connector.off("connect", onConnect);
27026
+ wallet.connector.off("disconnect", onDisconnect);
27027
+ };
27028
+ }, [disconnectWallet, setConnectedWallet, connectedCantonWallet.wallet]);
27029
+ return {
27030
+ connectCanton,
27031
+ disconnectCanton,
27032
+ autoConnectCanton,
27033
+ signer: connectedCantonWallet.wallet?.connector,
27034
+ wallets,
27035
+ };
27036
+ }
27037
+
27038
+ const CantonContext = createContext(undefined);
27039
+ const CantonProvider = ({ children, }) => {
27040
+ const cantonHook = useCanton();
27041
+ return (React.createElement(CantonContext.Provider, { value: cantonHook }, children));
27042
+ };
27043
+ const useCantonContext = () => {
27044
+ const context = useContext(CantonContext);
27045
+ if (!context) {
27046
+ throw new Error("useCantonContext must be used within a CantonProvider");
27047
+ }
27048
+ return context;
27049
+ };
27050
+
26537
27051
  function useEvmWallets() {
26538
27052
  const connectors = useConnectors();
26539
27053
  const wallets = useMemo(() => {
@@ -26745,7 +27259,7 @@ function useStellarWallets() {
26745
27259
  try {
26746
27260
  const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
26747
27261
  const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module.mjs');
26748
- const { formatStellarWallet } = await import('./stellarService.client-CkP5ng2n.js');
27262
+ const { formatStellarWallet } = await import('./stellarService.client-DMdUVPJ8.js');
26749
27263
  const modules = [...initializeAllModules(), new LedgerModule()];
26750
27264
  const promises = modules.map(async (module) => {
26751
27265
  const isAvailable = await module.isAvailable();
@@ -27218,17 +27732,24 @@ const useWallets = () => {
27218
27732
  const { wallets: suiWallets } = useSuiContext();
27219
27733
  const { wallets: xrplWallets } = useXrplContext();
27220
27734
  const { wallets: stellarWallets } = useStellarContext();
27735
+ const { wallets: cantonWallets } = useCantonContext();
27221
27736
  const wallets = useMemo(() => {
27222
27737
  const singleChainWallets$1 = populateWallets(clientWindow, singleChainWallets);
27223
27738
  const multiChainWallets$1 = populateWallets(clientWindow, multiChainWallets);
27739
+ const discoveredWallets = [
27740
+ ...evmWallets,
27741
+ ...solanaWallets,
27742
+ ...suiWallets,
27743
+ ...cantonWallets,
27744
+ ];
27745
+ const fallbackWallets = buildFallbackWallets(discoveredWallets);
27224
27746
  return mergeWallets({
27225
27747
  singleChainWallets: [
27226
27748
  ...singleChainWallets$1,
27227
- ...evmWallets,
27228
- ...solanaWallets,
27229
- ...suiWallets,
27749
+ ...discoveredWallets,
27230
27750
  ...xrplWallets,
27231
27751
  ...stellarWallets,
27752
+ ...fallbackWallets,
27232
27753
  ],
27233
27754
  multiChainWallets: multiChainWallets$1,
27234
27755
  });
@@ -27239,6 +27760,7 @@ const useWallets = () => {
27239
27760
  suiWallets,
27240
27761
  xrplWallets,
27241
27762
  stellarWallets,
27763
+ cantonWallets,
27242
27764
  ]);
27243
27765
  return {
27244
27766
  wallets,
@@ -27254,6 +27776,7 @@ const useWallet = () => {
27254
27776
  const { connectSui, disconnectSui } = useSuiContext();
27255
27777
  const { connectXrpl, disconnectXrpl } = useXrplContext();
27256
27778
  const { connectStellar, disconnectStellar } = useStellarContext();
27779
+ const { connectCanton, disconnectCanton } = useCantonContext();
27257
27780
  const { findChain } = useSquidChains();
27258
27781
  const { isGnosisConnected, gnosisAddress } = useGnosisContext();
27259
27782
  const destinationAddress = useSwapRoutePersistStore((state) => state.swapRoute?.destinationAddress);
@@ -27290,6 +27813,7 @@ const useWallet = () => {
27290
27813
  connectSui,
27291
27814
  connectXrpl,
27292
27815
  connectStellar,
27816
+ connectCanton,
27293
27817
  selectedChainTypes,
27294
27818
  findChain,
27295
27819
  });
@@ -27338,6 +27862,9 @@ const useWallet = () => {
27338
27862
  case ChainType.STELLAR:
27339
27863
  await disconnectStellar();
27340
27864
  break;
27865
+ case ChainType.CANTON:
27866
+ await disconnectCanton();
27867
+ break;
27341
27868
  default:
27342
27869
  // TODO: Implement disconnect for other chains
27343
27870
  break;
@@ -27444,6 +27971,7 @@ const useMultiChainWallet = (chain) => {
27444
27971
  const suiAddress = connectedAddresses[ChainType.SUI];
27445
27972
  const xrplAddress = connectedAddresses[ChainType.XRPL];
27446
27973
  const stellarAddress = connectedAddresses[ChainType.STELLAR];
27974
+ const cantonAddress = connectedAddresses[ChainType.CANTON];
27447
27975
  // Cosmos is a special case because the address changes on every chain
27448
27976
  // so we can't use the default cosmos connected address
27449
27977
  const { data: cosmosAddress } = useCosmosForChain(chain);
@@ -27531,6 +28059,16 @@ const useMultiChainWallet = (chain) => {
27531
28059
  chainType: chain.chainType,
27532
28060
  }),
27533
28061
  };
28062
+ case ChainType.CANTON:
28063
+ if (!cantonAddress)
28064
+ return {};
28065
+ return {
28066
+ address: cantonAddress,
28067
+ formatted: formatHash({
28068
+ hash: cantonAddress,
28069
+ chainType: chain.chainType,
28070
+ }),
28071
+ };
27534
28072
  }
27535
28073
  }, [
27536
28074
  chain?.chainType,
@@ -27542,6 +28080,7 @@ const useMultiChainWallet = (chain) => {
27542
28080
  suiAddress,
27543
28081
  xrplAddress,
27544
28082
  stellarAddress,
28083
+ cantonAddress,
27545
28084
  ]);
27546
28085
  /**
27547
28086
  * Change current network for desired chain
@@ -28366,6 +28905,8 @@ async function createClient(chain) {
28366
28905
  return new XrplRpcClient(chain.rpc);
28367
28906
  case ChainType.STELLAR:
28368
28907
  return new StellarRpcClient(chain.rpc);
28908
+ case ChainType.CANTON:
28909
+ return null;
28369
28910
  }
28370
28911
  }
28371
28912
 
@@ -29378,6 +29919,54 @@ const getAllStellarTokensBalance = async (userAddress, stellarTokens, stellarCha
29378
29919
  const allResults = await Promise.all(stellarChains.map(getBalancesForChain));
29379
29920
  return allResults.flat();
29380
29921
  };
29922
+ /**
29923
+ * Canton balances are private: they can only be read with a wallet-authorized
29924
+ * `ledgerApi` session (the connected wallet supplies a JWT that can read as the
29925
+ * party). So balance is fetchable only when a Canton wallet is connected, and
29926
+ * only for that wallet's party — there's no address-only read.
29927
+ */
29928
+ const getCantonTokenBalance = async (userAddress, token, cantonConnector) => {
29929
+ if (!token.originalAddress)
29930
+ return "0";
29931
+ const instrument = parseCantonInstrument(token.originalAddress);
29932
+ if (!instrument)
29933
+ return "0";
29934
+ const ledgerEnd = await cantonConnector.ledgerApi({ requestMethod: "get", resource: "/v2/state/ledger-end" });
29935
+ const activeContracts = await cantonConnector.ledgerApi({
29936
+ requestMethod: "post",
29937
+ resource: "/v2/state/active-contracts",
29938
+ body: buildHoldingsAcsRequestBody(userAddress, String(ledgerEnd.offset)),
29939
+ });
29940
+ const grouped = groupCantonHoldingBalances(activeContracts);
29941
+ return grouped[cantonInstrumentKey(instrument)] ?? "0";
29942
+ };
29943
+ /**
29944
+ * Fetch balances for all Canton tokens in one ACS query. Canton balances are
29945
+ * private, so this requires a connected wallet's authorized `ledgerApi`.
29946
+ */
29947
+ async function getAllCantonTokensBalance({ connector, partyId, tokens, }) {
29948
+ const ledgerEnd = await connector.ledgerApi({
29949
+ requestMethod: "get",
29950
+ resource: "/v2/state/ledger-end",
29951
+ });
29952
+ const activeContracts = await connector.ledgerApi({
29953
+ requestMethod: "post",
29954
+ resource: "/v2/state/active-contracts",
29955
+ body: buildHoldingsAcsRequestBody(partyId, String(ledgerEnd.offset)),
29956
+ });
29957
+ const grouped = groupCantonHoldingBalances(activeContracts);
29958
+ return tokens.map((token) => {
29959
+ const instrument = token.originalAddress
29960
+ ? parseCantonInstrument(token.originalAddress)
29961
+ : null;
29962
+ return {
29963
+ ...token,
29964
+ balance: instrument
29965
+ ? grouped[cantonInstrumentKey(instrument)] ?? "0"
29966
+ : "0",
29967
+ };
29968
+ });
29969
+ }
29381
29970
  /**
29382
29971
  * Returns a promise that resolves when the given promise resolves or after the given timeout
29383
29972
  * @param ms - timeout in milliseconds
@@ -29562,9 +30151,29 @@ const useStellarBalance = ({ userAddress, chain, enabled, token, refreshInterval
29562
30151
  });
29563
30152
  return { balance, isLoading };
29564
30153
  };
30154
+ const useCantonBalance = ({ chain, token, userAddress, enabled = true, refreshIntervalMs = DEFAULT_REFRESH_INTERVAL_MS$1, }) => {
30155
+ const cantonConnector = useWalletStore((store) => store.connectedWalletsByChainType[ChainType.CANTON]?.wallet?.connector);
30156
+ const { data: balance = "0", isLoading } = useQuery({
30157
+ queryKey: keys().balance(chain?.chainId, token?.address, userAddress),
30158
+ queryFn: async () => {
30159
+ if (!cantonConnector || !userAddress || !token)
30160
+ return "0";
30161
+ return getCantonTokenBalance(userAddress, token, cantonConnector);
30162
+ },
30163
+ enabled: enabled &&
30164
+ !!cantonConnector &&
30165
+ !!userAddress &&
30166
+ !!token &&
30167
+ chain?.chainType === ChainType.CANTON &&
30168
+ isCantonAddressValid(userAddress),
30169
+ refetchInterval: refreshIntervalMs,
30170
+ retry: 2,
30171
+ });
30172
+ return { balance, isLoading };
30173
+ };
29565
30174
 
29566
30175
  function useNativeTokenForChain(chain) {
29567
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = useSquidTokens();
30176
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens();
29568
30177
  const getTokensForChainType = () => {
29569
30178
  if (!chain?.chainType)
29570
30179
  return [];
@@ -29583,6 +30192,8 @@ function useNativeTokenForChain(chain) {
29583
30192
  return xrplTokens;
29584
30193
  case ChainType.STELLAR:
29585
30194
  return stellarTokens;
30195
+ case ChainType.CANTON:
30196
+ return cantonTokens;
29586
30197
  }
29587
30198
  };
29588
30199
  const nativeTokenForChainType = useMemo(() => {
@@ -29764,6 +30375,24 @@ const useStellarNativeBalance = ({ address, chain, }) => {
29764
30375
  isLoading,
29765
30376
  };
29766
30377
  };
30378
+ const useCantonNativeBalance = ({ address, chain, }) => {
30379
+ const { nativeToken } = useNativeTokenForChain(chain);
30380
+ const { balance: rawBalance, isLoading } = useCantonBalance({
30381
+ chain,
30382
+ token: nativeToken,
30383
+ userAddress: address,
30384
+ enabled: chain?.chainType === ChainType.CANTON,
30385
+ });
30386
+ const balance = useMemo(() => {
30387
+ if (nativeToken?.decimals && rawBalance) {
30388
+ return {
30389
+ decimals: nativeToken.decimals,
30390
+ value: parseToBigInt(rawBalance, nativeToken.decimals),
30391
+ };
30392
+ }
30393
+ }, [nativeToken?.decimals, rawBalance]);
30394
+ return { balance, isLoading };
30395
+ };
29767
30396
  const useNativeBalance = (chain) => {
29768
30397
  const { connectedAddresses } = useWallet();
29769
30398
  const { data: cosmosAddressForChain } = useCosmosForChain(chain);
@@ -29794,6 +30423,10 @@ const useNativeBalance = (chain) => {
29794
30423
  address: connectedAddresses[ChainType.STELLAR],
29795
30424
  chain,
29796
30425
  });
30426
+ const { balance: nativeCantonBalance, isLoading: isCantonLoading } = useCantonNativeBalance({
30427
+ address: connectedAddresses[ChainType.CANTON],
30428
+ chain,
30429
+ });
29797
30430
  const { nativeBalance, nativeBalanceFormatted } = useMemo(() => {
29798
30431
  let balance;
29799
30432
  switch (chain?.chainType) {
@@ -29817,6 +30450,10 @@ const useNativeBalance = (chain) => {
29817
30450
  break;
29818
30451
  case ChainType.STELLAR:
29819
30452
  balance = nativeStellarBalance;
30453
+ break;
30454
+ case ChainType.CANTON:
30455
+ balance = nativeCantonBalance;
30456
+ break;
29820
30457
  }
29821
30458
  const balanceFormatted = !!balance
29822
30459
  ? formatBNToReadable(balance.value, balance.decimals)
@@ -29834,6 +30471,7 @@ const useNativeBalance = (chain) => {
29834
30471
  nativeSuiBalance,
29835
30472
  nativeXrplBalance,
29836
30473
  nativeStellarBalance,
30474
+ nativeCantonBalance,
29837
30475
  ]);
29838
30476
  const isLoading = useMemo(() => {
29839
30477
  if (!chain?.chainType)
@@ -29853,6 +30491,8 @@ const useNativeBalance = (chain) => {
29853
30491
  return isXrpLoading;
29854
30492
  case ChainType.STELLAR:
29855
30493
  return isStellarLoading;
30494
+ case ChainType.CANTON:
30495
+ return isCantonLoading;
29856
30496
  }
29857
30497
  }, [
29858
30498
  chain?.chainType,
@@ -29863,6 +30503,7 @@ const useNativeBalance = (chain) => {
29863
30503
  isSuiLoading,
29864
30504
  isXrpLoading,
29865
30505
  isStellarLoading,
30506
+ isCantonLoading,
29866
30507
  ]);
29867
30508
  return { nativeBalance, nativeBalanceFormatted, isLoading };
29868
30509
  };
@@ -30077,7 +30718,7 @@ function hederaWalletConnect(parameters) {
30077
30718
  const optionalChains = config.chains.map((x) => x.id);
30078
30719
  if (!optionalChains.length)
30079
30720
  return;
30080
- const { EthereumProvider } = await import('./index.es-DSQHpime.js');
30721
+ const { EthereumProvider } = await import('./index.es-reWGC10l.js');
30081
30722
  const rawProvider = await EthereumProvider.init({
30082
30723
  ...restParameters,
30083
30724
  disableProviderPing: true,
@@ -30282,6 +30923,7 @@ const useSigner = ({ chain }) => {
30282
30923
  const { signer: suiSigner } = useSuiContext();
30283
30924
  const { signer: xrplSigner } = useXrplContext();
30284
30925
  const { signer: stellarSigner } = useStellarContext();
30926
+ const { signer: cantonSigner } = useCantonContext();
30285
30927
  const isEvmSignerReady = !!evmSigner;
30286
30928
  const isSolanaSignerReady = !!solanaSigner;
30287
30929
  const isCosmosSignerReady = !!cosmosSigner;
@@ -30289,6 +30931,7 @@ const useSigner = ({ chain }) => {
30289
30931
  const isSuiSignerReady = !!suiSigner;
30290
30932
  const isXrplSignerReady = !!xrplSigner;
30291
30933
  const isStellarSignerReady = !!stellarSigner;
30934
+ const isCantonSignerReady = !!cantonSigner;
30292
30935
  const isSignerReady = useMemo(() => {
30293
30936
  if (!chain?.chainType)
30294
30937
  return false;
@@ -30307,6 +30950,8 @@ const useSigner = ({ chain }) => {
30307
30950
  return isXrplSignerReady;
30308
30951
  case ChainType.STELLAR:
30309
30952
  return isStellarSignerReady;
30953
+ case ChainType.CANTON:
30954
+ return isCantonSignerReady;
30310
30955
  }
30311
30956
  }, [
30312
30957
  chain?.chainType,
@@ -30317,6 +30962,7 @@ const useSigner = ({ chain }) => {
30317
30962
  isSuiSignerReady,
30318
30963
  isXrplSignerReady,
30319
30964
  isStellarSignerReady,
30965
+ isCantonSignerReady,
30320
30966
  ]);
30321
30967
  return {
30322
30968
  isSignerReady,
@@ -30327,6 +30973,7 @@ const useSigner = ({ chain }) => {
30327
30973
  suiSigner,
30328
30974
  xrplSigner,
30329
30975
  stellarSigner,
30976
+ cantonSigner,
30330
30977
  };
30331
30978
  };
30332
30979
 
@@ -30662,10 +31309,10 @@ function useStellarTrustLine({ address, chain, token, amount }) {
30662
31309
  if (!amount) {
30663
31310
  throw new Error("Amount is required");
30664
31311
  }
30665
- const limitBn = BigNumber$1(trustLineQuery.data?.limit || "0");
30666
- const balanceBn = BigNumber$1(trustLineQuery.data?.balance || "0");
31312
+ const limitBn = BigNumber(trustLineQuery.data?.limit || "0");
31313
+ const balanceBn = BigNumber(trustLineQuery.data?.balance || "0");
30667
31314
  const availableAllowanceBn = limitBn.minus(balanceBn);
30668
- const amountBn = BigNumber$1(formatBNToReadable(amount, token.decimals));
31315
+ const amountBn = BigNumber(formatBNToReadable(amount, token.decimals));
30669
31316
  return availableAllowanceBn.gte(amountBn);
30670
31317
  },
30671
31318
  enabled: !!address &&
@@ -30756,21 +31403,21 @@ const useSendTransactionStore = create((set, get) => ({
30756
31403
 
30757
31404
  const useDepositAddressStore = create((set) => ({
30758
31405
  deposit: null,
30759
- isEnabled: false,
31406
+ selectedPaymentMethod: "connectedWallet",
30760
31407
  setDeposit: (data) => {
30761
31408
  set({ deposit: data });
30762
31409
  },
30763
- toggleDepositFlow: (enabled) => {
30764
- set({ isEnabled: enabled });
31410
+ setPaymentMethod: (method) => {
31411
+ set({ selectedPaymentMethod: method });
30765
31412
  },
30766
31413
  }));
30767
31414
 
30768
31415
  function useDepositAddress(squidRoute) {
30769
- const { isEnabled, depositAddress } = useDepositAddressStore((state) => ({
30770
- isEnabled: state.isEnabled,
31416
+ const { selectedPaymentMethod, depositAddress } = useDepositAddressStore((state) => ({
31417
+ selectedPaymentMethod: state.selectedPaymentMethod,
30771
31418
  depositAddress: state.deposit?.depositAddress,
30772
31419
  }));
30773
- const { setDeposit, toggleDepositFlow, deposit } = useDepositAddressStore();
31420
+ const { setDeposit, setPaymentMethod, deposit } = useDepositAddressStore();
30774
31421
  const { squid } = useSquidStore();
30775
31422
  const { fromChain } = useSwap();
30776
31423
  const isAvailableAsPaymentMethod = useMemo(() => {
@@ -30779,41 +31426,55 @@ function useDepositAddress(squidRoute) {
30779
31426
  const chainsSupportingDepositAddress = [
30780
31427
  CHAIN_IDS.BITCOIN,
30781
31428
  CHAIN_IDS.SOLANA,
31429
+ CHAIN_IDS.CANTON,
30782
31430
  ];
30783
31431
  return chainsSupportingDepositAddress.includes(fromChain.chainId);
30784
31432
  }, [fromChain?.chainId]);
30785
- const swapWillGenerateDepositAddress = useMemo(() => {
30786
- return (squidRoute?.transactionRequest?.type ===
30787
- SquidDataType.ChainflipDepositAddress);
30788
- }, [squidRoute?.transactionRequest?.type]);
30789
- const enable = useCallback(() => {
30790
- toggleDepositFlow(true);
30791
- }, [toggleDepositFlow]);
30792
- const disable = useCallback(() => {
30793
- toggleDepositFlow(false);
30794
- }, [toggleDepositFlow]);
31433
+ const routeProvidesDirectDepositAddress = !!squidRoute?.transactionRequest &&
31434
+ isDepositAddressDirectTransferRoute(squidRoute.transactionRequest);
31435
+ const swapWillGenerateDepositAddress = isChainflipDepositRoute(squidRoute) || routeProvidesDirectDepositAddress;
31436
+ const paymentMethod = isAvailableAsPaymentMethod
31437
+ ? selectedPaymentMethod
31438
+ : "connectedWallet";
31439
+ const routeSupportsDepositAddress = !squidRoute?.transactionRequest || swapWillGenerateDepositAddress;
31440
+ const isDepositAddressActive = paymentMethod === "depositAddress" && routeSupportsDepositAddress;
30795
31441
  const closeDepositChannel = useCallback(() => {
30796
- toggleDepositFlow(false);
30797
31442
  setDeposit(null);
30798
- }, [toggleDepositFlow, setDeposit]);
31443
+ }, [setDeposit]);
30799
31444
  const getRouteWithDeposit = useMutation(async ({ route }) => {
30800
- if (!squid)
30801
- throw new Error("Squid SDK not initialized");
30802
- const depositAddressResponse = (await squid.executeRoute({
30803
- signer: {},
30804
- route,
30805
- }));
30806
- setDeposit(depositAddressResponse);
30807
- return {
30808
- depositAddress: depositAddressResponse,
30809
- };
31445
+ if (!squid || !route.transactionRequest) {
31446
+ throw new Error("Missing required params");
31447
+ }
31448
+ if (isChainflipDepositRoute(route)) {
31449
+ const depositAddressResponse = (await squid.executeRoute({
31450
+ signer: {},
31451
+ route,
31452
+ }));
31453
+ setDeposit({
31454
+ amount: depositAddressResponse.amount,
31455
+ depositAddress: depositAddressResponse.depositAddress,
31456
+ statusTrackingId: depositAddressResponse.chainflipStatusTrackingId,
31457
+ });
31458
+ return;
31459
+ }
31460
+ else if (isDepositAddressDirectTransferRoute(route.transactionRequest)) {
31461
+ // Canton case
31462
+ const orderHash = route.transactionRequest.data;
31463
+ setDeposit({
31464
+ amount: route.params.fromAmount ?? "",
31465
+ depositAddress: route.transactionRequest.target,
31466
+ statusTrackingId: orderHash,
31467
+ memo: orderHash,
31468
+ });
31469
+ return;
31470
+ }
30810
31471
  });
30811
31472
  return {
30812
- isEnabled,
31473
+ paymentMethod,
31474
+ isDepositAddressActive,
30813
31475
  isAvailableAsPaymentMethod,
30814
31476
  swapWillGenerateDepositAddress,
30815
- enable,
30816
- disable,
31477
+ setPaymentMethod,
30817
31478
  getRouteWithDeposit,
30818
31479
  depositAddress,
30819
31480
  closeDepositChannel,
@@ -30845,8 +31506,9 @@ const useUrlSwapParams = () => {
30845
31506
 
30846
31507
  const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, queryOptions, }) => {
30847
31508
  const { evmChains, cosmosChains, suiChains, xrplChains, stellarChains } = useSquidChains(direction);
30848
- const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, } = useSquidTokens(direction);
31509
+ const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens(direction);
30849
31510
  const { keplrTypeWallet } = useCosmosContext();
31511
+ const cantonConnector = useWalletStore((store) => store.connectedWalletsByChainType[ChainType.CANTON]?.wallet?.connector);
30850
31512
  const placeholderData = useMemo(() => {
30851
31513
  const tokens = {
30852
31514
  [ChainType.EVM]: evmTokens.map((t) => ({ ...t, balance: "0" })),
@@ -30856,6 +31518,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30856
31518
  [ChainType.SUI]: suiTokens.map((t) => ({ ...t, balance: "0" })),
30857
31519
  [ChainType.XRPL]: xrplTokens.map((t) => ({ ...t, balance: "0" })),
30858
31520
  [ChainType.STELLAR]: stellarTokens.map((t) => ({ ...t, balance: "0" })),
31521
+ [ChainType.CANTON]: cantonTokens.map((t) => ({ ...t, balance: "0" })),
30859
31522
  };
30860
31523
  if (!chainType) {
30861
31524
  // Return all tokens with zero balance
@@ -30877,6 +31540,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30877
31540
  suiTokens,
30878
31541
  xrplTokens,
30879
31542
  stellarTokens,
31543
+ cantonTokens,
30880
31544
  ]);
30881
31545
  const isQueryEnabled = useMemo(() => {
30882
31546
  // Respect the queryOptions.enabled override if provided
@@ -30899,6 +31563,8 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30899
31563
  return xrplTokens.length > 0;
30900
31564
  case ChainType.STELLAR:
30901
31565
  return stellarTokens.length > 0;
31566
+ case ChainType.CANTON:
31567
+ return cantonTokens.length > 0;
30902
31568
  }
30903
31569
  }, [
30904
31570
  chainType,
@@ -30911,6 +31577,7 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30911
31577
  suiTokens.length,
30912
31578
  xrplTokens.length,
30913
31579
  stellarTokens.length,
31580
+ cantonTokens.length,
30914
31581
  ]);
30915
31582
  const query = useQuery(keys().allTokensBalance(address, chainType, direction), async () => {
30916
31583
  // Return zero balances if no address
@@ -30950,6 +31617,15 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
30950
31617
  case ChainType.STELLAR:
30951
31618
  fetchedTokens = await getAllStellarTokensBalance(address, stellarTokens, stellarChains);
30952
31619
  break;
31620
+ case ChainType.CANTON:
31621
+ fetchedTokens = cantonConnector
31622
+ ? await getAllCantonTokensBalance({
31623
+ connector: cantonConnector,
31624
+ partyId: address,
31625
+ tokens: cantonTokens,
31626
+ })
31627
+ : placeholderData.tokens;
31628
+ break;
30953
31629
  default:
30954
31630
  fetchedTokens = placeholderData.tokens;
30955
31631
  break;
@@ -31020,6 +31696,12 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31020
31696
  direction,
31021
31697
  queryOptions,
31022
31698
  });
31699
+ const cantonBalancesQuery = useAllTokensWithBalanceForChainType({
31700
+ chainType: ChainType.CANTON,
31701
+ address: connectedAddresses?.[ChainType.CANTON],
31702
+ direction,
31703
+ queryOptions,
31704
+ });
31023
31705
  // Create a map of chain type to balance query results
31024
31706
  const balanceQueries = useMemo(() => ({
31025
31707
  [ChainType.EVM]: evmBalancesQuery,
@@ -31029,6 +31711,7 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31029
31711
  [ChainType.SUI]: suiBalancesQuery,
31030
31712
  [ChainType.XRPL]: xrplBalancesQuery,
31031
31713
  [ChainType.STELLAR]: stellarBalancesQuery,
31714
+ [ChainType.CANTON]: cantonBalancesQuery,
31032
31715
  }), [
31033
31716
  evmBalancesQuery,
31034
31717
  cosmosBalancesQuery,
@@ -31037,6 +31720,7 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31037
31720
  suiBalancesQuery,
31038
31721
  xrplBalancesQuery,
31039
31722
  stellarBalancesQuery,
31723
+ cantonBalancesQuery,
31040
31724
  ]);
31041
31725
  // Combine all tokens from different chains
31042
31726
  const allTokens = useMemo(() => Object.values(balanceQueries).flatMap((query) => query.data?.tokens ?? []), [balanceQueries]);
@@ -31047,9 +31731,9 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
31047
31731
  const balanceStr = query?.data?.totalUsdBalance;
31048
31732
  if (!balanceStr)
31049
31733
  return total;
31050
- const balance = new BigNumber$1(balanceStr);
31734
+ const balance = new BigNumber(balanceStr);
31051
31735
  return balance.isFinite() ? total.plus(balance) : total;
31052
- }, new BigNumber$1(0))
31736
+ }, new BigNumber(0))
31053
31737
  .toString();
31054
31738
  }, [balanceQueries]);
31055
31739
  // Aggregate loading states
@@ -31118,6 +31802,12 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31118
31802
  userAddress,
31119
31803
  enabled: chain?.chainType === ChainType.STELLAR && enabled,
31120
31804
  });
31805
+ const { balance: cantonBalance } = useCantonBalance({
31806
+ chain,
31807
+ token,
31808
+ userAddress,
31809
+ enabled: chain?.chainType === ChainType.CANTON && enabled,
31810
+ });
31121
31811
  const balance = useMemo(() => {
31122
31812
  if (!chain?.chainType)
31123
31813
  return "0";
@@ -31136,6 +31826,8 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31136
31826
  return xrplBalance;
31137
31827
  case ChainType.STELLAR:
31138
31828
  return stellarBalance;
31829
+ case ChainType.CANTON:
31830
+ return cantonBalance;
31139
31831
  }
31140
31832
  }, [
31141
31833
  chain?.chainType,
@@ -31146,6 +31838,7 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
31146
31838
  suiBalance,
31147
31839
  xrplBalance,
31148
31840
  stellarBalance,
31841
+ cantonBalance,
31149
31842
  ]);
31150
31843
  return { balance };
31151
31844
  };
@@ -31615,7 +32308,7 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
31615
32308
  });
31616
32309
  // gas fees + fromAmount (if fromToken is gas token)
31617
32310
  const totalGasBalanceNeeded = networkFeesWei +
31618
- BigInt(chainFeeParams?.fromTokenPaysGasFees ? fromAmount ?? 0 : 0);
32311
+ BigInt(chainFeeParams?.fromTokenPaysGasFees ? (fromAmount ?? 0) : 0);
31619
32312
  const gasBalanceNeeded = gasToken
31620
32313
  ? formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals)
31621
32314
  : undefined;
@@ -31792,7 +32485,7 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
31792
32485
  return undefined;
31793
32486
  // gas fees + fromAmount (if fromToken is gas token)
31794
32487
  const totalGasBalanceNeeded = estimatedGas +
31795
- parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? amount ?? "0" : "0", token.decimals);
32488
+ parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? (amount ?? "0") : "0", token.decimals);
31796
32489
  return formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals);
31797
32490
  }, [
31798
32491
  amount,
@@ -32244,6 +32937,9 @@ function useSendTransaction({ to, amount, token, chain, }) {
32244
32937
  chain,
32245
32938
  });
32246
32939
  break;
32940
+ case ChainType.CANTON: {
32941
+ throw new Error("Not implemented");
32942
+ }
32247
32943
  }
32248
32944
  return {
32249
32945
  amount,
@@ -32447,6 +33143,8 @@ async function getSendTransactionStatus({ chain, txHash, }) {
32447
33143
  txHash,
32448
33144
  chain,
32449
33145
  });
33146
+ case ChainType.CANTON:
33147
+ throw new Error("Not implemented");
32450
33148
  }
32451
33149
  }
32452
33150
 
@@ -32470,7 +33168,7 @@ const useHistory = (txType) => {
32470
33168
  fromChain: tx.params.fromChain,
32471
33169
  fromToken: tx.params.fromToken,
32472
33170
  fromAddress: tx.params.fromAddress,
32473
- fromAmount: tx.params.fromAmount,
33171
+ fromAmount: tx.params.fromAmount ?? "",
32474
33172
  toChain: tx.params.toChain,
32475
33173
  toToken: tx.params.toToken,
32476
33174
  toAddress: tx.params.toAddress,
@@ -32898,6 +33596,129 @@ const useApproval = ({ squidRoute, }) => {
32898
33596
  };
32899
33597
  };
32900
33598
 
33599
+ const useSwapStatusQuery = ({ transaction, retry = 25, refetchOnWindowFocus = "always", enabled = true, onStatus, onEndStatus, onNotFound, onError, }) => {
33600
+ const config = useConfigStore((state) => state.config);
33601
+ const isInitialized = useConfigStore((state) => state.isInitialized);
33602
+ const [isTransactionComplete, setIsTransactionComplete] = useState(false);
33603
+ const [refetchInterval, setRefetchInterval] = useState(getSwapTxStatusRefetchInterval(transaction));
33604
+ const { getChainType } = useSquidChains();
33605
+ const fetchTransactionStatusWithLatestConfig = useCallback(async () => {
33606
+ const latestConfig = useConfigStore.getState().config;
33607
+ return fetchSwapTransactionStatus({
33608
+ transaction,
33609
+ integratorId: latestConfig.integratorId,
33610
+ apiUrl: latestConfig.apiUrl,
33611
+ });
33612
+ }, [transaction]);
33613
+ const transactionStatusQuery = useQuery(keys().swapTransactionStatus(transaction?.transactionId), fetchTransactionStatusWithLatestConfig, {
33614
+ enabled: enabled &&
33615
+ transaction?.transactionId !== "0" &&
33616
+ !!transaction?.transactionId &&
33617
+ !!transaction.fromAddress &&
33618
+ !!config.apiUrl &&
33619
+ transaction !== undefined &&
33620
+ !isTransactionComplete &&
33621
+ isInitialized,
33622
+ refetchInterval(statusResponse) {
33623
+ if (statusResponse &&
33624
+ transactionEndStatuses.includes(getTransactionStatus(statusResponse) ?? "")) {
33625
+ return false;
33626
+ }
33627
+ return refetchInterval;
33628
+ },
33629
+ retryDelay: getChainType(transaction?.fromChain) === ChainType.COSMOS ? 5000 : 3000,
33630
+ retry: getChainType(transaction?.fromChain) === ChainType.COSMOS ? 6 : retry,
33631
+ refetchOnWindowFocus,
33632
+ onSuccess: (statusResponse) => {
33633
+ WidgetEvents.getInstance().dispatchSwapStatus(statusResponse.squidTransactionStatus ?? "");
33634
+ onStatus?.({
33635
+ status: getTransactionStatus(statusResponse) ?? "",
33636
+ statusResponse,
33637
+ });
33638
+ const endStatus = getTransactionEndStatus({ statusResponse });
33639
+ if (endStatus) {
33640
+ setIsTransactionComplete(true);
33641
+ onEndStatus?.({ status: endStatus, statusResponse });
33642
+ }
33643
+ },
33644
+ onError: (error) => {
33645
+ if (is404Error(error.cause)) {
33646
+ onNotFound?.();
33647
+ return;
33648
+ }
33649
+ setRefetchInterval(-1);
33650
+ setIsTransactionComplete(true);
33651
+ onError?.();
33652
+ },
33653
+ });
33654
+ return {
33655
+ transactionStatusQuery,
33656
+ };
33657
+ };
33658
+
33659
+ // Statuses that indicate the source deposit has been received
33660
+ // and the swap is now progressing.
33661
+ const sourceReceivedStatuses = [
33662
+ // Chainflip
33663
+ "DEPOSIT_RECEIVED",
33664
+ "BROADCAST_REQUESTED",
33665
+ "COMPLETE",
33666
+ "SWAPPING",
33667
+ // Canton (Squid Intents)
33668
+ "awaiting",
33669
+ "success",
33670
+ ];
33671
+ /**
33672
+ * Tracks a deposit address intent before it becomes a persisted swap history item.
33673
+ *
33674
+ * Once the source deposit is received, it registers the transaction in the transaction
33675
+ * and history stores, then signals the view via `onReceived` to navigate.
33676
+ */
33677
+ const useDepositTransactionStatus = ({ transaction, route, retry = 25, refetchOnWindowFocus = "always", enabled = true, onReceived, }) => {
33678
+ const { fromChain, toChain } = useSwap();
33679
+ const { addSwapTransaction } = useHistory();
33680
+ const getTransaction = useTransactionStore((state) => state.getTransaction);
33681
+ const setTransactionStoreState = useTransactionStore((state) => state.setTransactionState);
33682
+ return useSwapStatusQuery({
33683
+ transaction,
33684
+ retry,
33685
+ refetchOnWindowFocus,
33686
+ enabled,
33687
+ onStatus: ({ status }) => {
33688
+ if (!sourceReceivedStatuses.includes(status))
33689
+ return;
33690
+ if (!transaction?.transactionId || !route?.transactionRequest)
33691
+ return;
33692
+ const { transactionId } = transaction;
33693
+ if (getTransaction(transactionId))
33694
+ return;
33695
+ useTransactionStore.setState({
33696
+ txLocalId: transactionId,
33697
+ currentTransaction: undefined,
33698
+ });
33699
+ const tx = {
33700
+ routeType: route.transactionRequest.type,
33701
+ fromChain,
33702
+ toChain,
33703
+ fromAddress: transaction.fromAddress,
33704
+ transactionId,
33705
+ transactionIdForStatus: transaction.transactionIdForStatus,
33706
+ quoteId: transaction.quoteId ?? "",
33707
+ status: TransactionStatus.ONGOING,
33708
+ sourceStatus: TransactionStatus.SUCCESS,
33709
+ timestamp: Date.now(),
33710
+ };
33711
+ setTransactionStoreState(transactionId, tx);
33712
+ addSwapTransaction({
33713
+ ...tx,
33714
+ params: route.params,
33715
+ estimate: route.estimate,
33716
+ });
33717
+ onReceived?.();
33718
+ },
33719
+ });
33720
+ };
33721
+
32901
33722
  const DEFAULT_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/providers/squid.webp";
32902
33723
  const AXELAR_PROVIDER_IMAGE_URL = "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/providers/axelar.webp";
32903
33724
  const useEstimate = (squidRoute) => {
@@ -35944,6 +36765,342 @@ coin.DecProto = {
35944
36765
 
35945
36766
  } (tx));
35946
36767
 
36768
+ const vParty = (party) => ({ party });
36769
+ const vText = (text) => ({ text });
36770
+ const vNumeric = (numeric) => ({ numeric });
36771
+ const vContractId = (contractId) => ({
36772
+ contractId,
36773
+ });
36774
+ const vList = (elements) => ({
36775
+ list: { elements },
36776
+ });
36777
+ const vRecord = (fields) => ({
36778
+ record: { fields: fields.map(([label, value]) => ({ label, value })) },
36779
+ });
36780
+ const vTextMap = (entries) => ({ textMap: { entries } });
36781
+ const vTimestamp = (isoString) => ({
36782
+ timestamp: String(Math.floor(new Date(isoString).getTime() * 1000)),
36783
+ });
36784
+ function isRecord(value) {
36785
+ return typeof value === "object" && value !== null && !Array.isArray(value);
36786
+ }
36787
+ function normalizeChoiceContextValue(value) {
36788
+ if (typeof value === "string")
36789
+ return value;
36790
+ if (!isRecord(value) || typeof value.tag !== "string")
36791
+ return null;
36792
+ switch (value.tag) {
36793
+ case "AV_Text":
36794
+ case "AV_ContractId":
36795
+ return typeof value.value === "string"
36796
+ ? { tag: value.tag, value: value.value }
36797
+ : null;
36798
+ case "AV_Bool":
36799
+ return typeof value.value === "boolean"
36800
+ ? { tag: value.tag, value: value.value }
36801
+ : null;
36802
+ case "AV_List":
36803
+ if (!Array.isArray(value.value))
36804
+ return null;
36805
+ return {
36806
+ tag: value.tag,
36807
+ value: value.value.flatMap((entry) => {
36808
+ const normalized = normalizeChoiceContextValue(entry);
36809
+ return normalized ? [normalized] : [];
36810
+ }),
36811
+ };
36812
+ default: {
36813
+ const inner = value.value;
36814
+ if (typeof inner === "string" ||
36815
+ typeof inner === "number" ||
36816
+ typeof inner === "boolean" ||
36817
+ inner === null) {
36818
+ return { tag: value.tag, value: inner };
36819
+ }
36820
+ if (Array.isArray(inner)) {
36821
+ return {
36822
+ tag: value.tag,
36823
+ value: inner.flatMap((entry) => {
36824
+ const normalized = normalizeChoiceContextValue(entry);
36825
+ return normalized ? [normalized] : [];
36826
+ }),
36827
+ };
36828
+ }
36829
+ if (!isRecord(inner))
36830
+ return null;
36831
+ const normalizedObject = {};
36832
+ for (const [key, entry] of Object.entries(inner)) {
36833
+ if (typeof entry !== "string" &&
36834
+ typeof entry !== "number" &&
36835
+ typeof entry !== "boolean" &&
36836
+ entry !== null) {
36837
+ return null;
36838
+ }
36839
+ normalizedObject[key] = entry;
36840
+ }
36841
+ return { tag: value.tag, value: normalizedObject };
36842
+ }
36843
+ }
36844
+ }
36845
+ function stringifyChoiceContextValue(value) {
36846
+ return typeof value === "string" ? value : String(value);
36847
+ }
36848
+ function choiceContextValueToAnyValue(value) {
36849
+ if (typeof value === "string") {
36850
+ return {
36851
+ variant: { constructor: "AV_Text", value: vText(value) },
36852
+ };
36853
+ }
36854
+ switch (value.tag) {
36855
+ case "AV_ContractId":
36856
+ if (typeof value.value !== "string") {
36857
+ throw new TypeError("AV_ContractId values must be strings");
36858
+ }
36859
+ return {
36860
+ variant: { constructor: value.tag, value: vContractId(value.value) },
36861
+ };
36862
+ case "AV_Bool":
36863
+ if (typeof value.value !== "boolean") {
36864
+ throw new TypeError("AV_Bool values must be booleans");
36865
+ }
36866
+ return {
36867
+ variant: { constructor: value.tag, value: { bool: value.value } },
36868
+ };
36869
+ case "AV_List":
36870
+ if (!Array.isArray(value.value)) {
36871
+ throw new TypeError("AV_List values must be arrays");
36872
+ }
36873
+ return {
36874
+ variant: {
36875
+ constructor: value.tag,
36876
+ value: vList(value.value.map(choiceContextValueToAnyValue)),
36877
+ },
36878
+ };
36879
+ default:
36880
+ return {
36881
+ variant: {
36882
+ constructor: value.tag,
36883
+ value: vText(stringifyChoiceContextValue(value.value)),
36884
+ },
36885
+ };
36886
+ }
36887
+ }
36888
+
36889
+ /** Metadata key used by Splice token-standard transfers to carry our Squid orderhash memo. */
36890
+ const CANTON_MEMO_KEY = "splice.lfdecentralizedtrust.org/reason";
36891
+ /** Interface id for the transfer factory contract returned by the token registry. */
36892
+ const TRANSFER_FACTORY_INTERFACE_ID = "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory";
36893
+ /** Choice exercised on the transfer factory to create the token-standard transfer. */
36894
+ const TRANSFER_FACTORY_CHOICE = "TransferFactory_Transfer";
36895
+ /** CIP-056 (non-Amulet) tokens expose a registrar parameterized by admin party. */
36896
+ const CIP056_REGISTRAR_BASE = "https://api.utilities.digitalasset.com/api/token-standard/v0/registrars";
36897
+ const TRANSFER_REQUESTED_AT_SKEW_MS = 60_000;
36898
+ const TRANSFER_EXECUTE_WINDOW_MS = 24 * 60 * 60 * 1000;
36899
+ function resolveCantonRegistryUrl(instrument) {
36900
+ if (instrument.id === CANTON_AMULET_INSTRUMENT_ID) {
36901
+ return CANTON_AMULET_REGISTRY_URL;
36902
+ }
36903
+ return `${CIP056_REGISTRAR_BASE}/${encodeURIComponent(instrument.admin)}`;
36904
+ }
36905
+ /**
36906
+ * Build the plain JSON arguments expected by the registry transfer-factory
36907
+ * endpoint before it adds choice context and disclosed contracts.
36908
+ */
36909
+ function buildTransferChoiceArgs({ sender, receiver, amount, instrument, inputHoldingCids, memo, nowMs, }) {
36910
+ return {
36911
+ expectedAdmin: instrument.admin,
36912
+ transfer: {
36913
+ sender,
36914
+ receiver,
36915
+ amount,
36916
+ instrumentId: { admin: instrument.admin, id: instrument.id },
36917
+ requestedAt: new Date(nowMs - TRANSFER_REQUESTED_AT_SKEW_MS).toISOString(),
36918
+ executeBefore: new Date(nowMs + TRANSFER_EXECUTE_WINDOW_MS).toISOString(),
36919
+ inputHoldingCids,
36920
+ meta: { values: { [CANTON_MEMO_KEY]: memo } },
36921
+ },
36922
+ extraArgs: { context: { values: {} }, meta: { values: {} } },
36923
+ };
36924
+ }
36925
+ /**
36926
+ * Canton's Holding contracts follow Bitcoin-style UTXOs model.
36927
+ *
36928
+ * Pick Holding contract ids covering `amount` for the instrument: prefer a
36929
+ * single exact-amount holding, else accumulate largest-first.
36930
+ */
36931
+ function selectInputHoldingCids(holdings, instrument, amount) {
36932
+ const spendableHoldings = holdings.filter((h) => !h.locked &&
36933
+ h.instrument.admin === instrument.admin &&
36934
+ h.instrument.id === instrument.id);
36935
+ const target = new BigNumber(amount);
36936
+ const exact = spendableHoldings.find((h) => new BigNumber(h.amount).eq(target));
36937
+ if (exact)
36938
+ return [exact.contractId];
36939
+ const sorted = [...spendableHoldings].sort((a, b) => new BigNumber(b.amount).comparedTo(new BigNumber(a.amount)));
36940
+ const selected = [];
36941
+ let sum = new BigNumber(0);
36942
+ for (const holding of sorted) {
36943
+ selected.push(holding.contractId);
36944
+ sum = sum.plus(holding.amount);
36945
+ if (sum.gte(target))
36946
+ break;
36947
+ }
36948
+ if (sum.lt(target)) {
36949
+ throw new Error("Insufficient Canton holdings to cover transfer amount");
36950
+ }
36951
+ return selected;
36952
+ }
36953
+ async function fetchInputHoldingCids(connector, party, instrument, amount) {
36954
+ const ledgerEnd = await connector.ledgerApi({
36955
+ requestMethod: "get",
36956
+ resource: "/v2/state/ledger-end",
36957
+ });
36958
+ const activeContracts = await connector.ledgerApi({
36959
+ requestMethod: "post",
36960
+ resource: "/v2/state/active-contracts",
36961
+ body: buildHoldingsAcsRequestBody(party, String(ledgerEnd.offset)),
36962
+ });
36963
+ return selectInputHoldingCids(parseCantonHoldings(activeContracts), instrument, amount);
36964
+ }
36965
+ /**
36966
+ * Ask the token registry for the transfer factory contract and extra context
36967
+ * required to exercise its transfer choice.
36968
+ */
36969
+ async function fetchTransferFactory(registryUrl, choiceArgs) {
36970
+ const response = await fetch(`${registryUrl}/registry/transfer-instruction/v1/transfer-factory`, {
36971
+ method: "POST",
36972
+ headers: { "Content-Type": "application/json" },
36973
+ body: JSON.stringify({
36974
+ choiceArguments: choiceArgs,
36975
+ excludeDebugFields: true,
36976
+ }),
36977
+ });
36978
+ if (!response.ok) {
36979
+ throw new Error(`Canton transfer-factory request failed (${response.status})`);
36980
+ }
36981
+ return response.json();
36982
+ }
36983
+ /**
36984
+ * Convert transfer choice args into strict Daml Value JSON for the wallet's
36985
+ * prepareExecute ExerciseCommand.
36986
+ */
36987
+ function buildPrepareChoiceArgument(choiceArgs) {
36988
+ const contextValues = Object.entries(choiceArgs.extraArgs.context?.values ?? {})
36989
+ .map(([key, value]) => {
36990
+ const normalized = normalizeChoiceContextValue(value);
36991
+ return normalized
36992
+ ? { key, value: choiceContextValueToAnyValue(normalized) }
36993
+ : undefined;
36994
+ })
36995
+ .filter((entry) => Boolean(entry));
36996
+ return vRecord([
36997
+ ["expectedAdmin", vParty(choiceArgs.expectedAdmin)],
36998
+ [
36999
+ "transfer",
37000
+ vRecord([
37001
+ ["sender", vParty(choiceArgs.transfer.sender)],
37002
+ ["receiver", vParty(choiceArgs.transfer.receiver)],
37003
+ ["amount", vNumeric(choiceArgs.transfer.amount)],
37004
+ [
37005
+ "instrumentId",
37006
+ vRecord([
37007
+ ["admin", vParty(choiceArgs.transfer.instrumentId.admin)],
37008
+ ["id", vText(choiceArgs.transfer.instrumentId.id)],
37009
+ ]),
37010
+ ],
37011
+ ["requestedAt", vTimestamp(choiceArgs.transfer.requestedAt)],
37012
+ ["executeBefore", vTimestamp(choiceArgs.transfer.executeBefore)],
37013
+ [
37014
+ "inputHoldingCids",
37015
+ vList(choiceArgs.transfer.inputHoldingCids.map(vContractId)),
37016
+ ],
37017
+ [
37018
+ "meta",
37019
+ vRecord([
37020
+ [
37021
+ "values",
37022
+ vTextMap(Object.entries(choiceArgs.transfer.meta.values).map(([key, value]) => ({ key, value: vText(value) }))),
37023
+ ],
37024
+ ]),
37025
+ ],
37026
+ ]),
37027
+ ],
37028
+ [
37029
+ "extraArgs",
37030
+ vRecord([
37031
+ ["context", vRecord([["values", vTextMap(contextValues)]])],
37032
+ ["meta", vRecord([["values", vTextMap([])]])],
37033
+ ]),
37034
+ ],
37035
+ ]);
37036
+ }
37037
+ /**
37038
+ * Convert a registry disclosed contract into the wallet submission shape,
37039
+ * dropping debug fields and entries without a usable createdEventBlob.
37040
+ */
37041
+ function toDisclosedContract(raw) {
37042
+ if (typeof raw.createdEventBlob !== "string")
37043
+ return null;
37044
+ return {
37045
+ createdEventBlob: raw.createdEventBlob,
37046
+ contractId: typeof raw.contractId === "string" ? raw.contractId : undefined,
37047
+ synchronizerId: typeof raw.synchronizerId === "string" ? raw.synchronizerId : undefined,
37048
+ };
37049
+ }
37050
+ /**
37051
+ * Build a Splice token-standard transfer of `amount` of `token` from `sender`
37052
+ * to `receiver`, carrying `memo`, ready to hand to a wallet's prepareExecute.
37053
+ * Returns the full prepareExecute params (commandId + commands + actAs +
37054
+ * disclosedContracts).
37055
+ */
37056
+ async function buildCantonTransfer(connector, { sender, receiver, amount, token, memo, nowMs, }) {
37057
+ if (!token.originalAddress) {
37058
+ throw new Error("Canton token originalAddress is required");
37059
+ }
37060
+ const instrument = parseCantonInstrument(token.originalAddress);
37061
+ if (!instrument) {
37062
+ throw new Error(`Invalid Canton token address: ${token.originalAddress}`);
37063
+ }
37064
+ const registryUrl = resolveCantonRegistryUrl(instrument);
37065
+ const inputHoldingCids = await fetchInputHoldingCids(connector, sender, instrument, amount);
37066
+ const choiceArgs = buildTransferChoiceArgs({
37067
+ sender,
37068
+ receiver,
37069
+ amount,
37070
+ instrument,
37071
+ inputHoldingCids,
37072
+ memo,
37073
+ nowMs,
37074
+ });
37075
+ const factory = await fetchTransferFactory(registryUrl, choiceArgs);
37076
+ const choiceContextData = factory.choiceContext.choiceContextData;
37077
+ if (!choiceContextData) {
37078
+ throw new Error("Transfer factory choice context is missing");
37079
+ }
37080
+ choiceArgs.extraArgs.context = choiceContextData;
37081
+ const disclosedContracts = (factory.choiceContext?.disclosedContracts ?? []).flatMap((raw) => {
37082
+ const disclosedContract = toDisclosedContract(raw);
37083
+ return disclosedContract ? [disclosedContract] : [];
37084
+ });
37085
+ // Command ID: client-supplied identifier used to deduplicate submissions
37086
+ const commandId = `canton-${memo}`;
37087
+ return {
37088
+ commandId,
37089
+ commands: [
37090
+ {
37091
+ ExerciseCommand: {
37092
+ templateId: TRANSFER_FACTORY_INTERFACE_ID,
37093
+ contractId: factory.factoryId,
37094
+ choice: TRANSFER_FACTORY_CHOICE,
37095
+ choiceArgument: buildPrepareChoiceArgument(choiceArgs),
37096
+ },
37097
+ },
37098
+ ],
37099
+ actAs: [sender],
37100
+ disclosedContracts,
37101
+ };
37102
+ }
37103
+
35947
37104
  const useExecuteTransaction = (squidRoute) => {
35948
37105
  const { fromChain, toChain, fromToken, toToken, isSameChain } = useSwap();
35949
37106
  // A route completes on source tx only if it's same-chain AND
@@ -35952,7 +37109,7 @@ const useExecuteTransaction = (squidRoute) => {
35952
37109
  !!fromChain &&
35953
37110
  !!squidRoute &&
35954
37111
  squidRoute.estimate.actions.every((a) => isActionCompletedOnSourceTx(a, fromChain.chainId));
35955
- const { evmSigner, cosmosSigner, solanaSigner, bitcoinSigner, suiSigner, xrplSigner, stellarSigner, } = useSigner({
37112
+ const { evmSigner, cosmosSigner, solanaSigner, bitcoinSigner, suiSigner, xrplSigner, stellarSigner, cantonSigner, } = useSigner({
35956
37113
  chain: fromChain,
35957
37114
  });
35958
37115
  const { findToken } = useSquidTokens();
@@ -36207,7 +37364,7 @@ const useExecuteTransaction = (squidRoute) => {
36207
37364
  });
36208
37365
  const swapMutationSolana = useMutation(async ({ id, route }) => {
36209
37366
  try {
36210
- if (!route) {
37367
+ if (!route?.transactionRequest) {
36211
37368
  throw new Error("Route is required");
36212
37369
  }
36213
37370
  if (!solanaSigner) {
@@ -36216,10 +37373,10 @@ const useExecuteTransaction = (squidRoute) => {
36216
37373
  if (!route.params.fromAddress || !route.params.toAddress) {
36217
37374
  throw new Error("From or to address is required");
36218
37375
  }
36219
- const isDirectTransfer = isDepositRoute(route);
37376
+ const isChainflipDirectTransfer = isChainflipDepositRoute(route);
36220
37377
  // Means it's a transfer to a deposit address
36221
37378
  // Instead of a Swap/Contract call using a DEX like Jupiter
36222
- if (isDirectTransfer) {
37379
+ if (isChainflipDirectTransfer) {
36223
37380
  // Get the deposit address from the squidRoute
36224
37381
  const depositData = useDepositAddressStore.getState().deposit;
36225
37382
  // Validate params
@@ -36227,7 +37384,7 @@ const useExecuteTransaction = (squidRoute) => {
36227
37384
  throw new Error("Deposit address is required");
36228
37385
  }
36229
37386
  const signature = await executeSolanaTransfer({
36230
- amount: BigInt(route.params.fromAmount),
37387
+ amount: BigInt(route.params.fromAmount ?? ""),
36231
37388
  target: depositData.depositAddress,
36232
37389
  signer: solanaSigner,
36233
37390
  connection: solanaConnection,
@@ -36237,7 +37394,7 @@ const useExecuteTransaction = (squidRoute) => {
36237
37394
  const txParams = setTransactionState({
36238
37395
  route,
36239
37396
  txHash,
36240
- transactionIdForStatus: depositData.chainflipStatusTrackingId,
37397
+ transactionIdForStatus: depositData.statusTrackingId,
36241
37398
  userAddress: sourceUserAddress,
36242
37399
  status: TransactionStatus.INITIAL_LOADING,
36243
37400
  sourceStatus: TransactionStatus.ONGOING,
@@ -36288,7 +37445,7 @@ const useExecuteTransaction = (squidRoute) => {
36288
37445
  }
36289
37446
  });
36290
37447
  const swapMutationBitcoin = useMutation(async ({ id, route }) => {
36291
- const { depositAddress, amount: sendAmount, chainflipStatusTrackingId, } = useDepositAddressStore.getState().deposit ?? {};
37448
+ const { depositAddress, amount: sendAmount, statusTrackingId, } = useDepositAddressStore.getState().deposit ?? {};
36292
37449
  if (!depositAddress) {
36293
37450
  throw new Error(`Invalid deposit address: ${depositAddress}`);
36294
37451
  }
@@ -36311,7 +37468,7 @@ const useExecuteTransaction = (squidRoute) => {
36311
37468
  txHash,
36312
37469
  // When bridging from Bitcoin we need to send the chainflipId to the status endpoint
36313
37470
  // instead of the Bitcoin transaction hash
36314
- transactionIdForStatus: chainflipStatusTrackingId,
37471
+ transactionIdForStatus: statusTrackingId,
36315
37472
  userAddress: sourceUserAddress,
36316
37473
  status: TransactionStatus.INITIAL_LOADING,
36317
37474
  sourceStatus: TransactionStatus.ONGOING,
@@ -36503,6 +37660,56 @@ const useExecuteTransaction = (squidRoute) => {
36503
37660
  const sentTransaction = await client.sendTransaction(signedTransaction);
36504
37661
  await client.waitForTransaction(sentTransaction.hash);
36505
37662
  }, {});
37663
+ const swapMutationCanton = useMutation(async ({ id, route }) => {
37664
+ if (!route?.transactionRequest) {
37665
+ throw new Error("Route is required");
37666
+ }
37667
+ if (!cantonSigner) {
37668
+ throw new Error("Canton signer is required");
37669
+ }
37670
+ if (!isDepositAddressDirectTransferRoute(route.transactionRequest)) {
37671
+ throw new Error("Invalid Canton route type");
37672
+ }
37673
+ const receiver = route.transactionRequest.target;
37674
+ const orderHash = route.transactionRequest.data;
37675
+ const fromAmount = route.params.fromAmount;
37676
+ const token = findToken(route.params.fromToken, route.params.fromChain);
37677
+ if (!sourceUserAddress || !fromAmount || !token) {
37678
+ throw new Error("Need all parameters");
37679
+ }
37680
+ const amount = formatBNToReadable(fromAmount, token.decimals);
37681
+ dispatchSignatureRequestEvent(route);
37682
+ const transferParams = await buildCantonTransfer(cantonSigner, {
37683
+ sender: sourceUserAddress,
37684
+ receiver,
37685
+ amount,
37686
+ token,
37687
+ memo: orderHash,
37688
+ nowMs: Date.now(),
37689
+ });
37690
+ const result = await cantonSigner.prepareExecuteAndWait(transferParams);
37691
+ const txHash = result.tx?.payload?.updateId ?? "";
37692
+ if (txHash) {
37693
+ resetQueriesAfterTxSigned();
37694
+ }
37695
+ WidgetEvents.getInstance().dispatchSwapExecuteCall(route, txHash);
37696
+ const txParams = setTransactionState({
37697
+ route,
37698
+ txHash: txHash,
37699
+ userAddress: sourceUserAddress,
37700
+ status: TransactionStatus.INITIAL_LOADING,
37701
+ sourceStatus: TransactionStatus.ONGOING,
37702
+ id,
37703
+ });
37704
+ if (txParams) {
37705
+ addSwapTransaction({
37706
+ ...txParams,
37707
+ params: route.params,
37708
+ estimate: route.estimate,
37709
+ });
37710
+ }
37711
+ return txHash;
37712
+ });
36506
37713
  const handleTransactionSuccess = useCallback((id) => {
36507
37714
  const currentTx = getTransaction(id);
36508
37715
  queryClient.invalidateQueries(getPrefixKey(QueryKeys.Balances));
@@ -36561,7 +37768,7 @@ const useExecuteTransaction = (squidRoute) => {
36561
37768
  if (!mutationParams.route?.transactionRequest) {
36562
37769
  throw new Error("Route is required");
36563
37770
  }
36564
- const sourceChain = findChain(mutationParams.route.params?.fromChain);
37771
+ const sourceChain = findChain(mutationParams.route.params.fromChain);
36565
37772
  if (!sourceChain)
36566
37773
  throw new Error("Could not find source chain");
36567
37774
  // After getting signature (if needed), continue with the swap flow
@@ -36587,6 +37794,9 @@ const useExecuteTransaction = (squidRoute) => {
36587
37794
  case ChainType.STELLAR: {
36588
37795
  return swapMutationStellar.mutateAsync(mutationParams);
36589
37796
  }
37797
+ case ChainType.CANTON: {
37798
+ return swapMutationCanton.mutateAsync(mutationParams);
37799
+ }
36590
37800
  default:
36591
37801
  throw new Error(`Swap mutation not implemented for chain type: ${sourceChain.chainType}`);
36592
37802
  }
@@ -36759,7 +37969,7 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36759
37969
  const squid = useSquidStore((state) => state.squid);
36760
37970
  const fallbackAddress = useSwapRoutePersistStore((store) => store.swapRoute?.fallbackAddress);
36761
37971
  const depositRefundAddress = useSwapRoutePersistStore((store) => store.swapRoute?.depositRefundAddress);
36762
- const { isAvailableAsPaymentMethod, isEnabled: isDepositAddressEnabled } = useDepositAddress();
37972
+ const { isDepositAddressActive } = useDepositAddress();
36763
37973
  const getRouteMutation = useGetRoute();
36764
37974
  const { fromChain, toChain, fromPrice, destinationAddress: { address: destinationAddress } = {}, fromToken, toToken, } = useSwap();
36765
37975
  const { connectedAddress: { address: sourceConnectedAddress }, } = useMultiChainWallet(fromChain);
@@ -36767,8 +37977,8 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
36767
37977
  // Tokens will be sent to this address in case of swap failure
36768
37978
  //
36769
37979
  // If deposit address is not selected, we use the connected address as the source address instead
36770
- const sourceUserAddress = isDepositAddressEnabled && isAvailableAsPaymentMethod
36771
- ? depositRefundAddress ?? sourceConnectedAddress
37980
+ const sourceUserAddress = isDepositAddressActive
37981
+ ? (depositRefundAddress ?? sourceConnectedAddress)
36772
37982
  : sourceConnectedAddress;
36773
37983
  const squidRouteQueryKeys = 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), [
36774
37984
  fromChain?.chainId,
@@ -36912,94 +38122,50 @@ function useSendTransactionStatus({ chain, txHash, }) {
36912
38122
  * Fetch status of a Swap transaction
36913
38123
  */
36914
38124
  const useSwapTransactionStatus = ({ transaction, retry = 25, refetchOnWindowFocus = "always", enabled = true, }) => {
36915
- const config = useConfigStore((state) => state.config);
36916
- const isInitialized = useConfigStore((state) => state.isInitialized);
36917
38125
  const { replaceSwapTransactionStatus } = useHistory();
36918
38126
  const findTransaction = useHistoryStore((state) => state.findTransaction);
36919
- const [isTransactionComplete, setIsTransactionComplete] = useState(false);
36920
- const [refetchInterval, setRefetchInterval] = useState(getSwapTxStatusRefetchInterval(transaction));
36921
- const { getChainType } = useSquidChains();
36922
38127
  const currentHistoryItem = useMemo(() => findTransaction({
36923
38128
  transactionId: transaction?.transactionId,
36924
38129
  txType: HistoryTxType.SWAP,
36925
38130
  }), [findTransaction, transaction?.transactionId]);
36926
- /**
36927
- * Transaction status endpoint
36928
- * Squid api is using axelar endpoint and parsing the response
36929
- * @returns {StatusResponse} Status response
36930
- */
36931
- const fetchTransactionStatusWithLatestConfig = useCallback(async () => {
36932
- const latestConfig = useConfigStore.getState().config;
36933
- return fetchSwapTransactionStatus({
36934
- transaction,
36935
- integratorId: latestConfig.integratorId,
36936
- apiUrl: latestConfig.apiUrl,
36937
- });
36938
- }, [transaction]);
36939
- const transactionStatusQuery = useQuery(keys().swapTransactionStatus(transaction?.transactionId), fetchTransactionStatusWithLatestConfig, {
38131
+ const transactionStatusQuery = useSwapStatusQuery({
38132
+ transaction,
38133
+ retry,
38134
+ refetchOnWindowFocus,
36940
38135
  enabled: enabled &&
36941
- transaction?.transactionId !== "0" &&
36942
- !!transaction?.transactionId &&
36943
- !!transaction.fromAddress &&
36944
- !!config.apiUrl &&
36945
- transaction !== undefined &&
36946
- !isTransactionComplete &&
36947
- isInitialized &&
36948
38136
  !!currentHistoryItem &&
36949
38137
  !isHistoryTransactionEnded({
36950
38138
  data: currentHistoryItem?.data,
36951
38139
  txType: HistoryTxType.SWAP,
36952
38140
  }),
36953
- refetchInterval(statusResponse) {
36954
- // If the status response is something telling that the transaction
36955
- // is finished, then store transaction history state if success
36956
- // And return false to indicate refetcher to stop
36957
- if (statusResponse &&
36958
- transactionEndStatuses.includes(getTransactionStatus(statusResponse) ?? "")) {
36959
- return false;
36960
- }
36961
- return refetchInterval; // Had to handle a variable here because after onError, we want the interval to stop
38141
+ onEndStatus: ({ status, statusResponse }) => {
38142
+ if (!transaction?.transactionId)
38143
+ return;
38144
+ replaceSwapTransactionStatus({
38145
+ transactionId: transaction.transactionId,
38146
+ statusResponse,
38147
+ status,
38148
+ });
36962
38149
  },
36963
- // At the moment Cosmos indexing takes more time, so need more time between retries
36964
- retryDelay: getChainType(transaction?.fromChain) === ChainType.COSMOS ? 5000 : 3000,
36965
- retry: getChainType(transaction?.fromChain) === ChainType.COSMOS ? 6 : retry,
36966
- refetchOnWindowFocus,
36967
- onSuccess: (statusResponse) => {
36968
- // Dispatch event
36969
- WidgetEvents.getInstance().dispatchSwapStatus(statusResponse.squidTransactionStatus ?? "");
36970
- const endStatus = getTransactionEndStatus({ statusResponse });
36971
- if (endStatus && transaction?.transactionId) {
36972
- setIsTransactionComplete(true);
36973
- replaceSwapTransactionStatus({
36974
- transactionId: transaction.transactionId,
36975
- statusResponse,
36976
- status: endStatus,
36977
- });
36978
- }
38150
+ onNotFound: () => {
38151
+ if (!transaction?.transactionId)
38152
+ return;
38153
+ replaceSwapTransactionStatus({
38154
+ transactionId: transaction.transactionId,
38155
+ statusResponse: undefined,
38156
+ status: TransactionStatus.NOT_FOUND,
38157
+ });
36979
38158
  },
36980
- onError: (error) => {
36981
- // `fetchTransactionStatus` throws an error with a cause being an AxiosError
36982
- const is404 = is404Error(error.cause);
38159
+ onError: () => {
36983
38160
  if (!transaction?.transactionId)
36984
38161
  return;
36985
- if (is404) {
36986
- replaceSwapTransactionStatus({
36987
- transactionId: transaction.transactionId,
36988
- statusResponse: undefined,
36989
- status: TransactionStatus.NOT_FOUND,
36990
- });
36991
- }
36992
- else {
36993
- setRefetchInterval(-1);
36994
- setIsTransactionComplete(true);
36995
- replaceSwapTransactionStatus({
36996
- transactionId: transaction.transactionId,
36997
- statusResponse: undefined,
36998
- status: TransactionStatus.ERROR,
36999
- });
37000
- }
38162
+ replaceSwapTransactionStatus({
38163
+ transactionId: transaction.transactionId,
38164
+ statusResponse: undefined,
38165
+ status: TransactionStatus.ERROR,
38166
+ });
37001
38167
  },
37002
- });
38168
+ }).transactionStatusQuery;
37003
38169
  return {
37004
38170
  transactionStatusQuery,
37005
38171
  latestStatus: transactionStatusQuery.data
@@ -37310,10 +38476,10 @@ function useXrplTrustLine({ address, chain, token, amount }) {
37310
38476
  if (!amount) {
37311
38477
  throw new Error("Amount is required");
37312
38478
  }
37313
- const limitBn = BigNumber$1(trustLineQuery.data?.limit || "0");
37314
- const balanceBn = BigNumber$1(trustLineQuery.data?.balance || "0");
38479
+ const limitBn = BigNumber(trustLineQuery.data?.limit || "0");
38480
+ const balanceBn = BigNumber(trustLineQuery.data?.balance || "0");
37315
38481
  const availableAllowanceBn = limitBn.minus(balanceBn);
37316
- const amountBn = BigNumber$1(formatBNToReadable(amount, token.decimals));
38482
+ const amountBn = BigNumber(formatBNToReadable(amount, token.decimals));
37317
38483
  return availableAllowanceBn.gte(amountBn);
37318
38484
  },
37319
38485
  enabled: !!address &&
@@ -37398,8 +38564,10 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37398
38564
  }
37399
38565
  if (assetsColorsResponse.status === "fulfilled") {
37400
38566
  useAssetsColorsStore.setState(assetsColorsResponse.value);
37401
- initializeSquidWithAssetsColors(squid, assetsColorsResponse.value);
37402
38567
  }
38568
+ initializeSquidData(squid, assetsColorsResponse.status === "fulfilled"
38569
+ ? assetsColorsResponse.value
38570
+ : undefined);
37403
38571
  const shouldResetSwapRouteStore =
37404
38572
  // reset swap route if specified in config
37405
38573
  !config?.loadPreviousStateFromLocalStorage ||
@@ -37431,8 +38599,8 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37431
38599
  error instanceof Error;
37432
38600
  if (isBackendDown) {
37433
38601
  const maintenanceMessage = isAxios503Error
37434
- ? error.response?.data
37435
- ?.message ?? undefined
38602
+ ? (error.response?.data
38603
+ ?.message ?? undefined)
37436
38604
  : "Unable to connect to Squid. Please check your connection or try again later.";
37437
38605
  // Even with an error, we want wagmi to be defined so that we can display the maintenance mode layout
37438
38606
  // Create wagmi config with mainnet as fallback in maintenance mode
@@ -37467,14 +38635,15 @@ const SquidProvider = ({ children, config, placeholder, }) => {
37467
38635
  }, [initializeSdk]);
37468
38636
  return wagmiConfig ? (React.createElement(WagmiProvider, { reconnectOnMount: false, config: wagmiConfig },
37469
38637
  React.createElement(QueryClientProvider, { client: queryClient },
37470
- React.createElement(StellarProvider, null,
37471
- React.createElement(EvmProvider, null,
37472
- React.createElement(XrplProvider, null,
37473
- React.createElement(SuiProvider, null,
37474
- React.createElement(SolanaProvider, null,
37475
- React.createElement(BitcoinProvider, null,
37476
- React.createElement(CosmosProvider, null, children)))))))))) : (placeholder);
37477
- };
37478
-
37479
- export { useDepositAddress as $, AxelarStatusResponseType as A, useHederaTokenAssociations as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useKeyboardNavigation as E, useSquidQueryClient as F, useSquid as G, HistoryTxType as H, useStellarAccountActivation as I, useStellarTrustLine as J, useAddressBookStore as K, useAssetsColorsStore as L, useFavoriteTokensStore as M, Nr as N, useHistoryStore as O, useSendTransactionStore as P, QueryKeys as Q, useConfigStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useSquidStore as U, useSwapRoutePersistStore as V, Wo as W, XamanXrplNetwork as X, useTransactionStore as Y, ConnectingWalletStatus as Z, useWalletStore as _, WindowWalletFlag as a, useGetOnrampPaymentTypes as a$, useSwap as a0, buildUrlSearchParamsFromSwapEvent as a1, parseInitialAssetsFromUrl as a2, useUrlSwapParams as a3, useAllConnectedWalletBalances as a4, useAllTokensWithBalanceForChainType as a5, useCosmosBalance as a6, useEvmBalance as a7, useMultiChainBalance as a8, useMultipleTokenPrices as a9, useSwapTransactionStatus as aA, useAvatar as aB, useHistory as aC, useDebouncedValue as aD, useAddToken as aE, useAutoConnect as aF, useEnsDataForAddress as aG, useEnsSearch as aH, useGnosisContext as aI, useIsSameAddressAndGnosisContext as aJ, useIntegratorContext as aK, useMultiChainWallet as aL, useSigner as aM, useWallet as aN, useWallets as aO, useXrplTrustLine as aP, TX_STATUS_CONSTANTS as aQ, FINAL_TRANSACTION_STATUSES as aR, useGetFiatQuote as aS, useGetOnRampConfig as aT, useExecuteFiatQuote as aU, useFiatOnRampTxStatus as aV, useFiatTransactions as aW, useCurrencyDetails as aX, useCountryDetails as aY, useAvailableQuotes as aZ, useRecommendedQuote as a_, useBitcoinNativeBalance as aa, useCosmosNativeBalance as ab, useEvmNativeBalance as ac, useNativeBalance as ad, useSolanaNativeBalance as ae, useStellarNativeBalance as af, useSuiNativeBalance as ag, useXrplNativeBalance as ah, useNativeTokenForChain as ai, useSingleTokenPrice as aj, useSourceChainGasToken as ak, useSquidTokens as al, useHistoricalData as am, useTokensData as an, useEstimateSendTransaction as ao, useSendTransaction as ap, useSendTransactionGas as aq, useAllTransactionsStatus as ar, useApproval as as, useEstimate as at, useEstimatePriceImpact as au, useExecuteTransaction as av, useGetRoute as aw, useGetRouteWrapper as ax, useRouteWarnings as ay, useSendTransactionStatus as az, chainTypeToZeroAddressMap as b, filterWagmiConnector as b$, useSuggestedFiatAmounts as b0, SquidProvider as b1, EnsService as b2, getXummClient as b3, isXamanXAppContext as b4, getQueryHeaders as b5, getStatusCode as b6, is404Error as b7, assetsBaseUrl as b8, shareSubgraphId as b9, fetchHighestBalanceToken as bA, getInitialOrDefaultTokenAddressForChain as bB, getInitialTokenAddressForChain as bC, filterTokensForDestination as bD, getInitialChainIdFromConfig as bE, getCosmosKey as bF, getKeysSettled as bG, getAllKeysForSupportedCosmosChains as bH, isCosmosAddressValid as bI, getCosmosSigningClient as bJ, getCosmosChainInfosObject as bK, connectCosmosWallet as bL, isFallbackAddressNeeded as bM, suggestChainOrThrow as bN, normalizeError as bO, transactionErrorCode as bP, isUserRejectionError as bQ, getTransactionError as bR, handleTransactionErrorEvents as bS, isSwapRouteError as bT, isStatusError as bU, createQuoteRequestParamsHash as bV, WidgetEvents as bW, EvmNetworkNotSupportedErrorCode as bX, addEthereumChain as bY, parseEvmAddress as bZ, formatEvmWallet as b_, sortTokensBySharedSubgraphIds as ba, getSupportedChainIdsForDirection as bb, filterChains as bc, filterTokens as bd, getTokenImage as be, getNewSwapParamsFromInput as bf, sortAllTokens as bg, findToken as bh, findNativeToken as bi, normalizeIbcAddress as bj, groupTokensBySymbol as bk, groupTokensByChainId as bl, filterViewableTokens as bm, getSecretNetworkBalances as bn, getTokenAssetsKey as bo, fetchAssetsColors as bp, initializeSquidWithAssetsColors as bq, isEmptyObject as br, normalizeTokenSymbol as bs, areTokenSymbolsCompatible as bt, isEvmosChain as bu, resolveChainIdFromAsset as bv, getConfigWithDefaults as bw, randomIntFromInterval as bx, getTokensForChain as by, getFirstAvailableChainId as bz, chainTypeToNativeTokenAddressMap as c, isHistoryTransactionPending as c$, waitForReceiptWithRetry as c0, getUserCountry as c1, getCountryData as c2, getCurrencyData as c3, adaptiveRound as c4, getSuggestedAmountsForCurrency as c5, HederaExtensionHelper as c6, convertHederaAccountIdToEvmAddress as c7, convertEvmAddressToHederaAccountId as c8, scaleHbarToWei as c9, isValidHorizonAsset as cA, formatTransactionHistoryDate as cB, getAxelarExplorerTxUrl as cC, getSourceExplorerTxUrl as cD, getMainExplorerUrl as cE, formatDistance as cF, formatSeconds as cG, formatSwapTxStatusResponseForStorage as cH, simplifyRouteAction as cI, fetchSwapTransactionStatus as cJ, compareTransactionIds as cK, isCoralBridgeAction as cL, isActionCompletedOnSourceTx as cM, sleep as cN, isDepositRoute as cO, isChainflipBridgeTransaction as cP, isOnChainTxData as cQ, getHistoryTransactionId as cR, getStepStatuses as cS, getHalfSuccessState as cT, getStepsInfos as cU, getSwapTxStatusRefetchInterval as cV, getSendTxStatusRefetchInterval as cW, chainflipMultihopBridgeType as cX, getBridgeType as cY, getTransactionStatus as cZ, getTransactionEndStatus as c_, scaleWeiToHbar as ca, parseToBigInt as cb, roundNumericValue as cc, formatUnitsRounded as cd, formatTokenAmount as ce, formatUsdAmount as cf, trimExtraDecimals as cg, getNumericValue as ch, cleanAmount as ci, convertTokenAmountToUSD as cj, convertUSDToTokenAmount as ck, calculateTotal24hChange as cl, getRouteExpiry as cm, searchTokens as cn, filterSolanaWallets as co, isSolanaAddressValid as cp, executeSolanaSwap as cq, executeSolanaTransfer as cr, isStellarAddressValid as cs, getStellarNetwork as ct, stellarAddressToScVal as cu, getStellarTrustLineAsset as cv, isStellarToken as cw, isStellarIssuedToken as cx, getStellarHorizonApiUrl as cy, isValidIssuedAsset as cz, definedInWindow as d, isHistoryTransactionFailed as d0, isHistoryTransactionWarning as d1, isHistoryTransactionEnded as d2, formatHash as d3, isWalletAddressValid as d4, redirectToExtensionsStore as d5, accessProperty as d6, populateWallets as d7, getDefaultChain as d8, sortWallets as d9, areSameAddress as da, sortAddressBook as db, calculateTotalUsdBalanceUSD as dc, addTokenToWallet as dd, isEvmChainNotSupportedError as de, getWalletSupportedChainTypes as df, getConnectorForChainType as dg, walletSupportsChainType as dh, connectWallet as di, cancelConnectWallet as dj, isProblematicConnector as dk, mergeWallets as dl, isXionSmartContractAddress as dm, isXrplAddressValid as dn, buildXrplTrustSetTx as dp, getXrplNetwork as dq, parseXrplPaymentTx as dr, parseXrplTokenAddress as ds, er as e, formatBNToReadable as f, DEFAULT_ROUTE_REFETCH_INTERVAL as g, destinationAddressResetValue as h, fallbackAddressResetValue as i, nativeCosmosTokenAddress as j, nativeEvmTokenAddress as k, nativeSolanaTokenAddress as l, nativeStellarTokenAddress as m, nativeBitcoinTokenAddress as n, nativeSuiTokenAddress as o, nativeXrplTokenAddress as p, CosmosProvider as q, SendTransactionStatus as r, TransactionStatus as s, useTrackSearchEmpty as t, useCosmosContext as u, useSquidChains as v, walletIconBaseUrl as w, useClient as x, useCosmosForChain as y, useHederaAccountActivation as z };
37480
- //# sourceMappingURL=index-BL_AUWQg.js.map
38638
+ React.createElement(CantonProvider, null,
38639
+ React.createElement(StellarProvider, null,
38640
+ React.createElement(EvmProvider, null,
38641
+ React.createElement(XrplProvider, null,
38642
+ React.createElement(SuiProvider, null,
38643
+ React.createElement(SolanaProvider, null,
38644
+ React.createElement(BitcoinProvider, null,
38645
+ React.createElement(CosmosProvider, null, children))))))))))) : (placeholder);
38646
+ };
38647
+
38648
+ export { useDepositAddress as $, AxelarStatusResponseType as A, useHederaTokenAssociations as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useKeyboardNavigation as E, useSquidQueryClient as F, useSquid as G, HistoryTxType as H, useStellarAccountActivation as I, useStellarTrustLine as J, useAddressBookStore as K, useAssetsColorsStore as L, useFavoriteTokensStore as M, Nr as N, useHistoryStore as O, useSendTransactionStore as P, QueryKeys as Q, useConfigStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useSquidStore as U, useSwapRoutePersistStore as V, Wo as W, XamanXrplNetwork as X, useTransactionStore as Y, ConnectingWalletStatus as Z, useWalletStore as _, WindowWalletFlag as a, useRecommendedQuote as a$, useSwap as a0, buildUrlSearchParamsFromSwapEvent as a1, parseInitialAssetsFromUrl as a2, useUrlSwapParams as a3, useAllConnectedWalletBalances as a4, useAllTokensWithBalanceForChainType as a5, useCosmosBalance as a6, useEvmBalance as a7, useMultiChainBalance as a8, useMultipleTokenPrices as a9, useSendTransactionStatus as aA, useSwapTransactionStatus as aB, useAvatar as aC, useHistory as aD, useDebouncedValue as aE, useAddToken as aF, useAutoConnect as aG, useEnsDataForAddress as aH, useEnsSearch as aI, useGnosisContext as aJ, useIsSameAddressAndGnosisContext as aK, useIntegratorContext as aL, useMultiChainWallet as aM, useSigner as aN, useWallet as aO, useWallets as aP, useXrplTrustLine as aQ, TX_STATUS_CONSTANTS as aR, FINAL_TRANSACTION_STATUSES as aS, useGetFiatQuote as aT, useGetOnRampConfig as aU, useExecuteFiatQuote as aV, useFiatOnRampTxStatus as aW, useFiatTransactions as aX, useCurrencyDetails as aY, useCountryDetails as aZ, useAvailableQuotes as a_, useBitcoinNativeBalance as aa, useCosmosNativeBalance as ab, useEvmNativeBalance as ac, useNativeBalance as ad, useSolanaNativeBalance as ae, useStellarNativeBalance as af, useSuiNativeBalance as ag, useXrplNativeBalance as ah, useNativeTokenForChain as ai, useSingleTokenPrice as aj, useSourceChainGasToken as ak, useSquidTokens as al, useHistoricalData as am, useTokensData as an, useEstimateSendTransaction as ao, useSendTransaction as ap, useSendTransactionGas as aq, useAllTransactionsStatus as ar, useApproval as as, useDepositTransactionStatus as at, useEstimate as au, useEstimatePriceImpact as av, useExecuteTransaction as aw, useGetRoute as ax, useGetRouteWrapper as ay, useRouteWarnings as az, chainTypeToZeroAddressMap as b, parseEvmAddress as b$, useGetOnrampPaymentTypes as b0, useSuggestedFiatAmounts as b1, SquidProvider as b2, EnsService as b3, getXummClient as b4, isXamanXAppContext as b5, getQueryHeaders as b6, getStatusCode as b7, is404Error as b8, assetsBaseUrl as b9, getTokensForChain as bA, getFirstAvailableChainId as bB, fetchHighestBalanceToken as bC, getInitialOrDefaultTokenAddressForChain as bD, getInitialTokenAddressForChain as bE, filterTokensForDestination as bF, getInitialChainIdFromConfig as bG, getCosmosKey as bH, getKeysSettled as bI, getAllKeysForSupportedCosmosChains as bJ, isCosmosAddressValid as bK, getCosmosSigningClient as bL, getCosmosChainInfosObject as bM, connectCosmosWallet as bN, isFallbackAddressNeeded as bO, suggestChainOrThrow as bP, normalizeError as bQ, transactionErrorCode as bR, isUserRejectionError as bS, getTransactionError as bT, handleTransactionErrorEvents as bU, isSwapRouteError as bV, isStatusError as bW, createQuoteRequestParamsHash as bX, WidgetEvents as bY, EvmNetworkNotSupportedErrorCode as bZ, addEthereumChain as b_, shareSubgraphId as ba, sortTokensBySharedSubgraphIds as bb, getSupportedChainIdsForDirection as bc, filterChains as bd, filterTokens as be, getTokenImage as bf, getNewSwapParamsFromInput as bg, sortAllTokens as bh, findToken as bi, findNativeToken as bj, normalizeIbcAddress as bk, groupTokensBySymbol as bl, groupTokensByChainId as bm, filterViewableTokens as bn, getSecretNetworkBalances as bo, getTokenAssetsKey as bp, fetchAssetsColors as bq, isSupportedChainType as br, initializeSquidData as bs, isEmptyObject as bt, normalizeTokenSymbol as bu, areTokenSymbolsCompatible as bv, isEvmosChain as bw, resolveChainIdFromAsset as bx, getConfigWithDefaults as by, randomIntFromInterval as bz, chainTypeToNativeTokenAddressMap as c, getBridgeType as c$, formatEvmWallet as c0, filterWagmiConnector as c1, waitForReceiptWithRetry as c2, getUserCountry as c3, getCountryData as c4, getCurrencyData as c5, adaptiveRound as c6, getSuggestedAmountsForCurrency as c7, HederaExtensionHelper as c8, convertHederaAccountIdToEvmAddress as c9, getStellarHorizonApiUrl as cA, isValidIssuedAsset as cB, isValidHorizonAsset as cC, formatTransactionHistoryDate as cD, getAxelarExplorerTxUrl as cE, getSourceExplorerTxUrl as cF, getMainExplorerUrl as cG, formatDistance as cH, formatSeconds as cI, formatSwapTxStatusResponseForStorage as cJ, simplifyRouteAction as cK, fetchSwapTransactionStatus as cL, compareTransactionIds as cM, isCoralBridgeAction as cN, isActionCompletedOnSourceTx as cO, sleep as cP, isChainflipDepositRoute as cQ, isChainflipBridgeTransaction as cR, isOnChainTxData as cS, isDepositAddressDirectTransferRoute as cT, getHistoryTransactionId as cU, getStepStatuses as cV, getHalfSuccessState as cW, getStepsInfos as cX, getSwapTxStatusRefetchInterval as cY, getSendTxStatusRefetchInterval as cZ, chainflipMultihopBridgeType as c_, convertEvmAddressToHederaAccountId as ca, scaleHbarToWei as cb, scaleWeiToHbar as cc, parseToBigInt as cd, roundNumericValue as ce, formatUnitsRounded as cf, formatTokenAmount as cg, formatUsdAmount as ch, trimExtraDecimals as ci, getNumericValue as cj, cleanAmount as ck, convertTokenAmountToUSD as cl, convertUSDToTokenAmount as cm, calculateTotal24hChange as cn, getRouteExpiry as co, searchTokens as cp, filterSolanaWallets as cq, isSolanaAddressValid as cr, executeSolanaSwap as cs, executeSolanaTransfer as ct, isStellarAddressValid as cu, getStellarNetwork as cv, stellarAddressToScVal as cw, getStellarTrustLineAsset as cx, isStellarToken as cy, isStellarIssuedToken as cz, definedInWindow as d, getTransactionStatus as d0, getTransactionEndStatus as d1, isHistoryTransactionPending as d2, isHistoryTransactionFailed as d3, isHistoryTransactionWarning as d4, isHistoryTransactionEnded as d5, formatHash as d6, isWalletAddressValid as d7, redirectToExtensionsStore as d8, populateWallets as d9, buildFallbackWallets as da, getDefaultChain as db, sortWallets as dc, areSameAddress as dd, sortAddressBook as de, calculateTotalUsdBalanceUSD as df, addTokenToWallet as dg, isEvmChainNotSupportedError as dh, getWalletSupportedChainTypes as di, getConnectorForChainType as dj, walletSupportsChainType as dk, connectWallet as dl, cancelConnectWallet as dm, isProblematicConnector as dn, mergeWallets as dp, isXionSmartContractAddress as dq, isXrplAddressValid as dr, buildXrplTrustSetTx as ds, getXrplNetwork as dt, parseXrplPaymentTx as du, parseXrplTokenAddress as dv, er as e, formatBNToReadable as f, DEFAULT_ROUTE_REFETCH_INTERVAL as g, destinationAddressResetValue as h, fallbackAddressResetValue as i, nativeCosmosTokenAddress as j, nativeEvmTokenAddress as k, nativeSolanaTokenAddress as l, nativeStellarTokenAddress as m, nativeBitcoinTokenAddress as n, nativeSuiTokenAddress as o, nativeXrplTokenAddress as p, CosmosProvider as q, SendTransactionStatus as r, TransactionStatus as s, useTrackSearchEmpty as t, useCosmosContext as u, useSquidChains as v, walletIconBaseUrl as w, useClient as x, useCosmosForChain as y, useHederaAccountActivation as z };
38649
+ //# sourceMappingURL=index-B8h1ypYK.js.map