@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.
- package/dist/core/canton/cantonConnector.d.ts +28 -0
- package/dist/core/canton/cip103Client.d.ts +20 -0
- package/dist/core/client/index.d.ts +1 -0
- package/dist/core/constants.d.ts +3 -0
- package/dist/core/fallbackWallets.d.ts +16 -0
- package/dist/core/providers/CantonProvider.d.ts +19 -0
- package/dist/core/types/canton.d.ts +58 -0
- package/dist/core/types/cosmos.d.ts +5 -0
- package/dist/core/types/wallet.d.ts +15 -7
- package/dist/core/wallets.d.ts +5 -0
- package/dist/hooks/canton/useCanton.d.ts +2 -0
- package/dist/hooks/canton/useCantonWallets.d.ts +8 -0
- package/dist/hooks/chains/useSquidChains.d.ts +1 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/store/useDepositAddressStore.d.ts +18 -5
- package/dist/hooks/swap/useDepositAddress.d.ts +6 -7
- package/dist/hooks/tokens/useBalance.d.ts +1 -0
- package/dist/hooks/tokens/useNativeBalance.d.ts +1 -0
- package/dist/hooks/tokens/useSquidTokens.d.ts +1 -0
- package/dist/hooks/transaction/useDepositTransactionStatus.d.ts +20 -0
- package/dist/hooks/transaction/useSwapStatusQuery.d.ts +29 -0
- package/dist/hooks/wallet/useMultiChainWallet.d.ts +55 -29
- package/dist/hooks/wallet/useSigner.d.ts +1 -0
- package/dist/hooks/wallet/useWallet.d.ts +59 -29
- package/dist/hooks/xrpl/useXrplWallets.d.ts +2 -2
- package/dist/{index-BL_AUWQg.js → index-B8h1ypYK.js} +1364 -195
- package/dist/index-B8h1ypYK.js.map +1 -0
- package/dist/{index-DcBFug8t.js → index-doLvokYY.js} +1349 -177
- package/dist/index-doLvokYY.js.map +1 -0
- package/dist/{index.es-1XEAWjab.js → index.es-CuIvGVFi.js} +4 -3
- package/dist/index.es-CuIvGVFi.js.map +1 -0
- package/dist/{index.es-DSQHpime.js → index.es-reWGC10l.js} +4 -3
- package/dist/index.es-reWGC10l.js.map +1 -0
- package/dist/index.esm.js +3 -2
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +9 -5
- package/dist/index.js.map +1 -1
- package/dist/{secretService-B1SDXLS1.js → secretService-3g7QoMaM.js} +4 -3
- package/dist/{secretService-B1SDXLS1.js.map → secretService-3g7QoMaM.js.map} +1 -1
- package/dist/{secretService-DxQ78j5I.js → secretService-DMcFUD-e.js} +4 -3
- package/dist/{secretService-DxQ78j5I.js.map → secretService-DMcFUD-e.js.map} +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.esm.js +7 -1
- package/dist/server.esm.js.map +1 -1
- package/dist/server.js +7 -0
- package/dist/server.js.map +1 -1
- package/dist/services/external/onrampAdapter.d.ts +3 -4
- package/dist/services/external/rpcService.d.ts +17 -0
- package/dist/services/internal/assetsService.d.ts +10 -1
- package/dist/services/internal/cantonDamlValue.d.ts +75 -0
- package/dist/services/internal/cantonService.d.ts +64 -0
- package/dist/services/internal/cantonTransferService.d.ts +93 -0
- package/dist/services/internal/transactionService.d.ts +5 -1
- package/dist/services/internal/walletService.d.ts +3 -6
- package/dist/{stellarService.client-C4TLBEpm.js → stellarService.client-DLPxIX3n.js} +5 -4
- package/dist/{stellarService.client-C4TLBEpm.js.map → stellarService.client-DLPxIX3n.js.map} +1 -1
- package/dist/{stellarService.client-CkP5ng2n.js → stellarService.client-DMdUVPJ8.js} +5 -4
- package/dist/{stellarService.client-CkP5ng2n.js.map → stellarService.client-DMdUVPJ8.js.map} +1 -1
- package/dist/tests/cantonService.test.d.ts +1 -0
- package/dist/tests/cantonTransferService.test.d.ts +1 -0
- package/dist/tests/cip103Client.test.d.ts +1 -0
- package/dist/tests/fallbackWallets.test.d.ts +1 -0
- package/dist/tests/wallets.test.d.ts +1 -0
- package/package.json +3 -2
- package/dist/index-BL_AUWQg.js.map +0 -1
- package/dist/index-DcBFug8t.js.map +0 -1
- package/dist/index.es-1XEAWjab.js.map +0 -1
- 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
|
|
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
|
|
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
|
|
21710
|
-
|
|
21711
|
-
|
|
21712
|
-
|
|
21713
|
-
return
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
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 =
|
|
21952
|
+
link =
|
|
21953
|
+
wallet.links?.firefox || walletStoreLinks[wallet.connectorId]?.firefox;
|
|
21743
21954
|
}
|
|
21744
21955
|
else if (userAgent.indexOf("Chrome") > -1) {
|
|
21745
|
-
link = wallet.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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-
|
|
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
|
-
|
|
23378
|
-
|
|
23379
|
-
|
|
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 =
|
|
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({
|
|
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
|
-
|
|
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-
|
|
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
|
-
...
|
|
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-
|
|
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
|
|
30666
|
-
const balanceBn = BigNumber
|
|
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
|
|
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
|
-
|
|
31406
|
+
selectedPaymentMethod: "connectedWallet",
|
|
30760
31407
|
setDeposit: (data) => {
|
|
30761
31408
|
set({ deposit: data });
|
|
30762
31409
|
},
|
|
30763
|
-
|
|
30764
|
-
set({
|
|
31410
|
+
setPaymentMethod: (method) => {
|
|
31411
|
+
set({ selectedPaymentMethod: method });
|
|
30765
31412
|
},
|
|
30766
31413
|
}));
|
|
30767
31414
|
|
|
30768
31415
|
function useDepositAddress(squidRoute) {
|
|
30769
|
-
const {
|
|
30770
|
-
|
|
31416
|
+
const { selectedPaymentMethod, depositAddress } = useDepositAddressStore((state) => ({
|
|
31417
|
+
selectedPaymentMethod: state.selectedPaymentMethod,
|
|
30771
31418
|
depositAddress: state.deposit?.depositAddress,
|
|
30772
31419
|
}));
|
|
30773
|
-
const { setDeposit,
|
|
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
|
|
30786
|
-
|
|
30787
|
-
|
|
30788
|
-
|
|
30789
|
-
|
|
30790
|
-
|
|
30791
|
-
|
|
30792
|
-
const
|
|
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
|
-
}, [
|
|
31443
|
+
}, [setDeposit]);
|
|
30799
31444
|
const getRouteWithDeposit = useMutation(async ({ route }) => {
|
|
30800
|
-
if (!squid)
|
|
30801
|
-
throw new Error("
|
|
30802
|
-
|
|
30803
|
-
|
|
30804
|
-
|
|
30805
|
-
|
|
30806
|
-
|
|
30807
|
-
|
|
30808
|
-
|
|
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
|
-
|
|
31473
|
+
paymentMethod,
|
|
31474
|
+
isDepositAddressActive,
|
|
30813
31475
|
isAvailableAsPaymentMethod,
|
|
30814
31476
|
swapWillGenerateDepositAddress,
|
|
30815
|
-
|
|
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
|
|
31734
|
+
const balance = new BigNumber(balanceStr);
|
|
31051
31735
|
return balance.isFinite() ? total.plus(balance) : total;
|
|
31052
|
-
}, new BigNumber
|
|
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
|
|
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 (
|
|
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.
|
|
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,
|
|
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:
|
|
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
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
36928
|
-
|
|
36929
|
-
|
|
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
|
-
|
|
36954
|
-
|
|
36955
|
-
|
|
36956
|
-
|
|
36957
|
-
|
|
36958
|
-
|
|
36959
|
-
|
|
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
|
-
|
|
36964
|
-
|
|
36965
|
-
|
|
36966
|
-
|
|
36967
|
-
|
|
36968
|
-
|
|
36969
|
-
|
|
36970
|
-
|
|
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: (
|
|
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
|
-
|
|
36986
|
-
|
|
36987
|
-
|
|
36988
|
-
|
|
36989
|
-
|
|
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
|
|
37314
|
-
const balanceBn = BigNumber
|
|
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
|
|
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(
|
|
37471
|
-
React.createElement(
|
|
37472
|
-
React.createElement(
|
|
37473
|
-
React.createElement(
|
|
37474
|
-
React.createElement(
|
|
37475
|
-
React.createElement(
|
|
37476
|
-
React.createElement(
|
|
37477
|
-
|
|
37478
|
-
|
|
37479
|
-
|
|
37480
|
-
|
|
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
|