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