@circle-fin/app-kit 1.16.0 → 1.18.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/CHANGELOG.md +79 -0
- package/borrow.cjs +150 -32
- package/borrow.d.cts +38 -9
- package/borrow.d.mts +38 -9
- package/borrow.d.ts +38 -9
- package/borrow.mjs +150 -32
- package/bridge.cjs +454 -53
- package/bridge.d.cts +38 -9
- package/bridge.d.mts +38 -9
- package/bridge.d.ts +38 -9
- package/bridge.mjs +454 -53
- package/chains.cjs +10 -6
- package/chains.d.cts +1 -1
- package/chains.d.mts +1 -1
- package/chains.d.ts +1 -1
- package/chains.mjs +10 -6
- package/context.d.cts +38 -9
- package/context.d.mts +38 -9
- package/context.d.ts +38 -9
- package/earn.cjs +830 -43
- package/earn.d.cts +38 -9
- package/earn.d.mts +38 -9
- package/earn.d.ts +38 -9
- package/earn.mjs +830 -43
- package/estimateBridge.cjs +454 -53
- package/estimateBridge.d.cts +38 -9
- package/estimateBridge.d.mts +38 -9
- package/estimateBridge.d.ts +38 -9
- package/estimateBridge.mjs +454 -53
- package/estimateSwap.cjs +265 -45
- package/estimateSwap.d.cts +86 -9
- package/estimateSwap.d.mts +86 -9
- package/estimateSwap.d.ts +86 -9
- package/estimateSwap.mjs +265 -45
- package/index.cjs +1019 -73
- package/index.d.cts +373 -210
- package/index.d.mts +373 -210
- package/index.d.ts +373 -210
- package/index.mjs +1019 -73
- package/package.json +8 -8
- package/server.cjs +35 -9
- package/server.d.cts +29 -10
- package/server.d.mts +29 -10
- package/server.d.ts +29 -10
- package/server.mjs +35 -9
- package/swap.cjs +265 -45
- package/swap.d.cts +86 -9
- package/swap.d.mts +86 -9
- package/swap.d.ts +86 -9
- package/swap.mjs +265 -45
- package/unifiedBalance.cjs +139 -20
- package/unifiedBalance.mjs +139 -20
package/unifiedBalance.mjs
CHANGED
|
@@ -2404,22 +2404,73 @@ let activeRedactor = defaultMessageRedactor;
|
|
|
2404
2404
|
'0x9147d463': 'Final balance is less than the initial balance',
|
|
2405
2405
|
'0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
|
|
2406
2406
|
};
|
|
2407
|
+
/**
|
|
2408
|
+
* Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
|
|
2409
|
+
*/ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
|
|
2410
|
+
/**
|
|
2411
|
+
* Returns the revert data held by one error in a `cause` chain.
|
|
2412
|
+
*
|
|
2413
|
+
* Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
|
|
2414
|
+
* one level down as `data.data`. viem's `getContractError` reads it the same
|
|
2415
|
+
* way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
|
|
2416
|
+
* node's error from the chain.
|
|
2417
|
+
*
|
|
2418
|
+
* @param link - One error in the `cause` chain
|
|
2419
|
+
* @returns The `raw` or `data` string, or undefined if there is none
|
|
2420
|
+
*/ function getRevertData(link) {
|
|
2421
|
+
if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
|
|
2422
|
+
return link.raw;
|
|
2423
|
+
}
|
|
2424
|
+
if (!('data' in link)) {
|
|
2425
|
+
return undefined;
|
|
2426
|
+
}
|
|
2427
|
+
const { data } = link;
|
|
2428
|
+
if (typeof data === 'string') {
|
|
2429
|
+
return data;
|
|
2430
|
+
}
|
|
2431
|
+
if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
|
|
2432
|
+
return data.data;
|
|
2433
|
+
}
|
|
2434
|
+
return undefined;
|
|
2435
|
+
}
|
|
2436
|
+
/**
|
|
2437
|
+
* Finds the first revert data on the error or in its `cause` chain that
|
|
2438
|
+
* `accept` takes.
|
|
2439
|
+
*
|
|
2440
|
+
* viem keeps the node's revert data on an inner `RpcRequestError`, not on
|
|
2441
|
+
* the error it throws. The `seen` set stops a self-referencing `cause` chain.
|
|
2442
|
+
*
|
|
2443
|
+
* @param error - The error object
|
|
2444
|
+
* @param accept - Returns true for the data shape the caller wants
|
|
2445
|
+
* @returns The data as written on the error, or undefined if not found
|
|
2446
|
+
*/ function findRevertData(error, accept) {
|
|
2447
|
+
const seen = new Set();
|
|
2448
|
+
let current = error;
|
|
2449
|
+
while(current !== null && typeof current === 'object' && !seen.has(current)){
|
|
2450
|
+
seen.add(current);
|
|
2451
|
+
const data = getRevertData(current);
|
|
2452
|
+
if (data !== undefined && accept(data)) {
|
|
2453
|
+
return data;
|
|
2454
|
+
}
|
|
2455
|
+
current = 'cause' in current ? current.cause : undefined;
|
|
2456
|
+
}
|
|
2457
|
+
return undefined;
|
|
2458
|
+
}
|
|
2407
2459
|
/**
|
|
2408
2460
|
* Attempts to extract an error selector from an error object or message.
|
|
2409
2461
|
*
|
|
2410
2462
|
* Checks multiple sources in priority order:
|
|
2411
|
-
* 1. `
|
|
2463
|
+
* 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
|
|
2464
|
+
* in its `cause` chain
|
|
2412
2465
|
* 2. Message pattern: "custom error 0x8baa579f"
|
|
2413
2466
|
*
|
|
2414
2467
|
* @param msg - The error message
|
|
2415
2468
|
* @param error - The error object (optional)
|
|
2416
2469
|
* @returns The 4 bytes selector , or undefined if not found
|
|
2417
2470
|
*/ function extractErrorSelector(msg, error) {
|
|
2418
|
-
|
|
2419
|
-
if (
|
|
2420
|
-
|
|
2421
|
-
return error.data.toLowerCase();
|
|
2422
|
-
}
|
|
2471
|
+
const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
|
|
2472
|
+
if (data !== undefined) {
|
|
2473
|
+
return data.toLowerCase();
|
|
2423
2474
|
}
|
|
2424
2475
|
// Check for "custom error 0x8baa579f" in the message
|
|
2425
2476
|
const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
|
|
@@ -3644,6 +3695,8 @@ var SwapChain;
|
|
|
3644
3695
|
SwapChain["HyperEVM"] = "HyperEVM";
|
|
3645
3696
|
SwapChain["Monad"] = "Monad";
|
|
3646
3697
|
SwapChain["Arc"] = "Arc";
|
|
3698
|
+
SwapChain["Cronos"] = "Cronos";
|
|
3699
|
+
SwapChain["Morph"] = "Morph";
|
|
3647
3700
|
// Testnet chains with swap support
|
|
3648
3701
|
SwapChain["Arc_Testnet"] = "Arc_Testnet";
|
|
3649
3702
|
})(SwapChain || (SwapChain = {}));
|
|
@@ -4334,14 +4387,14 @@ var BorrowChain;
|
|
|
4334
4387
|
symbol: 'USDC',
|
|
4335
4388
|
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
4336
4389
|
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
4337
|
-
// See: https://docs.arc.
|
|
4390
|
+
// See: https://docs.arc.io/arc/references/contract-addresses
|
|
4338
4391
|
decimals: 18
|
|
4339
4392
|
},
|
|
4340
4393
|
chainId: 5042002,
|
|
4341
4394
|
isTestnet: true,
|
|
4342
4395
|
explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
|
|
4343
4396
|
rpcEndpoints: [
|
|
4344
|
-
'https://rpc.testnet.arc.
|
|
4397
|
+
'https://rpc.testnet.arc.io'
|
|
4345
4398
|
],
|
|
4346
4399
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
4347
4400
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
@@ -4986,7 +5039,8 @@ var BorrowChain;
|
|
|
4986
5039
|
}
|
|
4987
5040
|
},
|
|
4988
5041
|
kitContracts: {
|
|
4989
|
-
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5042
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5043
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET
|
|
4990
5044
|
}
|
|
4991
5045
|
});
|
|
4992
5046
|
|
|
@@ -5855,7 +5909,8 @@ var BorrowChain;
|
|
|
5855
5909
|
}
|
|
5856
5910
|
},
|
|
5857
5911
|
kitContracts: {
|
|
5858
|
-
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5912
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5913
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET
|
|
5859
5914
|
}
|
|
5860
5915
|
});
|
|
5861
5916
|
|
|
@@ -8158,8 +8213,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
8158
8213
|
* Zod schema for validating swap-specific chain identifiers.
|
|
8159
8214
|
*
|
|
8160
8215
|
* Validates chains based on:
|
|
8161
|
-
* -
|
|
8162
|
-
* - Mainnet
|
|
8216
|
+
* - Membership in the SwapChain enum
|
|
8217
|
+
* - Mainnet or explicitly allowlisted testnet
|
|
8163
8218
|
* - At least one supported token available
|
|
8164
8219
|
*
|
|
8165
8220
|
*/ z.union([
|
|
@@ -10056,11 +10111,13 @@ function parseOrThrow(value, schema, context) {
|
|
|
10056
10111
|
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
10057
10112
|
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
10058
10113
|
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
10114
|
+
[Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
|
|
10059
10115
|
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
10060
10116
|
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
10061
10117
|
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
10062
10118
|
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
10063
10119
|
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
10120
|
+
[Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
10064
10121
|
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
10065
10122
|
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
10066
10123
|
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
@@ -10119,6 +10176,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
10119
10176
|
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
10120
10177
|
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
10121
10178
|
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
10179
|
+
[Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
|
|
10122
10180
|
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
10123
10181
|
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
10124
10182
|
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
@@ -10181,7 +10239,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
10181
10239
|
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
10182
10240
|
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
10183
10241
|
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
10242
|
+
[Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
|
|
10184
10243
|
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
10244
|
+
[Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
|
|
10185
10245
|
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
10186
10246
|
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
10187
10247
|
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
|
|
@@ -10200,6 +10260,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
10200
10260
|
locators: {
|
|
10201
10261
|
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
10202
10262
|
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
10263
|
+
[Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
|
|
10203
10264
|
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
|
|
10204
10265
|
}
|
|
10205
10266
|
};
|
|
@@ -11890,7 +11951,7 @@ function resolveOptions(options) {
|
|
|
11890
11951
|
}
|
|
11891
11952
|
|
|
11892
11953
|
var name = "@circle-fin/unified-balance-kit";
|
|
11893
|
-
var version$1 = "1.8.
|
|
11954
|
+
var version$1 = "1.8.2";
|
|
11894
11955
|
var pkg$1 = {
|
|
11895
11956
|
name: name,
|
|
11896
11957
|
version: version$1};
|
|
@@ -26483,6 +26544,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26483
26544
|
}
|
|
26484
26545
|
};
|
|
26485
26546
|
|
|
26547
|
+
/**
|
|
26548
|
+
* Check whether a forwarded burn to the given destination asks Circle's
|
|
26549
|
+
* Forwarding Service to set up the recipient's token account before minting.
|
|
26550
|
+
*
|
|
26551
|
+
* Must return `true` exactly for the destinations where
|
|
26552
|
+
* {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
|
|
26553
|
+
* fee quote includes the setup rent whenever the burn requests it.
|
|
26554
|
+
*
|
|
26555
|
+
* @internal
|
|
26556
|
+
* @param chainType - The destination blockchain type.
|
|
26557
|
+
* @returns `true` for Solana destinations, `false` otherwise.
|
|
26558
|
+
*
|
|
26559
|
+
* @example
|
|
26560
|
+
* ```typescript
|
|
26561
|
+
* requiresRecipientSetup('solana') // true
|
|
26562
|
+
* requiresRecipientSetup('evm') // false
|
|
26563
|
+
* ```
|
|
26564
|
+
*/ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
|
|
26486
26565
|
/**
|
|
26487
26566
|
* Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
|
|
26488
26567
|
* tailored to the destination chain.
|
|
@@ -26833,10 +26912,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26833
26912
|
* @param sourceDomain - The source domain
|
|
26834
26913
|
* @param destinationDomain - The destination domain
|
|
26835
26914
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
26915
|
+
* @param includeRecipientSetup - Whether the quote includes recipient account setup rent
|
|
26836
26916
|
* @returns The complete API URL with forward=true query parameter
|
|
26837
|
-
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
|
|
26917
|
+
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
|
|
26838
26918
|
const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL : IRIS_API_BASE_URL;
|
|
26839
|
-
|
|
26919
|
+
const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
|
|
26920
|
+
return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
|
|
26840
26921
|
}
|
|
26841
26922
|
/**
|
|
26842
26923
|
* Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
|
|
@@ -26853,6 +26934,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26853
26934
|
*
|
|
26854
26935
|
* The high fee tier is always used to provide buffer for destination gas fluctuations.
|
|
26855
26936
|
*
|
|
26937
|
+
* Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
|
|
26938
|
+
* the recipient's token account (Solana destinations). The quote then includes the
|
|
26939
|
+
* account rent, which the quote without this flag leaves out.
|
|
26940
|
+
*
|
|
26856
26941
|
* Implements timeout and retry logic to handle network issues and temporary API failures.
|
|
26857
26942
|
* Each HTTP request is given a maximum of 2 seconds before it is aborted.
|
|
26858
26943
|
* We retry up to 10 times, waiting 200ms between attempts.
|
|
@@ -26861,6 +26946,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26861
26946
|
* @param destinationDomain - The destination domain
|
|
26862
26947
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
26863
26948
|
* @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
|
|
26949
|
+
* @param includeRecipientSetup - Whether to include recipient account setup rent in the
|
|
26950
|
+
* quote. Defaults to `false`.
|
|
26864
26951
|
* @returns The high-tier forwarding fee in USDC minor units (6 decimals)
|
|
26865
26952
|
* @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
|
|
26866
26953
|
*
|
|
@@ -26872,8 +26959,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26872
26959
|
*
|
|
26873
26960
|
* // SLOW transfer - use 2000ms finality threshold
|
|
26874
26961
|
* const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
|
|
26962
|
+
*
|
|
26963
|
+
* // Ethereum -> Solana: include the recipient token account rent
|
|
26964
|
+
* const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
|
|
26875
26965
|
* ```
|
|
26876
|
-
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
|
|
26966
|
+
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
|
|
26877
26967
|
// Validate source domain
|
|
26878
26968
|
if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
|
|
26879
26969
|
throw new KitError({
|
|
@@ -26901,7 +26991,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26901
26991
|
});
|
|
26902
26992
|
}
|
|
26903
26993
|
// Fetch the fee tiers from the API with forward=true
|
|
26904
|
-
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
|
|
26994
|
+
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
|
|
26905
26995
|
const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$1);
|
|
26906
26996
|
// Validate that we have at least one fee tier
|
|
26907
26997
|
if (response.length === 0) {
|
|
@@ -29237,7 +29327,7 @@ const mockAttestationMessage = {
|
|
|
29237
29327
|
return step;
|
|
29238
29328
|
}
|
|
29239
29329
|
|
|
29240
|
-
var version = "1.14.
|
|
29330
|
+
var version = "1.14.3";
|
|
29241
29331
|
var pkg = {
|
|
29242
29332
|
version: version};
|
|
29243
29333
|
|
|
@@ -30156,9 +30246,34 @@ function assertCCTPV2Config(config) {
|
|
|
30156
30246
|
tokenAddress: source.chain.usdcAddress,
|
|
30157
30247
|
operationContext: sourceOperationContext
|
|
30158
30248
|
});
|
|
30249
|
+
await this.assertAmountCoversRecipientSetupFee(params);
|
|
30159
30250
|
return bridge(params, this);
|
|
30160
30251
|
}
|
|
30161
30252
|
/**
|
|
30253
|
+
* Reject a forwarded transfer to Solana whose amount does not exceed the fee.
|
|
30254
|
+
*
|
|
30255
|
+
* CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
|
|
30256
|
+
* forwarding fee includes the recipient token account rent. Checking before the
|
|
30257
|
+
* approval avoids sending a transaction that can never be followed by a burn.
|
|
30258
|
+
* Skipped when the caller provides `config.maxFee`.
|
|
30259
|
+
*
|
|
30260
|
+
* @param params - The validated CCTP v2 bridge parameters.
|
|
30261
|
+
* @returns A promise that resolves when the amount covers the fee.
|
|
30262
|
+
* @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
|
|
30263
|
+
* to the amount.
|
|
30264
|
+
*/ async assertAmountCoversRecipientSetupFee(params) {
|
|
30265
|
+
const { destination, amount, config } = params;
|
|
30266
|
+
if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
|
|
30267
|
+
return;
|
|
30268
|
+
}
|
|
30269
|
+
const { providerFee, forwarderFee } = await this.getMaxFee(params);
|
|
30270
|
+
const maxFee = providerFee + forwarderFee;
|
|
30271
|
+
if (maxFee >= BigInt(amount)) {
|
|
30272
|
+
// Amounts and fees are in USDC minor units (6 decimals)
|
|
30273
|
+
throw createInvalidAmountError(formatUnits(amount, 6), `Amount must be greater than the ${formatUnits(String(maxFee), 6)} USDC fee for forwarded transfers to ${destination.chain.name}, which includes creating the recipient's token account`);
|
|
30274
|
+
}
|
|
30275
|
+
}
|
|
30276
|
+
/**
|
|
30162
30277
|
* Retry a failed or incomplete CCTP v2 bridge operation.
|
|
30163
30278
|
*
|
|
30164
30279
|
* Analyzes the bridge result to determine where to continue and executes
|
|
@@ -30875,6 +30990,9 @@ function assertCCTPV2Config(config) {
|
|
|
30875
30990
|
* | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
|
|
30876
30991
|
* | FAST | true | Yes | maxFee = config.maxFee |
|
|
30877
30992
|
*
|
|
30993
|
+
* For forwarded burns to Solana, the forwarding fee includes the rent for creating the
|
|
30994
|
+
* recipient's token account. A caller-provided `maxFee` must cover it too.
|
|
30995
|
+
*
|
|
30878
30996
|
* @param params - The bridge parameters object containing:
|
|
30879
30997
|
* - `source`: The source wallet context with chain definition and adapter
|
|
30880
30998
|
* - `destination`: The destination wallet context with chain definition and adapter
|
|
@@ -30913,6 +31031,7 @@ function assertCCTPV2Config(config) {
|
|
|
30913
31031
|
}
|
|
30914
31032
|
// Get the min finality threshold based on the transfer speed
|
|
30915
31033
|
const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
|
|
31034
|
+
const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
|
|
30916
31035
|
// SLOW transfer without forwarder: no fee
|
|
30917
31036
|
if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
|
|
30918
31037
|
return {
|
|
@@ -30922,7 +31041,7 @@ function assertCCTPV2Config(config) {
|
|
|
30922
31041
|
}
|
|
30923
31042
|
// SLOW transfer with forwarder: only forwarding fee
|
|
30924
31043
|
if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
|
|
30925
|
-
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
|
|
31044
|
+
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
|
|
30926
31045
|
return {
|
|
30927
31046
|
providerFee: 0n,
|
|
30928
31047
|
forwarderFee
|
|
@@ -30932,7 +31051,7 @@ function assertCCTPV2Config(config) {
|
|
|
30932
31051
|
// Fetch fees in parallel when forwarder is enabled
|
|
30933
31052
|
const [scaledBps, forwarderFee] = await Promise.all([
|
|
30934
31053
|
fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
|
|
30935
|
-
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
|
|
31054
|
+
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
|
|
30936
31055
|
]);
|
|
30937
31056
|
// Calculate fee proportional to the transfer amount
|
|
30938
31057
|
const amountInMinorUnits = BigInt(amount);
|