@0xsquid/react-hooks 8.11.1-beta-danal.2 → 8.12.1-beta-arc.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 +5 -2
- package/dist/core/canton/errors.d.ts +4 -0
- package/dist/core/canton/loopCantonConnector.d.ts +38 -0
- package/dist/core/client/index.d.ts +0 -1
- package/dist/core/constants.d.ts +1 -2
- package/dist/core/types/canton.d.ts +37 -3
- package/dist/core/types/index.d.ts +1 -1
- package/dist/core/types/tokens.d.ts +1 -8
- package/dist/core/types/wallet.d.ts +1 -8
- package/dist/hooks/chains/useSquidChains.d.ts +0 -1
- package/dist/hooks/store/useDepositAddressStore.d.ts +0 -6
- package/dist/hooks/swap/useDepositAddress.d.ts +0 -2
- package/dist/hooks/tokens/useSquidTokens.d.ts +0 -1
- package/dist/hooks/transaction/send/useEstimateSendTransactionGas.d.ts +3 -0
- package/dist/hooks/wallet/useMultiChainWallet.d.ts +0 -38
- package/dist/hooks/wallet/useWallet.d.ts +0 -42
- package/dist/{index-nTqoaD0B.js → index-BBJD55XX.js} +1110 -593
- package/dist/index-BBJD55XX.js.map +1 -0
- package/dist/{index-ByakOYXP.js → index-CLzjMzS_.js} +1109 -590
- package/dist/index-CLzjMzS_.js.map +1 -0
- package/dist/{index.es-DtFDz6qc.js → index.es-BVCh4tlV.js} +2 -2
- package/dist/{index.es-DtFDz6qc.js.map → index.es-BVCh4tlV.js.map} +1 -1
- package/dist/{index.es--AR2n7a0.js → index.es-BiK_wjSb.js} +2 -2
- package/dist/{index.es--AR2n7a0.js.map → index.es-BiK_wjSb.js.map} +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/{secretService-29Ak2qp5.js → secretService-BZ06HTOJ.js} +2 -2
- package/dist/{secretService-29Ak2qp5.js.map → secretService-BZ06HTOJ.js.map} +1 -1
- package/dist/{secretService-cgr3P1zw.js → secretService-DkE9yz1o.js} +2 -2
- package/dist/{secretService-cgr3P1zw.js.map → secretService-DkE9yz1o.js.map} +1 -1
- package/dist/server.esm.js +1 -6
- package/dist/server.esm.js.map +1 -1
- package/dist/server.js +1 -6
- package/dist/server.js.map +1 -1
- package/dist/services/external/rpcService.d.ts +2 -4
- package/dist/services/index.d.ts +0 -1
- package/dist/services/internal/arcService.d.ts +7 -0
- package/dist/services/internal/assetsService.d.ts +9 -3
- package/dist/services/internal/cantonService.d.ts +2 -0
- package/dist/services/internal/cantonTransferService.d.ts +3 -3
- package/dist/services/internal/configService.d.ts +14 -3
- package/dist/services/internal/estimateService.d.ts +13 -3
- package/dist/services/internal/searchService.d.ts +1 -2
- package/dist/services/internal/tempoService.d.ts +2 -0
- package/dist/services/internal/transactionService.d.ts +0 -8
- package/dist/services/internal/walletService.d.ts +1 -1
- package/dist/{stellarService.client-B__dTUBZ.js → stellarService.client-DtA9zkRt.js} +2 -2
- package/dist/{stellarService.client-B__dTUBZ.js.map → stellarService.client-DtA9zkRt.js.map} +1 -1
- package/dist/{stellarService.client-D-zkMI5s.js → stellarService.client-fnyXRadt.js} +2 -2
- package/dist/{stellarService.client-D-zkMI5s.js.map → stellarService.client-fnyXRadt.js.map} +1 -1
- package/dist/tests/arcConfigService.test.d.ts +1 -0
- package/dist/tests/arcGasAccounting.test.d.ts +1 -0
- package/dist/tests/arcWalletService.test.d.ts +1 -0
- package/dist/tests/fixtures/arc.d.ts +8 -0
- package/dist/tests/loopCantonConnector.test.d.ts +1 -0
- package/dist/tests/loopSdkContract.test.d.ts +1 -0
- package/dist/tests/useArcApproval.test.d.ts +1 -0
- package/dist/tests/useArcSendEstimate.test.d.ts +1 -0
- package/dist/tests/useAutoConnectCanton.test.d.ts +1 -0
- package/dist/tests/useCantonRestoration.test.d.ts +1 -0
- package/dist/tests/useNativeTokenForChain.test.d.ts +1 -0
- package/dist/tests/useSwapArcSelection.test.d.ts +1 -0
- package/package.json +3 -2
- package/dist/core/types/danal.d.ts +0 -1
- package/dist/index-ByakOYXP.js.map +0 -1
- package/dist/index-nTqoaD0B.js.map +0 -1
- package/dist/services/internal/danalService.d.ts +0 -8
- /package/dist/tests/{danalService.test.d.ts → arcAssetsService.test.d.ts} +0 -0
|
@@ -59,7 +59,6 @@ const suiZeroAddress = "0x0000000000000000000000000000000000000000";
|
|
|
59
59
|
const xrplZeroAddress = "rrrrrrrrrrrrrrrrrrrrrhoLvTp";
|
|
60
60
|
const stellarZeroAddress = "GAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWHF";
|
|
61
61
|
const cantonZeroAddress = "none::12200000000000000000000000000000000000000000000000000000000000000000";
|
|
62
|
-
const danalZeroAddress = "PCI00000000000000000000000000000000000000000000000000";
|
|
63
62
|
const chainTypeToZeroAddressMap = {
|
|
64
63
|
[ChainType.EVM]: zeroAddress$1,
|
|
65
64
|
[ChainType.COSMOS]: cosmosZeroAddress,
|
|
@@ -69,7 +68,6 @@ const chainTypeToZeroAddressMap = {
|
|
|
69
68
|
[ChainType.XRPL]: xrplZeroAddress,
|
|
70
69
|
[ChainType.STELLAR]: stellarZeroAddress,
|
|
71
70
|
[ChainType.CANTON]: cantonZeroAddress,
|
|
72
|
-
[ChainType.DANAL]: danalZeroAddress,
|
|
73
71
|
};
|
|
74
72
|
const nativeEvmTokenAddress = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";
|
|
75
73
|
const nativeCosmosTokenAddress = "uosmo";
|
|
@@ -79,7 +77,6 @@ const nativeSuiTokenAddress = "0x00000000000000000000000000000000000000000000000
|
|
|
79
77
|
const nativeXrplTokenAddress = "xrp";
|
|
80
78
|
const nativeStellarTokenAddress = "CAS3J7GYLGXMF6TDJBBYYSE3HQ6BBSMLNUQ34T6TZMYMW2EVH34XOWMA";
|
|
81
79
|
const nativeCantonTokenAddress = "DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc";
|
|
82
|
-
const nativeDanalTokenAddress = "pci";
|
|
83
80
|
// by setting slippage to undefined, it's set to "auto"
|
|
84
81
|
const defaultSlippage = undefined;
|
|
85
82
|
const destinationAddressResetValue = "null";
|
|
@@ -135,6 +132,7 @@ const CHAIN_IDS = {
|
|
|
135
132
|
MANTRA: "5888",
|
|
136
133
|
CITREA: "4114",
|
|
137
134
|
TEMPO: "4217",
|
|
135
|
+
ARC: "5042",
|
|
138
136
|
// others
|
|
139
137
|
BITCOIN: "bitcoin",
|
|
140
138
|
SOLANA: "solana-mainnet-beta",
|
|
@@ -145,7 +143,6 @@ const CHAIN_IDS = {
|
|
|
145
143
|
STELLAR: "stellar-mainnet",
|
|
146
144
|
STELLAR_TESTNET: "stellar-testnet",
|
|
147
145
|
CANTON: "canton",
|
|
148
|
-
DANAL_TESTNET: "danal-testnet",
|
|
149
146
|
};
|
|
150
147
|
const chainTypeToDefaultChainIdMap = {
|
|
151
148
|
[ChainType.EVM]: CHAIN_IDS.ETHEREUM,
|
|
@@ -156,7 +153,6 @@ const chainTypeToDefaultChainIdMap = {
|
|
|
156
153
|
[ChainType.XRPL]: CHAIN_IDS.XRPL,
|
|
157
154
|
[ChainType.STELLAR]: CHAIN_IDS.STELLAR,
|
|
158
155
|
[ChainType.CANTON]: CHAIN_IDS.CANTON,
|
|
159
|
-
[ChainType.DANAL]: CHAIN_IDS.DANAL_TESTNET,
|
|
160
156
|
};
|
|
161
157
|
const chainTypeToNativeTokenAddressMap = {
|
|
162
158
|
[ChainType.EVM]: nativeEvmTokenAddress,
|
|
@@ -167,7 +163,6 @@ const chainTypeToNativeTokenAddressMap = {
|
|
|
167
163
|
[ChainType.XRPL]: nativeXrplTokenAddress,
|
|
168
164
|
[ChainType.STELLAR]: nativeStellarTokenAddress,
|
|
169
165
|
[ChainType.CANTON]: nativeCantonTokenAddress,
|
|
170
|
-
[ChainType.DANAL]: nativeDanalTokenAddress,
|
|
171
166
|
};
|
|
172
167
|
const defaultConfigValues = {
|
|
173
168
|
integratorId: INTEGRATOR_ID,
|
|
@@ -20949,6 +20944,27 @@ const isBitcoinAddressValid = (address$1) => {
|
|
|
20949
20944
|
}
|
|
20950
20945
|
};
|
|
20951
20946
|
|
|
20947
|
+
const arcUsdcTokenAddress = "0x3600000000000000000000000000000000000000";
|
|
20948
|
+
const isArcChain = (chainId) => chainId === CHAIN_IDS.ARC;
|
|
20949
|
+
const isArcUsdcToken = (token) => isArcChain(token?.chainId) &&
|
|
20950
|
+
token?.address.toLowerCase() === arcUsdcTokenAddress;
|
|
20951
|
+
const isArcNativeToken = (token) => isArcChain(token?.chainId) &&
|
|
20952
|
+
token?.address.toLowerCase() === nativeEvmTokenAddress;
|
|
20953
|
+
const normalizeArcTokenAddress = (chainId, address) => isArcChain(chainId) && address?.toLowerCase() === nativeEvmTokenAddress
|
|
20954
|
+
? arcUsdcTokenAddress
|
|
20955
|
+
: address;
|
|
20956
|
+
const deduplicateArcBalances = (tokens) => {
|
|
20957
|
+
const canonicalChains = new Set(tokens
|
|
20958
|
+
.filter((token) => isArcChain(token.chainId) &&
|
|
20959
|
+
token.address?.toLowerCase() === arcUsdcTokenAddress)
|
|
20960
|
+
.map((token) => token.chainId));
|
|
20961
|
+
return tokens.filter((token) => !(canonicalChains.has(token.chainId) &&
|
|
20962
|
+
token.address?.toLowerCase() === nativeEvmTokenAddress));
|
|
20963
|
+
};
|
|
20964
|
+
|
|
20965
|
+
function getCantonCommandId(memo) {
|
|
20966
|
+
return `canton-${memo}`;
|
|
20967
|
+
}
|
|
20952
20968
|
/**
|
|
20953
20969
|
* Format a Canton connector into a Squid {@link CantonWallet}. Shared by the
|
|
20954
20970
|
* announce-discovery and injected-provider paths.
|
|
@@ -21099,51 +21115,16 @@ function cantonInstrumentKey(instrument) {
|
|
|
21099
21115
|
* is already a Decimal, not base units).
|
|
21100
21116
|
*/
|
|
21101
21117
|
function groupCantonHoldingBalances(acsResponse) {
|
|
21118
|
+
return sumCantonHoldingBalances(parseCantonHoldings(acsResponse).filter((holding) => !holding.locked));
|
|
21119
|
+
}
|
|
21120
|
+
function sumCantonHoldingBalances(holdings) {
|
|
21102
21121
|
const totals = {};
|
|
21103
|
-
for (const holding of
|
|
21104
|
-
// Locked holdings are not spendable, skip them
|
|
21105
|
-
if (holding.locked)
|
|
21106
|
-
continue;
|
|
21122
|
+
for (const holding of holdings) {
|
|
21107
21123
|
const key = cantonInstrumentKey(holding.instrument);
|
|
21108
21124
|
const total = totals[key] ?? new BigNumber(0);
|
|
21109
21125
|
totals[key] = total.plus(new BigNumber(holding.amount));
|
|
21110
21126
|
}
|
|
21111
|
-
return Object.fromEntries(Object.entries(totals).map(([key, total]) => [key, total.
|
|
21112
|
-
}
|
|
21113
|
-
|
|
21114
|
-
// Matches the backend validation: "PCI" + 50 uppercase-hex chars, case-sensitive.
|
|
21115
|
-
const DANAL_ADDRESS_REGEX = /^PCI[0-9A-F]{50}$/;
|
|
21116
|
-
function isDanalAddressValid(address) {
|
|
21117
|
-
if (!address)
|
|
21118
|
-
return false;
|
|
21119
|
-
return DANAL_ADDRESS_REGEX.test(address);
|
|
21120
|
-
}
|
|
21121
|
-
// Fabric transaction id: 64 hex chars, no 0x prefix
|
|
21122
|
-
const DANAL_TX_HASH_REGEX = /^[0-9a-fA-F]{64}$/;
|
|
21123
|
-
function isDanalTxHashValid(hash) {
|
|
21124
|
-
if (!hash)
|
|
21125
|
-
return false;
|
|
21126
|
-
return DANAL_TX_HASH_REGEX.test(hash);
|
|
21127
|
-
}
|
|
21128
|
-
function isDanalTransferRequestBody(value) {
|
|
21129
|
-
if (typeof value !== "object" || value === null)
|
|
21130
|
-
return false;
|
|
21131
|
-
const { receiver, amount, memo } = value;
|
|
21132
|
-
return (typeof receiver === "string" &&
|
|
21133
|
-
receiver.length > 0 &&
|
|
21134
|
-
typeof amount === "string" &&
|
|
21135
|
-
amount.length > 0 &&
|
|
21136
|
-
typeof memo === "string" &&
|
|
21137
|
-
memo.length > 0);
|
|
21138
|
-
}
|
|
21139
|
-
function parseDanalTransferBody(data) {
|
|
21140
|
-
try {
|
|
21141
|
-
const parsed = JSON.parse(data);
|
|
21142
|
-
return isDanalTransferRequestBody(parsed) ? parsed : null;
|
|
21143
|
-
}
|
|
21144
|
-
catch {
|
|
21145
|
-
return null;
|
|
21146
|
-
}
|
|
21127
|
+
return Object.fromEntries(Object.entries(totals).map(([key, total]) => [key, total.toFixed()]));
|
|
21147
21128
|
}
|
|
21148
21129
|
|
|
21149
21130
|
const solanaTokenProgramIdByAddress = {
|
|
@@ -21482,15 +21463,6 @@ function isOnChainTxData(squidData) {
|
|
|
21482
21463
|
function isDepositAddressDirectTransferRoute(squidData) {
|
|
21483
21464
|
return squidData.type === SquidDataType.DepositAddressDirectTransfer;
|
|
21484
21465
|
}
|
|
21485
|
-
/**
|
|
21486
|
-
* Danal keeps SquidDataType.DepositAddressWithMemo, which XRPL/Stellar use for
|
|
21487
|
-
* wallet-signed transactions — so the deposit treatment is gated on the chain,
|
|
21488
|
-
* not just the type
|
|
21489
|
-
*/
|
|
21490
|
-
function isDanalDepositRoute(route) {
|
|
21491
|
-
return (route.params.fromChain === CHAIN_IDS.DANAL_TESTNET &&
|
|
21492
|
-
route.transactionRequest?.type === SquidDataType.DepositAddressWithMemo);
|
|
21493
|
-
}
|
|
21494
21466
|
function getHistoryTransactionId(tx) {
|
|
21495
21467
|
switch (tx.txType) {
|
|
21496
21468
|
case HistoryTxType.SWAP:
|
|
@@ -22015,11 +21987,6 @@ const chainTypeToTrimLength = {
|
|
|
22015
21987
|
start: 3,
|
|
22016
21988
|
end: 3,
|
|
22017
21989
|
},
|
|
22018
|
-
// PCI0180...E77E
|
|
22019
|
-
[ChainType.DANAL]: {
|
|
22020
|
-
start: 7,
|
|
22021
|
-
end: 4,
|
|
22022
|
-
},
|
|
22023
21990
|
};
|
|
22024
21991
|
const truncateWithEllipsis = (value, startLength, endLength) => value.length <= startLength + endLength
|
|
22025
21992
|
? value
|
|
@@ -22068,8 +22035,6 @@ const isWalletAddressValid = (chainData, address) => {
|
|
|
22068
22035
|
return isStellarAddressValid(address);
|
|
22069
22036
|
case ChainType.CANTON:
|
|
22070
22037
|
return isCantonAddressValid(address);
|
|
22071
|
-
case ChainType.DANAL:
|
|
22072
|
-
return isDanalAddressValid(address);
|
|
22073
22038
|
}
|
|
22074
22039
|
};
|
|
22075
22040
|
const redirectToExtensionsStore = (wallet) => {
|
|
@@ -22233,7 +22198,7 @@ function sortAddressBook(a, b, selectedAddress) {
|
|
|
22233
22198
|
return 0;
|
|
22234
22199
|
}
|
|
22235
22200
|
const calculateTotalUsdBalanceUSD = (tokens) => {
|
|
22236
|
-
const totalUsd = tokens.reduce((total, token) => {
|
|
22201
|
+
const totalUsd = deduplicateArcBalances(tokens).reduce((total, token) => {
|
|
22237
22202
|
const balance = parseFloat(token.balance);
|
|
22238
22203
|
const usdPrice = token.usdPrice ?? 0;
|
|
22239
22204
|
const balanceUsd = balance * usdPrice;
|
|
@@ -22354,8 +22319,6 @@ const connectByChainType = async (chainType, wallet, defaultChain, params) => {
|
|
|
22354
22319
|
connector,
|
|
22355
22320
|
},
|
|
22356
22321
|
});
|
|
22357
|
-
case ChainType.DANAL:
|
|
22358
|
-
return null;
|
|
22359
22322
|
}
|
|
22360
22323
|
};
|
|
22361
22324
|
const getChainTypesToConnect = (selectedChainTypes, defaultChain, supportedChains) => {
|
|
@@ -22480,6 +22443,8 @@ const cancelConnectWallet = (wallet) => {
|
|
|
22480
22443
|
return;
|
|
22481
22444
|
}
|
|
22482
22445
|
switch (wallet.type) {
|
|
22446
|
+
case ChainType.CANTON:
|
|
22447
|
+
return wallet.connector.cancelConnect?.();
|
|
22483
22448
|
case ChainType.XRPL:
|
|
22484
22449
|
return wallet.connector.cancelConnect?.();
|
|
22485
22450
|
default:
|
|
@@ -23045,22 +23010,36 @@ const getFirstAvailableChainId = (config, direction, chains = []) => {
|
|
|
23045
23010
|
// if no initial chain ID is found in config, return the first available chain ID
|
|
23046
23011
|
return availableChains.length > 0 ? availableChains[0].chainId : undefined;
|
|
23047
23012
|
};
|
|
23048
|
-
const fetchHighestBalanceToken = (fetchCachedBalance, chainId) => {
|
|
23013
|
+
const fetchHighestBalanceToken = (fetchCachedBalance, chainId, selectableTokens, direction) => {
|
|
23049
23014
|
let address = undefined;
|
|
23050
23015
|
if (fetchCachedBalance) {
|
|
23051
23016
|
const queryCache = fetchCachedBalance?.queryClient?.getQueryCache();
|
|
23017
|
+
const directionCache = isArcChain(chainId) && direction
|
|
23018
|
+
? queryCache?.find(keys().allTokensBalance(fetchCachedBalance.address, ChainType.EVM, direction))
|
|
23019
|
+
: undefined;
|
|
23052
23020
|
// get cached balance from key
|
|
23053
|
-
const cache =
|
|
23054
|
-
|
|
23055
|
-
|
|
23021
|
+
const cache = directionCache?.state.data !== undefined
|
|
23022
|
+
? directionCache
|
|
23023
|
+
: queryCache?.find(keys().allTokensBalance(fetchCachedBalance?.address, !isNaN(Number(chainId)) ? ChainType.EVM : ChainType.COSMOS));
|
|
23024
|
+
const cacheData = cache?.state.data;
|
|
23025
|
+
const cacheResult = Array.isArray(cacheData)
|
|
23026
|
+
? cacheData
|
|
23027
|
+
: isArcChain(chainId)
|
|
23028
|
+
? (cacheData?.tokens ?? [])
|
|
23029
|
+
: [];
|
|
23056
23030
|
if (cacheResult.length > 0) {
|
|
23057
|
-
const tokensWithBalance = cacheResult.filter((t) => t.chainId === chainId &&
|
|
23031
|
+
const tokensWithBalance = deduplicateArcBalances(cacheResult).filter((t) => t.chainId === chainId &&
|
|
23032
|
+
Number(t.balance) > 0 &&
|
|
23033
|
+
(!selectableTokens ||
|
|
23034
|
+
selectableTokens.some((token) => token.chainId === t.chainId &&
|
|
23035
|
+
token.address.toLowerCase() ===
|
|
23036
|
+
normalizeArcTokenAddress(t.chainId, t.address)?.toLowerCase())));
|
|
23058
23037
|
if (tokensWithBalance.length > 0) {
|
|
23059
23038
|
// Return the token with the highest balance
|
|
23060
23039
|
// TODO: At the moment we're not taking into account usd price
|
|
23061
23040
|
const tokenWithHighestBalance = tokensWithBalance.reduce((prev, current) => Number(prev.balance) > Number(current.balance) ? prev : current);
|
|
23062
23041
|
if (tokenWithHighestBalance) {
|
|
23063
|
-
address = tokenWithHighestBalance.address;
|
|
23042
|
+
address = normalizeArcTokenAddress(tokenWithHighestBalance.chainId, tokenWithHighestBalance.address);
|
|
23064
23043
|
}
|
|
23065
23044
|
}
|
|
23066
23045
|
}
|
|
@@ -23071,6 +23050,21 @@ const findNativeTokenForChainType = (tokens) => {
|
|
|
23071
23050
|
return tokens.find((t) => t.address.toLowerCase() ===
|
|
23072
23051
|
chainTypeToNativeTokenAddressMap[t.type].toLowerCase());
|
|
23073
23052
|
};
|
|
23053
|
+
const getTokenAddressForSelection = ({ tokens, config, chainId, address, direction, excludeToken, }) => {
|
|
23054
|
+
if (!isArcChain(chainId))
|
|
23055
|
+
return address;
|
|
23056
|
+
const normalizedAddress = normalizeArcTokenAddress(chainId, address);
|
|
23057
|
+
const excludedAddress = normalizeArcTokenAddress(excludeToken?.chainId, excludeToken?.address);
|
|
23058
|
+
if (!chainId ||
|
|
23059
|
+
!normalizedAddress ||
|
|
23060
|
+
(excludeToken?.chainId === chainId &&
|
|
23061
|
+
normalizedAddress.toLowerCase() === excludedAddress?.toLowerCase()) ||
|
|
23062
|
+
!getSupportedChainIdsForDirection([chainId], config, direction).includes(chainId)) {
|
|
23063
|
+
return undefined;
|
|
23064
|
+
}
|
|
23065
|
+
return filterViewableTokens(tokens, config, direction).find((token) => token.chainId === chainId &&
|
|
23066
|
+
token.address.toLowerCase() === normalizedAddress.toLowerCase())?.address;
|
|
23067
|
+
};
|
|
23074
23068
|
/**
|
|
23075
23069
|
* Returns the default token address for a specific chain and direction based on config.
|
|
23076
23070
|
* If no default tokens are set in config, returns the native token for the specified chain
|
|
@@ -23088,6 +23082,25 @@ const getInitialOrDefaultTokenAddressForChain = ({ tokens, config, chainId, dire
|
|
|
23088
23082
|
const supportedChainIds = getSupportedChainIdsForDirection([chainId], config, direction);
|
|
23089
23083
|
if (!supportedChainIds.includes(chainId))
|
|
23090
23084
|
return;
|
|
23085
|
+
if (isArcChain(chainId)) {
|
|
23086
|
+
const selectAddress = (address) => getTokenAddressForSelection({
|
|
23087
|
+
tokens,
|
|
23088
|
+
config,
|
|
23089
|
+
chainId,
|
|
23090
|
+
address,
|
|
23091
|
+
direction,
|
|
23092
|
+
excludeToken,
|
|
23093
|
+
});
|
|
23094
|
+
const selectableTokens = tokens.filter((token) => token.chainId === chainId &&
|
|
23095
|
+
!isArcNativeToken(token) &&
|
|
23096
|
+
selectAddress(token.address) !== undefined);
|
|
23097
|
+
return (selectAddress(config.defaultTokensPerChain?.find((token) => token.chainId === chainId)
|
|
23098
|
+
?.address) ??
|
|
23099
|
+
selectAddress(getInitialTokenAddressForChain({ tokens, config, chainId, direction })) ??
|
|
23100
|
+
selectAddress(fetchHighestBalanceToken(fetchCachedBalance, chainId, selectableTokens, direction)) ??
|
|
23101
|
+
selectAddress(arcUsdcTokenAddress) ??
|
|
23102
|
+
selectableTokens[0]?.address);
|
|
23103
|
+
}
|
|
23091
23104
|
const configDefaultTokenForChain = config.defaultTokensPerChain?.find((token) => token.chainId == chainId);
|
|
23092
23105
|
// get default token from config
|
|
23093
23106
|
if (configDefaultTokenForChain &&
|
|
@@ -23131,6 +23144,23 @@ const getInitialTokenAddressForChain = ({ chainId, config, direction, tokens, un
|
|
|
23131
23144
|
const initialAsset = config.initialAssets?.[direction];
|
|
23132
23145
|
if (!initialAsset)
|
|
23133
23146
|
return undefined;
|
|
23147
|
+
if (isArcChain(chainId)) {
|
|
23148
|
+
const address = isNamedTokenConfig(initialAsset)
|
|
23149
|
+
? tokens.find((token) => token.chainId === chainId &&
|
|
23150
|
+
!isArcNativeToken(token) &&
|
|
23151
|
+
token.symbol.toLowerCase() === initialAsset.symbol?.toLowerCase())?.address
|
|
23152
|
+
: initialAsset.chainId === chainId
|
|
23153
|
+
? initialAsset.address
|
|
23154
|
+
: undefined;
|
|
23155
|
+
return getTokenAddressForSelection({
|
|
23156
|
+
tokens,
|
|
23157
|
+
config,
|
|
23158
|
+
chainId,
|
|
23159
|
+
address,
|
|
23160
|
+
direction,
|
|
23161
|
+
excludeToken: { chainId, address: unavailableTokenAddress },
|
|
23162
|
+
});
|
|
23163
|
+
}
|
|
23134
23164
|
if (isNamedTokenConfig(initialAsset)) {
|
|
23135
23165
|
if (!initialAsset.symbol)
|
|
23136
23166
|
return undefined;
|
|
@@ -23340,12 +23370,44 @@ const handleDestinationAddressOnSwapChange = ({ fromChainId, fromTokenAddress, t
|
|
|
23340
23370
|
});
|
|
23341
23371
|
let destinationTokenAddress = toChainId && !toTokenAddress
|
|
23342
23372
|
? defaultToAddress
|
|
23343
|
-
: toTokenAddress ?? swapRoute?.toTokenAddress;
|
|
23373
|
+
: (toTokenAddress ?? swapRoute?.toTokenAddress);
|
|
23344
23374
|
const lowerCaseDestinationTokenAddress = destinationTokenAddress?.toLowerCase();
|
|
23345
23375
|
if (destinationTokensFiltered.find((t) => t.address === lowerCaseDestinationTokenAddress) === undefined) {
|
|
23346
23376
|
destinationTokenAddress = defaultToAddress;
|
|
23347
23377
|
}
|
|
23348
|
-
return
|
|
23378
|
+
return isArcChain(toChainId ?? swapRoute?.toChainId)
|
|
23379
|
+
? destinationTokenAddress?.toLowerCase()
|
|
23380
|
+
: lowerCaseDestinationTokenAddress;
|
|
23381
|
+
};
|
|
23382
|
+
const normalizeSwapParamsForSelection = ({ swapParams, tokens, chains, config, }) => {
|
|
23383
|
+
const fromTokenAddress = getTokenAddressForSelection({
|
|
23384
|
+
tokens,
|
|
23385
|
+
config,
|
|
23386
|
+
chainId: swapParams.fromChainId,
|
|
23387
|
+
address: swapParams.fromTokenAddress,
|
|
23388
|
+
direction: "from",
|
|
23389
|
+
});
|
|
23390
|
+
const fromToken = tokens.find((token) => token.chainId === swapParams.fromChainId &&
|
|
23391
|
+
token.address.toLowerCase() === fromTokenAddress?.toLowerCase());
|
|
23392
|
+
const toTokenAddress = getTokenAddressForSelection({
|
|
23393
|
+
tokens: isArcChain(swapParams.toChainId)
|
|
23394
|
+
? filterTokensForDestination({
|
|
23395
|
+
tokens,
|
|
23396
|
+
selectedDestinationChain: chains.find((chain) => chain.chainId === swapParams.toChainId),
|
|
23397
|
+
selectedSourceToken: fromToken,
|
|
23398
|
+
removeSourceToken: true,
|
|
23399
|
+
})
|
|
23400
|
+
: tokens,
|
|
23401
|
+
config,
|
|
23402
|
+
chainId: swapParams.toChainId,
|
|
23403
|
+
address: swapParams.toTokenAddress,
|
|
23404
|
+
direction: "to",
|
|
23405
|
+
excludeToken: {
|
|
23406
|
+
chainId: swapParams.fromChainId,
|
|
23407
|
+
address: fromTokenAddress,
|
|
23408
|
+
},
|
|
23409
|
+
});
|
|
23410
|
+
return { ...swapParams, fromTokenAddress, toTokenAddress };
|
|
23349
23411
|
};
|
|
23350
23412
|
/**
|
|
23351
23413
|
* When user changes something from the SwapView
|
|
@@ -23357,10 +23419,19 @@ const handleDestinationAddressOnSwapChange = ({ fromChainId, fromTokenAddress, t
|
|
|
23357
23419
|
* If only destination token is changed but source is not, and they were the same, then source token updates to something else
|
|
23358
23420
|
*
|
|
23359
23421
|
*/
|
|
23360
|
-
const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chains, config, queryClient, connectedSourceAddress, }) => {
|
|
23361
|
-
const
|
|
23422
|
+
const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute: storedSwapRoute, tokens, chains, config, queryClient, connectedSourceAddress, }) => {
|
|
23423
|
+
const initialSwapRoute = storedSwapRoute
|
|
23424
|
+
? {
|
|
23425
|
+
...storedSwapRoute,
|
|
23426
|
+
fromTokenAddress: normalizeArcTokenAddress(storedSwapRoute.fromChainId, storedSwapRoute.fromTokenAddress),
|
|
23427
|
+
toTokenAddress: normalizeArcTokenAddress(storedSwapRoute.toChainId, storedSwapRoute.toTokenAddress),
|
|
23428
|
+
}
|
|
23429
|
+
: undefined;
|
|
23430
|
+
const { fromChainId, toChainId, destinationAddress, fallbackAddress, depositRefundAddress, } = inputParams;
|
|
23362
23431
|
const srcChainId = fromChainId ?? initialSwapRoute?.fromChainId;
|
|
23363
23432
|
const destinationChainId = toChainId ?? initialSwapRoute?.toChainId;
|
|
23433
|
+
const fromTokenAddress = normalizeArcTokenAddress(srcChainId, inputParams.fromTokenAddress);
|
|
23434
|
+
const toTokenAddress = normalizeArcTokenAddress(destinationChainId, inputParams.toTokenAddress);
|
|
23364
23435
|
const defaultFromAddress = getInitialOrDefaultTokenAddressForChain({
|
|
23365
23436
|
tokens,
|
|
23366
23437
|
config,
|
|
@@ -23392,7 +23463,7 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
|
|
|
23392
23463
|
toTokenAddress === initialSwapRoute?.fromTokenAddress;
|
|
23393
23464
|
const sourceTokenAddress = sameNewDestAndInitialSource || onlySourceChainIdChanged
|
|
23394
23465
|
? defaultFromAddress
|
|
23395
|
-
: fromTokenAddress ?? initialSwapRoute?.fromTokenAddress;
|
|
23466
|
+
: (fromTokenAddress ?? initialSwapRoute?.fromTokenAddress);
|
|
23396
23467
|
let destinationTokenAddress = undefined;
|
|
23397
23468
|
if (!sameNewSourceAndInitialDest) {
|
|
23398
23469
|
if (onlySourceChainIdChanged) {
|
|
@@ -23436,15 +23507,20 @@ const getNewSwapParamsFromInput = ({ inputParams, initialSwapRoute, tokens, chai
|
|
|
23436
23507
|
const newDepositRefundAddress = sourceChainChanged
|
|
23437
23508
|
? undefined
|
|
23438
23509
|
: depositRefundAddress || initialSwapRoute?.depositRefundAddress;
|
|
23439
|
-
return {
|
|
23440
|
-
|
|
23441
|
-
|
|
23442
|
-
|
|
23443
|
-
|
|
23444
|
-
|
|
23445
|
-
|
|
23446
|
-
|
|
23447
|
-
|
|
23510
|
+
return normalizeSwapParamsForSelection({
|
|
23511
|
+
swapParams: {
|
|
23512
|
+
fromChainId: srcChainId,
|
|
23513
|
+
fromTokenAddress: sourceTokenAddress,
|
|
23514
|
+
toChainId: destinationChainId,
|
|
23515
|
+
toTokenAddress: destinationTokenAddress,
|
|
23516
|
+
destinationAddress: newDestinationAddress,
|
|
23517
|
+
fallbackAddress: newFallbackAddress,
|
|
23518
|
+
depositRefundAddress: newDepositRefundAddress,
|
|
23519
|
+
},
|
|
23520
|
+
tokens,
|
|
23521
|
+
chains,
|
|
23522
|
+
config,
|
|
23523
|
+
});
|
|
23448
23524
|
};
|
|
23449
23525
|
/* Sorts tokens based on the following order:
|
|
23450
23526
|
* 1. Native token on chain ID "1" (Ethereum) comes first.
|
|
@@ -23502,8 +23578,10 @@ const sortAllTokens = (tokenA, tokenB) => {
|
|
|
23502
23578
|
return 0;
|
|
23503
23579
|
};
|
|
23504
23580
|
const findToken = (tokens, chainId, address) => tokens.find((t) => t.chainId === chainId && t.address === address);
|
|
23505
|
-
const findNativeToken = (tokens, chain) => tokens.find((t) => t.
|
|
23506
|
-
|
|
23581
|
+
const findNativeToken = (tokens, chain) => tokens.find((t) => t.chainId === chain.chainId &&
|
|
23582
|
+
(isArcChain(chain.chainId)
|
|
23583
|
+
? isArcNativeToken(t)
|
|
23584
|
+
: t.symbol.toUpperCase() === chain.nativeCurrency.symbol.toUpperCase()));
|
|
23507
23585
|
const normalizeIbcAddress = (address) => {
|
|
23508
23586
|
if (!address.toLowerCase().startsWith("ibc/")) {
|
|
23509
23587
|
return address;
|
|
@@ -23573,9 +23651,7 @@ function selectGroupDefaultInfo(tokens) {
|
|
|
23573
23651
|
const groupTokensBySymbol = (tokens, chainType) => {
|
|
23574
23652
|
const groups = {};
|
|
23575
23653
|
// Filter tokens by chain type if specified
|
|
23576
|
-
const filteredTokens = chainType
|
|
23577
|
-
? tokens.filter((token) => token.type === chainType)
|
|
23578
|
-
: tokens;
|
|
23654
|
+
const filteredTokens = deduplicateArcBalances(chainType ? tokens.filter((token) => token.type === chainType) : tokens);
|
|
23579
23655
|
// First pass: group by coingeckoId or symbol
|
|
23580
23656
|
filteredTokens.forEach((token) => {
|
|
23581
23657
|
const groupKey = token.coingeckoId || token.symbol.split(".")[0];
|
|
@@ -23651,7 +23727,7 @@ const groupTokensBySymbol = (tokens, chainType) => {
|
|
|
23651
23727
|
*/
|
|
23652
23728
|
const groupTokensByChainId = (tokens, chains) => {
|
|
23653
23729
|
const groups = {};
|
|
23654
|
-
tokens.forEach((token) => {
|
|
23730
|
+
deduplicateArcBalances(tokens).forEach((token) => {
|
|
23655
23731
|
const chainData = chains.find((chain) => chain.chainId === token.chainId);
|
|
23656
23732
|
const groupKey = token.chainId;
|
|
23657
23733
|
if (!groups[groupKey]) {
|
|
@@ -23699,6 +23775,8 @@ const filterViewableTokens = (tokens, config, direction) => {
|
|
|
23699
23775
|
{ chainId: CHAIN_IDS.DCHAIN, address: nativeEvmTokenAddress },
|
|
23700
23776
|
];
|
|
23701
23777
|
return (tokens.filter((token) => {
|
|
23778
|
+
if (isArcNativeToken(token))
|
|
23779
|
+
return false;
|
|
23702
23780
|
if (direction) {
|
|
23703
23781
|
const parsedDirection = getParsedDirection(direction);
|
|
23704
23782
|
const availableTokensForDirection = config.availableTokens?.[parsedDirection];
|
|
@@ -23714,7 +23792,7 @@ const filterViewableTokens = (tokens, config, direction) => {
|
|
|
23714
23792
|
};
|
|
23715
23793
|
const getSecretNetworkBalances = async (chainData, cosmosAddress, squidTokens, keplrTypeWallet) => {
|
|
23716
23794
|
const squidSecretTokens = squidTokens.filter((t) => t.chainId === CHAIN_IDS.SECRET);
|
|
23717
|
-
const { fetchAllSecretBalances } = await import('./secretService-
|
|
23795
|
+
const { fetchAllSecretBalances } = await import('./secretService-DkE9yz1o.js');
|
|
23718
23796
|
return fetchAllSecretBalances(chainData, cosmosAddress, squidSecretTokens, keplrTypeWallet);
|
|
23719
23797
|
};
|
|
23720
23798
|
function getTokenAssetsKey(token) {
|
|
@@ -25295,8 +25373,7 @@ const searchTokens = (query, tokens, chains) => {
|
|
|
25295
25373
|
.filter((chain) => chain.nativeCurrency.symbol.toLowerCase() === query.toLowerCase() ||
|
|
25296
25374
|
chain.nativeCurrency.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
25297
25375
|
chain.networkName.toLowerCase().includes(query.toLowerCase()) ||
|
|
25298
|
-
|
|
25299
|
-
false))
|
|
25376
|
+
chain.axelarChainName.toLowerCase().includes(query.toLowerCase()))
|
|
25300
25377
|
.map((chain) => tokens.find((token) => token.chainId === chain.chainId &&
|
|
25301
25378
|
token.address.toLowerCase() === nativeEvmTokenAddress))
|
|
25302
25379
|
.filter((token) => token !== undefined);
|
|
@@ -25709,7 +25786,7 @@ const useSquidTokens = (direction) => {
|
|
|
25709
25786
|
config.availableChains,
|
|
25710
25787
|
direction,
|
|
25711
25788
|
]);
|
|
25712
|
-
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens,
|
|
25789
|
+
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useMemo(() => {
|
|
25713
25790
|
return tokens?.reduce((acc, token) => {
|
|
25714
25791
|
switch (token.type) {
|
|
25715
25792
|
case ChainType.EVM:
|
|
@@ -25736,9 +25813,6 @@ const useSquidTokens = (direction) => {
|
|
|
25736
25813
|
case ChainType.CANTON:
|
|
25737
25814
|
acc.cantonTokens.push(token);
|
|
25738
25815
|
break;
|
|
25739
|
-
case ChainType.DANAL:
|
|
25740
|
-
acc.danalTokens.push(token);
|
|
25741
|
-
break;
|
|
25742
25816
|
}
|
|
25743
25817
|
return acc;
|
|
25744
25818
|
}, {
|
|
@@ -25750,7 +25824,6 @@ const useSquidTokens = (direction) => {
|
|
|
25750
25824
|
xrplTokens: [],
|
|
25751
25825
|
stellarTokens: [],
|
|
25752
25826
|
cantonTokens: [],
|
|
25753
|
-
danalTokens: [],
|
|
25754
25827
|
});
|
|
25755
25828
|
}, [tokens]);
|
|
25756
25829
|
const findToken = useCallback((address, chainId) => {
|
|
@@ -25769,7 +25842,6 @@ const useSquidTokens = (direction) => {
|
|
|
25769
25842
|
xrplTokens,
|
|
25770
25843
|
stellarTokens,
|
|
25771
25844
|
cantonTokens,
|
|
25772
|
-
danalTokens,
|
|
25773
25845
|
};
|
|
25774
25846
|
};
|
|
25775
25847
|
|
|
@@ -26306,7 +26378,6 @@ const chainTypeToRefetchInterval = {
|
|
|
26306
26378
|
[ChainType.XRPL]: 1_000,
|
|
26307
26379
|
[ChainType.STELLAR]: 1_000,
|
|
26308
26380
|
[ChainType.CANTON]: 1_000,
|
|
26309
|
-
[ChainType.DANAL]: 1_000,
|
|
26310
26381
|
};
|
|
26311
26382
|
/**
|
|
26312
26383
|
* Returns the status refetch interval of a Send transaction
|
|
@@ -26573,7 +26644,7 @@ const useSquidChains = (direction) => {
|
|
|
26573
26644
|
const chain = findChain(chainId);
|
|
26574
26645
|
return chain?.chainType;
|
|
26575
26646
|
}, [findChain]);
|
|
26576
|
-
const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains, cantonChains,
|
|
26647
|
+
const { evmChains, cosmosChains, suiChains, stellarChains, xrplChains, cantonChains, } = useMemo(() => {
|
|
26577
26648
|
return chains.reduce((acc, chain) => {
|
|
26578
26649
|
switch (chain.chainType) {
|
|
26579
26650
|
case ChainType.EVM:
|
|
@@ -26594,9 +26665,6 @@ const useSquidChains = (direction) => {
|
|
|
26594
26665
|
case ChainType.CANTON:
|
|
26595
26666
|
acc.cantonChains.push(chain);
|
|
26596
26667
|
break;
|
|
26597
|
-
case ChainType.DANAL:
|
|
26598
|
-
acc.danalChains.push(chain);
|
|
26599
|
-
break;
|
|
26600
26668
|
}
|
|
26601
26669
|
return acc;
|
|
26602
26670
|
}, {
|
|
@@ -26606,7 +26674,6 @@ const useSquidChains = (direction) => {
|
|
|
26606
26674
|
xrplChains: [],
|
|
26607
26675
|
stellarChains: [],
|
|
26608
26676
|
cantonChains: [],
|
|
26609
|
-
danalChains: [],
|
|
26610
26677
|
});
|
|
26611
26678
|
}, [chains]);
|
|
26612
26679
|
const { supportedSourceChains, supportedDestinationChains } = useMemo(() => {
|
|
@@ -26628,7 +26695,6 @@ const useSquidChains = (direction) => {
|
|
|
26628
26695
|
xrplChains,
|
|
26629
26696
|
stellarChains,
|
|
26630
26697
|
cantonChains,
|
|
26631
|
-
danalChains,
|
|
26632
26698
|
getChainType,
|
|
26633
26699
|
findChain,
|
|
26634
26700
|
};
|
|
@@ -26942,7 +27008,343 @@ const useBitcoinContext = () => {
|
|
|
26942
27008
|
return context;
|
|
26943
27009
|
};
|
|
26944
27010
|
|
|
26945
|
-
const
|
|
27011
|
+
const vParty = (party) => ({ party });
|
|
27012
|
+
const vText = (text) => ({ text });
|
|
27013
|
+
const vNumeric = (numeric) => ({ numeric });
|
|
27014
|
+
const vContractId = (contractId) => ({
|
|
27015
|
+
contractId,
|
|
27016
|
+
});
|
|
27017
|
+
const vList = (elements) => ({
|
|
27018
|
+
list: { elements },
|
|
27019
|
+
});
|
|
27020
|
+
const vRecord = (fields) => ({
|
|
27021
|
+
record: { fields: fields.map(([label, value]) => ({ label, value })) },
|
|
27022
|
+
});
|
|
27023
|
+
const vTextMap = (entries) => ({ textMap: { entries } });
|
|
27024
|
+
const vTimestamp = (isoString) => ({
|
|
27025
|
+
timestamp: String(Math.floor(new Date(isoString).getTime() * 1000)),
|
|
27026
|
+
});
|
|
27027
|
+
function isRecord(value) {
|
|
27028
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27029
|
+
}
|
|
27030
|
+
function normalizeChoiceContextValue(value) {
|
|
27031
|
+
if (typeof value === "string")
|
|
27032
|
+
return value;
|
|
27033
|
+
if (!isRecord(value) || typeof value.tag !== "string")
|
|
27034
|
+
return null;
|
|
27035
|
+
switch (value.tag) {
|
|
27036
|
+
case "AV_Text":
|
|
27037
|
+
case "AV_ContractId":
|
|
27038
|
+
return typeof value.value === "string"
|
|
27039
|
+
? { tag: value.tag, value: value.value }
|
|
27040
|
+
: null;
|
|
27041
|
+
case "AV_Bool":
|
|
27042
|
+
return typeof value.value === "boolean"
|
|
27043
|
+
? { tag: value.tag, value: value.value }
|
|
27044
|
+
: null;
|
|
27045
|
+
case "AV_List":
|
|
27046
|
+
if (!Array.isArray(value.value))
|
|
27047
|
+
return null;
|
|
27048
|
+
return {
|
|
27049
|
+
tag: value.tag,
|
|
27050
|
+
value: value.value.flatMap((entry) => {
|
|
27051
|
+
const normalized = normalizeChoiceContextValue(entry);
|
|
27052
|
+
return normalized ? [normalized] : [];
|
|
27053
|
+
}),
|
|
27054
|
+
};
|
|
27055
|
+
default: {
|
|
27056
|
+
const inner = value.value;
|
|
27057
|
+
if (typeof inner === "string" ||
|
|
27058
|
+
typeof inner === "number" ||
|
|
27059
|
+
typeof inner === "boolean" ||
|
|
27060
|
+
inner === null) {
|
|
27061
|
+
return { tag: value.tag, value: inner };
|
|
27062
|
+
}
|
|
27063
|
+
if (Array.isArray(inner)) {
|
|
27064
|
+
return {
|
|
27065
|
+
tag: value.tag,
|
|
27066
|
+
value: inner.flatMap((entry) => {
|
|
27067
|
+
const normalized = normalizeChoiceContextValue(entry);
|
|
27068
|
+
return normalized ? [normalized] : [];
|
|
27069
|
+
}),
|
|
27070
|
+
};
|
|
27071
|
+
}
|
|
27072
|
+
if (!isRecord(inner))
|
|
27073
|
+
return null;
|
|
27074
|
+
const normalizedObject = {};
|
|
27075
|
+
for (const [key, entry] of Object.entries(inner)) {
|
|
27076
|
+
if (typeof entry !== "string" &&
|
|
27077
|
+
typeof entry !== "number" &&
|
|
27078
|
+
typeof entry !== "boolean" &&
|
|
27079
|
+
entry !== null) {
|
|
27080
|
+
return null;
|
|
27081
|
+
}
|
|
27082
|
+
normalizedObject[key] = entry;
|
|
27083
|
+
}
|
|
27084
|
+
return { tag: value.tag, value: normalizedObject };
|
|
27085
|
+
}
|
|
27086
|
+
}
|
|
27087
|
+
}
|
|
27088
|
+
function stringifyChoiceContextValue(value) {
|
|
27089
|
+
return typeof value === "string" ? value : String(value);
|
|
27090
|
+
}
|
|
27091
|
+
function choiceContextValueToAnyValue(value) {
|
|
27092
|
+
if (typeof value === "string") {
|
|
27093
|
+
return {
|
|
27094
|
+
variant: { constructor: "AV_Text", value: vText(value) },
|
|
27095
|
+
};
|
|
27096
|
+
}
|
|
27097
|
+
switch (value.tag) {
|
|
27098
|
+
case "AV_ContractId":
|
|
27099
|
+
if (typeof value.value !== "string") {
|
|
27100
|
+
throw new TypeError("AV_ContractId values must be strings");
|
|
27101
|
+
}
|
|
27102
|
+
return {
|
|
27103
|
+
variant: { constructor: value.tag, value: vContractId(value.value) },
|
|
27104
|
+
};
|
|
27105
|
+
case "AV_Bool":
|
|
27106
|
+
if (typeof value.value !== "boolean") {
|
|
27107
|
+
throw new TypeError("AV_Bool values must be booleans");
|
|
27108
|
+
}
|
|
27109
|
+
return {
|
|
27110
|
+
variant: { constructor: value.tag, value: { bool: value.value } },
|
|
27111
|
+
};
|
|
27112
|
+
case "AV_List":
|
|
27113
|
+
if (!Array.isArray(value.value)) {
|
|
27114
|
+
throw new TypeError("AV_List values must be arrays");
|
|
27115
|
+
}
|
|
27116
|
+
return {
|
|
27117
|
+
variant: {
|
|
27118
|
+
constructor: value.tag,
|
|
27119
|
+
value: vList(value.value.map(choiceContextValueToAnyValue)),
|
|
27120
|
+
},
|
|
27121
|
+
};
|
|
27122
|
+
default:
|
|
27123
|
+
return {
|
|
27124
|
+
variant: {
|
|
27125
|
+
constructor: value.tag,
|
|
27126
|
+
value: vText(stringifyChoiceContextValue(value.value)),
|
|
27127
|
+
},
|
|
27128
|
+
};
|
|
27129
|
+
}
|
|
27130
|
+
}
|
|
27131
|
+
|
|
27132
|
+
/** Metadata key used by Splice token-standard transfers to carry our Squid orderhash memo. */
|
|
27133
|
+
const CANTON_MEMO_KEY = "splice.lfdecentralizedtrust.org/reason";
|
|
27134
|
+
/** Interface id for the transfer factory contract returned by the token registry. */
|
|
27135
|
+
const TRANSFER_FACTORY_INTERFACE_ID = "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory";
|
|
27136
|
+
/** Choice exercised on the transfer factory to create the token-standard transfer. */
|
|
27137
|
+
const TRANSFER_FACTORY_CHOICE = "TransferFactory_Transfer";
|
|
27138
|
+
/** CIP-056 (non-Amulet) tokens expose a registrar parameterized by admin party. */
|
|
27139
|
+
const CIP056_REGISTRAR_BASE = "https://api.utilities.digitalasset.com/api/token-standard/v0/registrars";
|
|
27140
|
+
const TRANSFER_REQUESTED_AT_SKEW_MS = 60_000;
|
|
27141
|
+
const TRANSFER_EXECUTE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
27142
|
+
function resolveCantonRegistryUrl(instrument) {
|
|
27143
|
+
if (instrument.id === CANTON_AMULET_INSTRUMENT_ID) {
|
|
27144
|
+
return CANTON_AMULET_REGISTRY_URL;
|
|
27145
|
+
}
|
|
27146
|
+
return `${CIP056_REGISTRAR_BASE}/${encodeURIComponent(instrument.admin)}`;
|
|
27147
|
+
}
|
|
27148
|
+
/**
|
|
27149
|
+
* Build the plain JSON arguments expected by the registry transfer-factory
|
|
27150
|
+
* endpoint before it adds choice context and disclosed contracts.
|
|
27151
|
+
*/
|
|
27152
|
+
function buildTransferChoiceArgs({ sender, receiver, amount, instrument, inputHoldingCids, memo, nowMs, }) {
|
|
27153
|
+
return {
|
|
27154
|
+
expectedAdmin: instrument.admin,
|
|
27155
|
+
transfer: {
|
|
27156
|
+
sender,
|
|
27157
|
+
receiver,
|
|
27158
|
+
amount,
|
|
27159
|
+
instrumentId: { admin: instrument.admin, id: instrument.id },
|
|
27160
|
+
requestedAt: new Date(nowMs - TRANSFER_REQUESTED_AT_SKEW_MS).toISOString(),
|
|
27161
|
+
executeBefore: new Date(nowMs + TRANSFER_EXECUTE_WINDOW_MS).toISOString(),
|
|
27162
|
+
inputHoldingCids,
|
|
27163
|
+
meta: { values: { [CANTON_MEMO_KEY]: memo } },
|
|
27164
|
+
},
|
|
27165
|
+
extraArgs: { context: { values: {} }, meta: { values: {} } },
|
|
27166
|
+
};
|
|
27167
|
+
}
|
|
27168
|
+
/**
|
|
27169
|
+
* Canton's Holding contracts follow Bitcoin-style UTXOs model.
|
|
27170
|
+
*
|
|
27171
|
+
* Pick Holding contract ids covering `amount` for the instrument: prefer a
|
|
27172
|
+
* single exact-amount holding, else accumulate largest-first.
|
|
27173
|
+
*/
|
|
27174
|
+
function selectInputHoldingCids(holdings, instrument, amount) {
|
|
27175
|
+
const spendableHoldings = holdings.filter((h) => !h.locked &&
|
|
27176
|
+
h.instrument.admin === instrument.admin &&
|
|
27177
|
+
h.instrument.id === instrument.id);
|
|
27178
|
+
const target = new BigNumber(amount);
|
|
27179
|
+
const exact = spendableHoldings.find((h) => new BigNumber(h.amount).eq(target));
|
|
27180
|
+
if (exact)
|
|
27181
|
+
return [exact.contractId];
|
|
27182
|
+
const sorted = [...spendableHoldings].sort((a, b) => new BigNumber(b.amount).comparedTo(new BigNumber(a.amount)));
|
|
27183
|
+
const selected = [];
|
|
27184
|
+
let sum = new BigNumber(0);
|
|
27185
|
+
for (const holding of sorted) {
|
|
27186
|
+
selected.push(holding.contractId);
|
|
27187
|
+
sum = sum.plus(holding.amount);
|
|
27188
|
+
if (sum.gte(target))
|
|
27189
|
+
break;
|
|
27190
|
+
}
|
|
27191
|
+
if (sum.lt(target)) {
|
|
27192
|
+
throw new Error("Insufficient Canton holdings to cover transfer amount");
|
|
27193
|
+
}
|
|
27194
|
+
return selected;
|
|
27195
|
+
}
|
|
27196
|
+
async function fetchInputHoldingCids(connector, party, instrument, amount) {
|
|
27197
|
+
const ledgerEnd = await connector.ledgerApi({
|
|
27198
|
+
requestMethod: "get",
|
|
27199
|
+
resource: "/v2/state/ledger-end",
|
|
27200
|
+
});
|
|
27201
|
+
const activeContracts = await connector.ledgerApi({
|
|
27202
|
+
requestMethod: "post",
|
|
27203
|
+
resource: "/v2/state/active-contracts",
|
|
27204
|
+
body: buildHoldingsAcsRequestBody(party, String(ledgerEnd.offset)),
|
|
27205
|
+
});
|
|
27206
|
+
return selectInputHoldingCids(parseCantonHoldings(activeContracts), instrument, amount);
|
|
27207
|
+
}
|
|
27208
|
+
/**
|
|
27209
|
+
* Ask the token registry for the transfer factory contract and extra context
|
|
27210
|
+
* required to exercise its transfer choice.
|
|
27211
|
+
*/
|
|
27212
|
+
async function fetchTransferFactory(registryUrl, choiceArgs) {
|
|
27213
|
+
const response = await fetch(`${registryUrl}/registry/transfer-instruction/v1/transfer-factory`, {
|
|
27214
|
+
method: "POST",
|
|
27215
|
+
headers: { "Content-Type": "application/json" },
|
|
27216
|
+
body: JSON.stringify({
|
|
27217
|
+
choiceArguments: choiceArgs,
|
|
27218
|
+
excludeDebugFields: true,
|
|
27219
|
+
}),
|
|
27220
|
+
});
|
|
27221
|
+
if (!response.ok) {
|
|
27222
|
+
throw new Error(`Canton transfer-factory request failed (${response.status})`);
|
|
27223
|
+
}
|
|
27224
|
+
return response.json();
|
|
27225
|
+
}
|
|
27226
|
+
/**
|
|
27227
|
+
* Convert transfer choice args into strict Daml Value JSON for the wallet's
|
|
27228
|
+
* prepareExecute ExerciseCommand.
|
|
27229
|
+
*/
|
|
27230
|
+
function buildPrepareChoiceArgument(choiceArgs) {
|
|
27231
|
+
const contextValues = Object.entries(choiceArgs.extraArgs.context?.values ?? {})
|
|
27232
|
+
.map(([key, value]) => {
|
|
27233
|
+
const normalized = normalizeChoiceContextValue(value);
|
|
27234
|
+
return normalized
|
|
27235
|
+
? { key, value: choiceContextValueToAnyValue(normalized) }
|
|
27236
|
+
: undefined;
|
|
27237
|
+
})
|
|
27238
|
+
.filter((entry) => Boolean(entry));
|
|
27239
|
+
return vRecord([
|
|
27240
|
+
["expectedAdmin", vParty(choiceArgs.expectedAdmin)],
|
|
27241
|
+
[
|
|
27242
|
+
"transfer",
|
|
27243
|
+
vRecord([
|
|
27244
|
+
["sender", vParty(choiceArgs.transfer.sender)],
|
|
27245
|
+
["receiver", vParty(choiceArgs.transfer.receiver)],
|
|
27246
|
+
["amount", vNumeric(choiceArgs.transfer.amount)],
|
|
27247
|
+
[
|
|
27248
|
+
"instrumentId",
|
|
27249
|
+
vRecord([
|
|
27250
|
+
["admin", vParty(choiceArgs.transfer.instrumentId.admin)],
|
|
27251
|
+
["id", vText(choiceArgs.transfer.instrumentId.id)],
|
|
27252
|
+
]),
|
|
27253
|
+
],
|
|
27254
|
+
["requestedAt", vTimestamp(choiceArgs.transfer.requestedAt)],
|
|
27255
|
+
["executeBefore", vTimestamp(choiceArgs.transfer.executeBefore)],
|
|
27256
|
+
[
|
|
27257
|
+
"inputHoldingCids",
|
|
27258
|
+
vList(choiceArgs.transfer.inputHoldingCids.map(vContractId)),
|
|
27259
|
+
],
|
|
27260
|
+
[
|
|
27261
|
+
"meta",
|
|
27262
|
+
vRecord([
|
|
27263
|
+
[
|
|
27264
|
+
"values",
|
|
27265
|
+
vTextMap(Object.entries(choiceArgs.transfer.meta.values).map(([key, value]) => ({ key, value: vText(value) }))),
|
|
27266
|
+
],
|
|
27267
|
+
]),
|
|
27268
|
+
],
|
|
27269
|
+
]),
|
|
27270
|
+
],
|
|
27271
|
+
[
|
|
27272
|
+
"extraArgs",
|
|
27273
|
+
vRecord([
|
|
27274
|
+
["context", vRecord([["values", vTextMap(contextValues)]])],
|
|
27275
|
+
["meta", vRecord([["values", vTextMap([])]])],
|
|
27276
|
+
]),
|
|
27277
|
+
],
|
|
27278
|
+
]);
|
|
27279
|
+
}
|
|
27280
|
+
/**
|
|
27281
|
+
* Convert a registry disclosed contract into the wallet submission shape,
|
|
27282
|
+
* dropping debug fields and entries without a usable createdEventBlob.
|
|
27283
|
+
*/
|
|
27284
|
+
function toDisclosedContract(raw) {
|
|
27285
|
+
if (typeof raw.createdEventBlob !== "string")
|
|
27286
|
+
return null;
|
|
27287
|
+
return {
|
|
27288
|
+
createdEventBlob: raw.createdEventBlob,
|
|
27289
|
+
contractId: typeof raw.contractId === "string" ? raw.contractId : undefined,
|
|
27290
|
+
synchronizerId: typeof raw.synchronizerId === "string" ? raw.synchronizerId : undefined,
|
|
27291
|
+
};
|
|
27292
|
+
}
|
|
27293
|
+
/**
|
|
27294
|
+
* Build a Splice token-standard transfer of `amount` of `token` from `sender`
|
|
27295
|
+
* to `receiver`, carrying `memo`, ready to hand to a wallet's prepareExecute.
|
|
27296
|
+
* Returns the full prepareExecute params (commandId + commands + actAs +
|
|
27297
|
+
* disclosedContracts).
|
|
27298
|
+
*/
|
|
27299
|
+
async function buildCantonTransfer(connector, { sender, receiver, amount, token, memo, nowMs, }) {
|
|
27300
|
+
if (!token.originalAddress) {
|
|
27301
|
+
throw new Error("Canton token originalAddress is required");
|
|
27302
|
+
}
|
|
27303
|
+
const instrument = parseCantonInstrument(token.originalAddress);
|
|
27304
|
+
if (!instrument) {
|
|
27305
|
+
throw new Error(`Invalid Canton token address: ${token.originalAddress}`);
|
|
27306
|
+
}
|
|
27307
|
+
const registryUrl = resolveCantonRegistryUrl(instrument);
|
|
27308
|
+
const inputHoldingCids = await fetchInputHoldingCids(connector, sender, instrument, amount);
|
|
27309
|
+
const choiceArgs = buildTransferChoiceArgs({
|
|
27310
|
+
sender,
|
|
27311
|
+
receiver,
|
|
27312
|
+
amount,
|
|
27313
|
+
instrument,
|
|
27314
|
+
inputHoldingCids,
|
|
27315
|
+
memo,
|
|
27316
|
+
nowMs,
|
|
27317
|
+
});
|
|
27318
|
+
const factory = await fetchTransferFactory(registryUrl, choiceArgs);
|
|
27319
|
+
const choiceContextData = factory.choiceContext.choiceContextData;
|
|
27320
|
+
if (!choiceContextData) {
|
|
27321
|
+
throw new Error("Transfer factory choice context is missing");
|
|
27322
|
+
}
|
|
27323
|
+
choiceArgs.extraArgs.context = choiceContextData;
|
|
27324
|
+
const disclosedContracts = (factory.choiceContext?.disclosedContracts ?? []).flatMap((raw) => {
|
|
27325
|
+
const disclosedContract = toDisclosedContract(raw);
|
|
27326
|
+
return disclosedContract ? [disclosedContract] : [];
|
|
27327
|
+
});
|
|
27328
|
+
// Command ID: client-supplied identifier used to deduplicate submissions
|
|
27329
|
+
const commandId = getCantonCommandId(memo);
|
|
27330
|
+
return {
|
|
27331
|
+
commandId,
|
|
27332
|
+
commands: [
|
|
27333
|
+
{
|
|
27334
|
+
ExerciseCommand: {
|
|
27335
|
+
templateId: TRANSFER_FACTORY_INTERFACE_ID,
|
|
27336
|
+
contractId: factory.factoryId,
|
|
27337
|
+
choice: TRANSFER_FACTORY_CHOICE,
|
|
27338
|
+
choiceArgument: buildPrepareChoiceArgument(choiceArgs),
|
|
27339
|
+
},
|
|
27340
|
+
},
|
|
27341
|
+
],
|
|
27342
|
+
actAs: [sender],
|
|
27343
|
+
disclosedContracts,
|
|
27344
|
+
};
|
|
27345
|
+
}
|
|
27346
|
+
|
|
27347
|
+
const REQUEST_TIMEOUT_MS$1 = 60_000;
|
|
26946
27348
|
function pickAddress(accounts) {
|
|
26947
27349
|
return (accounts.find((a) => a.primary) ?? accounts[0])?.partyId;
|
|
26948
27350
|
}
|
|
@@ -26951,6 +27353,7 @@ function pickAddress(accounts) {
|
|
|
26951
27353
|
* (bound to its announce `target`) and exposes the lifecycle methods.
|
|
26952
27354
|
*/
|
|
26953
27355
|
class CantonBrowserConnector {
|
|
27356
|
+
kind = "cip103";
|
|
26954
27357
|
providerId;
|
|
26955
27358
|
name;
|
|
26956
27359
|
target;
|
|
@@ -26965,7 +27368,7 @@ class CantonBrowserConnector {
|
|
|
26965
27368
|
client ??
|
|
26966
27369
|
createCantonClient(new WindowTransport(win, {
|
|
26967
27370
|
target: this.target,
|
|
26968
|
-
timeout: REQUEST_TIMEOUT_MS,
|
|
27371
|
+
timeout: REQUEST_TIMEOUT_MS$1,
|
|
26969
27372
|
}));
|
|
26970
27373
|
}
|
|
26971
27374
|
get accounts() {
|
|
@@ -27011,6 +27414,28 @@ class CantonBrowserConnector {
|
|
|
27011
27414
|
this._accounts = await this.client.listAccounts();
|
|
27012
27415
|
return this._accounts;
|
|
27013
27416
|
}
|
|
27417
|
+
async getBalances(partyId) {
|
|
27418
|
+
const { offset } = await this.ledgerApi({
|
|
27419
|
+
requestMethod: "get",
|
|
27420
|
+
resource: "/v2/state/ledger-end",
|
|
27421
|
+
});
|
|
27422
|
+
const contracts = await this.ledgerApi({
|
|
27423
|
+
requestMethod: "post",
|
|
27424
|
+
resource: "/v2/state/active-contracts",
|
|
27425
|
+
body: buildHoldingsAcsRequestBody(partyId, String(offset)),
|
|
27426
|
+
});
|
|
27427
|
+
return groupCantonHoldingBalances(contracts);
|
|
27428
|
+
}
|
|
27429
|
+
async transfer(params) {
|
|
27430
|
+
const payload = await buildCantonTransfer(this, params);
|
|
27431
|
+
const result = await this.prepareExecuteAndWait(payload);
|
|
27432
|
+
const updateId = result.tx?.payload?.updateId ?? "";
|
|
27433
|
+
return {
|
|
27434
|
+
status: "completed",
|
|
27435
|
+
commandId: getCantonCommandId(params.memo),
|
|
27436
|
+
updateId,
|
|
27437
|
+
};
|
|
27438
|
+
}
|
|
27014
27439
|
on(event, handler) {
|
|
27015
27440
|
this.listeners[event].add(handler);
|
|
27016
27441
|
}
|
|
@@ -27117,6 +27542,313 @@ function discoverInjectedCantonWallets(win) {
|
|
|
27117
27542
|
});
|
|
27118
27543
|
}
|
|
27119
27544
|
|
|
27545
|
+
class CantonConnectionCancelledError extends Error {
|
|
27546
|
+
code = 4001;
|
|
27547
|
+
constructor() {
|
|
27548
|
+
super("Wallet connection cancelled");
|
|
27549
|
+
}
|
|
27550
|
+
}
|
|
27551
|
+
|
|
27552
|
+
const REQUEST_TIMEOUT_MS = 5 * 60_000;
|
|
27553
|
+
const OVERLAY_ID = "loop-sdk-connect-overlay";
|
|
27554
|
+
class LoopSubmissionUnknownError extends Error {
|
|
27555
|
+
constructor(cause) {
|
|
27556
|
+
super("Loop transfer outcome is unknown. Check Loop before trying again.", {
|
|
27557
|
+
cause,
|
|
27558
|
+
});
|
|
27559
|
+
}
|
|
27560
|
+
}
|
|
27561
|
+
function parseLoopTransferUpdate(value, commandId) {
|
|
27562
|
+
if (!value || typeof value !== "object")
|
|
27563
|
+
return undefined;
|
|
27564
|
+
const response = value;
|
|
27565
|
+
if (response.command_id !== commandId)
|
|
27566
|
+
return undefined;
|
|
27567
|
+
if (response.status === "failed" || response.error) {
|
|
27568
|
+
const error = response.error;
|
|
27569
|
+
return {
|
|
27570
|
+
status: "failed",
|
|
27571
|
+
commandId,
|
|
27572
|
+
message: typeof error?.error_message === "string"
|
|
27573
|
+
? error.error_message
|
|
27574
|
+
: "Loop transaction failed",
|
|
27575
|
+
};
|
|
27576
|
+
}
|
|
27577
|
+
if (typeof response.update_id === "string" && response.update_id) {
|
|
27578
|
+
return { status: "completed", commandId, updateId: response.update_id };
|
|
27579
|
+
}
|
|
27580
|
+
return undefined;
|
|
27581
|
+
}
|
|
27582
|
+
class LoopCantonConnector {
|
|
27583
|
+
loadSdk;
|
|
27584
|
+
kind = "loop";
|
|
27585
|
+
providerId = "canton-loop";
|
|
27586
|
+
name = "Loop";
|
|
27587
|
+
target = undefined;
|
|
27588
|
+
module;
|
|
27589
|
+
initialization;
|
|
27590
|
+
provider;
|
|
27591
|
+
pendingConnection;
|
|
27592
|
+
connectionStart = Promise.resolve();
|
|
27593
|
+
transfers = new Map();
|
|
27594
|
+
listeners = { connect: new Set(), disconnect: new Set() };
|
|
27595
|
+
constructor(loadSdk = () => import('@fivenorth/loop-sdk')) {
|
|
27596
|
+
this.loadSdk = loadSdk;
|
|
27597
|
+
}
|
|
27598
|
+
get accounts() {
|
|
27599
|
+
return this.provider
|
|
27600
|
+
? [{ partyId: this.provider.party_id, primary: true }]
|
|
27601
|
+
: [];
|
|
27602
|
+
}
|
|
27603
|
+
get address() {
|
|
27604
|
+
return this.provider?.party_id;
|
|
27605
|
+
}
|
|
27606
|
+
connect() {
|
|
27607
|
+
return this.startConnection(true);
|
|
27608
|
+
}
|
|
27609
|
+
autoConnect() {
|
|
27610
|
+
return this.startConnection(false);
|
|
27611
|
+
}
|
|
27612
|
+
cancelConnect() {
|
|
27613
|
+
if (!this.pendingConnection)
|
|
27614
|
+
return;
|
|
27615
|
+
this.rejectConnection(new CantonConnectionCancelledError());
|
|
27616
|
+
this.module?.loop.logout();
|
|
27617
|
+
}
|
|
27618
|
+
async disconnect() {
|
|
27619
|
+
this.cancelConnect();
|
|
27620
|
+
this.module?.loop.logout();
|
|
27621
|
+
this.provider = undefined;
|
|
27622
|
+
this.emit("disconnect");
|
|
27623
|
+
}
|
|
27624
|
+
async getAccounts() {
|
|
27625
|
+
const provider = this.requireProvider();
|
|
27626
|
+
try {
|
|
27627
|
+
const account = await provider.getAccount();
|
|
27628
|
+
if (account.party_id !== provider.party_id) {
|
|
27629
|
+
await this.disconnect();
|
|
27630
|
+
throw new Error("Loop account changed. Connect again.");
|
|
27631
|
+
}
|
|
27632
|
+
return this.accounts;
|
|
27633
|
+
}
|
|
27634
|
+
catch (error) {
|
|
27635
|
+
if (this.module && error instanceof this.module.UnauthorizedError) {
|
|
27636
|
+
await this.disconnect();
|
|
27637
|
+
}
|
|
27638
|
+
throw error;
|
|
27639
|
+
}
|
|
27640
|
+
}
|
|
27641
|
+
async getBalances(partyId) {
|
|
27642
|
+
const provider = this.requireProvider();
|
|
27643
|
+
if (partyId !== provider.party_id) {
|
|
27644
|
+
throw new Error("Loop balances require the connected account");
|
|
27645
|
+
}
|
|
27646
|
+
const holdings = await provider.getHolding();
|
|
27647
|
+
return sumCantonHoldingBalances(holdings.map((holding) => {
|
|
27648
|
+
const amount = new BigNumber(holding.total_unlocked_coin);
|
|
27649
|
+
if (!amount.isFinite() || amount.isNegative()) {
|
|
27650
|
+
throw new Error("Loop returned an invalid balance");
|
|
27651
|
+
}
|
|
27652
|
+
return {
|
|
27653
|
+
instrument: holding.instrument_id,
|
|
27654
|
+
amount: holding.total_unlocked_coin,
|
|
27655
|
+
};
|
|
27656
|
+
}));
|
|
27657
|
+
}
|
|
27658
|
+
transfer(params) {
|
|
27659
|
+
const commandId = getCantonCommandId(params.memo);
|
|
27660
|
+
const existing = this.transfers.get(commandId);
|
|
27661
|
+
if (existing)
|
|
27662
|
+
return existing;
|
|
27663
|
+
const request = this.submitTransfer(params, commandId).catch((error) => {
|
|
27664
|
+
if (!(error instanceof LoopSubmissionUnknownError))
|
|
27665
|
+
this.transfers.delete(commandId);
|
|
27666
|
+
throw error;
|
|
27667
|
+
});
|
|
27668
|
+
this.transfers.set(commandId, request);
|
|
27669
|
+
return request;
|
|
27670
|
+
}
|
|
27671
|
+
on(event, handler) {
|
|
27672
|
+
this.listeners[event].add(handler);
|
|
27673
|
+
}
|
|
27674
|
+
off(event, handler) {
|
|
27675
|
+
this.listeners[event].delete(handler);
|
|
27676
|
+
}
|
|
27677
|
+
emit(event, ...args) {
|
|
27678
|
+
this.listeners[event].forEach((handler) => handler(...args));
|
|
27679
|
+
}
|
|
27680
|
+
initialize() {
|
|
27681
|
+
if (!this.initialization) {
|
|
27682
|
+
this.initialization = this.loadSdk()
|
|
27683
|
+
.then((module) => {
|
|
27684
|
+
module.loop.init({
|
|
27685
|
+
appName: SQUID_METADATA.name,
|
|
27686
|
+
network: "mainnet",
|
|
27687
|
+
onAccept: (provider) => this.acceptConnection(provider),
|
|
27688
|
+
onReject: () => {
|
|
27689
|
+
this.rejectConnection(new CantonConnectionCancelledError());
|
|
27690
|
+
this.provider = undefined;
|
|
27691
|
+
this.emit("disconnect");
|
|
27692
|
+
},
|
|
27693
|
+
});
|
|
27694
|
+
this.module = module;
|
|
27695
|
+
})
|
|
27696
|
+
.catch((error) => {
|
|
27697
|
+
this.initialization = undefined;
|
|
27698
|
+
throw error;
|
|
27699
|
+
});
|
|
27700
|
+
}
|
|
27701
|
+
return this.initialization;
|
|
27702
|
+
}
|
|
27703
|
+
startConnection(interactive) {
|
|
27704
|
+
if (this.pendingConnection)
|
|
27705
|
+
return this.pendingConnection.promise;
|
|
27706
|
+
let resolve;
|
|
27707
|
+
let reject;
|
|
27708
|
+
const promise = new Promise((accept, decline) => {
|
|
27709
|
+
resolve = accept;
|
|
27710
|
+
reject = decline;
|
|
27711
|
+
});
|
|
27712
|
+
const timer = setTimeout(() => {
|
|
27713
|
+
this.rejectConnection(new Error("Loop connection timed out"));
|
|
27714
|
+
this.module?.loop.logout();
|
|
27715
|
+
}, REQUEST_TIMEOUT_MS);
|
|
27716
|
+
let observer;
|
|
27717
|
+
const pending = {
|
|
27718
|
+
promise,
|
|
27719
|
+
resolve,
|
|
27720
|
+
reject,
|
|
27721
|
+
cleanup: () => {
|
|
27722
|
+
clearTimeout(timer);
|
|
27723
|
+
observer?.disconnect();
|
|
27724
|
+
},
|
|
27725
|
+
};
|
|
27726
|
+
this.pendingConnection = pending;
|
|
27727
|
+
this.connectionStart = this.connectionStart
|
|
27728
|
+
.then(async () => {
|
|
27729
|
+
await this.initialize();
|
|
27730
|
+
if (this.pendingConnection !== pending)
|
|
27731
|
+
return;
|
|
27732
|
+
if (interactive && typeof MutationObserver !== "undefined") {
|
|
27733
|
+
let sawOverlay = false;
|
|
27734
|
+
observer = new MutationObserver(() => {
|
|
27735
|
+
const overlay = document.getElementById(OVERLAY_ID);
|
|
27736
|
+
if (overlay)
|
|
27737
|
+
sawOverlay = true;
|
|
27738
|
+
if (sawOverlay && !overlay && this.pendingConnection === pending) {
|
|
27739
|
+
this.cancelConnect();
|
|
27740
|
+
}
|
|
27741
|
+
});
|
|
27742
|
+
observer.observe(document.body, { childList: true });
|
|
27743
|
+
}
|
|
27744
|
+
const sdk = this.module.loop;
|
|
27745
|
+
if (interactive)
|
|
27746
|
+
await sdk.connect();
|
|
27747
|
+
else
|
|
27748
|
+
await sdk.autoConnect();
|
|
27749
|
+
if (!interactive && this.pendingConnection === pending) {
|
|
27750
|
+
this.rejectConnection(new Error("No saved Loop connection"));
|
|
27751
|
+
}
|
|
27752
|
+
else if (interactive &&
|
|
27753
|
+
this.pendingConnection !== pending &&
|
|
27754
|
+
!this.provider) {
|
|
27755
|
+
sdk.logout();
|
|
27756
|
+
}
|
|
27757
|
+
})
|
|
27758
|
+
.catch((error) => {
|
|
27759
|
+
if (this.pendingConnection === pending)
|
|
27760
|
+
this.rejectConnection(error);
|
|
27761
|
+
});
|
|
27762
|
+
return promise;
|
|
27763
|
+
}
|
|
27764
|
+
acceptConnection(provider) {
|
|
27765
|
+
const pending = this.pendingConnection;
|
|
27766
|
+
if (!pending)
|
|
27767
|
+
return;
|
|
27768
|
+
if (!provider.party_id) {
|
|
27769
|
+
this.rejectConnection(new Error("Loop returned no account"));
|
|
27770
|
+
return;
|
|
27771
|
+
}
|
|
27772
|
+
this.provider = provider;
|
|
27773
|
+
this.pendingConnection = undefined;
|
|
27774
|
+
pending.cleanup();
|
|
27775
|
+
pending.resolve({ address: provider.party_id, accounts: this.accounts });
|
|
27776
|
+
this.emit("connect", provider.party_id);
|
|
27777
|
+
}
|
|
27778
|
+
rejectConnection(error) {
|
|
27779
|
+
const pending = this.pendingConnection;
|
|
27780
|
+
if (!pending)
|
|
27781
|
+
return;
|
|
27782
|
+
this.pendingConnection = undefined;
|
|
27783
|
+
pending.cleanup();
|
|
27784
|
+
pending.reject(error);
|
|
27785
|
+
}
|
|
27786
|
+
requireProvider() {
|
|
27787
|
+
if (!this.provider)
|
|
27788
|
+
throw new Error("Loop wallet is not connected");
|
|
27789
|
+
return this.provider;
|
|
27790
|
+
}
|
|
27791
|
+
async submitTransfer(params, commandId) {
|
|
27792
|
+
const provider = this.requireProvider();
|
|
27793
|
+
if (params.sender !== provider.party_id)
|
|
27794
|
+
throw new Error("Loop account does not match the sender");
|
|
27795
|
+
const instrument = params.token.originalAddress
|
|
27796
|
+
? parseCantonInstrument(params.token.originalAddress)
|
|
27797
|
+
: null;
|
|
27798
|
+
if (!instrument)
|
|
27799
|
+
throw new Error("Canton token originalAddress is required");
|
|
27800
|
+
if (!new BigNumber(params.amount).isFinite() ||
|
|
27801
|
+
!new BigNumber(params.amount).isPositive()) {
|
|
27802
|
+
throw new Error("Canton transfer amount must be positive");
|
|
27803
|
+
}
|
|
27804
|
+
const payload = await provider.connection.prepareTransfer(provider.getAuthToken(), {
|
|
27805
|
+
recipient: params.receiver,
|
|
27806
|
+
amount: params.amount,
|
|
27807
|
+
instrument: {
|
|
27808
|
+
instrument_admin: instrument.admin,
|
|
27809
|
+
instrument_id: instrument.id,
|
|
27810
|
+
},
|
|
27811
|
+
memo: params.memo,
|
|
27812
|
+
requested_at: new Date(params.nowMs - 60_000).toISOString(),
|
|
27813
|
+
execute_before: new Date(params.nowMs + 24 * 60 * 60_000).toISOString(),
|
|
27814
|
+
});
|
|
27815
|
+
if (this.provider !== provider)
|
|
27816
|
+
throw new Error("Loop account disconnected before submission");
|
|
27817
|
+
let response;
|
|
27818
|
+
let timer;
|
|
27819
|
+
try {
|
|
27820
|
+
const submission = { ...payload, commandId };
|
|
27821
|
+
const submitted = provider.submitAndWaitForTransaction(submission, {
|
|
27822
|
+
requestTimeout: REQUEST_TIMEOUT_MS,
|
|
27823
|
+
});
|
|
27824
|
+
response = await Promise.race([
|
|
27825
|
+
submitted,
|
|
27826
|
+
new Promise((_, reject) => {
|
|
27827
|
+
timer = setTimeout(() => reject(new Error("Loop submission timed out")), REQUEST_TIMEOUT_MS);
|
|
27828
|
+
}),
|
|
27829
|
+
]);
|
|
27830
|
+
}
|
|
27831
|
+
catch (error) {
|
|
27832
|
+
if (this.module && error instanceof this.module.RejectRequestError) {
|
|
27833
|
+
throw Object.assign(new Error("Loop transaction rejected"), {
|
|
27834
|
+
code: 4001,
|
|
27835
|
+
});
|
|
27836
|
+
}
|
|
27837
|
+
throw new LoopSubmissionUnknownError(error);
|
|
27838
|
+
}
|
|
27839
|
+
finally {
|
|
27840
|
+
clearTimeout(timer);
|
|
27841
|
+
}
|
|
27842
|
+
const update = parseLoopTransferUpdate(response, commandId);
|
|
27843
|
+
if (update?.status === "failed")
|
|
27844
|
+
throw new Error(update.message);
|
|
27845
|
+
if (!update)
|
|
27846
|
+
throw new LoopSubmissionUnknownError();
|
|
27847
|
+
return update;
|
|
27848
|
+
}
|
|
27849
|
+
}
|
|
27850
|
+
const loopCantonConnector = new LoopCantonConnector();
|
|
27851
|
+
|
|
27120
27852
|
/**
|
|
27121
27853
|
* Discovers Canton browser-extension wallets and maps each to a
|
|
27122
27854
|
* {@link CantonWallet}: CIP-103 announce-protocol wallets (on mount and on
|
|
@@ -27163,7 +27895,19 @@ function useCantonWallets() {
|
|
|
27163
27895
|
return;
|
|
27164
27896
|
const announced = (await discoverCantonProviders()).map(toAnnouncedWallet);
|
|
27165
27897
|
const injected = discoverInjectedCantonWallets().map(toInjectedWallet);
|
|
27166
|
-
|
|
27898
|
+
const loopWallet = {
|
|
27899
|
+
...formatCantonWallet({
|
|
27900
|
+
connectorId: "canton-loop",
|
|
27901
|
+
name: "Loop",
|
|
27902
|
+
icon: "https://raw.githubusercontent.com/0xsquid/assets/main/images/master/wallets/canton-loop.svg",
|
|
27903
|
+
connector: loopCantonConnector,
|
|
27904
|
+
}),
|
|
27905
|
+
links: { website: "https://cantonloop.com" },
|
|
27906
|
+
isInstalled: () => false,
|
|
27907
|
+
skipInstallCheck: true,
|
|
27908
|
+
isMobile: true,
|
|
27909
|
+
};
|
|
27910
|
+
setWallets(mergeInjectedCantonWallets(announced, [...injected, loopWallet]));
|
|
27167
27911
|
}, [toAnnouncedWallet, toInjectedWallet]);
|
|
27168
27912
|
useEffect(() => {
|
|
27169
27913
|
refresh();
|
|
@@ -27194,7 +27938,9 @@ function useCanton() {
|
|
|
27194
27938
|
// Try to reconnect silently first (existing session, no popup)
|
|
27195
27939
|
result = await wallet.connector.autoConnect();
|
|
27196
27940
|
}
|
|
27197
|
-
catch {
|
|
27941
|
+
catch (error) {
|
|
27942
|
+
if (error instanceof CantonConnectionCancelledError)
|
|
27943
|
+
throw error;
|
|
27198
27944
|
// Otherwise prompt the wallet to connect
|
|
27199
27945
|
result = await wallet.connector.connect();
|
|
27200
27946
|
}
|
|
@@ -27216,8 +27962,7 @@ function useCanton() {
|
|
|
27216
27962
|
wallet: recentCantonWallet,
|
|
27217
27963
|
address,
|
|
27218
27964
|
});
|
|
27219
|
-
|
|
27220
|
-
}, [wallets.map((w) => w.connectorId), recentCantonWalletId]);
|
|
27965
|
+
}, [wallets, recentCantonWalletId, setConnectedWallet]);
|
|
27221
27966
|
useEffect(() => {
|
|
27222
27967
|
const wallet = connectedCantonWallet.wallet;
|
|
27223
27968
|
if (!wallet) {
|
|
@@ -27474,7 +28219,7 @@ function useStellarWallets() {
|
|
|
27474
28219
|
try {
|
|
27475
28220
|
const { allowAllModules: initializeAllModules } = await import('@creit.tech/stellar-wallets-kit');
|
|
27476
28221
|
const { LedgerModule } = await import('@creit.tech/stellar-wallets-kit/modules/ledger.module.mjs');
|
|
27477
|
-
const { formatStellarWallet } = await import('./stellarService.client-
|
|
28222
|
+
const { formatStellarWallet } = await import('./stellarService.client-DtA9zkRt.js');
|
|
27478
28223
|
const modules = [...initializeAllModules(), new LedgerModule()];
|
|
27479
28224
|
const promises = modules.map(async (module) => {
|
|
27480
28225
|
const isAvailable = await module.isAvailable();
|
|
@@ -28053,6 +28798,11 @@ const useWallet = () => {
|
|
|
28053
28798
|
}
|
|
28054
28799
|
}
|
|
28055
28800
|
catch (error) {
|
|
28801
|
+
const connecting = useWalletStore.getState().connectingWalletState;
|
|
28802
|
+
if (connecting.wallet !== wallet ||
|
|
28803
|
+
connecting.status !== ConnectingWalletStatus.CONNECTING) {
|
|
28804
|
+
return false;
|
|
28805
|
+
}
|
|
28056
28806
|
console.error("Failed to connect wallet", error);
|
|
28057
28807
|
walletConnectionError(wallet, error);
|
|
28058
28808
|
return false;
|
|
@@ -28284,8 +29034,6 @@ const useMultiChainWallet = (chain) => {
|
|
|
28284
29034
|
chainType: chain.chainType,
|
|
28285
29035
|
}),
|
|
28286
29036
|
};
|
|
28287
|
-
case ChainType.DANAL:
|
|
28288
|
-
return {};
|
|
28289
29037
|
}
|
|
28290
29038
|
}, [
|
|
28291
29039
|
chain?.chainType,
|
|
@@ -28399,12 +29147,27 @@ const useMultiChainWallet = (chain) => {
|
|
|
28399
29147
|
};
|
|
28400
29148
|
|
|
28401
29149
|
const useSwap = () => {
|
|
28402
|
-
const { initialAssets, defaultTokensPerChain, disabledChains, availableChains, } = useConfigStore((state) => state.config);
|
|
29150
|
+
const { initialAssets, defaultTokensPerChain, disabledChains, availableChains, availableTokens, } = useConfigStore((state) => state.config);
|
|
28403
29151
|
const fromPrice = useTransactionStore((state) => state.fromPrice);
|
|
28404
|
-
const { swapRoute } = useSwapRoutePersistStore();
|
|
29152
|
+
const { swapRoute: storedSwapRoute } = useSwapRoutePersistStore();
|
|
28405
29153
|
const { tokens } = useSquidTokens();
|
|
28406
29154
|
const queryClient = useQueryClient();
|
|
28407
29155
|
const { chains, supportedDestinationChains, supportedSourceChains } = useSquidChains();
|
|
29156
|
+
const swapRoute = useMemo(() => storedSwapRoute
|
|
29157
|
+
? normalizeSwapParamsForSelection({
|
|
29158
|
+
swapParams: storedSwapRoute,
|
|
29159
|
+
tokens,
|
|
29160
|
+
chains,
|
|
29161
|
+
config: { disabledChains, availableChains, availableTokens },
|
|
29162
|
+
})
|
|
29163
|
+
: undefined, [
|
|
29164
|
+
storedSwapRoute,
|
|
29165
|
+
tokens,
|
|
29166
|
+
chains,
|
|
29167
|
+
disabledChains,
|
|
29168
|
+
availableChains,
|
|
29169
|
+
availableTokens,
|
|
29170
|
+
]);
|
|
28408
29171
|
const sourceChainId = useMemo(() => swapRoute?.fromChainId ??
|
|
28409
29172
|
(initialAssets?.from
|
|
28410
29173
|
? resolveChainIdFromAsset(initialAssets.from, supportedSourceChains)
|
|
@@ -28415,13 +29178,23 @@ const useSwap = () => {
|
|
|
28415
29178
|
: undefined), [swapRoute?.toChainId, supportedDestinationChains, initialAssets?.to]);
|
|
28416
29179
|
const fromChain = useMemo(() => supportedSourceChains.find((c) => c.chainId === swapRoute?.fromChainId), [swapRoute?.fromChainId, supportedSourceChains]);
|
|
28417
29180
|
const toChain = useMemo(() => supportedDestinationChains.find((c) => c.chainId === swapRoute?.toChainId), [swapRoute?.toChainId, supportedDestinationChains]);
|
|
28418
|
-
const fromTokens = useMemo(() =>
|
|
29181
|
+
const fromTokens = useMemo(() => {
|
|
29182
|
+
const chainTokens = getTokensForChain(tokens, sourceChainId);
|
|
29183
|
+
return isArcChain(sourceChainId)
|
|
29184
|
+
? filterViewableTokens(chainTokens, { availableTokens }, "from")
|
|
29185
|
+
: chainTokens;
|
|
29186
|
+
}, [tokens, sourceChainId, availableTokens]);
|
|
28419
29187
|
const fromToken = useMemo(() => fromTokens.find((t) => t.address.toLowerCase() === swapRoute?.fromTokenAddress?.toLowerCase()), [fromTokens, swapRoute?.fromTokenAddress]);
|
|
28420
|
-
const toTokens = useMemo(() =>
|
|
28421
|
-
|
|
28422
|
-
|
|
28423
|
-
|
|
28424
|
-
|
|
29188
|
+
const toTokens = useMemo(() => {
|
|
29189
|
+
const destinationTokens = filterTokensForDestination({
|
|
29190
|
+
tokens: getTokensForChain(tokens, destChainId),
|
|
29191
|
+
selectedDestinationChain: toChain,
|
|
29192
|
+
selectedSourceToken: fromToken,
|
|
29193
|
+
});
|
|
29194
|
+
return isArcChain(destChainId)
|
|
29195
|
+
? filterViewableTokens(destinationTokens, { availableTokens }, "to")
|
|
29196
|
+
: destinationTokens;
|
|
29197
|
+
}, [destChainId, toChain, fromToken, tokens, availableTokens]);
|
|
28425
29198
|
const toToken = useMemo(() => toTokens.find((t) => t.address.toLowerCase() === swapRoute?.toTokenAddress?.toLowerCase()), [toTokens, swapRoute?.toTokenAddress]);
|
|
28426
29199
|
const isSameChain = sourceChainId === destChainId;
|
|
28427
29200
|
const tokenItems = useMemo(() => ({ from: fromTokens, to: toTokens }), [fromTokens, toTokens]);
|
|
@@ -28469,6 +29242,7 @@ const useSwap = () => {
|
|
|
28469
29242
|
defaultTokensPerChain,
|
|
28470
29243
|
disabledChains,
|
|
28471
29244
|
availableChains,
|
|
29245
|
+
availableTokens,
|
|
28472
29246
|
},
|
|
28473
29247
|
queryClient,
|
|
28474
29248
|
connectedSourceAddress: connectedSourceAddress.address,
|
|
@@ -28508,6 +29282,7 @@ const useSwap = () => {
|
|
|
28508
29282
|
defaultTokensPerChain,
|
|
28509
29283
|
disabledChains,
|
|
28510
29284
|
availableChains,
|
|
29285
|
+
availableTokens,
|
|
28511
29286
|
initialAssets,
|
|
28512
29287
|
queryClient,
|
|
28513
29288
|
swapRoute,
|
|
@@ -28563,6 +29338,10 @@ const useSwap = () => {
|
|
|
28563
29338
|
},
|
|
28564
29339
|
direction: "to",
|
|
28565
29340
|
});
|
|
29341
|
+
if ([defaultFromChainId, defaultToChainId].some((chainId) => isArcChain(chainId) &&
|
|
29342
|
+
!tokens.some((token) => token.chainId === chainId && !isArcNativeToken(token)))) {
|
|
29343
|
+
return;
|
|
29344
|
+
}
|
|
28566
29345
|
const fromTokenAddress = getInitialOrDefaultTokenAddressForChain({
|
|
28567
29346
|
tokens,
|
|
28568
29347
|
config: {
|
|
@@ -28570,6 +29349,7 @@ const useSwap = () => {
|
|
|
28570
29349
|
defaultTokensPerChain,
|
|
28571
29350
|
disabledChains,
|
|
28572
29351
|
availableChains,
|
|
29352
|
+
availableTokens,
|
|
28573
29353
|
},
|
|
28574
29354
|
chainId: defaultFromChainId,
|
|
28575
29355
|
direction: "from",
|
|
@@ -28581,6 +29361,7 @@ const useSwap = () => {
|
|
|
28581
29361
|
defaultTokensPerChain,
|
|
28582
29362
|
disabledChains,
|
|
28583
29363
|
availableChains,
|
|
29364
|
+
availableTokens,
|
|
28584
29365
|
},
|
|
28585
29366
|
chainId: defaultToChainId,
|
|
28586
29367
|
direction: "to",
|
|
@@ -28605,6 +29386,7 @@ const useSwap = () => {
|
|
|
28605
29386
|
initialAssets,
|
|
28606
29387
|
disabledChains,
|
|
28607
29388
|
availableChains,
|
|
29389
|
+
availableTokens,
|
|
28608
29390
|
defaultTokensPerChain,
|
|
28609
29391
|
tokens,
|
|
28610
29392
|
]);
|
|
@@ -29124,8 +29906,6 @@ async function createClient(chain) {
|
|
|
29124
29906
|
return new StellarRpcClient(chain.rpc);
|
|
29125
29907
|
case ChainType.CANTON:
|
|
29126
29908
|
return null;
|
|
29127
|
-
case ChainType.DANAL:
|
|
29128
|
-
return null;
|
|
29129
29909
|
}
|
|
29130
29910
|
}
|
|
29131
29911
|
|
|
@@ -30140,8 +30920,7 @@ const getAllStellarTokensBalance = async (userAddress, stellarTokens, stellarCha
|
|
|
30140
30920
|
};
|
|
30141
30921
|
/**
|
|
30142
30922
|
* Canton balances are private: they can only be read with a wallet-authorized
|
|
30143
|
-
*
|
|
30144
|
-
* party). So balance is fetchable only when a Canton wallet is connected, and
|
|
30923
|
+
* session. Balance is fetchable only when a Canton wallet is connected, and
|
|
30145
30924
|
* only for that wallet's party — there's no address-only read.
|
|
30146
30925
|
*/
|
|
30147
30926
|
const getCantonTokenBalance = async (userAddress, token, cantonConnector) => {
|
|
@@ -30150,30 +30929,14 @@ const getCantonTokenBalance = async (userAddress, token, cantonConnector) => {
|
|
|
30150
30929
|
const instrument = parseCantonInstrument(token.originalAddress);
|
|
30151
30930
|
if (!instrument)
|
|
30152
30931
|
return "0";
|
|
30153
|
-
const
|
|
30154
|
-
const activeContracts = await cantonConnector.ledgerApi({
|
|
30155
|
-
requestMethod: "post",
|
|
30156
|
-
resource: "/v2/state/active-contracts",
|
|
30157
|
-
body: buildHoldingsAcsRequestBody(userAddress, String(ledgerEnd.offset)),
|
|
30158
|
-
});
|
|
30159
|
-
const grouped = groupCantonHoldingBalances(activeContracts);
|
|
30932
|
+
const grouped = await cantonConnector.getBalances(userAddress);
|
|
30160
30933
|
return grouped[cantonInstrumentKey(instrument)] ?? "0";
|
|
30161
30934
|
};
|
|
30162
30935
|
/**
|
|
30163
|
-
* Fetch balances for all Canton tokens
|
|
30164
|
-
* private, so this requires a connected wallet's authorized `ledgerApi`.
|
|
30936
|
+
* Fetch balances for all Canton tokens through the connected wallet.
|
|
30165
30937
|
*/
|
|
30166
30938
|
async function getAllCantonTokensBalance({ connector, partyId, tokens, }) {
|
|
30167
|
-
const
|
|
30168
|
-
requestMethod: "get",
|
|
30169
|
-
resource: "/v2/state/ledger-end",
|
|
30170
|
-
});
|
|
30171
|
-
const activeContracts = await connector.ledgerApi({
|
|
30172
|
-
requestMethod: "post",
|
|
30173
|
-
resource: "/v2/state/active-contracts",
|
|
30174
|
-
body: buildHoldingsAcsRequestBody(partyId, String(ledgerEnd.offset)),
|
|
30175
|
-
});
|
|
30176
|
-
const grouped = groupCantonHoldingBalances(activeContracts);
|
|
30939
|
+
const grouped = await connector.getBalances(partyId);
|
|
30177
30940
|
return tokens.map((token) => {
|
|
30178
30941
|
const instrument = token.originalAddress
|
|
30179
30942
|
? parseCantonInstrument(token.originalAddress)
|
|
@@ -30392,7 +31155,7 @@ const useCantonBalance = ({ chain, token, userAddress, enabled = true, refreshIn
|
|
|
30392
31155
|
};
|
|
30393
31156
|
|
|
30394
31157
|
function useNativeTokenForChain(chain) {
|
|
30395
|
-
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens,
|
|
31158
|
+
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens();
|
|
30396
31159
|
const getTokensForChainType = () => {
|
|
30397
31160
|
if (!chain?.chainType)
|
|
30398
31161
|
return [];
|
|
@@ -30413,21 +31176,20 @@ function useNativeTokenForChain(chain) {
|
|
|
30413
31176
|
return stellarTokens;
|
|
30414
31177
|
case ChainType.CANTON:
|
|
30415
31178
|
return cantonTokens;
|
|
30416
|
-
case ChainType.DANAL:
|
|
30417
|
-
return danalTokens;
|
|
30418
31179
|
}
|
|
30419
31180
|
};
|
|
31181
|
+
const tokens = getTokensForChainType();
|
|
30420
31182
|
const nativeTokenForChainType = useMemo(() => {
|
|
30421
31183
|
if (!chain)
|
|
30422
31184
|
return undefined;
|
|
30423
|
-
return findNativeToken(
|
|
30424
|
-
}, [chain]);
|
|
31185
|
+
return findNativeToken(tokens, chain);
|
|
31186
|
+
}, [chain, tokens]);
|
|
30425
31187
|
return { nativeToken: nativeTokenForChainType };
|
|
30426
31188
|
}
|
|
30427
31189
|
|
|
30428
31190
|
const useEvmNativeBalance = ({ address, chain, }) => {
|
|
30429
31191
|
const { isChainTypeConnected } = useWallet();
|
|
30430
|
-
const { data: nativeEvmBalance, isLoading } = useBalance({
|
|
31192
|
+
const { data: nativeEvmBalance, isLoading, isError, } = useBalance({
|
|
30431
31193
|
address: address,
|
|
30432
31194
|
chainId: Number(chain?.chainId),
|
|
30433
31195
|
query: {
|
|
@@ -30439,6 +31201,8 @@ const useEvmNativeBalance = ({ address, chain, }) => {
|
|
|
30439
31201
|
},
|
|
30440
31202
|
});
|
|
30441
31203
|
const balance = useMemo(() => {
|
|
31204
|
+
if (isArcChain(chain?.chainId) && isError)
|
|
31205
|
+
return undefined;
|
|
30442
31206
|
if (nativeEvmBalance?.decimals != null && nativeEvmBalance?.value != null) {
|
|
30443
31207
|
if (chain?.chainId === CHAIN_IDS.HEDERA) {
|
|
30444
31208
|
return {
|
|
@@ -30452,7 +31216,12 @@ const useEvmNativeBalance = ({ address, chain, }) => {
|
|
|
30452
31216
|
};
|
|
30453
31217
|
}
|
|
30454
31218
|
return;
|
|
30455
|
-
}, [
|
|
31219
|
+
}, [
|
|
31220
|
+
nativeEvmBalance?.decimals,
|
|
31221
|
+
nativeEvmBalance?.value,
|
|
31222
|
+
chain?.chainId,
|
|
31223
|
+
isError,
|
|
31224
|
+
]);
|
|
30456
31225
|
return {
|
|
30457
31226
|
balance,
|
|
30458
31227
|
isLoading,
|
|
@@ -30675,9 +31444,6 @@ const useNativeBalance = (chain) => {
|
|
|
30675
31444
|
case ChainType.CANTON:
|
|
30676
31445
|
balance = nativeCantonBalance;
|
|
30677
31446
|
break;
|
|
30678
|
-
case ChainType.DANAL:
|
|
30679
|
-
balance = undefined;
|
|
30680
|
-
break;
|
|
30681
31447
|
}
|
|
30682
31448
|
const balanceFormatted = !!balance
|
|
30683
31449
|
? formatBNToReadable(balance.value, balance.decimals)
|
|
@@ -30717,8 +31483,6 @@ const useNativeBalance = (chain) => {
|
|
|
30717
31483
|
return isStellarLoading;
|
|
30718
31484
|
case ChainType.CANTON:
|
|
30719
31485
|
return isCantonLoading;
|
|
30720
|
-
case ChainType.DANAL:
|
|
30721
|
-
return false;
|
|
30722
31486
|
}
|
|
30723
31487
|
}, [
|
|
30724
31488
|
chain?.chainType,
|
|
@@ -30944,7 +31708,7 @@ function hederaWalletConnect(parameters) {
|
|
|
30944
31708
|
const optionalChains = config.chains.map((x) => x.id);
|
|
30945
31709
|
if (!optionalChains.length)
|
|
30946
31710
|
return;
|
|
30947
|
-
const { EthereumProvider } = await import('./index.es
|
|
31711
|
+
const { EthereumProvider } = await import('./index.es-BiK_wjSb.js');
|
|
30948
31712
|
const rawProvider = await EthereumProvider.init({
|
|
30949
31713
|
...restParameters,
|
|
30950
31714
|
disableProviderPing: true,
|
|
@@ -31178,8 +31942,6 @@ const useSigner = ({ chain }) => {
|
|
|
31178
31942
|
return isStellarSignerReady;
|
|
31179
31943
|
case ChainType.CANTON:
|
|
31180
31944
|
return isCantonSignerReady;
|
|
31181
|
-
case ChainType.DANAL:
|
|
31182
|
-
return false;
|
|
31183
31945
|
}
|
|
31184
31946
|
}, [
|
|
31185
31947
|
chain?.chainType,
|
|
@@ -31632,12 +32394,8 @@ const useSendTransactionStore = create((set, get) => ({
|
|
|
31632
32394
|
const useDepositAddressStore = create((set) => ({
|
|
31633
32395
|
deposit: null,
|
|
31634
32396
|
selectedPaymentMethod: "connectedWallet",
|
|
31635
|
-
userDepositTxId: null,
|
|
31636
32397
|
setDeposit: (data) => {
|
|
31637
|
-
set({ deposit: data
|
|
31638
|
-
},
|
|
31639
|
-
setUserDepositTxId: (txId) => {
|
|
31640
|
-
set({ userDepositTxId: txId });
|
|
32398
|
+
set({ deposit: data });
|
|
31641
32399
|
},
|
|
31642
32400
|
setPaymentMethod: (method) => {
|
|
31643
32401
|
set({ selectedPaymentMethod: method });
|
|
@@ -31649,7 +32407,7 @@ function useDepositAddress(squidRoute) {
|
|
|
31649
32407
|
selectedPaymentMethod: state.selectedPaymentMethod,
|
|
31650
32408
|
depositAddress: state.deposit?.depositAddress,
|
|
31651
32409
|
}));
|
|
31652
|
-
const { setDeposit, setPaymentMethod, deposit
|
|
32410
|
+
const { setDeposit, setPaymentMethod, deposit } = useDepositAddressStore();
|
|
31653
32411
|
const { squid } = useSquidStore();
|
|
31654
32412
|
const { fromChain } = useSwap();
|
|
31655
32413
|
const isAvailableAsPaymentMethod = useMemo(() => {
|
|
@@ -31659,13 +32417,11 @@ function useDepositAddress(squidRoute) {
|
|
|
31659
32417
|
CHAIN_IDS.BITCOIN,
|
|
31660
32418
|
CHAIN_IDS.SOLANA,
|
|
31661
32419
|
CHAIN_IDS.CANTON,
|
|
31662
|
-
CHAIN_IDS.DANAL_TESTNET,
|
|
31663
32420
|
];
|
|
31664
32421
|
return chainsSupportingDepositAddress.includes(fromChain.chainId);
|
|
31665
32422
|
}, [fromChain?.chainId]);
|
|
31666
|
-
const routeProvidesDirectDepositAddress =
|
|
31667
|
-
isDepositAddressDirectTransferRoute(squidRoute.transactionRequest)
|
|
31668
|
-
(!!squidRoute && isDanalDepositRoute(squidRoute));
|
|
32423
|
+
const routeProvidesDirectDepositAddress = !!squidRoute?.transactionRequest &&
|
|
32424
|
+
isDepositAddressDirectTransferRoute(squidRoute.transactionRequest);
|
|
31669
32425
|
const swapWillGenerateDepositAddress = isChainflipDepositRoute(squidRoute) || routeProvidesDirectDepositAddress;
|
|
31670
32426
|
const paymentMethod = isAvailableAsPaymentMethod
|
|
31671
32427
|
? selectedPaymentMethod
|
|
@@ -31691,19 +32447,6 @@ function useDepositAddress(squidRoute) {
|
|
|
31691
32447
|
});
|
|
31692
32448
|
return;
|
|
31693
32449
|
}
|
|
31694
|
-
else if (isDanalDepositRoute(route)) {
|
|
31695
|
-
const transferBody = parseDanalTransferBody(route.transactionRequest.data);
|
|
31696
|
-
if (!transferBody) {
|
|
31697
|
-
throw new Error("Could not parse Danal transfer request body");
|
|
31698
|
-
}
|
|
31699
|
-
setDeposit({
|
|
31700
|
-
amount: transferBody.amount,
|
|
31701
|
-
depositAddress: route.transactionRequest.target,
|
|
31702
|
-
statusTrackingId: transferBody.memo,
|
|
31703
|
-
memo: transferBody.memo,
|
|
31704
|
-
});
|
|
31705
|
-
return;
|
|
31706
|
-
}
|
|
31707
32450
|
else if (isDepositAddressDirectTransferRoute(route.transactionRequest)) {
|
|
31708
32451
|
// Canton case
|
|
31709
32452
|
const orderHash = route.transactionRequest.data;
|
|
@@ -31726,8 +32469,6 @@ function useDepositAddress(squidRoute) {
|
|
|
31726
32469
|
depositAddress,
|
|
31727
32470
|
closeDepositChannel,
|
|
31728
32471
|
depositData: deposit,
|
|
31729
|
-
userDepositTxId,
|
|
31730
|
-
setUserDepositTxId,
|
|
31731
32472
|
};
|
|
31732
32473
|
}
|
|
31733
32474
|
|
|
@@ -31755,7 +32496,7 @@ const useUrlSwapParams = () => {
|
|
|
31755
32496
|
|
|
31756
32497
|
const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, queryOptions, }) => {
|
|
31757
32498
|
const { evmChains, cosmosChains, suiChains, xrplChains, stellarChains } = useSquidChains(direction);
|
|
31758
|
-
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens,
|
|
32499
|
+
const { evmTokens, cosmosTokens, solanaTokens, bitcoinTokens, suiTokens, xrplTokens, stellarTokens, cantonTokens, } = useSquidTokens(direction);
|
|
31759
32500
|
const { keplrTypeWallet } = useCosmosContext();
|
|
31760
32501
|
const cantonConnector = useWalletStore((store) => store.connectedWalletsByChainType[ChainType.CANTON]?.wallet?.connector);
|
|
31761
32502
|
const placeholderData = useMemo(() => {
|
|
@@ -31768,7 +32509,6 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
|
|
|
31768
32509
|
[ChainType.XRPL]: xrplTokens.map((t) => ({ ...t, balance: "0" })),
|
|
31769
32510
|
[ChainType.STELLAR]: stellarTokens.map((t) => ({ ...t, balance: "0" })),
|
|
31770
32511
|
[ChainType.CANTON]: cantonTokens.map((t) => ({ ...t, balance: "0" })),
|
|
31771
|
-
[ChainType.DANAL]: danalTokens.map((t) => ({ ...t, balance: "0" })),
|
|
31772
32512
|
};
|
|
31773
32513
|
if (!chainType) {
|
|
31774
32514
|
// Return all tokens with zero balance
|
|
@@ -31791,7 +32531,6 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
|
|
|
31791
32531
|
xrplTokens,
|
|
31792
32532
|
stellarTokens,
|
|
31793
32533
|
cantonTokens,
|
|
31794
|
-
danalTokens,
|
|
31795
32534
|
]);
|
|
31796
32535
|
const isQueryEnabled = useMemo(() => {
|
|
31797
32536
|
// Respect the queryOptions.enabled override if provided
|
|
@@ -31816,8 +32555,6 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
|
|
|
31816
32555
|
return stellarTokens.length > 0;
|
|
31817
32556
|
case ChainType.CANTON:
|
|
31818
32557
|
return cantonTokens.length > 0;
|
|
31819
|
-
case ChainType.DANAL:
|
|
31820
|
-
return danalTokens.length > 0;
|
|
31821
32558
|
}
|
|
31822
32559
|
}, [
|
|
31823
32560
|
chainType,
|
|
@@ -31831,7 +32568,6 @@ const useAllTokensWithBalanceForChainType = ({ chainType, address, direction, qu
|
|
|
31831
32568
|
xrplTokens.length,
|
|
31832
32569
|
stellarTokens.length,
|
|
31833
32570
|
cantonTokens.length,
|
|
31834
|
-
danalTokens.length,
|
|
31835
32571
|
]);
|
|
31836
32572
|
const query = useQuery(keys().allTokensBalance(address, chainType, direction), async () => {
|
|
31837
32573
|
// Return zero balances if no address
|
|
@@ -31956,12 +32692,6 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
|
|
|
31956
32692
|
direction,
|
|
31957
32693
|
queryOptions,
|
|
31958
32694
|
});
|
|
31959
|
-
const danalBalancesQuery = useAllTokensWithBalanceForChainType({
|
|
31960
|
-
chainType: ChainType.DANAL,
|
|
31961
|
-
address: connectedAddresses?.[ChainType.DANAL],
|
|
31962
|
-
direction,
|
|
31963
|
-
queryOptions,
|
|
31964
|
-
});
|
|
31965
32695
|
// Create a map of chain type to balance query results
|
|
31966
32696
|
const balanceQueries = useMemo(() => ({
|
|
31967
32697
|
[ChainType.EVM]: evmBalancesQuery,
|
|
@@ -31972,7 +32702,6 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
|
|
|
31972
32702
|
[ChainType.XRPL]: xrplBalancesQuery,
|
|
31973
32703
|
[ChainType.STELLAR]: stellarBalancesQuery,
|
|
31974
32704
|
[ChainType.CANTON]: cantonBalancesQuery,
|
|
31975
|
-
[ChainType.DANAL]: danalBalancesQuery,
|
|
31976
32705
|
}), [
|
|
31977
32706
|
evmBalancesQuery,
|
|
31978
32707
|
cosmosBalancesQuery,
|
|
@@ -31982,7 +32711,6 @@ const useAllConnectedWalletBalances = ({ direction, queryOptions = {
|
|
|
31982
32711
|
xrplBalancesQuery,
|
|
31983
32712
|
stellarBalancesQuery,
|
|
31984
32713
|
cantonBalancesQuery,
|
|
31985
|
-
danalBalancesQuery,
|
|
31986
32714
|
]);
|
|
31987
32715
|
// Combine all tokens from different chains
|
|
31988
32716
|
const allTokens = useMemo(() => Object.values(balanceQueries).flatMap((query) => query.data?.tokens ?? []), [balanceQueries]);
|
|
@@ -32090,8 +32818,6 @@ const useMultiChainBalance = ({ chain, token, userAddress, enabled = true, }) =>
|
|
|
32090
32818
|
return stellarBalance;
|
|
32091
32819
|
case ChainType.CANTON:
|
|
32092
32820
|
return cantonBalance;
|
|
32093
|
-
case ChainType.DANAL:
|
|
32094
|
-
return "0";
|
|
32095
32821
|
}
|
|
32096
32822
|
}, [
|
|
32097
32823
|
chain?.chainType,
|
|
@@ -32297,6 +33023,27 @@ function useSourceChainGasToken({ fromChain, fromToken, }) {
|
|
|
32297
33023
|
normalizeFee: convertTempoFeeToStablecoinUnits,
|
|
32298
33024
|
};
|
|
32299
33025
|
}
|
|
33026
|
+
if (isArcChain(fromChain.chainId)) {
|
|
33027
|
+
const isUsdc = isArcUsdcToken(fromToken);
|
|
33028
|
+
const isNative = isArcNativeToken(fromToken);
|
|
33029
|
+
if (fromToken.chainId !== fromChain.chainId ||
|
|
33030
|
+
nativeBalance.decimals !== 18 ||
|
|
33031
|
+
(isUsdc && fromToken.decimals !== 6) ||
|
|
33032
|
+
(isNative && fromToken.decimals !== 18)) {
|
|
33033
|
+
return null;
|
|
33034
|
+
}
|
|
33035
|
+
return {
|
|
33036
|
+
fromTokenPaysGasFees: isUsdc || isNative,
|
|
33037
|
+
gasTokenBalanceWei: nativeBalance.value,
|
|
33038
|
+
normalizeFee: (fee) => fee,
|
|
33039
|
+
fromAmountToGasUnits: isUsdc
|
|
33040
|
+
? (amount) => amount * 10n ** 12n
|
|
33041
|
+
: undefined,
|
|
33042
|
+
gasUnitsToFromAmount: isUsdc
|
|
33043
|
+
? (amount) => amount / 10n ** 12n
|
|
33044
|
+
: undefined,
|
|
33045
|
+
};
|
|
33046
|
+
}
|
|
32300
33047
|
return {
|
|
32301
33048
|
fromTokenPaysGasFees: fromToken.address.toLowerCase() ===
|
|
32302
33049
|
chainTypeToNativeTokenAddressMap[fromToken.type].toLowerCase(),
|
|
@@ -32304,10 +33051,10 @@ function useSourceChainGasToken({ fromChain, fromToken, }) {
|
|
|
32304
33051
|
normalizeFee: (fee) => fee,
|
|
32305
33052
|
};
|
|
32306
33053
|
}, [
|
|
32307
|
-
fromToken
|
|
32308
|
-
fromToken?.type,
|
|
33054
|
+
fromToken,
|
|
32309
33055
|
fromChain?.chainId,
|
|
32310
33056
|
nativeBalance?.value,
|
|
33057
|
+
nativeBalance?.decimals,
|
|
32311
33058
|
tempoFeeData,
|
|
32312
33059
|
]);
|
|
32313
33060
|
/**
|
|
@@ -32322,9 +33069,20 @@ function useSourceChainGasToken({ fromChain, fromToken, }) {
|
|
|
32322
33069
|
return evmTokens.find((t) => t.chainId === fromChain.chainId &&
|
|
32323
33070
|
t.address.toLowerCase() === tempoFeeData.gasTokenAddress.toLowerCase());
|
|
32324
33071
|
}
|
|
33072
|
+
if (isArcChain(fromChain.chainId)) {
|
|
33073
|
+
return nativeToken?.decimals === 18
|
|
33074
|
+
? {
|
|
33075
|
+
...nativeToken,
|
|
33076
|
+
symbol: fromChain.nativeCurrency.symbol,
|
|
33077
|
+
name: fromChain.nativeCurrency.name,
|
|
33078
|
+
}
|
|
33079
|
+
: undefined;
|
|
33080
|
+
}
|
|
32325
33081
|
return nativeToken;
|
|
32326
33082
|
}, [
|
|
32327
33083
|
fromChain?.chainId,
|
|
33084
|
+
fromChain?.nativeCurrency.symbol,
|
|
33085
|
+
fromChain?.nativeCurrency.name,
|
|
32328
33086
|
fromToken?.address,
|
|
32329
33087
|
nativeToken,
|
|
32330
33088
|
tempoFeeData,
|
|
@@ -32483,22 +33241,57 @@ const calculateTotalNativeFees = ({ expressFeeCost, firstFeeCost, firstGasCost,
|
|
|
32483
33241
|
(sameTokenBetweenFees
|
|
32484
33242
|
? BigInt(firstFeeCost?.amount ?? "0") + BigInt(firstGasCost?.amount ?? "0")
|
|
32485
33243
|
: BigInt(firstGasCost?.amount ?? "0"));
|
|
33244
|
+
const addGasReserve = (fee) => (fee * 110n + 99n) / 100n;
|
|
33245
|
+
const calculateArcGasCosts = (gasCosts) => {
|
|
33246
|
+
const sourceGasCosts = gasCosts.filter((cost) => isArcChain(cost.token.chainId));
|
|
33247
|
+
if (sourceGasCosts.length === 0)
|
|
33248
|
+
return undefined;
|
|
33249
|
+
let total = 0n;
|
|
33250
|
+
for (const { amount, token } of sourceGasCosts) {
|
|
33251
|
+
const fee = BigInt(amount);
|
|
33252
|
+
if (fee <= 0n)
|
|
33253
|
+
return undefined;
|
|
33254
|
+
if (isArcUsdcToken(token) && token.decimals === 6) {
|
|
33255
|
+
total += fee * 10n ** 12n;
|
|
33256
|
+
}
|
|
33257
|
+
else if (isArcNativeToken(token) && token.decimals === 18) {
|
|
33258
|
+
total += fee;
|
|
33259
|
+
}
|
|
33260
|
+
else {
|
|
33261
|
+
return undefined;
|
|
33262
|
+
}
|
|
33263
|
+
}
|
|
33264
|
+
return total;
|
|
33265
|
+
};
|
|
33266
|
+
const calculateTotalGasBalanceNeeded = ({ fromAmount, networkFeesWei, chainFeeParams, }) => {
|
|
33267
|
+
if (!chainFeeParams || networkFeesWei == null)
|
|
33268
|
+
return undefined;
|
|
33269
|
+
if (!chainFeeParams.fromTokenPaysGasFees)
|
|
33270
|
+
return networkFeesWei;
|
|
33271
|
+
const amount = BigInt(fromAmount ?? "0");
|
|
33272
|
+
const amountInGasUnits = chainFeeParams.fromAmountToGasUnits?.(amount) ?? amount;
|
|
33273
|
+
return amountInGasUnits + networkFeesWei;
|
|
33274
|
+
};
|
|
32486
33275
|
const checkIsGasBalanceEnough = ({ fromAmount, networkFeesWei, chainFeeParams, }) => {
|
|
32487
33276
|
if (!chainFeeParams)
|
|
32488
33277
|
return false;
|
|
32489
|
-
|
|
32490
|
-
|
|
32491
|
-
|
|
32492
|
-
|
|
32493
|
-
|
|
33278
|
+
const total = calculateTotalGasBalanceNeeded({
|
|
33279
|
+
fromAmount,
|
|
33280
|
+
networkFeesWei,
|
|
33281
|
+
chainFeeParams,
|
|
33282
|
+
});
|
|
33283
|
+
return total != null && total <= chainFeeParams.gasTokenBalanceWei;
|
|
32494
33284
|
};
|
|
32495
33285
|
const calculateMinAmountValueWarnMsg = ({ networkFeesWei, chainFeeParams, fromTokenDecimals, }) => {
|
|
32496
|
-
if (!chainFeeParams?.fromTokenPaysGasFees)
|
|
33286
|
+
if (!chainFeeParams?.fromTokenPaysGasFees || networkFeesWei == null)
|
|
32497
33287
|
return undefined;
|
|
32498
33288
|
const minAmount = chainFeeParams.gasTokenBalanceWei - networkFeesWei;
|
|
32499
33289
|
if (minAmount <= BigInt(0))
|
|
32500
33290
|
return undefined;
|
|
32501
|
-
|
|
33291
|
+
const amountInTokenUnits = chainFeeParams.gasUnitsToFromAmount?.(minAmount) ?? minAmount;
|
|
33292
|
+
if (amountInTokenUnits <= 0n)
|
|
33293
|
+
return undefined;
|
|
33294
|
+
return formatBNToReadable(amountInTokenUnits, fromTokenDecimals);
|
|
32502
33295
|
};
|
|
32503
33296
|
/**
|
|
32504
33297
|
* Calculates the estimated duration of a route
|
|
@@ -32547,14 +33340,22 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
|
|
|
32547
33340
|
const expectedGasRefundCostUSD = convertTokenAmountToUSD(formatBNToReadable(expectedGasRefundCost, firstFeeCost?.token.decimals ?? 18), firstFeeCost?.token.usdPrice ?? "0");
|
|
32548
33341
|
const sameTokenBetweenFees = firstFeeCost?.token.address === firstGasCost?.token.address &&
|
|
32549
33342
|
firstFeeCost?.token.chainId === firstGasCost?.token.chainId;
|
|
32550
|
-
const totalNativeFees =
|
|
32551
|
-
|
|
32552
|
-
|
|
32553
|
-
|
|
32554
|
-
|
|
32555
|
-
|
|
32556
|
-
|
|
32557
|
-
|
|
33343
|
+
const totalNativeFees = isArcChain(fromChain?.chainId)
|
|
33344
|
+
? calculateArcGasCosts(allGasCosts)
|
|
33345
|
+
: calculateTotalNativeFees({
|
|
33346
|
+
expressFeeCost,
|
|
33347
|
+
firstFeeCost,
|
|
33348
|
+
firstGasCost,
|
|
33349
|
+
sameTokenBetweenFees,
|
|
33350
|
+
});
|
|
33351
|
+
const totalFeesInNativeTokenPlusRatio = totalNativeFees == null
|
|
33352
|
+
? undefined
|
|
33353
|
+
: isArcChain(fromChain?.chainId)
|
|
33354
|
+
? addGasReserve(totalNativeFees)
|
|
33355
|
+
: (totalNativeFees * BigInt(110)) / BigInt(100);
|
|
33356
|
+
const networkFeesWei = totalFeesInNativeTokenPlusRatio == null
|
|
33357
|
+
? undefined
|
|
33358
|
+
: chainFeeParams?.normalizeFee(totalFeesInNativeTokenPlusRatio);
|
|
32558
33359
|
const isGasBalanceEnough = checkIsGasBalanceEnough({
|
|
32559
33360
|
chainFeeParams,
|
|
32560
33361
|
fromAmount,
|
|
@@ -32570,10 +33371,12 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
|
|
|
32570
33371
|
estimatedRouteDuration: squidRoute?.estimate?.estimatedRouteDuration,
|
|
32571
33372
|
isSingleChainRoute,
|
|
32572
33373
|
});
|
|
32573
|
-
|
|
32574
|
-
|
|
32575
|
-
|
|
32576
|
-
|
|
33374
|
+
const totalGasBalanceNeeded = calculateTotalGasBalanceNeeded({
|
|
33375
|
+
fromAmount,
|
|
33376
|
+
networkFeesWei,
|
|
33377
|
+
chainFeeParams,
|
|
33378
|
+
});
|
|
33379
|
+
const gasBalanceNeeded = gasToken && totalGasBalanceNeeded != null
|
|
32577
33380
|
? formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals)
|
|
32578
33381
|
: undefined;
|
|
32579
33382
|
return {
|
|
@@ -32595,7 +33398,7 @@ const calculateEstimateResults = ({ squidRoute, tokens, fromChain, toChain, coll
|
|
|
32595
33398
|
expectedGasRefundCostUSD,
|
|
32596
33399
|
sameTokenBetweenFees,
|
|
32597
33400
|
fromTokenPaysGasFees: chainFeeParams?.fromTokenPaysGasFees ?? false,
|
|
32598
|
-
totalNativeFees,
|
|
33401
|
+
totalNativeFees: totalNativeFees ?? 0n,
|
|
32599
33402
|
isGasBalanceEnough,
|
|
32600
33403
|
minAmountValueWarnMsg,
|
|
32601
33404
|
estimatedRouteDuration,
|
|
@@ -32644,8 +33447,12 @@ function useSendTransactionGas({ chain, token, from, }) {
|
|
|
32644
33447
|
case ChainType.EVM: {
|
|
32645
33448
|
const client = await getClient(chain);
|
|
32646
33449
|
const feeData = await client.getFeeData();
|
|
32647
|
-
if (!feeData.maxFeePerGas)
|
|
33450
|
+
if (!feeData.maxFeePerGas) {
|
|
33451
|
+
if (isArcChain(chain.chainId)) {
|
|
33452
|
+
throw new Error("Gas price is unavailable");
|
|
33453
|
+
}
|
|
32648
33454
|
return BigInt(0);
|
|
33455
|
+
}
|
|
32649
33456
|
let maxFeePerGas = feeData.maxFeePerGas;
|
|
32650
33457
|
if (token.chainId === CHAIN_IDS.HEDERA) {
|
|
32651
33458
|
maxFeePerGas = scaleWeiToHbar(BigInt(feeData.maxFeePerGas));
|
|
@@ -32665,6 +33472,9 @@ function useSendTransactionGas({ chain, token, from, }) {
|
|
|
32665
33472
|
value: 1,
|
|
32666
33473
|
chainId: chain.chainId,
|
|
32667
33474
|
});
|
|
33475
|
+
if (isArcChain(chain.chainId) && gas <= 0n) {
|
|
33476
|
+
throw new Error("Gas estimate is unavailable");
|
|
33477
|
+
}
|
|
32668
33478
|
return gas * maxFeePerGas;
|
|
32669
33479
|
}
|
|
32670
33480
|
const erc20Interface = new Interface(erc20Abi);
|
|
@@ -32679,6 +33489,9 @@ function useSendTransactionGas({ chain, token, from, }) {
|
|
|
32679
33489
|
chainId: chain.chainId,
|
|
32680
33490
|
});
|
|
32681
33491
|
const feeWei = gas * maxFeePerGas;
|
|
33492
|
+
if (isArcChain(chain.chainId) && feeWei <= 0n) {
|
|
33493
|
+
throw new Error("Gas estimate is unavailable");
|
|
33494
|
+
}
|
|
32682
33495
|
// Tempo gas fees are denominated 18 units,
|
|
32683
33496
|
// this value needs to be scaled to 6 decimals
|
|
32684
33497
|
if (chain.chainId === CHAIN_IDS.TEMPO) {
|
|
@@ -32726,35 +33539,45 @@ function useSendTransactionGas({ chain, token, from, }) {
|
|
|
32726
33539
|
}
|
|
32727
33540
|
|
|
32728
33541
|
function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
|
|
32729
|
-
const { data
|
|
33542
|
+
const { data, isLoading, isFetching, isError, refetch } = useSendTransactionGas({
|
|
32730
33543
|
chain,
|
|
32731
33544
|
token,
|
|
32732
33545
|
from,
|
|
32733
33546
|
});
|
|
33547
|
+
const estimatedGas = isError || isFetching ? undefined : data;
|
|
33548
|
+
const networkFeesWei = estimatedGas == null
|
|
33549
|
+
? undefined
|
|
33550
|
+
: isArcChain(chain?.chainId)
|
|
33551
|
+
? addGasReserve(estimatedGas)
|
|
33552
|
+
: estimatedGas;
|
|
32734
33553
|
const { chainFeeParams, gasToken } = useSourceChainGasToken({
|
|
32735
33554
|
fromChain: chain,
|
|
32736
33555
|
fromToken: token,
|
|
32737
33556
|
});
|
|
32738
33557
|
const isGasBalanceEnough = useMemo(() => {
|
|
32739
|
-
if (!amount ||
|
|
33558
|
+
if (!amount || token?.decimals == null || !gasToken)
|
|
32740
33559
|
return false;
|
|
32741
33560
|
return checkIsGasBalanceEnough({
|
|
32742
33561
|
fromAmount: parseToBigInt(amount, token.decimals).toString(),
|
|
32743
|
-
networkFeesWei
|
|
33562
|
+
networkFeesWei,
|
|
32744
33563
|
chainFeeParams,
|
|
32745
33564
|
});
|
|
32746
|
-
}, [amount,
|
|
33565
|
+
}, [amount, networkFeesWei, token, chainFeeParams, gasToken]);
|
|
32747
33566
|
const gasBalanceNeeded = useMemo(() => {
|
|
32748
|
-
if (!amount ||
|
|
33567
|
+
if (!amount || token?.decimals == null || gasToken?.decimals == null)
|
|
33568
|
+
return undefined;
|
|
33569
|
+
const totalGasBalanceNeeded = calculateTotalGasBalanceNeeded({
|
|
33570
|
+
fromAmount: parseToBigInt(amount, token.decimals).toString(),
|
|
33571
|
+
networkFeesWei,
|
|
33572
|
+
chainFeeParams,
|
|
33573
|
+
});
|
|
33574
|
+
if (totalGasBalanceNeeded == null)
|
|
32749
33575
|
return undefined;
|
|
32750
|
-
// gas fees + fromAmount (if fromToken is gas token)
|
|
32751
|
-
const totalGasBalanceNeeded = estimatedGas +
|
|
32752
|
-
parseToBigInt(chainFeeParams?.fromTokenPaysGasFees ? (amount ?? "0") : "0", token.decimals);
|
|
32753
33576
|
return formatBNToReadable(totalGasBalanceNeeded, gasToken.decimals);
|
|
32754
33577
|
}, [
|
|
32755
33578
|
amount,
|
|
32756
|
-
chainFeeParams
|
|
32757
|
-
|
|
33579
|
+
chainFeeParams,
|
|
33580
|
+
networkFeesWei,
|
|
32758
33581
|
gasToken?.decimals,
|
|
32759
33582
|
token?.decimals,
|
|
32760
33583
|
]);
|
|
@@ -32765,20 +33588,22 @@ function useEstimateSendTransaction({ chain, token, amount, balance, from, }) {
|
|
|
32765
33588
|
parseToBigInt(amount, token.decimals));
|
|
32766
33589
|
}, [amount, balance, token?.decimals]);
|
|
32767
33590
|
const minAmountValueWarnMsg = useMemo(() => {
|
|
32768
|
-
if (!token?.address || !
|
|
33591
|
+
if (!token?.address || !gasToken || !chainFeeParams)
|
|
32769
33592
|
return undefined;
|
|
32770
33593
|
return calculateMinAmountValueWarnMsg({
|
|
32771
33594
|
chainFeeParams,
|
|
32772
|
-
networkFeesWei
|
|
33595
|
+
networkFeesWei,
|
|
32773
33596
|
fromTokenDecimals: token.decimals,
|
|
32774
33597
|
});
|
|
32775
|
-
}, [
|
|
33598
|
+
}, [networkFeesWei, token, chainFeeParams, gasToken]);
|
|
32776
33599
|
return {
|
|
32777
33600
|
estimatedGas,
|
|
32778
33601
|
gasBalanceNeeded,
|
|
32779
33602
|
isBalanceEnough,
|
|
32780
33603
|
tokenPaysGasFees: chainFeeParams?.fromTokenPaysGasFees ?? false,
|
|
32781
|
-
isLoading,
|
|
33604
|
+
isLoading: isLoading || isFetching,
|
|
33605
|
+
isError,
|
|
33606
|
+
refetchGasEstimate: refetch,
|
|
32782
33607
|
isGasBalanceEnough,
|
|
32783
33608
|
minAmountValueWarnMsg,
|
|
32784
33609
|
};
|
|
@@ -33201,9 +34026,8 @@ function useSendTransaction({ to, amount, token, chain, }) {
|
|
|
33201
34026
|
chain,
|
|
33202
34027
|
});
|
|
33203
34028
|
break;
|
|
33204
|
-
case ChainType.CANTON:
|
|
33205
|
-
|
|
33206
|
-
throw new Error(`Send not implemented for chain type ${chain.chainType}`);
|
|
34029
|
+
case ChainType.CANTON: {
|
|
34030
|
+
throw new Error("Not implemented");
|
|
33207
34031
|
}
|
|
33208
34032
|
}
|
|
33209
34033
|
return {
|
|
@@ -33409,8 +34233,7 @@ async function getSendTransactionStatus({ chain, txHash, }) {
|
|
|
33409
34233
|
chain,
|
|
33410
34234
|
});
|
|
33411
34235
|
case ChainType.CANTON:
|
|
33412
|
-
|
|
33413
|
-
throw new Error(`Send not implemented for chain type ${chain.chainType}`);
|
|
34236
|
+
throw new Error("Not implemented");
|
|
33414
34237
|
}
|
|
33415
34238
|
}
|
|
33416
34239
|
|
|
@@ -33681,6 +34504,19 @@ const useApproval = ({ squidRoute, }) => {
|
|
|
33681
34504
|
const { getChainType } = useSquidChains();
|
|
33682
34505
|
const { switchChainAsync } = useSwitchChain();
|
|
33683
34506
|
const { connectedAddress: { address: sourceUserAddress }, } = useMultiChainWallet(fromChain);
|
|
34507
|
+
const arcNativeBalanceQuery = useBalance({
|
|
34508
|
+
address: sourceUserAddress,
|
|
34509
|
+
chainId: Number(fromChain?.chainId),
|
|
34510
|
+
query: { enabled: false },
|
|
34511
|
+
});
|
|
34512
|
+
const arcTokenBalanceQuery = useReadContract({
|
|
34513
|
+
address: fromToken?.address,
|
|
34514
|
+
abi: erc20Abi,
|
|
34515
|
+
functionName: "balanceOf",
|
|
34516
|
+
args: [sourceUserAddress],
|
|
34517
|
+
chainId: Number(fromChain?.chainId),
|
|
34518
|
+
query: { enabled: false },
|
|
34519
|
+
});
|
|
33684
34520
|
const isSagaEvmSameChainSwap = isSameChain &&
|
|
33685
34521
|
fromChain?.chainId.toString() === CHAIN_IDS.SAGA_EVM.toString();
|
|
33686
34522
|
// Swaps on SagaEVM are regular EVM transactions, following the standard ERC20 approve/allowance mechanism.
|
|
@@ -33841,13 +34677,20 @@ const useApproval = ({ squidRoute, }) => {
|
|
|
33841
34677
|
return false;
|
|
33842
34678
|
}
|
|
33843
34679
|
}, {
|
|
33844
|
-
onSuccess: async () => {
|
|
34680
|
+
onSuccess: async (approved) => {
|
|
34681
|
+
if (approved && isArcChain(fromChain?.chainId)) {
|
|
34682
|
+
await Promise.all([
|
|
34683
|
+
arcNativeBalanceQuery.refetch({ throwOnError: true }),
|
|
34684
|
+
arcTokenBalanceQuery.refetch({ throwOnError: true }),
|
|
34685
|
+
]);
|
|
34686
|
+
queryClient.invalidateQueries(getPrefixKey(QueryKeys.AllTokensBalance));
|
|
34687
|
+
}
|
|
33845
34688
|
await allowanceQuery?.refetch();
|
|
33846
34689
|
queryClient.invalidateQueries(getPrefixKey(QueryKeys.RouteApproved));
|
|
33847
34690
|
// After an approval, we refetch the transaction query with all required parameters
|
|
33848
34691
|
// This is to ensure we're using the latest expiry timestamp
|
|
33849
34692
|
if (squidRoute) {
|
|
33850
|
-
queryClient.refetchQueries({
|
|
34693
|
+
await queryClient.refetchQueries({
|
|
33851
34694
|
queryKey: keys().transaction(squidRoute.params.fromChain, squidRoute.params.toChain, squidRoute.params.toToken, squidRoute.params.fromToken, fromPrice, squidRoute.params.slippage, squidRoute.params.fromAddress, squidRoute.params.bypassGuardrails, squidRoute.params.toAddress, squidRoute.params.fallbackAddresses?.[0]?.address, squidRoute.params.quoteOnly, getChainType(squidRoute.params.fromChain), squidRoute.params.preHook, squidRoute.params.postHook,
|
|
33852
34695
|
// TODO: update types
|
|
33853
34696
|
squidRoute.params?.overrideGasRefundAddress),
|
|
@@ -37031,342 +37874,6 @@ coin.DecProto = {
|
|
|
37031
37874
|
|
|
37032
37875
|
} (tx));
|
|
37033
37876
|
|
|
37034
|
-
const vParty = (party) => ({ party });
|
|
37035
|
-
const vText = (text) => ({ text });
|
|
37036
|
-
const vNumeric = (numeric) => ({ numeric });
|
|
37037
|
-
const vContractId = (contractId) => ({
|
|
37038
|
-
contractId,
|
|
37039
|
-
});
|
|
37040
|
-
const vList = (elements) => ({
|
|
37041
|
-
list: { elements },
|
|
37042
|
-
});
|
|
37043
|
-
const vRecord = (fields) => ({
|
|
37044
|
-
record: { fields: fields.map(([label, value]) => ({ label, value })) },
|
|
37045
|
-
});
|
|
37046
|
-
const vTextMap = (entries) => ({ textMap: { entries } });
|
|
37047
|
-
const vTimestamp = (isoString) => ({
|
|
37048
|
-
timestamp: String(Math.floor(new Date(isoString).getTime() * 1000)),
|
|
37049
|
-
});
|
|
37050
|
-
function isRecord(value) {
|
|
37051
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37052
|
-
}
|
|
37053
|
-
function normalizeChoiceContextValue(value) {
|
|
37054
|
-
if (typeof value === "string")
|
|
37055
|
-
return value;
|
|
37056
|
-
if (!isRecord(value) || typeof value.tag !== "string")
|
|
37057
|
-
return null;
|
|
37058
|
-
switch (value.tag) {
|
|
37059
|
-
case "AV_Text":
|
|
37060
|
-
case "AV_ContractId":
|
|
37061
|
-
return typeof value.value === "string"
|
|
37062
|
-
? { tag: value.tag, value: value.value }
|
|
37063
|
-
: null;
|
|
37064
|
-
case "AV_Bool":
|
|
37065
|
-
return typeof value.value === "boolean"
|
|
37066
|
-
? { tag: value.tag, value: value.value }
|
|
37067
|
-
: null;
|
|
37068
|
-
case "AV_List":
|
|
37069
|
-
if (!Array.isArray(value.value))
|
|
37070
|
-
return null;
|
|
37071
|
-
return {
|
|
37072
|
-
tag: value.tag,
|
|
37073
|
-
value: value.value.flatMap((entry) => {
|
|
37074
|
-
const normalized = normalizeChoiceContextValue(entry);
|
|
37075
|
-
return normalized ? [normalized] : [];
|
|
37076
|
-
}),
|
|
37077
|
-
};
|
|
37078
|
-
default: {
|
|
37079
|
-
const inner = value.value;
|
|
37080
|
-
if (typeof inner === "string" ||
|
|
37081
|
-
typeof inner === "number" ||
|
|
37082
|
-
typeof inner === "boolean" ||
|
|
37083
|
-
inner === null) {
|
|
37084
|
-
return { tag: value.tag, value: inner };
|
|
37085
|
-
}
|
|
37086
|
-
if (Array.isArray(inner)) {
|
|
37087
|
-
return {
|
|
37088
|
-
tag: value.tag,
|
|
37089
|
-
value: inner.flatMap((entry) => {
|
|
37090
|
-
const normalized = normalizeChoiceContextValue(entry);
|
|
37091
|
-
return normalized ? [normalized] : [];
|
|
37092
|
-
}),
|
|
37093
|
-
};
|
|
37094
|
-
}
|
|
37095
|
-
if (!isRecord(inner))
|
|
37096
|
-
return null;
|
|
37097
|
-
const normalizedObject = {};
|
|
37098
|
-
for (const [key, entry] of Object.entries(inner)) {
|
|
37099
|
-
if (typeof entry !== "string" &&
|
|
37100
|
-
typeof entry !== "number" &&
|
|
37101
|
-
typeof entry !== "boolean" &&
|
|
37102
|
-
entry !== null) {
|
|
37103
|
-
return null;
|
|
37104
|
-
}
|
|
37105
|
-
normalizedObject[key] = entry;
|
|
37106
|
-
}
|
|
37107
|
-
return { tag: value.tag, value: normalizedObject };
|
|
37108
|
-
}
|
|
37109
|
-
}
|
|
37110
|
-
}
|
|
37111
|
-
function stringifyChoiceContextValue(value) {
|
|
37112
|
-
return typeof value === "string" ? value : String(value);
|
|
37113
|
-
}
|
|
37114
|
-
function choiceContextValueToAnyValue(value) {
|
|
37115
|
-
if (typeof value === "string") {
|
|
37116
|
-
return {
|
|
37117
|
-
variant: { constructor: "AV_Text", value: vText(value) },
|
|
37118
|
-
};
|
|
37119
|
-
}
|
|
37120
|
-
switch (value.tag) {
|
|
37121
|
-
case "AV_ContractId":
|
|
37122
|
-
if (typeof value.value !== "string") {
|
|
37123
|
-
throw new TypeError("AV_ContractId values must be strings");
|
|
37124
|
-
}
|
|
37125
|
-
return {
|
|
37126
|
-
variant: { constructor: value.tag, value: vContractId(value.value) },
|
|
37127
|
-
};
|
|
37128
|
-
case "AV_Bool":
|
|
37129
|
-
if (typeof value.value !== "boolean") {
|
|
37130
|
-
throw new TypeError("AV_Bool values must be booleans");
|
|
37131
|
-
}
|
|
37132
|
-
return {
|
|
37133
|
-
variant: { constructor: value.tag, value: { bool: value.value } },
|
|
37134
|
-
};
|
|
37135
|
-
case "AV_List":
|
|
37136
|
-
if (!Array.isArray(value.value)) {
|
|
37137
|
-
throw new TypeError("AV_List values must be arrays");
|
|
37138
|
-
}
|
|
37139
|
-
return {
|
|
37140
|
-
variant: {
|
|
37141
|
-
constructor: value.tag,
|
|
37142
|
-
value: vList(value.value.map(choiceContextValueToAnyValue)),
|
|
37143
|
-
},
|
|
37144
|
-
};
|
|
37145
|
-
default:
|
|
37146
|
-
return {
|
|
37147
|
-
variant: {
|
|
37148
|
-
constructor: value.tag,
|
|
37149
|
-
value: vText(stringifyChoiceContextValue(value.value)),
|
|
37150
|
-
},
|
|
37151
|
-
};
|
|
37152
|
-
}
|
|
37153
|
-
}
|
|
37154
|
-
|
|
37155
|
-
/** Metadata key used by Splice token-standard transfers to carry our Squid orderhash memo. */
|
|
37156
|
-
const CANTON_MEMO_KEY = "splice.lfdecentralizedtrust.org/reason";
|
|
37157
|
-
/** Interface id for the transfer factory contract returned by the token registry. */
|
|
37158
|
-
const TRANSFER_FACTORY_INTERFACE_ID = "#splice-api-token-transfer-instruction-v1:Splice.Api.Token.TransferInstructionV1:TransferFactory";
|
|
37159
|
-
/** Choice exercised on the transfer factory to create the token-standard transfer. */
|
|
37160
|
-
const TRANSFER_FACTORY_CHOICE = "TransferFactory_Transfer";
|
|
37161
|
-
/** CIP-056 (non-Amulet) tokens expose a registrar parameterized by admin party. */
|
|
37162
|
-
const CIP056_REGISTRAR_BASE = "https://api.utilities.digitalasset.com/api/token-standard/v0/registrars";
|
|
37163
|
-
const TRANSFER_REQUESTED_AT_SKEW_MS = 60_000;
|
|
37164
|
-
const TRANSFER_EXECUTE_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
37165
|
-
function resolveCantonRegistryUrl(instrument) {
|
|
37166
|
-
if (instrument.id === CANTON_AMULET_INSTRUMENT_ID) {
|
|
37167
|
-
return CANTON_AMULET_REGISTRY_URL;
|
|
37168
|
-
}
|
|
37169
|
-
return `${CIP056_REGISTRAR_BASE}/${encodeURIComponent(instrument.admin)}`;
|
|
37170
|
-
}
|
|
37171
|
-
/**
|
|
37172
|
-
* Build the plain JSON arguments expected by the registry transfer-factory
|
|
37173
|
-
* endpoint before it adds choice context and disclosed contracts.
|
|
37174
|
-
*/
|
|
37175
|
-
function buildTransferChoiceArgs({ sender, receiver, amount, instrument, inputHoldingCids, memo, nowMs, }) {
|
|
37176
|
-
return {
|
|
37177
|
-
expectedAdmin: instrument.admin,
|
|
37178
|
-
transfer: {
|
|
37179
|
-
sender,
|
|
37180
|
-
receiver,
|
|
37181
|
-
amount,
|
|
37182
|
-
instrumentId: { admin: instrument.admin, id: instrument.id },
|
|
37183
|
-
requestedAt: new Date(nowMs - TRANSFER_REQUESTED_AT_SKEW_MS).toISOString(),
|
|
37184
|
-
executeBefore: new Date(nowMs + TRANSFER_EXECUTE_WINDOW_MS).toISOString(),
|
|
37185
|
-
inputHoldingCids,
|
|
37186
|
-
meta: { values: { [CANTON_MEMO_KEY]: memo } },
|
|
37187
|
-
},
|
|
37188
|
-
extraArgs: { context: { values: {} }, meta: { values: {} } },
|
|
37189
|
-
};
|
|
37190
|
-
}
|
|
37191
|
-
/**
|
|
37192
|
-
* Canton's Holding contracts follow Bitcoin-style UTXOs model.
|
|
37193
|
-
*
|
|
37194
|
-
* Pick Holding contract ids covering `amount` for the instrument: prefer a
|
|
37195
|
-
* single exact-amount holding, else accumulate largest-first.
|
|
37196
|
-
*/
|
|
37197
|
-
function selectInputHoldingCids(holdings, instrument, amount) {
|
|
37198
|
-
const spendableHoldings = holdings.filter((h) => !h.locked &&
|
|
37199
|
-
h.instrument.admin === instrument.admin &&
|
|
37200
|
-
h.instrument.id === instrument.id);
|
|
37201
|
-
const target = new BigNumber(amount);
|
|
37202
|
-
const exact = spendableHoldings.find((h) => new BigNumber(h.amount).eq(target));
|
|
37203
|
-
if (exact)
|
|
37204
|
-
return [exact.contractId];
|
|
37205
|
-
const sorted = [...spendableHoldings].sort((a, b) => new BigNumber(b.amount).comparedTo(new BigNumber(a.amount)));
|
|
37206
|
-
const selected = [];
|
|
37207
|
-
let sum = new BigNumber(0);
|
|
37208
|
-
for (const holding of sorted) {
|
|
37209
|
-
selected.push(holding.contractId);
|
|
37210
|
-
sum = sum.plus(holding.amount);
|
|
37211
|
-
if (sum.gte(target))
|
|
37212
|
-
break;
|
|
37213
|
-
}
|
|
37214
|
-
if (sum.lt(target)) {
|
|
37215
|
-
throw new Error("Insufficient Canton holdings to cover transfer amount");
|
|
37216
|
-
}
|
|
37217
|
-
return selected;
|
|
37218
|
-
}
|
|
37219
|
-
async function fetchInputHoldingCids(connector, party, instrument, amount) {
|
|
37220
|
-
const ledgerEnd = await connector.ledgerApi({
|
|
37221
|
-
requestMethod: "get",
|
|
37222
|
-
resource: "/v2/state/ledger-end",
|
|
37223
|
-
});
|
|
37224
|
-
const activeContracts = await connector.ledgerApi({
|
|
37225
|
-
requestMethod: "post",
|
|
37226
|
-
resource: "/v2/state/active-contracts",
|
|
37227
|
-
body: buildHoldingsAcsRequestBody(party, String(ledgerEnd.offset)),
|
|
37228
|
-
});
|
|
37229
|
-
return selectInputHoldingCids(parseCantonHoldings(activeContracts), instrument, amount);
|
|
37230
|
-
}
|
|
37231
|
-
/**
|
|
37232
|
-
* Ask the token registry for the transfer factory contract and extra context
|
|
37233
|
-
* required to exercise its transfer choice.
|
|
37234
|
-
*/
|
|
37235
|
-
async function fetchTransferFactory(registryUrl, choiceArgs) {
|
|
37236
|
-
const response = await fetch(`${registryUrl}/registry/transfer-instruction/v1/transfer-factory`, {
|
|
37237
|
-
method: "POST",
|
|
37238
|
-
headers: { "Content-Type": "application/json" },
|
|
37239
|
-
body: JSON.stringify({
|
|
37240
|
-
choiceArguments: choiceArgs,
|
|
37241
|
-
excludeDebugFields: true,
|
|
37242
|
-
}),
|
|
37243
|
-
});
|
|
37244
|
-
if (!response.ok) {
|
|
37245
|
-
throw new Error(`Canton transfer-factory request failed (${response.status})`);
|
|
37246
|
-
}
|
|
37247
|
-
return response.json();
|
|
37248
|
-
}
|
|
37249
|
-
/**
|
|
37250
|
-
* Convert transfer choice args into strict Daml Value JSON for the wallet's
|
|
37251
|
-
* prepareExecute ExerciseCommand.
|
|
37252
|
-
*/
|
|
37253
|
-
function buildPrepareChoiceArgument(choiceArgs) {
|
|
37254
|
-
const contextValues = Object.entries(choiceArgs.extraArgs.context?.values ?? {})
|
|
37255
|
-
.map(([key, value]) => {
|
|
37256
|
-
const normalized = normalizeChoiceContextValue(value);
|
|
37257
|
-
return normalized
|
|
37258
|
-
? { key, value: choiceContextValueToAnyValue(normalized) }
|
|
37259
|
-
: undefined;
|
|
37260
|
-
})
|
|
37261
|
-
.filter((entry) => Boolean(entry));
|
|
37262
|
-
return vRecord([
|
|
37263
|
-
["expectedAdmin", vParty(choiceArgs.expectedAdmin)],
|
|
37264
|
-
[
|
|
37265
|
-
"transfer",
|
|
37266
|
-
vRecord([
|
|
37267
|
-
["sender", vParty(choiceArgs.transfer.sender)],
|
|
37268
|
-
["receiver", vParty(choiceArgs.transfer.receiver)],
|
|
37269
|
-
["amount", vNumeric(choiceArgs.transfer.amount)],
|
|
37270
|
-
[
|
|
37271
|
-
"instrumentId",
|
|
37272
|
-
vRecord([
|
|
37273
|
-
["admin", vParty(choiceArgs.transfer.instrumentId.admin)],
|
|
37274
|
-
["id", vText(choiceArgs.transfer.instrumentId.id)],
|
|
37275
|
-
]),
|
|
37276
|
-
],
|
|
37277
|
-
["requestedAt", vTimestamp(choiceArgs.transfer.requestedAt)],
|
|
37278
|
-
["executeBefore", vTimestamp(choiceArgs.transfer.executeBefore)],
|
|
37279
|
-
[
|
|
37280
|
-
"inputHoldingCids",
|
|
37281
|
-
vList(choiceArgs.transfer.inputHoldingCids.map(vContractId)),
|
|
37282
|
-
],
|
|
37283
|
-
[
|
|
37284
|
-
"meta",
|
|
37285
|
-
vRecord([
|
|
37286
|
-
[
|
|
37287
|
-
"values",
|
|
37288
|
-
vTextMap(Object.entries(choiceArgs.transfer.meta.values).map(([key, value]) => ({ key, value: vText(value) }))),
|
|
37289
|
-
],
|
|
37290
|
-
]),
|
|
37291
|
-
],
|
|
37292
|
-
]),
|
|
37293
|
-
],
|
|
37294
|
-
[
|
|
37295
|
-
"extraArgs",
|
|
37296
|
-
vRecord([
|
|
37297
|
-
["context", vRecord([["values", vTextMap(contextValues)]])],
|
|
37298
|
-
["meta", vRecord([["values", vTextMap([])]])],
|
|
37299
|
-
]),
|
|
37300
|
-
],
|
|
37301
|
-
]);
|
|
37302
|
-
}
|
|
37303
|
-
/**
|
|
37304
|
-
* Convert a registry disclosed contract into the wallet submission shape,
|
|
37305
|
-
* dropping debug fields and entries without a usable createdEventBlob.
|
|
37306
|
-
*/
|
|
37307
|
-
function toDisclosedContract(raw) {
|
|
37308
|
-
if (typeof raw.createdEventBlob !== "string")
|
|
37309
|
-
return null;
|
|
37310
|
-
return {
|
|
37311
|
-
createdEventBlob: raw.createdEventBlob,
|
|
37312
|
-
contractId: typeof raw.contractId === "string" ? raw.contractId : undefined,
|
|
37313
|
-
synchronizerId: typeof raw.synchronizerId === "string" ? raw.synchronizerId : undefined,
|
|
37314
|
-
};
|
|
37315
|
-
}
|
|
37316
|
-
/**
|
|
37317
|
-
* Build a Splice token-standard transfer of `amount` of `token` from `sender`
|
|
37318
|
-
* to `receiver`, carrying `memo`, ready to hand to a wallet's prepareExecute.
|
|
37319
|
-
* Returns the full prepareExecute params (commandId + commands + actAs +
|
|
37320
|
-
* disclosedContracts).
|
|
37321
|
-
*/
|
|
37322
|
-
async function buildCantonTransfer(connector, { sender, receiver, amount, token, memo, nowMs, }) {
|
|
37323
|
-
if (!token.originalAddress) {
|
|
37324
|
-
throw new Error("Canton token originalAddress is required");
|
|
37325
|
-
}
|
|
37326
|
-
const instrument = parseCantonInstrument(token.originalAddress);
|
|
37327
|
-
if (!instrument) {
|
|
37328
|
-
throw new Error(`Invalid Canton token address: ${token.originalAddress}`);
|
|
37329
|
-
}
|
|
37330
|
-
const registryUrl = resolveCantonRegistryUrl(instrument);
|
|
37331
|
-
const inputHoldingCids = await fetchInputHoldingCids(connector, sender, instrument, amount);
|
|
37332
|
-
const choiceArgs = buildTransferChoiceArgs({
|
|
37333
|
-
sender,
|
|
37334
|
-
receiver,
|
|
37335
|
-
amount,
|
|
37336
|
-
instrument,
|
|
37337
|
-
inputHoldingCids,
|
|
37338
|
-
memo,
|
|
37339
|
-
nowMs,
|
|
37340
|
-
});
|
|
37341
|
-
const factory = await fetchTransferFactory(registryUrl, choiceArgs);
|
|
37342
|
-
const choiceContextData = factory.choiceContext.choiceContextData;
|
|
37343
|
-
if (!choiceContextData) {
|
|
37344
|
-
throw new Error("Transfer factory choice context is missing");
|
|
37345
|
-
}
|
|
37346
|
-
choiceArgs.extraArgs.context = choiceContextData;
|
|
37347
|
-
const disclosedContracts = (factory.choiceContext?.disclosedContracts ?? []).flatMap((raw) => {
|
|
37348
|
-
const disclosedContract = toDisclosedContract(raw);
|
|
37349
|
-
return disclosedContract ? [disclosedContract] : [];
|
|
37350
|
-
});
|
|
37351
|
-
// Command ID: client-supplied identifier used to deduplicate submissions
|
|
37352
|
-
const commandId = `canton-${memo}`;
|
|
37353
|
-
return {
|
|
37354
|
-
commandId,
|
|
37355
|
-
commands: [
|
|
37356
|
-
{
|
|
37357
|
-
ExerciseCommand: {
|
|
37358
|
-
templateId: TRANSFER_FACTORY_INTERFACE_ID,
|
|
37359
|
-
contractId: factory.factoryId,
|
|
37360
|
-
choice: TRANSFER_FACTORY_CHOICE,
|
|
37361
|
-
choiceArgument: buildPrepareChoiceArgument(choiceArgs),
|
|
37362
|
-
},
|
|
37363
|
-
},
|
|
37364
|
-
],
|
|
37365
|
-
actAs: [sender],
|
|
37366
|
-
disclosedContracts,
|
|
37367
|
-
};
|
|
37368
|
-
}
|
|
37369
|
-
|
|
37370
37877
|
const useExecuteTransaction = (squidRoute) => {
|
|
37371
37878
|
const { fromChain, toChain, fromToken, toToken, isSameChain } = useSwap();
|
|
37372
37879
|
// A route completes on source tx only if it's same-chain AND
|
|
@@ -37981,7 +38488,7 @@ const useExecuteTransaction = (squidRoute) => {
|
|
|
37981
38488
|
}
|
|
37982
38489
|
const amount = formatBNToReadable(fromAmount, token.decimals);
|
|
37983
38490
|
dispatchSignatureRequestEvent(route);
|
|
37984
|
-
const
|
|
38491
|
+
const result = await cantonSigner.transfer({
|
|
37985
38492
|
sender: sourceUserAddress,
|
|
37986
38493
|
receiver,
|
|
37987
38494
|
amount,
|
|
@@ -37989,15 +38496,14 @@ const useExecuteTransaction = (squidRoute) => {
|
|
|
37989
38496
|
memo: orderHash,
|
|
37990
38497
|
nowMs: Date.now(),
|
|
37991
38498
|
});
|
|
37992
|
-
const
|
|
37993
|
-
const txHash = result.tx?.payload?.updateId ?? "";
|
|
38499
|
+
const txHash = result.updateId;
|
|
37994
38500
|
if (txHash) {
|
|
37995
38501
|
resetQueriesAfterTxSigned();
|
|
37996
38502
|
}
|
|
37997
38503
|
WidgetEvents.getInstance().dispatchSwapExecuteCall(route, txHash);
|
|
37998
38504
|
const txParams = setTransactionState({
|
|
37999
38505
|
route,
|
|
38000
|
-
txHash
|
|
38506
|
+
txHash,
|
|
38001
38507
|
userAddress: sourceUserAddress,
|
|
38002
38508
|
status: TransactionStatus.INITIAL_LOADING,
|
|
38003
38509
|
sourceStatus: TransactionStatus.ONGOING,
|
|
@@ -38280,7 +38786,7 @@ refetchIntervalInBackground = false, refetchInterval = 30000, quoteOnly = true,
|
|
|
38280
38786
|
//
|
|
38281
38787
|
// If deposit address is not selected, we use the connected address as the source address instead
|
|
38282
38788
|
const sourceUserAddress = isDepositAddressActive
|
|
38283
|
-
? depositRefundAddress ?? sourceConnectedAddress
|
|
38789
|
+
? (depositRefundAddress ?? sourceConnectedAddress)
|
|
38284
38790
|
: sourceConnectedAddress;
|
|
38285
38791
|
const squidRouteQueryKeys = useMemo(() => keys().transaction(fromChain?.chainId, toChain?.chainId, toToken?.address, fromToken?.address, fromPrice, config.slippage, sourceUserAddress, config.degenMode, destinationAddress, fallbackAddress, quoteOnly, fromChain?.chainType, config.preHook, config.postHook, config.overrideGasRefundAddress), [
|
|
38286
38792
|
fromChain?.chainId,
|
|
@@ -38572,6 +39078,10 @@ const useAutoConnect = () => {
|
|
|
38572
39078
|
const { chains } = useSquidChains();
|
|
38573
39079
|
const { isInitialized } = useConfigStore();
|
|
38574
39080
|
const hasAttemptedReconnect = useRef(false);
|
|
39081
|
+
const hasAttemptedCantonReconnect = useRef(false);
|
|
39082
|
+
const { autoConnectCanton, wallets: cantonWallets } = useCantonContext();
|
|
39083
|
+
const recentCantonWalletId = useWalletStore((state) => state.recentConnectorIds[ChainType.CANTON]);
|
|
39084
|
+
const hasRecentCantonWallet = cantonWallets.some((wallet) => wallet.connectorId === recentCantonWalletId);
|
|
38575
39085
|
const { autoConnectEvm } = useEvmContext();
|
|
38576
39086
|
const { autoConnectSolana } = useSolanaContext();
|
|
38577
39087
|
const { autoConnectSui } = useSuiContext();
|
|
@@ -38639,6 +39149,15 @@ const useAutoConnect = () => {
|
|
|
38639
39149
|
useEffect(() => {
|
|
38640
39150
|
autoConnect();
|
|
38641
39151
|
}, [autoConnect]);
|
|
39152
|
+
useEffect(() => {
|
|
39153
|
+
if (!isInitialized ||
|
|
39154
|
+
chains.length === 0 ||
|
|
39155
|
+
!hasRecentCantonWallet ||
|
|
39156
|
+
hasAttemptedCantonReconnect.current)
|
|
39157
|
+
return;
|
|
39158
|
+
hasAttemptedCantonReconnect.current = true;
|
|
39159
|
+
autoConnectCanton().catch(() => undefined);
|
|
39160
|
+
}, [autoConnectCanton, hasRecentCantonWallet, isInitialized, chains.length]);
|
|
38642
39161
|
return { autoConnect };
|
|
38643
39162
|
};
|
|
38644
39163
|
|
|
@@ -38947,5 +39466,5 @@ const SquidProvider = ({ children, config, placeholder, }) => {
|
|
|
38947
39466
|
React.createElement(CosmosProvider, null, children))))))))))) : (placeholder);
|
|
38948
39467
|
};
|
|
38949
39468
|
|
|
38950
|
-
export { useWalletStore as $, AxelarStatusResponseType as A, useHederaAccountActivation as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useHederaTokenAssociations as E, useKeyboardNavigation as F, useSquidQueryClient as G, HistoryTxType as H, useSquid as I, useStellarAccountActivation as J, useStellarTrustLine as K, useAddressBookStore as L, useAssetsColorsStore as M, Nr as N, useFavoriteTokensStore as O, useHistoryStore as P, QueryKeys as Q, useSendTransactionStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useConfigStore as U, useSquidStore as V, Wo as W, XamanXrplNetwork as X, useSwapRoutePersistStore as Y, useTransactionStore as Z, ConnectingWalletStatus as _, WindowWalletFlag as a, useAvailableQuotes as a$, useDepositAddress as a0, useSwap as a1, buildUrlSearchParamsFromSwapEvent as a2, parseInitialAssetsFromUrl as a3, useUrlSwapParams as a4, useAllConnectedWalletBalances as a5, useAllTokensWithBalanceForChainType as a6, useCosmosBalance as a7, useEvmBalance as a8, useMultiChainBalance as a9, useRouteWarnings as aA, useSendTransactionStatus as aB, useSwapTransactionStatus as aC, useAvatar as aD, useHistory as aE, useDebouncedValue as aF, useAddToken as aG, useAutoConnect as aH, useEnsDataForAddress as aI, useEnsSearch as aJ, useGnosisContext as aK, useIsSameAddressAndGnosisContext as aL, useIntegratorContext as aM, useMultiChainWallet as aN, useSigner as aO, useWallet as aP, useWallets as aQ, useXrplTrustLine as aR, TX_STATUS_CONSTANTS as aS, FINAL_TRANSACTION_STATUSES as aT, useGetFiatQuote as aU, useGetOnRampConfig as aV, useExecuteFiatQuote as aW, useFiatOnRampTxStatus as aX, useFiatTransactions as aY, useCurrencyDetails as aZ, useCountryDetails as a_, useMultipleTokenPrices as aa, useBitcoinNativeBalance as ab, useCosmosNativeBalance as ac, useEvmNativeBalance as ad, useNativeBalance as ae, useSolanaNativeBalance as af, useStellarNativeBalance as ag, useSuiNativeBalance as ah, useXrplNativeBalance as ai, useNativeTokenForChain as aj, useSingleTokenPrice as ak, useSourceChainGasToken as al, useSquidTokens as am, useHistoricalData as an, useTokensData as ao, useEstimateSendTransaction as ap, useSendTransaction as aq, useSendTransactionGas as ar, useAllTransactionsStatus as as, useApproval as at, useDepositTransactionStatus as au, useEstimate as av, useEstimatePriceImpact as aw, useExecuteTransaction as ax, useGetRoute as ay, useGetRouteWrapper as az, DEFAULT_ROUTE_REFETCH_INTERVAL as b,
|
|
38951
|
-
//# sourceMappingURL=index-
|
|
39469
|
+
export { useWalletStore as $, AxelarStatusResponseType as A, useHederaAccountActivation as B, CHAIN_IDS as C, DEFAULT_LOCALE as D, useHederaTokenAssociations as E, useKeyboardNavigation as F, useSquidQueryClient as G, HistoryTxType as H, useSquid as I, useStellarAccountActivation as J, useStellarTrustLine as K, useAddressBookStore as L, useAssetsColorsStore as M, Nr as N, useFavoriteTokensStore as O, useHistoryStore as P, QueryKeys as Q, useSendTransactionStore as R, SquidStatusErrorType as S, TransactionErrorType as T, useConfigStore as U, useSquidStore as V, Wo as W, XamanXrplNetwork as X, useSwapRoutePersistStore as Y, useTransactionStore as Z, ConnectingWalletStatus as _, WindowWalletFlag as a, useAvailableQuotes as a$, useDepositAddress as a0, useSwap as a1, buildUrlSearchParamsFromSwapEvent as a2, parseInitialAssetsFromUrl as a3, useUrlSwapParams as a4, useAllConnectedWalletBalances as a5, useAllTokensWithBalanceForChainType as a6, useCosmosBalance as a7, useEvmBalance as a8, useMultiChainBalance as a9, useRouteWarnings as aA, useSendTransactionStatus as aB, useSwapTransactionStatus as aC, useAvatar as aD, useHistory as aE, useDebouncedValue as aF, useAddToken as aG, useAutoConnect as aH, useEnsDataForAddress as aI, useEnsSearch as aJ, useGnosisContext as aK, useIsSameAddressAndGnosisContext as aL, useIntegratorContext as aM, useMultiChainWallet as aN, useSigner as aO, useWallet as aP, useWallets as aQ, useXrplTrustLine as aR, TX_STATUS_CONSTANTS as aS, FINAL_TRANSACTION_STATUSES as aT, useGetFiatQuote as aU, useGetOnRampConfig as aV, useExecuteFiatQuote as aW, useFiatOnRampTxStatus as aX, useFiatTransactions as aY, useCurrencyDetails as aZ, useCountryDetails as a_, useMultipleTokenPrices as aa, useBitcoinNativeBalance as ab, useCosmosNativeBalance as ac, useEvmNativeBalance as ad, useNativeBalance as ae, useSolanaNativeBalance as af, useStellarNativeBalance as ag, useSuiNativeBalance as ah, useXrplNativeBalance as ai, useNativeTokenForChain as aj, useSingleTokenPrice as ak, useSourceChainGasToken as al, useSquidTokens as am, useHistoricalData as an, useTokensData as ao, useEstimateSendTransaction as ap, useSendTransaction as aq, useSendTransactionGas as ar, useAllTransactionsStatus as as, useApproval as at, useDepositTransactionStatus as au, useEstimate as av, useEstimatePriceImpact as aw, useExecuteTransaction as ax, useGetRoute as ay, useGetRouteWrapper as az, DEFAULT_ROUTE_REFETCH_INTERVAL as b, WidgetEvents as b$, useRecommendedQuote as b0, useGetOnrampPaymentTypes as b1, useSuggestedFiatAmounts as b2, SquidProvider as b3, EnsService as b4, getXummClient as b5, isXamanXAppContext as b6, getQueryHeaders as b7, getStatusCode as b8, is404Error as b9, getConfigWithDefaults as bA, randomIntFromInterval as bB, getTokensForChain as bC, getFirstAvailableChainId as bD, fetchHighestBalanceToken as bE, getTokenAddressForSelection as bF, getInitialOrDefaultTokenAddressForChain as bG, getInitialTokenAddressForChain as bH, filterTokensForDestination as bI, getInitialChainIdFromConfig as bJ, getCosmosKey as bK, getKeysSettled as bL, getAllKeysForSupportedCosmosChains as bM, isCosmosAddressValid as bN, getCosmosSigningClient as bO, getCosmosChainInfosObject as bP, connectCosmosWallet as bQ, isFallbackAddressNeeded as bR, suggestChainOrThrow as bS, normalizeError as bT, transactionErrorCode as bU, isUserRejectionError as bV, getTransactionError as bW, handleTransactionErrorEvents as bX, isSwapRouteError as bY, isStatusError as bZ, createQuoteRequestParamsHash as b_, assetsBaseUrl as ba, shareSubgraphId as bb, sortTokensBySharedSubgraphIds as bc, getSupportedChainIdsForDirection as bd, filterChains as be, filterTokens as bf, getTokenImage as bg, normalizeSwapParamsForSelection as bh, getNewSwapParamsFromInput as bi, sortAllTokens as bj, findToken as bk, findNativeToken as bl, normalizeIbcAddress as bm, groupTokensBySymbol as bn, groupTokensByChainId as bo, filterViewableTokens as bp, getSecretNetworkBalances as bq, getTokenAssetsKey as br, fetchAssetsColors as bs, isSupportedChainType as bt, initializeSquidData as bu, isEmptyObject as bv, normalizeTokenSymbol as bw, areTokenSymbolsCompatible as bx, isEvmosChain as by, resolveChainIdFromAsset as bz, chainTypeToNativeTokenAddressMap as c, getSwapTxStatusRefetchInterval as c$, EvmNetworkNotSupportedErrorCode as c0, addEthereumChain as c1, parseEvmAddress as c2, formatEvmWallet as c3, filterWagmiConnector as c4, waitForReceiptWithRetry as c5, getUserCountry as c6, getCountryData as c7, getCurrencyData as c8, adaptiveRound as c9, getStellarTrustLineAsset as cA, isStellarToken as cB, isStellarIssuedToken as cC, getStellarHorizonApiUrl as cD, isValidIssuedAsset as cE, isValidHorizonAsset as cF, formatTransactionHistoryDate as cG, getAxelarExplorerTxUrl as cH, getSourceExplorerTxUrl as cI, getMainExplorerUrl as cJ, formatDistance as cK, formatSeconds as cL, formatSwapTxStatusResponseForStorage as cM, simplifyRouteAction as cN, fetchSwapTransactionStatus as cO, compareTransactionIds as cP, isCoralBridgeAction as cQ, isActionCompletedOnSourceTx as cR, sleep as cS, isChainflipDepositRoute as cT, isChainflipBridgeTransaction as cU, isOnChainTxData as cV, isDepositAddressDirectTransferRoute as cW, getHistoryTransactionId as cX, getStepStatuses as cY, getHalfSuccessState as cZ, getStepsInfos as c_, getSuggestedAmountsForCurrency as ca, HederaExtensionHelper as cb, convertHederaAccountIdToEvmAddress as cc, convertEvmAddressToHederaAccountId as cd, scaleHbarToWei as ce, scaleWeiToHbar as cf, parseToBigInt as cg, roundNumericValue as ch, formatUnitsRounded as ci, formatTokenAmount as cj, formatUsdAmount as ck, trimExtraDecimals as cl, getNumericValue as cm, cleanAmount as cn, convertTokenAmountToUSD as co, convertUSDToTokenAmount as cp, calculateTotal24hChange as cq, getRouteExpiry as cr, searchTokens as cs, filterSolanaWallets as ct, isSolanaAddressValid as cu, executeSolanaSwap as cv, executeSolanaTransfer as cw, isStellarAddressValid as cx, getStellarNetwork as cy, stellarAddressToScVal as cz, definedInWindow as d, getSendTxStatusRefetchInterval as d0, chainflipMultihopBridgeType as d1, getBridgeType as d2, getTransactionStatus as d3, getTransactionEndStatus as d4, isHistoryTransactionPending as d5, isHistoryTransactionFailed as d6, isHistoryTransactionWarning as d7, isHistoryTransactionEnded as d8, formatHash as d9, isWalletAddressValid as da, redirectToExtensionsStore as db, populateWallets as dc, buildFallbackWallets as dd, getDefaultChain as de, sortWallets as df, areSameAddress as dg, sortAddressBook as dh, calculateTotalUsdBalanceUSD as di, addTokenToWallet as dj, isEvmChainNotSupportedError as dk, getWalletSupportedChainTypes as dl, getConnectorForChainType as dm, walletSupportsChainType as dn, connectWallet as dp, cancelConnectWallet as dq, isProblematicConnector as dr, mergeWallets as ds, isXionSmartContractAddress as dt, isXrplAddressValid as du, buildXrplTrustSetTx as dv, getXrplNetwork as dw, parseXrplPaymentTx as dx, parseXrplTokenAddress as dy, er as e, formatBNToReadable as f, chainTypeToZeroAddressMap as g, destinationAddressResetValue as h, fallbackAddressResetValue as i, nativeCantonTokenAddress as j, nativeCosmosTokenAddress as k, nativeEvmTokenAddress as l, nativeSolanaTokenAddress as m, nativeBitcoinTokenAddress as n, nativeStellarTokenAddress as o, nativeSuiTokenAddress as p, nativeXrplTokenAddress as q, CosmosProvider as r, SendTransactionStatus as s, TransactionStatus as t, useCosmosContext as u, useTrackSearchEmpty as v, walletIconBaseUrl as w, useSquidChains as x, useClient as y, useCosmosForChain as z };
|
|
39470
|
+
//# sourceMappingURL=index-CLzjMzS_.js.map
|