@circle-fin/app-kit 1.17.0 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/borrow.cjs +6 -6
- package/borrow.d.cts +3 -3
- package/borrow.d.mts +3 -3
- package/borrow.d.ts +3 -3
- package/borrow.mjs +6 -6
- package/bridge.cjs +272 -18
- package/bridge.d.cts +3 -3
- package/bridge.d.mts +3 -3
- package/bridge.d.ts +3 -3
- package/bridge.mjs +272 -18
- package/chains.cjs +2 -2
- package/chains.d.cts +1 -1
- package/chains.d.mts +1 -1
- package/chains.d.ts +1 -1
- package/chains.mjs +2 -2
- package/context.d.cts +3 -3
- package/context.d.mts +3 -3
- package/context.d.ts +3 -3
- package/earn.cjs +365 -14
- package/earn.d.cts +3 -3
- package/earn.d.mts +3 -3
- package/earn.d.ts +3 -3
- package/earn.mjs +365 -14
- package/estimateBridge.cjs +272 -18
- package/estimateBridge.d.cts +3 -3
- package/estimateBridge.d.mts +3 -3
- package/estimateBridge.d.ts +3 -3
- package/estimateBridge.mjs +272 -18
- package/estimateSwap.cjs +6 -6
- package/estimateSwap.d.cts +3 -3
- package/estimateSwap.d.mts +3 -3
- package/estimateSwap.d.ts +3 -3
- package/estimateSwap.mjs +6 -6
- package/index.cjs +558 -27
- package/index.d.cts +42 -8
- package/index.d.mts +42 -8
- package/index.d.ts +42 -8
- package/index.mjs +558 -27
- package/package.json +8 -8
- package/server.cjs +3 -3
- package/server.mjs +3 -3
- package/swap.cjs +6 -6
- package/swap.d.cts +3 -3
- package/swap.d.mts +3 -3
- package/swap.d.ts +3 -3
- package/swap.mjs +6 -6
- package/unifiedBalance.cjs +68 -10
- package/unifiedBalance.mjs +68 -10
package/index.mjs
CHANGED
|
@@ -4741,6 +4741,15 @@ let activeRedactor = defaultMessageRedactor;
|
|
|
4741
4741
|
recoverability: 'RETRYABLE'
|
|
4742
4742
|
}
|
|
4743
4743
|
],
|
|
4744
|
+
// DEPOSIT_INTENT_INVALID: the Veda deposit intent is missing, expired, or
|
|
4745
|
+
// not signed by the depositing wallet.
|
|
4746
|
+
[
|
|
4747
|
+
380418,
|
|
4748
|
+
{
|
|
4749
|
+
errorDef: EarnError.SIGNATURE_REJECTED,
|
|
4750
|
+
recoverability: 'FATAL'
|
|
4751
|
+
}
|
|
4752
|
+
],
|
|
4744
4753
|
// Bridge (380_5XX)
|
|
4745
4754
|
[
|
|
4746
4755
|
380500,
|
|
@@ -6349,14 +6358,14 @@ var BorrowChain;
|
|
|
6349
6358
|
symbol: 'USDC',
|
|
6350
6359
|
// Arc uses native USDC with 18 decimals for gas payments (EVM standard).
|
|
6351
6360
|
// Note: The ERC-20 USDC contract at usdcAddress uses 6 decimals.
|
|
6352
|
-
// See: https://docs.arc.
|
|
6361
|
+
// See: https://docs.arc.io/arc/references/contract-addresses
|
|
6353
6362
|
decimals: 18
|
|
6354
6363
|
},
|
|
6355
6364
|
chainId: 5042002,
|
|
6356
6365
|
isTestnet: true,
|
|
6357
6366
|
explorerUrl: 'https://testnet.arcscan.app/tx/{hash}',
|
|
6358
6367
|
rpcEndpoints: [
|
|
6359
|
-
'https://rpc.testnet.arc.
|
|
6368
|
+
'https://rpc.testnet.arc.io'
|
|
6360
6369
|
],
|
|
6361
6370
|
eurcAddress: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
6362
6371
|
usdcAddress: '0x3600000000000000000000000000000000000000',
|
|
@@ -14674,7 +14683,7 @@ function resolveOptions(options) {
|
|
|
14674
14683
|
}
|
|
14675
14684
|
|
|
14676
14685
|
var name$5 = "@circle-fin/bridge-kit";
|
|
14677
|
-
var version$6 = "1.
|
|
14686
|
+
var version$6 = "1.16.0";
|
|
14678
14687
|
var pkg$6 = {
|
|
14679
14688
|
name: name$5,
|
|
14680
14689
|
version: version$6};
|
|
@@ -16396,6 +16405,53 @@ const EURC_MAINNET_TOKEN_ID = '0x6ca9e29fa53becc29becaf4a90b9ca7a995ad4d2234880d
|
|
|
16396
16405
|
}
|
|
16397
16406
|
};
|
|
16398
16407
|
|
|
16408
|
+
/**
|
|
16409
|
+
* Map a CCTPx bytes32 token id back to its known display symbol.
|
|
16410
|
+
*
|
|
16411
|
+
* The inverse of the provider's internal symbol -> id resolution: a bridge
|
|
16412
|
+
* resolves a symbol such as `'cirBTC'` to its canonical bytes32 id and reports
|
|
16413
|
+
* that id on `result.token`, dropping the symbol. This helper recovers the
|
|
16414
|
+
* symbol for display. It is scoped to {@link KNOWN_TOKEN_SYMBOLS} — the same
|
|
16415
|
+
* known set the forward resolution covers — and is keyed by network, because a
|
|
16416
|
+
* symbol names a separate registration on each network, whose ids are
|
|
16417
|
+
* unrelated.
|
|
16418
|
+
*
|
|
16419
|
+
* The lookup is best-effort by design: an arbitrary registry token, a
|
|
16420
|
+
* non-canonical bridge of a known symbol, or any unrecognized id has no known
|
|
16421
|
+
* symbol and yields `undefined`. The id is matched case-insensitively (bytes32
|
|
16422
|
+
* ids have no checksum casing).
|
|
16423
|
+
*
|
|
16424
|
+
* @param id - The bytes32 token id to decode (e.g. a `result.token` value).
|
|
16425
|
+
* @param network - The network the id belongs to (`'testnet'` or `'mainnet'`);
|
|
16426
|
+
* derive it from the source chain, e.g. `chain.isTestnet ? 'testnet' :
|
|
16427
|
+
* 'mainnet'`.
|
|
16428
|
+
* @returns The matching {@link KnownTokenSymbol}, or `undefined` when `id` is
|
|
16429
|
+
* not one of the known canonical ids for `network`.
|
|
16430
|
+
* @throws A `KitError` (`INPUT_VALIDATION_FAILED`, FATAL) when `id` is not a
|
|
16431
|
+
* string or `network` is not a recognized network.
|
|
16432
|
+
*
|
|
16433
|
+
* @example
|
|
16434
|
+
* ```typescript
|
|
16435
|
+
* import { resolveToKnownTokenSymbol } from '@circle-fin/provider-cctpx'
|
|
16436
|
+
*
|
|
16437
|
+
* const result = await provider.bridge(params) // params.token === 'cirBTC'
|
|
16438
|
+
* const network = result.source.chain.isTestnet ? 'testnet' : 'mainnet'
|
|
16439
|
+
*
|
|
16440
|
+
* resolveToKnownTokenSymbol(result.token, network) // 'cirBTC'
|
|
16441
|
+
* resolveToKnownTokenSymbol('0xdeadbeef…', network) // undefined (not known)
|
|
16442
|
+
* ```
|
|
16443
|
+
*/ function resolveToKnownTokenSymbol(id, network) {
|
|
16444
|
+
if (typeof id !== 'string') {
|
|
16445
|
+
throw createValidationFailedError$1('id', id, 'must be a string');
|
|
16446
|
+
}
|
|
16447
|
+
if (network !== 'testnet' && network !== 'mainnet') {
|
|
16448
|
+
throw createValidationFailedError$1('network', network, "must be 'testnet' or 'mainnet'");
|
|
16449
|
+
}
|
|
16450
|
+
const row = KNOWN_TOKEN_IDS_BY_NETWORK[network];
|
|
16451
|
+
const target = id.toLowerCase();
|
|
16452
|
+
return KNOWN_TOKEN_SYMBOLS.find((symbol)=>row[symbol].toLowerCase() === target);
|
|
16453
|
+
}
|
|
16454
|
+
|
|
16399
16455
|
/**
|
|
16400
16456
|
* Default clock implementation.
|
|
16401
16457
|
*
|
|
@@ -23619,6 +23675,24 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
23619
23675
|
}
|
|
23620
23676
|
};
|
|
23621
23677
|
|
|
23678
|
+
/**
|
|
23679
|
+
* Check whether a forwarded burn to the given destination asks Circle's
|
|
23680
|
+
* Forwarding Service to set up the recipient's token account before minting.
|
|
23681
|
+
*
|
|
23682
|
+
* Must return `true` exactly for the destinations where
|
|
23683
|
+
* {@link getForwarderHookData} emits the `createAta` frame, so the forwarding
|
|
23684
|
+
* fee quote includes the setup rent whenever the burn requests it.
|
|
23685
|
+
*
|
|
23686
|
+
* @internal
|
|
23687
|
+
* @param chainType - The destination blockchain type.
|
|
23688
|
+
* @returns `true` for Solana destinations, `false` otherwise.
|
|
23689
|
+
*
|
|
23690
|
+
* @example
|
|
23691
|
+
* ```typescript
|
|
23692
|
+
* requiresRecipientSetup('solana') // true
|
|
23693
|
+
* requiresRecipientSetup('evm') // false
|
|
23694
|
+
* ```
|
|
23695
|
+
*/ const requiresRecipientSetup = (chainType)=>chainType === 'solana';
|
|
23622
23696
|
/**
|
|
23623
23697
|
* Build the forwarding `hookData` for a forwarded (Orbit-relayed) CCTP v2 burn,
|
|
23624
23698
|
* tailored to the destination chain.
|
|
@@ -23969,10 +24043,12 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
23969
24043
|
* @param sourceDomain - The source domain
|
|
23970
24044
|
* @param destinationDomain - The destination domain
|
|
23971
24045
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
24046
|
+
* @param includeRecipientSetup - Whether the quote includes recipient account setup rent
|
|
23972
24047
|
* @returns The complete API URL with forward=true query parameter
|
|
23973
|
-
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet) {
|
|
24048
|
+
*/ function buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup) {
|
|
23974
24049
|
const baseUrl = isTestnet ? IRIS_API_SANDBOX_BASE_URL$1 : IRIS_API_BASE_URL$1;
|
|
23975
|
-
|
|
24050
|
+
const recipientSetupQuery = includeRecipientSetup ? '&includeRecipientSetup=true' : '';
|
|
24051
|
+
return `${baseUrl}/v2/burn/USDC/fees/${sourceDomain.toString()}/${destinationDomain.toString()}?forward=true${recipientSetupQuery}`;
|
|
23976
24052
|
}
|
|
23977
24053
|
/**
|
|
23978
24054
|
* Fetches the forwarding fee for a USDC transfer operation with retry and timeout handling.
|
|
@@ -23989,6 +24065,10 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
23989
24065
|
*
|
|
23990
24066
|
* The high fee tier is always used to provide buffer for destination gas fluctuations.
|
|
23991
24067
|
*
|
|
24068
|
+
* Pass `includeRecipientSetup: true` when the burn asks the Forwarding Service to create
|
|
24069
|
+
* the recipient's token account (Solana destinations). The quote then includes the
|
|
24070
|
+
* account rent, which the quote without this flag leaves out.
|
|
24071
|
+
*
|
|
23992
24072
|
* Implements timeout and retry logic to handle network issues and temporary API failures.
|
|
23993
24073
|
* Each HTTP request is given a maximum of 2 seconds before it is aborted.
|
|
23994
24074
|
* We retry up to 10 times, waiting 200ms between attempts.
|
|
@@ -23997,6 +24077,8 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
23997
24077
|
* @param destinationDomain - The destination domain
|
|
23998
24078
|
* @param isTestnet - Whether the request is for a testnet chain
|
|
23999
24079
|
* @param finalityThreshold - The finality threshold to select the fee tier (1000 for FAST, 2000 for SLOW)
|
|
24080
|
+
* @param includeRecipientSetup - Whether to include recipient account setup rent in the
|
|
24081
|
+
* quote. Defaults to `false`.
|
|
24000
24082
|
* @returns The high-tier forwarding fee in USDC minor units (6 decimals)
|
|
24001
24083
|
* @throws Error if the input domains are invalid, the API request fails, returns invalid data, or network errors occur
|
|
24002
24084
|
*
|
|
@@ -24008,8 +24090,11 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
24008
24090
|
*
|
|
24009
24091
|
* // SLOW transfer - use 2000ms finality threshold
|
|
24010
24092
|
* const slowForwardingFee = await fetchForwardingFee(0, 6, false, 2000)
|
|
24093
|
+
*
|
|
24094
|
+
* // Ethereum -> Solana: include the recipient token account rent
|
|
24095
|
+
* const solanaForwardingFee = await fetchForwardingFee(0, 5, false, 1000, true)
|
|
24011
24096
|
* ```
|
|
24012
|
-
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold) {
|
|
24097
|
+
*/ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, finalityThreshold, includeRecipientSetup = false) {
|
|
24013
24098
|
// Validate source domain
|
|
24014
24099
|
if (!Number.isInteger(sourceDomain) || sourceDomain < 0) {
|
|
24015
24100
|
throw new KitError({
|
|
@@ -24037,7 +24122,7 @@ const FAST_TIER_FINALITY_THRESHOLD = 1000;
|
|
|
24037
24122
|
});
|
|
24038
24123
|
}
|
|
24039
24124
|
// Fetch the fee tiers from the API with forward=true
|
|
24040
|
-
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
|
|
24125
|
+
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet, includeRecipientSetup);
|
|
24041
24126
|
const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$4);
|
|
24042
24127
|
// Validate that we have at least one fee tier
|
|
24043
24128
|
if (response.length === 0) {
|
|
@@ -26373,7 +26458,7 @@ const mockAttestationMessage = {
|
|
|
26373
26458
|
return step;
|
|
26374
26459
|
}
|
|
26375
26460
|
|
|
26376
|
-
var version$5 = "1.14.
|
|
26461
|
+
var version$5 = "1.14.3";
|
|
26377
26462
|
var pkg$5 = {
|
|
26378
26463
|
version: version$5};
|
|
26379
26464
|
|
|
@@ -27292,9 +27377,34 @@ function assertCCTPV2Config(config) {
|
|
|
27292
27377
|
tokenAddress: source.chain.usdcAddress,
|
|
27293
27378
|
operationContext: sourceOperationContext
|
|
27294
27379
|
});
|
|
27380
|
+
await this.assertAmountCoversRecipientSetupFee(params);
|
|
27295
27381
|
return bridge$1(params, this);
|
|
27296
27382
|
}
|
|
27297
27383
|
/**
|
|
27384
|
+
* Reject a forwarded transfer to Solana whose amount does not exceed the fee.
|
|
27385
|
+
*
|
|
27386
|
+
* CCTP v2 reverts a burn whose `maxFee` is not less than its amount, and the Solana
|
|
27387
|
+
* forwarding fee includes the recipient token account rent. Checking before the
|
|
27388
|
+
* approval avoids sending a transaction that can never be followed by a burn.
|
|
27389
|
+
* Skipped when the caller provides `config.maxFee`.
|
|
27390
|
+
*
|
|
27391
|
+
* @param params - The validated CCTP v2 bridge parameters.
|
|
27392
|
+
* @returns A promise that resolves when the amount covers the fee.
|
|
27393
|
+
* @throws {KitError} INPUT_INVALID_AMOUNT (FATAL) when the fee is greater than or equal
|
|
27394
|
+
* to the amount.
|
|
27395
|
+
*/ async assertAmountCoversRecipientSetupFee(params) {
|
|
27396
|
+
const { destination, amount, config } = params;
|
|
27397
|
+
if (destination.useForwarder !== true || config.maxFee !== undefined || !requiresRecipientSetup(destination.chain.type)) {
|
|
27398
|
+
return;
|
|
27399
|
+
}
|
|
27400
|
+
const { providerFee, forwarderFee } = await this.getMaxFee(params);
|
|
27401
|
+
const maxFee = providerFee + forwarderFee;
|
|
27402
|
+
if (maxFee >= BigInt(amount)) {
|
|
27403
|
+
// Amounts and fees are in USDC minor units (6 decimals)
|
|
27404
|
+
throw createInvalidAmountError(formatUnits(amount, 6), `Amount must be greater than the ${formatUnits(String(maxFee), 6)} USDC fee for forwarded transfers to ${destination.chain.name}, which includes creating the recipient's token account`);
|
|
27405
|
+
}
|
|
27406
|
+
}
|
|
27407
|
+
/**
|
|
27298
27408
|
* Retry a failed or incomplete CCTP v2 bridge operation.
|
|
27299
27409
|
*
|
|
27300
27410
|
* Analyzes the bridge result to determine where to continue and executes
|
|
@@ -28011,6 +28121,9 @@ function assertCCTPV2Config(config) {
|
|
|
28011
28121
|
* | FAST | true | No | maxFee = calculatedBurnFee + forwardingFee |
|
|
28012
28122
|
* | FAST | true | Yes | maxFee = config.maxFee |
|
|
28013
28123
|
*
|
|
28124
|
+
* For forwarded burns to Solana, the forwarding fee includes the rent for creating the
|
|
28125
|
+
* recipient's token account. A caller-provided `maxFee` must cover it too.
|
|
28126
|
+
*
|
|
28014
28127
|
* @param params - The bridge parameters object containing:
|
|
28015
28128
|
* - `source`: The source wallet context with chain definition and adapter
|
|
28016
28129
|
* - `destination`: The destination wallet context with chain definition and adapter
|
|
@@ -28049,6 +28162,7 @@ function assertCCTPV2Config(config) {
|
|
|
28049
28162
|
}
|
|
28050
28163
|
// Get the min finality threshold based on the transfer speed
|
|
28051
28164
|
const minFinalityThreshold = CCTPv2MinFinalityThreshold[transferSpeed];
|
|
28165
|
+
const includeRecipientSetup = requiresRecipientSetup(destination.chain.type);
|
|
28052
28166
|
// SLOW transfer without forwarder: no fee
|
|
28053
28167
|
if (transferSpeed === TransferSpeed.SLOW && !useForwarder) {
|
|
28054
28168
|
return {
|
|
@@ -28058,7 +28172,7 @@ function assertCCTPV2Config(config) {
|
|
|
28058
28172
|
}
|
|
28059
28173
|
// SLOW transfer with forwarder: only forwarding fee
|
|
28060
28174
|
if (transferSpeed === TransferSpeed.SLOW && useForwarder) {
|
|
28061
|
-
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold);
|
|
28175
|
+
const forwarderFee = await fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup);
|
|
28062
28176
|
return {
|
|
28063
28177
|
providerFee: 0n,
|
|
28064
28178
|
forwarderFee
|
|
@@ -28068,7 +28182,7 @@ function assertCCTPV2Config(config) {
|
|
|
28068
28182
|
// Fetch fees in parallel when forwarder is enabled
|
|
28069
28183
|
const [scaledBps, forwarderFee] = await Promise.all([
|
|
28070
28184
|
fetchUsdcFastBurnFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet),
|
|
28071
|
-
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold) : Promise.resolve(0n)
|
|
28185
|
+
useForwarder ? fetchForwardingFee(source.chain.cctp.domain, destination.chain.cctp.domain, source.chain.isTestnet, minFinalityThreshold, includeRecipientSetup) : Promise.resolve(0n)
|
|
28072
28186
|
]);
|
|
28073
28187
|
// Calculate fee proportional to the transfer amount
|
|
28074
28188
|
const amountInMinorUnits = BigInt(amount);
|
|
@@ -28618,6 +28732,21 @@ function assertCCTPV2Config(config) {
|
|
|
28618
28732
|
'bridge_forward'
|
|
28619
28733
|
]
|
|
28620
28734
|
];
|
|
28735
|
+
/**
|
|
28736
|
+
* Provider step names whose `txHash` is the source-chain transaction that
|
|
28737
|
+
* moves funds into the bridge protocol.
|
|
28738
|
+
*
|
|
28739
|
+
* @remarks
|
|
28740
|
+
* The success event carries this hash so the backend can join it to the
|
|
28741
|
+
* on-chain CCTP / CCTPx event for the same transfer. `burn` is the CCTP v2
|
|
28742
|
+
* step (including batched and source-fee flows); `transfer` is the CCTPx
|
|
28743
|
+
* `CrossChainTokenService` step.
|
|
28744
|
+
*
|
|
28745
|
+
* @internal
|
|
28746
|
+
*/ const BRIDGE_SOURCE_TX_STEP_NAMES = [
|
|
28747
|
+
'burn',
|
|
28748
|
+
'transfer'
|
|
28749
|
+
];
|
|
28621
28750
|
|
|
28622
28751
|
/**
|
|
28623
28752
|
* Base URL for Circle's Quote API (hosted in Iris) on mainnet/production.
|
|
@@ -29713,6 +29842,85 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29713
29842
|
}
|
|
29714
29843
|
return undefined;
|
|
29715
29844
|
}
|
|
29845
|
+
/**
|
|
29846
|
+
* Pick the source-chain transaction hash from a bridge result.
|
|
29847
|
+
*
|
|
29848
|
+
* Walk the steps from the end and return the hash of the most recent
|
|
29849
|
+
* successful source step (`burn` for CCTP v2, `transfer` for CCTPx). Walking
|
|
29850
|
+
* backwards selects the attempt that landed when a retry appended a new
|
|
29851
|
+
* source step after a failed one.
|
|
29852
|
+
*
|
|
29853
|
+
* @param steps - All steps from the bridge result.
|
|
29854
|
+
* @returns The source transaction hash, or `undefined` if no source step recorded one.
|
|
29855
|
+
*
|
|
29856
|
+
* @internal
|
|
29857
|
+
*/ function pickSourceTxHash(steps) {
|
|
29858
|
+
for(let i = steps.length - 1; i >= 0; i--){
|
|
29859
|
+
const step = steps[i];
|
|
29860
|
+
if (step?.txHash != null && step.state === 'success' && BRIDGE_SOURCE_TX_STEP_NAMES.includes(step.name)) {
|
|
29861
|
+
return step.txHash;
|
|
29862
|
+
}
|
|
29863
|
+
}
|
|
29864
|
+
return undefined;
|
|
29865
|
+
}
|
|
29866
|
+
/**
|
|
29867
|
+
* Resolve the token value reported in telemetry.
|
|
29868
|
+
*
|
|
29869
|
+
* CCTPx reports `result.token` as a bytes32 token id, while the backend's
|
|
29870
|
+
* canonical tables key tokens by symbol. Map the canonical id of a known CCTPx
|
|
29871
|
+
* token back to its symbol and pass any other value (USDC, or a registry token
|
|
29872
|
+
* without a known symbol) through unchanged. Registry symbols are not used
|
|
29873
|
+
* because they are not unique across CCTPx tokens. Never throws.
|
|
29874
|
+
*
|
|
29875
|
+
* @param token - The token from a bridge result.
|
|
29876
|
+
* @param sourceChain - The result's source chain; selects testnet or mainnet ids.
|
|
29877
|
+
* @returns The known symbol, or `token` unchanged.
|
|
29878
|
+
*
|
|
29879
|
+
* @internal
|
|
29880
|
+
*/ function toTelemetryToken(token, sourceChain) {
|
|
29881
|
+
try {
|
|
29882
|
+
const network = sourceChain.isTestnet ? 'testnet' : 'mainnet';
|
|
29883
|
+
return resolveToKnownTokenSymbol(token, network) ?? token;
|
|
29884
|
+
} catch {
|
|
29885
|
+
return token;
|
|
29886
|
+
}
|
|
29887
|
+
}
|
|
29888
|
+
/**
|
|
29889
|
+
* Emit the `bridge_bridge` success event for a completed transfer.
|
|
29890
|
+
*
|
|
29891
|
+
* No-ops unless `result.state` is `'success'`. Failed results are already
|
|
29892
|
+
* reported by error telemetry. Never throws: a malformed result (for example
|
|
29893
|
+
* from a custom provider) is reported as a telemetry drop warning and the
|
|
29894
|
+
* caller's result is returned unchanged.
|
|
29895
|
+
*
|
|
29896
|
+
* @param result - The human-readable bridge result returned to the caller.
|
|
29897
|
+
* @param config - Analytics telemetry identity, gated by `disableAnalytics`.
|
|
29898
|
+
*
|
|
29899
|
+
* @internal
|
|
29900
|
+
*/ function emitBridgeSuccessTelemetry(result, config) {
|
|
29901
|
+
if (config.disabled || result.state !== 'success') {
|
|
29902
|
+
return;
|
|
29903
|
+
}
|
|
29904
|
+
try {
|
|
29905
|
+
const txHash = pickSourceTxHash(result.steps);
|
|
29906
|
+
// `JSON.stringify` turns a non-finite number into `null`, which the logs
|
|
29907
|
+
// endpoint's strict schema rejects along with the whole event.
|
|
29908
|
+
const amountIn = Number.parseFloat(result.amount);
|
|
29909
|
+
emitSuccessTelemetry(BRIDGE_EVENT_TYPES.BRIDGE, config, {
|
|
29910
|
+
sourceChain: result.source.chain.chain,
|
|
29911
|
+
destinationChain: result.destination.chain.chain,
|
|
29912
|
+
tokenIn: toTelemetryToken(result.token, result.source.chain),
|
|
29913
|
+
...Number.isFinite(amountIn) && {
|
|
29914
|
+
amountIn
|
|
29915
|
+
},
|
|
29916
|
+
...txHash != null && {
|
|
29917
|
+
txHash
|
|
29918
|
+
}
|
|
29919
|
+
});
|
|
29920
|
+
} catch (telemetryError) {
|
|
29921
|
+
warnTelemetryDrop(BRIDGE_EVENT_TYPES.BRIDGE, telemetryError);
|
|
29922
|
+
}
|
|
29923
|
+
}
|
|
29716
29924
|
/**
|
|
29717
29925
|
* BridgeKit caller component for retry and estimate operations.
|
|
29718
29926
|
*/ const BRIDGE_KIT_CALLER = {
|
|
@@ -29843,6 +30051,10 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29843
30051
|
/** Whether error telemetry is disabled. */ disableErrorReporting;
|
|
29844
30052
|
/** Per-kit telemetry identity for shared helpers. */ telemetryConfig;
|
|
29845
30053
|
/**
|
|
30054
|
+
* Per-kit telemetry identity for success events. Gated by `disableAnalytics`
|
|
30055
|
+
* independently of `disableErrorReporting`.
|
|
30056
|
+
*/ analyticsTelemetryConfig;
|
|
30057
|
+
/**
|
|
29846
30058
|
* Create a new BridgeKit instance.
|
|
29847
30059
|
*
|
|
29848
30060
|
* @param config - The configuration containing the CCTPv2 provider
|
|
@@ -29869,6 +30081,11 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29869
30081
|
sdkVersion: pkg$6.version,
|
|
29870
30082
|
disabled: this.disableErrorReporting
|
|
29871
30083
|
};
|
|
30084
|
+
this.analyticsTelemetryConfig = {
|
|
30085
|
+
sdkName: SDK_NAME$4,
|
|
30086
|
+
sdkVersion: pkg$6.version,
|
|
30087
|
+
disabled: config.disableAnalytics === true
|
|
30088
|
+
};
|
|
29872
30089
|
for (const provider of this.providers){
|
|
29873
30090
|
provider.registerDispatcher(this.actionDispatcher);
|
|
29874
30091
|
}
|
|
@@ -29882,7 +30099,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29882
30099
|
this.actionDispatcher.off(actionOrWildCard, handler);
|
|
29883
30100
|
}
|
|
29884
30101
|
async bridge(params) {
|
|
29885
|
-
|
|
30102
|
+
const bridgeResult = await withErrorTelemetry(async ()=>{
|
|
29886
30103
|
// First validate the parameters
|
|
29887
30104
|
assertBridgeParams(params, bridgeParamsWithChainIdentifierSchema);
|
|
29888
30105
|
// Then resolve chain definitions (includes adapter chain support validation)
|
|
@@ -29919,7 +30136,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29919
30136
|
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.BRIDGE, this.telemetryConfig, {
|
|
29920
30137
|
sourceChain: resolveChainName(params.from.chain),
|
|
29921
30138
|
destinationChain: resolveChainName(params.to.chain),
|
|
29922
|
-
tokenIn:
|
|
30139
|
+
tokenIn: toTelemetryToken(result.token, result.source.chain),
|
|
29923
30140
|
...txHash != null && {
|
|
29924
30141
|
txHash
|
|
29925
30142
|
}
|
|
@@ -29931,6 +30148,8 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
29931
30148
|
destinationChain: resolveChainName(params.to.chain),
|
|
29932
30149
|
tokenIn: params.token
|
|
29933
30150
|
});
|
|
30151
|
+
emitBridgeSuccessTelemetry(bridgeResult, this.analyticsTelemetryConfig);
|
|
30152
|
+
return bridgeResult;
|
|
29934
30153
|
}
|
|
29935
30154
|
/**
|
|
29936
30155
|
* Retry a failed or incomplete cross-chain USDC bridge operation.
|
|
@@ -30001,7 +30220,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
30001
30220
|
* )
|
|
30002
30221
|
* ```
|
|
30003
30222
|
*/ async retry(result, context, invocationMeta) {
|
|
30004
|
-
|
|
30223
|
+
const retriedResult = await withErrorTelemetry(async ()=>{
|
|
30005
30224
|
// Cast the providers list to the wide view here. The tuple
|
|
30006
30225
|
// type on `this.providers` retains concrete provider types
|
|
30007
30226
|
// (CCTPv2 narrows `TToken` to `'USDC'`); calling `.retry`
|
|
@@ -30029,7 +30248,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
30029
30248
|
emitResultStepErrorTelemetry(failedStep, BRIDGE_STEP_EVENT_MAP, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
30030
30249
|
sourceChain: result.source.chain.chain,
|
|
30031
30250
|
destinationChain: result.destination.chain.chain,
|
|
30032
|
-
tokenIn: result.token,
|
|
30251
|
+
tokenIn: toTelemetryToken(result.token, result.source.chain),
|
|
30033
30252
|
...txHash != null && {
|
|
30034
30253
|
txHash
|
|
30035
30254
|
}
|
|
@@ -30043,8 +30262,16 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
30043
30262
|
}, BRIDGE_EVENT_TYPES.RETRY, this.telemetryConfig, {
|
|
30044
30263
|
sourceChain: result.source.chain.chain,
|
|
30045
30264
|
destinationChain: result.destination.chain.chain,
|
|
30046
|
-
tokenIn: result.token
|
|
30265
|
+
tokenIn: toTelemetryToken(result.token, result.source.chain)
|
|
30047
30266
|
});
|
|
30267
|
+
// A retry that completes the transfer is the transfer's only success
|
|
30268
|
+
// event, so it reports the same `bridge_bridge` type as `bridge()`. An
|
|
30269
|
+
// input that already succeeded was reported by the call that completed it
|
|
30270
|
+
// (CCTP v2 returns such a result unchanged), so it is not reported again.
|
|
30271
|
+
if (result.state !== 'success') {
|
|
30272
|
+
emitBridgeSuccessTelemetry(retriedResult, this.analyticsTelemetryConfig);
|
|
30273
|
+
}
|
|
30274
|
+
return retriedResult;
|
|
30048
30275
|
}
|
|
30049
30276
|
async estimate(params) {
|
|
30050
30277
|
return withErrorTelemetry(async ()=>{
|
|
@@ -30593,7 +30820,7 @@ async function resolveExecutionQuote(binding, suppliedQuote, refundAddress) {
|
|
|
30593
30820
|
registerKit(`${pkg$6.name}/${pkg$6.version}`);
|
|
30594
30821
|
|
|
30595
30822
|
var name$4 = "@circle-fin/swap-kit";
|
|
30596
|
-
var version$4 = "1.8.
|
|
30823
|
+
var version$4 = "1.8.1";
|
|
30597
30824
|
var pkg$4 = {
|
|
30598
30825
|
name: name$4,
|
|
30599
30826
|
version: version$4};
|
|
@@ -46827,6 +47054,9 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
|
|
|
46827
47054
|
...context.disableErrorReporting != null && {
|
|
46828
47055
|
disableErrorReporting: context.disableErrorReporting
|
|
46829
47056
|
},
|
|
47057
|
+
...context.disableAnalytics != null && {
|
|
47058
|
+
disableAnalytics: context.disableAnalytics
|
|
47059
|
+
},
|
|
46830
47060
|
...context.headers != null && {
|
|
46831
47061
|
headers: context.headers
|
|
46832
47062
|
}
|
|
@@ -46947,7 +47177,7 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
|
|
|
46947
47177
|
};
|
|
46948
47178
|
|
|
46949
47179
|
var name$3 = "@circle-fin/earn-kit";
|
|
46950
|
-
var version$3 = "1.
|
|
47180
|
+
var version$3 = "1.10.0";
|
|
46951
47181
|
var pkg$3 = {
|
|
46952
47182
|
name: name$3,
|
|
46953
47183
|
version: version$3};
|
|
@@ -47054,6 +47284,61 @@ const EARN_BRIDGE_USDC_ERC3009_DOMAINS = {
|
|
|
47054
47284
|
*
|
|
47055
47285
|
* @internal
|
|
47056
47286
|
*/ const EARN_BRIDGE_MAX_VALIDITY_SECONDS = 86_400n;
|
|
47287
|
+
/**
|
|
47288
|
+
* Static fields of the EIP-712 domain for the `DepositIntent` typed-data
|
|
47289
|
+
* intent. `chainId` is excluded here — it must come from the deposit's
|
|
47290
|
+
* actual chain (see {@link buildDepositIntentTypedData}), since a mismatched
|
|
47291
|
+
* `chainId` in the domain separator would make every intent signature
|
|
47292
|
+
* invalid.
|
|
47293
|
+
*
|
|
47294
|
+
* `verifyingContract` is intentionally omitted — the intent is verified
|
|
47295
|
+
* off-chain by the Earn Service, not by a deployed contract.
|
|
47296
|
+
*
|
|
47297
|
+
* @internal
|
|
47298
|
+
*/ const DEPOSIT_INTENT_DOMAIN = {
|
|
47299
|
+
name: 'Circle EarnKit',
|
|
47300
|
+
version: '1'
|
|
47301
|
+
};
|
|
47302
|
+
/**
|
|
47303
|
+
* EIP-712 type definition for the `DepositIntent` struct.
|
|
47304
|
+
*
|
|
47305
|
+
* @internal
|
|
47306
|
+
*/ const DEPOSIT_INTENT_TYPES = {
|
|
47307
|
+
DepositIntent: [
|
|
47308
|
+
{
|
|
47309
|
+
name: 'wallet',
|
|
47310
|
+
type: 'address'
|
|
47311
|
+
},
|
|
47312
|
+
{
|
|
47313
|
+
name: 'vault',
|
|
47314
|
+
type: 'address'
|
|
47315
|
+
},
|
|
47316
|
+
{
|
|
47317
|
+
name: 'amount',
|
|
47318
|
+
type: 'uint256'
|
|
47319
|
+
},
|
|
47320
|
+
{
|
|
47321
|
+
name: 'deadline',
|
|
47322
|
+
type: 'uint256'
|
|
47323
|
+
}
|
|
47324
|
+
]
|
|
47325
|
+
};
|
|
47326
|
+
/**
|
|
47327
|
+
* Lifetime of a `DepositIntent` signature, in seconds.
|
|
47328
|
+
*
|
|
47329
|
+
* The Earn Service rejects a deadline more than 300 seconds ahead of its own
|
|
47330
|
+
* clock. 240 seconds leaves room for clock skew between the client and the
|
|
47331
|
+
* service while still covering the deposit request that follows the
|
|
47332
|
+
* signature.
|
|
47333
|
+
*
|
|
47334
|
+
* @internal
|
|
47335
|
+
*/ const DEPOSIT_INTENT_TTL_SECONDS = 240;
|
|
47336
|
+
/**
|
|
47337
|
+
* Protocol value the Earn Service reports for Veda vaults. A deposit into a
|
|
47338
|
+
* Veda vault needs a signed `DepositIntent`.
|
|
47339
|
+
*
|
|
47340
|
+
* @internal
|
|
47341
|
+
*/ const VEDA_PROTOCOL = 'veda';
|
|
47057
47342
|
/**
|
|
47058
47343
|
* Display symbol for vault share tokens.
|
|
47059
47344
|
*
|
|
@@ -49929,7 +50214,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
49929
50214
|
}
|
|
49930
50215
|
|
|
49931
50216
|
var name$2 = "@circle-fin/provider-earn-service";
|
|
49932
|
-
var version$2 = "1.
|
|
50217
|
+
var version$2 = "1.8.0";
|
|
49933
50218
|
var pkg$2 = {
|
|
49934
50219
|
name: name$2,
|
|
49935
50220
|
version: version$2};
|
|
@@ -50281,8 +50566,9 @@ function toPositionInfo(data) {
|
|
|
50281
50566
|
* Build signed deposit instructions via the Earn Service API.
|
|
50282
50567
|
*
|
|
50283
50568
|
* Call `POST /v1/earnKit/deposit` with the vault address, amount,
|
|
50284
|
-
* wallet address, and chain
|
|
50285
|
-
* parameters for on-chain
|
|
50569
|
+
* wallet address, and chain, plus the signed `DepositIntent` when one is
|
|
50570
|
+
* given. Return EIP-712 signed execution parameters for on-chain
|
|
50571
|
+
* submission.
|
|
50286
50572
|
*
|
|
50287
50573
|
* @param params - Deposit parameters
|
|
50288
50574
|
* @returns Signed execution parameters for the deposit
|
|
@@ -50296,7 +50582,8 @@ function toPositionInfo(data) {
|
|
|
50296
50582
|
vaultAddress: params.vaultAddress,
|
|
50297
50583
|
amount: params.amount,
|
|
50298
50584
|
address: params.address,
|
|
50299
|
-
chain: params.chain
|
|
50585
|
+
chain: params.chain,
|
|
50586
|
+
...params.intent
|
|
50300
50587
|
};
|
|
50301
50588
|
try {
|
|
50302
50589
|
const response = await pollApiPost(url.toString(), requestBody, isDepositResponse, pollingConfig);
|
|
@@ -50308,6 +50595,232 @@ function toPositionInfo(data) {
|
|
|
50308
50595
|
}
|
|
50309
50596
|
}
|
|
50310
50597
|
|
|
50598
|
+
/**
|
|
50599
|
+
* Build the version-1 EarnKit `DepositIntent` EIP-712 typed data.
|
|
50600
|
+
*
|
|
50601
|
+
* The signed struct binds the depositing `wallet`, the target `vault`, the
|
|
50602
|
+
* deposit `amount` in the asset's smallest unit, and a signature `deadline`.
|
|
50603
|
+
* The Earn Service rebuilds the same struct from the deposit request and
|
|
50604
|
+
* rejects the deposit unless `wallet` signed it. The domain intentionally
|
|
50605
|
+
* omits `verifyingContract` because the service verifies the signature
|
|
50606
|
+
* off-chain.
|
|
50607
|
+
*
|
|
50608
|
+
* `domain.chainId` comes from the deposit's chain rather than a constant: the
|
|
50609
|
+
* domain separator must match what the service rebuilds, and a wrong
|
|
50610
|
+
* `chainId` would make every intent signature invalid.
|
|
50611
|
+
*
|
|
50612
|
+
* This function returns the fully-typed {@link DepositIntentTypedData} with
|
|
50613
|
+
* no assertion. {@link resolveDepositIntent} casts it to the adapter's
|
|
50614
|
+
* generic `EIP712Domain` shape only where it calls `adapter.signTypedData`,
|
|
50615
|
+
* since that shared interface always requires `verifyingContract`. The
|
|
50616
|
+
* adapter's runtime `eip712DomainSchema` treats `verifyingContract` as
|
|
50617
|
+
* optional, so the cast is safe at runtime. BorrowKit's
|
|
50618
|
+
* `buildWebhookRegistrationTypedData` works around the same gap.
|
|
50619
|
+
*
|
|
50620
|
+
* @param params - Wallet, vault, base-unit amount, deadline, and chain id.
|
|
50621
|
+
* @returns EIP-712 typed data ready to be cast for `adapter.signTypedData`.
|
|
50622
|
+
*
|
|
50623
|
+
* @example
|
|
50624
|
+
* ```typescript
|
|
50625
|
+
* const typedData = buildDepositIntentTypedData({
|
|
50626
|
+
* wallet: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
|
|
50627
|
+
* vault: '0x00000000000000000000000000000000000000a1',
|
|
50628
|
+
* amount: 100_000_000n,
|
|
50629
|
+
* deadline: 1_700_000_000n,
|
|
50630
|
+
* chainId: 5_042_002,
|
|
50631
|
+
* })
|
|
50632
|
+
* ```
|
|
50633
|
+
*
|
|
50634
|
+
* @internal
|
|
50635
|
+
*/ function buildDepositIntentTypedData(params) {
|
|
50636
|
+
return {
|
|
50637
|
+
domain: {
|
|
50638
|
+
...DEPOSIT_INTENT_DOMAIN,
|
|
50639
|
+
chainId: params.chainId
|
|
50640
|
+
},
|
|
50641
|
+
types: DEPOSIT_INTENT_TYPES,
|
|
50642
|
+
primaryType: 'DepositIntent',
|
|
50643
|
+
message: {
|
|
50644
|
+
wallet: params.wallet,
|
|
50645
|
+
vault: params.vault,
|
|
50646
|
+
amount: params.amount,
|
|
50647
|
+
deadline: params.deadline
|
|
50648
|
+
}
|
|
50649
|
+
};
|
|
50650
|
+
}
|
|
50651
|
+
/**
|
|
50652
|
+
* Earn Service error code for a missing, expired, or wrongly signed
|
|
50653
|
+
* `DepositIntent` (`DEPOSIT_INTENT_INVALID`).
|
|
50654
|
+
*/ const DEPOSIT_INTENT_INVALID_CODE = 380418;
|
|
50655
|
+
/**
|
|
50656
|
+
* Sign a `DepositIntent` when the target vault needs one.
|
|
50657
|
+
*
|
|
50658
|
+
* A Veda vault mints shares straight to the depositing wallet, so the Earn
|
|
50659
|
+
* Service only builds a Veda deposit for a wallet that signed a
|
|
50660
|
+
* `DepositIntent` for the same vault and amount. The vault lookup exists only
|
|
50661
|
+
* to find out whether the vault is a Veda vault (and its asset decimals, to
|
|
50662
|
+
* sign the amount). Other vaults ignore the intent, so this returns no intent
|
|
50663
|
+
* for them and the wallet sees no extra signature prompt. A vault the service
|
|
50664
|
+
* does not return is also treated as not needing an intent; the deposit call
|
|
50665
|
+
* then reports why.
|
|
50666
|
+
*
|
|
50667
|
+
* A failed vault lookup does not stop the deposit: this returns the lookup
|
|
50668
|
+
* error with no intent, so a non-Veda deposit works as before. A Veda deposit
|
|
50669
|
+
* then gets `DEPOSIT_INTENT_INVALID` from the service, and
|
|
50670
|
+
* {@link resolveDepositError} reports the lookup error instead. The lookup
|
|
50671
|
+
* fails either by throwing or by returning the vault in its `errors` list (for
|
|
50672
|
+
* example `VAULT_REFRESH_BUSY`); both are kept the same way.
|
|
50673
|
+
*
|
|
50674
|
+
* @param params - Adapter, resolved chain, wallet, vault, human-readable
|
|
50675
|
+
* amount, and service config.
|
|
50676
|
+
* @returns The signed intent when the vault needs one, and the lookup error
|
|
50677
|
+
* when the vault lookup failed.
|
|
50678
|
+
* @throws {@link KitError} `InputError.VALIDATION_FAILED` when the vault needs
|
|
50679
|
+
* an intent but the chain is not EVM, the adapter cannot sign typed data, or
|
|
50680
|
+
* the amount has more decimal places than the vault asset.
|
|
50681
|
+
*
|
|
50682
|
+
* @example
|
|
50683
|
+
* ```typescript
|
|
50684
|
+
* const { intent } = await resolveDepositIntent({
|
|
50685
|
+
* adapter,
|
|
50686
|
+
* chain: ArcTestnet,
|
|
50687
|
+
* address: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
|
|
50688
|
+
* vaultAddress: '0x00000000000000000000000000000000000000a1',
|
|
50689
|
+
* amount: '100',
|
|
50690
|
+
* config,
|
|
50691
|
+
* })
|
|
50692
|
+
* // intent -> { intentSignature: '0x…', intentDeadline: 1700000240 }
|
|
50693
|
+
* ```
|
|
50694
|
+
*
|
|
50695
|
+
* @internal
|
|
50696
|
+
*/ async function resolveDepositIntent(params) {
|
|
50697
|
+
let lookup;
|
|
50698
|
+
try {
|
|
50699
|
+
lookup = await fetchVaults({
|
|
50700
|
+
// `resolveAdapterContext` already rejected chains the Earn Service does
|
|
50701
|
+
// not support, so the chain is an Earn chain here.
|
|
50702
|
+
vaults: [
|
|
50703
|
+
{
|
|
50704
|
+
chain: params.chain,
|
|
50705
|
+
vaultAddress: params.vaultAddress
|
|
50706
|
+
}
|
|
50707
|
+
],
|
|
50708
|
+
config: params.config
|
|
50709
|
+
});
|
|
50710
|
+
} catch (lookupError) {
|
|
50711
|
+
return {
|
|
50712
|
+
lookupError
|
|
50713
|
+
};
|
|
50714
|
+
}
|
|
50715
|
+
const vaultError = lookup.errors.find((candidate)=>isSameAddress(candidate.vaultAddress, params.vaultAddress));
|
|
50716
|
+
if (vaultError !== undefined) {
|
|
50717
|
+
// Same handling as a thrown lookup error, mapped with the Earn Service
|
|
50718
|
+
// error table so it keeps its recoverability (VAULT_REFRESH_BUSY retries).
|
|
50719
|
+
return {
|
|
50720
|
+
lookupError: parseEarnApiError({
|
|
50721
|
+
responseBody: {
|
|
50722
|
+
code: vaultError.code,
|
|
50723
|
+
message: vaultError.message
|
|
50724
|
+
}
|
|
50725
|
+
}, {
|
|
50726
|
+
operation: 'getVaults'
|
|
50727
|
+
})
|
|
50728
|
+
};
|
|
50729
|
+
}
|
|
50730
|
+
const vault = lookup.vaults.find((candidate)=>isSameAddress(candidate.address, params.vaultAddress));
|
|
50731
|
+
if (vault?.protocol.toLowerCase() !== VEDA_PROTOCOL) {
|
|
50732
|
+
return {};
|
|
50733
|
+
}
|
|
50734
|
+
if (params.chain.type !== 'evm') {
|
|
50735
|
+
throw createValidationFailedError$1('from.chain', params.chain.chain, 'Veda vault deposits need an EVM chain to sign the deposit intent');
|
|
50736
|
+
}
|
|
50737
|
+
if (!canSignTypedData(params.adapter)) {
|
|
50738
|
+
throw createValidationFailedError$1('from.adapter', params.adapter, 'adapter must support signTypedData for Veda vault deposits');
|
|
50739
|
+
}
|
|
50740
|
+
const wallet = assertHexAddress('from.address', params.address, 'Depositor address must be a 0x-prefixed 20-byte hex address.');
|
|
50741
|
+
const assetDecimals = vault.liquidityProfile.totalDeposits.decimals;
|
|
50742
|
+
// Amount.parse truncates extra digits, but the service rejects them. Fail
|
|
50743
|
+
// before the wallet prompt instead of asking to sign a deposit that cannot
|
|
50744
|
+
// go through.
|
|
50745
|
+
assertDecimalPlaces('amount', params.amount, assetDecimals, `amount must have at most ${String(assetDecimals)} decimal places for the vault asset`);
|
|
50746
|
+
const deadline = Math.floor(Date.now() / 1000) + DEPOSIT_INTENT_TTL_SECONDS;
|
|
50747
|
+
const typedData = buildDepositIntentTypedData({
|
|
50748
|
+
wallet,
|
|
50749
|
+
vault: params.vaultAddress,
|
|
50750
|
+
amount: Amount.parse(params.amount, {
|
|
50751
|
+
decimals: assetDecimals
|
|
50752
|
+
}).raw,
|
|
50753
|
+
deadline: BigInt(deadline),
|
|
50754
|
+
chainId: params.chain.chainId
|
|
50755
|
+
});
|
|
50756
|
+
// `typedData.domain` intentionally omits `verifyingContract` (the Earn
|
|
50757
|
+
// Service verifies off-chain), but the shared `signTypedData` signature
|
|
50758
|
+
// requires the standard `EIP712Domain` shape. The adapter's runtime
|
|
50759
|
+
// `eip712DomainSchema` treats `verifyingContract` as optional, so this cast
|
|
50760
|
+
// is safe at runtime.
|
|
50761
|
+
const intentSignature = await params.adapter.signTypedData(typedData, {
|
|
50762
|
+
chain: params.chain,
|
|
50763
|
+
address: wallet
|
|
50764
|
+
});
|
|
50765
|
+
return {
|
|
50766
|
+
intent: {
|
|
50767
|
+
intentSignature,
|
|
50768
|
+
intentDeadline: deadline
|
|
50769
|
+
}
|
|
50770
|
+
};
|
|
50771
|
+
}
|
|
50772
|
+
/**
|
|
50773
|
+
* Pick the error to report for a failed deposit request.
|
|
50774
|
+
*
|
|
50775
|
+
* When the vault lookup failed, the SDK sent the deposit without an intent.
|
|
50776
|
+
* If the service then answers `DEPOSIT_INTENT_INVALID`, the vault is a Veda
|
|
50777
|
+
* vault and the real cause is the failed lookup, not a bad signature. Report
|
|
50778
|
+
* the lookup error, which keeps its own recoverability (often retryable),
|
|
50779
|
+
* instead of a fatal signature rejection.
|
|
50780
|
+
*
|
|
50781
|
+
* When the SDK did send an intent and the service still answers
|
|
50782
|
+
* `DEPOSIT_INTENT_INVALID`, the error stays a fatal signature rejection, but
|
|
50783
|
+
* its message adds that the intent may have expired: the deadline starts
|
|
50784
|
+
* before the wallet prompt, so a slow signer can submit an expired intent.
|
|
50785
|
+
* Calling `deposit()` again signs a new one. Every other error is reported as
|
|
50786
|
+
* is.
|
|
50787
|
+
*
|
|
50788
|
+
* @param resolution - The result of {@link resolveDepositIntent}.
|
|
50789
|
+
* @param error - The error from the deposit request.
|
|
50790
|
+
* @returns The error to throw.
|
|
50791
|
+
*
|
|
50792
|
+
* @example
|
|
50793
|
+
* ```typescript
|
|
50794
|
+
* try {
|
|
50795
|
+
* return await fetchDeposit({ ...params, intent: resolution.intent })
|
|
50796
|
+
* } catch (error) {
|
|
50797
|
+
* throw resolveDepositError(resolution, error)
|
|
50798
|
+
* }
|
|
50799
|
+
* ```
|
|
50800
|
+
*
|
|
50801
|
+
* @internal
|
|
50802
|
+
*/ function resolveDepositError(resolution, error) {
|
|
50803
|
+
if (resolution.lookupError !== undefined && isKitError(error) && isEarnServiceCode(error.cause?.trace, DEPOSIT_INTENT_INVALID_CODE)) {
|
|
50804
|
+
return resolution.lookupError;
|
|
50805
|
+
}
|
|
50806
|
+
if (resolution.intent !== undefined && isKitError(error) && isEarnServiceCode(error.cause?.trace, DEPOSIT_INTENT_INVALID_CODE)) {
|
|
50807
|
+
return new KitError({
|
|
50808
|
+
code: error.code,
|
|
50809
|
+
name: error.name,
|
|
50810
|
+
type: error.type,
|
|
50811
|
+
recoverability: error.recoverability,
|
|
50812
|
+
message: `${error.message} The deposit intent may have expired before the deposit was submitted (it is valid for ${String(DEPOSIT_INTENT_TTL_SECONDS)} seconds from when the SDK asks the wallet to sign). Call deposit() again to sign a new intent.`,
|
|
50813
|
+
...error.cause !== undefined && {
|
|
50814
|
+
cause: error.cause
|
|
50815
|
+
}
|
|
50816
|
+
});
|
|
50817
|
+
}
|
|
50818
|
+
return error;
|
|
50819
|
+
}
|
|
50820
|
+
function isEarnServiceCode(trace, code) {
|
|
50821
|
+
return typeof trace === 'object' && trace !== null && 'earnServiceCode' in trace && trace.earnServiceCode === code;
|
|
50822
|
+
}
|
|
50823
|
+
|
|
50311
50824
|
/**
|
|
50312
50825
|
* Build cross-chain deposit instructions via the bridge API.
|
|
50313
50826
|
*
|
|
@@ -51546,13 +52059,31 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
51546
52059
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
51547
52060
|
const { adapter } = params.from;
|
|
51548
52061
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
51549
|
-
const { execId, executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>
|
|
52062
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>{
|
|
52063
|
+
// Veda vaults mint shares straight to `address`, so the service
|
|
52064
|
+
// needs proof that `address` asked for this deposit. Sign it here,
|
|
52065
|
+
// inside fetchParams, so a rejected prompt fails this phase.
|
|
52066
|
+
const resolution = await resolveDepositIntent({
|
|
52067
|
+
adapter,
|
|
52068
|
+
chain,
|
|
52069
|
+
address,
|
|
51550
52070
|
vaultAddress,
|
|
51551
52071
|
amount: params.amount,
|
|
51552
|
-
address,
|
|
51553
|
-
chain: apiChain,
|
|
51554
52072
|
config
|
|
51555
|
-
})
|
|
52073
|
+
});
|
|
52074
|
+
try {
|
|
52075
|
+
return await fetchDeposit({
|
|
52076
|
+
vaultAddress,
|
|
52077
|
+
amount: params.amount,
|
|
52078
|
+
address,
|
|
52079
|
+
chain: apiChain,
|
|
52080
|
+
intent: resolution.intent,
|
|
52081
|
+
config
|
|
52082
|
+
});
|
|
52083
|
+
} catch (error) {
|
|
52084
|
+
throw resolveDepositError(resolution, error);
|
|
52085
|
+
}
|
|
52086
|
+
}, ()=>undefined);
|
|
51556
52087
|
validateExecutionDeadline$1(executionParams);
|
|
51557
52088
|
const transactionReportContext = {
|
|
51558
52089
|
execId,
|
|
@@ -54559,7 +55090,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
54559
55090
|
};
|
|
54560
55091
|
|
|
54561
55092
|
var name$1 = "@circle-fin/borrow-kit";
|
|
54562
|
-
var version$1 = "1.1.
|
|
55093
|
+
var version$1 = "1.1.1";
|
|
54563
55094
|
var pkg$1 = {
|
|
54564
55095
|
name: name$1,
|
|
54565
55096
|
version: version$1};
|
|
@@ -67468,7 +67999,7 @@ async function deposit$2(context, params) {
|
|
|
67468
67999
|
}
|
|
67469
68000
|
|
|
67470
68001
|
var name = "@circle-fin/unified-balance-kit";
|
|
67471
|
-
var version = "1.8.
|
|
68002
|
+
var version = "1.8.2";
|
|
67472
68003
|
var pkg = {
|
|
67473
68004
|
name: name,
|
|
67474
68005
|
version: version};
|