@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/estimateBridge.mjs
CHANGED
|
@@ -20,6 +20,7 @@ import { z } from 'zod';
|
|
|
20
20
|
import pino from 'pino';
|
|
21
21
|
import { formatUnits as formatUnits$1, parseUnits as parseUnits$1 } from '@ethersproject/units';
|
|
22
22
|
import { hexlify, hexZeroPad } from '@ethersproject/bytes';
|
|
23
|
+
import '@ethersproject/abi';
|
|
23
24
|
import { getAddress } from '@ethersproject/address';
|
|
24
25
|
import bs58 from 'bs58';
|
|
25
26
|
import { PublicKey } from '@solana/web3.js';
|
|
@@ -2472,6 +2473,8 @@ class KitError extends Error {
|
|
|
2472
2473
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
2473
2474
|
Blockchain["Codex"] = "Codex";
|
|
2474
2475
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
2476
|
+
Blockchain["Cronos"] = "Cronos";
|
|
2477
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2475
2478
|
Blockchain["Edge"] = "Edge";
|
|
2476
2479
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
2477
2480
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -2554,6 +2557,7 @@ var BridgeChain;
|
|
|
2554
2557
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
2555
2558
|
BridgeChain["Base"] = "Base";
|
|
2556
2559
|
BridgeChain["Codex"] = "Codex";
|
|
2560
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
2557
2561
|
BridgeChain["Edge"] = "Edge";
|
|
2558
2562
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
2559
2563
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -2578,6 +2582,7 @@ var BridgeChain;
|
|
|
2578
2582
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
2579
2583
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
2580
2584
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
2585
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2581
2586
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
2582
2587
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
2583
2588
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -3089,7 +3094,10 @@ var EarnChain;
|
|
|
3089
3094
|
contracts: {
|
|
3090
3095
|
v1: {
|
|
3091
3096
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3092
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
3097
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3098
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
3099
|
+
// deposit into the GatewayWallet above.
|
|
3100
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3093
3101
|
}
|
|
3094
3102
|
},
|
|
3095
3103
|
forwarderSupported: {
|
|
@@ -3623,6 +3631,96 @@ var EarnChain;
|
|
|
3623
3631
|
}
|
|
3624
3632
|
});
|
|
3625
3633
|
|
|
3634
|
+
/**
|
|
3635
|
+
* Cronos Mainnet chain definition
|
|
3636
|
+
* @remarks
|
|
3637
|
+
* This represents the official production network for the Cronos blockchain.
|
|
3638
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3639
|
+
*/ const Cronos = defineChain({
|
|
3640
|
+
type: 'evm',
|
|
3641
|
+
chain: Blockchain.Cronos,
|
|
3642
|
+
name: 'Cronos',
|
|
3643
|
+
title: 'Cronos Mainnet',
|
|
3644
|
+
nativeCurrency: {
|
|
3645
|
+
name: 'Cronos',
|
|
3646
|
+
symbol: 'CRO',
|
|
3647
|
+
decimals: 18
|
|
3648
|
+
},
|
|
3649
|
+
chainId: 25,
|
|
3650
|
+
isTestnet: false,
|
|
3651
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
3652
|
+
rpcEndpoints: [
|
|
3653
|
+
'https://evm.cronos.org'
|
|
3654
|
+
],
|
|
3655
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
3656
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
3657
|
+
usdtAddress: null,
|
|
3658
|
+
cctp: {
|
|
3659
|
+
domain: 32,
|
|
3660
|
+
contracts: {
|
|
3661
|
+
v2: {
|
|
3662
|
+
type: 'split',
|
|
3663
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
3664
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
3665
|
+
confirmations: 1,
|
|
3666
|
+
fastConfirmations: 1
|
|
3667
|
+
}
|
|
3668
|
+
},
|
|
3669
|
+
forwarderSupported: {
|
|
3670
|
+
source: false,
|
|
3671
|
+
destination: false
|
|
3672
|
+
}
|
|
3673
|
+
},
|
|
3674
|
+
kitContracts: {
|
|
3675
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
3676
|
+
}
|
|
3677
|
+
});
|
|
3678
|
+
|
|
3679
|
+
/**
|
|
3680
|
+
* Cronos Testnet chain definition
|
|
3681
|
+
* @remarks
|
|
3682
|
+
* This represents the official test network for the Cronos blockchain.
|
|
3683
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3684
|
+
*/ const CronosTestnet = defineChain({
|
|
3685
|
+
type: 'evm',
|
|
3686
|
+
chain: Blockchain.Cronos_Testnet,
|
|
3687
|
+
name: 'Cronos Testnet',
|
|
3688
|
+
title: 'Cronos Testnet',
|
|
3689
|
+
nativeCurrency: {
|
|
3690
|
+
name: 'CRO',
|
|
3691
|
+
symbol: 'tCRO',
|
|
3692
|
+
decimals: 18
|
|
3693
|
+
},
|
|
3694
|
+
chainId: 338,
|
|
3695
|
+
isTestnet: true,
|
|
3696
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
3697
|
+
rpcEndpoints: [
|
|
3698
|
+
'https://evm-t3.cronos.org'
|
|
3699
|
+
],
|
|
3700
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
3701
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
3702
|
+
usdtAddress: null,
|
|
3703
|
+
cctp: {
|
|
3704
|
+
domain: 32,
|
|
3705
|
+
contracts: {
|
|
3706
|
+
v2: {
|
|
3707
|
+
type: 'split',
|
|
3708
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
3709
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
3710
|
+
confirmations: 1,
|
|
3711
|
+
fastConfirmations: 1
|
|
3712
|
+
}
|
|
3713
|
+
},
|
|
3714
|
+
forwarderSupported: {
|
|
3715
|
+
source: false,
|
|
3716
|
+
destination: false
|
|
3717
|
+
}
|
|
3718
|
+
},
|
|
3719
|
+
kitContracts: {
|
|
3720
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
3721
|
+
}
|
|
3722
|
+
});
|
|
3723
|
+
|
|
3626
3724
|
/**
|
|
3627
3725
|
* Edge Mainnet chain definition
|
|
3628
3726
|
* @remarks
|
|
@@ -5974,6 +6072,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
5974
6072
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
5975
6073
|
Codex: Codex,
|
|
5976
6074
|
CodexTestnet: CodexTestnet,
|
|
6075
|
+
Cronos: Cronos,
|
|
6076
|
+
CronosTestnet: CronosTestnet,
|
|
5977
6077
|
Edge: Edge,
|
|
5978
6078
|
EdgeTestnet: EdgeTestnet,
|
|
5979
6079
|
Ethereum: Ethereum,
|
|
@@ -6115,7 +6215,10 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
6115
6215
|
minter: z.string({
|
|
6116
6216
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6117
6217
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6118
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
6218
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
6219
|
+
depositForHandler: z.string({
|
|
6220
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
6221
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
6119
6222
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6120
6223
|
;
|
|
6121
6224
|
/**
|
|
@@ -6637,21 +6740,31 @@ const swapTokenEnumSchema = z.enum([
|
|
|
6637
6740
|
* returning the appropriate address based on the requested contract type.
|
|
6638
6741
|
*
|
|
6639
6742
|
* @param chain - The chain definition to resolve the contract address for
|
|
6640
|
-
* @param contractType - The type of contract address to resolve ('tokenMessenger' or '
|
|
6743
|
+
* @param contractType - The type of contract address to resolve ('tokenMessenger', 'messageTransmitter', or 'tokenMessengerWithFees')
|
|
6641
6744
|
* @returns The contract address for the specified contract type
|
|
6642
6745
|
* @throws Error when chain does not support CCTP v2 or has unsupported contract configuration
|
|
6746
|
+
* @throws Error when 'tokenMessengerWithFees' is requested but not configured on the chain
|
|
6643
6747
|
*/ const resolveCCTPV2ContractAddress = (chain, contractType)=>{
|
|
6644
6748
|
// Handle custom bridge contract for tokenMessenger (burn transaction)
|
|
6645
|
-
if (hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6749
|
+
if (contractType === 'tokenMessenger' && hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6646
6750
|
return chain.kitContracts.bridge;
|
|
6647
6751
|
}
|
|
6648
6752
|
// At this point we know CCTP v2 is supported, so contracts exist
|
|
6649
6753
|
const cctpConfig = chain.cctp;
|
|
6650
6754
|
const contracts = cctpConfig.contracts.v2;
|
|
6755
|
+
// The `TokenMessengerWithFees` wrapper (prepaid FORWARD path) is an optional
|
|
6756
|
+
// deployment carried alongside both split and merged configurations.
|
|
6757
|
+
if (contractType === 'tokenMessengerWithFees') {
|
|
6758
|
+
const wrapper = contracts.tokenMessengerWithFees;
|
|
6759
|
+
if (wrapper === undefined || wrapper === '') {
|
|
6760
|
+
throw new Error(`TokenMessengerWithFees is not configured on chain ${chain.name}. The prepaid FORWARD path is unavailable on this chain.`);
|
|
6761
|
+
}
|
|
6762
|
+
return wrapper;
|
|
6763
|
+
}
|
|
6651
6764
|
// Handle different contract types with explicit type checking
|
|
6652
6765
|
switch(contracts.type){
|
|
6653
6766
|
case 'split':
|
|
6654
|
-
return contracts.tokenMessenger ;
|
|
6767
|
+
return contractType === 'tokenMessenger' ? contracts.tokenMessenger : contracts.messageTransmitter;
|
|
6655
6768
|
case 'merged':
|
|
6656
6769
|
return contracts.contract;
|
|
6657
6770
|
default:
|
|
@@ -8039,6 +8152,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8039
8152
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8040
8153
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8041
8154
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8155
|
+
[Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
8042
8156
|
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
8043
8157
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8044
8158
|
[Blockchain.Hedera]: '0.0.456858',
|
|
@@ -8072,6 +8186,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8072
8186
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8073
8187
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8074
8188
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8189
|
+
[Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
8075
8190
|
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
8076
8191
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8077
8192
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -8144,6 +8259,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8144
8259
|
// =========================================================================
|
|
8145
8260
|
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
8146
8261
|
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
8262
|
+
[Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
8147
8263
|
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
8148
8264
|
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
8149
8265
|
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
@@ -8152,6 +8268,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8152
8268
|
// =========================================================================
|
|
8153
8269
|
[Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
8154
8270
|
[Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
8271
|
+
[Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
8155
8272
|
[Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
8156
8273
|
}
|
|
8157
8274
|
};
|
|
@@ -9502,7 +9619,7 @@ function resolveOptions(options) {
|
|
|
9502
9619
|
}
|
|
9503
9620
|
|
|
9504
9621
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9505
|
-
var version$3 = "1.
|
|
9622
|
+
var version$3 = "1.12.1";
|
|
9506
9623
|
var pkg$3 = {
|
|
9507
9624
|
name: name$2,
|
|
9508
9625
|
version: version$3};
|
|
@@ -12006,6 +12123,144 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
12006
12123
|
return false;
|
|
12007
12124
|
};
|
|
12008
12125
|
|
|
12126
|
+
/**
|
|
12127
|
+
* The zero address, denoting a native-currency fee in a signed quote.
|
|
12128
|
+
*/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
12129
|
+
/**
|
|
12130
|
+
* Resolve the fee payment channel for a prepaid-FORWARD burn via `TokenMessengerWithFees`.
|
|
12131
|
+
*
|
|
12132
|
+
* Determines the native `msg.value` and the ERC-20 approvals required, honouring
|
|
12133
|
+
* the quote's `feeToken`:
|
|
12134
|
+
* - Native fee (`feeToken` is the zero address): attach exactly `feeTotalAmount`
|
|
12135
|
+
* as `msg.value`; approve only the burn amount.
|
|
12136
|
+
* - ERC-20 fee equal to the burn token (both USDC — the `isBurnTokenFee` case):
|
|
12137
|
+
* approve a single combined `amount + feeTotalAmount` and skip the redundant
|
|
12138
|
+
* second approval.
|
|
12139
|
+
* - ERC-20 fee different from the burn token: approve the burn amount and the fee
|
|
12140
|
+
* amount separately.
|
|
12141
|
+
*
|
|
12142
|
+
* This encodes only balance/allowance intent; it does not fetch balances. The
|
|
12143
|
+
* caller is responsible for a balance preflight against the fresh quote.
|
|
12144
|
+
*
|
|
12145
|
+
* @param params - The fee token, burn token, burn amount, and total fee amount.
|
|
12146
|
+
* @returns The resolved fee payment plan.
|
|
12147
|
+
* @throws KitError if `amount` or `feeTotalAmount` is negative.
|
|
12148
|
+
*
|
|
12149
|
+
* @example
|
|
12150
|
+
* ```typescript
|
|
12151
|
+
* // Native fee
|
|
12152
|
+
* resolveFeePayment({
|
|
12153
|
+
* feeToken: '0x0000000000000000000000000000000000000000',
|
|
12154
|
+
* burnToken: '0xUSDC...',
|
|
12155
|
+
* amount: 1_000_000n,
|
|
12156
|
+
* feeTotalAmount: 3_500_000n,
|
|
12157
|
+
* })
|
|
12158
|
+
* // → { isNativeFee: true, isBurnTokenFee: false, nativeValue: 3_500_000n,
|
|
12159
|
+
* // approvals: [{ token: '0xUSDC...', amount: 1_000_000n }] }
|
|
12160
|
+
* ```
|
|
12161
|
+
*/ const resolveFeePayment = (params)=>{
|
|
12162
|
+
const { feeToken, burnToken, amount, feeTotalAmount } = params;
|
|
12163
|
+
if (typeof amount !== 'bigint' || amount < 0n) {
|
|
12164
|
+
throw createValidationFailedError$1('amount', amount, 'Must be a non-negative bigint');
|
|
12165
|
+
}
|
|
12166
|
+
if (typeof feeTotalAmount !== 'bigint' || feeTotalAmount < 0n) {
|
|
12167
|
+
throw createValidationFailedError$1('feeTotalAmount', feeTotalAmount, 'Must be a non-negative bigint');
|
|
12168
|
+
}
|
|
12169
|
+
const isNativeFee = feeToken.toLowerCase() === ZERO_ADDRESS;
|
|
12170
|
+
const isBurnTokenFee = !isNativeFee && feeToken.toLowerCase() === burnToken.toLowerCase();
|
|
12171
|
+
if (isNativeFee) {
|
|
12172
|
+
return {
|
|
12173
|
+
isNativeFee: true,
|
|
12174
|
+
isBurnTokenFee: false,
|
|
12175
|
+
nativeValue: feeTotalAmount,
|
|
12176
|
+
approvals: [
|
|
12177
|
+
{
|
|
12178
|
+
token: burnToken,
|
|
12179
|
+
amount
|
|
12180
|
+
}
|
|
12181
|
+
]
|
|
12182
|
+
};
|
|
12183
|
+
}
|
|
12184
|
+
if (isBurnTokenFee) {
|
|
12185
|
+
// Fee and burn draw on the same token — a single combined approval covers
|
|
12186
|
+
// both; the redundant second approval is skipped.
|
|
12187
|
+
return {
|
|
12188
|
+
isNativeFee: false,
|
|
12189
|
+
isBurnTokenFee: true,
|
|
12190
|
+
nativeValue: 0n,
|
|
12191
|
+
approvals: [
|
|
12192
|
+
{
|
|
12193
|
+
token: burnToken,
|
|
12194
|
+
amount: amount + feeTotalAmount
|
|
12195
|
+
}
|
|
12196
|
+
]
|
|
12197
|
+
};
|
|
12198
|
+
}
|
|
12199
|
+
return {
|
|
12200
|
+
isNativeFee: false,
|
|
12201
|
+
isBurnTokenFee: false,
|
|
12202
|
+
nativeValue: 0n,
|
|
12203
|
+
approvals: [
|
|
12204
|
+
{
|
|
12205
|
+
token: burnToken,
|
|
12206
|
+
amount
|
|
12207
|
+
},
|
|
12208
|
+
{
|
|
12209
|
+
token: feeToken,
|
|
12210
|
+
amount: feeTotalAmount
|
|
12211
|
+
}
|
|
12212
|
+
]
|
|
12213
|
+
};
|
|
12214
|
+
};
|
|
12215
|
+
|
|
12216
|
+
/**
|
|
12217
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
12218
|
+
* hookData must start with.
|
|
12219
|
+
*/ const CCTP_FORWARD_MAGIC_HEX = Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
12220
|
+
/**
|
|
12221
|
+
* Determine whether a hookData blob begins with the `cctp-forward` envelope.
|
|
12222
|
+
*
|
|
12223
|
+
* The prepaid FORWARD path requires the GenericExecutor blob to be wrapped in a
|
|
12224
|
+
* `cctp-forward` frame; without it the wrapper reverts `ForwardFeeWithoutHook`.
|
|
12225
|
+
*
|
|
12226
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12227
|
+
* @returns True when the hookData starts with the `cctp-forward` magic.
|
|
12228
|
+
*
|
|
12229
|
+
* @example
|
|
12230
|
+
* ```typescript
|
|
12231
|
+
* hasForwardHook('0x636374702d666f7277617264...') // true
|
|
12232
|
+
* hasForwardHook('0xdeadbeef') // false
|
|
12233
|
+
* ```
|
|
12234
|
+
*/ const hasForwardHook = (hookData)=>{
|
|
12235
|
+
if (typeof hookData !== 'string') {
|
|
12236
|
+
return false;
|
|
12237
|
+
}
|
|
12238
|
+
const normalized = (hookData.startsWith('0x') ? hookData.slice(2) : hookData).toLowerCase();
|
|
12239
|
+
return normalized.startsWith(CCTP_FORWARD_MAGIC_HEX);
|
|
12240
|
+
};
|
|
12241
|
+
/**
|
|
12242
|
+
* Assert that a hookData blob is forward-friendly for the prepaid FORWARD path.
|
|
12243
|
+
*
|
|
12244
|
+
* The prepaid FORWARD path always requests a FORWARD fee item, so the wrapper
|
|
12245
|
+
* requires the hookData to start with a `cctp-forward` frame. Validating this
|
|
12246
|
+
* before the burn surfaces the guaranteed `ForwardFeeWithoutHook` revert as a
|
|
12247
|
+
* typed input error instead of an on-chain failure.
|
|
12248
|
+
*
|
|
12249
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12250
|
+
* @throws KitError (`INPUT_VALIDATION_FAILED`) if the hookData is missing or lacks
|
|
12251
|
+
* the `cctp-forward` frame.
|
|
12252
|
+
*
|
|
12253
|
+
* @example
|
|
12254
|
+
* ```typescript
|
|
12255
|
+
* assertForwardHookData(geForwardHookData) // ok
|
|
12256
|
+
* assertForwardHookData('0xdeadbeef') // throws — would revert ForwardFeeWithoutHook
|
|
12257
|
+
* ```
|
|
12258
|
+
*/ const assertForwardHookData = (hookData)=>{
|
|
12259
|
+
if (!hasForwardHook(hookData)) {
|
|
12260
|
+
throw createValidationFailedError$1('hookData', hookData, 'Prepaid FORWARD burns require a cctp-forward-wrapped hookData; without it the TokenMessengerWithFees wrapper reverts ForwardFeeWithoutHook');
|
|
12261
|
+
}
|
|
12262
|
+
};
|
|
12263
|
+
|
|
12009
12264
|
/**
|
|
12010
12265
|
* Type guard to validate the forwardFee object structure.
|
|
12011
12266
|
*
|
|
@@ -12162,6 +12417,15 @@ const CUSTOM_BURN_GAS_ESTIMATE_EVM = 201_525n // p99 and max are same here: 201_
|
|
|
12162
12417
|
;
|
|
12163
12418
|
const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_839n) / 2 = 237_401n
|
|
12164
12419
|
;
|
|
12420
|
+
// Hard execution caps: observed max + ~30% buffer, used as gasLimit overrides on
|
|
12421
|
+
// chains whose eth_estimateGas under-reports (e.g. Cronos EIP-7623 calldata floor).
|
|
12422
|
+
// Kept separate from the fee-estimate averages above.
|
|
12423
|
+
const APPROVE_GAS_LIMIT_EVM = 100_000n // ERC-20 approve observed max ~46k
|
|
12424
|
+
;
|
|
12425
|
+
const DEPOSIT_FOR_BURN_GAS_LIMIT_EVM = 300_000n // observed max 226_506 + ~30%
|
|
12426
|
+
;
|
|
12427
|
+
const RECEIVE_MESSAGE_GAS_LIMIT_EVM = 400_000n // observed max 310_839 + ~30%
|
|
12428
|
+
;
|
|
12165
12429
|
/**
|
|
12166
12430
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
12167
12431
|
*
|
|
@@ -12190,6 +12454,27 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12190
12454
|
'Content-Type': 'application/json'
|
|
12191
12455
|
}
|
|
12192
12456
|
};
|
|
12457
|
+
/**
|
|
12458
|
+
* Merges caller-provided polling overrides on top of {@link DEFAULT_CONFIG}.
|
|
12459
|
+
*
|
|
12460
|
+
* Headers are merged independently so caller-supplied headers augment the
|
|
12461
|
+
* defaults (such as `Content-Type`) rather than replacing them wholesale.
|
|
12462
|
+
*
|
|
12463
|
+
* @param config - Caller-provided polling configuration overrides
|
|
12464
|
+
* @param internalDefaults - Internal defaults applied before `config` (for example a
|
|
12465
|
+
* reduced `maxRetries` for one-shot requests); `config` still wins on conflict
|
|
12466
|
+
* @returns The effective polling configuration
|
|
12467
|
+
* @internal
|
|
12468
|
+
*/ const mergeAttestationConfig = (config, internalDefaults = {})=>({
|
|
12469
|
+
...DEFAULT_CONFIG,
|
|
12470
|
+
...internalDefaults,
|
|
12471
|
+
...config,
|
|
12472
|
+
headers: {
|
|
12473
|
+
...DEFAULT_CONFIG.headers,
|
|
12474
|
+
...internalDefaults.headers,
|
|
12475
|
+
...config.headers
|
|
12476
|
+
}
|
|
12477
|
+
});
|
|
12193
12478
|
/**
|
|
12194
12479
|
* Type guard that verifies if an unknown value matches the AttestationMessage shape
|
|
12195
12480
|
* and has all required properties.
|
|
@@ -12336,10 +12621,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12336
12621
|
* ```
|
|
12337
12622
|
*/ const fetchAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12338
12623
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12339
|
-
const effectiveConfig =
|
|
12340
|
-
...DEFAULT_CONFIG,
|
|
12341
|
-
...config
|
|
12342
|
-
};
|
|
12624
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12343
12625
|
return await pollApiGet(url, isAttestationResponse, effectiveConfig);
|
|
12344
12626
|
};
|
|
12345
12627
|
/**
|
|
@@ -12382,11 +12664,9 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12382
12664
|
*/ const fetchAttestationWithoutStatusCheck = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12383
12665
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12384
12666
|
// Use minimal retries since we're just fetching existing data
|
|
12385
|
-
const effectiveConfig = {
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
...config
|
|
12389
|
-
};
|
|
12667
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
12668
|
+
maxRetries: 3
|
|
12669
|
+
});
|
|
12390
12670
|
return await pollApiGet(url, isAttestationResponseWithoutStatusCheck, effectiveConfig);
|
|
12391
12671
|
};
|
|
12392
12672
|
/**
|
|
@@ -12446,10 +12726,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12446
12726
|
* ```
|
|
12447
12727
|
*/ const fetchReAttestedAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12448
12728
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12449
|
-
const effectiveConfig =
|
|
12450
|
-
...DEFAULT_CONFIG,
|
|
12451
|
-
...config
|
|
12452
|
-
};
|
|
12729
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12453
12730
|
return await pollApiGet(url, isReAttestedAttestationResponse, effectiveConfig);
|
|
12454
12731
|
};
|
|
12455
12732
|
/**
|
|
@@ -12515,81 +12792,206 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
12515
12792
|
*/ const requestReAttestation = async (nonce, isTestnet, config = {})=>{
|
|
12516
12793
|
const url = buildReAttestUrl(nonce, isTestnet);
|
|
12517
12794
|
// Use minimal retries since we're just submitting a request, not polling for state
|
|
12518
|
-
const effectiveConfig = {
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
...config
|
|
12522
|
-
};
|
|
12795
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
12796
|
+
maxRetries: 3
|
|
12797
|
+
});
|
|
12523
12798
|
return await pollApiPost(url, {}, isReAttestationResponse, effectiveConfig);
|
|
12524
12799
|
};
|
|
12525
12800
|
|
|
12526
|
-
const assertCCTPv2WalletContextSymbol = Symbol('assertCCTPv2WalletContext');
|
|
12527
12801
|
/**
|
|
12528
|
-
*
|
|
12529
|
-
* The validation includes:
|
|
12530
|
-
* - Basic wallet context validation (adapter, address, chain)
|
|
12531
|
-
* - CCTPv2-specific chain validation (must be an EVM chain)
|
|
12532
|
-
*
|
|
12533
|
-
* @param params - The parameters to validate
|
|
12534
|
-
* @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
|
|
12535
|
-
*
|
|
12536
|
-
* @example
|
|
12537
|
-
* ```typescript
|
|
12538
|
-
* import { assertCCTPv2WalletContext } from '@circle-fin/provider-cctp-v2'
|
|
12539
|
-
* import { Ethereum } from '@core/chains'
|
|
12802
|
+
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
12540
12803
|
*
|
|
12541
|
-
*
|
|
12542
|
-
*
|
|
12543
|
-
*
|
|
12544
|
-
* prepare: async () => ({ data: 'prepared transaction' }),
|
|
12545
|
-
* waitForTransaction: async () => ({ status: 'confirmed' })
|
|
12546
|
-
* },
|
|
12547
|
-
* address: '0x1234567890123456789012345678901234567890',
|
|
12548
|
-
* chain: {
|
|
12549
|
-
* ...Ethereum,
|
|
12550
|
-
* usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
12551
|
-
* cctp: {
|
|
12552
|
-
* domain: 1,
|
|
12553
|
-
* contracts: {
|
|
12554
|
-
* v2: {
|
|
12555
|
-
* tokenMessenger: '0xTokenMessenger',
|
|
12556
|
-
* messageTransmitter: '0xMessageTransmitter'
|
|
12557
|
-
* }
|
|
12558
|
-
* }
|
|
12559
|
-
* }
|
|
12560
|
-
* }
|
|
12561
|
-
* }
|
|
12804
|
+
* This function validates that:
|
|
12805
|
+
* 1. The response has valid AttestationResponse structure
|
|
12806
|
+
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
12562
12807
|
*
|
|
12563
|
-
*
|
|
12564
|
-
*
|
|
12808
|
+
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
12809
|
+
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
12565
12810
|
*
|
|
12566
|
-
*
|
|
12567
|
-
*
|
|
12568
|
-
*
|
|
12569
|
-
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12811
|
+
* @param obj - The value to check, typically a parsed JSON response
|
|
12812
|
+
* @returns True if the relayer has confirmed the mint
|
|
12813
|
+
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
12814
|
+
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
12815
|
+
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
12816
|
+
* @internal
|
|
12817
|
+
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
12818
|
+
// First check if the structure is valid
|
|
12819
|
+
if (!hasValidAttestationStructure(obj)) {
|
|
12820
|
+
throw new KitError({
|
|
12821
|
+
...InputError.VALIDATION_FAILED,
|
|
12822
|
+
recoverability: 'FATAL',
|
|
12823
|
+
message: 'Invalid attestation response structure from IRIS API.'
|
|
12824
|
+
});
|
|
12577
12825
|
}
|
|
12578
|
-
//
|
|
12579
|
-
|
|
12580
|
-
|
|
12826
|
+
// Find the first message (typically there's only one)
|
|
12827
|
+
const message = obj.messages[0];
|
|
12828
|
+
if (!message) {
|
|
12829
|
+
throw new KitError({
|
|
12830
|
+
...InputError.VALIDATION_FAILED,
|
|
12831
|
+
recoverability: 'FATAL',
|
|
12832
|
+
message: 'No attestation messages found in IRIS API response.'
|
|
12833
|
+
});
|
|
12581
12834
|
}
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12835
|
+
// Check for FAILED state - this is a permanent failure
|
|
12836
|
+
if (message.forwardState === 'FAILED') {
|
|
12837
|
+
throw new KitError({
|
|
12838
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
12839
|
+
recoverability: 'RESUMABLE',
|
|
12840
|
+
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.',
|
|
12841
|
+
cause: {
|
|
12842
|
+
trace: {
|
|
12843
|
+
eventNonce: message.eventNonce,
|
|
12844
|
+
attestation: message.attestation,
|
|
12845
|
+
message: message.message
|
|
12846
|
+
}
|
|
12847
|
+
}
|
|
12848
|
+
});
|
|
12849
|
+
}
|
|
12850
|
+
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
12851
|
+
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
12852
|
+
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
12853
|
+
return true;
|
|
12854
|
+
}
|
|
12855
|
+
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
12856
|
+
throw new KitError({
|
|
12857
|
+
...NetworkError.RELAYER_PENDING,
|
|
12858
|
+
recoverability: 'RETRYABLE',
|
|
12859
|
+
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
12860
|
+
});
|
|
12861
|
+
};
|
|
12585
12862
|
/**
|
|
12586
|
-
*
|
|
12587
|
-
*
|
|
12588
|
-
*
|
|
12589
|
-
*
|
|
12590
|
-
*
|
|
12591
|
-
*
|
|
12592
|
-
*
|
|
12863
|
+
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
12864
|
+
*
|
|
12865
|
+
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
12866
|
+
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
12867
|
+
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
12868
|
+
*
|
|
12869
|
+
* @remarks
|
|
12870
|
+
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
12871
|
+
* - Throws immediately if `forwardState` is 'FAILED'
|
|
12872
|
+
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
12873
|
+
* - Returns the attestation message with `forwardTxHash` populated
|
|
12874
|
+
*
|
|
12875
|
+
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
12876
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
12877
|
+
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
12878
|
+
* @param config - Optional configuration overrides for polling behavior
|
|
12879
|
+
* @returns The attestation message with confirmed forwardTxHash
|
|
12880
|
+
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
12881
|
+
* @throws {KitError} If timeout is reached while still pending
|
|
12882
|
+
*
|
|
12883
|
+
* @example
|
|
12884
|
+
* ```typescript
|
|
12885
|
+
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
12886
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
12887
|
+
* ```
|
|
12888
|
+
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
12889
|
+
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
12890
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
12891
|
+
let response;
|
|
12892
|
+
try {
|
|
12893
|
+
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
12894
|
+
} catch (error) {
|
|
12895
|
+
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
12896
|
+
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
12897
|
+
throw new KitError({
|
|
12898
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
12899
|
+
recoverability: error.recoverability,
|
|
12900
|
+
message: error.message,
|
|
12901
|
+
cause: {
|
|
12902
|
+
...error.cause,
|
|
12903
|
+
trace: {
|
|
12904
|
+
...error.cause?.trace,
|
|
12905
|
+
burnTxHash: transactionHash
|
|
12906
|
+
}
|
|
12907
|
+
}
|
|
12908
|
+
});
|
|
12909
|
+
}
|
|
12910
|
+
throw error;
|
|
12911
|
+
}
|
|
12912
|
+
// Return the first message (which should have forwardTxHash)
|
|
12913
|
+
// Note: This check is needed for TypeScript type safety even though
|
|
12914
|
+
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
12915
|
+
// narrows the type at the call site, but TypeScript can't infer that
|
|
12916
|
+
// the array still has elements after pollApiGet returns.
|
|
12917
|
+
const message = response.messages[0];
|
|
12918
|
+
if (!message) {
|
|
12919
|
+
throw new KitError({
|
|
12920
|
+
...InputError.VALIDATION_FAILED,
|
|
12921
|
+
recoverability: 'FATAL',
|
|
12922
|
+
message: 'No attestation messages found in response after polling.'
|
|
12923
|
+
});
|
|
12924
|
+
}
|
|
12925
|
+
return message;
|
|
12926
|
+
};
|
|
12927
|
+
|
|
12928
|
+
const assertCCTPv2WalletContextSymbol = Symbol('assertCCTPv2WalletContext');
|
|
12929
|
+
/**
|
|
12930
|
+
* Asserts that the provided parameters match the CCTPv2 wallet context interface.
|
|
12931
|
+
* The validation includes:
|
|
12932
|
+
* - Basic wallet context validation (adapter, address, chain)
|
|
12933
|
+
* - CCTPv2-specific chain validation (must be an EVM chain)
|
|
12934
|
+
*
|
|
12935
|
+
* @param params - The parameters to validate
|
|
12936
|
+
* @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
|
|
12937
|
+
*
|
|
12938
|
+
* @example
|
|
12939
|
+
* ```typescript
|
|
12940
|
+
* import { assertCCTPv2WalletContext } from '@circle-fin/provider-cctp-v2'
|
|
12941
|
+
* import { Ethereum } from '@core/chains'
|
|
12942
|
+
*
|
|
12943
|
+
* // Prepare wallet context
|
|
12944
|
+
* const context = {
|
|
12945
|
+
* adapter: {
|
|
12946
|
+
* prepare: async () => ({ data: 'prepared transaction' }),
|
|
12947
|
+
* waitForTransaction: async () => ({ status: 'confirmed' })
|
|
12948
|
+
* },
|
|
12949
|
+
* address: '0x1234567890123456789012345678901234567890',
|
|
12950
|
+
* chain: {
|
|
12951
|
+
* ...Ethereum,
|
|
12952
|
+
* usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
12953
|
+
* cctp: {
|
|
12954
|
+
* domain: 1,
|
|
12955
|
+
* contracts: {
|
|
12956
|
+
* v2: {
|
|
12957
|
+
* tokenMessenger: '0xTokenMessenger',
|
|
12958
|
+
* messageTransmitter: '0xMessageTransmitter'
|
|
12959
|
+
* }
|
|
12960
|
+
* }
|
|
12961
|
+
* }
|
|
12962
|
+
* }
|
|
12963
|
+
* }
|
|
12964
|
+
*
|
|
12965
|
+
* // This will throw if validation fails
|
|
12966
|
+
* assertCCTPv2WalletContext(context)
|
|
12967
|
+
*
|
|
12968
|
+
* // If we get here, context is guaranteed to be valid
|
|
12969
|
+
* console.log('CCTPv2 wallet context is valid')
|
|
12970
|
+
* ```
|
|
12971
|
+
*/ function assertCCTPv2WalletContext(params) {
|
|
12972
|
+
// First validate basic wallet context
|
|
12973
|
+
validateWithStateTracking(params, walletContextSchema, 'CCTPv2 wallet context', assertCCTPv2WalletContextSymbol);
|
|
12974
|
+
// After validation, we know params is WalletContext
|
|
12975
|
+
const context = params;
|
|
12976
|
+
// Validate USDC support
|
|
12977
|
+
if (context.chain.usdcAddress === null) {
|
|
12978
|
+
throw createInvalidChainError(context.chain.name, 'Does not have USDC configured');
|
|
12979
|
+
}
|
|
12980
|
+
// Validate CCTPv2 support
|
|
12981
|
+
if (!isCCTPV2Supported(context.chain)) {
|
|
12982
|
+
throw createInvalidChainError(context.chain.name, 'Does not support CCTPv2');
|
|
12983
|
+
}
|
|
12984
|
+
}
|
|
12985
|
+
|
|
12986
|
+
const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
12987
|
+
/**
|
|
12988
|
+
* Asserts that the provided parameters match the CCTPv2 bridge parameters interface.
|
|
12989
|
+
* The validation includes:
|
|
12990
|
+
* - Basic parameter structure and types
|
|
12991
|
+
* - Amount validation (non-empty numeric string \> 0)
|
|
12992
|
+
* - Wallet address format validation (must be valid Ethereum address)
|
|
12993
|
+
* - Chain definition validation (must be a valid chain with required properties)
|
|
12994
|
+
* - Adapter validation (must implement required methods)
|
|
12593
12995
|
* - Optional config validation (transfer speed and max fee)
|
|
12594
12996
|
* - Network compatibility (source and destination chains must both be testnet or both mainnet)
|
|
12595
12997
|
* - CCTPv2-specific wallet context validations
|
|
@@ -12790,6 +13192,109 @@ const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
|
12790
13192
|
}
|
|
12791
13193
|
}
|
|
12792
13194
|
|
|
13195
|
+
/**
|
|
13196
|
+
* Assert that `params` is a well-formed {@link BurnWithFeesParams} object.
|
|
13197
|
+
*
|
|
13198
|
+
* Validates the full public-boundary input before any field destructuring,
|
|
13199
|
+
* `BigInt()` coercion, or adapter preparation runs, so malformed JS-caller
|
|
13200
|
+
* inputs always produce typed `KitError` validation failures.
|
|
13201
|
+
*
|
|
13202
|
+
* Checks performed (in order):
|
|
13203
|
+
* - `params` must be a non-null plain object
|
|
13204
|
+
* - `source` — valid CCTP v2 wallet context (via `assertCCTPv2WalletContext`)
|
|
13205
|
+
* - `destinationChain` — present and supports CCTP v2
|
|
13206
|
+
* - source and destination chains must both be testnet or both mainnet
|
|
13207
|
+
* - source and destination chains must differ
|
|
13208
|
+
* - `executor` — non-empty string
|
|
13209
|
+
* - `amount` — bigint or non-empty string coercible to bigint
|
|
13210
|
+
* - `feeTotalAmount` — bigint or non-empty string coercible to bigint
|
|
13211
|
+
* - `feeToken` — valid EVM address (`0x` + 40 hex chars)
|
|
13212
|
+
* - `claim.signedQuote` — valid `0x`-prefixed hex string
|
|
13213
|
+
* - `claim.refundAddress` — valid EVM address
|
|
13214
|
+
* - `hookData` — valid `0x`-prefixed hex string when present
|
|
13215
|
+
*
|
|
13216
|
+
* @param params - The value to validate.
|
|
13217
|
+
* @throws {KitError} If any field is missing or invalid.
|
|
13218
|
+
*
|
|
13219
|
+
* @example
|
|
13220
|
+
* ```typescript
|
|
13221
|
+
* assertBurnWithFeesParams(params)
|
|
13222
|
+
* // params is now typed as BurnWithFeesParams and safe to use
|
|
13223
|
+
* const { source, destinationChain, amount } = params
|
|
13224
|
+
* ```
|
|
13225
|
+
*/ function assertBurnWithFeesParams(params) {
|
|
13226
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
13227
|
+
throw createValidationFailedError$1('params', params, 'Must be a non-null plain object');
|
|
13228
|
+
}
|
|
13229
|
+
const p = params;
|
|
13230
|
+
// Source wallet context
|
|
13231
|
+
assertCCTPv2WalletContext(p['source']);
|
|
13232
|
+
const source = p['source'];
|
|
13233
|
+
// destinationChain
|
|
13234
|
+
const destinationChain = p['destinationChain'];
|
|
13235
|
+
if (destinationChain === null || destinationChain === undefined || typeof destinationChain !== 'object') {
|
|
13236
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'Must be a chain definition object');
|
|
13237
|
+
}
|
|
13238
|
+
if (!isCCTPV2Supported(destinationChain)) {
|
|
13239
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'destinationChain must support CCTP v2');
|
|
13240
|
+
}
|
|
13241
|
+
const dest = destinationChain;
|
|
13242
|
+
// Testnet / mainnet mismatch
|
|
13243
|
+
if (source.chain.isTestnet !== dest.isTestnet) {
|
|
13244
|
+
throw createNetworkMismatchError(source.chain, dest);
|
|
13245
|
+
}
|
|
13246
|
+
// Same-chain guard
|
|
13247
|
+
if (source.chain.name === dest.name) {
|
|
13248
|
+
throw createUnsupportedRouteError(source.chain.name, dest.name);
|
|
13249
|
+
}
|
|
13250
|
+
// executor
|
|
13251
|
+
const executor = p['executor'];
|
|
13252
|
+
if (typeof executor !== 'string' || executor === '') {
|
|
13253
|
+
throw createValidationFailedError$1('executor', executor, 'A GenericExecutor address is required (used for both mintRecipient and destinationCaller)');
|
|
13254
|
+
}
|
|
13255
|
+
// amount
|
|
13256
|
+
const rawAmount = p['amount'];
|
|
13257
|
+
if (typeof rawAmount !== 'bigint' && typeof rawAmount !== 'string' || rawAmount === '') {
|
|
13258
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a bigint or a numeric string');
|
|
13259
|
+
}
|
|
13260
|
+
try {
|
|
13261
|
+
BigInt(rawAmount);
|
|
13262
|
+
} catch {
|
|
13263
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a valid integer value coercible to bigint');
|
|
13264
|
+
}
|
|
13265
|
+
// feeTotalAmount
|
|
13266
|
+
const rawFee = p['feeTotalAmount'];
|
|
13267
|
+
if (typeof rawFee !== 'bigint' && typeof rawFee !== 'string' || rawFee === '') {
|
|
13268
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a bigint or a numeric string');
|
|
13269
|
+
}
|
|
13270
|
+
try {
|
|
13271
|
+
BigInt(rawFee);
|
|
13272
|
+
} catch {
|
|
13273
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a valid integer value coercible to bigint');
|
|
13274
|
+
}
|
|
13275
|
+
// feeToken
|
|
13276
|
+
if (!evmAddressSchema.safeParse(p['feeToken']).success) {
|
|
13277
|
+
throw createValidationFailedError$1('feeToken', p['feeToken'], 'Must be a valid EVM address (use the zero address for a native fee)');
|
|
13278
|
+
}
|
|
13279
|
+
// claim
|
|
13280
|
+
const rawClaim = p['claim'];
|
|
13281
|
+
if (rawClaim === null || typeof rawClaim !== 'object' || Array.isArray(rawClaim)) {
|
|
13282
|
+
throw createValidationFailedError$1('claim', rawClaim, 'Must be an object with signedQuote and refundAddress');
|
|
13283
|
+
}
|
|
13284
|
+
const claim = rawClaim;
|
|
13285
|
+
if (!hexStringSchema.safeParse(claim['signedQuote']).success) {
|
|
13286
|
+
throw createValidationFailedError$1('claim.signedQuote', claim['signedQuote'], 'Must be a valid hex string starting with 0x');
|
|
13287
|
+
}
|
|
13288
|
+
if (!evmAddressSchema.safeParse(claim['refundAddress']).success) {
|
|
13289
|
+
throw createValidationFailedError$1('claim.refundAddress', claim['refundAddress'], 'Must be a valid EVM address');
|
|
13290
|
+
}
|
|
13291
|
+
// hookData (optional)
|
|
13292
|
+
const hookData = p['hookData'];
|
|
13293
|
+
if (hookData !== undefined && hookData !== '' && !hexStringSchema.safeParse(hookData).success) {
|
|
13294
|
+
throw createValidationFailedError$1('hookData', hookData, 'Must be a valid hex string starting with 0x');
|
|
13295
|
+
}
|
|
13296
|
+
}
|
|
13297
|
+
|
|
12793
13298
|
/**
|
|
12794
13299
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
12795
13300
|
*
|
|
@@ -13397,6 +13902,8 @@ function hasPendingState(analysis, result) {
|
|
|
13397
13902
|
* - `adapter`: The adapter that will execute the transaction
|
|
13398
13903
|
* - `confirmations`: The number of confirmations to wait for (defaults to 1)
|
|
13399
13904
|
* - `timeout`: The timeout for the request in milliseconds
|
|
13905
|
+
* - `gasLimit`: Optional explicit gas limit (number) forwarded to EVM execute,
|
|
13906
|
+
* bypassing `eth_estimateGas`; ignored for non-EVM requests
|
|
13400
13907
|
* @returns The bridge step with the transaction details and explorer URL
|
|
13401
13908
|
* @throws If the transaction execution fails
|
|
13402
13909
|
*
|
|
@@ -13411,7 +13918,7 @@ function hasPendingState(analysis, result) {
|
|
|
13411
13918
|
* })
|
|
13412
13919
|
* console.log('Transaction hash:', step.txHash)
|
|
13413
13920
|
* ```
|
|
13414
|
-
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout }) {
|
|
13921
|
+
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout, gasLimit }) {
|
|
13415
13922
|
const step = {
|
|
13416
13923
|
name,
|
|
13417
13924
|
state: 'pending'
|
|
@@ -13424,7 +13931,9 @@ function hasPendingState(analysis, result) {
|
|
|
13424
13931
|
step.state = 'noop';
|
|
13425
13932
|
return step;
|
|
13426
13933
|
}
|
|
13427
|
-
const txHash = await request.execute(
|
|
13934
|
+
const txHash = request.type === 'evm' && gasLimit !== undefined ? await request.execute({
|
|
13935
|
+
gasLimit
|
|
13936
|
+
}) : await request.execute();
|
|
13428
13937
|
step.txHash = txHash;
|
|
13429
13938
|
const retryOptions = {
|
|
13430
13939
|
isRetryable: (err)=>isRetryableError$1(parseBlockchainError(err, {
|
|
@@ -13496,7 +14005,8 @@ function hasPendingState(analysis, result) {
|
|
|
13496
14005
|
name: 'approve',
|
|
13497
14006
|
adapter: params.source.adapter,
|
|
13498
14007
|
chain: params.source.chain,
|
|
13499
|
-
request: await provider.approve(params.source, approvalAmount)
|
|
14008
|
+
request: await provider.approve(params.source, approvalAmount),
|
|
14009
|
+
gasLimit: Number(APPROVE_GAS_LIMIT_EVM)
|
|
13500
14010
|
});
|
|
13501
14011
|
}
|
|
13502
14012
|
|
|
@@ -13523,7 +14033,8 @@ function hasPendingState(analysis, result) {
|
|
|
13523
14033
|
name: 'burn',
|
|
13524
14034
|
adapter: params.source.adapter,
|
|
13525
14035
|
chain: params.source.chain,
|
|
13526
|
-
request: await provider.burn(params)
|
|
14036
|
+
request: await provider.burn(params),
|
|
14037
|
+
gasLimit: Number(DEPOSIT_FOR_BURN_GAS_LIMIT_EVM)
|
|
13527
14038
|
});
|
|
13528
14039
|
}
|
|
13529
14040
|
|
|
@@ -13609,11 +14120,18 @@ function hasPendingState(analysis, result) {
|
|
|
13609
14120
|
*/ async function bridgeMint({ params, provider }, attestation) {
|
|
13610
14121
|
// Validate attestation message matches transfer params
|
|
13611
14122
|
await assertCCTPv2AttestationParams(attestation, params);
|
|
14123
|
+
const mintRequest = await provider.mint(params.source, params.destination, attestation);
|
|
13612
14124
|
const step = await executePreparedChainRequest({
|
|
13613
14125
|
name: 'mint',
|
|
13614
14126
|
adapter: params.destination.adapter,
|
|
13615
14127
|
chain: params.destination.chain,
|
|
13616
|
-
request:
|
|
14128
|
+
request: mintRequest,
|
|
14129
|
+
// Some chains (e.g. Cronos) enforce an EIP-7623 calldata gas floor that
|
|
14130
|
+
// eth_estimateGas does not account for, returning a below-floor value
|
|
14131
|
+
// without reverting. Pinning to a value above the observed execution max
|
|
14132
|
+
// (310_839) bypasses re-estimation and guarantees we clear both the floor
|
|
14133
|
+
// and the actual execution cost.
|
|
14134
|
+
gasLimit: Number(RECEIVE_MESSAGE_GAS_LIMIT_EVM)
|
|
13617
14135
|
});
|
|
13618
14136
|
// Add forwarded: false for non-relayer mints
|
|
13619
14137
|
return {
|
|
@@ -13651,136 +14169,6 @@ const mockAttestationMessage = {
|
|
|
13651
14169
|
delayReason: null
|
|
13652
14170
|
};
|
|
13653
14171
|
|
|
13654
|
-
/**
|
|
13655
|
-
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
13656
|
-
*
|
|
13657
|
-
* This function validates that:
|
|
13658
|
-
* 1. The response has valid AttestationResponse structure
|
|
13659
|
-
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
13660
|
-
*
|
|
13661
|
-
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
13662
|
-
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
13663
|
-
*
|
|
13664
|
-
* @param obj - The value to check, typically a parsed JSON response
|
|
13665
|
-
* @returns True if the relayer has confirmed the mint
|
|
13666
|
-
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
13667
|
-
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
13668
|
-
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
13669
|
-
* @internal
|
|
13670
|
-
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
13671
|
-
// First check if the structure is valid
|
|
13672
|
-
if (!hasValidAttestationStructure(obj)) {
|
|
13673
|
-
throw new KitError({
|
|
13674
|
-
...InputError.VALIDATION_FAILED,
|
|
13675
|
-
recoverability: 'FATAL',
|
|
13676
|
-
message: 'Invalid attestation response structure from IRIS API.'
|
|
13677
|
-
});
|
|
13678
|
-
}
|
|
13679
|
-
// Find the first message (typically there's only one)
|
|
13680
|
-
const message = obj.messages[0];
|
|
13681
|
-
if (!message) {
|
|
13682
|
-
throw new KitError({
|
|
13683
|
-
...InputError.VALIDATION_FAILED,
|
|
13684
|
-
recoverability: 'FATAL',
|
|
13685
|
-
message: 'No attestation messages found in IRIS API response.'
|
|
13686
|
-
});
|
|
13687
|
-
}
|
|
13688
|
-
// Check for FAILED state - this is a permanent failure
|
|
13689
|
-
if (message.forwardState === 'FAILED') {
|
|
13690
|
-
throw new KitError({
|
|
13691
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
13692
|
-
recoverability: 'RESUMABLE',
|
|
13693
|
-
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.',
|
|
13694
|
-
cause: {
|
|
13695
|
-
trace: {
|
|
13696
|
-
eventNonce: message.eventNonce,
|
|
13697
|
-
attestation: message.attestation,
|
|
13698
|
-
message: message.message
|
|
13699
|
-
}
|
|
13700
|
-
}
|
|
13701
|
-
});
|
|
13702
|
-
}
|
|
13703
|
-
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
13704
|
-
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
13705
|
-
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
13706
|
-
return true;
|
|
13707
|
-
}
|
|
13708
|
-
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
13709
|
-
throw new KitError({
|
|
13710
|
-
...NetworkError.RELAYER_PENDING,
|
|
13711
|
-
recoverability: 'RETRYABLE',
|
|
13712
|
-
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
13713
|
-
});
|
|
13714
|
-
};
|
|
13715
|
-
/**
|
|
13716
|
-
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
13717
|
-
*
|
|
13718
|
-
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
13719
|
-
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
13720
|
-
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
13721
|
-
*
|
|
13722
|
-
* @remarks
|
|
13723
|
-
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
13724
|
-
* - Throws immediately if `forwardState` is 'FAILED'
|
|
13725
|
-
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
13726
|
-
* - Returns the attestation message with `forwardTxHash` populated
|
|
13727
|
-
*
|
|
13728
|
-
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
13729
|
-
* @param transactionHash - The transaction hash of the burn operation
|
|
13730
|
-
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
13731
|
-
* @param config - Optional configuration overrides for polling behavior
|
|
13732
|
-
* @returns The attestation message with confirmed forwardTxHash
|
|
13733
|
-
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
13734
|
-
* @throws {KitError} If timeout is reached while still pending
|
|
13735
|
-
*
|
|
13736
|
-
* @example
|
|
13737
|
-
* ```typescript
|
|
13738
|
-
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
13739
|
-
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
13740
|
-
* ```
|
|
13741
|
-
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
13742
|
-
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
13743
|
-
const effectiveConfig = {
|
|
13744
|
-
...DEFAULT_CONFIG,
|
|
13745
|
-
...config
|
|
13746
|
-
};
|
|
13747
|
-
let response;
|
|
13748
|
-
try {
|
|
13749
|
-
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
13750
|
-
} catch (error) {
|
|
13751
|
-
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
13752
|
-
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
13753
|
-
throw new KitError({
|
|
13754
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
13755
|
-
recoverability: error.recoverability,
|
|
13756
|
-
message: error.message,
|
|
13757
|
-
cause: {
|
|
13758
|
-
...error.cause,
|
|
13759
|
-
trace: {
|
|
13760
|
-
...error.cause?.trace,
|
|
13761
|
-
burnTxHash: transactionHash
|
|
13762
|
-
}
|
|
13763
|
-
}
|
|
13764
|
-
});
|
|
13765
|
-
}
|
|
13766
|
-
throw error;
|
|
13767
|
-
}
|
|
13768
|
-
// Return the first message (which should have forwardTxHash)
|
|
13769
|
-
// Note: This check is needed for TypeScript type safety even though
|
|
13770
|
-
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
13771
|
-
// narrows the type at the call site, but TypeScript can't infer that
|
|
13772
|
-
// the array still has elements after pollApiGet returns.
|
|
13773
|
-
const message = response.messages[0];
|
|
13774
|
-
if (!message) {
|
|
13775
|
-
throw new KitError({
|
|
13776
|
-
...InputError.VALIDATION_FAILED,
|
|
13777
|
-
recoverability: 'FATAL',
|
|
13778
|
-
message: 'No attestation messages found in response after polling.'
|
|
13779
|
-
});
|
|
13780
|
-
}
|
|
13781
|
-
return message;
|
|
13782
|
-
};
|
|
13783
|
-
|
|
13784
14172
|
/**
|
|
13785
14173
|
* Executes the mint step for forwarding mode where Circle's relayer handles the mint.
|
|
13786
14174
|
*
|
|
@@ -13794,6 +14182,7 @@ const mockAttestationMessage = {
|
|
|
13794
14182
|
* immediately after the API confirms the mint.
|
|
13795
14183
|
*
|
|
13796
14184
|
* @param params - The bridge parameters containing source, destination, amount and config
|
|
14185
|
+
* @param provider - The CCTP v2 bridging provider
|
|
13797
14186
|
* @param context - The step context containing burnTxHash from the burn step
|
|
13798
14187
|
* @returns Promise resolving to the bridge step with transaction details
|
|
13799
14188
|
* @throws {KitError} If burnTxHash is not available in context
|
|
@@ -13802,10 +14191,13 @@ const mockAttestationMessage = {
|
|
|
13802
14191
|
*
|
|
13803
14192
|
* @example
|
|
13804
14193
|
* ```typescript
|
|
13805
|
-
* const step = await bridgeRelayerMint(
|
|
14194
|
+
* const step = await bridgeRelayerMint(
|
|
14195
|
+
* { params, provider },
|
|
14196
|
+
* { burnTxHash: '0x...' }
|
|
14197
|
+
* )
|
|
13806
14198
|
* console.log('Relayer mint tx:', step.txHash)
|
|
13807
14199
|
* ```
|
|
13808
|
-
*/ async function bridgeRelayerMint(params, context) {
|
|
14200
|
+
*/ async function bridgeRelayerMint({ params, provider }, context) {
|
|
13809
14201
|
const step = {
|
|
13810
14202
|
name: 'mint',
|
|
13811
14203
|
state: 'pending',
|
|
@@ -13821,7 +14213,7 @@ const mockAttestationMessage = {
|
|
|
13821
14213
|
}
|
|
13822
14214
|
try {
|
|
13823
14215
|
// Poll attestation API until relayer confirms the mint
|
|
13824
|
-
const attestation = await fetchRelayerMint(params.source
|
|
14216
|
+
const attestation = await provider.fetchRelayerMint(params.source, context.burnTxHash);
|
|
13825
14217
|
// Extract the relayer's mint transaction hash
|
|
13826
14218
|
const forwardTxHash = attestation.forwardTxHash;
|
|
13827
14219
|
if (!forwardTxHash) {
|
|
@@ -13915,7 +14307,7 @@ const mockAttestationMessage = {
|
|
|
13915
14307
|
name: 'mint',
|
|
13916
14308
|
// bridgeRelayerMint validates context.burnTxHash internally with a KitError
|
|
13917
14309
|
// bridgeMint requires attestationData which is validated here
|
|
13918
|
-
executor: useForwarder ? async (params,
|
|
14310
|
+
executor: useForwarder ? async (params, provider, context)=>{
|
|
13919
14311
|
if (!context) {
|
|
13920
14312
|
throw new KitError({
|
|
13921
14313
|
...InputError.VALIDATION_FAILED,
|
|
@@ -13923,7 +14315,10 @@ const mockAttestationMessage = {
|
|
|
13923
14315
|
message: 'Step context is required for relayer mint'
|
|
13924
14316
|
});
|
|
13925
14317
|
}
|
|
13926
|
-
return bridgeRelayerMint(
|
|
14318
|
+
return bridgeRelayerMint({
|
|
14319
|
+
params,
|
|
14320
|
+
provider
|
|
14321
|
+
}, context);
|
|
13927
14322
|
} : async (params, provider, context)=>{
|
|
13928
14323
|
if (!context?.attestationData) {
|
|
13929
14324
|
throw new KitError({
|
|
@@ -14108,10 +14503,15 @@ const mockAttestationMessage = {
|
|
|
14108
14503
|
const burnCallData = burnRequest.getCallData();
|
|
14109
14504
|
// batchExecute may throw before submission (wallet declined) but never
|
|
14110
14505
|
// after — post-submission errors are returned as empty receipts.
|
|
14506
|
+
// The sender is threaded for adapters whose execution is routed through a
|
|
14507
|
+
// signing strategy (which has no wallet account to read it from); the
|
|
14508
|
+
// wallet-client path ignores it.
|
|
14111
14509
|
const batchResult = await adapter.batchExecute([
|
|
14112
14510
|
approveCallData,
|
|
14113
14511
|
burnCallData
|
|
14114
|
-
], chain
|
|
14512
|
+
], chain, {
|
|
14513
|
+
fromAddress: params.source.address
|
|
14514
|
+
});
|
|
14115
14515
|
const approveReceipt = batchResult.receipts[0];
|
|
14116
14516
|
const burnReceipt = batchResult.receipts[1];
|
|
14117
14517
|
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
|
|
@@ -14254,7 +14654,7 @@ const mockAttestationMessage = {
|
|
|
14254
14654
|
return step;
|
|
14255
14655
|
}
|
|
14256
14656
|
|
|
14257
|
-
var version$2 = "1.
|
|
14657
|
+
var version$2 = "1.10.0";
|
|
14258
14658
|
var pkg$2 = {
|
|
14259
14659
|
version: version$2};
|
|
14260
14660
|
|
|
@@ -14960,6 +15360,39 @@ var pkg$2 = {
|
|
|
14960
15360
|
}
|
|
14961
15361
|
}
|
|
14962
15362
|
|
|
15363
|
+
function isPlainObject(value) {
|
|
15364
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
15365
|
+
return false;
|
|
15366
|
+
}
|
|
15367
|
+
const prototype = Object.getPrototypeOf(value);
|
|
15368
|
+
return prototype === Object.prototype || prototype === null;
|
|
15369
|
+
}
|
|
15370
|
+
function assertHeadersConfig(headers, field) {
|
|
15371
|
+
if (headers === undefined) {
|
|
15372
|
+
return;
|
|
15373
|
+
}
|
|
15374
|
+
if (!isPlainObject(headers)) {
|
|
15375
|
+
throw createValidationFailedError$1(field, headers, `${field} must be a plain object with string header values when provided`);
|
|
15376
|
+
}
|
|
15377
|
+
for (const [name, value] of Object.entries(headers)){
|
|
15378
|
+
if (typeof value !== 'string') {
|
|
15379
|
+
throw createValidationFailedError$1(`${field}.${name}`, value, 'header values must be strings');
|
|
15380
|
+
}
|
|
15381
|
+
}
|
|
15382
|
+
}
|
|
15383
|
+
function assertCCTPV2Config(config) {
|
|
15384
|
+
if (!isPlainObject(config)) {
|
|
15385
|
+
throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
|
|
15386
|
+
}
|
|
15387
|
+
assertHeadersConfig(config['headers'], 'config.headers');
|
|
15388
|
+
const attestation = config['attestation'];
|
|
15389
|
+
if (attestation !== undefined) {
|
|
15390
|
+
if (!isPlainObject(attestation)) {
|
|
15391
|
+
throw createValidationFailedError$1('config.attestation', attestation, 'config.attestation must be a plain object when provided');
|
|
15392
|
+
}
|
|
15393
|
+
assertHeadersConfig(attestation['headers'], 'config.attestation.headers');
|
|
15394
|
+
}
|
|
15395
|
+
}
|
|
14963
15396
|
/**
|
|
14964
15397
|
* All chains that are supported by the CCTP v2 provider.
|
|
14965
15398
|
*
|
|
@@ -15028,9 +15461,38 @@ var pkg$2 = {
|
|
|
15028
15461
|
* @param config - Optional configuration overrides for the provider
|
|
15029
15462
|
*/ constructor(config = {}){
|
|
15030
15463
|
super();
|
|
15464
|
+
assertCCTPV2Config(config);
|
|
15031
15465
|
this.config = config;
|
|
15032
15466
|
}
|
|
15033
15467
|
/**
|
|
15468
|
+
* Resolves the effective polling configuration for an attestation request.
|
|
15469
|
+
*
|
|
15470
|
+
* Precedence (lowest to highest): provider `config.attestation`, then the
|
|
15471
|
+
* per-call `config`. Headers merge independently across
|
|
15472
|
+
* `config.attestation.headers`, the provider-level `config.headers`, and any
|
|
15473
|
+
* per-call `config.headers`, so a more specific header augments rather than
|
|
15474
|
+
* replaces the broader ones. The `headers` key is omitted entirely when no
|
|
15475
|
+
* headers are configured, leaving the attestation fetchers' defaults intact.
|
|
15476
|
+
*
|
|
15477
|
+
* @param config - Optional per-call polling configuration overrides
|
|
15478
|
+
* @returns The merged polling configuration passed to the attestation fetchers
|
|
15479
|
+
*/ resolveAttestationConfig(config) {
|
|
15480
|
+
const headers = {
|
|
15481
|
+
...this.config?.attestation?.headers,
|
|
15482
|
+
...this.config?.headers,
|
|
15483
|
+
...config?.headers
|
|
15484
|
+
};
|
|
15485
|
+
// Polling fields follow normal precedence; headers are merged separately
|
|
15486
|
+
// below so narrower config layers augment rather than replace broader ones.
|
|
15487
|
+
return {
|
|
15488
|
+
...this.config?.attestation,
|
|
15489
|
+
...config,
|
|
15490
|
+
...Object.keys(headers).length > 0 ? {
|
|
15491
|
+
headers
|
|
15492
|
+
} : {}
|
|
15493
|
+
};
|
|
15494
|
+
}
|
|
15495
|
+
/**
|
|
15034
15496
|
* Execute a cross-chain USDC bridge operation using the CCTP v2 protocol.
|
|
15035
15497
|
*
|
|
15036
15498
|
* This method orchestrates the complete CCTP v2 bridge flow including validation,
|
|
@@ -15347,7 +15809,7 @@ var pkg$2 = {
|
|
|
15347
15809
|
throw new Error(`Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
15348
15810
|
}
|
|
15349
15811
|
// Resolve spender address with proper error handling
|
|
15350
|
-
const spenderAddress = resolveCCTPV2ContractAddress(chain);
|
|
15812
|
+
const spenderAddress = resolveCCTPV2ContractAddress(chain, 'tokenMessenger');
|
|
15351
15813
|
// Prepare action parameters
|
|
15352
15814
|
const actionParams = {
|
|
15353
15815
|
amount: BigInt(amount),
|
|
@@ -15456,11 +15918,7 @@ var pkg$2 = {
|
|
|
15456
15918
|
*/ async fetchAttestation(source, transactionHash, config) {
|
|
15457
15919
|
assertCCTPv2WalletContext(source);
|
|
15458
15920
|
try {
|
|
15459
|
-
|
|
15460
|
-
const effectiveConfig = {
|
|
15461
|
-
...this.config?.attestation,
|
|
15462
|
-
...config
|
|
15463
|
-
};
|
|
15921
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15464
15922
|
const response = await fetchAttestation(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15465
15923
|
const message = response.messages[0];
|
|
15466
15924
|
if (!message) {
|
|
@@ -15477,6 +15935,49 @@ var pkg$2 = {
|
|
|
15477
15935
|
}
|
|
15478
15936
|
}
|
|
15479
15937
|
/**
|
|
15938
|
+
* Polls attestation data until Circle's relayer mint transaction is confirmed.
|
|
15939
|
+
*
|
|
15940
|
+
* This method is used by forwarded transfers. It polls the same Iris
|
|
15941
|
+
* attestation endpoint as {@link CCTPV2BridgingProvider.fetchAttestation},
|
|
15942
|
+
* but waits for a completed relayer forward state and returns the attestation
|
|
15943
|
+
* message containing `forwardTxHash`.
|
|
15944
|
+
*
|
|
15945
|
+
* @typeParam TFromAdapterCapabilities - The type representing the capabilities of the source adapter
|
|
15946
|
+
* @param source - The source wallet context containing the chain definition and wallet address
|
|
15947
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
15948
|
+
* @param config - Optional polling configuration overrides for timeout, retries, delay, and headers
|
|
15949
|
+
* @returns A promise that resolves to the attestation message with `forwardTxHash`
|
|
15950
|
+
* @throws KitError If the relayer forward fails, the response is invalid, or polling times out
|
|
15951
|
+
*
|
|
15952
|
+
* @example
|
|
15953
|
+
* ```typescript
|
|
15954
|
+
* import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2'
|
|
15955
|
+
* import { Chains } from '@core/chains'
|
|
15956
|
+
*
|
|
15957
|
+
* const provider = new CCTPV2BridgingProvider({
|
|
15958
|
+
* headers: { 'X-Partner-UUID': '00000000-0000-0000-0000-000000000000' },
|
|
15959
|
+
* })
|
|
15960
|
+
*
|
|
15961
|
+
* const attestation = await provider.fetchRelayerMint(
|
|
15962
|
+
* {
|
|
15963
|
+
* adapter,
|
|
15964
|
+
* chain: Chains.EthereumSepolia,
|
|
15965
|
+
* address: '0x1234...',
|
|
15966
|
+
* },
|
|
15967
|
+
* '0xabc123...',
|
|
15968
|
+
* )
|
|
15969
|
+
*
|
|
15970
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
15971
|
+
* ```
|
|
15972
|
+
*/ async fetchRelayerMint(source, transactionHash, config) {
|
|
15973
|
+
assertCCTPv2WalletContext(source);
|
|
15974
|
+
if (typeof transactionHash !== 'string' || transactionHash.trim() === '') {
|
|
15975
|
+
throw createValidationFailedError$1('transactionHash', transactionHash, 'transactionHash must be a non-empty string');
|
|
15976
|
+
}
|
|
15977
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15978
|
+
return await fetchRelayerMint(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15979
|
+
}
|
|
15980
|
+
/**
|
|
15480
15981
|
* Requests a fresh attestation for an expired attestation.
|
|
15481
15982
|
*
|
|
15482
15983
|
* This method is used when the original attestation has expired before the mint
|
|
@@ -15530,11 +16031,7 @@ var pkg$2 = {
|
|
|
15530
16031
|
throw new Error('Failed to re-attest: Invalid transaction hash');
|
|
15531
16032
|
}
|
|
15532
16033
|
try {
|
|
15533
|
-
|
|
15534
|
-
const effectiveConfig = {
|
|
15535
|
-
...this.config?.attestation,
|
|
15536
|
-
...config
|
|
15537
|
-
};
|
|
16034
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
15538
16035
|
// Step 1: Get existing attestation data to extract nonce
|
|
15539
16036
|
const existingAttestation = await fetchAttestationWithoutStatusCheck(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
15540
16037
|
const nonce = existingAttestation.messages[0]?.eventNonce;
|
|
@@ -15792,6 +16289,106 @@ var pkg$2 = {
|
|
|
15792
16289
|
return await source.adapter.prepareAction('cctp.v2.depositForBurn', actionParams, resolvedContext);
|
|
15793
16290
|
}
|
|
15794
16291
|
/**
|
|
16292
|
+
* Prepare a prepaid-FORWARD burn through the `TokenMessengerWithFees` wrapper.
|
|
16293
|
+
*
|
|
16294
|
+
* Builds the source-chain `depositForBurnWithHookAndFees` call for the
|
|
16295
|
+
* GenericExecutor FORWARD path: fees are collected up front on the source chain
|
|
16296
|
+
* against a signed quote, `mintRecipient` and `destinationCaller` are both set to
|
|
16297
|
+
* the GenericExecutor, and the GE `hookData` is passed through unchanged.
|
|
16298
|
+
*
|
|
16299
|
+
* This is the low-level on-chain primitive behind the UBK `fastCrossChainDeposit`
|
|
16300
|
+
* and Bridge Kit `bridge({ deposit })` flows. The `hookData` and signed-quote
|
|
16301
|
+
* `claim` are produced elsewhere and passed in here:
|
|
16302
|
+
* - `hookData`: `buildForwardingHookDataWithPayload(version,
|
|
16303
|
+
* buildDepositForGenericExecutorPayload(...).hookData)` from `@core/utils`.
|
|
16304
|
+
* - `claim.signedQuote` / `feeToken` / `feeTotalAmount`: from `fetchFeeQuote`
|
|
16305
|
+
* (`@circle-fin/provider-fee-v1`), whose FORWARD item must be bound to the
|
|
16306
|
+
* SAME `hookData` and executor `destinationCaller` used here.
|
|
16307
|
+
*
|
|
16308
|
+
* The returned approvals and burn are NOT executed — the caller executes the
|
|
16309
|
+
* approvals first (in order) and then the burn. The fee payment channel matches
|
|
16310
|
+
* the quote's `feeToken`:
|
|
16311
|
+
* - Native fee: exactly `feeTotalAmount` is attached as the burn's `msg.value`;
|
|
16312
|
+
* only the burn amount is approved.
|
|
16313
|
+
* - USDC fee (same token as the burn): a single combined `amount + feeTotalAmount`
|
|
16314
|
+
* approval covers both; the redundant second approval is skipped.
|
|
16315
|
+
*
|
|
16316
|
+
* @typeParam TFromAdapterCapabilities - The source adapter's capabilities.
|
|
16317
|
+
* @param params - The burn amount, executor, hookData, signed-quote claim, and fee.
|
|
16318
|
+
* @returns The prepared approvals, the prepared burn, and the resolved fee plan.
|
|
16319
|
+
* @throws {KitError} If the wallet context is invalid, `destinationChain` does not
|
|
16320
|
+
* support CCTP v2, the executor is missing, `amount` or `feeTotalAmount` is not
|
|
16321
|
+
* a bigint or a numeric string coercible to bigint, the hookData lacks a
|
|
16322
|
+
* `cctp-forward` frame (guaranteed `ForwardFeeWithoutHook`), or the operation
|
|
16323
|
+
* context cannot be resolved.
|
|
16324
|
+
*
|
|
16325
|
+
* @example
|
|
16326
|
+
* ```typescript
|
|
16327
|
+
* const { approvals, burn } = await provider.burnWithFees({
|
|
16328
|
+
* source,
|
|
16329
|
+
* destinationChain: Arc,
|
|
16330
|
+
* amount: 1_000_000n,
|
|
16331
|
+
* executor: genericExecutorAddress,
|
|
16332
|
+
* hookData: geForwardHookData,
|
|
16333
|
+
* claim: { signedQuote: '0x01...', refundAddress: userAddress },
|
|
16334
|
+
* feeToken: '0x0000000000000000000000000000000000000000', // native
|
|
16335
|
+
* feeTotalAmount: 3_500_000n,
|
|
16336
|
+
* })
|
|
16337
|
+
* for (const approval of approvals) await approval.execute()
|
|
16338
|
+
* const txHash = await burn.execute()
|
|
16339
|
+
* ```
|
|
16340
|
+
*/ async burnWithFees(params) {
|
|
16341
|
+
assertBurnWithFeesParams(params);
|
|
16342
|
+
const { source, destinationChain, executor, hookData, claim, feeToken } = params;
|
|
16343
|
+
const amount = BigInt(params.amount);
|
|
16344
|
+
const feeTotalAmount = BigInt(params.feeTotalAmount);
|
|
16345
|
+
// Coupling guard: the prepaid FORWARD path always requests a FORWARD fee item,
|
|
16346
|
+
// so the hookData must carry a cctp-forward frame; otherwise the wrapper
|
|
16347
|
+
// reverts ForwardFeeWithoutHook. Surface it as a typed input error up front.
|
|
16348
|
+
assertForwardHookData(hookData);
|
|
16349
|
+
const burnToken = source.chain.usdcAddress;
|
|
16350
|
+
const feePayment = resolveFeePayment({
|
|
16351
|
+
feeToken,
|
|
16352
|
+
burnToken,
|
|
16353
|
+
amount,
|
|
16354
|
+
feeTotalAmount
|
|
16355
|
+
});
|
|
16356
|
+
// Resolve operation context from the source wallet context.
|
|
16357
|
+
const operationContext = this.extractOperationContext(source);
|
|
16358
|
+
let resolvedContext;
|
|
16359
|
+
try {
|
|
16360
|
+
resolvedContext = await resolveOperationContext(source.adapter, operationContext);
|
|
16361
|
+
} catch (error) {
|
|
16362
|
+
throw createValidationFailedError$1('source.adapter', undefined, `Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
16363
|
+
}
|
|
16364
|
+
const context = resolvedContext;
|
|
16365
|
+
const wrapperAddress = resolveCCTPV2ContractAddress(source.chain, 'tokenMessengerWithFees');
|
|
16366
|
+
// Build the ERC-20 approvals to the wrapper (burn token, plus a distinct fee
|
|
16367
|
+
// token only when the fee is not paid in the burn token).
|
|
16368
|
+
const approvals = await Promise.all(feePayment.approvals.map(async (approval)=>source.adapter.prepareAction('token.approve', {
|
|
16369
|
+
tokenAddress: approval.token,
|
|
16370
|
+
delegate: wrapperAddress,
|
|
16371
|
+
amount: approval.amount
|
|
16372
|
+
}, context)));
|
|
16373
|
+
// Build the burn: mintRecipient AND destinationCaller are both the executor.
|
|
16374
|
+
const burn = await source.adapter.prepareAction('cctp.v2.depositForBurnWithFees', {
|
|
16375
|
+
fromChain: source.chain,
|
|
16376
|
+
toChain: destinationChain,
|
|
16377
|
+
amount,
|
|
16378
|
+
mintRecipient: executor,
|
|
16379
|
+
destinationCaller: executor,
|
|
16380
|
+
hookData,
|
|
16381
|
+
claim,
|
|
16382
|
+
feeToken,
|
|
16383
|
+
feeTotalAmount
|
|
16384
|
+
}, context);
|
|
16385
|
+
return {
|
|
16386
|
+
approvals,
|
|
16387
|
+
burn,
|
|
16388
|
+
feePayment
|
|
16389
|
+
};
|
|
16390
|
+
}
|
|
16391
|
+
/**
|
|
15795
16392
|
* Waits for a transaction to be mined and confirmed on the blockchain.
|
|
15796
16393
|
*
|
|
15797
16394
|
* This method should block until the transaction is confirmed on the blockchain.
|
|
@@ -15819,8 +16416,13 @@ var pkg$2 = {
|
|
|
15819
16416
|
/**
|
|
15820
16417
|
* The default providers that will be used in addition to the providers provided
|
|
15821
16418
|
* to the BridgeKit constructor.
|
|
15822
|
-
|
|
15823
|
-
|
|
16419
|
+
*
|
|
16420
|
+
* @param config - Optional configuration forwarded to the default providers
|
|
16421
|
+
* @returns The default bridging providers
|
|
16422
|
+
*/ const getDefaultProviders = (config = {})=>[
|
|
16423
|
+
new CCTPV2BridgingProvider(config.headers ? {
|
|
16424
|
+
headers: config.headers
|
|
16425
|
+
} : {})
|
|
15824
16426
|
];
|
|
15825
16427
|
|
|
15826
16428
|
/**
|
|
@@ -16063,7 +16665,9 @@ var pkg$2 = {
|
|
|
16063
16665
|
* ```
|
|
16064
16666
|
*/ constructor(config = {}){
|
|
16065
16667
|
// Handle provider configuration
|
|
16066
|
-
const defaultProviders = getDefaultProviders(
|
|
16668
|
+
const defaultProviders = getDefaultProviders(config.headers ? {
|
|
16669
|
+
headers: config.headers
|
|
16670
|
+
} : {});
|
|
16067
16671
|
this.providers = [
|
|
16068
16672
|
...defaultProviders,
|
|
16069
16673
|
...config.providers ?? []
|
|
@@ -16643,6 +17247,9 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16643
17247
|
const kit = new BridgeKit({
|
|
16644
17248
|
...context.disableErrorReporting != null && {
|
|
16645
17249
|
disableErrorReporting: context.disableErrorReporting
|
|
17250
|
+
},
|
|
17251
|
+
...context.headers != null && {
|
|
17252
|
+
headers: context.headers
|
|
16646
17253
|
}
|
|
16647
17254
|
});
|
|
16648
17255
|
if (hasBoth) {
|
|
@@ -16661,7 +17268,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16661
17268
|
};
|
|
16662
17269
|
|
|
16663
17270
|
var name$1 = "@circle-fin/swap-kit";
|
|
16664
|
-
var version$1 = "1.
|
|
17271
|
+
var version$1 = "1.4.0";
|
|
16665
17272
|
var pkg$1 = {
|
|
16666
17273
|
name: name$1,
|
|
16667
17274
|
version: version$1};
|
|
@@ -16726,7 +17333,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
16726
17333
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
16727
17334
|
provider: z.string({
|
|
16728
17335
|
invalid_type_error: 'provider must be a string'
|
|
16729
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
17336
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
17337
|
+
batchTransactions: z.boolean({
|
|
17338
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
17339
|
+
}).optional()
|
|
16730
17340
|
});
|
|
16731
17341
|
/**
|
|
16732
17342
|
* Zod schema for adapter context.
|
|
@@ -17165,7 +17775,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17165
17775
|
/**
|
|
17166
17776
|
* Circle Stablecoin Service API Key.
|
|
17167
17777
|
* Must be a valid API key format.
|
|
17168
|
-
*/ apiKey: apiKeySchema
|
|
17778
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17169
17779
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
17170
17780
|
/**
|
|
17171
17781
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -17223,7 +17833,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17223
17833
|
/**
|
|
17224
17834
|
* Circle Stablecoin Service API Key.
|
|
17225
17835
|
* Must be a valid API key format.
|
|
17226
|
-
*/ apiKey: apiKeySchema
|
|
17836
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17227
17837
|
});
|
|
17228
17838
|
/**
|
|
17229
17839
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -17259,7 +17869,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17259
17869
|
toChain: z.string({
|
|
17260
17870
|
invalid_type_error: 'toChain must be a string'
|
|
17261
17871
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
17262
|
-
apiKey: apiKeySchema
|
|
17872
|
+
apiKey: apiKeySchema.optional()
|
|
17263
17873
|
});
|
|
17264
17874
|
/**
|
|
17265
17875
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -17268,13 +17878,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17268
17878
|
required_error: 'fee token is required',
|
|
17269
17879
|
invalid_type_error: 'fee token must be a string'
|
|
17270
17880
|
}).min(1, 'fee token must be a non-empty string'),
|
|
17271
|
-
amount: feeAmountSchema
|
|
17881
|
+
amount: feeAmountSchema,
|
|
17882
|
+
decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
17883
|
+
symbol: z.string({
|
|
17884
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
17885
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
17272
17886
|
});
|
|
17273
17887
|
/**
|
|
17274
17888
|
* Developer fee item schema with basis field.
|
|
17275
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
17276
|
-
token: z.string().min(1, 'fee token must be a non-empty string'),
|
|
17277
|
-
amount: feeAmountSchema,
|
|
17889
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
17278
17890
|
basis: z.enum([
|
|
17279
17891
|
'inputAmount',
|
|
17280
17892
|
'estimatedAmount'
|
|
@@ -17366,7 +17978,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17366
17978
|
addresses: z.array(z.string({
|
|
17367
17979
|
invalid_type_error: 'addresses entries must be strings'
|
|
17368
17980
|
}).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(),
|
|
17369
|
-
apiKey: apiKeySchema
|
|
17981
|
+
apiKey: apiKeySchema.optional()
|
|
17370
17982
|
});
|
|
17371
17983
|
/**
|
|
17372
17984
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -18589,7 +19201,7 @@ new Set(Object.values(Blockchain));
|
|
|
18589
19201
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18590
19202
|
|
|
18591
19203
|
var name = "@circle-fin/earn-kit";
|
|
18592
|
-
var version = "1.
|
|
19204
|
+
var version = "1.3.0";
|
|
18593
19205
|
var pkg = {
|
|
18594
19206
|
name: name,
|
|
18595
19207
|
version: version};
|
|
@@ -18719,7 +19331,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18719
19331
|
asset: z.string(),
|
|
18720
19332
|
assetAddress: z.string(),
|
|
18721
19333
|
lltv: z.number(),
|
|
18722
|
-
supplyUsd: z.number()
|
|
19334
|
+
supplyUsd: z.number(),
|
|
19335
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
19336
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
19337
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
19338
|
+
allocationPct: z.number().nullable().optional()
|
|
18723
19339
|
});
|
|
18724
19340
|
/**
|
|
18725
19341
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -18733,7 +19349,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18733
19349
|
])
|
|
18734
19350
|
});
|
|
18735
19351
|
/**
|
|
18736
|
-
* Zod schema for
|
|
19352
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
19353
|
+
*
|
|
19354
|
+
* @internal
|
|
19355
|
+
*/ const managerSchema = z.object({
|
|
19356
|
+
name: z.string(),
|
|
19357
|
+
address: z.string().optional(),
|
|
19358
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
19359
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
19360
|
+
// speculatively.
|
|
19361
|
+
type: z.enum([
|
|
19362
|
+
'curator'
|
|
19363
|
+
])
|
|
19364
|
+
});
|
|
19365
|
+
/**
|
|
19366
|
+
* Zod schema for the APY profile facet in the API response.
|
|
19367
|
+
*
|
|
19368
|
+
* @internal
|
|
19369
|
+
*/ const apyProfileSchema = z.object({
|
|
19370
|
+
current: z.number(),
|
|
19371
|
+
native: z.number().nullable(),
|
|
19372
|
+
d7: z.number().nullable(),
|
|
19373
|
+
d30: z.number().nullable(),
|
|
19374
|
+
d90: z.number().nullable(),
|
|
19375
|
+
rewardShare: z.number().nullable(),
|
|
19376
|
+
source: z.string().optional(),
|
|
19377
|
+
asOf: z.string().optional()
|
|
19378
|
+
});
|
|
19379
|
+
/**
|
|
19380
|
+
* Zod schema for the fee split facet in the API response.
|
|
19381
|
+
*
|
|
19382
|
+
* @internal
|
|
19383
|
+
*/ const feeInfoSchema = z.object({
|
|
19384
|
+
performance: z.number().nullable(),
|
|
19385
|
+
management: z.number().nullable()
|
|
19386
|
+
});
|
|
19387
|
+
/**
|
|
19388
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
19389
|
+
*
|
|
19390
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
19391
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
19392
|
+
*
|
|
19393
|
+
* @internal
|
|
19394
|
+
*/ const liquidityProfileSchema = z.object({
|
|
19395
|
+
totalDeposits: amountJsonSchema,
|
|
19396
|
+
available: amountJsonSchema,
|
|
19397
|
+
totalSupply: amountJsonSchema,
|
|
19398
|
+
status: z.enum([
|
|
19399
|
+
'active',
|
|
19400
|
+
'low_liquidity'
|
|
19401
|
+
])
|
|
19402
|
+
});
|
|
19403
|
+
/**
|
|
19404
|
+
* Zod schema for the risk signals facet in the API response.
|
|
19405
|
+
*
|
|
19406
|
+
* @internal
|
|
19407
|
+
*/ const riskSignalsSchema = z.object({
|
|
19408
|
+
circleSentinel: z.boolean(),
|
|
19409
|
+
warnings: z.array(vaultWarningSchema).optional(),
|
|
19410
|
+
earnKitWarnings: z.array(z.string()).optional()
|
|
19411
|
+
});
|
|
19412
|
+
/**
|
|
19413
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
19414
|
+
*
|
|
19415
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
19416
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
19417
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
19418
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
19419
|
+
* backend; they become required after Expand ships.
|
|
18737
19420
|
*
|
|
18738
19421
|
* @internal
|
|
18739
19422
|
*/ const vaultInfoResponseSchema = z.object({
|
|
@@ -18758,6 +19441,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18758
19441
|
warnings: z.array(vaultWarningSchema).optional(),
|
|
18759
19442
|
earnKitWarnings: z.array(z.string()).optional()
|
|
18760
19443
|
});
|
|
19444
|
+
/**
|
|
19445
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
19446
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
19447
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
19448
|
+
*
|
|
19449
|
+
* @internal
|
|
19450
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
19451
|
+
address: z.string().optional(),
|
|
19452
|
+
asOf: z.string().optional(),
|
|
19453
|
+
manager: managerSchema.nullable().optional(),
|
|
19454
|
+
apyProfile: apyProfileSchema.optional(),
|
|
19455
|
+
fee: feeInfoSchema.optional(),
|
|
19456
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
19457
|
+
riskSignals: riskSignalsSchema.optional()
|
|
19458
|
+
});
|
|
19459
|
+
/**
|
|
19460
|
+
* Zod schema for the `vault` opportunity variant.
|
|
19461
|
+
*
|
|
19462
|
+
* @internal
|
|
19463
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
19464
|
+
productType: z.literal('vault'),
|
|
19465
|
+
collateral: z.array(collateralSchema)
|
|
19466
|
+
});
|
|
19467
|
+
/**
|
|
19468
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
19469
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
19470
|
+
*
|
|
19471
|
+
* @internal
|
|
19472
|
+
*/ const earnOpportunityVariants = [
|
|
19473
|
+
vaultOpportunitySchema
|
|
19474
|
+
];
|
|
19475
|
+
/** @internal */ const earnOpportunitySchema = z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
19476
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
19477
|
+
/**
|
|
19478
|
+
* Tolerant list parser for earn opportunities.
|
|
19479
|
+
*
|
|
19480
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
19481
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
19482
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
19483
|
+
*
|
|
19484
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
19485
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
19486
|
+
* rather than dropping every vault the backend returns.
|
|
19487
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
19488
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
19489
|
+
* of rejecting the whole list.
|
|
19490
|
+
*
|
|
19491
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
19492
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
19493
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
19494
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
19495
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
19496
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
19497
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
19498
|
+
* `ZodError`).
|
|
19499
|
+
*
|
|
19500
|
+
* @internal
|
|
19501
|
+
*/ const earnOpportunityListSchema = z.preprocess((raw)=>{
|
|
19502
|
+
if (!Array.isArray(raw)) {
|
|
19503
|
+
return raw;
|
|
19504
|
+
}
|
|
19505
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
19506
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
19507
|
+
const entries = raw;
|
|
19508
|
+
return entries.map((entry)=>{
|
|
19509
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
19510
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19511
|
+
return entry;
|
|
19512
|
+
}
|
|
19513
|
+
const record = entry;
|
|
19514
|
+
// Older backend predating productType: default to the only type then.
|
|
19515
|
+
return record.productType === undefined ? {
|
|
19516
|
+
...record,
|
|
19517
|
+
productType: 'vault'
|
|
19518
|
+
} : record;
|
|
19519
|
+
}).filter((entry)=>{
|
|
19520
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
19521
|
+
// productType this SDK version doesn't know). Everything else —
|
|
19522
|
+
// non-objects, a non-string productType — flows through to
|
|
19523
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
19524
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19525
|
+
return true;
|
|
19526
|
+
}
|
|
19527
|
+
const productType = entry.productType;
|
|
19528
|
+
if (typeof productType !== 'string') {
|
|
19529
|
+
return true;
|
|
19530
|
+
}
|
|
19531
|
+
return knownProductTypes.has(productType);
|
|
19532
|
+
});
|
|
19533
|
+
}, z.array(earnOpportunitySchema));
|
|
18761
19534
|
// ---------------------------------------------------------------------------
|
|
18762
19535
|
// Position response schema
|
|
18763
19536
|
// ---------------------------------------------------------------------------
|
|
@@ -18887,6 +19660,7 @@ const positionPnlSchema = z.discriminatedUnion('status', [
|
|
|
18887
19660
|
*
|
|
18888
19661
|
* @internal
|
|
18889
19662
|
*/ const depositPayloadSchema = z.object({
|
|
19663
|
+
execId: bridgeDepositExecIdSchema,
|
|
18890
19664
|
executionParams: depositExecutionParamsSchema,
|
|
18891
19665
|
signature: hexSignatureSchema
|
|
18892
19666
|
});
|
|
@@ -18978,6 +19752,21 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
18978
19752
|
amount: amountJsonSchema,
|
|
18979
19753
|
vaultAddress: hexAddressSchema
|
|
18980
19754
|
}).passthrough();
|
|
19755
|
+
/** @internal */ const bridgeQuoteExpirySchema = z.discriminatedUnion('mode', [
|
|
19756
|
+
z.object({
|
|
19757
|
+
mode: z.literal('TIMESTAMP'),
|
|
19758
|
+
expiresAt: z.string().datetime({
|
|
19759
|
+
offset: true
|
|
19760
|
+
})
|
|
19761
|
+
}),
|
|
19762
|
+
z.object({
|
|
19763
|
+
mode: z.literal('BLOCK_NUMBER'),
|
|
19764
|
+
expiresAtBlock: z.number().int(),
|
|
19765
|
+
blockEstimatedAt: z.string().datetime({
|
|
19766
|
+
offset: true
|
|
19767
|
+
}).optional()
|
|
19768
|
+
})
|
|
19769
|
+
]).optional().catch(undefined);
|
|
18981
19770
|
/**
|
|
18982
19771
|
* Zod schema for the bridge deposit prepare payload.
|
|
18983
19772
|
*
|
|
@@ -18989,6 +19778,10 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
18989
19778
|
execId: bridgeDepositExecIdSchema,
|
|
18990
19779
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
18991
19780
|
expiresAt: z.string().datetime(),
|
|
19781
|
+
quoteIssuedAt: z.string().datetime({
|
|
19782
|
+
offset: true
|
|
19783
|
+
}).optional().catch(undefined),
|
|
19784
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
18992
19785
|
review: bridgeDepositPrepareReviewSchema
|
|
18993
19786
|
});
|
|
18994
19787
|
/**
|
|
@@ -19054,6 +19847,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19054
19847
|
*
|
|
19055
19848
|
* @internal
|
|
19056
19849
|
*/ const withdrawPayloadSchema = z.object({
|
|
19850
|
+
execId: bridgeDepositExecIdSchema,
|
|
19057
19851
|
executionParams: withdrawExecutionParamsSchema,
|
|
19058
19852
|
signature: hexSignatureSchema
|
|
19059
19853
|
});
|
|
@@ -19067,6 +19861,27 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19067
19861
|
data: withdrawPayloadSchema
|
|
19068
19862
|
});
|
|
19069
19863
|
// ---------------------------------------------------------------------------
|
|
19864
|
+
// Transaction report response schema
|
|
19865
|
+
// ---------------------------------------------------------------------------
|
|
19866
|
+
/**
|
|
19867
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
19868
|
+
*
|
|
19869
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
19870
|
+
* schema accepts any object shape and does not require specific fields.
|
|
19871
|
+
*
|
|
19872
|
+
* @internal
|
|
19873
|
+
*/ const transactionReportPayloadSchema = z.object({}).passthrough();
|
|
19874
|
+
/**
|
|
19875
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
19876
|
+
*
|
|
19877
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
19878
|
+
* envelope.
|
|
19879
|
+
*
|
|
19880
|
+
* @internal
|
|
19881
|
+
*/ z.object({
|
|
19882
|
+
data: transactionReportPayloadSchema
|
|
19883
|
+
});
|
|
19884
|
+
// ---------------------------------------------------------------------------
|
|
19070
19885
|
// Claim rewards response schema
|
|
19071
19886
|
// ---------------------------------------------------------------------------
|
|
19072
19887
|
/**
|
|
@@ -19114,10 +19929,11 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19114
19929
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
19115
19930
|
*
|
|
19116
19931
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
19117
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
19118
|
-
*
|
|
19119
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
19120
|
-
* `'
|
|
19932
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
19933
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
19934
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
19935
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
19936
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
19121
19937
|
*
|
|
19122
19938
|
* @internal
|
|
19123
19939
|
*/ const feeSchema = z.object({
|
|
@@ -19126,6 +19942,30 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19126
19942
|
token: z.string(),
|
|
19127
19943
|
amount: amountJsonSchema
|
|
19128
19944
|
});
|
|
19945
|
+
/**
|
|
19946
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
19947
|
+
*
|
|
19948
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
19949
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
19950
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
19951
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
19952
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
19953
|
+
*
|
|
19954
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
19955
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
19956
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
19957
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
19958
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
19959
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
19960
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
19961
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
19962
|
+
*
|
|
19963
|
+
* @internal
|
|
19964
|
+
*/ const quoteGasFeeSchema = z.object({
|
|
19965
|
+
name: z.string().optional(),
|
|
19966
|
+
fees: z.unknown(),
|
|
19967
|
+
error: z.string().optional()
|
|
19968
|
+
}).passthrough();
|
|
19129
19969
|
/**
|
|
19130
19970
|
* Zod schema for the inner deposit quote payload.
|
|
19131
19971
|
*
|
|
@@ -19141,7 +19981,8 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19141
19981
|
expectedShares: amountJsonSchema,
|
|
19142
19982
|
sharePrice: z.string(),
|
|
19143
19983
|
currentApy: z.number(),
|
|
19144
|
-
fees: z.array(feeSchema).optional()
|
|
19984
|
+
fees: z.array(feeSchema).optional(),
|
|
19985
|
+
gasFees: z.array(quoteGasFeeSchema).optional()
|
|
19145
19986
|
});
|
|
19146
19987
|
/**
|
|
19147
19988
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -19168,6 +20009,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19168
20009
|
sharePrice: z.string(),
|
|
19169
20010
|
maxWithdrawable: amountJsonSchema,
|
|
19170
20011
|
fees: z.array(feeSchema),
|
|
20012
|
+
gasFees: z.array(quoteGasFeeSchema).optional(),
|
|
19171
20013
|
warnings: z.array(z.string()).optional()
|
|
19172
20014
|
});
|
|
19173
20015
|
/**
|
|
@@ -19225,7 +20067,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19225
20067
|
*
|
|
19226
20068
|
* @internal
|
|
19227
20069
|
*/ const getVaultsPayloadSchema = z.object({
|
|
19228
|
-
vaults:
|
|
20070
|
+
vaults: earnOpportunityListSchema,
|
|
19229
20071
|
errors: z.array(vaultErrorSchema)
|
|
19230
20072
|
});
|
|
19231
20073
|
/**
|
|
@@ -19255,7 +20097,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19255
20097
|
*
|
|
19256
20098
|
* @internal
|
|
19257
20099
|
*/ const exploreVaultsPayloadSchema = z.object({
|
|
19258
|
-
vaults:
|
|
20100
|
+
vaults: earnOpportunityListSchema,
|
|
19259
20101
|
pagination: explorePaginationSchema
|
|
19260
20102
|
});
|
|
19261
20103
|
/**
|