@circle-fin/app-kit 1.8.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +3 -3
- package/bridge.cjs +1102 -260
- package/bridge.d.cts +161 -10
- package/bridge.d.mts +161 -10
- package/bridge.d.ts +161 -10
- package/bridge.mjs +1102 -260
- package/chains.cjs +102 -2
- package/chains.d.cts +3 -0
- package/chains.d.mts +3 -0
- package/chains.d.ts +3 -0
- package/chains.mjs +102 -2
- package/context.cjs +1 -0
- package/context.d.cts +166 -12
- package/context.d.mts +166 -12
- package/context.d.ts +166 -12
- package/context.mjs +1 -0
- package/earn.cjs +1074 -454
- package/earn.d.cts +546 -99
- package/earn.d.mts +546 -99
- package/earn.d.ts +546 -99
- package/earn.mjs +1074 -455
- package/estimateBridge.cjs +1102 -260
- package/estimateBridge.d.cts +161 -10
- package/estimateBridge.d.mts +161 -10
- package/estimateBridge.d.ts +161 -10
- package/estimateBridge.mjs +1102 -260
- package/estimateSwap.cjs +915 -96
- package/estimateSwap.d.cts +161 -10
- package/estimateSwap.d.mts +161 -10
- package/estimateSwap.d.ts +161 -10
- package/estimateSwap.mjs +915 -96
- package/index.cjs +3029 -862
- package/index.d.cts +1277 -143
- package/index.d.mts +1277 -143
- package/index.d.ts +1277 -143
- package/index.mjs +3029 -862
- package/package.json +12 -6
- package/swap.cjs +915 -96
- package/swap.d.cts +161 -10
- package/swap.d.mts +161 -10
- package/swap.d.ts +161 -10
- package/swap.mjs +915 -96
- package/unifiedBalance.cjs +822 -115
- package/unifiedBalance.d.cts +224 -4
- package/unifiedBalance.d.mts +224 -4
- package/unifiedBalance.d.ts +224 -4
- package/unifiedBalance.mjs +822 -115
package/bridge.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var zod = require('zod');
|
|
|
22
22
|
var pino = require('pino');
|
|
23
23
|
var units = require('@ethersproject/units');
|
|
24
24
|
var bytes = require('@ethersproject/bytes');
|
|
25
|
+
require('@ethersproject/abi');
|
|
25
26
|
var address = require('@ethersproject/address');
|
|
26
27
|
var bs58 = require('bs58');
|
|
27
28
|
var web3_js = require('@solana/web3.js');
|
|
@@ -2479,6 +2480,8 @@ class KitError extends Error {
|
|
|
2479
2480
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
2480
2481
|
Blockchain["Codex"] = "Codex";
|
|
2481
2482
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
2483
|
+
Blockchain["Cronos"] = "Cronos";
|
|
2484
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2482
2485
|
Blockchain["Edge"] = "Edge";
|
|
2483
2486
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
2484
2487
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -2561,6 +2564,7 @@ var BridgeChain;
|
|
|
2561
2564
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
2562
2565
|
BridgeChain["Base"] = "Base";
|
|
2563
2566
|
BridgeChain["Codex"] = "Codex";
|
|
2567
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
2564
2568
|
BridgeChain["Edge"] = "Edge";
|
|
2565
2569
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
2566
2570
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -2585,6 +2589,7 @@ var BridgeChain;
|
|
|
2585
2589
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
2586
2590
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
2587
2591
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
2592
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2588
2593
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
2589
2594
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
2590
2595
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -3096,7 +3101,10 @@ var EarnChain;
|
|
|
3096
3101
|
contracts: {
|
|
3097
3102
|
v1: {
|
|
3098
3103
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3099
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
3104
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3105
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
3106
|
+
// deposit into the GatewayWallet above.
|
|
3107
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3100
3108
|
}
|
|
3101
3109
|
},
|
|
3102
3110
|
forwarderSupported: {
|
|
@@ -3630,6 +3638,96 @@ var EarnChain;
|
|
|
3630
3638
|
}
|
|
3631
3639
|
});
|
|
3632
3640
|
|
|
3641
|
+
/**
|
|
3642
|
+
* Cronos Mainnet chain definition
|
|
3643
|
+
* @remarks
|
|
3644
|
+
* This represents the official production network for the Cronos blockchain.
|
|
3645
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3646
|
+
*/ const Cronos = defineChain({
|
|
3647
|
+
type: 'evm',
|
|
3648
|
+
chain: Blockchain.Cronos,
|
|
3649
|
+
name: 'Cronos',
|
|
3650
|
+
title: 'Cronos Mainnet',
|
|
3651
|
+
nativeCurrency: {
|
|
3652
|
+
name: 'Cronos',
|
|
3653
|
+
symbol: 'CRO',
|
|
3654
|
+
decimals: 18
|
|
3655
|
+
},
|
|
3656
|
+
chainId: 25,
|
|
3657
|
+
isTestnet: false,
|
|
3658
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
3659
|
+
rpcEndpoints: [
|
|
3660
|
+
'https://evm.cronos.org'
|
|
3661
|
+
],
|
|
3662
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
3663
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
3664
|
+
usdtAddress: null,
|
|
3665
|
+
cctp: {
|
|
3666
|
+
domain: 32,
|
|
3667
|
+
contracts: {
|
|
3668
|
+
v2: {
|
|
3669
|
+
type: 'split',
|
|
3670
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
3671
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
3672
|
+
confirmations: 1,
|
|
3673
|
+
fastConfirmations: 1
|
|
3674
|
+
}
|
|
3675
|
+
},
|
|
3676
|
+
forwarderSupported: {
|
|
3677
|
+
source: false,
|
|
3678
|
+
destination: false
|
|
3679
|
+
}
|
|
3680
|
+
},
|
|
3681
|
+
kitContracts: {
|
|
3682
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
3683
|
+
}
|
|
3684
|
+
});
|
|
3685
|
+
|
|
3686
|
+
/**
|
|
3687
|
+
* Cronos Testnet chain definition
|
|
3688
|
+
* @remarks
|
|
3689
|
+
* This represents the official test network for the Cronos blockchain.
|
|
3690
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3691
|
+
*/ const CronosTestnet = defineChain({
|
|
3692
|
+
type: 'evm',
|
|
3693
|
+
chain: Blockchain.Cronos_Testnet,
|
|
3694
|
+
name: 'Cronos Testnet',
|
|
3695
|
+
title: 'Cronos Testnet',
|
|
3696
|
+
nativeCurrency: {
|
|
3697
|
+
name: 'CRO',
|
|
3698
|
+
symbol: 'tCRO',
|
|
3699
|
+
decimals: 18
|
|
3700
|
+
},
|
|
3701
|
+
chainId: 338,
|
|
3702
|
+
isTestnet: true,
|
|
3703
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
3704
|
+
rpcEndpoints: [
|
|
3705
|
+
'https://evm-t3.cronos.org'
|
|
3706
|
+
],
|
|
3707
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
3708
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
3709
|
+
usdtAddress: null,
|
|
3710
|
+
cctp: {
|
|
3711
|
+
domain: 32,
|
|
3712
|
+
contracts: {
|
|
3713
|
+
v2: {
|
|
3714
|
+
type: 'split',
|
|
3715
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
3716
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
3717
|
+
confirmations: 1,
|
|
3718
|
+
fastConfirmations: 1
|
|
3719
|
+
}
|
|
3720
|
+
},
|
|
3721
|
+
forwarderSupported: {
|
|
3722
|
+
source: false,
|
|
3723
|
+
destination: false
|
|
3724
|
+
}
|
|
3725
|
+
},
|
|
3726
|
+
kitContracts: {
|
|
3727
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
3728
|
+
}
|
|
3729
|
+
});
|
|
3730
|
+
|
|
3633
3731
|
/**
|
|
3634
3732
|
* Edge Mainnet chain definition
|
|
3635
3733
|
* @remarks
|
|
@@ -5981,6 +6079,8 @@ var Chains = {
|
|
|
5981
6079
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
5982
6080
|
Codex: Codex,
|
|
5983
6081
|
CodexTestnet: CodexTestnet,
|
|
6082
|
+
Cronos: Cronos,
|
|
6083
|
+
CronosTestnet: CronosTestnet,
|
|
5984
6084
|
Edge: Edge,
|
|
5985
6085
|
EdgeTestnet: EdgeTestnet,
|
|
5986
6086
|
Ethereum: Ethereum,
|
|
@@ -6122,7 +6222,10 @@ var Chains = {
|
|
|
6122
6222
|
minter: zod.z.string({
|
|
6123
6223
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6124
6224
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6125
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
6225
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
6226
|
+
depositForHandler: zod.z.string({
|
|
6227
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
6228
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
6126
6229
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6127
6230
|
;
|
|
6128
6231
|
/**
|
|
@@ -6644,21 +6747,31 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
6644
6747
|
* returning the appropriate address based on the requested contract type.
|
|
6645
6748
|
*
|
|
6646
6749
|
* @param chain - The chain definition to resolve the contract address for
|
|
6647
|
-
* @param contractType - The type of contract address to resolve ('tokenMessenger' or '
|
|
6750
|
+
* @param contractType - The type of contract address to resolve ('tokenMessenger', 'messageTransmitter', or 'tokenMessengerWithFees')
|
|
6648
6751
|
* @returns The contract address for the specified contract type
|
|
6649
6752
|
* @throws Error when chain does not support CCTP v2 or has unsupported contract configuration
|
|
6753
|
+
* @throws Error when 'tokenMessengerWithFees' is requested but not configured on the chain
|
|
6650
6754
|
*/ const resolveCCTPV2ContractAddress = (chain, contractType)=>{
|
|
6651
6755
|
// Handle custom bridge contract for tokenMessenger (burn transaction)
|
|
6652
|
-
if (hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6756
|
+
if (contractType === 'tokenMessenger' && hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6653
6757
|
return chain.kitContracts.bridge;
|
|
6654
6758
|
}
|
|
6655
6759
|
// At this point we know CCTP v2 is supported, so contracts exist
|
|
6656
6760
|
const cctpConfig = chain.cctp;
|
|
6657
6761
|
const contracts = cctpConfig.contracts.v2;
|
|
6762
|
+
// The `TokenMessengerWithFees` wrapper (prepaid FORWARD path) is an optional
|
|
6763
|
+
// deployment carried alongside both split and merged configurations.
|
|
6764
|
+
if (contractType === 'tokenMessengerWithFees') {
|
|
6765
|
+
const wrapper = contracts.tokenMessengerWithFees;
|
|
6766
|
+
if (wrapper === undefined || wrapper === '') {
|
|
6767
|
+
throw new Error(`TokenMessengerWithFees is not configured on chain ${chain.name}. The prepaid FORWARD path is unavailable on this chain.`);
|
|
6768
|
+
}
|
|
6769
|
+
return wrapper;
|
|
6770
|
+
}
|
|
6658
6771
|
// Handle different contract types with explicit type checking
|
|
6659
6772
|
switch(contracts.type){
|
|
6660
6773
|
case 'split':
|
|
6661
|
-
return contracts.tokenMessenger ;
|
|
6774
|
+
return contractType === 'tokenMessenger' ? contracts.tokenMessenger : contracts.messageTransmitter;
|
|
6662
6775
|
case 'merged':
|
|
6663
6776
|
return contracts.contract;
|
|
6664
6777
|
default:
|
|
@@ -8046,6 +8159,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8046
8159
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8047
8160
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8048
8161
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8162
|
+
[Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
8049
8163
|
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
8050
8164
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8051
8165
|
[Blockchain.Hedera]: '0.0.456858',
|
|
@@ -8079,6 +8193,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8079
8193
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8080
8194
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8081
8195
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8196
|
+
[Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
8082
8197
|
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
8083
8198
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8084
8199
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -8151,6 +8266,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8151
8266
|
// =========================================================================
|
|
8152
8267
|
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
8153
8268
|
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
8269
|
+
[Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
8154
8270
|
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
8155
8271
|
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
8156
8272
|
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
@@ -8159,6 +8275,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8159
8275
|
// =========================================================================
|
|
8160
8276
|
[Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
8161
8277
|
[Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
8278
|
+
[Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
8162
8279
|
[Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
8163
8280
|
}
|
|
8164
8281
|
};
|
|
@@ -9509,7 +9626,7 @@ function resolveOptions(options) {
|
|
|
9509
9626
|
}
|
|
9510
9627
|
|
|
9511
9628
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9512
|
-
var version$3 = "1.
|
|
9629
|
+
var version$3 = "1.12.1";
|
|
9513
9630
|
var pkg$3 = {
|
|
9514
9631
|
name: name$2,
|
|
9515
9632
|
version: version$3};
|
|
@@ -12013,6 +12130,144 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
12013
12130
|
return false;
|
|
12014
12131
|
};
|
|
12015
12132
|
|
|
12133
|
+
/**
|
|
12134
|
+
* The zero address, denoting a native-currency fee in a signed quote.
|
|
12135
|
+
*/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
12136
|
+
/**
|
|
12137
|
+
* Resolve the fee payment channel for a prepaid-FORWARD burn via `TokenMessengerWithFees`.
|
|
12138
|
+
*
|
|
12139
|
+
* Determines the native `msg.value` and the ERC-20 approvals required, honouring
|
|
12140
|
+
* the quote's `feeToken`:
|
|
12141
|
+
* - Native fee (`feeToken` is the zero address): attach exactly `feeTotalAmount`
|
|
12142
|
+
* as `msg.value`; approve only the burn amount.
|
|
12143
|
+
* - ERC-20 fee equal to the burn token (both USDC — the `isBurnTokenFee` case):
|
|
12144
|
+
* approve a single combined `amount + feeTotalAmount` and skip the redundant
|
|
12145
|
+
* second approval.
|
|
12146
|
+
* - ERC-20 fee different from the burn token: approve the burn amount and the fee
|
|
12147
|
+
* amount separately.
|
|
12148
|
+
*
|
|
12149
|
+
* This encodes only balance/allowance intent; it does not fetch balances. The
|
|
12150
|
+
* caller is responsible for a balance preflight against the fresh quote.
|
|
12151
|
+
*
|
|
12152
|
+
* @param params - The fee token, burn token, burn amount, and total fee amount.
|
|
12153
|
+
* @returns The resolved fee payment plan.
|
|
12154
|
+
* @throws KitError if `amount` or `feeTotalAmount` is negative.
|
|
12155
|
+
*
|
|
12156
|
+
* @example
|
|
12157
|
+
* ```typescript
|
|
12158
|
+
* // Native fee
|
|
12159
|
+
* resolveFeePayment({
|
|
12160
|
+
* feeToken: '0x0000000000000000000000000000000000000000',
|
|
12161
|
+
* burnToken: '0xUSDC...',
|
|
12162
|
+
* amount: 1_000_000n,
|
|
12163
|
+
* feeTotalAmount: 3_500_000n,
|
|
12164
|
+
* })
|
|
12165
|
+
* // → { isNativeFee: true, isBurnTokenFee: false, nativeValue: 3_500_000n,
|
|
12166
|
+
* // approvals: [{ token: '0xUSDC...', amount: 1_000_000n }] }
|
|
12167
|
+
* ```
|
|
12168
|
+
*/ const resolveFeePayment = (params)=>{
|
|
12169
|
+
const { feeToken, burnToken, amount, feeTotalAmount } = params;
|
|
12170
|
+
if (typeof amount !== 'bigint' || amount < 0n) {
|
|
12171
|
+
throw createValidationFailedError$1('amount', amount, 'Must be a non-negative bigint');
|
|
12172
|
+
}
|
|
12173
|
+
if (typeof feeTotalAmount !== 'bigint' || feeTotalAmount < 0n) {
|
|
12174
|
+
throw createValidationFailedError$1('feeTotalAmount', feeTotalAmount, 'Must be a non-negative bigint');
|
|
12175
|
+
}
|
|
12176
|
+
const isNativeFee = feeToken.toLowerCase() === ZERO_ADDRESS;
|
|
12177
|
+
const isBurnTokenFee = !isNativeFee && feeToken.toLowerCase() === burnToken.toLowerCase();
|
|
12178
|
+
if (isNativeFee) {
|
|
12179
|
+
return {
|
|
12180
|
+
isNativeFee: true,
|
|
12181
|
+
isBurnTokenFee: false,
|
|
12182
|
+
nativeValue: feeTotalAmount,
|
|
12183
|
+
approvals: [
|
|
12184
|
+
{
|
|
12185
|
+
token: burnToken,
|
|
12186
|
+
amount
|
|
12187
|
+
}
|
|
12188
|
+
]
|
|
12189
|
+
};
|
|
12190
|
+
}
|
|
12191
|
+
if (isBurnTokenFee) {
|
|
12192
|
+
// Fee and burn draw on the same token — a single combined approval covers
|
|
12193
|
+
// both; the redundant second approval is skipped.
|
|
12194
|
+
return {
|
|
12195
|
+
isNativeFee: false,
|
|
12196
|
+
isBurnTokenFee: true,
|
|
12197
|
+
nativeValue: 0n,
|
|
12198
|
+
approvals: [
|
|
12199
|
+
{
|
|
12200
|
+
token: burnToken,
|
|
12201
|
+
amount: amount + feeTotalAmount
|
|
12202
|
+
}
|
|
12203
|
+
]
|
|
12204
|
+
};
|
|
12205
|
+
}
|
|
12206
|
+
return {
|
|
12207
|
+
isNativeFee: false,
|
|
12208
|
+
isBurnTokenFee: false,
|
|
12209
|
+
nativeValue: 0n,
|
|
12210
|
+
approvals: [
|
|
12211
|
+
{
|
|
12212
|
+
token: burnToken,
|
|
12213
|
+
amount
|
|
12214
|
+
},
|
|
12215
|
+
{
|
|
12216
|
+
token: feeToken,
|
|
12217
|
+
amount: feeTotalAmount
|
|
12218
|
+
}
|
|
12219
|
+
]
|
|
12220
|
+
};
|
|
12221
|
+
};
|
|
12222
|
+
|
|
12223
|
+
/**
|
|
12224
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
12225
|
+
* hookData must start with.
|
|
12226
|
+
*/ const CCTP_FORWARD_MAGIC_HEX = Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
12227
|
+
/**
|
|
12228
|
+
* Determine whether a hookData blob begins with the `cctp-forward` envelope.
|
|
12229
|
+
*
|
|
12230
|
+
* The prepaid FORWARD path requires the GenericExecutor blob to be wrapped in a
|
|
12231
|
+
* `cctp-forward` frame; without it the wrapper reverts `ForwardFeeWithoutHook`.
|
|
12232
|
+
*
|
|
12233
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12234
|
+
* @returns True when the hookData starts with the `cctp-forward` magic.
|
|
12235
|
+
*
|
|
12236
|
+
* @example
|
|
12237
|
+
* ```typescript
|
|
12238
|
+
* hasForwardHook('0x636374702d666f7277617264...') // true
|
|
12239
|
+
* hasForwardHook('0xdeadbeef') // false
|
|
12240
|
+
* ```
|
|
12241
|
+
*/ const hasForwardHook = (hookData)=>{
|
|
12242
|
+
if (typeof hookData !== 'string') {
|
|
12243
|
+
return false;
|
|
12244
|
+
}
|
|
12245
|
+
const normalized = (hookData.startsWith('0x') ? hookData.slice(2) : hookData).toLowerCase();
|
|
12246
|
+
return normalized.startsWith(CCTP_FORWARD_MAGIC_HEX);
|
|
12247
|
+
};
|
|
12248
|
+
/**
|
|
12249
|
+
* Assert that a hookData blob is forward-friendly for the prepaid FORWARD path.
|
|
12250
|
+
*
|
|
12251
|
+
* The prepaid FORWARD path always requests a FORWARD fee item, so the wrapper
|
|
12252
|
+
* requires the hookData to start with a `cctp-forward` frame. Validating this
|
|
12253
|
+
* before the burn surfaces the guaranteed `ForwardFeeWithoutHook` revert as a
|
|
12254
|
+
* typed input error instead of an on-chain failure.
|
|
12255
|
+
*
|
|
12256
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12257
|
+
* @throws KitError (`INPUT_VALIDATION_FAILED`) if the hookData is missing or lacks
|
|
12258
|
+
* the `cctp-forward` frame.
|
|
12259
|
+
*
|
|
12260
|
+
* @example
|
|
12261
|
+
* ```typescript
|
|
12262
|
+
* assertForwardHookData(geForwardHookData) // ok
|
|
12263
|
+
* assertForwardHookData('0xdeadbeef') // throws — would revert ForwardFeeWithoutHook
|
|
12264
|
+
* ```
|
|
12265
|
+
*/ const assertForwardHookData = (hookData)=>{
|
|
12266
|
+
if (!hasForwardHook(hookData)) {
|
|
12267
|
+
throw createValidationFailedError$1('hookData', hookData, 'Prepaid FORWARD burns require a cctp-forward-wrapped hookData; without it the TokenMessengerWithFees wrapper reverts ForwardFeeWithoutHook');
|
|
12268
|
+
}
|
|
12269
|
+
};
|
|
12270
|
+
|
|
12016
12271
|
/**
|
|
12017
12272
|
* Type guard to validate the forwardFee object structure.
|
|
12018
12273
|
*
|
|
@@ -12169,6 +12424,15 @@ const CUSTOM_BURN_GAS_ESTIMATE_EVM = 201_525n // p99 and max are same here: 201_
|
|
|
12169
12424
|
;
|
|
12170
12425
|
const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_839n) / 2 = 237_401n
|
|
12171
12426
|
;
|
|
12427
|
+
// Hard execution caps: observed max + ~30% buffer, used as gasLimit overrides on
|
|
12428
|
+
// chains whose eth_estimateGas under-reports (e.g. Cronos EIP-7623 calldata floor).
|
|
12429
|
+
// Kept separate from the fee-estimate averages above.
|
|
12430
|
+
const APPROVE_GAS_LIMIT_EVM = 100_000n // ERC-20 approve observed max ~46k
|
|
12431
|
+
;
|
|
12432
|
+
const DEPOSIT_FOR_BURN_GAS_LIMIT_EVM = 300_000n // observed max 226_506 + ~30%
|
|
12433
|
+
;
|
|
12434
|
+
const RECEIVE_MESSAGE_GAS_LIMIT_EVM = 400_000n // observed max 310_839 + ~30%
|
|
12435
|
+
;
|
|
12172
12436
|
/**
|
|
12173
12437
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
12174
12438
|
*
|
|
@@ -12197,6 +12461,27 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12197
12461
|
'Content-Type': 'application/json'
|
|
12198
12462
|
}
|
|
12199
12463
|
};
|
|
12464
|
+
/**
|
|
12465
|
+
* Merges caller-provided polling overrides on top of {@link DEFAULT_CONFIG}.
|
|
12466
|
+
*
|
|
12467
|
+
* Headers are merged independently so caller-supplied headers augment the
|
|
12468
|
+
* defaults (such as `Content-Type`) rather than replacing them wholesale.
|
|
12469
|
+
*
|
|
12470
|
+
* @param config - Caller-provided polling configuration overrides
|
|
12471
|
+
* @param internalDefaults - Internal defaults applied before `config` (for example a
|
|
12472
|
+
* reduced `maxRetries` for one-shot requests); `config` still wins on conflict
|
|
12473
|
+
* @returns The effective polling configuration
|
|
12474
|
+
* @internal
|
|
12475
|
+
*/ const mergeAttestationConfig = (config, internalDefaults = {})=>({
|
|
12476
|
+
...DEFAULT_CONFIG,
|
|
12477
|
+
...internalDefaults,
|
|
12478
|
+
...config,
|
|
12479
|
+
headers: {
|
|
12480
|
+
...DEFAULT_CONFIG.headers,
|
|
12481
|
+
...internalDefaults.headers,
|
|
12482
|
+
...config.headers
|
|
12483
|
+
}
|
|
12484
|
+
});
|
|
12200
12485
|
/**
|
|
12201
12486
|
* Type guard that verifies if an unknown value matches the AttestationMessage shape
|
|
12202
12487
|
* and has all required properties.
|
|
@@ -12343,10 +12628,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12343
12628
|
* ```
|
|
12344
12629
|
*/ const fetchAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12345
12630
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12346
|
-
const effectiveConfig =
|
|
12347
|
-
...DEFAULT_CONFIG,
|
|
12348
|
-
...config
|
|
12349
|
-
};
|
|
12631
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12350
12632
|
return await pollApiGet(url, isAttestationResponse, effectiveConfig);
|
|
12351
12633
|
};
|
|
12352
12634
|
/**
|
|
@@ -12389,11 +12671,9 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12389
12671
|
*/ const fetchAttestationWithoutStatusCheck = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12390
12672
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12391
12673
|
// Use minimal retries since we're just fetching existing data
|
|
12392
|
-
const effectiveConfig = {
|
|
12393
|
-
|
|
12394
|
-
|
|
12395
|
-
...config
|
|
12396
|
-
};
|
|
12674
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
12675
|
+
maxRetries: 3
|
|
12676
|
+
});
|
|
12397
12677
|
return await pollApiGet(url, isAttestationResponseWithoutStatusCheck, effectiveConfig);
|
|
12398
12678
|
};
|
|
12399
12679
|
/**
|
|
@@ -12453,10 +12733,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12453
12733
|
* ```
|
|
12454
12734
|
*/ const fetchReAttestedAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12455
12735
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12456
|
-
const effectiveConfig =
|
|
12457
|
-
...DEFAULT_CONFIG,
|
|
12458
|
-
...config
|
|
12459
|
-
};
|
|
12736
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12460
12737
|
return await pollApiGet(url, isReAttestedAttestationResponse, effectiveConfig);
|
|
12461
12738
|
};
|
|
12462
12739
|
/**
|
|
@@ -12522,81 +12799,206 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12522
12799
|
*/ const requestReAttestation = async (nonce, isTestnet, config = {})=>{
|
|
12523
12800
|
const url = buildReAttestUrl(nonce, isTestnet);
|
|
12524
12801
|
// Use minimal retries since we're just submitting a request, not polling for state
|
|
12525
|
-
const effectiveConfig = {
|
|
12526
|
-
|
|
12527
|
-
|
|
12528
|
-
...config
|
|
12529
|
-
};
|
|
12802
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
12803
|
+
maxRetries: 3
|
|
12804
|
+
});
|
|
12530
12805
|
return await pollApiPost(url, {}, isReAttestationResponse, effectiveConfig);
|
|
12531
12806
|
};
|
|
12532
12807
|
|
|
12533
|
-
const assertCCTPv2WalletContextSymbol = Symbol('assertCCTPv2WalletContext');
|
|
12534
12808
|
/**
|
|
12535
|
-
*
|
|
12536
|
-
* The validation includes:
|
|
12537
|
-
* - Basic wallet context validation (adapter, address, chain)
|
|
12538
|
-
* - CCTPv2-specific chain validation (must be an EVM chain)
|
|
12539
|
-
*
|
|
12540
|
-
* @param params - The parameters to validate
|
|
12541
|
-
* @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
|
|
12542
|
-
*
|
|
12543
|
-
* @example
|
|
12544
|
-
* ```typescript
|
|
12545
|
-
* import { assertCCTPv2WalletContext } from '@circle-fin/provider-cctp-v2'
|
|
12546
|
-
* import { Ethereum } from '@core/chains'
|
|
12809
|
+
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
12547
12810
|
*
|
|
12548
|
-
*
|
|
12549
|
-
*
|
|
12550
|
-
*
|
|
12551
|
-
* prepare: async () => ({ data: 'prepared transaction' }),
|
|
12552
|
-
* waitForTransaction: async () => ({ status: 'confirmed' })
|
|
12553
|
-
* },
|
|
12554
|
-
* address: '0x1234567890123456789012345678901234567890',
|
|
12555
|
-
* chain: {
|
|
12556
|
-
* ...Ethereum,
|
|
12557
|
-
* usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
12558
|
-
* cctp: {
|
|
12559
|
-
* domain: 1,
|
|
12560
|
-
* contracts: {
|
|
12561
|
-
* v2: {
|
|
12562
|
-
* tokenMessenger: '0xTokenMessenger',
|
|
12563
|
-
* messageTransmitter: '0xMessageTransmitter'
|
|
12564
|
-
* }
|
|
12565
|
-
* }
|
|
12566
|
-
* }
|
|
12567
|
-
* }
|
|
12568
|
-
* }
|
|
12811
|
+
* This function validates that:
|
|
12812
|
+
* 1. The response has valid AttestationResponse structure
|
|
12813
|
+
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
12569
12814
|
*
|
|
12570
|
-
*
|
|
12571
|
-
*
|
|
12815
|
+
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
12816
|
+
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
12572
12817
|
*
|
|
12573
|
-
*
|
|
12574
|
-
*
|
|
12575
|
-
*
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12818
|
+
* @param obj - The value to check, typically a parsed JSON response
|
|
12819
|
+
* @returns True if the relayer has confirmed the mint
|
|
12820
|
+
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
12821
|
+
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
12822
|
+
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
12823
|
+
* @internal
|
|
12824
|
+
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
12825
|
+
// First check if the structure is valid
|
|
12826
|
+
if (!hasValidAttestationStructure(obj)) {
|
|
12827
|
+
throw new KitError({
|
|
12828
|
+
...InputError.VALIDATION_FAILED,
|
|
12829
|
+
recoverability: 'FATAL',
|
|
12830
|
+
message: 'Invalid attestation response structure from IRIS API.'
|
|
12831
|
+
});
|
|
12584
12832
|
}
|
|
12585
|
-
//
|
|
12586
|
-
|
|
12587
|
-
|
|
12833
|
+
// Find the first message (typically there's only one)
|
|
12834
|
+
const message = obj.messages[0];
|
|
12835
|
+
if (!message) {
|
|
12836
|
+
throw new KitError({
|
|
12837
|
+
...InputError.VALIDATION_FAILED,
|
|
12838
|
+
recoverability: 'FATAL',
|
|
12839
|
+
message: 'No attestation messages found in IRIS API response.'
|
|
12840
|
+
});
|
|
12588
12841
|
}
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12842
|
+
// Check for FAILED state - this is a permanent failure
|
|
12843
|
+
if (message.forwardState === 'FAILED') {
|
|
12844
|
+
throw new KitError({
|
|
12845
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
12846
|
+
recoverability: 'RESUMABLE',
|
|
12847
|
+
message: 'Circle relayer failed to forward the mint transaction. The mint may still have succeeded if another party submitted it. Check the recipient wallet balance before retrying. If the mint did not occur, you can manually submit it using the attestation data in the error cause.',
|
|
12848
|
+
cause: {
|
|
12849
|
+
trace: {
|
|
12850
|
+
eventNonce: message.eventNonce,
|
|
12851
|
+
attestation: message.attestation,
|
|
12852
|
+
message: message.message
|
|
12853
|
+
}
|
|
12854
|
+
}
|
|
12855
|
+
});
|
|
12856
|
+
}
|
|
12857
|
+
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
12858
|
+
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
12859
|
+
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
12860
|
+
return true;
|
|
12861
|
+
}
|
|
12862
|
+
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
12863
|
+
throw new KitError({
|
|
12864
|
+
...NetworkError.RELAYER_PENDING,
|
|
12865
|
+
recoverability: 'RETRYABLE',
|
|
12866
|
+
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
12867
|
+
});
|
|
12868
|
+
};
|
|
12592
12869
|
/**
|
|
12593
|
-
*
|
|
12594
|
-
*
|
|
12595
|
-
*
|
|
12596
|
-
*
|
|
12597
|
-
*
|
|
12598
|
-
*
|
|
12599
|
-
*
|
|
12870
|
+
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
12871
|
+
*
|
|
12872
|
+
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
12873
|
+
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
12874
|
+
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
12875
|
+
*
|
|
12876
|
+
* @remarks
|
|
12877
|
+
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
12878
|
+
* - Throws immediately if `forwardState` is 'FAILED'
|
|
12879
|
+
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
12880
|
+
* - Returns the attestation message with `forwardTxHash` populated
|
|
12881
|
+
*
|
|
12882
|
+
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
12883
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
12884
|
+
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
12885
|
+
* @param config - Optional configuration overrides for polling behavior
|
|
12886
|
+
* @returns The attestation message with confirmed forwardTxHash
|
|
12887
|
+
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
12888
|
+
* @throws {KitError} If timeout is reached while still pending
|
|
12889
|
+
*
|
|
12890
|
+
* @example
|
|
12891
|
+
* ```typescript
|
|
12892
|
+
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
12893
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
12894
|
+
* ```
|
|
12895
|
+
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12896
|
+
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12897
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12898
|
+
let response;
|
|
12899
|
+
try {
|
|
12900
|
+
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
12901
|
+
} catch (error) {
|
|
12902
|
+
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
12903
|
+
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
12904
|
+
throw new KitError({
|
|
12905
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
12906
|
+
recoverability: error.recoverability,
|
|
12907
|
+
message: error.message,
|
|
12908
|
+
cause: {
|
|
12909
|
+
...error.cause,
|
|
12910
|
+
trace: {
|
|
12911
|
+
...error.cause?.trace,
|
|
12912
|
+
burnTxHash: transactionHash
|
|
12913
|
+
}
|
|
12914
|
+
}
|
|
12915
|
+
});
|
|
12916
|
+
}
|
|
12917
|
+
throw error;
|
|
12918
|
+
}
|
|
12919
|
+
// Return the first message (which should have forwardTxHash)
|
|
12920
|
+
// Note: This check is needed for TypeScript type safety even though
|
|
12921
|
+
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
12922
|
+
// narrows the type at the call site, but TypeScript can't infer that
|
|
12923
|
+
// the array still has elements after pollApiGet returns.
|
|
12924
|
+
const message = response.messages[0];
|
|
12925
|
+
if (!message) {
|
|
12926
|
+
throw new KitError({
|
|
12927
|
+
...InputError.VALIDATION_FAILED,
|
|
12928
|
+
recoverability: 'FATAL',
|
|
12929
|
+
message: 'No attestation messages found in response after polling.'
|
|
12930
|
+
});
|
|
12931
|
+
}
|
|
12932
|
+
return message;
|
|
12933
|
+
};
|
|
12934
|
+
|
|
12935
|
+
const assertCCTPv2WalletContextSymbol = Symbol('assertCCTPv2WalletContext');
|
|
12936
|
+
/**
|
|
12937
|
+
* Asserts that the provided parameters match the CCTPv2 wallet context interface.
|
|
12938
|
+
* The validation includes:
|
|
12939
|
+
* - Basic wallet context validation (adapter, address, chain)
|
|
12940
|
+
* - CCTPv2-specific chain validation (must be an EVM chain)
|
|
12941
|
+
*
|
|
12942
|
+
* @param params - The parameters to validate
|
|
12943
|
+
* @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
|
|
12944
|
+
*
|
|
12945
|
+
* @example
|
|
12946
|
+
* ```typescript
|
|
12947
|
+
* import { assertCCTPv2WalletContext } from '@circle-fin/provider-cctp-v2'
|
|
12948
|
+
* import { Ethereum } from '@core/chains'
|
|
12949
|
+
*
|
|
12950
|
+
* // Prepare wallet context
|
|
12951
|
+
* const context = {
|
|
12952
|
+
* adapter: {
|
|
12953
|
+
* prepare: async () => ({ data: 'prepared transaction' }),
|
|
12954
|
+
* waitForTransaction: async () => ({ status: 'confirmed' })
|
|
12955
|
+
* },
|
|
12956
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12957
|
+
* chain: {
|
|
12958
|
+
* ...Ethereum,
|
|
12959
|
+
* usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
12960
|
+
* cctp: {
|
|
12961
|
+
* domain: 1,
|
|
12962
|
+
* contracts: {
|
|
12963
|
+
* v2: {
|
|
12964
|
+
* tokenMessenger: '0xTokenMessenger',
|
|
12965
|
+
* messageTransmitter: '0xMessageTransmitter'
|
|
12966
|
+
* }
|
|
12967
|
+
* }
|
|
12968
|
+
* }
|
|
12969
|
+
* }
|
|
12970
|
+
* }
|
|
12971
|
+
*
|
|
12972
|
+
* // This will throw if validation fails
|
|
12973
|
+
* assertCCTPv2WalletContext(context)
|
|
12974
|
+
*
|
|
12975
|
+
* // If we get here, context is guaranteed to be valid
|
|
12976
|
+
* console.log('CCTPv2 wallet context is valid')
|
|
12977
|
+
* ```
|
|
12978
|
+
*/ function assertCCTPv2WalletContext(params) {
|
|
12979
|
+
// First validate basic wallet context
|
|
12980
|
+
validateWithStateTracking(params, walletContextSchema, 'CCTPv2 wallet context', assertCCTPv2WalletContextSymbol);
|
|
12981
|
+
// After validation, we know params is WalletContext
|
|
12982
|
+
const context = params;
|
|
12983
|
+
// Validate USDC support
|
|
12984
|
+
if (context.chain.usdcAddress === null) {
|
|
12985
|
+
throw createInvalidChainError(context.chain.name, 'Does not have USDC configured');
|
|
12986
|
+
}
|
|
12987
|
+
// Validate CCTPv2 support
|
|
12988
|
+
if (!isCCTPV2Supported(context.chain)) {
|
|
12989
|
+
throw createInvalidChainError(context.chain.name, 'Does not support CCTPv2');
|
|
12990
|
+
}
|
|
12991
|
+
}
|
|
12992
|
+
|
|
12993
|
+
const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
12994
|
+
/**
|
|
12995
|
+
* Asserts that the provided parameters match the CCTPv2 bridge parameters interface.
|
|
12996
|
+
* The validation includes:
|
|
12997
|
+
* - Basic parameter structure and types
|
|
12998
|
+
* - Amount validation (non-empty numeric string \> 0)
|
|
12999
|
+
* - Wallet address format validation (must be valid Ethereum address)
|
|
13000
|
+
* - Chain definition validation (must be a valid chain with required properties)
|
|
13001
|
+
* - Adapter validation (must implement required methods)
|
|
12600
13002
|
* - Optional config validation (transfer speed and max fee)
|
|
12601
13003
|
* - Network compatibility (source and destination chains must both be testnet or both mainnet)
|
|
12602
13004
|
* - CCTPv2-specific wallet context validations
|
|
@@ -12797,6 +13199,109 @@ const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
|
12797
13199
|
}
|
|
12798
13200
|
}
|
|
12799
13201
|
|
|
13202
|
+
/**
|
|
13203
|
+
* Assert that `params` is a well-formed {@link BurnWithFeesParams} object.
|
|
13204
|
+
*
|
|
13205
|
+
* Validates the full public-boundary input before any field destructuring,
|
|
13206
|
+
* `BigInt()` coercion, or adapter preparation runs, so malformed JS-caller
|
|
13207
|
+
* inputs always produce typed `KitError` validation failures.
|
|
13208
|
+
*
|
|
13209
|
+
* Checks performed (in order):
|
|
13210
|
+
* - `params` must be a non-null plain object
|
|
13211
|
+
* - `source` — valid CCTP v2 wallet context (via `assertCCTPv2WalletContext`)
|
|
13212
|
+
* - `destinationChain` — present and supports CCTP v2
|
|
13213
|
+
* - source and destination chains must both be testnet or both mainnet
|
|
13214
|
+
* - source and destination chains must differ
|
|
13215
|
+
* - `executor` — non-empty string
|
|
13216
|
+
* - `amount` — bigint or non-empty string coercible to bigint
|
|
13217
|
+
* - `feeTotalAmount` — bigint or non-empty string coercible to bigint
|
|
13218
|
+
* - `feeToken` — valid EVM address (`0x` + 40 hex chars)
|
|
13219
|
+
* - `claim.signedQuote` — valid `0x`-prefixed hex string
|
|
13220
|
+
* - `claim.refundAddress` — valid EVM address
|
|
13221
|
+
* - `hookData` — valid `0x`-prefixed hex string when present
|
|
13222
|
+
*
|
|
13223
|
+
* @param params - The value to validate.
|
|
13224
|
+
* @throws {KitError} If any field is missing or invalid.
|
|
13225
|
+
*
|
|
13226
|
+
* @example
|
|
13227
|
+
* ```typescript
|
|
13228
|
+
* assertBurnWithFeesParams(params)
|
|
13229
|
+
* // params is now typed as BurnWithFeesParams and safe to use
|
|
13230
|
+
* const { source, destinationChain, amount } = params
|
|
13231
|
+
* ```
|
|
13232
|
+
*/ function assertBurnWithFeesParams(params) {
|
|
13233
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
13234
|
+
throw createValidationFailedError$1('params', params, 'Must be a non-null plain object');
|
|
13235
|
+
}
|
|
13236
|
+
const p = params;
|
|
13237
|
+
// Source wallet context
|
|
13238
|
+
assertCCTPv2WalletContext(p['source']);
|
|
13239
|
+
const source = p['source'];
|
|
13240
|
+
// destinationChain
|
|
13241
|
+
const destinationChain = p['destinationChain'];
|
|
13242
|
+
if (destinationChain === null || destinationChain === undefined || typeof destinationChain !== 'object') {
|
|
13243
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'Must be a chain definition object');
|
|
13244
|
+
}
|
|
13245
|
+
if (!isCCTPV2Supported(destinationChain)) {
|
|
13246
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'destinationChain must support CCTP v2');
|
|
13247
|
+
}
|
|
13248
|
+
const dest = destinationChain;
|
|
13249
|
+
// Testnet / mainnet mismatch
|
|
13250
|
+
if (source.chain.isTestnet !== dest.isTestnet) {
|
|
13251
|
+
throw createNetworkMismatchError(source.chain, dest);
|
|
13252
|
+
}
|
|
13253
|
+
// Same-chain guard
|
|
13254
|
+
if (source.chain.name === dest.name) {
|
|
13255
|
+
throw createUnsupportedRouteError(source.chain.name, dest.name);
|
|
13256
|
+
}
|
|
13257
|
+
// executor
|
|
13258
|
+
const executor = p['executor'];
|
|
13259
|
+
if (typeof executor !== 'string' || executor === '') {
|
|
13260
|
+
throw createValidationFailedError$1('executor', executor, 'A GenericExecutor address is required (used for both mintRecipient and destinationCaller)');
|
|
13261
|
+
}
|
|
13262
|
+
// amount
|
|
13263
|
+
const rawAmount = p['amount'];
|
|
13264
|
+
if (typeof rawAmount !== 'bigint' && typeof rawAmount !== 'string' || rawAmount === '') {
|
|
13265
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a bigint or a numeric string');
|
|
13266
|
+
}
|
|
13267
|
+
try {
|
|
13268
|
+
BigInt(rawAmount);
|
|
13269
|
+
} catch {
|
|
13270
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a valid integer value coercible to bigint');
|
|
13271
|
+
}
|
|
13272
|
+
// feeTotalAmount
|
|
13273
|
+
const rawFee = p['feeTotalAmount'];
|
|
13274
|
+
if (typeof rawFee !== 'bigint' && typeof rawFee !== 'string' || rawFee === '') {
|
|
13275
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a bigint or a numeric string');
|
|
13276
|
+
}
|
|
13277
|
+
try {
|
|
13278
|
+
BigInt(rawFee);
|
|
13279
|
+
} catch {
|
|
13280
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a valid integer value coercible to bigint');
|
|
13281
|
+
}
|
|
13282
|
+
// feeToken
|
|
13283
|
+
if (!evmAddressSchema.safeParse(p['feeToken']).success) {
|
|
13284
|
+
throw createValidationFailedError$1('feeToken', p['feeToken'], 'Must be a valid EVM address (use the zero address for a native fee)');
|
|
13285
|
+
}
|
|
13286
|
+
// claim
|
|
13287
|
+
const rawClaim = p['claim'];
|
|
13288
|
+
if (rawClaim === null || typeof rawClaim !== 'object' || Array.isArray(rawClaim)) {
|
|
13289
|
+
throw createValidationFailedError$1('claim', rawClaim, 'Must be an object with signedQuote and refundAddress');
|
|
13290
|
+
}
|
|
13291
|
+
const claim = rawClaim;
|
|
13292
|
+
if (!hexStringSchema.safeParse(claim['signedQuote']).success) {
|
|
13293
|
+
throw createValidationFailedError$1('claim.signedQuote', claim['signedQuote'], 'Must be a valid hex string starting with 0x');
|
|
13294
|
+
}
|
|
13295
|
+
if (!evmAddressSchema.safeParse(claim['refundAddress']).success) {
|
|
13296
|
+
throw createValidationFailedError$1('claim.refundAddress', claim['refundAddress'], 'Must be a valid EVM address');
|
|
13297
|
+
}
|
|
13298
|
+
// hookData (optional)
|
|
13299
|
+
const hookData = p['hookData'];
|
|
13300
|
+
if (hookData !== undefined && hookData !== '' && !hexStringSchema.safeParse(hookData).success) {
|
|
13301
|
+
throw createValidationFailedError$1('hookData', hookData, 'Must be a valid hex string starting with 0x');
|
|
13302
|
+
}
|
|
13303
|
+
}
|
|
13304
|
+
|
|
12800
13305
|
/**
|
|
12801
13306
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
12802
13307
|
*
|
|
@@ -13404,6 +13909,8 @@ function hasPendingState(analysis, result) {
|
|
|
13404
13909
|
* - `adapter`: The adapter that will execute the transaction
|
|
13405
13910
|
* - `confirmations`: The number of confirmations to wait for (defaults to 1)
|
|
13406
13911
|
* - `timeout`: The timeout for the request in milliseconds
|
|
13912
|
+
* - `gasLimit`: Optional explicit gas limit (number) forwarded to EVM execute,
|
|
13913
|
+
* bypassing `eth_estimateGas`; ignored for non-EVM requests
|
|
13407
13914
|
* @returns The bridge step with the transaction details and explorer URL
|
|
13408
13915
|
* @throws If the transaction execution fails
|
|
13409
13916
|
*
|
|
@@ -13418,7 +13925,7 @@ function hasPendingState(analysis, result) {
|
|
|
13418
13925
|
* })
|
|
13419
13926
|
* console.log('Transaction hash:', step.txHash)
|
|
13420
13927
|
* ```
|
|
13421
|
-
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout }) {
|
|
13928
|
+
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout, gasLimit }) {
|
|
13422
13929
|
const step = {
|
|
13423
13930
|
name,
|
|
13424
13931
|
state: 'pending'
|
|
@@ -13431,7 +13938,9 @@ function hasPendingState(analysis, result) {
|
|
|
13431
13938
|
step.state = 'noop';
|
|
13432
13939
|
return step;
|
|
13433
13940
|
}
|
|
13434
|
-
const txHash = await request.execute(
|
|
13941
|
+
const txHash = request.type === 'evm' && gasLimit !== undefined ? await request.execute({
|
|
13942
|
+
gasLimit
|
|
13943
|
+
}) : await request.execute();
|
|
13435
13944
|
step.txHash = txHash;
|
|
13436
13945
|
const retryOptions = {
|
|
13437
13946
|
isRetryable: (err)=>isRetryableError$1(parseBlockchainError(err, {
|
|
@@ -13503,7 +14012,8 @@ function hasPendingState(analysis, result) {
|
|
|
13503
14012
|
name: 'approve',
|
|
13504
14013
|
adapter: params.source.adapter,
|
|
13505
14014
|
chain: params.source.chain,
|
|
13506
|
-
request: await provider.approve(params.source, approvalAmount)
|
|
14015
|
+
request: await provider.approve(params.source, approvalAmount),
|
|
14016
|
+
gasLimit: Number(APPROVE_GAS_LIMIT_EVM)
|
|
13507
14017
|
});
|
|
13508
14018
|
}
|
|
13509
14019
|
|
|
@@ -13530,7 +14040,8 @@ function hasPendingState(analysis, result) {
|
|
|
13530
14040
|
name: 'burn',
|
|
13531
14041
|
adapter: params.source.adapter,
|
|
13532
14042
|
chain: params.source.chain,
|
|
13533
|
-
request: await provider.burn(params)
|
|
14043
|
+
request: await provider.burn(params),
|
|
14044
|
+
gasLimit: Number(DEPOSIT_FOR_BURN_GAS_LIMIT_EVM)
|
|
13534
14045
|
});
|
|
13535
14046
|
}
|
|
13536
14047
|
|
|
@@ -13616,11 +14127,18 @@ function hasPendingState(analysis, result) {
|
|
|
13616
14127
|
*/ async function bridgeMint({ params, provider }, attestation) {
|
|
13617
14128
|
// Validate attestation message matches transfer params
|
|
13618
14129
|
await assertCCTPv2AttestationParams(attestation, params);
|
|
14130
|
+
const mintRequest = await provider.mint(params.source, params.destination, attestation);
|
|
13619
14131
|
const step = await executePreparedChainRequest({
|
|
13620
14132
|
name: 'mint',
|
|
13621
14133
|
adapter: params.destination.adapter,
|
|
13622
14134
|
chain: params.destination.chain,
|
|
13623
|
-
request:
|
|
14135
|
+
request: mintRequest,
|
|
14136
|
+
// Some chains (e.g. Cronos) enforce an EIP-7623 calldata gas floor that
|
|
14137
|
+
// eth_estimateGas does not account for, returning a below-floor value
|
|
14138
|
+
// without reverting. Pinning to a value above the observed execution max
|
|
14139
|
+
// (310_839) bypasses re-estimation and guarantees we clear both the floor
|
|
14140
|
+
// and the actual execution cost.
|
|
14141
|
+
gasLimit: Number(RECEIVE_MESSAGE_GAS_LIMIT_EVM)
|
|
13624
14142
|
});
|
|
13625
14143
|
// Add forwarded: false for non-relayer mints
|
|
13626
14144
|
return {
|
|
@@ -13658,136 +14176,6 @@ const mockAttestationMessage = {
|
|
|
13658
14176
|
delayReason: null
|
|
13659
14177
|
};
|
|
13660
14178
|
|
|
13661
|
-
/**
|
|
13662
|
-
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
13663
|
-
*
|
|
13664
|
-
* This function validates that:
|
|
13665
|
-
* 1. The response has valid AttestationResponse structure
|
|
13666
|
-
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
13667
|
-
*
|
|
13668
|
-
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
13669
|
-
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
13670
|
-
*
|
|
13671
|
-
* @param obj - The value to check, typically a parsed JSON response
|
|
13672
|
-
* @returns True if the relayer has confirmed the mint
|
|
13673
|
-
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
13674
|
-
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
13675
|
-
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
13676
|
-
* @internal
|
|
13677
|
-
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
13678
|
-
// First check if the structure is valid
|
|
13679
|
-
if (!hasValidAttestationStructure(obj)) {
|
|
13680
|
-
throw new KitError({
|
|
13681
|
-
...InputError.VALIDATION_FAILED,
|
|
13682
|
-
recoverability: 'FATAL',
|
|
13683
|
-
message: 'Invalid attestation response structure from IRIS API.'
|
|
13684
|
-
});
|
|
13685
|
-
}
|
|
13686
|
-
// Find the first message (typically there's only one)
|
|
13687
|
-
const message = obj.messages[0];
|
|
13688
|
-
if (!message) {
|
|
13689
|
-
throw new KitError({
|
|
13690
|
-
...InputError.VALIDATION_FAILED,
|
|
13691
|
-
recoverability: 'FATAL',
|
|
13692
|
-
message: 'No attestation messages found in IRIS API response.'
|
|
13693
|
-
});
|
|
13694
|
-
}
|
|
13695
|
-
// Check for FAILED state - this is a permanent failure
|
|
13696
|
-
if (message.forwardState === 'FAILED') {
|
|
13697
|
-
throw new KitError({
|
|
13698
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
13699
|
-
recoverability: 'RESUMABLE',
|
|
13700
|
-
message: 'Circle relayer failed to forward the mint transaction. The mint may still have succeeded if another party submitted it. Check the recipient wallet balance before retrying. If the mint did not occur, you can manually submit it using the attestation data in the error cause.',
|
|
13701
|
-
cause: {
|
|
13702
|
-
trace: {
|
|
13703
|
-
eventNonce: message.eventNonce,
|
|
13704
|
-
attestation: message.attestation,
|
|
13705
|
-
message: message.message
|
|
13706
|
-
}
|
|
13707
|
-
}
|
|
13708
|
-
});
|
|
13709
|
-
}
|
|
13710
|
-
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
13711
|
-
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
13712
|
-
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
13713
|
-
return true;
|
|
13714
|
-
}
|
|
13715
|
-
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
13716
|
-
throw new KitError({
|
|
13717
|
-
...NetworkError.RELAYER_PENDING,
|
|
13718
|
-
recoverability: 'RETRYABLE',
|
|
13719
|
-
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
13720
|
-
});
|
|
13721
|
-
};
|
|
13722
|
-
/**
|
|
13723
|
-
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
13724
|
-
*
|
|
13725
|
-
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
13726
|
-
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
13727
|
-
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
13728
|
-
*
|
|
13729
|
-
* @remarks
|
|
13730
|
-
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
13731
|
-
* - Throws immediately if `forwardState` is 'FAILED'
|
|
13732
|
-
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
13733
|
-
* - Returns the attestation message with `forwardTxHash` populated
|
|
13734
|
-
*
|
|
13735
|
-
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
13736
|
-
* @param transactionHash - The transaction hash of the burn operation
|
|
13737
|
-
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
13738
|
-
* @param config - Optional configuration overrides for polling behavior
|
|
13739
|
-
* @returns The attestation message with confirmed forwardTxHash
|
|
13740
|
-
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
13741
|
-
* @throws {KitError} If timeout is reached while still pending
|
|
13742
|
-
*
|
|
13743
|
-
* @example
|
|
13744
|
-
* ```typescript
|
|
13745
|
-
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
13746
|
-
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
13747
|
-
* ```
|
|
13748
|
-
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
13749
|
-
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
13750
|
-
const effectiveConfig = {
|
|
13751
|
-
...DEFAULT_CONFIG,
|
|
13752
|
-
...config
|
|
13753
|
-
};
|
|
13754
|
-
let response;
|
|
13755
|
-
try {
|
|
13756
|
-
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
13757
|
-
} catch (error) {
|
|
13758
|
-
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
13759
|
-
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
13760
|
-
throw new KitError({
|
|
13761
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
13762
|
-
recoverability: error.recoverability,
|
|
13763
|
-
message: error.message,
|
|
13764
|
-
cause: {
|
|
13765
|
-
...error.cause,
|
|
13766
|
-
trace: {
|
|
13767
|
-
...error.cause?.trace,
|
|
13768
|
-
burnTxHash: transactionHash
|
|
13769
|
-
}
|
|
13770
|
-
}
|
|
13771
|
-
});
|
|
13772
|
-
}
|
|
13773
|
-
throw error;
|
|
13774
|
-
}
|
|
13775
|
-
// Return the first message (which should have forwardTxHash)
|
|
13776
|
-
// Note: This check is needed for TypeScript type safety even though
|
|
13777
|
-
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
13778
|
-
// narrows the type at the call site, but TypeScript can't infer that
|
|
13779
|
-
// the array still has elements after pollApiGet returns.
|
|
13780
|
-
const message = response.messages[0];
|
|
13781
|
-
if (!message) {
|
|
13782
|
-
throw new KitError({
|
|
13783
|
-
...InputError.VALIDATION_FAILED,
|
|
13784
|
-
recoverability: 'FATAL',
|
|
13785
|
-
message: 'No attestation messages found in response after polling.'
|
|
13786
|
-
});
|
|
13787
|
-
}
|
|
13788
|
-
return message;
|
|
13789
|
-
};
|
|
13790
|
-
|
|
13791
14179
|
/**
|
|
13792
14180
|
* Executes the mint step for forwarding mode where Circle's relayer handles the mint.
|
|
13793
14181
|
*
|
|
@@ -13801,6 +14189,7 @@ const mockAttestationMessage = {
|
|
|
13801
14189
|
* immediately after the API confirms the mint.
|
|
13802
14190
|
*
|
|
13803
14191
|
* @param params - The bridge parameters containing source, destination, amount and config
|
|
14192
|
+
* @param provider - The CCTP v2 bridging provider
|
|
13804
14193
|
* @param context - The step context containing burnTxHash from the burn step
|
|
13805
14194
|
* @returns Promise resolving to the bridge step with transaction details
|
|
13806
14195
|
* @throws {KitError} If burnTxHash is not available in context
|
|
@@ -13809,10 +14198,13 @@ const mockAttestationMessage = {
|
|
|
13809
14198
|
*
|
|
13810
14199
|
* @example
|
|
13811
14200
|
* ```typescript
|
|
13812
|
-
* const step = await bridgeRelayerMint(
|
|
14201
|
+
* const step = await bridgeRelayerMint(
|
|
14202
|
+
* { params, provider },
|
|
14203
|
+
* { burnTxHash: '0x...' }
|
|
14204
|
+
* )
|
|
13813
14205
|
* console.log('Relayer mint tx:', step.txHash)
|
|
13814
14206
|
* ```
|
|
13815
|
-
*/ async function bridgeRelayerMint(params, context) {
|
|
14207
|
+
*/ async function bridgeRelayerMint({ params, provider }, context) {
|
|
13816
14208
|
const step = {
|
|
13817
14209
|
name: 'mint',
|
|
13818
14210
|
state: 'pending',
|
|
@@ -13828,7 +14220,7 @@ const mockAttestationMessage = {
|
|
|
13828
14220
|
}
|
|
13829
14221
|
try {
|
|
13830
14222
|
// Poll attestation API until relayer confirms the mint
|
|
13831
|
-
const attestation = await fetchRelayerMint(params.source
|
|
14223
|
+
const attestation = await provider.fetchRelayerMint(params.source, context.burnTxHash);
|
|
13832
14224
|
// Extract the relayer's mint transaction hash
|
|
13833
14225
|
const forwardTxHash = attestation.forwardTxHash;
|
|
13834
14226
|
if (!forwardTxHash) {
|
|
@@ -13922,7 +14314,7 @@ const mockAttestationMessage = {
|
|
|
13922
14314
|
name: 'mint',
|
|
13923
14315
|
// bridgeRelayerMint validates context.burnTxHash internally with a KitError
|
|
13924
14316
|
// bridgeMint requires attestationData which is validated here
|
|
13925
|
-
executor: useForwarder ? async (params,
|
|
14317
|
+
executor: useForwarder ? async (params, provider, context)=>{
|
|
13926
14318
|
if (!context) {
|
|
13927
14319
|
throw new KitError({
|
|
13928
14320
|
...InputError.VALIDATION_FAILED,
|
|
@@ -13930,7 +14322,10 @@ const mockAttestationMessage = {
|
|
|
13930
14322
|
message: 'Step context is required for relayer mint'
|
|
13931
14323
|
});
|
|
13932
14324
|
}
|
|
13933
|
-
return bridgeRelayerMint(
|
|
14325
|
+
return bridgeRelayerMint({
|
|
14326
|
+
params,
|
|
14327
|
+
provider
|
|
14328
|
+
}, context);
|
|
13934
14329
|
} : async (params, provider, context)=>{
|
|
13935
14330
|
if (!context?.attestationData) {
|
|
13936
14331
|
throw new KitError({
|
|
@@ -14115,10 +14510,15 @@ const mockAttestationMessage = {
|
|
|
14115
14510
|
const burnCallData = burnRequest.getCallData();
|
|
14116
14511
|
// batchExecute may throw before submission (wallet declined) but never
|
|
14117
14512
|
// after — post-submission errors are returned as empty receipts.
|
|
14513
|
+
// The sender is threaded for adapters whose execution is routed through a
|
|
14514
|
+
// signing strategy (which has no wallet account to read it from); the
|
|
14515
|
+
// wallet-client path ignores it.
|
|
14118
14516
|
const batchResult = await adapter.batchExecute([
|
|
14119
14517
|
approveCallData,
|
|
14120
14518
|
burnCallData
|
|
14121
|
-
], chain
|
|
14519
|
+
], chain, {
|
|
14520
|
+
fromAddress: params.source.address
|
|
14521
|
+
});
|
|
14122
14522
|
const approveReceipt = batchResult.receipts[0];
|
|
14123
14523
|
const burnReceipt = batchResult.receipts[1];
|
|
14124
14524
|
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
|
|
@@ -14261,7 +14661,7 @@ const mockAttestationMessage = {
|
|
|
14261
14661
|
return step;
|
|
14262
14662
|
}
|
|
14263
14663
|
|
|
14264
|
-
var version$2 = "1.
|
|
14664
|
+
var version$2 = "1.10.0";
|
|
14265
14665
|
var pkg$2 = {
|
|
14266
14666
|
version: version$2};
|
|
14267
14667
|
|
|
@@ -14967,6 +15367,39 @@ var pkg$2 = {
|
|
|
14967
15367
|
}
|
|
14968
15368
|
}
|
|
14969
15369
|
|
|
15370
|
+
function isPlainObject(value) {
|
|
15371
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
15372
|
+
return false;
|
|
15373
|
+
}
|
|
15374
|
+
const prototype = Object.getPrototypeOf(value);
|
|
15375
|
+
return prototype === Object.prototype || prototype === null;
|
|
15376
|
+
}
|
|
15377
|
+
function assertHeadersConfig(headers, field) {
|
|
15378
|
+
if (headers === undefined) {
|
|
15379
|
+
return;
|
|
15380
|
+
}
|
|
15381
|
+
if (!isPlainObject(headers)) {
|
|
15382
|
+
throw createValidationFailedError$1(field, headers, `${field} must be a plain object with string header values when provided`);
|
|
15383
|
+
}
|
|
15384
|
+
for (const [name, value] of Object.entries(headers)){
|
|
15385
|
+
if (typeof value !== 'string') {
|
|
15386
|
+
throw createValidationFailedError$1(`${field}.${name}`, value, 'header values must be strings');
|
|
15387
|
+
}
|
|
15388
|
+
}
|
|
15389
|
+
}
|
|
15390
|
+
function assertCCTPV2Config(config) {
|
|
15391
|
+
if (!isPlainObject(config)) {
|
|
15392
|
+
throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
|
|
15393
|
+
}
|
|
15394
|
+
assertHeadersConfig(config['headers'], 'config.headers');
|
|
15395
|
+
const attestation = config['attestation'];
|
|
15396
|
+
if (attestation !== undefined) {
|
|
15397
|
+
if (!isPlainObject(attestation)) {
|
|
15398
|
+
throw createValidationFailedError$1('config.attestation', attestation, 'config.attestation must be a plain object when provided');
|
|
15399
|
+
}
|
|
15400
|
+
assertHeadersConfig(attestation['headers'], 'config.attestation.headers');
|
|
15401
|
+
}
|
|
15402
|
+
}
|
|
14970
15403
|
/**
|
|
14971
15404
|
* All chains that are supported by the CCTP v2 provider.
|
|
14972
15405
|
*
|
|
@@ -15035,9 +15468,38 @@ var pkg$2 = {
|
|
|
15035
15468
|
* @param config - Optional configuration overrides for the provider
|
|
15036
15469
|
*/ constructor(config = {}){
|
|
15037
15470
|
super();
|
|
15471
|
+
assertCCTPV2Config(config);
|
|
15038
15472
|
this.config = config;
|
|
15039
15473
|
}
|
|
15040
15474
|
/**
|
|
15475
|
+
* Resolves the effective polling configuration for an attestation request.
|
|
15476
|
+
*
|
|
15477
|
+
* Precedence (lowest to highest): provider `config.attestation`, then the
|
|
15478
|
+
* per-call `config`. Headers merge independently across
|
|
15479
|
+
* `config.attestation.headers`, the provider-level `config.headers`, and any
|
|
15480
|
+
* per-call `config.headers`, so a more specific header augments rather than
|
|
15481
|
+
* replaces the broader ones. The `headers` key is omitted entirely when no
|
|
15482
|
+
* headers are configured, leaving the attestation fetchers' defaults intact.
|
|
15483
|
+
*
|
|
15484
|
+
* @param config - Optional per-call polling configuration overrides
|
|
15485
|
+
* @returns The merged polling configuration passed to the attestation fetchers
|
|
15486
|
+
*/ resolveAttestationConfig(config) {
|
|
15487
|
+
const headers = {
|
|
15488
|
+
...this.config?.attestation?.headers,
|
|
15489
|
+
...this.config?.headers,
|
|
15490
|
+
...config?.headers
|
|
15491
|
+
};
|
|
15492
|
+
// Polling fields follow normal precedence; headers are merged separately
|
|
15493
|
+
// below so narrower config layers augment rather than replace broader ones.
|
|
15494
|
+
return {
|
|
15495
|
+
...this.config?.attestation,
|
|
15496
|
+
...config,
|
|
15497
|
+
...Object.keys(headers).length > 0 ? {
|
|
15498
|
+
headers
|
|
15499
|
+
} : {}
|
|
15500
|
+
};
|
|
15501
|
+
}
|
|
15502
|
+
/**
|
|
15041
15503
|
* Execute a cross-chain USDC bridge operation using the CCTP v2 protocol.
|
|
15042
15504
|
*
|
|
15043
15505
|
* This method orchestrates the complete CCTP v2 bridge flow including validation,
|
|
@@ -15354,7 +15816,7 @@ var pkg$2 = {
|
|
|
15354
15816
|
throw new Error(`Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
15355
15817
|
}
|
|
15356
15818
|
// Resolve spender address with proper error handling
|
|
15357
|
-
const spenderAddress = resolveCCTPV2ContractAddress(chain);
|
|
15819
|
+
const spenderAddress = resolveCCTPV2ContractAddress(chain, 'tokenMessenger');
|
|
15358
15820
|
// Prepare action parameters
|
|
15359
15821
|
const actionParams = {
|
|
15360
15822
|
amount: BigInt(amount),
|
|
@@ -15463,11 +15925,7 @@ var pkg$2 = {
|
|
|
15463
15925
|
*/ async fetchAttestation(source, transactionHash, config) {
|
|
15464
15926
|
assertCCTPv2WalletContext(source);
|
|
15465
15927
|
try {
|
|
15466
|
-
|
|
15467
|
-
const effectiveConfig = {
|
|
15468
|
-
...this.config?.attestation,
|
|
15469
|
-
...config
|
|
15470
|
-
};
|
|
15928
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15471
15929
|
const response = await fetchAttestation(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15472
15930
|
const message = response.messages[0];
|
|
15473
15931
|
if (!message) {
|
|
@@ -15484,6 +15942,49 @@ var pkg$2 = {
|
|
|
15484
15942
|
}
|
|
15485
15943
|
}
|
|
15486
15944
|
/**
|
|
15945
|
+
* Polls attestation data until Circle's relayer mint transaction is confirmed.
|
|
15946
|
+
*
|
|
15947
|
+
* This method is used by forwarded transfers. It polls the same Iris
|
|
15948
|
+
* attestation endpoint as {@link CCTPV2BridgingProvider.fetchAttestation},
|
|
15949
|
+
* but waits for a completed relayer forward state and returns the attestation
|
|
15950
|
+
* message containing `forwardTxHash`.
|
|
15951
|
+
*
|
|
15952
|
+
* @typeParam TFromAdapterCapabilities - The type representing the capabilities of the source adapter
|
|
15953
|
+
* @param source - The source wallet context containing the chain definition and wallet address
|
|
15954
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
15955
|
+
* @param config - Optional polling configuration overrides for timeout, retries, delay, and headers
|
|
15956
|
+
* @returns A promise that resolves to the attestation message with `forwardTxHash`
|
|
15957
|
+
* @throws KitError If the relayer forward fails, the response is invalid, or polling times out
|
|
15958
|
+
*
|
|
15959
|
+
* @example
|
|
15960
|
+
* ```typescript
|
|
15961
|
+
* import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2'
|
|
15962
|
+
* import { Chains } from '@core/chains'
|
|
15963
|
+
*
|
|
15964
|
+
* const provider = new CCTPV2BridgingProvider({
|
|
15965
|
+
* headers: { 'X-Partner-UUID': '00000000-0000-0000-0000-000000000000' },
|
|
15966
|
+
* })
|
|
15967
|
+
*
|
|
15968
|
+
* const attestation = await provider.fetchRelayerMint(
|
|
15969
|
+
* {
|
|
15970
|
+
* adapter,
|
|
15971
|
+
* chain: Chains.EthereumSepolia,
|
|
15972
|
+
* address: '0x1234...',
|
|
15973
|
+
* },
|
|
15974
|
+
* '0xabc123...',
|
|
15975
|
+
* )
|
|
15976
|
+
*
|
|
15977
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
15978
|
+
* ```
|
|
15979
|
+
*/ async fetchRelayerMint(source, transactionHash, config) {
|
|
15980
|
+
assertCCTPv2WalletContext(source);
|
|
15981
|
+
if (typeof transactionHash !== 'string' || transactionHash.trim() === '') {
|
|
15982
|
+
throw createValidationFailedError$1('transactionHash', transactionHash, 'transactionHash must be a non-empty string');
|
|
15983
|
+
}
|
|
15984
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15985
|
+
return await fetchRelayerMint(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15986
|
+
}
|
|
15987
|
+
/**
|
|
15487
15988
|
* Requests a fresh attestation for an expired attestation.
|
|
15488
15989
|
*
|
|
15489
15990
|
* This method is used when the original attestation has expired before the mint
|
|
@@ -15537,11 +16038,7 @@ var pkg$2 = {
|
|
|
15537
16038
|
throw new Error('Failed to re-attest: Invalid transaction hash');
|
|
15538
16039
|
}
|
|
15539
16040
|
try {
|
|
15540
|
-
|
|
15541
|
-
const effectiveConfig = {
|
|
15542
|
-
...this.config?.attestation,
|
|
15543
|
-
...config
|
|
15544
|
-
};
|
|
16041
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15545
16042
|
// Step 1: Get existing attestation data to extract nonce
|
|
15546
16043
|
const existingAttestation = await fetchAttestationWithoutStatusCheck(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15547
16044
|
const nonce = existingAttestation.messages[0]?.eventNonce;
|
|
@@ -15799,6 +16296,106 @@ var pkg$2 = {
|
|
|
15799
16296
|
return await source.adapter.prepareAction('cctp.v2.depositForBurn', actionParams, resolvedContext);
|
|
15800
16297
|
}
|
|
15801
16298
|
/**
|
|
16299
|
+
* Prepare a prepaid-FORWARD burn through the `TokenMessengerWithFees` wrapper.
|
|
16300
|
+
*
|
|
16301
|
+
* Builds the source-chain `depositForBurnWithHookAndFees` call for the
|
|
16302
|
+
* GenericExecutor FORWARD path: fees are collected up front on the source chain
|
|
16303
|
+
* against a signed quote, `mintRecipient` and `destinationCaller` are both set to
|
|
16304
|
+
* the GenericExecutor, and the GE `hookData` is passed through unchanged.
|
|
16305
|
+
*
|
|
16306
|
+
* This is the low-level on-chain primitive behind the UBK `fastCrossChainDeposit`
|
|
16307
|
+
* and Bridge Kit `bridge({ deposit })` flows. The `hookData` and signed-quote
|
|
16308
|
+
* `claim` are produced elsewhere and passed in here:
|
|
16309
|
+
* - `hookData`: `buildForwardingHookDataWithPayload(version,
|
|
16310
|
+
* buildDepositForGenericExecutorPayload(...).hookData)` from `@core/utils`.
|
|
16311
|
+
* - `claim.signedQuote` / `feeToken` / `feeTotalAmount`: from `fetchFeeQuote`
|
|
16312
|
+
* (`@circle-fin/provider-fee-v1`), whose FORWARD item must be bound to the
|
|
16313
|
+
* SAME `hookData` and executor `destinationCaller` used here.
|
|
16314
|
+
*
|
|
16315
|
+
* The returned approvals and burn are NOT executed — the caller executes the
|
|
16316
|
+
* approvals first (in order) and then the burn. The fee payment channel matches
|
|
16317
|
+
* the quote's `feeToken`:
|
|
16318
|
+
* - Native fee: exactly `feeTotalAmount` is attached as the burn's `msg.value`;
|
|
16319
|
+
* only the burn amount is approved.
|
|
16320
|
+
* - USDC fee (same token as the burn): a single combined `amount + feeTotalAmount`
|
|
16321
|
+
* approval covers both; the redundant second approval is skipped.
|
|
16322
|
+
*
|
|
16323
|
+
* @typeParam TFromAdapterCapabilities - The source adapter's capabilities.
|
|
16324
|
+
* @param params - The burn amount, executor, hookData, signed-quote claim, and fee.
|
|
16325
|
+
* @returns The prepared approvals, the prepared burn, and the resolved fee plan.
|
|
16326
|
+
* @throws {KitError} If the wallet context is invalid, `destinationChain` does not
|
|
16327
|
+
* support CCTP v2, the executor is missing, `amount` or `feeTotalAmount` is not
|
|
16328
|
+
* a bigint or a numeric string coercible to bigint, the hookData lacks a
|
|
16329
|
+
* `cctp-forward` frame (guaranteed `ForwardFeeWithoutHook`), or the operation
|
|
16330
|
+
* context cannot be resolved.
|
|
16331
|
+
*
|
|
16332
|
+
* @example
|
|
16333
|
+
* ```typescript
|
|
16334
|
+
* const { approvals, burn } = await provider.burnWithFees({
|
|
16335
|
+
* source,
|
|
16336
|
+
* destinationChain: Arc,
|
|
16337
|
+
* amount: 1_000_000n,
|
|
16338
|
+
* executor: genericExecutorAddress,
|
|
16339
|
+
* hookData: geForwardHookData,
|
|
16340
|
+
* claim: { signedQuote: '0x01...', refundAddress: userAddress },
|
|
16341
|
+
* feeToken: '0x0000000000000000000000000000000000000000', // native
|
|
16342
|
+
* feeTotalAmount: 3_500_000n,
|
|
16343
|
+
* })
|
|
16344
|
+
* for (const approval of approvals) await approval.execute()
|
|
16345
|
+
* const txHash = await burn.execute()
|
|
16346
|
+
* ```
|
|
16347
|
+
*/ async burnWithFees(params) {
|
|
16348
|
+
assertBurnWithFeesParams(params);
|
|
16349
|
+
const { source, destinationChain, executor, hookData, claim, feeToken } = params;
|
|
16350
|
+
const amount = BigInt(params.amount);
|
|
16351
|
+
const feeTotalAmount = BigInt(params.feeTotalAmount);
|
|
16352
|
+
// Coupling guard: the prepaid FORWARD path always requests a FORWARD fee item,
|
|
16353
|
+
// so the hookData must carry a cctp-forward frame; otherwise the wrapper
|
|
16354
|
+
// reverts ForwardFeeWithoutHook. Surface it as a typed input error up front.
|
|
16355
|
+
assertForwardHookData(hookData);
|
|
16356
|
+
const burnToken = source.chain.usdcAddress;
|
|
16357
|
+
const feePayment = resolveFeePayment({
|
|
16358
|
+
feeToken,
|
|
16359
|
+
burnToken,
|
|
16360
|
+
amount,
|
|
16361
|
+
feeTotalAmount
|
|
16362
|
+
});
|
|
16363
|
+
// Resolve operation context from the source wallet context.
|
|
16364
|
+
const operationContext = this.extractOperationContext(source);
|
|
16365
|
+
let resolvedContext;
|
|
16366
|
+
try {
|
|
16367
|
+
resolvedContext = await resolveOperationContext(source.adapter, operationContext);
|
|
16368
|
+
} catch (error) {
|
|
16369
|
+
throw createValidationFailedError$1('source.adapter', undefined, `Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
16370
|
+
}
|
|
16371
|
+
const context = resolvedContext;
|
|
16372
|
+
const wrapperAddress = resolveCCTPV2ContractAddress(source.chain, 'tokenMessengerWithFees');
|
|
16373
|
+
// Build the ERC-20 approvals to the wrapper (burn token, plus a distinct fee
|
|
16374
|
+
// token only when the fee is not paid in the burn token).
|
|
16375
|
+
const approvals = await Promise.all(feePayment.approvals.map(async (approval)=>source.adapter.prepareAction('token.approve', {
|
|
16376
|
+
tokenAddress: approval.token,
|
|
16377
|
+
delegate: wrapperAddress,
|
|
16378
|
+
amount: approval.amount
|
|
16379
|
+
}, context)));
|
|
16380
|
+
// Build the burn: mintRecipient AND destinationCaller are both the executor.
|
|
16381
|
+
const burn = await source.adapter.prepareAction('cctp.v2.depositForBurnWithFees', {
|
|
16382
|
+
fromChain: source.chain,
|
|
16383
|
+
toChain: destinationChain,
|
|
16384
|
+
amount,
|
|
16385
|
+
mintRecipient: executor,
|
|
16386
|
+
destinationCaller: executor,
|
|
16387
|
+
hookData,
|
|
16388
|
+
claim,
|
|
16389
|
+
feeToken,
|
|
16390
|
+
feeTotalAmount
|
|
16391
|
+
}, context);
|
|
16392
|
+
return {
|
|
16393
|
+
approvals,
|
|
16394
|
+
burn,
|
|
16395
|
+
feePayment
|
|
16396
|
+
};
|
|
16397
|
+
}
|
|
16398
|
+
/**
|
|
15802
16399
|
* Waits for a transaction to be mined and confirmed on the blockchain.
|
|
15803
16400
|
*
|
|
15804
16401
|
* This method should block until the transaction is confirmed on the blockchain.
|
|
@@ -15826,8 +16423,13 @@ var pkg$2 = {
|
|
|
15826
16423
|
/**
|
|
15827
16424
|
* The default providers that will be used in addition to the providers provided
|
|
15828
16425
|
* to the BridgeKit constructor.
|
|
15829
|
-
|
|
15830
|
-
|
|
16426
|
+
*
|
|
16427
|
+
* @param config - Optional configuration forwarded to the default providers
|
|
16428
|
+
* @returns The default bridging providers
|
|
16429
|
+
*/ const getDefaultProviders = (config = {})=>[
|
|
16430
|
+
new CCTPV2BridgingProvider(config.headers ? {
|
|
16431
|
+
headers: config.headers
|
|
16432
|
+
} : {})
|
|
15831
16433
|
];
|
|
15832
16434
|
|
|
15833
16435
|
/**
|
|
@@ -16070,7 +16672,9 @@ var pkg$2 = {
|
|
|
16070
16672
|
* ```
|
|
16071
16673
|
*/ constructor(config = {}){
|
|
16072
16674
|
// Handle provider configuration
|
|
16073
|
-
const defaultProviders = getDefaultProviders(
|
|
16675
|
+
const defaultProviders = getDefaultProviders(config.headers ? {
|
|
16676
|
+
headers: config.headers
|
|
16677
|
+
} : {});
|
|
16074
16678
|
this.providers = [
|
|
16075
16679
|
...defaultProviders,
|
|
16076
16680
|
...config.providers ?? []
|
|
@@ -16650,6 +17254,9 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16650
17254
|
const kit = new BridgeKit({
|
|
16651
17255
|
...context.disableErrorReporting != null && {
|
|
16652
17256
|
disableErrorReporting: context.disableErrorReporting
|
|
17257
|
+
},
|
|
17258
|
+
...context.headers != null && {
|
|
17259
|
+
headers: context.headers
|
|
16653
17260
|
}
|
|
16654
17261
|
});
|
|
16655
17262
|
if (hasBoth) {
|
|
@@ -16668,7 +17275,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16668
17275
|
};
|
|
16669
17276
|
|
|
16670
17277
|
var name$1 = "@circle-fin/swap-kit";
|
|
16671
|
-
var version$1 = "1.
|
|
17278
|
+
var version$1 = "1.4.0";
|
|
16672
17279
|
var pkg$1 = {
|
|
16673
17280
|
name: name$1,
|
|
16674
17281
|
version: version$1};
|
|
@@ -16733,7 +17340,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
16733
17340
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
16734
17341
|
provider: zod.z.string({
|
|
16735
17342
|
invalid_type_error: 'provider must be a string'
|
|
16736
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
17343
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
17344
|
+
batchTransactions: zod.z.boolean({
|
|
17345
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
17346
|
+
}).optional()
|
|
16737
17347
|
});
|
|
16738
17348
|
/**
|
|
16739
17349
|
* Zod schema for adapter context.
|
|
@@ -17172,7 +17782,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17172
17782
|
/**
|
|
17173
17783
|
* Circle Stablecoin Service API Key.
|
|
17174
17784
|
* Must be a valid API key format.
|
|
17175
|
-
*/ apiKey: apiKeySchema
|
|
17785
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17176
17786
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
17177
17787
|
/**
|
|
17178
17788
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -17230,7 +17840,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17230
17840
|
/**
|
|
17231
17841
|
* Circle Stablecoin Service API Key.
|
|
17232
17842
|
* Must be a valid API key format.
|
|
17233
|
-
*/ apiKey: apiKeySchema
|
|
17843
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17234
17844
|
});
|
|
17235
17845
|
/**
|
|
17236
17846
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -17266,7 +17876,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17266
17876
|
toChain: zod.z.string({
|
|
17267
17877
|
invalid_type_error: 'toChain must be a string'
|
|
17268
17878
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
17269
|
-
apiKey: apiKeySchema
|
|
17879
|
+
apiKey: apiKeySchema.optional()
|
|
17270
17880
|
});
|
|
17271
17881
|
/**
|
|
17272
17882
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -17275,13 +17885,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17275
17885
|
required_error: 'fee token is required',
|
|
17276
17886
|
invalid_type_error: 'fee token must be a string'
|
|
17277
17887
|
}).min(1, 'fee token must be a non-empty string'),
|
|
17278
|
-
amount: feeAmountSchema
|
|
17888
|
+
amount: feeAmountSchema,
|
|
17889
|
+
decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
17890
|
+
symbol: zod.z.string({
|
|
17891
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
17892
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
17279
17893
|
});
|
|
17280
17894
|
/**
|
|
17281
17895
|
* Developer fee item schema with basis field.
|
|
17282
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
17283
|
-
token: zod.z.string().min(1, 'fee token must be a non-empty string'),
|
|
17284
|
-
amount: feeAmountSchema,
|
|
17896
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
17285
17897
|
basis: zod.z.enum([
|
|
17286
17898
|
'inputAmount',
|
|
17287
17899
|
'estimatedAmount'
|
|
@@ -17373,7 +17985,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17373
17985
|
addresses: zod.z.array(zod.z.string({
|
|
17374
17986
|
invalid_type_error: 'addresses entries must be strings'
|
|
17375
17987
|
}).min(1, 'addresses entries must be non-empty strings')).min(1, 'addresses must contain at least one entry when provided').max(MAX_RATE_ADDRESSES_PER_REQUEST, `addresses supports at most ${String(MAX_RATE_ADDRESSES_PER_REQUEST)} values per request`).optional(),
|
|
17376
|
-
apiKey: apiKeySchema
|
|
17988
|
+
apiKey: apiKeySchema.optional()
|
|
17377
17989
|
});
|
|
17378
17990
|
/**
|
|
17379
17991
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -18596,7 +19208,7 @@ new Set(Object.values(Blockchain));
|
|
|
18596
19208
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18597
19209
|
|
|
18598
19210
|
var name = "@circle-fin/earn-kit";
|
|
18599
|
-
var version = "1.
|
|
19211
|
+
var version = "1.3.0";
|
|
18600
19212
|
var pkg = {
|
|
18601
19213
|
name: name,
|
|
18602
19214
|
version: version};
|
|
@@ -18726,7 +19338,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18726
19338
|
asset: zod.z.string(),
|
|
18727
19339
|
assetAddress: zod.z.string(),
|
|
18728
19340
|
lltv: zod.z.number(),
|
|
18729
|
-
supplyUsd: zod.z.number()
|
|
19341
|
+
supplyUsd: zod.z.number(),
|
|
19342
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
19343
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
19344
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
19345
|
+
allocationPct: zod.z.number().nullable().optional()
|
|
18730
19346
|
});
|
|
18731
19347
|
/**
|
|
18732
19348
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -18740,7 +19356,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18740
19356
|
])
|
|
18741
19357
|
});
|
|
18742
19358
|
/**
|
|
18743
|
-
* Zod schema for
|
|
19359
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
19360
|
+
*
|
|
19361
|
+
* @internal
|
|
19362
|
+
*/ const managerSchema = zod.z.object({
|
|
19363
|
+
name: zod.z.string(),
|
|
19364
|
+
address: zod.z.string().optional(),
|
|
19365
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
19366
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
19367
|
+
// speculatively.
|
|
19368
|
+
type: zod.z.enum([
|
|
19369
|
+
'curator'
|
|
19370
|
+
])
|
|
19371
|
+
});
|
|
19372
|
+
/**
|
|
19373
|
+
* Zod schema for the APY profile facet in the API response.
|
|
19374
|
+
*
|
|
19375
|
+
* @internal
|
|
19376
|
+
*/ const apyProfileSchema = zod.z.object({
|
|
19377
|
+
current: zod.z.number(),
|
|
19378
|
+
native: zod.z.number().nullable(),
|
|
19379
|
+
d7: zod.z.number().nullable(),
|
|
19380
|
+
d30: zod.z.number().nullable(),
|
|
19381
|
+
d90: zod.z.number().nullable(),
|
|
19382
|
+
rewardShare: zod.z.number().nullable(),
|
|
19383
|
+
source: zod.z.string().optional(),
|
|
19384
|
+
asOf: zod.z.string().optional()
|
|
19385
|
+
});
|
|
19386
|
+
/**
|
|
19387
|
+
* Zod schema for the fee split facet in the API response.
|
|
19388
|
+
*
|
|
19389
|
+
* @internal
|
|
19390
|
+
*/ const feeInfoSchema = zod.z.object({
|
|
19391
|
+
performance: zod.z.number().nullable(),
|
|
19392
|
+
management: zod.z.number().nullable()
|
|
19393
|
+
});
|
|
19394
|
+
/**
|
|
19395
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
19396
|
+
*
|
|
19397
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
19398
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
19399
|
+
*
|
|
19400
|
+
* @internal
|
|
19401
|
+
*/ const liquidityProfileSchema = zod.z.object({
|
|
19402
|
+
totalDeposits: amountJsonSchema,
|
|
19403
|
+
available: amountJsonSchema,
|
|
19404
|
+
totalSupply: amountJsonSchema,
|
|
19405
|
+
status: zod.z.enum([
|
|
19406
|
+
'active',
|
|
19407
|
+
'low_liquidity'
|
|
19408
|
+
])
|
|
19409
|
+
});
|
|
19410
|
+
/**
|
|
19411
|
+
* Zod schema for the risk signals facet in the API response.
|
|
19412
|
+
*
|
|
19413
|
+
* @internal
|
|
19414
|
+
*/ const riskSignalsSchema = zod.z.object({
|
|
19415
|
+
circleSentinel: zod.z.boolean(),
|
|
19416
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
19417
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
19418
|
+
});
|
|
19419
|
+
/**
|
|
19420
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
19421
|
+
*
|
|
19422
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
19423
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
19424
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
19425
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
19426
|
+
* backend; they become required after Expand ships.
|
|
18744
19427
|
*
|
|
18745
19428
|
* @internal
|
|
18746
19429
|
*/ const vaultInfoResponseSchema = zod.z.object({
|
|
@@ -18765,6 +19448,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18765
19448
|
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
18766
19449
|
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
18767
19450
|
});
|
|
19451
|
+
/**
|
|
19452
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
19453
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
19454
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
19455
|
+
*
|
|
19456
|
+
* @internal
|
|
19457
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
19458
|
+
address: zod.z.string().optional(),
|
|
19459
|
+
asOf: zod.z.string().optional(),
|
|
19460
|
+
manager: managerSchema.nullable().optional(),
|
|
19461
|
+
apyProfile: apyProfileSchema.optional(),
|
|
19462
|
+
fee: feeInfoSchema.optional(),
|
|
19463
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
19464
|
+
riskSignals: riskSignalsSchema.optional()
|
|
19465
|
+
});
|
|
19466
|
+
/**
|
|
19467
|
+
* Zod schema for the `vault` opportunity variant.
|
|
19468
|
+
*
|
|
19469
|
+
* @internal
|
|
19470
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
19471
|
+
productType: zod.z.literal('vault'),
|
|
19472
|
+
collateral: zod.z.array(collateralSchema)
|
|
19473
|
+
});
|
|
19474
|
+
/**
|
|
19475
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
19476
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
19477
|
+
*
|
|
19478
|
+
* @internal
|
|
19479
|
+
*/ const earnOpportunityVariants = [
|
|
19480
|
+
vaultOpportunitySchema
|
|
19481
|
+
];
|
|
19482
|
+
/** @internal */ const earnOpportunitySchema = zod.z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
19483
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
19484
|
+
/**
|
|
19485
|
+
* Tolerant list parser for earn opportunities.
|
|
19486
|
+
*
|
|
19487
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
19488
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
19489
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
19490
|
+
*
|
|
19491
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
19492
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
19493
|
+
* rather than dropping every vault the backend returns.
|
|
19494
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
19495
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
19496
|
+
* of rejecting the whole list.
|
|
19497
|
+
*
|
|
19498
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
19499
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
19500
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
19501
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
19502
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
19503
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
19504
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
19505
|
+
* `ZodError`).
|
|
19506
|
+
*
|
|
19507
|
+
* @internal
|
|
19508
|
+
*/ const earnOpportunityListSchema = zod.z.preprocess((raw)=>{
|
|
19509
|
+
if (!Array.isArray(raw)) {
|
|
19510
|
+
return raw;
|
|
19511
|
+
}
|
|
19512
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
19513
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
19514
|
+
const entries = raw;
|
|
19515
|
+
return entries.map((entry)=>{
|
|
19516
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
19517
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19518
|
+
return entry;
|
|
19519
|
+
}
|
|
19520
|
+
const record = entry;
|
|
19521
|
+
// Older backend predating productType: default to the only type then.
|
|
19522
|
+
return record.productType === undefined ? {
|
|
19523
|
+
...record,
|
|
19524
|
+
productType: 'vault'
|
|
19525
|
+
} : record;
|
|
19526
|
+
}).filter((entry)=>{
|
|
19527
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
19528
|
+
// productType this SDK version doesn't know). Everything else —
|
|
19529
|
+
// non-objects, a non-string productType — flows through to
|
|
19530
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
19531
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19532
|
+
return true;
|
|
19533
|
+
}
|
|
19534
|
+
const productType = entry.productType;
|
|
19535
|
+
if (typeof productType !== 'string') {
|
|
19536
|
+
return true;
|
|
19537
|
+
}
|
|
19538
|
+
return knownProductTypes.has(productType);
|
|
19539
|
+
});
|
|
19540
|
+
}, zod.z.array(earnOpportunitySchema));
|
|
18768
19541
|
// ---------------------------------------------------------------------------
|
|
18769
19542
|
// Position response schema
|
|
18770
19543
|
// ---------------------------------------------------------------------------
|
|
@@ -18894,6 +19667,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
|
18894
19667
|
*
|
|
18895
19668
|
* @internal
|
|
18896
19669
|
*/ const depositPayloadSchema = zod.z.object({
|
|
19670
|
+
execId: bridgeDepositExecIdSchema,
|
|
18897
19671
|
executionParams: depositExecutionParamsSchema,
|
|
18898
19672
|
signature: hexSignatureSchema
|
|
18899
19673
|
});
|
|
@@ -18985,6 +19759,21 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
18985
19759
|
amount: amountJsonSchema,
|
|
18986
19760
|
vaultAddress: hexAddressSchema
|
|
18987
19761
|
}).passthrough();
|
|
19762
|
+
/** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
|
|
19763
|
+
zod.z.object({
|
|
19764
|
+
mode: zod.z.literal('TIMESTAMP'),
|
|
19765
|
+
expiresAt: zod.z.string().datetime({
|
|
19766
|
+
offset: true
|
|
19767
|
+
})
|
|
19768
|
+
}),
|
|
19769
|
+
zod.z.object({
|
|
19770
|
+
mode: zod.z.literal('BLOCK_NUMBER'),
|
|
19771
|
+
expiresAtBlock: zod.z.number().int(),
|
|
19772
|
+
blockEstimatedAt: zod.z.string().datetime({
|
|
19773
|
+
offset: true
|
|
19774
|
+
}).optional()
|
|
19775
|
+
})
|
|
19776
|
+
]).optional().catch(undefined);
|
|
18988
19777
|
/**
|
|
18989
19778
|
* Zod schema for the bridge deposit prepare payload.
|
|
18990
19779
|
*
|
|
@@ -18996,6 +19785,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
18996
19785
|
execId: bridgeDepositExecIdSchema,
|
|
18997
19786
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
18998
19787
|
expiresAt: zod.z.string().datetime(),
|
|
19788
|
+
quoteIssuedAt: zod.z.string().datetime({
|
|
19789
|
+
offset: true
|
|
19790
|
+
}).optional().catch(undefined),
|
|
19791
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
18999
19792
|
review: bridgeDepositPrepareReviewSchema
|
|
19000
19793
|
});
|
|
19001
19794
|
/**
|
|
@@ -19061,6 +19854,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19061
19854
|
*
|
|
19062
19855
|
* @internal
|
|
19063
19856
|
*/ const withdrawPayloadSchema = zod.z.object({
|
|
19857
|
+
execId: bridgeDepositExecIdSchema,
|
|
19064
19858
|
executionParams: withdrawExecutionParamsSchema,
|
|
19065
19859
|
signature: hexSignatureSchema
|
|
19066
19860
|
});
|
|
@@ -19074,6 +19868,27 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19074
19868
|
data: withdrawPayloadSchema
|
|
19075
19869
|
});
|
|
19076
19870
|
// ---------------------------------------------------------------------------
|
|
19871
|
+
// Transaction report response schema
|
|
19872
|
+
// ---------------------------------------------------------------------------
|
|
19873
|
+
/**
|
|
19874
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
19875
|
+
*
|
|
19876
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
19877
|
+
* schema accepts any object shape and does not require specific fields.
|
|
19878
|
+
*
|
|
19879
|
+
* @internal
|
|
19880
|
+
*/ const transactionReportPayloadSchema = zod.z.object({}).passthrough();
|
|
19881
|
+
/**
|
|
19882
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
19883
|
+
*
|
|
19884
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
19885
|
+
* envelope.
|
|
19886
|
+
*
|
|
19887
|
+
* @internal
|
|
19888
|
+
*/ zod.z.object({
|
|
19889
|
+
data: transactionReportPayloadSchema
|
|
19890
|
+
});
|
|
19891
|
+
// ---------------------------------------------------------------------------
|
|
19077
19892
|
// Claim rewards response schema
|
|
19078
19893
|
// ---------------------------------------------------------------------------
|
|
19079
19894
|
/**
|
|
@@ -19121,10 +19936,11 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19121
19936
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
19122
19937
|
*
|
|
19123
19938
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
19124
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
19125
|
-
*
|
|
19126
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
19127
|
-
* `'
|
|
19939
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
19940
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
19941
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
19942
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
19943
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
19128
19944
|
*
|
|
19129
19945
|
* @internal
|
|
19130
19946
|
*/ const feeSchema = zod.z.object({
|
|
@@ -19133,6 +19949,30 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19133
19949
|
token: zod.z.string(),
|
|
19134
19950
|
amount: amountJsonSchema
|
|
19135
19951
|
});
|
|
19952
|
+
/**
|
|
19953
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
19954
|
+
*
|
|
19955
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
19956
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
19957
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
19958
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
19959
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
19960
|
+
*
|
|
19961
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
19962
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
19963
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
19964
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
19965
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
19966
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
19967
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
19968
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
19969
|
+
*
|
|
19970
|
+
* @internal
|
|
19971
|
+
*/ const quoteGasFeeSchema = zod.z.object({
|
|
19972
|
+
name: zod.z.string().optional(),
|
|
19973
|
+
fees: zod.z.unknown(),
|
|
19974
|
+
error: zod.z.string().optional()
|
|
19975
|
+
}).passthrough();
|
|
19136
19976
|
/**
|
|
19137
19977
|
* Zod schema for the inner deposit quote payload.
|
|
19138
19978
|
*
|
|
@@ -19148,7 +19988,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19148
19988
|
expectedShares: amountJsonSchema,
|
|
19149
19989
|
sharePrice: zod.z.string(),
|
|
19150
19990
|
currentApy: zod.z.number(),
|
|
19151
|
-
fees: zod.z.array(feeSchema).optional()
|
|
19991
|
+
fees: zod.z.array(feeSchema).optional(),
|
|
19992
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional()
|
|
19152
19993
|
});
|
|
19153
19994
|
/**
|
|
19154
19995
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -19175,6 +20016,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19175
20016
|
sharePrice: zod.z.string(),
|
|
19176
20017
|
maxWithdrawable: amountJsonSchema,
|
|
19177
20018
|
fees: zod.z.array(feeSchema),
|
|
20019
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional(),
|
|
19178
20020
|
warnings: zod.z.array(zod.z.string()).optional()
|
|
19179
20021
|
});
|
|
19180
20022
|
/**
|
|
@@ -19232,7 +20074,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19232
20074
|
*
|
|
19233
20075
|
* @internal
|
|
19234
20076
|
*/ const getVaultsPayloadSchema = zod.z.object({
|
|
19235
|
-
vaults:
|
|
20077
|
+
vaults: earnOpportunityListSchema,
|
|
19236
20078
|
errors: zod.z.array(vaultErrorSchema)
|
|
19237
20079
|
});
|
|
19238
20080
|
/**
|
|
@@ -19262,7 +20104,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19262
20104
|
*
|
|
19263
20105
|
* @internal
|
|
19264
20106
|
*/ const exploreVaultsPayloadSchema = zod.z.object({
|
|
19265
|
-
vaults:
|
|
20107
|
+
vaults: earnOpportunityListSchema,
|
|
19266
20108
|
pagination: explorePaginationSchema
|
|
19267
20109
|
});
|
|
19268
20110
|
/**
|