@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.cjs
CHANGED
|
@@ -2411,22 +2411,73 @@ let activeRedactor = defaultMessageRedactor;
|
|
|
2411
2411
|
'0x9147d463': 'Final balance is less than the initial balance',
|
|
2412
2412
|
'0xf4b3b1bc': 'Native token transfer to the beneficiary failed'
|
|
2413
2413
|
};
|
|
2414
|
+
/**
|
|
2415
|
+
* Matches revert data: a 4-byte selector followed by whole ABI-encoded bytes.
|
|
2416
|
+
*/ const REVERT_DATA_PATTERN = /^0x[0-9a-f]{8}(?:[0-9a-f]{2})*$/i;
|
|
2417
|
+
/**
|
|
2418
|
+
* Returns the revert data held by one error in a `cause` chain.
|
|
2419
|
+
*
|
|
2420
|
+
* Browser wallets (EIP-1193) wrap the node's error, so the revert data sits
|
|
2421
|
+
* one level down as `data.data`. viem's `getContractError` reads it the same
|
|
2422
|
+
* way, then keeps it on `ContractFunctionRevertedError.raw` and drops the
|
|
2423
|
+
* node's error from the chain.
|
|
2424
|
+
*
|
|
2425
|
+
* @param link - One error in the `cause` chain
|
|
2426
|
+
* @returns The `raw` or `data` string, or undefined if there is none
|
|
2427
|
+
*/ function getRevertData(link) {
|
|
2428
|
+
if ('raw' in link && typeof link.raw === 'string' && REVERT_DATA_PATTERN.test(link.raw)) {
|
|
2429
|
+
return link.raw;
|
|
2430
|
+
}
|
|
2431
|
+
if (!('data' in link)) {
|
|
2432
|
+
return undefined;
|
|
2433
|
+
}
|
|
2434
|
+
const { data } = link;
|
|
2435
|
+
if (typeof data === 'string') {
|
|
2436
|
+
return data;
|
|
2437
|
+
}
|
|
2438
|
+
if (data !== null && typeof data === 'object' && 'data' in data && typeof data.data === 'string') {
|
|
2439
|
+
return data.data;
|
|
2440
|
+
}
|
|
2441
|
+
return undefined;
|
|
2442
|
+
}
|
|
2443
|
+
/**
|
|
2444
|
+
* Finds the first revert data on the error or in its `cause` chain that
|
|
2445
|
+
* `accept` takes.
|
|
2446
|
+
*
|
|
2447
|
+
* viem keeps the node's revert data on an inner `RpcRequestError`, not on
|
|
2448
|
+
* the error it throws. The `seen` set stops a self-referencing `cause` chain.
|
|
2449
|
+
*
|
|
2450
|
+
* @param error - The error object
|
|
2451
|
+
* @param accept - Returns true for the data shape the caller wants
|
|
2452
|
+
* @returns The data as written on the error, or undefined if not found
|
|
2453
|
+
*/ function findRevertData(error, accept) {
|
|
2454
|
+
const seen = new Set();
|
|
2455
|
+
let current = error;
|
|
2456
|
+
while(current !== null && typeof current === 'object' && !seen.has(current)){
|
|
2457
|
+
seen.add(current);
|
|
2458
|
+
const data = getRevertData(current);
|
|
2459
|
+
if (data !== undefined && accept(data)) {
|
|
2460
|
+
return data;
|
|
2461
|
+
}
|
|
2462
|
+
current = 'cause' in current ? current.cause : undefined;
|
|
2463
|
+
}
|
|
2464
|
+
return undefined;
|
|
2465
|
+
}
|
|
2414
2466
|
/**
|
|
2415
2467
|
* Attempts to extract an error selector from an error object or message.
|
|
2416
2468
|
*
|
|
2417
2469
|
* Checks multiple sources in priority order:
|
|
2418
|
-
* 1. `
|
|
2470
|
+
* 1. `raw` or `data` field (or nested `data.data`) on the error or anywhere
|
|
2471
|
+
* in its `cause` chain
|
|
2419
2472
|
* 2. Message pattern: "custom error 0x8baa579f"
|
|
2420
2473
|
*
|
|
2421
2474
|
* @param msg - The error message
|
|
2422
2475
|
* @param error - The error object (optional)
|
|
2423
2476
|
* @returns The 4 bytes selector , or undefined if not found
|
|
2424
2477
|
*/ function extractErrorSelector(msg, error) {
|
|
2425
|
-
|
|
2426
|
-
if (
|
|
2427
|
-
|
|
2428
|
-
return error.data.toLowerCase();
|
|
2429
|
-
}
|
|
2478
|
+
const data = findRevertData(error, (value)=>/^0x[0-9a-f]{8}$/i.test(value));
|
|
2479
|
+
if (data !== undefined) {
|
|
2480
|
+
return data.toLowerCase();
|
|
2430
2481
|
}
|
|
2431
2482
|
// Check for "custom error 0x8baa579f" in the message
|
|
2432
2483
|
const match = /custom error (0x[0-9a-f]{8})\b/i.exec(msg);
|
|
@@ -3651,6 +3702,8 @@ var SwapChain;
|
|
|
3651
3702
|
SwapChain["HyperEVM"] = "HyperEVM";
|
|
3652
3703
|
SwapChain["Monad"] = "Monad";
|
|
3653
3704
|
SwapChain["Arc"] = "Arc";
|
|
3705
|
+
SwapChain["Cronos"] = "Cronos";
|
|
3706
|
+
SwapChain["Morph"] = "Morph";
|
|
3654
3707
|
// Testnet chains with swap support
|
|
3655
3708
|
SwapChain["Arc_Testnet"] = "Arc_Testnet";
|
|
3656
3709
|
})(SwapChain || (SwapChain = {}));
|
|
@@ -4341,14 +4394,14 @@ var BorrowChain;
|
|
|
4341
4394
|
symbol: 'USDC',
|
|
4342
4395
|
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
4343
4396
|
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
4344
|
-
// See: https://docs.arc.
|
|
4397
|
+
// See: https://docs.arc.io/arc/references/contract-addresses
|
|
4345
4398
|
decimals: 18
|
|
4346
4399
|
},
|
|
4347
4400
|
chainId: 5042002,
|
|
4348
4401
|
isTestnet: true,
|
|
4349
4402
|
explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
|
|
4350
4403
|
rpcEndpoints: [
|
|
4351
|
-
'https://rpc.testnet.arc.
|
|
4404
|
+
'https://rpc.testnet.arc.io'
|
|
4352
4405
|
],
|
|
4353
4406
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
4354
4407
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
@@ -4993,7 +5046,8 @@ var BorrowChain;
|
|
|
4993
5046
|
}
|
|
4994
5047
|
},
|
|
4995
5048
|
kitContracts: {
|
|
4996
|
-
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5049
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5050
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET
|
|
4997
5051
|
}
|
|
4998
5052
|
});
|
|
4999
5053
|
|
|
@@ -5862,7 +5916,8 @@ var BorrowChain;
|
|
|
5862
5916
|
}
|
|
5863
5917
|
},
|
|
5864
5918
|
kitContracts: {
|
|
5865
|
-
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5919
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET,
|
|
5920
|
+
adapter: ADAPTER_CONTRACT_EVM_MAINNET
|
|
5866
5921
|
}
|
|
5867
5922
|
});
|
|
5868
5923
|
|
|
@@ -8165,8 +8220,8 @@ var Chains = {
|
|
|
8165
8220
|
* Zod schema for validating swap-specific chain identifiers.
|
|
8166
8221
|
*
|
|
8167
8222
|
* Validates chains based on:
|
|
8168
|
-
* -
|
|
8169
|
-
* - Mainnet
|
|
8223
|
+
* - Membership in the SwapChain enum
|
|
8224
|
+
* - Mainnet or explicitly allowlisted testnet
|
|
8170
8225
|
* - At least one supported token available
|
|
8171
8226
|
*
|
|
8172
8227
|
*/ zod.z.union([
|
|
@@ -10063,11 +10118,13 @@ function parseOrThrow(value, schema, context) {
|
|
|
10063
10118
|
[Blockchain.Arbitrum]: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9',
|
|
10064
10119
|
[Blockchain.Avalanche]: '0x9702230A8Ea53601f5cD2dc00fDBc13d4dF4A8c7',
|
|
10065
10120
|
[Blockchain.Celo]: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
|
|
10121
|
+
[Blockchain.Cronos]: '0x66e428c3f67a68878562e79A0234c1F83c208770',
|
|
10066
10122
|
[Blockchain.Ethereum]: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
|
|
10067
10123
|
[Blockchain.HyperEVM]: '0xb8ce59fc3717ada4c02eadf9682a9e934f625ebb',
|
|
10068
10124
|
[Blockchain.Ink]: '0x0200C29006150606B650577BBE7B6248F58470c1',
|
|
10069
10125
|
[Blockchain.Linea]: '0xA219439258ca9da29E9Cc4cE5596924745e12B93',
|
|
10070
10126
|
[Blockchain.Monad]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
10127
|
+
[Blockchain.Morph]: '0xe7cd86e13AC4309349F30B3435a9d337750fC82D',
|
|
10071
10128
|
[Blockchain.NEAR]: 'usdt.tether-token.near',
|
|
10072
10129
|
[Blockchain.Optimism]: '0x94b008aA00579c1307B0EF2c499aD98a8ce58e58',
|
|
10073
10130
|
[Blockchain.Polkadot_Asset_Hub]: '1984',
|
|
@@ -10126,6 +10183,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
10126
10183
|
[Blockchain.Arbitrum]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
10127
10184
|
[Blockchain.Avalanche]: '0xd586E7F844cEa2F87f50152665BCbc2C279D8d70',
|
|
10128
10185
|
[Blockchain.Base]: '0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb',
|
|
10186
|
+
[Blockchain.Cronos]: '0xF2001B145b43032AAF5Ee2884e456CCd805F677D',
|
|
10129
10187
|
[Blockchain.Ethereum]: '0x6B175474E89094C44Da98b954EedeAC495271d0F',
|
|
10130
10188
|
[Blockchain.Linea]: '0x4AF15ec2A0BD43Db75dd04E62FAA3B8EF36b00d5',
|
|
10131
10189
|
[Blockchain.Optimism]: '0xDA10009cBd5D07dd0CeCc66161FC93D7c9000da1',
|
|
@@ -10188,7 +10246,9 @@ function parseOrThrow(value, schema, context) {
|
|
|
10188
10246
|
[Blockchain.Arbitrum]: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
|
|
10189
10247
|
[Blockchain.Avalanche]: '0x49D5c2BdFfac6CE2BFdB6640F4F80f226bc10bAB',
|
|
10190
10248
|
[Blockchain.Base]: '0x4200000000000000000000000000000000000006',
|
|
10249
|
+
[Blockchain.Cronos]: '0xe44Fd7fCb2b1581822D0c862B68222998a0c299a',
|
|
10191
10250
|
[Blockchain.Ethereum]: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
|
|
10251
|
+
[Blockchain.Morph]: '0x5300000000000000000000000000000000000011',
|
|
10192
10252
|
[Blockchain.Optimism]: '0x4200000000000000000000000000000000000006',
|
|
10193
10253
|
[Blockchain.Polygon]: '0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619',
|
|
10194
10254
|
[Blockchain.Solana]: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs'
|
|
@@ -10207,6 +10267,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
10207
10267
|
locators: {
|
|
10208
10268
|
[Blockchain.Ethereum]: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599',
|
|
10209
10269
|
[Blockchain.Arbitrum]: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
|
|
10270
|
+
[Blockchain.Cronos]: '0x062E66477Faf219F25D27dCED647BF57C3107d52',
|
|
10210
10271
|
[Blockchain.Avalanche]: '0x50b7545627a5162F82A992c33b87aDc75187B218'
|
|
10211
10272
|
}
|
|
10212
10273
|
};
|
|
@@ -11897,7 +11958,7 @@ function resolveOptions(options) {
|
|
|
11897
11958
|
}
|
|
11898
11959
|
|
|
11899
11960
|
var name = "@circle-fin/unified-balance-kit";
|
|
11900
|
-
var version$1 = "1.8.
|
|
11961
|
+
var version$1 = "1.8.2";
|
|
11901
11962
|
var pkg$1 = {
|
|
11902
11963
|
name: name,
|
|
11903
11964
|
version: version$1};
|
|
@@ -26490,6 +26551,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26490
26551
|
}
|
|
26491
26552
|
};
|
|
26492
26553
|
|
|
26554
|
+
/**
|
|
26555
|
+
* Check whether a forwarded burn to the given destination asks Circle's
|
|
26556
|
+
* Forwarding Service to set up the recipient's token account before minting.
|
|
26557
|
+
*
|
|
26558
|
+
* Must return `true` exactly for the destinations where
|
|
26559
|
+
* {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
|
|
26560
|
+
* fee quote includes the setup rent whenever the burn requests it.
|
|
26561
|
+
*
|
|
26562
|
+
* @internal
|
|
26563
|
+
* @param chainType - The destination blockchain type.
|
|
26564
|
+
* @returns `true` for Solana destinations, `false` otherwise.
|
|
26565
|
+
*
|
|
26566
|
+
* @example
|
|
26567
|
+
* ```typescript
|
|
26568
|
+
* requiresRecipientSetup('solana') // true
|
|
26569
|
+
* requiresRecipientSetup('evm') // false
|
|
26570
|
+
* ```
|
|
26571
|
+
*/ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
|
|
26493
26572
|
/**
|
|
26494
26573
|
* Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
|
|
26495
26574
|
* tailored to the destination chain.
|
|
@@ -26840,10 +26919,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26840
26919
|
* @param sourceDomain - The source domain
|
|
26841
26920
|
* @param destinationDomain - The destination domain
|
|
26842
26921
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
26922
|
+
* @param includeRecipientSetup - Whether the quote includes recipient account setup rent
|
|
26843
26923
|
* @returns The complete API URL with forward=true query parameter
|
|
26844
|
-
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
|
|
26924
|
+
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
|
|
26845
26925
|
const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL : IRIS_API_BASE_URL;
|
|
26846
|
-
|
|
26926
|
+
const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
|
|
26927
|
+
return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
|
|
26847
26928
|
}
|
|
26848
26929
|
/**
|
|
26849
26930
|
* Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
|
|
@@ -26860,6 +26941,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26860
26941
|
*
|
|
26861
26942
|
* The high fee tier is always used to provide buffer for destination gas fluctuations.
|
|
26862
26943
|
*
|
|
26944
|
+
* Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
|
|
26945
|
+
* the recipient's token account (Solana destinations). The quote then includes the
|
|
26946
|
+
* account rent, which the quote without this flag leaves out.
|
|
26947
|
+
*
|
|
26863
26948
|
* Implements timeout and retry logic to handle network issues and temporary API failures.
|
|
26864
26949
|
* Each HTTP request is given a maximum of 2 seconds before it is aborted.
|
|
26865
26950
|
* We retry up to 10 times, waiting 200ms between attempts.
|
|
@@ -26868,6 +26953,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26868
26953
|
* @param destinationDomain - The destination domain
|
|
26869
26954
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
26870
26955
|
* @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
|
|
26956
|
+
* @param includeRecipientSetup - Whether to include recipient account setup rent in the
|
|
26957
|
+
* quote. Defaults to `false`.
|
|
26871
26958
|
* @returns The high-tier forwarding fee in USDC minor units (6 decimals)
|
|
26872
26959
|
* @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
|
|
26873
26960
|
*
|
|
@@ -26879,8 +26966,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26879
26966
|
*
|
|
26880
26967
|
* // SLOW transfer - use 2000ms finality threshold
|
|
26881
26968
|
* const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
|
|
26969
|
+
*
|
|
26970
|
+
* // Ethereum -> Solana: include the recipient token account rent
|
|
26971
|
+
* const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
|
|
26882
26972
|
* ```
|
|
26883
|
-
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
|
|
26973
|
+
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
|
|
26884
26974
|
// Validate source domain
|
|
26885
26975
|
if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
|
|
26886
26976
|
throw new KitError({
|
|
@@ -26908,7 +26998,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
26908
26998
|
});
|
|
26909
26999
|
}
|
|
26910
27000
|
// Fetch the fee tiers from the API with forward=true
|
|
26911
|
-
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
|
|
27001
|
+
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
|
|
26912
27002
|
const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$1);
|
|
26913
27003
|
// Validate that we have at least one fee tier
|
|
26914
27004
|
if (response.length === 0) {
|
|
@@ -29244,7 +29334,7 @@ const mockAttestationMessage = {
|
|
|
29244
29334
|
return step;
|
|
29245
29335
|
}
|
|
29246
29336
|
|
|
29247
|
-
var version = "1.14.
|
|
29337
|
+
var version = "1.14.3";
|
|
29248
29338
|
var pkg = {
|
|
29249
29339
|
version: version};
|
|
29250
29340
|
|
|
@@ -30163,9 +30253,34 @@ function assertCCTPV2Config(config) {
|
|
|
30163
30253
|
tokenAddress: source.chain.usdcAddress,
|
|
30164
30254
|
operationContext: sourceOperationContext
|
|
30165
30255
|
});
|
|
30256
|
+
await this.assertAmountCoversRecipientSetupFee(params);
|
|
30166
30257
|
return bridge(params, this);
|
|
30167
30258
|
}
|
|
30168
30259
|
/**
|
|
30260
|
+
* Reject a forwarded transfer to Solana whose amount does not exceed the fee.
|
|
30261
|
+
*
|
|
30262
|
+
* CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
|
|
30263
|
+
* forwarding fee includes the recipient token account rent. Checking before the
|
|
30264
|
+
* approval avoids sending a transaction that can never be followed by a burn.
|
|
30265
|
+
* Skipped when the caller provides `config.maxFee`.
|
|
30266
|
+
*
|
|
30267
|
+
* @param params - The validated CCTP v2 bridge parameters.
|
|
30268
|
+
* @returns A promise that resolves when the amount covers the fee.
|
|
30269
|
+
* @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
|
|
30270
|
+
* to the amount.
|
|
30271
|
+
*/ async assertAmountCoversRecipientSetupFee(params) {
|
|
30272
|
+
const { destination, amount, config } = params;
|
|
30273
|
+
if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
|
|
30274
|
+
return;
|
|
30275
|
+
}
|
|
30276
|
+
const { providerFee, forwarderFee } = await this.getMaxFee(params);
|
|
30277
|
+
const maxFee = providerFee + forwarderFee;
|
|
30278
|
+
if (maxFee >= BigInt(amount)) {
|
|
30279
|
+
// Amounts and fees are in USDC minor units (6 decimals)
|
|
30280
|
+
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`);
|
|
30281
|
+
}
|
|
30282
|
+
}
|
|
30283
|
+
/**
|
|
30169
30284
|
* Retry a failed or incomplete CCTP v2 bridge operation.
|
|
30170
30285
|
*
|
|
30171
30286
|
* Analyzes the bridge result to determine where to continue and executes
|
|
@@ -30882,6 +30997,9 @@ function assertCCTPV2Config(config) {
|
|
|
30882
30997
|
* | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
|
|
30883
30998
|
* | FAST | true | Yes | maxFee = config.maxFee |
|
|
30884
30999
|
*
|
|
31000
|
+
* For forwarded burns to Solana, the forwarding fee includes the rent for creating the
|
|
31001
|
+
* recipient's token account. A caller-provided `maxFee` must cover it too.
|
|
31002
|
+
*
|
|
30885
31003
|
* @param params - The bridge parameters object containing:
|
|
30886
31004
|
* - `source`: The source wallet context with chain definition and adapter
|
|
30887
31005
|
* - `destination`: The destination wallet context with chain definition and adapter
|
|
@@ -30920,6 +31038,7 @@ function assertCCTPV2Config(config) {
|
|
|
30920
31038
|
}
|
|
30921
31039
|
// Get the min finality threshold based on the transfer speed
|
|
30922
31040
|
const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
|
|
31041
|
+
const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
|
|
30923
31042
|
// SLOW transfer without forwarder: no fee
|
|
30924
31043
|
if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
|
|
30925
31044
|
return {
|
|
@@ -30929,7 +31048,7 @@ function assertCCTPV2Config(config) {
|
|
|
30929
31048
|
}
|
|
30930
31049
|
// SLOW transfer with forwarder: only forwarding fee
|
|
30931
31050
|
if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
|
|
30932
|
-
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
|
|
31051
|
+
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
|
|
30933
31052
|
return {
|
|
30934
31053
|
providerFee: 0n,
|
|
30935
31054
|
forwarderFee
|
|
@@ -30939,7 +31058,7 @@ function assertCCTPV2Config(config) {
|
|
|
30939
31058
|
// Fetch fees in parallel when forwarder is enabled
|
|
30940
31059
|
const [scaledBps, forwarderFee] = await Promise.all([
|
|
30941
31060
|
fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
|
|
30942
|
-
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
|
|
31061
|
+
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
|
|
30943
31062
|
]);
|
|
30944
31063
|
// Calculate fee proportional to the transfer amount
|
|
30945
31064
|
const amountInMinorUnits = BigInt(amount);
|