@circle-fin/app-kit 1.9.0 → 1.11.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 +60 -0
- package/bridge.cjs +691 -43
- package/bridge.d.cts +159 -11
- package/bridge.d.mts +159 -11
- package/bridge.d.ts +159 -11
- package/bridge.mjs +691 -43
- package/chains.cjs +19 -2
- package/chains.d.cts +1 -0
- package/chains.d.mts +1 -0
- package/chains.d.ts +1 -0
- package/chains.mjs +19 -2
- package/context.cjs +12 -0
- package/context.d.cts +164 -13
- package/context.d.mts +164 -13
- package/context.d.ts +164 -13
- package/context.mjs +12 -0
- package/earn.cjs +1559 -468
- package/earn.d.cts +533 -95
- package/earn.d.mts +533 -95
- package/earn.d.ts +533 -95
- package/earn.mjs +1559 -469
- package/estimateBridge.cjs +691 -43
- package/estimateBridge.d.cts +159 -11
- package/estimateBridge.d.mts +159 -11
- package/estimateBridge.d.ts +159 -11
- package/estimateBridge.mjs +691 -43
- package/estimateSwap.cjs +1065 -118
- package/estimateSwap.d.cts +159 -11
- package/estimateSwap.d.mts +159 -11
- package/estimateSwap.d.ts +159 -11
- package/estimateSwap.mjs +1065 -118
- package/index.cjs +2981 -718
- package/index.d.cts +1104 -133
- package/index.d.mts +1104 -133
- package/index.d.ts +1104 -133
- package/index.mjs +2981 -718
- package/package.json +7 -6
- package/swap.cjs +1065 -118
- package/swap.d.cts +159 -11
- package/swap.d.mts +159 -11
- package/swap.d.ts +159 -11
- package/swap.mjs +1065 -118
- package/unifiedBalance.cjs +817 -140
- package/unifiedBalance.d.cts +250 -9
- package/unifiedBalance.d.mts +250 -9
- package/unifiedBalance.d.ts +250 -9
- package/unifiedBalance.mjs +817 -140
package/bridge.cjs
CHANGED
|
@@ -18,13 +18,24 @@
|
|
|
18
18
|
|
|
19
19
|
'use strict';
|
|
20
20
|
|
|
21
|
+
// Buffer polyfill setup - executes before any other code
|
|
22
|
+
// Ensures globalThis.Buffer is available for Solana libraries
|
|
23
|
+
const { Buffer } = require('buffer');
|
|
24
|
+
if (typeof globalThis !== 'undefined' && typeof globalThis.Buffer === 'undefined') {
|
|
25
|
+
globalThis.Buffer = Buffer;
|
|
26
|
+
}
|
|
27
|
+
if (typeof window !== 'undefined' && typeof window.Buffer === 'undefined') {
|
|
28
|
+
window.Buffer = Buffer;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
21
32
|
var zod = require('zod');
|
|
22
33
|
var pino = require('pino');
|
|
23
34
|
var units = require('@ethersproject/units');
|
|
24
35
|
var bytes = require('@ethersproject/bytes');
|
|
36
|
+
require('@ethersproject/abi');
|
|
25
37
|
var address = require('@ethersproject/address');
|
|
26
38
|
var bs58 = require('bs58');
|
|
27
|
-
require('@ethersproject/abi');
|
|
28
39
|
var web3_js = require('@solana/web3.js');
|
|
29
40
|
require('bn.js');
|
|
30
41
|
require('@coral-xyz/anchor');
|
|
@@ -51,6 +62,27 @@ var bs58__default = /*#__PURE__*/_interopDefault(bs58);
|
|
|
51
62
|
* }
|
|
52
63
|
* ```
|
|
53
64
|
*/ const isNodeEnvironment = ()=>typeof process !== 'undefined' && typeof process.versions === 'object' && typeof process.versions.node === 'string';
|
|
65
|
+
/**
|
|
66
|
+
* Return the SDK User-Agent request header only when running in Node.js.
|
|
67
|
+
*
|
|
68
|
+
* Browsers forbid manually setting `User-Agent`, and a custom fallback header
|
|
69
|
+
* can trigger CORS preflight. Non-Node server runtimes also omit this optional
|
|
70
|
+
* attribution header because they cannot set it reliably.
|
|
71
|
+
*
|
|
72
|
+
* @returns A User-Agent header in Node.js, or an empty object otherwise.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* import { getNodeUserAgentHeader } from '@core/utils'
|
|
77
|
+
*
|
|
78
|
+
* const headers = {
|
|
79
|
+
* 'Content-Type': 'application/json',
|
|
80
|
+
* ...getNodeUserAgentHeader(),
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/ const getNodeUserAgentHeader = ()=>isNodeEnvironment() ? {
|
|
84
|
+
'User-Agent': getUserAgent()
|
|
85
|
+
} : {};
|
|
54
86
|
/**
|
|
55
87
|
* Detect the runtime environment and return a shortened identifier.
|
|
56
88
|
*
|
|
@@ -3101,7 +3133,10 @@ var EarnChain;
|
|
|
3101
3133
|
contracts: {
|
|
3102
3134
|
v1: {
|
|
3103
3135
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3104
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
3136
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3137
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
3138
|
+
// deposit into the GatewayWallet above.
|
|
3139
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3105
3140
|
}
|
|
3106
3141
|
},
|
|
3107
3142
|
forwarderSupported: {
|
|
@@ -6219,7 +6254,10 @@ var Chains = {
|
|
|
6219
6254
|
minter: zod.z.string({
|
|
6220
6255
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6221
6256
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6222
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
6257
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
6258
|
+
depositForHandler: zod.z.string({
|
|
6259
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
6260
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
6223
6261
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6224
6262
|
;
|
|
6225
6263
|
/**
|
|
@@ -6741,21 +6779,31 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
6741
6779
|
* returning the appropriate address based on the requested contract type.
|
|
6742
6780
|
*
|
|
6743
6781
|
* @param chain - The chain definition to resolve the contract address for
|
|
6744
|
-
* @param contractType - The type of contract address to resolve ('tokenMessenger' or '
|
|
6782
|
+
* @param contractType - The type of contract address to resolve ('tokenMessenger', 'messageTransmitter', or 'tokenMessengerWithFees')
|
|
6745
6783
|
* @returns The contract address for the specified contract type
|
|
6746
6784
|
* @throws Error when chain does not support CCTP v2 or has unsupported contract configuration
|
|
6785
|
+
* @throws Error when 'tokenMessengerWithFees' is requested but not configured on the chain
|
|
6747
6786
|
*/ const resolveCCTPV2ContractAddress = (chain, contractType)=>{
|
|
6748
6787
|
// Handle custom bridge contract for tokenMessenger (burn transaction)
|
|
6749
|
-
if (hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6788
|
+
if (contractType === 'tokenMessenger' && hasCustomContractSupport(chain, 'bridge') && chain.kitContracts?.bridge !== undefined) {
|
|
6750
6789
|
return chain.kitContracts.bridge;
|
|
6751
6790
|
}
|
|
6752
6791
|
// At this point we know CCTP v2 is supported, so contracts exist
|
|
6753
6792
|
const cctpConfig = chain.cctp;
|
|
6754
6793
|
const contracts = cctpConfig.contracts.v2;
|
|
6794
|
+
// The `TokenMessengerWithFees` wrapper (prepaid FORWARD path) is an optional
|
|
6795
|
+
// deployment carried alongside both split and merged configurations.
|
|
6796
|
+
if (contractType === 'tokenMessengerWithFees') {
|
|
6797
|
+
const wrapper = contracts.tokenMessengerWithFees;
|
|
6798
|
+
if (wrapper === undefined || wrapper === '') {
|
|
6799
|
+
throw new Error(`TokenMessengerWithFees is not configured on chain ${chain.name}. The prepaid FORWARD path is unavailable on this chain.`);
|
|
6800
|
+
}
|
|
6801
|
+
return wrapper;
|
|
6802
|
+
}
|
|
6755
6803
|
// Handle different contract types with explicit type checking
|
|
6756
6804
|
switch(contracts.type){
|
|
6757
6805
|
case 'split':
|
|
6758
|
-
return contracts.tokenMessenger ;
|
|
6806
|
+
return contractType === 'tokenMessenger' ? contracts.tokenMessenger : contracts.messageTransmitter;
|
|
6759
6807
|
case 'merged':
|
|
6760
6808
|
return contracts.contract;
|
|
6761
6809
|
default:
|
|
@@ -7461,13 +7509,12 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7461
7509
|
headers: {
|
|
7462
7510
|
...DEFAULT_CONFIG$1.headers,
|
|
7463
7511
|
...config.headers ?? {},
|
|
7464
|
-
//
|
|
7465
|
-
//
|
|
7466
|
-
|
|
7467
|
-
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
}
|
|
7512
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
7513
|
+
// fallback header the SDK used instead trips CORS preflight against the
|
|
7514
|
+
// Circle APIs (it isn't in their `Access-Control-Allow-Headers`),
|
|
7515
|
+
// blocking the request. So send the SDK user agent only in Node;
|
|
7516
|
+
// browsers omit it entirely.
|
|
7517
|
+
...getNodeUserAgentHeader()
|
|
7471
7518
|
}
|
|
7472
7519
|
};
|
|
7473
7520
|
let lastError;
|
|
@@ -9253,6 +9300,7 @@ function resolveOptions(options) {
|
|
|
9253
9300
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
9254
9301
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
9255
9302
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
9303
|
+
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
9256
9304
|
if (payload.errorDetails !== undefined) {
|
|
9257
9305
|
const errorDetails = {
|
|
9258
9306
|
...payload.errorDetails.errorCode !== undefined && {
|
|
@@ -9323,18 +9371,15 @@ function resolveOptions(options) {
|
|
|
9323
9371
|
timeoutHandle.unref();
|
|
9324
9372
|
}
|
|
9325
9373
|
try {
|
|
9326
|
-
const isNode = isNodeEnvironment();
|
|
9327
|
-
const userAgent = getUserAgent();
|
|
9328
9374
|
await fetch(getLogsUrl(), {
|
|
9329
9375
|
method: 'POST',
|
|
9330
9376
|
headers: {
|
|
9331
9377
|
'Content-Type': 'application/json',
|
|
9332
|
-
//
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
|
|
9337
|
-
}
|
|
9378
|
+
// Browsers forbid setting a user-agent request header, and the custom
|
|
9379
|
+
// fallback header the SDK used instead trips CORS preflight (it isn't
|
|
9380
|
+
// in the telemetry endpoint's `Access-Control-Allow-Headers`), so send
|
|
9381
|
+
// it only in Node; browsers omit it entirely.
|
|
9382
|
+
...getNodeUserAgentHeader()
|
|
9338
9383
|
},
|
|
9339
9384
|
body: JSON.stringify(toSafePayload(payload)),
|
|
9340
9385
|
signal: controller.signal
|
|
@@ -9465,7 +9510,7 @@ function resolveOptions(options) {
|
|
|
9465
9510
|
// discards the stack trace, nested `cause`, and any custom Error
|
|
9466
9511
|
// properties — exactly the context an on-call needs when a
|
|
9467
9512
|
// resolver-closure regression triggers this path.
|
|
9468
|
-
console.warn(`[stablecoin-kits telemetry] dropped
|
|
9513
|
+
console.warn(`[stablecoin-kits telemetry] dropped event '${eventType}':`, cause);
|
|
9469
9514
|
} catch {
|
|
9470
9515
|
// console.warn itself throwing is the user's environment; nothing more we
|
|
9471
9516
|
// can do without risking the original operation error.
|
|
@@ -9481,7 +9526,9 @@ function resolveOptions(options) {
|
|
|
9481
9526
|
sdkVersion: config.sdkVersion,
|
|
9482
9527
|
eventType,
|
|
9483
9528
|
timestamp: new Date().toISOString(),
|
|
9484
|
-
errorDetails
|
|
9529
|
+
...errorDetails !== undefined && {
|
|
9530
|
+
errorDetails
|
|
9531
|
+
},
|
|
9485
9532
|
clientContext: buildClientContext(),
|
|
9486
9533
|
...context?.sourceChain != null && {
|
|
9487
9534
|
sourceChain: context.sourceChain
|
|
@@ -9497,6 +9544,9 @@ function resolveOptions(options) {
|
|
|
9497
9544
|
},
|
|
9498
9545
|
...context?.txHash != null && {
|
|
9499
9546
|
txHash: context.txHash
|
|
9547
|
+
},
|
|
9548
|
+
...context?.correlationId != null && {
|
|
9549
|
+
correlationId: context.correlationId
|
|
9500
9550
|
}
|
|
9501
9551
|
};
|
|
9502
9552
|
}
|
|
@@ -9610,7 +9660,7 @@ function resolveOptions(options) {
|
|
|
9610
9660
|
}
|
|
9611
9661
|
|
|
9612
9662
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9613
|
-
var version$3 = "1.12.
|
|
9663
|
+
var version$3 = "1.12.2";
|
|
9614
9664
|
var pkg$3 = {
|
|
9615
9665
|
name: name$2,
|
|
9616
9666
|
version: version$3};
|
|
@@ -12114,6 +12164,150 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
12114
12164
|
return false;
|
|
12115
12165
|
};
|
|
12116
12166
|
|
|
12167
|
+
/**
|
|
12168
|
+
* The zero address, denoting a native-currency fee in a signed quote.
|
|
12169
|
+
*/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
12170
|
+
/**
|
|
12171
|
+
* Resolve the fee payment channel for a prepaid-FORWARD burn via `TokenMessengerWithFees`.
|
|
12172
|
+
*
|
|
12173
|
+
* Determines the native `msg.value` and the ERC-20 approvals required, honouring
|
|
12174
|
+
* the quote's `feeToken`:
|
|
12175
|
+
* - Native fee (`feeToken` is the zero address): attach exactly `feeTotalAmount`
|
|
12176
|
+
* as `msg.value`; approve only the burn amount.
|
|
12177
|
+
* - ERC-20 fee equal to the burn token (both USDC — the `isBurnTokenFee` case):
|
|
12178
|
+
* approve a single combined `amount + feeTotalAmount` and skip the redundant
|
|
12179
|
+
* second approval.
|
|
12180
|
+
* - ERC-20 fee different from the burn token: approve the burn amount and the fee
|
|
12181
|
+
* amount separately.
|
|
12182
|
+
*
|
|
12183
|
+
* This encodes only balance/allowance intent; it does not fetch balances. The
|
|
12184
|
+
* caller is responsible for a balance preflight against the fresh quote.
|
|
12185
|
+
*
|
|
12186
|
+
* @param params - The fee token, burn token, burn amount, and total fee amount.
|
|
12187
|
+
* @returns The resolved fee payment plan.
|
|
12188
|
+
* @throws KitError if `amount` or `feeTotalAmount` is negative.
|
|
12189
|
+
*
|
|
12190
|
+
* @example
|
|
12191
|
+
* ```typescript
|
|
12192
|
+
* // Native fee
|
|
12193
|
+
* resolveFeePayment({
|
|
12194
|
+
* feeToken: '0x0000000000000000000000000000000000000000',
|
|
12195
|
+
* burnToken: '0xUSDC...',
|
|
12196
|
+
* amount: 1_000_000n,
|
|
12197
|
+
* feeTotalAmount: 3_500_000n,
|
|
12198
|
+
* })
|
|
12199
|
+
* // → { isNativeFee: true, isBurnTokenFee: false, nativeValue: 3_500_000n,
|
|
12200
|
+
* // approvals: [{ token: '0xUSDC...', amount: 1_000_000n }] }
|
|
12201
|
+
* ```
|
|
12202
|
+
*/ const resolveFeePayment = (params)=>{
|
|
12203
|
+
const { feeToken, burnToken, amount, feeTotalAmount } = params;
|
|
12204
|
+
if (typeof amount !== 'bigint' || amount < 0n) {
|
|
12205
|
+
throw createValidationFailedError$1('amount', amount, 'Must be a non-negative bigint');
|
|
12206
|
+
}
|
|
12207
|
+
if (typeof feeTotalAmount !== 'bigint' || feeTotalAmount < 0n) {
|
|
12208
|
+
throw createValidationFailedError$1('feeTotalAmount', feeTotalAmount, 'Must be a non-negative bigint');
|
|
12209
|
+
}
|
|
12210
|
+
const isNativeFee = feeToken.toLowerCase() === ZERO_ADDRESS;
|
|
12211
|
+
const isBurnTokenFee = !isNativeFee && feeToken.toLowerCase() === burnToken.toLowerCase();
|
|
12212
|
+
if (isNativeFee) {
|
|
12213
|
+
return {
|
|
12214
|
+
isNativeFee: true,
|
|
12215
|
+
isBurnTokenFee: false,
|
|
12216
|
+
nativeValue: feeTotalAmount,
|
|
12217
|
+
approvals: [
|
|
12218
|
+
{
|
|
12219
|
+
token: burnToken,
|
|
12220
|
+
amount
|
|
12221
|
+
}
|
|
12222
|
+
]
|
|
12223
|
+
};
|
|
12224
|
+
}
|
|
12225
|
+
if (isBurnTokenFee) {
|
|
12226
|
+
// Fee and burn draw on the same token — a single combined approval covers
|
|
12227
|
+
// both; the redundant second approval is skipped.
|
|
12228
|
+
return {
|
|
12229
|
+
isNativeFee: false,
|
|
12230
|
+
isBurnTokenFee: true,
|
|
12231
|
+
nativeValue: 0n,
|
|
12232
|
+
approvals: [
|
|
12233
|
+
{
|
|
12234
|
+
token: burnToken,
|
|
12235
|
+
amount: amount + feeTotalAmount
|
|
12236
|
+
}
|
|
12237
|
+
]
|
|
12238
|
+
};
|
|
12239
|
+
}
|
|
12240
|
+
return {
|
|
12241
|
+
isNativeFee: false,
|
|
12242
|
+
isBurnTokenFee: false,
|
|
12243
|
+
nativeValue: 0n,
|
|
12244
|
+
approvals: [
|
|
12245
|
+
{
|
|
12246
|
+
token: burnToken,
|
|
12247
|
+
amount
|
|
12248
|
+
},
|
|
12249
|
+
{
|
|
12250
|
+
token: feeToken,
|
|
12251
|
+
amount: feeTotalAmount
|
|
12252
|
+
}
|
|
12253
|
+
]
|
|
12254
|
+
};
|
|
12255
|
+
};
|
|
12256
|
+
|
|
12257
|
+
/**
|
|
12258
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
12259
|
+
* hookData must start with.
|
|
12260
|
+
*
|
|
12261
|
+
* Encoded with `TextEncoder` (a browser-safe Web API) rather than `Buffer.from`
|
|
12262
|
+
* so this module-level constant does not reference the Node `Buffer` global at
|
|
12263
|
+
* import time. App Kit inlines this provider into its bundle without a Buffer polyfill, and a
|
|
12264
|
+
* bare `Buffer` here crashes browser bundles (e.g. Vite) on load — even for apps
|
|
12265
|
+
* that never touch the prepaid FORWARD path. Mirrors `buildForwardingHookData`.
|
|
12266
|
+
*/ const CCTP_FORWARD_MAGIC_HEX = Array.from(new TextEncoder().encode(CCTP_FORWARD_MAGIC_PREFIX)).map((byte)=>byte.toString(16).padStart(2, '0')).join('');
|
|
12267
|
+
/**
|
|
12268
|
+
* Determine whether a hookData blob begins with the `cctp-forward` envelope.
|
|
12269
|
+
*
|
|
12270
|
+
* The prepaid FORWARD path requires the GenericExecutor blob to be wrapped in a
|
|
12271
|
+
* `cctp-forward` frame; without it the wrapper reverts `ForwardFeeWithoutHook`.
|
|
12272
|
+
*
|
|
12273
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12274
|
+
* @returns True when the hookData starts with the `cctp-forward` magic.
|
|
12275
|
+
*
|
|
12276
|
+
* @example
|
|
12277
|
+
* ```typescript
|
|
12278
|
+
* hasForwardHook('0x636374702d666f7277617264...') // true
|
|
12279
|
+
* hasForwardHook('0xdeadbeef') // false
|
|
12280
|
+
* ```
|
|
12281
|
+
*/ const hasForwardHook = (hookData)=>{
|
|
12282
|
+
if (typeof hookData !== 'string') {
|
|
12283
|
+
return false;
|
|
12284
|
+
}
|
|
12285
|
+
const normalized = (hookData.startsWith('0x') ? hookData.slice(2) : hookData).toLowerCase();
|
|
12286
|
+
return normalized.startsWith(CCTP_FORWARD_MAGIC_HEX);
|
|
12287
|
+
};
|
|
12288
|
+
/**
|
|
12289
|
+
* Assert that a hookData blob is forward-friendly for the prepaid FORWARD path.
|
|
12290
|
+
*
|
|
12291
|
+
* The prepaid FORWARD path always requests a FORWARD fee item, so the wrapper
|
|
12292
|
+
* requires the hookData to start with a `cctp-forward` frame. Validating this
|
|
12293
|
+
* before the burn surfaces the guaranteed `ForwardFeeWithoutHook` revert as a
|
|
12294
|
+
* typed input error instead of an on-chain failure.
|
|
12295
|
+
*
|
|
12296
|
+
* @param hookData - The 0x-prefixed hookData hex string.
|
|
12297
|
+
* @throws KitError (`INPUT_VALIDATION_FAILED`) if the hookData is missing or lacks
|
|
12298
|
+
* the `cctp-forward` frame.
|
|
12299
|
+
*
|
|
12300
|
+
* @example
|
|
12301
|
+
* ```typescript
|
|
12302
|
+
* assertForwardHookData(geForwardHookData) // ok
|
|
12303
|
+
* assertForwardHookData('0xdeadbeef') // throws — would revert ForwardFeeWithoutHook
|
|
12304
|
+
* ```
|
|
12305
|
+
*/ const assertForwardHookData = (hookData)=>{
|
|
12306
|
+
if (!hasForwardHook(hookData)) {
|
|
12307
|
+
throw createValidationFailedError$1('hookData', hookData, 'Prepaid FORWARD burns require a cctp-forward-wrapped hookData; without it the TokenMessengerWithFees wrapper reverts ForwardFeeWithoutHook');
|
|
12308
|
+
}
|
|
12309
|
+
};
|
|
12310
|
+
|
|
12117
12311
|
/**
|
|
12118
12312
|
* Type guard to validate the forwardFee object structure.
|
|
12119
12313
|
*
|
|
@@ -13045,6 +13239,109 @@ const assertCCTPv2BridgeParamsSymbol = Symbol('assertCCTPv2BridgeParams');
|
|
|
13045
13239
|
}
|
|
13046
13240
|
}
|
|
13047
13241
|
|
|
13242
|
+
/**
|
|
13243
|
+
* Assert that `params` is a well-formed {@link BurnWithFeesParams} object.
|
|
13244
|
+
*
|
|
13245
|
+
* Validates the full public-boundary input before any field destructuring,
|
|
13246
|
+
* `BigInt()` coercion, or adapter preparation runs, so malformed JS-caller
|
|
13247
|
+
* inputs always produce typed `KitError` validation failures.
|
|
13248
|
+
*
|
|
13249
|
+
* Checks performed (in order):
|
|
13250
|
+
* - `params` must be a non-null plain object
|
|
13251
|
+
* - `source` — valid CCTP v2 wallet context (via `assertCCTPv2WalletContext`)
|
|
13252
|
+
* - `destinationChain` — present and supports CCTP v2
|
|
13253
|
+
* - source and destination chains must both be testnet or both mainnet
|
|
13254
|
+
* - source and destination chains must differ
|
|
13255
|
+
* - `executor` — non-empty string
|
|
13256
|
+
* - `amount` — bigint or non-empty string coercible to bigint
|
|
13257
|
+
* - `feeTotalAmount` — bigint or non-empty string coercible to bigint
|
|
13258
|
+
* - `feeToken` — valid EVM address (`0x` + 40 hex chars)
|
|
13259
|
+
* - `claim.signedQuote` — valid `0x`-prefixed hex string
|
|
13260
|
+
* - `claim.refundAddress` — valid EVM address
|
|
13261
|
+
* - `hookData` — valid `0x`-prefixed hex string when present
|
|
13262
|
+
*
|
|
13263
|
+
* @param params - The value to validate.
|
|
13264
|
+
* @throws {KitError} If any field is missing or invalid.
|
|
13265
|
+
*
|
|
13266
|
+
* @example
|
|
13267
|
+
* ```typescript
|
|
13268
|
+
* assertBurnWithFeesParams(params)
|
|
13269
|
+
* // params is now typed as BurnWithFeesParams and safe to use
|
|
13270
|
+
* const { source, destinationChain, amount } = params
|
|
13271
|
+
* ```
|
|
13272
|
+
*/ function assertBurnWithFeesParams(params) {
|
|
13273
|
+
if (params === null || typeof params !== 'object' || Array.isArray(params)) {
|
|
13274
|
+
throw createValidationFailedError$1('params', params, 'Must be a non-null plain object');
|
|
13275
|
+
}
|
|
13276
|
+
const p = params;
|
|
13277
|
+
// Source wallet context
|
|
13278
|
+
assertCCTPv2WalletContext(p['source']);
|
|
13279
|
+
const source = p['source'];
|
|
13280
|
+
// destinationChain
|
|
13281
|
+
const destinationChain = p['destinationChain'];
|
|
13282
|
+
if (destinationChain === null || destinationChain === undefined || typeof destinationChain !== 'object') {
|
|
13283
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'Must be a chain definition object');
|
|
13284
|
+
}
|
|
13285
|
+
if (!isCCTPV2Supported(destinationChain)) {
|
|
13286
|
+
throw createValidationFailedError$1('destinationChain', destinationChain, 'destinationChain must support CCTP v2');
|
|
13287
|
+
}
|
|
13288
|
+
const dest = destinationChain;
|
|
13289
|
+
// Testnet / mainnet mismatch
|
|
13290
|
+
if (source.chain.isTestnet !== dest.isTestnet) {
|
|
13291
|
+
throw createNetworkMismatchError(source.chain, dest);
|
|
13292
|
+
}
|
|
13293
|
+
// Same-chain guard
|
|
13294
|
+
if (source.chain.name === dest.name) {
|
|
13295
|
+
throw createUnsupportedRouteError(source.chain.name, dest.name);
|
|
13296
|
+
}
|
|
13297
|
+
// executor
|
|
13298
|
+
const executor = p['executor'];
|
|
13299
|
+
if (typeof executor !== 'string' || executor === '') {
|
|
13300
|
+
throw createValidationFailedError$1('executor', executor, 'A GenericExecutor address is required (used for both mintRecipient and destinationCaller)');
|
|
13301
|
+
}
|
|
13302
|
+
// amount
|
|
13303
|
+
const rawAmount = p['amount'];
|
|
13304
|
+
if (typeof rawAmount !== 'bigint' && typeof rawAmount !== 'string' || rawAmount === '') {
|
|
13305
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a bigint or a numeric string');
|
|
13306
|
+
}
|
|
13307
|
+
try {
|
|
13308
|
+
BigInt(rawAmount);
|
|
13309
|
+
} catch {
|
|
13310
|
+
throw createValidationFailedError$1('amount', rawAmount, 'Must be a valid integer value coercible to bigint');
|
|
13311
|
+
}
|
|
13312
|
+
// feeTotalAmount
|
|
13313
|
+
const rawFee = p['feeTotalAmount'];
|
|
13314
|
+
if (typeof rawFee !== 'bigint' && typeof rawFee !== 'string' || rawFee === '') {
|
|
13315
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a bigint or a numeric string');
|
|
13316
|
+
}
|
|
13317
|
+
try {
|
|
13318
|
+
BigInt(rawFee);
|
|
13319
|
+
} catch {
|
|
13320
|
+
throw createValidationFailedError$1('feeTotalAmount', rawFee, 'Must be a valid integer value coercible to bigint');
|
|
13321
|
+
}
|
|
13322
|
+
// feeToken
|
|
13323
|
+
if (!evmAddressSchema.safeParse(p['feeToken']).success) {
|
|
13324
|
+
throw createValidationFailedError$1('feeToken', p['feeToken'], 'Must be a valid EVM address (use the zero address for a native fee)');
|
|
13325
|
+
}
|
|
13326
|
+
// claim
|
|
13327
|
+
const rawClaim = p['claim'];
|
|
13328
|
+
if (rawClaim === null || typeof rawClaim !== 'object' || Array.isArray(rawClaim)) {
|
|
13329
|
+
throw createValidationFailedError$1('claim', rawClaim, 'Must be an object with signedQuote and refundAddress');
|
|
13330
|
+
}
|
|
13331
|
+
const claim = rawClaim;
|
|
13332
|
+
if (!hexStringSchema.safeParse(claim['signedQuote']).success) {
|
|
13333
|
+
throw createValidationFailedError$1('claim.signedQuote', claim['signedQuote'], 'Must be a valid hex string starting with 0x');
|
|
13334
|
+
}
|
|
13335
|
+
if (!evmAddressSchema.safeParse(claim['refundAddress']).success) {
|
|
13336
|
+
throw createValidationFailedError$1('claim.refundAddress', claim['refundAddress'], 'Must be a valid EVM address');
|
|
13337
|
+
}
|
|
13338
|
+
// hookData (optional)
|
|
13339
|
+
const hookData = p['hookData'];
|
|
13340
|
+
if (hookData !== undefined && hookData !== '' && !hexStringSchema.safeParse(hookData).success) {
|
|
13341
|
+
throw createValidationFailedError$1('hookData', hookData, 'Must be a valid hex string starting with 0x');
|
|
13342
|
+
}
|
|
13343
|
+
}
|
|
13344
|
+
|
|
13048
13345
|
/**
|
|
13049
13346
|
* CCTP bridge step names that can occur in the bridging flow.
|
|
13050
13347
|
*
|
|
@@ -14253,10 +14550,15 @@ const mockAttestationMessage = {
|
|
|
14253
14550
|
const burnCallData = burnRequest.getCallData();
|
|
14254
14551
|
// batchExecute may throw before submission (wallet declined) but never
|
|
14255
14552
|
// after — post-submission errors are returned as empty receipts.
|
|
14553
|
+
// The sender is threaded for adapters whose execution is routed through a
|
|
14554
|
+
// signing strategy (which has no wallet account to read it from); the
|
|
14555
|
+
// wallet-client path ignores it.
|
|
14256
14556
|
const batchResult = await adapter.batchExecute([
|
|
14257
14557
|
approveCallData,
|
|
14258
14558
|
burnCallData
|
|
14259
|
-
], chain
|
|
14559
|
+
], chain, {
|
|
14560
|
+
fromAddress: params.source.address
|
|
14561
|
+
});
|
|
14260
14562
|
const approveReceipt = batchResult.receipts[0];
|
|
14261
14563
|
const burnReceipt = batchResult.receipts[1];
|
|
14262
14564
|
const approveStep = await buildBatchedStep('approve', approveReceipt, batchResult.batchId, adapter, chain, batchResult.statusCode, batchResult.error);
|
|
@@ -14399,7 +14701,7 @@ const mockAttestationMessage = {
|
|
|
14399
14701
|
return step;
|
|
14400
14702
|
}
|
|
14401
14703
|
|
|
14402
|
-
var version$2 = "1.
|
|
14704
|
+
var version$2 = "1.10.1";
|
|
14403
14705
|
var pkg$2 = {
|
|
14404
14706
|
version: version$2};
|
|
14405
14707
|
|
|
@@ -15554,7 +15856,7 @@ function assertCCTPV2Config(config) {
|
|
|
15554
15856
|
throw new Error(`Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
15555
15857
|
}
|
|
15556
15858
|
// Resolve spender address with proper error handling
|
|
15557
|
-
const spenderAddress = resolveCCTPV2ContractAddress(chain);
|
|
15859
|
+
const spenderAddress = resolveCCTPV2ContractAddress(chain, 'tokenMessenger');
|
|
15558
15860
|
// Prepare action parameters
|
|
15559
15861
|
const actionParams = {
|
|
15560
15862
|
amount: BigInt(amount),
|
|
@@ -16034,6 +16336,106 @@ function assertCCTPV2Config(config) {
|
|
|
16034
16336
|
return await source.adapter.prepareAction('cctp.v2.depositForBurn', actionParams, resolvedContext);
|
|
16035
16337
|
}
|
|
16036
16338
|
/**
|
|
16339
|
+
* Prepare a prepaid-FORWARD burn through the `TokenMessengerWithFees` wrapper.
|
|
16340
|
+
*
|
|
16341
|
+
* Builds the source-chain `depositForBurnWithHookAndFees` call for the
|
|
16342
|
+
* GenericExecutor FORWARD path: fees are collected up front on the source chain
|
|
16343
|
+
* against a signed quote, `mintRecipient` and `destinationCaller` are both set to
|
|
16344
|
+
* the GenericExecutor, and the GE `hookData` is passed through unchanged.
|
|
16345
|
+
*
|
|
16346
|
+
* This is the low-level on-chain primitive behind the UBK `fastCrossChainDeposit`
|
|
16347
|
+
* and Bridge Kit `bridge({ deposit })` flows. The `hookData` and signed-quote
|
|
16348
|
+
* `claim` are produced elsewhere and passed in here:
|
|
16349
|
+
* - `hookData`: `buildForwardingHookDataWithPayload(version,
|
|
16350
|
+
* buildDepositForGenericExecutorPayload(...).hookData)` from `@core/utils`.
|
|
16351
|
+
* - `claim.signedQuote` / `feeToken` / `feeTotalAmount`: from `fetchFeeQuote`
|
|
16352
|
+
* (`@circle-fin/provider-fee-v1`), whose FORWARD item must be bound to the
|
|
16353
|
+
* SAME `hookData` and executor `destinationCaller` used here.
|
|
16354
|
+
*
|
|
16355
|
+
* The returned approvals and burn are NOT executed — the caller executes the
|
|
16356
|
+
* approvals first (in order) and then the burn. The fee payment channel matches
|
|
16357
|
+
* the quote's `feeToken`:
|
|
16358
|
+
* - Native fee: exactly `feeTotalAmount` is attached as the burn's `msg.value`;
|
|
16359
|
+
* only the burn amount is approved.
|
|
16360
|
+
* - USDC fee (same token as the burn): a single combined `amount + feeTotalAmount`
|
|
16361
|
+
* approval covers both; the redundant second approval is skipped.
|
|
16362
|
+
*
|
|
16363
|
+
* @typeParam TFromAdapterCapabilities - The source adapter's capabilities.
|
|
16364
|
+
* @param params - The burn amount, executor, hookData, signed-quote claim, and fee.
|
|
16365
|
+
* @returns The prepared approvals, the prepared burn, and the resolved fee plan.
|
|
16366
|
+
* @throws {KitError} If the wallet context is invalid, `destinationChain` does not
|
|
16367
|
+
* support CCTP v2, the executor is missing, `amount` or `feeTotalAmount` is not
|
|
16368
|
+
* a bigint or a numeric string coercible to bigint, the hookData lacks a
|
|
16369
|
+
* `cctp-forward` frame (guaranteed `ForwardFeeWithoutHook`), or the operation
|
|
16370
|
+
* context cannot be resolved.
|
|
16371
|
+
*
|
|
16372
|
+
* @example
|
|
16373
|
+
* ```typescript
|
|
16374
|
+
* const { approvals, burn } = await provider.burnWithFees({
|
|
16375
|
+
* source,
|
|
16376
|
+
* destinationChain: Arc,
|
|
16377
|
+
* amount: 1_000_000n,
|
|
16378
|
+
* executor: genericExecutorAddress,
|
|
16379
|
+
* hookData: geForwardHookData,
|
|
16380
|
+
* claim: { signedQuote: '0x01...', refundAddress: userAddress },
|
|
16381
|
+
* feeToken: '0x0000000000000000000000000000000000000000', // native
|
|
16382
|
+
* feeTotalAmount: 3_500_000n,
|
|
16383
|
+
* })
|
|
16384
|
+
* for (const approval of approvals) await approval.execute()
|
|
16385
|
+
* const txHash = await burn.execute()
|
|
16386
|
+
* ```
|
|
16387
|
+
*/ async burnWithFees(params) {
|
|
16388
|
+
assertBurnWithFeesParams(params);
|
|
16389
|
+
const { source, destinationChain, executor, hookData, claim, feeToken } = params;
|
|
16390
|
+
const amount = BigInt(params.amount);
|
|
16391
|
+
const feeTotalAmount = BigInt(params.feeTotalAmount);
|
|
16392
|
+
// Coupling guard: the prepaid FORWARD path always requests a FORWARD fee item,
|
|
16393
|
+
// so the hookData must carry a cctp-forward frame; otherwise the wrapper
|
|
16394
|
+
// reverts ForwardFeeWithoutHook. Surface it as a typed input error up front.
|
|
16395
|
+
assertForwardHookData(hookData);
|
|
16396
|
+
const burnToken = source.chain.usdcAddress;
|
|
16397
|
+
const feePayment = resolveFeePayment({
|
|
16398
|
+
feeToken,
|
|
16399
|
+
burnToken,
|
|
16400
|
+
amount,
|
|
16401
|
+
feeTotalAmount
|
|
16402
|
+
});
|
|
16403
|
+
// Resolve operation context from the source wallet context.
|
|
16404
|
+
const operationContext = this.extractOperationContext(source);
|
|
16405
|
+
let resolvedContext;
|
|
16406
|
+
try {
|
|
16407
|
+
resolvedContext = await resolveOperationContext(source.adapter, operationContext);
|
|
16408
|
+
} catch (error) {
|
|
16409
|
+
throw createValidationFailedError$1('source.adapter', undefined, `Failed to resolve operation context: ${error instanceof Error ? error.message : String(error)}`);
|
|
16410
|
+
}
|
|
16411
|
+
const context = resolvedContext;
|
|
16412
|
+
const wrapperAddress = resolveCCTPV2ContractAddress(source.chain, 'tokenMessengerWithFees');
|
|
16413
|
+
// Build the ERC-20 approvals to the wrapper (burn token, plus a distinct fee
|
|
16414
|
+
// token only when the fee is not paid in the burn token).
|
|
16415
|
+
const approvals = await Promise.all(feePayment.approvals.map(async (approval)=>source.adapter.prepareAction('token.approve', {
|
|
16416
|
+
tokenAddress: approval.token,
|
|
16417
|
+
delegate: wrapperAddress,
|
|
16418
|
+
amount: approval.amount
|
|
16419
|
+
}, context)));
|
|
16420
|
+
// Build the burn: mintRecipient AND destinationCaller are both the executor.
|
|
16421
|
+
const burn = await source.adapter.prepareAction('cctp.v2.depositForBurnWithFees', {
|
|
16422
|
+
fromChain: source.chain,
|
|
16423
|
+
toChain: destinationChain,
|
|
16424
|
+
amount,
|
|
16425
|
+
mintRecipient: executor,
|
|
16426
|
+
destinationCaller: executor,
|
|
16427
|
+
hookData,
|
|
16428
|
+
claim,
|
|
16429
|
+
feeToken,
|
|
16430
|
+
feeTotalAmount
|
|
16431
|
+
}, context);
|
|
16432
|
+
return {
|
|
16433
|
+
approvals,
|
|
16434
|
+
burn,
|
|
16435
|
+
feePayment
|
|
16436
|
+
};
|
|
16437
|
+
}
|
|
16438
|
+
/**
|
|
16037
16439
|
* Waits for a transaction to be mined and confirmed on the blockchain.
|
|
16038
16440
|
*
|
|
16039
16441
|
* This method should block until the transaction is confirmed on the blockchain.
|
|
@@ -16913,7 +17315,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
16913
17315
|
};
|
|
16914
17316
|
|
|
16915
17317
|
var name$1 = "@circle-fin/swap-kit";
|
|
16916
|
-
var version$1 = "1.
|
|
17318
|
+
var version$1 = "1.5.0";
|
|
16917
17319
|
var pkg$1 = {
|
|
16918
17320
|
name: name$1,
|
|
16919
17321
|
version: version$1};
|
|
@@ -16978,7 +17380,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
16978
17380
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
16979
17381
|
provider: zod.z.string({
|
|
16980
17382
|
invalid_type_error: 'provider must be a string'
|
|
16981
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
17383
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
17384
|
+
batchTransactions: zod.z.boolean({
|
|
17385
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
17386
|
+
}).optional()
|
|
16982
17387
|
});
|
|
16983
17388
|
/**
|
|
16984
17389
|
* Zod schema for adapter context.
|
|
@@ -17417,7 +17822,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17417
17822
|
/**
|
|
17418
17823
|
* Circle Stablecoin Service API Key.
|
|
17419
17824
|
* Must be a valid API key format.
|
|
17420
|
-
*/ apiKey: apiKeySchema
|
|
17825
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17421
17826
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
17422
17827
|
/**
|
|
17423
17828
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -17475,7 +17880,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17475
17880
|
/**
|
|
17476
17881
|
* Circle Stablecoin Service API Key.
|
|
17477
17882
|
* Must be a valid API key format.
|
|
17478
|
-
*/ apiKey: apiKeySchema
|
|
17883
|
+
*/ apiKey: apiKeySchema.optional()
|
|
17479
17884
|
});
|
|
17480
17885
|
/**
|
|
17481
17886
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -17511,7 +17916,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17511
17916
|
toChain: zod.z.string({
|
|
17512
17917
|
invalid_type_error: 'toChain must be a string'
|
|
17513
17918
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
17514
|
-
apiKey: apiKeySchema
|
|
17919
|
+
apiKey: apiKeySchema.optional()
|
|
17515
17920
|
});
|
|
17516
17921
|
/**
|
|
17517
17922
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -17520,13 +17925,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17520
17925
|
required_error: 'fee token is required',
|
|
17521
17926
|
invalid_type_error: 'fee token must be a string'
|
|
17522
17927
|
}).min(1, 'fee token must be a non-empty string'),
|
|
17523
|
-
amount: feeAmountSchema
|
|
17928
|
+
amount: feeAmountSchema,
|
|
17929
|
+
decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
17930
|
+
symbol: zod.z.string({
|
|
17931
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
17932
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
17524
17933
|
});
|
|
17525
17934
|
/**
|
|
17526
17935
|
* Developer fee item schema with basis field.
|
|
17527
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
17528
|
-
token: zod.z.string().min(1, 'fee token must be a non-empty string'),
|
|
17529
|
-
amount: feeAmountSchema,
|
|
17936
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
17530
17937
|
basis: zod.z.enum([
|
|
17531
17938
|
'inputAmount',
|
|
17532
17939
|
'estimatedAmount'
|
|
@@ -17618,7 +18025,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17618
18025
|
addresses: zod.z.array(zod.z.string({
|
|
17619
18026
|
invalid_type_error: 'addresses entries must be strings'
|
|
17620
18027
|
}).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(),
|
|
17621
|
-
apiKey: apiKeySchema
|
|
18028
|
+
apiKey: apiKeySchema.optional()
|
|
17622
18029
|
});
|
|
17623
18030
|
/**
|
|
17624
18031
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -17649,6 +18056,16 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
17649
18056
|
required_error: 'estimatedAmount is required',
|
|
17650
18057
|
invalid_type_error: 'estimatedAmount must be a string'
|
|
17651
18058
|
}).min(1, 'estimatedAmount must be a non-empty string'),
|
|
18059
|
+
// Per-swap join key echoed back verbatim on success telemetry. Optional so a
|
|
18060
|
+
// not-yet-upgraded service (no field) still validates during rollout. A
|
|
18061
|
+
// malformed/non-UUID value is coerced to `undefined` (no telemetry id) rather
|
|
18062
|
+
// than throwing: this is a telemetry-only field (stripped from the developer
|
|
18063
|
+
// result, never used for control flow), so it must not be able to abort the
|
|
18064
|
+
// swap via `parseCreateSwapResponse().parse()`. Mirrors the best-effort,
|
|
18065
|
+
// never-throw contract of the rest of the telemetry stack. Implemented with
|
|
18066
|
+
// `preprocess` rather than Zod's `.catch()` because static analysis misreads
|
|
18067
|
+
// `.catch` on the schema chain as an unhandled Promise (S7785).
|
|
18068
|
+
correlationId: zod.z.preprocess((value)=>zod.z.string().uuid().safeParse(value).success ? value : undefined, zod.z.string().optional()),
|
|
17652
18069
|
config: createSwapRequestBaseSchema.shape.config.optional(),
|
|
17653
18070
|
fees: createSwapFeesSchema.optional(),
|
|
17654
18071
|
transaction: createSwapTransactionSchema
|
|
@@ -18841,7 +19258,7 @@ new Set(Object.values(Blockchain));
|
|
|
18841
19258
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18842
19259
|
|
|
18843
19260
|
var name = "@circle-fin/earn-kit";
|
|
18844
|
-
var version = "1.
|
|
19261
|
+
var version = "1.4.0";
|
|
18845
19262
|
var pkg = {
|
|
18846
19263
|
name: name,
|
|
18847
19264
|
version: version};
|
|
@@ -18971,7 +19388,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18971
19388
|
asset: zod.z.string(),
|
|
18972
19389
|
assetAddress: zod.z.string(),
|
|
18973
19390
|
lltv: zod.z.number(),
|
|
18974
|
-
supplyUsd: zod.z.number()
|
|
19391
|
+
supplyUsd: zod.z.number(),
|
|
19392
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
19393
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
19394
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
19395
|
+
allocationPct: zod.z.number().nullable().optional()
|
|
18975
19396
|
});
|
|
18976
19397
|
/**
|
|
18977
19398
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -18985,7 +19406,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
18985
19406
|
])
|
|
18986
19407
|
});
|
|
18987
19408
|
/**
|
|
18988
|
-
* Zod schema for
|
|
19409
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
19410
|
+
*
|
|
19411
|
+
* @internal
|
|
19412
|
+
*/ const managerSchema = zod.z.object({
|
|
19413
|
+
name: zod.z.string(),
|
|
19414
|
+
address: zod.z.string().optional(),
|
|
19415
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
19416
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
19417
|
+
// speculatively.
|
|
19418
|
+
type: zod.z.enum([
|
|
19419
|
+
'curator'
|
|
19420
|
+
])
|
|
19421
|
+
});
|
|
19422
|
+
/**
|
|
19423
|
+
* Zod schema for the APY profile facet in the API response.
|
|
19424
|
+
*
|
|
19425
|
+
* @internal
|
|
19426
|
+
*/ const apyProfileSchema = zod.z.object({
|
|
19427
|
+
current: zod.z.number(),
|
|
19428
|
+
native: zod.z.number().nullable(),
|
|
19429
|
+
d7: zod.z.number().nullable(),
|
|
19430
|
+
d30: zod.z.number().nullable(),
|
|
19431
|
+
d90: zod.z.number().nullable(),
|
|
19432
|
+
rewardShare: zod.z.number().nullable(),
|
|
19433
|
+
source: zod.z.string().optional(),
|
|
19434
|
+
asOf: zod.z.string().optional()
|
|
19435
|
+
});
|
|
19436
|
+
/**
|
|
19437
|
+
* Zod schema for the fee split facet in the API response.
|
|
19438
|
+
*
|
|
19439
|
+
* @internal
|
|
19440
|
+
*/ const feeInfoSchema = zod.z.object({
|
|
19441
|
+
performance: zod.z.number().nullable(),
|
|
19442
|
+
management: zod.z.number().nullable()
|
|
19443
|
+
});
|
|
19444
|
+
/**
|
|
19445
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
19446
|
+
*
|
|
19447
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
19448
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
19449
|
+
*
|
|
19450
|
+
* @internal
|
|
19451
|
+
*/ const liquidityProfileSchema = zod.z.object({
|
|
19452
|
+
totalDeposits: amountJsonSchema,
|
|
19453
|
+
available: amountJsonSchema,
|
|
19454
|
+
totalSupply: amountJsonSchema,
|
|
19455
|
+
status: zod.z.enum([
|
|
19456
|
+
'active',
|
|
19457
|
+
'low_liquidity'
|
|
19458
|
+
])
|
|
19459
|
+
});
|
|
19460
|
+
/**
|
|
19461
|
+
* Zod schema for the risk signals facet in the API response.
|
|
19462
|
+
*
|
|
19463
|
+
* @internal
|
|
19464
|
+
*/ const riskSignalsSchema = zod.z.object({
|
|
19465
|
+
circleSentinel: zod.z.boolean(),
|
|
19466
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
19467
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
19468
|
+
});
|
|
19469
|
+
/**
|
|
19470
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
19471
|
+
*
|
|
19472
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
19473
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
19474
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
19475
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
19476
|
+
* backend; they become required after Expand ships.
|
|
18989
19477
|
*
|
|
18990
19478
|
* @internal
|
|
18991
19479
|
*/ const vaultInfoResponseSchema = zod.z.object({
|
|
@@ -19010,6 +19498,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
19010
19498
|
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
19011
19499
|
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
19012
19500
|
});
|
|
19501
|
+
/**
|
|
19502
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
19503
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
19504
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
19505
|
+
*
|
|
19506
|
+
* @internal
|
|
19507
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
19508
|
+
address: zod.z.string().optional(),
|
|
19509
|
+
asOf: zod.z.string().optional(),
|
|
19510
|
+
manager: managerSchema.nullable().optional(),
|
|
19511
|
+
apyProfile: apyProfileSchema.optional(),
|
|
19512
|
+
fee: feeInfoSchema.optional(),
|
|
19513
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
19514
|
+
riskSignals: riskSignalsSchema.optional()
|
|
19515
|
+
});
|
|
19516
|
+
/**
|
|
19517
|
+
* Zod schema for the `vault` opportunity variant.
|
|
19518
|
+
*
|
|
19519
|
+
* @internal
|
|
19520
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
19521
|
+
productType: zod.z.literal('vault'),
|
|
19522
|
+
collateral: zod.z.array(collateralSchema)
|
|
19523
|
+
});
|
|
19524
|
+
/**
|
|
19525
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
19526
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
19527
|
+
*
|
|
19528
|
+
* @internal
|
|
19529
|
+
*/ const earnOpportunityVariants = [
|
|
19530
|
+
vaultOpportunitySchema
|
|
19531
|
+
];
|
|
19532
|
+
/** @internal */ const earnOpportunitySchema = zod.z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
19533
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
19534
|
+
/**
|
|
19535
|
+
* Tolerant list parser for earn opportunities.
|
|
19536
|
+
*
|
|
19537
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
19538
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
19539
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
19540
|
+
*
|
|
19541
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
19542
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
19543
|
+
* rather than dropping every vault the backend returns.
|
|
19544
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
19545
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
19546
|
+
* of rejecting the whole list.
|
|
19547
|
+
*
|
|
19548
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
19549
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
19550
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
19551
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
19552
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
19553
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
19554
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
19555
|
+
* `ZodError`).
|
|
19556
|
+
*
|
|
19557
|
+
* @internal
|
|
19558
|
+
*/ const earnOpportunityListSchema = zod.z.preprocess((raw)=>{
|
|
19559
|
+
if (!Array.isArray(raw)) {
|
|
19560
|
+
return raw;
|
|
19561
|
+
}
|
|
19562
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
19563
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
19564
|
+
const entries = raw;
|
|
19565
|
+
return entries.map((entry)=>{
|
|
19566
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
19567
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19568
|
+
return entry;
|
|
19569
|
+
}
|
|
19570
|
+
const record = entry;
|
|
19571
|
+
// Older backend predating productType: default to the only type then.
|
|
19572
|
+
return record.productType === undefined ? {
|
|
19573
|
+
...record,
|
|
19574
|
+
productType: 'vault'
|
|
19575
|
+
} : record;
|
|
19576
|
+
}).filter((entry)=>{
|
|
19577
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
19578
|
+
// productType this SDK version doesn't know). Everything else —
|
|
19579
|
+
// non-objects, a non-string productType — flows through to
|
|
19580
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
19581
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
19582
|
+
return true;
|
|
19583
|
+
}
|
|
19584
|
+
const productType = entry.productType;
|
|
19585
|
+
if (typeof productType !== 'string') {
|
|
19586
|
+
return true;
|
|
19587
|
+
}
|
|
19588
|
+
return knownProductTypes.has(productType);
|
|
19589
|
+
});
|
|
19590
|
+
}, zod.z.array(earnOpportunitySchema));
|
|
19013
19591
|
// ---------------------------------------------------------------------------
|
|
19014
19592
|
// Position response schema
|
|
19015
19593
|
// ---------------------------------------------------------------------------
|
|
@@ -19139,6 +19717,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
|
19139
19717
|
*
|
|
19140
19718
|
* @internal
|
|
19141
19719
|
*/ const depositPayloadSchema = zod.z.object({
|
|
19720
|
+
execId: bridgeDepositExecIdSchema,
|
|
19142
19721
|
executionParams: depositExecutionParamsSchema,
|
|
19143
19722
|
signature: hexSignatureSchema
|
|
19144
19723
|
});
|
|
@@ -19230,6 +19809,21 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19230
19809
|
amount: amountJsonSchema,
|
|
19231
19810
|
vaultAddress: hexAddressSchema
|
|
19232
19811
|
}).passthrough();
|
|
19812
|
+
/** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
|
|
19813
|
+
zod.z.object({
|
|
19814
|
+
mode: zod.z.literal('TIMESTAMP'),
|
|
19815
|
+
expiresAt: zod.z.string().datetime({
|
|
19816
|
+
offset: true
|
|
19817
|
+
})
|
|
19818
|
+
}),
|
|
19819
|
+
zod.z.object({
|
|
19820
|
+
mode: zod.z.literal('BLOCK_NUMBER'),
|
|
19821
|
+
expiresAtBlock: zod.z.number().int(),
|
|
19822
|
+
blockEstimatedAt: zod.z.string().datetime({
|
|
19823
|
+
offset: true
|
|
19824
|
+
}).optional()
|
|
19825
|
+
})
|
|
19826
|
+
]).optional().catch(undefined);
|
|
19233
19827
|
/**
|
|
19234
19828
|
* Zod schema for the bridge deposit prepare payload.
|
|
19235
19829
|
*
|
|
@@ -19241,6 +19835,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19241
19835
|
execId: bridgeDepositExecIdSchema,
|
|
19242
19836
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
19243
19837
|
expiresAt: zod.z.string().datetime(),
|
|
19838
|
+
quoteIssuedAt: zod.z.string().datetime({
|
|
19839
|
+
offset: true
|
|
19840
|
+
}).optional().catch(undefined),
|
|
19841
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
19244
19842
|
review: bridgeDepositPrepareReviewSchema
|
|
19245
19843
|
});
|
|
19246
19844
|
/**
|
|
@@ -19306,6 +19904,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19306
19904
|
*
|
|
19307
19905
|
* @internal
|
|
19308
19906
|
*/ const withdrawPayloadSchema = zod.z.object({
|
|
19907
|
+
execId: bridgeDepositExecIdSchema,
|
|
19309
19908
|
executionParams: withdrawExecutionParamsSchema,
|
|
19310
19909
|
signature: hexSignatureSchema
|
|
19311
19910
|
});
|
|
@@ -19319,6 +19918,27 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19319
19918
|
data: withdrawPayloadSchema
|
|
19320
19919
|
});
|
|
19321
19920
|
// ---------------------------------------------------------------------------
|
|
19921
|
+
// Transaction report response schema
|
|
19922
|
+
// ---------------------------------------------------------------------------
|
|
19923
|
+
/**
|
|
19924
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
19925
|
+
*
|
|
19926
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
19927
|
+
* schema accepts any object shape and does not require specific fields.
|
|
19928
|
+
*
|
|
19929
|
+
* @internal
|
|
19930
|
+
*/ const transactionReportPayloadSchema = zod.z.object({}).passthrough();
|
|
19931
|
+
/**
|
|
19932
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
19933
|
+
*
|
|
19934
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
19935
|
+
* envelope.
|
|
19936
|
+
*
|
|
19937
|
+
* @internal
|
|
19938
|
+
*/ zod.z.object({
|
|
19939
|
+
data: transactionReportPayloadSchema
|
|
19940
|
+
});
|
|
19941
|
+
// ---------------------------------------------------------------------------
|
|
19322
19942
|
// Claim rewards response schema
|
|
19323
19943
|
// ---------------------------------------------------------------------------
|
|
19324
19944
|
/**
|
|
@@ -19379,6 +19999,30 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19379
19999
|
token: zod.z.string(),
|
|
19380
20000
|
amount: amountJsonSchema
|
|
19381
20001
|
});
|
|
20002
|
+
/**
|
|
20003
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
20004
|
+
*
|
|
20005
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
20006
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
20007
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
20008
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
20009
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
20010
|
+
*
|
|
20011
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
20012
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
20013
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
20014
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
20015
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
20016
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
20017
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
20018
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
20019
|
+
*
|
|
20020
|
+
* @internal
|
|
20021
|
+
*/ const quoteGasFeeSchema = zod.z.object({
|
|
20022
|
+
name: zod.z.string().optional(),
|
|
20023
|
+
fees: zod.z.unknown(),
|
|
20024
|
+
error: zod.z.string().optional()
|
|
20025
|
+
}).passthrough();
|
|
19382
20026
|
/**
|
|
19383
20027
|
* Zod schema for the inner deposit quote payload.
|
|
19384
20028
|
*
|
|
@@ -19394,7 +20038,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19394
20038
|
expectedShares: amountJsonSchema,
|
|
19395
20039
|
sharePrice: zod.z.string(),
|
|
19396
20040
|
currentApy: zod.z.number(),
|
|
19397
|
-
fees: zod.z.array(feeSchema).optional()
|
|
20041
|
+
fees: zod.z.array(feeSchema).optional(),
|
|
20042
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional()
|
|
19398
20043
|
});
|
|
19399
20044
|
/**
|
|
19400
20045
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -19421,6 +20066,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19421
20066
|
sharePrice: zod.z.string(),
|
|
19422
20067
|
maxWithdrawable: amountJsonSchema,
|
|
19423
20068
|
fees: zod.z.array(feeSchema),
|
|
20069
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional(),
|
|
19424
20070
|
warnings: zod.z.array(zod.z.string()).optional()
|
|
19425
20071
|
});
|
|
19426
20072
|
/**
|
|
@@ -19478,7 +20124,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19478
20124
|
*
|
|
19479
20125
|
* @internal
|
|
19480
20126
|
*/ const getVaultsPayloadSchema = zod.z.object({
|
|
19481
|
-
vaults:
|
|
20127
|
+
vaults: earnOpportunityListSchema,
|
|
19482
20128
|
errors: zod.z.array(vaultErrorSchema)
|
|
19483
20129
|
});
|
|
19484
20130
|
/**
|
|
@@ -19508,7 +20154,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
19508
20154
|
*
|
|
19509
20155
|
* @internal
|
|
19510
20156
|
*/ const exploreVaultsPayloadSchema = zod.z.object({
|
|
19511
|
-
vaults:
|
|
20157
|
+
vaults: earnOpportunityListSchema,
|
|
19512
20158
|
pagination: explorePaginationSchema
|
|
19513
20159
|
});
|
|
19514
20160
|
/**
|
|
@@ -20076,6 +20722,8 @@ function hasCrossChainDepositQuoteShape(params) {
|
|
|
20076
20722
|
config: earnConfigSchema.optional()
|
|
20077
20723
|
});
|
|
20078
20724
|
|
|
20725
|
+
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg.name);
|
|
20726
|
+
|
|
20079
20727
|
// Auto-register this kit for user agent tracking
|
|
20080
20728
|
registerKit(`${pkg.name}/${pkg.version}`);
|
|
20081
20729
|
|