@circle-fin/app-kit 1.9.0 → 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 +26 -0
- package/bridge.cjs +622 -26
- package/bridge.d.cts +147 -10
- package/bridge.d.mts +147 -10
- package/bridge.d.ts +147 -10
- package/bridge.mjs +622 -26
- package/chains.cjs +8 -2
- package/chains.d.cts +1 -0
- package/chains.d.mts +1 -0
- package/chains.d.ts +1 -0
- package/chains.mjs +8 -2
- package/context.cjs +1 -0
- package/context.d.cts +152 -12
- package/context.d.mts +152 -12
- package/context.d.ts +152 -12
- package/context.mjs +1 -0
- package/earn.cjs +859 -420
- package/earn.d.cts +521 -94
- package/earn.d.mts +521 -94
- package/earn.d.ts +521 -94
- package/earn.mjs +859 -421
- package/estimateBridge.cjs +622 -26
- package/estimateBridge.d.cts +147 -10
- package/estimateBridge.d.mts +147 -10
- package/estimateBridge.d.ts +147 -10
- package/estimateBridge.mjs +622 -26
- package/estimateSwap.cjs +810 -92
- package/estimateSwap.d.cts +147 -10
- package/estimateSwap.d.mts +147 -10
- package/estimateSwap.d.ts +147 -10
- package/estimateSwap.mjs +810 -92
- package/index.cjs +2450 -645
- package/index.d.cts +1003 -126
- package/index.d.mts +1003 -126
- package/index.d.ts +1003 -126
- package/index.mjs +2450 -645
- package/package.json +6 -6
- package/swap.cjs +810 -92
- package/swap.d.cts +147 -10
- package/swap.d.mts +147 -10
- package/swap.d.ts +147 -10
- package/swap.mjs +810 -92
- package/unifiedBalance.cjs +722 -115
- package/unifiedBalance.d.cts +222 -4
- package/unifiedBalance.d.mts +222 -4
- package/unifiedBalance.d.ts +222 -4
- package/unifiedBalance.mjs +722 -115
package/bridge.mjs
CHANGED
|
@@ -20,9 +20,9 @@ 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
|
-
import '@ethersproject/abi';
|
|
26
26
|
import { PublicKey } from '@solana/web3.js';
|
|
27
27
|
import 'bn.js';
|
|
28
28
|
import '@coral-xyz/anchor';
|
|
@@ -3094,7 +3094,10 @@ var EarnChain;
|
|
|
3094
3094
|
contracts: {
|
|
3095
3095
|
v1: {
|
|
3096
3096
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3097
|
-
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'
|
|
3098
3101
|
}
|
|
3099
3102
|
},
|
|
3100
3103
|
forwarderSupported: {
|
|
@@ -6212,7 +6215,10 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
6212
6215
|
minter: z.string({
|
|
6213
6216
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6214
6217
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6215
|
-
}).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()
|
|
6216
6222
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6217
6223
|
;
|
|
6218
6224
|
/**
|
|
@@ -6734,21 +6740,31 @@ const swapTokenEnumSchema = z.enum([
|
|
|
6734
6740
|
* returning the appropriate address based on the requested contract type.
|
|
6735
6741
|
*
|
|
6736
6742
|
* @param chain - The chain definition to resolve the contract address for
|
|
6737
|
-
* @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')
|
|
6738
6744
|
* @returns The contract address for the specified contract type
|
|
6739
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
|
|
6740
6747
|
*/ const resolveCCTPV2ContractAddress = (chain, contractType)=>{
|
|
6741
6748
|
// Handle custom bridge contract for tokenMessenger (burn transaction)
|
|
6742
|
-
if (hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6749
|
+
if (contractType === 'tokenMessenger' && hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6743
6750
|
return chain.kitContracts.bridge;
|
|
6744
6751
|
}
|
|
6745
6752
|
// At this point we know CCTP v2 is supported, so contracts exist
|
|
6746
6753
|
const cctpConfig = chain.cctp;
|
|
6747
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
|
+
}
|
|
6748
6764
|
// Handle different contract types with explicit type checking
|
|
6749
6765
|
switch(contracts.type){
|
|
6750
6766
|
case 'split':
|
|
6751
|
-
return contracts.tokenMessenger ;
|
|
6767
|
+
return contractType === 'tokenMessenger' ? contracts.tokenMessenger : contracts.messageTransmitter;
|
|
6752
6768
|
case 'merged':
|
|
6753
6769
|
return contracts.contract;
|
|
6754
6770
|
default:
|
|
@@ -9603,7 +9619,7 @@ function resolveOptions(options) {
|
|
|
9603
9619
|
}
|
|
9604
9620
|
|
|
9605
9621
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9606
|
-
var version$3 = "1.12.
|
|
9622
|
+
var version$3 = "1.12.1";
|
|
9607
9623
|
var pkg$3 = {
|
|
9608
9624
|
name: name$2,
|
|
9609
9625
|
version: version$3};
|
|
@@ -12107,6 +12123,144 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
12107
12123
|
return false;
|
|
12108
12124
|
};
|
|
12109
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
|
+
|
|
12110
12264
|
/**
|
|
12111
12265
|
* Type guard to validate the forwardFee object structure.
|
|
12112
12266
|
*
|
|
@@ -13038,6 +13192,109 @@ const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
|
13038
13192
|
}
|
|
13039
13193
|
}
|
|
13040
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
|
+
|
|
13041
13298
|
/**
|
|
13042
13299
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
13043
13300
|
*
|
|
@@ -14246,10 +14503,15 @@ const mockAttestationMessage = {
|
|
|
14246
14503
|
const burnCallData = burnRequest.getCallData();
|
|
14247
14504
|
// batchExecute may throw before submission (wallet declined) but never
|
|
14248
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.
|
|
14249
14509
|
const batchResult = await adapter.batchExecute([
|
|
14250
14510
|
approveCallData,
|
|
14251
14511
|
burnCallData
|
|
14252
|
-
], chain
|
|
14512
|
+
], chain, {
|
|
14513
|
+
fromAddress: params.source.address
|
|
14514
|
+
});
|
|
14253
14515
|
const approveReceipt = batchResult.receipts[0];
|
|
14254
14516
|
const burnReceipt = batchResult.receipts[1];
|
|
14255
14517
|
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
|
|
@@ -14392,7 +14654,7 @@ const mockAttestationMessage = {
|
|
|
14392
14654
|
return step;
|
|
14393
14655
|
}
|
|
14394
14656
|
|
|
14395
|
-
var version$2 = "1.
|
|
14657
|
+
var version$2 = "1.10.0";
|
|
14396
14658
|
var pkg$2 = {
|
|
14397
14659
|
version: version$2};
|
|
14398
14660
|
|
|
@@ -15547,7 +15809,7 @@ function assertCCTPV2Config(config) {
|
|
|
15547
15809
|
throw new Error(`Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
15548
15810
|
}
|
|
15549
15811
|
// Resolve spender address with proper error handling
|
|
15550
|
-
const spenderAddress = resolveCCTPV2ContractAddress(chain);
|
|
15812
|
+
const spenderAddress = resolveCCTPV2ContractAddress(chain, 'tokenMessenger');
|
|
15551
15813
|
// Prepare action parameters
|
|
15552
15814
|
const actionParams = {
|
|
15553
15815
|
amount: BigInt(amount),
|
|
@@ -16027,6 +16289,106 @@ function assertCCTPV2Config(config) {
|
|
|
16027
16289
|
return await source.adapter.prepareAction('cctp.v2.depositForBurn', actionParams, resolvedContext);
|
|
16028
16290
|
}
|
|
16029
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
|
+
/**
|
|
16030
16392
|
* Waits for a transaction to be mined and confirmed on the blockchain.
|
|
16031
16393
|
*
|
|
16032
16394
|
* This method should block until the transaction is confirmed on the blockchain.
|
|
@@ -16906,7 +17268,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16906
17268
|
};
|
|
16907
17269
|
|
|
16908
17270
|
var name$1 = "@circle-fin/swap-kit";
|
|
16909
|
-
var version$1 = "1.
|
|
17271
|
+
var version$1 = "1.4.0";
|
|
16910
17272
|
var pkg$1 = {
|
|
16911
17273
|
name: name$1,
|
|
16912
17274
|
version: version$1};
|
|
@@ -16971,7 +17333,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
16971
17333
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
16972
17334
|
provider: z.string({
|
|
16973
17335
|
invalid_type_error: 'provider must be a string'
|
|
16974
|
-
}).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()
|
|
16975
17340
|
});
|
|
16976
17341
|
/**
|
|
16977
17342
|
* Zod schema for adapter context.
|
|
@@ -17410,7 +17775,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17410
17775
|
/**
|
|
17411
17776
|
* Circle Stablecoin Service API Key.
|
|
17412
17777
|
* Must be a valid API key format.
|
|
17413
|
-
*/ apiKey: apiKeySchema
|
|
17778
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17414
17779
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
17415
17780
|
/**
|
|
17416
17781
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -17468,7 +17833,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17468
17833
|
/**
|
|
17469
17834
|
* Circle Stablecoin Service API Key.
|
|
17470
17835
|
* Must be a valid API key format.
|
|
17471
|
-
*/ apiKey: apiKeySchema
|
|
17836
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17472
17837
|
});
|
|
17473
17838
|
/**
|
|
17474
17839
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -17504,7 +17869,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17504
17869
|
toChain: z.string({
|
|
17505
17870
|
invalid_type_error: 'toChain must be a string'
|
|
17506
17871
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
17507
|
-
apiKey: apiKeySchema
|
|
17872
|
+
apiKey: apiKeySchema.optional()
|
|
17508
17873
|
});
|
|
17509
17874
|
/**
|
|
17510
17875
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -17513,13 +17878,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17513
17878
|
required_error: 'fee token is required',
|
|
17514
17879
|
invalid_type_error: 'fee token must be a string'
|
|
17515
17880
|
}).min(1, 'fee token must be a non-empty string'),
|
|
17516
|
-
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()
|
|
17517
17886
|
});
|
|
17518
17887
|
/**
|
|
17519
17888
|
* Developer fee item schema with basis field.
|
|
17520
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
17521
|
-
token: z.string().min(1, 'fee token must be a non-empty string'),
|
|
17522
|
-
amount: feeAmountSchema,
|
|
17889
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
17523
17890
|
basis: z.enum([
|
|
17524
17891
|
'inputAmount',
|
|
17525
17892
|
'estimatedAmount'
|
|
@@ -17611,7 +17978,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17611
17978
|
addresses: z.array(z.string({
|
|
17612
17979
|
invalid_type_error: 'addresses entries must be strings'
|
|
17613
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(),
|
|
17614
|
-
apiKey: apiKeySchema
|
|
17981
|
+
apiKey: apiKeySchema.optional()
|
|
17615
17982
|
});
|
|
17616
17983
|
/**
|
|
17617
17984
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -18834,7 +19201,7 @@ new Set(Object.values(Blockchain));
|
|
|
18834
19201
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18835
19202
|
|
|
18836
19203
|
var name = "@circle-fin/earn-kit";
|
|
18837
|
-
var version = "1.
|
|
19204
|
+
var version = "1.3.0";
|
|
18838
19205
|
var pkg = {
|
|
18839
19206
|
name: name,
|
|
18840
19207
|
version: version};
|
|
@@ -18964,7 +19331,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18964
19331
|
asset: z.string(),
|
|
18965
19332
|
assetAddress: z.string(),
|
|
18966
19333
|
lltv: z.number(),
|
|
18967
|
-
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()
|
|
18968
19339
|
});
|
|
18969
19340
|
/**
|
|
18970
19341
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -18978,7 +19349,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18978
19349
|
])
|
|
18979
19350
|
});
|
|
18980
19351
|
/**
|
|
18981
|
-
* 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.
|
|
18982
19420
|
*
|
|
18983
19421
|
* @internal
|
|
18984
19422
|
*/ const vaultInfoResponseSchema = z.object({
|
|
@@ -19003,6 +19441,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
19003
19441
|
warnings: z.array(vaultWarningSchema).optional(),
|
|
19004
19442
|
earnKitWarnings: z.array(z.string()).optional()
|
|
19005
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));
|
|
19006
19534
|
// ---------------------------------------------------------------------------
|
|
19007
19535
|
// Position response schema
|
|
19008
19536
|
// ---------------------------------------------------------------------------
|
|
@@ -19132,6 +19660,7 @@ const positionPnlSchema = z.discriminatedUnion('status', [
|
|
|
19132
19660
|
*
|
|
19133
19661
|
* @internal
|
|
19134
19662
|
*/ const depositPayloadSchema = z.object({
|
|
19663
|
+
execId: bridgeDepositExecIdSchema,
|
|
19135
19664
|
executionParams: depositExecutionParamsSchema,
|
|
19136
19665
|
signature: hexSignatureSchema
|
|
19137
19666
|
});
|
|
@@ -19223,6 +19752,21 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19223
19752
|
amount: amountJsonSchema,
|
|
19224
19753
|
vaultAddress: hexAddressSchema
|
|
19225
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);
|
|
19226
19770
|
/**
|
|
19227
19771
|
* Zod schema for the bridge deposit prepare payload.
|
|
19228
19772
|
*
|
|
@@ -19234,6 +19778,10 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19234
19778
|
execId: bridgeDepositExecIdSchema,
|
|
19235
19779
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
19236
19780
|
expiresAt: z.string().datetime(),
|
|
19781
|
+
quoteIssuedAt: z.string().datetime({
|
|
19782
|
+
offset: true
|
|
19783
|
+
}).optional().catch(undefined),
|
|
19784
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
19237
19785
|
review: bridgeDepositPrepareReviewSchema
|
|
19238
19786
|
});
|
|
19239
19787
|
/**
|
|
@@ -19299,6 +19847,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19299
19847
|
*
|
|
19300
19848
|
* @internal
|
|
19301
19849
|
*/ const withdrawPayloadSchema = z.object({
|
|
19850
|
+
execId: bridgeDepositExecIdSchema,
|
|
19302
19851
|
executionParams: withdrawExecutionParamsSchema,
|
|
19303
19852
|
signature: hexSignatureSchema
|
|
19304
19853
|
});
|
|
@@ -19312,6 +19861,27 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19312
19861
|
data: withdrawPayloadSchema
|
|
19313
19862
|
});
|
|
19314
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
|
+
// ---------------------------------------------------------------------------
|
|
19315
19885
|
// Claim rewards response schema
|
|
19316
19886
|
// ---------------------------------------------------------------------------
|
|
19317
19887
|
/**
|
|
@@ -19372,6 +19942,30 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19372
19942
|
token: z.string(),
|
|
19373
19943
|
amount: amountJsonSchema
|
|
19374
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();
|
|
19375
19969
|
/**
|
|
19376
19970
|
* Zod schema for the inner deposit quote payload.
|
|
19377
19971
|
*
|
|
@@ -19387,7 +19981,8 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19387
19981
|
expectedShares: amountJsonSchema,
|
|
19388
19982
|
sharePrice: z.string(),
|
|
19389
19983
|
currentApy: z.number(),
|
|
19390
|
-
fees: z.array(feeSchema).optional()
|
|
19984
|
+
fees: z.array(feeSchema).optional(),
|
|
19985
|
+
gasFees: z.array(quoteGasFeeSchema).optional()
|
|
19391
19986
|
});
|
|
19392
19987
|
/**
|
|
19393
19988
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -19414,6 +20009,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19414
20009
|
sharePrice: z.string(),
|
|
19415
20010
|
maxWithdrawable: amountJsonSchema,
|
|
19416
20011
|
fees: z.array(feeSchema),
|
|
20012
|
+
gasFees: z.array(quoteGasFeeSchema).optional(),
|
|
19417
20013
|
warnings: z.array(z.string()).optional()
|
|
19418
20014
|
});
|
|
19419
20015
|
/**
|
|
@@ -19471,7 +20067,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19471
20067
|
*
|
|
19472
20068
|
* @internal
|
|
19473
20069
|
*/ const getVaultsPayloadSchema = z.object({
|
|
19474
|
-
vaults:
|
|
20070
|
+
vaults: earnOpportunityListSchema,
|
|
19475
20071
|
errors: z.array(vaultErrorSchema)
|
|
19476
20072
|
});
|
|
19477
20073
|
/**
|
|
@@ -19501,7 +20097,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
19501
20097
|
*
|
|
19502
20098
|
* @internal
|
|
19503
20099
|
*/ const exploreVaultsPayloadSchema = z.object({
|
|
19504
|
-
vaults:
|
|
20100
|
+
vaults: earnOpportunityListSchema,
|
|
19505
20101
|
pagination: explorePaginationSchema
|
|
19506
20102
|
});
|
|
19507
20103
|
/**
|