@circle-fin/app-kit 1.8.0 → 1.9.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 +53 -0
- package/README.md +3 -3
- package/bridge.cjs +469 -231
- package/bridge.d.cts +16 -2
- package/bridge.d.mts +16 -2
- package/bridge.d.ts +16 -2
- package/bridge.mjs +469 -231
- package/chains.cjs +94 -0
- package/chains.d.cts +2 -0
- package/chains.d.mts +2 -0
- package/chains.d.ts +2 -0
- package/chains.mjs +94 -0
- package/context.d.cts +16 -2
- package/context.d.mts +16 -2
- package/context.d.ts +16 -2
- package/earn.cjs +438 -208
- package/earn.d.cts +33 -13
- package/earn.d.mts +33 -13
- package/earn.d.ts +33 -13
- package/earn.mjs +438 -208
- package/estimateBridge.cjs +469 -231
- package/estimateBridge.d.cts +16 -2
- package/estimateBridge.d.mts +16 -2
- package/estimateBridge.d.ts +16 -2
- package/estimateBridge.mjs +469 -231
- package/estimateSwap.cjs +210 -87
- package/estimateSwap.d.cts +16 -2
- package/estimateSwap.d.mts +16 -2
- package/estimateSwap.d.ts +16 -2
- package/estimateSwap.mjs +210 -87
- package/index.cjs +884 -413
- package/index.d.cts +284 -27
- package/index.d.mts +284 -27
- package/index.d.ts +284 -27
- package/index.mjs +884 -413
- package/package.json +12 -6
- package/swap.cjs +210 -87
- package/swap.d.cts +16 -2
- package/swap.d.mts +16 -2
- package/swap.d.ts +16 -2
- package/swap.mjs +210 -87
- package/unifiedBalance.cjs +119 -5
- package/unifiedBalance.d.cts +2 -0
- package/unifiedBalance.d.mts +2 -0
- package/unifiedBalance.d.ts +2 -0
- package/unifiedBalance.mjs +119 -5
package/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ var units = require('@ethersproject/units');
|
|
|
24
24
|
var bytes = require('@ethersproject/bytes');
|
|
25
25
|
var address = require('@ethersproject/address');
|
|
26
26
|
var bs58 = require('bs58');
|
|
27
|
+
require('@ethersproject/abi');
|
|
27
28
|
var web3_js = require('@solana/web3.js');
|
|
28
29
|
require('bn.js');
|
|
29
30
|
require('@coral-xyz/anchor');
|
|
@@ -3558,7 +3559,7 @@ class KitError extends Error {
|
|
|
3558
3559
|
*
|
|
3559
3560
|
* Error code ranges:
|
|
3560
3561
|
* - 1100-1105: INPUT errors — invalid inputs, unsupported configurations
|
|
3561
|
-
* - 8100-
|
|
3562
|
+
* - 8100-8105: SERVICE errors — retryable backend/provider failures
|
|
3562
3563
|
*
|
|
3563
3564
|
* @example
|
|
3564
3565
|
* ```typescript
|
|
@@ -3634,6 +3635,11 @@ class KitError extends Error {
|
|
|
3634
3635
|
code: 8104,
|
|
3635
3636
|
name: 'EARN_PAUSED',
|
|
3636
3637
|
type: 'SERVICE'
|
|
3638
|
+
},
|
|
3639
|
+
/** Position PnL is still reconciling and can be retried. */ POSITION_PNL_PENDING: {
|
|
3640
|
+
code: 8105,
|
|
3641
|
+
name: 'EARN_POSITION_PNL_PENDING',
|
|
3642
|
+
type: 'SERVICE'
|
|
3637
3643
|
}
|
|
3638
3644
|
};
|
|
3639
3645
|
|
|
@@ -3657,11 +3663,11 @@ function getOptionalString(value) {
|
|
|
3657
3663
|
* - vault-not-found, unsupported-chain, unsupported-vault,
|
|
3658
3664
|
* signature-rejected, invalid-id, invalid-batch-size, position-not-registered,
|
|
3659
3665
|
* withdrawal-max-exceeded, insufficient-balance, bridge prepare idempotency
|
|
3660
|
-
* conflicts
|
|
3666
|
+
* conflicts, invalid vault-asset amount precision
|
|
3661
3667
|
*
|
|
3662
3668
|
* SERVICE errors (RETRYABLE) — try again later:
|
|
3663
3669
|
* - signing-failed, provider-error, rewards-fetch-failed,
|
|
3664
|
-
* internal-error, vault-refresh-busy, off-chain-paused,
|
|
3670
|
+
* internal-error, vault-refresh-busy, off-chain-paused, position-PnL-pending,
|
|
3665
3671
|
* bridge failures/status lookup failures
|
|
3666
3672
|
*
|
|
3667
3673
|
* Unrecognized codes fall through to `parseApiError` for HTTP-status-based
|
|
@@ -3841,6 +3847,20 @@ function getOptionalString(value) {
|
|
|
3841
3847
|
recoverability: 'RETRYABLE'
|
|
3842
3848
|
}
|
|
3843
3849
|
],
|
|
3850
|
+
[
|
|
3851
|
+
380415,
|
|
3852
|
+
{
|
|
3853
|
+
errorDef: EarnError.INVALID_INPUT,
|
|
3854
|
+
recoverability: 'FATAL'
|
|
3855
|
+
}
|
|
3856
|
+
],
|
|
3857
|
+
[
|
|
3858
|
+
380416,
|
|
3859
|
+
{
|
|
3860
|
+
errorDef: EarnError.POSITION_PNL_PENDING,
|
|
3861
|
+
recoverability: 'RETRYABLE'
|
|
3862
|
+
}
|
|
3863
|
+
],
|
|
3844
3864
|
// Bridge (380_5XX)
|
|
3845
3865
|
[
|
|
3846
3866
|
380500,
|
|
@@ -3876,6 +3896,13 @@ function getOptionalString(value) {
|
|
|
3876
3896
|
errorDef: EarnError.PROVIDER_ERROR,
|
|
3877
3897
|
recoverability: 'RETRYABLE'
|
|
3878
3898
|
}
|
|
3899
|
+
],
|
|
3900
|
+
[
|
|
3901
|
+
380505,
|
|
3902
|
+
{
|
|
3903
|
+
errorDef: EarnError.PROVIDER_ERROR,
|
|
3904
|
+
recoverability: 'FATAL'
|
|
3905
|
+
}
|
|
3879
3906
|
]
|
|
3880
3907
|
]);
|
|
3881
3908
|
/**
|
|
@@ -3978,6 +4005,8 @@ function getOptionalString(value) {
|
|
|
3978
4005
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
3979
4006
|
Blockchain["Codex"] = "Codex";
|
|
3980
4007
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
4008
|
+
Blockchain["Cronos"] = "Cronos";
|
|
4009
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
3981
4010
|
Blockchain["Edge"] = "Edge";
|
|
3982
4011
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
3983
4012
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -4060,6 +4089,7 @@ exports.BridgeChain = void 0;
|
|
|
4060
4089
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
4061
4090
|
BridgeChain["Base"] = "Base";
|
|
4062
4091
|
BridgeChain["Codex"] = "Codex";
|
|
4092
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
4063
4093
|
BridgeChain["Edge"] = "Edge";
|
|
4064
4094
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
4065
4095
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -4084,6 +4114,7 @@ exports.BridgeChain = void 0;
|
|
|
4084
4114
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
4085
4115
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
4086
4116
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
4117
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
4087
4118
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
4088
4119
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
4089
4120
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -4335,23 +4366,6 @@ exports.EarnChain = void 0;
|
|
|
4335
4366
|
}
|
|
4336
4367
|
});
|
|
4337
4368
|
|
|
4338
|
-
/**
|
|
4339
|
-
* Standard decimal places for tokens.
|
|
4340
|
-
*
|
|
4341
|
-
* These constants define the decimal precision used by different token types
|
|
4342
|
-
* across the SDK. They are used for amount conversions between human-readable
|
|
4343
|
-
* format and smallest units (base units).
|
|
4344
|
-
*
|
|
4345
|
-
* @remarks
|
|
4346
|
-
* - Most stablecoins (USDC, EURC, USDT, PYUSD) use 6 decimal places
|
|
4347
|
-
* - Some stablecoins (DAI, USDE) and most native tokens (ETH, POL, PLUME) use 18 decimals
|
|
4348
|
-
* - The NATIVE alias uses chain-specific decimals which may vary (e.g., SOL uses 9)
|
|
4349
|
-
*/ /**
|
|
4350
|
-
* Standard decimal places for 6-decimal tokens.
|
|
4351
|
-
*
|
|
4352
|
-
* Used by most stablecoins: USDC, EURC, USDT, PYUSD
|
|
4353
|
-
*/ const TOKEN_DECIMALS_6 = 6;
|
|
4354
|
-
|
|
4355
4369
|
/**
|
|
4356
4370
|
* @packageDocumentation
|
|
4357
4371
|
* @module SwapTokenRegistry
|
|
@@ -5167,6 +5181,96 @@ exports.EarnChain = void 0;
|
|
|
5167
5181
|
}
|
|
5168
5182
|
});
|
|
5169
5183
|
|
|
5184
|
+
/**
|
|
5185
|
+
* Cronos Mainnet chain definition
|
|
5186
|
+
* @remarks
|
|
5187
|
+
* This represents the official production network for the Cronos blockchain.
|
|
5188
|
+
* Cronos is an EVM-compatible blockchain.
|
|
5189
|
+
*/ const Cronos = defineChain({
|
|
5190
|
+
type: 'evm',
|
|
5191
|
+
chain: exports.Blockchain.Cronos,
|
|
5192
|
+
name: 'Cronos',
|
|
5193
|
+
title: 'Cronos Mainnet',
|
|
5194
|
+
nativeCurrency: {
|
|
5195
|
+
name: 'Cronos',
|
|
5196
|
+
symbol: 'CRO',
|
|
5197
|
+
decimals: 18
|
|
5198
|
+
},
|
|
5199
|
+
chainId: 25,
|
|
5200
|
+
isTestnet: false,
|
|
5201
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
5202
|
+
rpcEndpoints: [
|
|
5203
|
+
'https://evm.cronos.org'
|
|
5204
|
+
],
|
|
5205
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
5206
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
5207
|
+
usdtAddress: null,
|
|
5208
|
+
cctp: {
|
|
5209
|
+
domain: 32,
|
|
5210
|
+
contracts: {
|
|
5211
|
+
v2: {
|
|
5212
|
+
type: 'split',
|
|
5213
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5214
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5215
|
+
confirmations: 1,
|
|
5216
|
+
fastConfirmations: 1
|
|
5217
|
+
}
|
|
5218
|
+
},
|
|
5219
|
+
forwarderSupported: {
|
|
5220
|
+
source: false,
|
|
5221
|
+
destination: false
|
|
5222
|
+
}
|
|
5223
|
+
},
|
|
5224
|
+
kitContracts: {
|
|
5225
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
5226
|
+
}
|
|
5227
|
+
});
|
|
5228
|
+
|
|
5229
|
+
/**
|
|
5230
|
+
* Cronos Testnet chain definition
|
|
5231
|
+
* @remarks
|
|
5232
|
+
* This represents the official test network for the Cronos blockchain.
|
|
5233
|
+
* Cronos is an EVM-compatible blockchain.
|
|
5234
|
+
*/ const CronosTestnet = defineChain({
|
|
5235
|
+
type: 'evm',
|
|
5236
|
+
chain: exports.Blockchain.Cronos_Testnet,
|
|
5237
|
+
name: 'Cronos Testnet',
|
|
5238
|
+
title: 'Cronos Testnet',
|
|
5239
|
+
nativeCurrency: {
|
|
5240
|
+
name: 'CRO',
|
|
5241
|
+
symbol: 'tCRO',
|
|
5242
|
+
decimals: 18
|
|
5243
|
+
},
|
|
5244
|
+
chainId: 338,
|
|
5245
|
+
isTestnet: true,
|
|
5246
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
5247
|
+
rpcEndpoints: [
|
|
5248
|
+
'https://evm-t3.cronos.org'
|
|
5249
|
+
],
|
|
5250
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
5251
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
5252
|
+
usdtAddress: null,
|
|
5253
|
+
cctp: {
|
|
5254
|
+
domain: 32,
|
|
5255
|
+
contracts: {
|
|
5256
|
+
v2: {
|
|
5257
|
+
type: 'split',
|
|
5258
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5259
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5260
|
+
confirmations: 1,
|
|
5261
|
+
fastConfirmations: 1
|
|
5262
|
+
}
|
|
5263
|
+
},
|
|
5264
|
+
forwarderSupported: {
|
|
5265
|
+
source: false,
|
|
5266
|
+
destination: false
|
|
5267
|
+
}
|
|
5268
|
+
},
|
|
5269
|
+
kitContracts: {
|
|
5270
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
5271
|
+
}
|
|
5272
|
+
});
|
|
5273
|
+
|
|
5170
5274
|
/**
|
|
5171
5275
|
* Edge Mainnet chain definition
|
|
5172
5276
|
* @remarks
|
|
@@ -7518,6 +7622,8 @@ var Chains = {
|
|
|
7518
7622
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
7519
7623
|
Codex: Codex,
|
|
7520
7624
|
CodexTestnet: CodexTestnet,
|
|
7625
|
+
Cronos: Cronos,
|
|
7626
|
+
CronosTestnet: CronosTestnet,
|
|
7521
7627
|
Edge: Edge,
|
|
7522
7628
|
EdgeTestnet: EdgeTestnet,
|
|
7523
7629
|
Ethereum: Ethereum,
|
|
@@ -9892,6 +9998,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
9892
9998
|
[exports.Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
9893
9999
|
[exports.Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
9894
10000
|
[exports.Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
10001
|
+
[exports.Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
9895
10002
|
[exports.Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
9896
10003
|
[exports.Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
9897
10004
|
[exports.Blockchain.Hedera]: '0.0.456858',
|
|
@@ -9925,6 +10032,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
9925
10032
|
[exports.Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
9926
10033
|
[exports.Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
9927
10034
|
[exports.Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
10035
|
+
[exports.Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
9928
10036
|
[exports.Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
9929
10037
|
[exports.Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
9930
10038
|
[exports.Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -9992,13 +10100,22 @@ function parseOrThrow(value, schema, context) {
|
|
|
9992
10100
|
symbol: 'EURC',
|
|
9993
10101
|
decimals: 6,
|
|
9994
10102
|
locators: {
|
|
10103
|
+
// =========================================================================
|
|
10104
|
+
// Mainnets
|
|
10105
|
+
// =========================================================================
|
|
9995
10106
|
[exports.Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
9996
10107
|
[exports.Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
10108
|
+
[exports.Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
9997
10109
|
[exports.Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
9998
10110
|
[exports.Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
9999
10111
|
[exports.Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
10112
|
+
// =========================================================================
|
|
10000
10113
|
// Testnets
|
|
10001
|
-
|
|
10114
|
+
// =========================================================================
|
|
10115
|
+
[exports.Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
10116
|
+
[exports.Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
10117
|
+
[exports.Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
10118
|
+
[exports.Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
10002
10119
|
}
|
|
10003
10120
|
};
|
|
10004
10121
|
|
|
@@ -10208,8 +10325,7 @@ function parseOrThrow(value, schema, context) {
|
|
|
10208
10325
|
* cirBTC (Circle Bitcoin) token definition with addresses and metadata.
|
|
10209
10326
|
*
|
|
10210
10327
|
* @remarks
|
|
10211
|
-
* Built-in cirBTC definition for the TokenRegistry.
|
|
10212
|
-
* on Arc Testnet.
|
|
10328
|
+
* Built-in cirBTC definition for the TokenRegistry.
|
|
10213
10329
|
*
|
|
10214
10330
|
* @example
|
|
10215
10331
|
* ```typescript
|
|
@@ -10225,7 +10341,15 @@ function parseOrThrow(value, schema, context) {
|
|
|
10225
10341
|
symbol: 'cirBTC',
|
|
10226
10342
|
decimals: 8,
|
|
10227
10343
|
locators: {
|
|
10228
|
-
|
|
10344
|
+
// =========================================================================
|
|
10345
|
+
// Mainnets
|
|
10346
|
+
// =========================================================================
|
|
10347
|
+
[exports.Blockchain.Ethereum]: '0x72DFB2E44f59C5AD2bAFE84314E5b99a7cd5075E',
|
|
10348
|
+
// =========================================================================
|
|
10349
|
+
// Testnets
|
|
10350
|
+
// =========================================================================
|
|
10351
|
+
[exports.Blockchain.Arc_Testnet]: '0xf0C4a4CE82A5746AbAAd9425360Ab04fbBA432BF',
|
|
10352
|
+
[exports.Blockchain.Ethereum_Sepolia]: '0x3a3fe695F684Bf9b9e43CF43C2b895Ea5e392bB3'
|
|
10229
10353
|
}
|
|
10230
10354
|
};
|
|
10231
10355
|
|
|
@@ -11505,11 +11629,11 @@ function resolveOptions(options) {
|
|
|
11505
11629
|
void emitAnalyticsLog(buildPayload$1(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
|
|
11506
11630
|
}
|
|
11507
11631
|
|
|
11508
|
-
var name$
|
|
11509
|
-
var version$
|
|
11510
|
-
var pkg$
|
|
11511
|
-
name: name$
|
|
11512
|
-
version: version$
|
|
11632
|
+
var name$4 = "@circle-fin/bridge-kit";
|
|
11633
|
+
var version$5 = "1.12.0";
|
|
11634
|
+
var pkg$5 = {
|
|
11635
|
+
name: name$4,
|
|
11636
|
+
version: version$5};
|
|
11513
11637
|
|
|
11514
11638
|
const assertCustomFeePolicySymbol$2 = Symbol('assertCustomFeePolicy');
|
|
11515
11639
|
/**
|
|
@@ -13535,7 +13659,7 @@ exports.TransferSpeed = void 0;
|
|
|
13535
13659
|
const bridgeKitCaller = {
|
|
13536
13660
|
type: 'kit',
|
|
13537
13661
|
name: 'BridgeKit',
|
|
13538
|
-
version: pkg$
|
|
13662
|
+
version: pkg$5.version
|
|
13539
13663
|
};
|
|
13540
13664
|
// Create default runtime and tokens for invocation context resolution
|
|
13541
13665
|
const defaults = {
|
|
@@ -14205,6 +14329,15 @@ const CUSTOM_BURN_GAS_ESTIMATE_EVM = 201_525n // p99 and max are same here: 201_
|
|
|
14205
14329
|
;
|
|
14206
14330
|
const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_839n) / 2 = 237_401n
|
|
14207
14331
|
;
|
|
14332
|
+
// Hard execution caps: observed max + ~30% buffer, used as gasLimit overrides on
|
|
14333
|
+
// chains whose eth_estimateGas under-reports (e.g. Cronos EIP-7623 calldata floor).
|
|
14334
|
+
// Kept separate from the fee-estimate averages above.
|
|
14335
|
+
const APPROVE_GAS_LIMIT_EVM = 100_000n // ERC-20 approve observed max ~46k
|
|
14336
|
+
;
|
|
14337
|
+
const DEPOSIT_FOR_BURN_GAS_LIMIT_EVM = 300_000n // observed max 226_506 + ~30%
|
|
14338
|
+
;
|
|
14339
|
+
const RECEIVE_MESSAGE_GAS_LIMIT_EVM = 400_000n // observed max 310_839 + ~30%
|
|
14340
|
+
;
|
|
14208
14341
|
/**
|
|
14209
14342
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
14210
14343
|
*
|
|
@@ -14233,6 +14366,27 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
14233
14366
|
'Content-Type': 'application/json'
|
|
14234
14367
|
}
|
|
14235
14368
|
};
|
|
14369
|
+
/**
|
|
14370
|
+
* Merges caller-provided polling overrides on top of {@link DEFAULT_CONFIG}.
|
|
14371
|
+
*
|
|
14372
|
+
* Headers are merged independently so caller-supplied headers augment the
|
|
14373
|
+
* defaults (such as `Content-Type`) rather than replacing them wholesale.
|
|
14374
|
+
*
|
|
14375
|
+
* @param config - Caller-provided polling configuration overrides
|
|
14376
|
+
* @param internalDefaults - Internal defaults applied before `config` (for example a
|
|
14377
|
+
* reduced `maxRetries` for one-shot requests); `config` still wins on conflict
|
|
14378
|
+
* @returns The effective polling configuration
|
|
14379
|
+
* @internal
|
|
14380
|
+
*/ const mergeAttestationConfig = (config, internalDefaults = {})=>({
|
|
14381
|
+
...DEFAULT_CONFIG$2,
|
|
14382
|
+
...internalDefaults,
|
|
14383
|
+
...config,
|
|
14384
|
+
headers: {
|
|
14385
|
+
...DEFAULT_CONFIG$2.headers,
|
|
14386
|
+
...internalDefaults.headers,
|
|
14387
|
+
...config.headers
|
|
14388
|
+
}
|
|
14389
|
+
});
|
|
14236
14390
|
/**
|
|
14237
14391
|
* Type guard that verifies if an unknown value matches the AttestationMessage shape
|
|
14238
14392
|
* and has all required properties.
|
|
@@ -14379,10 +14533,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
14379
14533
|
* ```
|
|
14380
14534
|
*/ const fetchAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
14381
14535
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
14382
|
-
const effectiveConfig =
|
|
14383
|
-
...DEFAULT_CONFIG$2,
|
|
14384
|
-
...config
|
|
14385
|
-
};
|
|
14536
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
14386
14537
|
return await pollApiGet(url, isAttestationResponse, effectiveConfig);
|
|
14387
14538
|
};
|
|
14388
14539
|
/**
|
|
@@ -14425,11 +14576,9 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
14425
14576
|
*/ const fetchAttestationWithoutStatusCheck = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
14426
14577
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
14427
14578
|
// Use minimal retries since we're just fetching existing data
|
|
14428
|
-
const effectiveConfig = {
|
|
14429
|
-
|
|
14430
|
-
|
|
14431
|
-
...config
|
|
14432
|
-
};
|
|
14579
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
14580
|
+
maxRetries: 3
|
|
14581
|
+
});
|
|
14433
14582
|
return await pollApiGet(url, isAttestationResponseWithoutStatusCheck, effectiveConfig);
|
|
14434
14583
|
};
|
|
14435
14584
|
/**
|
|
@@ -14489,10 +14638,7 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
14489
14638
|
* ```
|
|
14490
14639
|
*/ const fetchReAttestedAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
14491
14640
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
14492
|
-
const effectiveConfig =
|
|
14493
|
-
...DEFAULT_CONFIG$2,
|
|
14494
|
-
...config
|
|
14495
|
-
};
|
|
14641
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
14496
14642
|
return await pollApiGet(url, isReAttestedAttestationResponse, effectiveConfig);
|
|
14497
14643
|
};
|
|
14498
14644
|
/**
|
|
@@ -14558,14 +14704,139 @@ const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_8
|
|
|
14558
14704
|
*/ const requestReAttestation = async (nonce, isTestnet, config = {})=>{
|
|
14559
14705
|
const url = buildReAttestUrl(nonce, isTestnet);
|
|
14560
14706
|
// Use minimal retries since we're just submitting a request, not polling for state
|
|
14561
|
-
const effectiveConfig = {
|
|
14562
|
-
|
|
14563
|
-
|
|
14564
|
-
...config
|
|
14565
|
-
};
|
|
14707
|
+
const effectiveConfig = mergeAttestationConfig(config, {
|
|
14708
|
+
maxRetries: 3
|
|
14709
|
+
});
|
|
14566
14710
|
return await pollApiPost(url, {}, isReAttestationResponse, effectiveConfig);
|
|
14567
14711
|
};
|
|
14568
14712
|
|
|
14713
|
+
/**
|
|
14714
|
+
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
14715
|
+
*
|
|
14716
|
+
* This function validates that:
|
|
14717
|
+
* 1. The response has valid AttestationResponse structure
|
|
14718
|
+
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
14719
|
+
*
|
|
14720
|
+
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
14721
|
+
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
14722
|
+
*
|
|
14723
|
+
* @param obj - The value to check, typically a parsed JSON response
|
|
14724
|
+
* @returns True if the relayer has confirmed the mint
|
|
14725
|
+
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
14726
|
+
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
14727
|
+
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
14728
|
+
* @internal
|
|
14729
|
+
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
14730
|
+
// First check if the structure is valid
|
|
14731
|
+
if (!hasValidAttestationStructure(obj)) {
|
|
14732
|
+
throw new KitError({
|
|
14733
|
+
...InputError.VALIDATION_FAILED,
|
|
14734
|
+
recoverability: 'FATAL',
|
|
14735
|
+
message: 'Invalid attestation response structure from IRIS API.'
|
|
14736
|
+
});
|
|
14737
|
+
}
|
|
14738
|
+
// Find the first message (typically there's only one)
|
|
14739
|
+
const message = obj.messages[0];
|
|
14740
|
+
if (!message) {
|
|
14741
|
+
throw new KitError({
|
|
14742
|
+
...InputError.VALIDATION_FAILED,
|
|
14743
|
+
recoverability: 'FATAL',
|
|
14744
|
+
message: 'No attestation messages found in IRIS API response.'
|
|
14745
|
+
});
|
|
14746
|
+
}
|
|
14747
|
+
// Check for FAILED state - this is a permanent failure
|
|
14748
|
+
if (message.forwardState === 'FAILED') {
|
|
14749
|
+
throw new KitError({
|
|
14750
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
14751
|
+
recoverability: 'RESUMABLE',
|
|
14752
|
+
message: 'Circle relayer failed to forward the mint transaction. The mint may still have succeeded if another party submitted it. Check the recipient wallet balance before retrying. If the mint did not occur, you can manually submit it using the attestation data in the error cause.',
|
|
14753
|
+
cause: {
|
|
14754
|
+
trace: {
|
|
14755
|
+
eventNonce: message.eventNonce,
|
|
14756
|
+
attestation: message.attestation,
|
|
14757
|
+
message: message.message
|
|
14758
|
+
}
|
|
14759
|
+
}
|
|
14760
|
+
});
|
|
14761
|
+
}
|
|
14762
|
+
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
14763
|
+
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
14764
|
+
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
14765
|
+
return true;
|
|
14766
|
+
}
|
|
14767
|
+
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
14768
|
+
throw new KitError({
|
|
14769
|
+
...NetworkError.RELAYER_PENDING,
|
|
14770
|
+
recoverability: 'RETRYABLE',
|
|
14771
|
+
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
14772
|
+
});
|
|
14773
|
+
};
|
|
14774
|
+
/**
|
|
14775
|
+
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
14776
|
+
*
|
|
14777
|
+
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
14778
|
+
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
14779
|
+
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
14780
|
+
*
|
|
14781
|
+
* @remarks
|
|
14782
|
+
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
14783
|
+
* - Throws immediately if `forwardState` is 'FAILED'
|
|
14784
|
+
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
14785
|
+
* - Returns the attestation message with `forwardTxHash` populated
|
|
14786
|
+
*
|
|
14787
|
+
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
14788
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
14789
|
+
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
14790
|
+
* @param config - Optional configuration overrides for polling behavior
|
|
14791
|
+
* @returns The attestation message with confirmed forwardTxHash
|
|
14792
|
+
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
14793
|
+
* @throws {KitError} If timeout is reached while still pending
|
|
14794
|
+
*
|
|
14795
|
+
* @example
|
|
14796
|
+
* ```typescript
|
|
14797
|
+
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
14798
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
14799
|
+
* ```
|
|
14800
|
+
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
14801
|
+
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
14802
|
+
const effectiveConfig = mergeAttestationConfig(config);
|
|
14803
|
+
let response;
|
|
14804
|
+
try {
|
|
14805
|
+
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
14806
|
+
} catch (error) {
|
|
14807
|
+
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
14808
|
+
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
14809
|
+
throw new KitError({
|
|
14810
|
+
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
14811
|
+
recoverability: error.recoverability,
|
|
14812
|
+
message: error.message,
|
|
14813
|
+
cause: {
|
|
14814
|
+
...error.cause,
|
|
14815
|
+
trace: {
|
|
14816
|
+
...error.cause?.trace,
|
|
14817
|
+
burnTxHash: transactionHash
|
|
14818
|
+
}
|
|
14819
|
+
}
|
|
14820
|
+
});
|
|
14821
|
+
}
|
|
14822
|
+
throw error;
|
|
14823
|
+
}
|
|
14824
|
+
// Return the first message (which should have forwardTxHash)
|
|
14825
|
+
// Note: This check is needed for TypeScript type safety even though
|
|
14826
|
+
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
14827
|
+
// narrows the type at the call site, but TypeScript can't infer that
|
|
14828
|
+
// the array still has elements after pollApiGet returns.
|
|
14829
|
+
const message = response.messages[0];
|
|
14830
|
+
if (!message) {
|
|
14831
|
+
throw new KitError({
|
|
14832
|
+
...InputError.VALIDATION_FAILED,
|
|
14833
|
+
recoverability: 'FATAL',
|
|
14834
|
+
message: 'No attestation messages found in response after polling.'
|
|
14835
|
+
});
|
|
14836
|
+
}
|
|
14837
|
+
return message;
|
|
14838
|
+
};
|
|
14839
|
+
|
|
14569
14840
|
const assertCCTPv2WalletContextSymbol = Symbol('assertCCTPv2WalletContext');
|
|
14570
14841
|
/**
|
|
14571
14842
|
* Asserts that the provided parameters match the CCTPv2 wallet context interface.
|
|
@@ -15440,6 +15711,8 @@ function hasPendingState(analysis, result) {
|
|
|
15440
15711
|
* - `adapter`: The adapter that will execute the transaction
|
|
15441
15712
|
* - `confirmations`: The number of confirmations to wait for (defaults to 1)
|
|
15442
15713
|
* - `timeout`: The timeout for the request in milliseconds
|
|
15714
|
+
* - `gasLimit`: Optional explicit gas limit (number) forwarded to EVM execute,
|
|
15715
|
+
* bypassing `eth_estimateGas`; ignored for non-EVM requests
|
|
15443
15716
|
* @returns The bridge step with the transaction details and explorer URL
|
|
15444
15717
|
* @throws If the transaction execution fails
|
|
15445
15718
|
*
|
|
@@ -15454,7 +15727,7 @@ function hasPendingState(analysis, result) {
|
|
|
15454
15727
|
* })
|
|
15455
15728
|
* console.log('Transaction hash:', step.txHash)
|
|
15456
15729
|
* ```
|
|
15457
|
-
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout }) {
|
|
15730
|
+
*/ async function executePreparedChainRequest({ name, request, adapter, chain, confirmations = 1, timeout, gasLimit }) {
|
|
15458
15731
|
const step = {
|
|
15459
15732
|
name,
|
|
15460
15733
|
state: 'pending'
|
|
@@ -15467,7 +15740,9 @@ function hasPendingState(analysis, result) {
|
|
|
15467
15740
|
step.state = 'noop';
|
|
15468
15741
|
return step;
|
|
15469
15742
|
}
|
|
15470
|
-
const txHash = await request.execute(
|
|
15743
|
+
const txHash = request.type === 'evm' && gasLimit !== undefined ? await request.execute({
|
|
15744
|
+
gasLimit
|
|
15745
|
+
}) : await request.execute();
|
|
15471
15746
|
step.txHash = txHash;
|
|
15472
15747
|
const retryOptions = {
|
|
15473
15748
|
isRetryable: (err)=>isRetryableError$1(parseBlockchainError(err, {
|
|
@@ -15539,7 +15814,8 @@ function hasPendingState(analysis, result) {
|
|
|
15539
15814
|
name: 'approve',
|
|
15540
15815
|
adapter: params.source.adapter,
|
|
15541
15816
|
chain: params.source.chain,
|
|
15542
|
-
request: await provider.approve(params.source, approvalAmount)
|
|
15817
|
+
request: await provider.approve(params.source, approvalAmount),
|
|
15818
|
+
gasLimit: Number(APPROVE_GAS_LIMIT_EVM)
|
|
15543
15819
|
});
|
|
15544
15820
|
}
|
|
15545
15821
|
|
|
@@ -15566,7 +15842,8 @@ function hasPendingState(analysis, result) {
|
|
|
15566
15842
|
name: 'burn',
|
|
15567
15843
|
adapter: params.source.adapter,
|
|
15568
15844
|
chain: params.source.chain,
|
|
15569
|
-
request: await provider.burn(params)
|
|
15845
|
+
request: await provider.burn(params),
|
|
15846
|
+
gasLimit: Number(DEPOSIT_FOR_BURN_GAS_LIMIT_EVM)
|
|
15570
15847
|
});
|
|
15571
15848
|
}
|
|
15572
15849
|
|
|
@@ -15652,11 +15929,18 @@ function hasPendingState(analysis, result) {
|
|
|
15652
15929
|
*/ async function bridgeMint({ params, provider }, attestation) {
|
|
15653
15930
|
// Validate attestation message matches transfer params
|
|
15654
15931
|
await assertCCTPv2AttestationParams(attestation, params);
|
|
15932
|
+
const mintRequest = await provider.mint(params.source, params.destination, attestation);
|
|
15655
15933
|
const step = await executePreparedChainRequest({
|
|
15656
15934
|
name: 'mint',
|
|
15657
15935
|
adapter: params.destination.adapter,
|
|
15658
15936
|
chain: params.destination.chain,
|
|
15659
|
-
request:
|
|
15937
|
+
request: mintRequest,
|
|
15938
|
+
// Some chains (e.g. Cronos) enforce an EIP-7623 calldata gas floor that
|
|
15939
|
+
// eth_estimateGas does not account for, returning a below-floor value
|
|
15940
|
+
// without reverting. Pinning to a value above the observed execution max
|
|
15941
|
+
// (310_839) bypasses re-estimation and guarantees we clear both the floor
|
|
15942
|
+
// and the actual execution cost.
|
|
15943
|
+
gasLimit: Number(RECEIVE_MESSAGE_GAS_LIMIT_EVM)
|
|
15660
15944
|
});
|
|
15661
15945
|
// Add forwarded: false for non-relayer mints
|
|
15662
15946
|
return {
|
|
@@ -15694,136 +15978,6 @@ const mockAttestationMessage = {
|
|
|
15694
15978
|
delayReason: null
|
|
15695
15979
|
};
|
|
15696
15980
|
|
|
15697
|
-
/**
|
|
15698
|
-
* Type guard that checks if the relayer has confirmed the mint transaction.
|
|
15699
|
-
*
|
|
15700
|
-
* This function validates that:
|
|
15701
|
-
* 1. The response has valid AttestationResponse structure
|
|
15702
|
-
* 2. At least one message has forwardState === 'CONFIRMED' (or 'COMPLETE') and a valid forwardTxHash
|
|
15703
|
-
*
|
|
15704
|
-
* If forwardState is 'FAILED', throws a non-retryable KitError.
|
|
15705
|
-
* If forwardState is 'PENDING' or not present, throws a RETRYABLE KitError to continue polling.
|
|
15706
|
-
*
|
|
15707
|
-
* @param obj - The value to check, typically a parsed JSON response
|
|
15708
|
-
* @returns True if the relayer has confirmed the mint
|
|
15709
|
-
* @throws {KitError} With FATAL recoverability if structure is invalid
|
|
15710
|
-
* @throws {KitError} With RESUMABLE recoverability if forwardState is 'FAILED'
|
|
15711
|
-
* @throws {KitError} With RETRYABLE recoverability if still pending
|
|
15712
|
-
* @internal
|
|
15713
|
-
*/ const isRelayerMintConfirmed = (obj)=>{
|
|
15714
|
-
// First check if the structure is valid
|
|
15715
|
-
if (!hasValidAttestationStructure(obj)) {
|
|
15716
|
-
throw new KitError({
|
|
15717
|
-
...InputError.VALIDATION_FAILED,
|
|
15718
|
-
recoverability: 'FATAL',
|
|
15719
|
-
message: 'Invalid attestation response structure from IRIS API.'
|
|
15720
|
-
});
|
|
15721
|
-
}
|
|
15722
|
-
// Find the first message (typically there's only one)
|
|
15723
|
-
const message = obj.messages[0];
|
|
15724
|
-
if (!message) {
|
|
15725
|
-
throw new KitError({
|
|
15726
|
-
...InputError.VALIDATION_FAILED,
|
|
15727
|
-
recoverability: 'FATAL',
|
|
15728
|
-
message: 'No attestation messages found in IRIS API response.'
|
|
15729
|
-
});
|
|
15730
|
-
}
|
|
15731
|
-
// Check for FAILED state - this is a permanent failure
|
|
15732
|
-
if (message.forwardState === 'FAILED') {
|
|
15733
|
-
throw new KitError({
|
|
15734
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
15735
|
-
recoverability: 'RESUMABLE',
|
|
15736
|
-
message: 'Circle relayer failed to forward the mint transaction. The mint may still have succeeded if another party submitted it. Check the recipient wallet balance before retrying. If the mint did not occur, you can manually submit it using the attestation data in the error cause.',
|
|
15737
|
-
cause: {
|
|
15738
|
-
trace: {
|
|
15739
|
-
eventNonce: message.eventNonce,
|
|
15740
|
-
attestation: message.attestation,
|
|
15741
|
-
message: message.message
|
|
15742
|
-
}
|
|
15743
|
-
}
|
|
15744
|
-
});
|
|
15745
|
-
}
|
|
15746
|
-
// Check if mint is confirmed (or complete) with a valid transaction hash
|
|
15747
|
-
// We accept both CONFIRMED and COMPLETE since COMPLETE implies CONFIRMED
|
|
15748
|
-
if ((message.forwardState === 'CONFIRMED' || message.forwardState === 'COMPLETE') && typeof message.forwardTxHash === 'string' && message.forwardTxHash.trim().length > 0) {
|
|
15749
|
-
return true;
|
|
15750
|
-
}
|
|
15751
|
-
// Still pending or not yet processed - throw RETRYABLE error to continue polling
|
|
15752
|
-
throw new KitError({
|
|
15753
|
-
...NetworkError.RELAYER_PENDING,
|
|
15754
|
-
recoverability: 'RETRYABLE',
|
|
15755
|
-
message: 'Relayer mint not ready. Waiting for confirmation.'
|
|
15756
|
-
});
|
|
15757
|
-
};
|
|
15758
|
-
/**
|
|
15759
|
-
* Polls the attestation API until the relayer's mint transaction is confirmed.
|
|
15760
|
-
*
|
|
15761
|
-
* This function is used when `useForwarder` is enabled. Instead of the user
|
|
15762
|
-
* submitting the mint transaction, Circle's Orbit relayer handles it automatically.
|
|
15763
|
-
* This function polls until the relayer has submitted and confirmed the mint transaction.
|
|
15764
|
-
*
|
|
15765
|
-
* @remarks
|
|
15766
|
-
* - Uses a 20-minute timeout by default (600 retries × 2 seconds)
|
|
15767
|
-
* - Throws immediately if `forwardState` is 'FAILED'
|
|
15768
|
-
* - Waits for `forwardState` to be 'CONFIRMED' or 'COMPLETE' (COMPLETE implies CONFIRMED)
|
|
15769
|
-
* - Returns the attestation message with `forwardTxHash` populated
|
|
15770
|
-
*
|
|
15771
|
-
* @param sourceDomainId - The CCTP domain ID of the source chain
|
|
15772
|
-
* @param transactionHash - The transaction hash of the burn operation
|
|
15773
|
-
* @param isTestnet - Whether this is for a testnet chain (true) or mainnet (false)
|
|
15774
|
-
* @param config - Optional configuration overrides for polling behavior
|
|
15775
|
-
* @returns The attestation message with confirmed forwardTxHash
|
|
15776
|
-
* @throws {KitError} With code 'NETWORK_RELAYER_FORWARD_FAILED' if relayer failed
|
|
15777
|
-
* @throws {KitError} If timeout is reached while still pending
|
|
15778
|
-
*
|
|
15779
|
-
* @example
|
|
15780
|
-
* ```typescript
|
|
15781
|
-
* const attestation = await fetchRelayerMint(0, '0xabc...', false)
|
|
15782
|
-
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
15783
|
-
* ```
|
|
15784
|
-
*/ const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {})=>{
|
|
15785
|
-
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
15786
|
-
const effectiveConfig = {
|
|
15787
|
-
...DEFAULT_CONFIG$2,
|
|
15788
|
-
...config
|
|
15789
|
-
};
|
|
15790
|
-
let response;
|
|
15791
|
-
try {
|
|
15792
|
-
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
15793
|
-
} catch (error) {
|
|
15794
|
-
// Enrich RELAYER_FORWARD_FAILED errors with the burn transaction hash
|
|
15795
|
-
if (error instanceof KitError && error.name === 'NETWORK_RELAYER_FORWARD_FAILED') {
|
|
15796
|
-
throw new KitError({
|
|
15797
|
-
...NetworkError.RELAYER_FORWARD_FAILED,
|
|
15798
|
-
recoverability: error.recoverability,
|
|
15799
|
-
message: error.message,
|
|
15800
|
-
cause: {
|
|
15801
|
-
...error.cause,
|
|
15802
|
-
trace: {
|
|
15803
|
-
...error.cause?.trace,
|
|
15804
|
-
burnTxHash: transactionHash
|
|
15805
|
-
}
|
|
15806
|
-
}
|
|
15807
|
-
});
|
|
15808
|
-
}
|
|
15809
|
-
throw error;
|
|
15810
|
-
}
|
|
15811
|
-
// Return the first message (which should have forwardTxHash)
|
|
15812
|
-
// Note: This check is needed for TypeScript type safety even though
|
|
15813
|
-
// isRelayerMintConfirmed validates messages[0] exists. The type guard
|
|
15814
|
-
// narrows the type at the call site, but TypeScript can't infer that
|
|
15815
|
-
// the array still has elements after pollApiGet returns.
|
|
15816
|
-
const message = response.messages[0];
|
|
15817
|
-
if (!message) {
|
|
15818
|
-
throw new KitError({
|
|
15819
|
-
...InputError.VALIDATION_FAILED,
|
|
15820
|
-
recoverability: 'FATAL',
|
|
15821
|
-
message: 'No attestation messages found in response after polling.'
|
|
15822
|
-
});
|
|
15823
|
-
}
|
|
15824
|
-
return message;
|
|
15825
|
-
};
|
|
15826
|
-
|
|
15827
15981
|
/**
|
|
15828
15982
|
* Executes the mint step for forwarding mode where Circle's relayer handles the mint.
|
|
15829
15983
|
*
|
|
@@ -15837,6 +15991,7 @@ const mockAttestationMessage = {
|
|
|
15837
15991
|
* immediately after the API confirms the mint.
|
|
15838
15992
|
*
|
|
15839
15993
|
* @param params - The bridge parameters containing source, destination, amount and config
|
|
15994
|
+
* @param provider - The CCTP v2 bridging provider
|
|
15840
15995
|
* @param context - The step context containing burnTxHash from the burn step
|
|
15841
15996
|
* @returns Promise resolving to the bridge step with transaction details
|
|
15842
15997
|
* @throws {KitError} If burnTxHash is not available in context
|
|
@@ -15845,10 +16000,13 @@ const mockAttestationMessage = {
|
|
|
15845
16000
|
*
|
|
15846
16001
|
* @example
|
|
15847
16002
|
* ```typescript
|
|
15848
|
-
* const step = await bridgeRelayerMint(
|
|
16003
|
+
* const step = await bridgeRelayerMint(
|
|
16004
|
+
* { params, provider },
|
|
16005
|
+
* { burnTxHash: '0x...' }
|
|
16006
|
+
* )
|
|
15849
16007
|
* console.log('Relayer mint tx:', step.txHash)
|
|
15850
16008
|
* ```
|
|
15851
|
-
*/ async function bridgeRelayerMint(params, context) {
|
|
16009
|
+
*/ async function bridgeRelayerMint({ params, provider }, context) {
|
|
15852
16010
|
const step = {
|
|
15853
16011
|
name: 'mint',
|
|
15854
16012
|
state: 'pending',
|
|
@@ -15864,7 +16022,7 @@ const mockAttestationMessage = {
|
|
|
15864
16022
|
}
|
|
15865
16023
|
try {
|
|
15866
16024
|
// Poll attestation API until relayer confirms the mint
|
|
15867
|
-
const attestation = await fetchRelayerMint(params.source
|
|
16025
|
+
const attestation = await provider.fetchRelayerMint(params.source, context.burnTxHash);
|
|
15868
16026
|
// Extract the relayer's mint transaction hash
|
|
15869
16027
|
const forwardTxHash = attestation.forwardTxHash;
|
|
15870
16028
|
if (!forwardTxHash) {
|
|
@@ -15958,7 +16116,7 @@ const mockAttestationMessage = {
|
|
|
15958
16116
|
name: 'mint',
|
|
15959
16117
|
// bridgeRelayerMint validates context.burnTxHash internally with a KitError
|
|
15960
16118
|
// bridgeMint requires attestationData which is validated here
|
|
15961
|
-
executor: useForwarder ? async (params,
|
|
16119
|
+
executor: useForwarder ? async (params, provider, context)=>{
|
|
15962
16120
|
if (!context) {
|
|
15963
16121
|
throw new KitError({
|
|
15964
16122
|
...InputError.VALIDATION_FAILED,
|
|
@@ -15966,7 +16124,10 @@ const mockAttestationMessage = {
|
|
|
15966
16124
|
message: 'Step context is required for relayer mint'
|
|
15967
16125
|
});
|
|
15968
16126
|
}
|
|
15969
|
-
return bridgeRelayerMint(
|
|
16127
|
+
return bridgeRelayerMint({
|
|
16128
|
+
params,
|
|
16129
|
+
provider
|
|
16130
|
+
}, context);
|
|
15970
16131
|
} : async (params, provider, context)=>{
|
|
15971
16132
|
if (!context?.attestationData) {
|
|
15972
16133
|
throw new KitError({
|
|
@@ -16297,16 +16458,16 @@ const mockAttestationMessage = {
|
|
|
16297
16458
|
return step;
|
|
16298
16459
|
}
|
|
16299
16460
|
|
|
16300
|
-
var version$
|
|
16301
|
-
var pkg$
|
|
16302
|
-
version: version$
|
|
16461
|
+
var version$4 = "1.9.0";
|
|
16462
|
+
var pkg$4 = {
|
|
16463
|
+
version: version$4};
|
|
16303
16464
|
|
|
16304
16465
|
/**
|
|
16305
16466
|
* Provider caller component for bridge operations.
|
|
16306
16467
|
*/ const BRIDGE_CALLER = {
|
|
16307
16468
|
type: 'provider',
|
|
16308
16469
|
name: 'CCTPV2BridgingProvider.bridge',
|
|
16309
|
-
version: pkg$
|
|
16470
|
+
version: pkg$4.version
|
|
16310
16471
|
};
|
|
16311
16472
|
/**
|
|
16312
16473
|
* Resolve invocation context for bridge operations.
|
|
@@ -16679,7 +16840,7 @@ var pkg$3 = {
|
|
|
16679
16840
|
*/ const RETRY_CALLER = {
|
|
16680
16841
|
type: 'provider',
|
|
16681
16842
|
name: 'CCTPV2BridgingProvider.retry',
|
|
16682
|
-
version: pkg$
|
|
16843
|
+
version: pkg$4.version
|
|
16683
16844
|
};
|
|
16684
16845
|
/**
|
|
16685
16846
|
* Resolve invocation context for retry operations.
|
|
@@ -17003,6 +17164,39 @@ var pkg$3 = {
|
|
|
17003
17164
|
}
|
|
17004
17165
|
}
|
|
17005
17166
|
|
|
17167
|
+
function isPlainObject(value) {
|
|
17168
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
17169
|
+
return false;
|
|
17170
|
+
}
|
|
17171
|
+
const prototype = Object.getPrototypeOf(value);
|
|
17172
|
+
return prototype === Object.prototype || prototype === null;
|
|
17173
|
+
}
|
|
17174
|
+
function assertHeadersConfig(headers, field) {
|
|
17175
|
+
if (headers === undefined) {
|
|
17176
|
+
return;
|
|
17177
|
+
}
|
|
17178
|
+
if (!isPlainObject(headers)) {
|
|
17179
|
+
throw createValidationFailedError$1(field, headers, `${field} must be a plain object with string header values when provided`);
|
|
17180
|
+
}
|
|
17181
|
+
for (const [name, value] of Object.entries(headers)){
|
|
17182
|
+
if (typeof value !== 'string') {
|
|
17183
|
+
throw createValidationFailedError$1(`${field}.${name}`, value, 'header values must be strings');
|
|
17184
|
+
}
|
|
17185
|
+
}
|
|
17186
|
+
}
|
|
17187
|
+
function assertCCTPV2Config(config) {
|
|
17188
|
+
if (!isPlainObject(config)) {
|
|
17189
|
+
throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
|
|
17190
|
+
}
|
|
17191
|
+
assertHeadersConfig(config['headers'], 'config.headers');
|
|
17192
|
+
const attestation = config['attestation'];
|
|
17193
|
+
if (attestation !== undefined) {
|
|
17194
|
+
if (!isPlainObject(attestation)) {
|
|
17195
|
+
throw createValidationFailedError$1('config.attestation', attestation, 'config.attestation must be a plain object when provided');
|
|
17196
|
+
}
|
|
17197
|
+
assertHeadersConfig(attestation['headers'], 'config.attestation.headers');
|
|
17198
|
+
}
|
|
17199
|
+
}
|
|
17006
17200
|
/**
|
|
17007
17201
|
* All chains that are supported by the CCTP v2 provider.
|
|
17008
17202
|
*
|
|
@@ -17071,9 +17265,38 @@ var pkg$3 = {
|
|
|
17071
17265
|
* @param config - Optional configuration overrides for the provider
|
|
17072
17266
|
*/ constructor(config = {}){
|
|
17073
17267
|
super();
|
|
17268
|
+
assertCCTPV2Config(config);
|
|
17074
17269
|
this.config = config;
|
|
17075
17270
|
}
|
|
17076
17271
|
/**
|
|
17272
|
+
* Resolves the effective polling configuration for an attestation request.
|
|
17273
|
+
*
|
|
17274
|
+
* Precedence (lowest to highest): provider `config.attestation`, then the
|
|
17275
|
+
* per-call `config`. Headers merge independently across
|
|
17276
|
+
* `config.attestation.headers`, the provider-level `config.headers`, and any
|
|
17277
|
+
* per-call `config.headers`, so a more specific header augments rather than
|
|
17278
|
+
* replaces the broader ones. The `headers` key is omitted entirely when no
|
|
17279
|
+
* headers are configured, leaving the attestation fetchers' defaults intact.
|
|
17280
|
+
*
|
|
17281
|
+
* @param config - Optional per-call polling configuration overrides
|
|
17282
|
+
* @returns The merged polling configuration passed to the attestation fetchers
|
|
17283
|
+
*/ resolveAttestationConfig(config) {
|
|
17284
|
+
const headers = {
|
|
17285
|
+
...this.config?.attestation?.headers,
|
|
17286
|
+
...this.config?.headers,
|
|
17287
|
+
...config?.headers
|
|
17288
|
+
};
|
|
17289
|
+
// Polling fields follow normal precedence; headers are merged separately
|
|
17290
|
+
// below so narrower config layers augment rather than replace broader ones.
|
|
17291
|
+
return {
|
|
17292
|
+
...this.config?.attestation,
|
|
17293
|
+
...config,
|
|
17294
|
+
...Object.keys(headers).length > 0 ? {
|
|
17295
|
+
headers
|
|
17296
|
+
} : {}
|
|
17297
|
+
};
|
|
17298
|
+
}
|
|
17299
|
+
/**
|
|
17077
17300
|
* Execute a cross-chain USDC bridge operation using the CCTP v2 protocol.
|
|
17078
17301
|
*
|
|
17079
17302
|
* This method orchestrates the complete CCTP v2 bridge flow including validation,
|
|
@@ -17499,11 +17722,7 @@ var pkg$3 = {
|
|
|
17499
17722
|
*/ async fetchAttestation(source, transactionHash, config) {
|
|
17500
17723
|
assertCCTPv2WalletContext(source);
|
|
17501
17724
|
try {
|
|
17502
|
-
|
|
17503
|
-
const effectiveConfig = {
|
|
17504
|
-
...this.config?.attestation,
|
|
17505
|
-
...config
|
|
17506
|
-
};
|
|
17725
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
17507
17726
|
const response = await fetchAttestation(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
17508
17727
|
const message = response.messages[0];
|
|
17509
17728
|
if (!message) {
|
|
@@ -17520,6 +17739,49 @@ var pkg$3 = {
|
|
|
17520
17739
|
}
|
|
17521
17740
|
}
|
|
17522
17741
|
/**
|
|
17742
|
+
* Polls attestation data until Circle's relayer mint transaction is confirmed.
|
|
17743
|
+
*
|
|
17744
|
+
* This method is used by forwarded transfers. It polls the same Iris
|
|
17745
|
+
* attestation endpoint as {@link CCTPV2BridgingProvider.fetchAttestation},
|
|
17746
|
+
* but waits for a completed relayer forward state and returns the attestation
|
|
17747
|
+
* message containing `forwardTxHash`.
|
|
17748
|
+
*
|
|
17749
|
+
* @typeParam TFromAdapterCapabilities - The type representing the capabilities of the source adapter
|
|
17750
|
+
* @param source - The source wallet context containing the chain definition and wallet address
|
|
17751
|
+
* @param transactionHash - The transaction hash of the burn operation
|
|
17752
|
+
* @param config - Optional polling configuration overrides for timeout, retries, delay, and headers
|
|
17753
|
+
* @returns A promise that resolves to the attestation message with `forwardTxHash`
|
|
17754
|
+
* @throws KitError If the relayer forward fails, the response is invalid, or polling times out
|
|
17755
|
+
*
|
|
17756
|
+
* @example
|
|
17757
|
+
* ```typescript
|
|
17758
|
+
* import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2'
|
|
17759
|
+
* import { Chains } from '@core/chains'
|
|
17760
|
+
*
|
|
17761
|
+
* const provider = new CCTPV2BridgingProvider({
|
|
17762
|
+
* headers: { 'X-Partner-UUID': '00000000-0000-0000-0000-000000000000' },
|
|
17763
|
+
* })
|
|
17764
|
+
*
|
|
17765
|
+
* const attestation = await provider.fetchRelayerMint(
|
|
17766
|
+
* {
|
|
17767
|
+
* adapter,
|
|
17768
|
+
* chain: Chains.EthereumSepolia,
|
|
17769
|
+
* address: '0x1234...',
|
|
17770
|
+
* },
|
|
17771
|
+
* '0xabc123...',
|
|
17772
|
+
* )
|
|
17773
|
+
*
|
|
17774
|
+
* console.log('Relayer mint tx:', attestation.forwardTxHash)
|
|
17775
|
+
* ```
|
|
17776
|
+
*/ async fetchRelayerMint(source, transactionHash, config) {
|
|
17777
|
+
assertCCTPv2WalletContext(source);
|
|
17778
|
+
if (typeof transactionHash !== 'string' || transactionHash.trim() === '') {
|
|
17779
|
+
throw createValidationFailedError$1('transactionHash', transactionHash, 'transactionHash must be a non-empty string');
|
|
17780
|
+
}
|
|
17781
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
17782
|
+
return await fetchRelayerMint(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
17783
|
+
}
|
|
17784
|
+
/**
|
|
17523
17785
|
* Requests a fresh attestation for an expired attestation.
|
|
17524
17786
|
*
|
|
17525
17787
|
* This method is used when the original attestation has expired before the mint
|
|
@@ -17573,11 +17835,7 @@ var pkg$3 = {
|
|
|
17573
17835
|
throw new Error('Failed to re-attest: Invalid transaction hash');
|
|
17574
17836
|
}
|
|
17575
17837
|
try {
|
|
17576
|
-
|
|
17577
|
-
const effectiveConfig = {
|
|
17578
|
-
...this.config?.attestation,
|
|
17579
|
-
...config
|
|
17580
|
-
};
|
|
17838
|
+
const effectiveConfig = this.resolveAttestationConfig(config);
|
|
17581
17839
|
// Step 1: Get existing attestation data to extract nonce
|
|
17582
17840
|
const existingAttestation = await fetchAttestationWithoutStatusCheck(source.chain.cctp.domain, transactionHash, source.chain.isTestnet, effectiveConfig);
|
|
17583
17841
|
const nonce = existingAttestation.messages[0]?.eventNonce;
|
|
@@ -17862,8 +18120,13 @@ var pkg$3 = {
|
|
|
17862
18120
|
/**
|
|
17863
18121
|
* The default providers that will be used in addition to the providers provided
|
|
17864
18122
|
* to the BridgeKit constructor.
|
|
17865
|
-
|
|
17866
|
-
|
|
18123
|
+
*
|
|
18124
|
+
* @param config - Optional configuration forwarded to the default providers
|
|
18125
|
+
* @returns The default bridging providers
|
|
18126
|
+
*/ const getDefaultProviders$3 = (config = {})=>[
|
|
18127
|
+
new CCTPV2BridgingProvider(config.headers ? {
|
|
18128
|
+
headers: config.headers
|
|
18129
|
+
} : {})
|
|
17867
18130
|
];
|
|
17868
18131
|
|
|
17869
18132
|
/**
|
|
@@ -17974,7 +18237,7 @@ var pkg$3 = {
|
|
|
17974
18237
|
]
|
|
17975
18238
|
];
|
|
17976
18239
|
|
|
17977
|
-
/** SDK name used in telemetry payloads. */ const SDK_NAME$2 = resolveKitSdkName(pkg$
|
|
18240
|
+
/** SDK name used in telemetry payloads. */ const SDK_NAME$2 = resolveKitSdkName(pkg$5.name);
|
|
17978
18241
|
/**
|
|
17979
18242
|
* Pick the most-relevant `txHash` to attach to an error telemetry payload.
|
|
17980
18243
|
*
|
|
@@ -18015,7 +18278,7 @@ var pkg$3 = {
|
|
|
18015
18278
|
*/ const BRIDGE_KIT_CALLER = {
|
|
18016
18279
|
type: 'kit',
|
|
18017
18280
|
name: 'BridgeKit',
|
|
18018
|
-
version: pkg$
|
|
18281
|
+
version: pkg$5.version
|
|
18019
18282
|
};
|
|
18020
18283
|
/**
|
|
18021
18284
|
* Merge BridgeKit's caller into the invocation metadata for retry operations.
|
|
@@ -18106,7 +18369,9 @@ var pkg$3 = {
|
|
|
18106
18369
|
* ```
|
|
18107
18370
|
*/ constructor(config = {}){
|
|
18108
18371
|
// Handle provider configuration
|
|
18109
|
-
const defaultProviders = getDefaultProviders$3(
|
|
18372
|
+
const defaultProviders = getDefaultProviders$3(config.headers ? {
|
|
18373
|
+
headers: config.headers
|
|
18374
|
+
} : {});
|
|
18110
18375
|
this.providers = [
|
|
18111
18376
|
...defaultProviders,
|
|
18112
18377
|
...config.providers ?? []
|
|
@@ -18115,7 +18380,7 @@ var pkg$3 = {
|
|
|
18115
18380
|
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
18116
18381
|
this.telemetryConfig = {
|
|
18117
18382
|
sdkName: SDK_NAME$2,
|
|
18118
|
-
sdkVersion: pkg$
|
|
18383
|
+
sdkVersion: pkg$5.version,
|
|
18119
18384
|
disabled: this.disableErrorReporting
|
|
18120
18385
|
};
|
|
18121
18386
|
for (const provider of this.providers){
|
|
@@ -18637,7 +18902,7 @@ var pkg$3 = {
|
|
|
18637
18902
|
}
|
|
18638
18903
|
|
|
18639
18904
|
// Auto-register this kit for user agent tracking
|
|
18640
|
-
registerKit(`${pkg$
|
|
18905
|
+
registerKit(`${pkg$5.name}/${pkg$5.version}`);
|
|
18641
18906
|
|
|
18642
18907
|
/**
|
|
18643
18908
|
* Create a BridgeKit instance with optional developer fee configuration.
|
|
@@ -18686,6 +18951,9 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
|
|
|
18686
18951
|
const kit = new BridgeKit({
|
|
18687
18952
|
...context.disableErrorReporting != null && {
|
|
18688
18953
|
disableErrorReporting: context.disableErrorReporting
|
|
18954
|
+
},
|
|
18955
|
+
...context.headers != null && {
|
|
18956
|
+
headers: context.headers
|
|
18689
18957
|
}
|
|
18690
18958
|
});
|
|
18691
18959
|
if (hasBoth) {
|
|
@@ -18703,11 +18971,11 @@ registerKit(`${pkg$4.name}/${pkg$4.version}`);
|
|
|
18703
18971
|
return kit;
|
|
18704
18972
|
};
|
|
18705
18973
|
|
|
18706
|
-
var name$
|
|
18707
|
-
var version$
|
|
18708
|
-
var pkg$
|
|
18709
|
-
name: name$
|
|
18710
|
-
version: version$
|
|
18974
|
+
var name$3 = "@circle-fin/swap-kit";
|
|
18975
|
+
var version$3 = "1.3.2";
|
|
18976
|
+
var pkg$3 = {
|
|
18977
|
+
name: name$3,
|
|
18978
|
+
version: version$3};
|
|
18711
18979
|
|
|
18712
18980
|
const chainIdentifierField = zod.z.custom((value)=>chainIdentifierSchema.safeParse(value).success, {
|
|
18713
18981
|
message: 'chain must be a valid chain identifier'
|
|
@@ -23639,7 +23907,7 @@ function writeBytes32(buffer, hex, offset) {
|
|
|
23639
23907
|
}
|
|
23640
23908
|
}
|
|
23641
23909
|
|
|
23642
|
-
const TOKEN_REGISTRY$
|
|
23910
|
+
const TOKEN_REGISTRY$4 = createTokenRegistry();
|
|
23643
23911
|
/**
|
|
23644
23912
|
* Resolve token alias to contract address for the given chain.
|
|
23645
23913
|
*
|
|
@@ -23728,7 +23996,7 @@ const TOKEN_REGISTRY$3 = createTokenRegistry();
|
|
|
23728
23996
|
}
|
|
23729
23997
|
});
|
|
23730
23998
|
}
|
|
23731
|
-
const tokenDefinition = TOKEN_REGISTRY$
|
|
23999
|
+
const tokenDefinition = TOKEN_REGISTRY$4.get(upperToken);
|
|
23732
24000
|
if (tokenDefinition !== undefined) {
|
|
23733
24001
|
const resolvedAddress = tokenDefinition.locators[chain.chain];
|
|
23734
24002
|
if (!resolvedAddress) {
|
|
@@ -23745,7 +24013,7 @@ const TOKEN_REGISTRY$3 = createTokenRegistry();
|
|
|
23745
24013
|
}
|
|
23746
24014
|
});
|
|
23747
24015
|
}
|
|
23748
|
-
return TOKEN_REGISTRY$
|
|
24016
|
+
return TOKEN_REGISTRY$4.resolve(upperToken, chain.chain).locator;
|
|
23749
24017
|
}
|
|
23750
24018
|
// Not an alias - return as-is (assumed to be address)
|
|
23751
24019
|
return token;
|
|
@@ -23842,11 +24110,11 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
23842
24110
|
if (destinationChain.chain !== sourceChain.chain) {
|
|
23843
24111
|
return sourceChain;
|
|
23844
24112
|
}
|
|
23845
|
-
const inputIsOk = isOkToken(tokenIn, sourceChain, TOKEN_REGISTRY$
|
|
24113
|
+
const inputIsOk = isOkToken(tokenIn, sourceChain, TOKEN_REGISTRY$4, OK_TOKEN_SYMBOLS$1);
|
|
23846
24114
|
if (inputIsOk) {
|
|
23847
24115
|
return sourceChain;
|
|
23848
24116
|
}
|
|
23849
|
-
const outputIsOk = isOkToken(tokenOut, destinationChain, TOKEN_REGISTRY$
|
|
24117
|
+
const outputIsOk = isOkToken(tokenOut, destinationChain, TOKEN_REGISTRY$4, OK_TOKEN_SYMBOLS$1);
|
|
23850
24118
|
return outputIsOk ? destinationChain : sourceChain;
|
|
23851
24119
|
}
|
|
23852
24120
|
/**
|
|
@@ -25137,7 +25405,7 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
25137
25405
|
}
|
|
25138
25406
|
}
|
|
25139
25407
|
|
|
25140
|
-
const TOKEN_REGISTRY$
|
|
25408
|
+
const TOKEN_REGISTRY$3 = createTokenRegistry();
|
|
25141
25409
|
/**
|
|
25142
25410
|
* Resolve a token identifier to its canonical symbol for the Stablecoin Service Swap Provider.
|
|
25143
25411
|
*
|
|
@@ -25181,7 +25449,7 @@ const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
|
25181
25449
|
return NATIVE_TOKEN;
|
|
25182
25450
|
}
|
|
25183
25451
|
// For known registry aliases, return canonical symbol directly.
|
|
25184
|
-
if (TOKEN_REGISTRY$
|
|
25452
|
+
if (TOKEN_REGISTRY$3.get(upperToken) !== undefined) {
|
|
25185
25453
|
return upperToken;
|
|
25186
25454
|
}
|
|
25187
25455
|
// For EVM chains, normalize addresses to lowercase for case-insensitive comparison.
|
|
@@ -25191,7 +25459,7 @@ const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
|
25191
25459
|
// Native address is given
|
|
25192
25460
|
if (isNativeEvmAddress(token) || isNativeSolanaAddress(token)) return NATIVE_TOKEN;
|
|
25193
25461
|
try {
|
|
25194
|
-
const { symbol } = TOKEN_REGISTRY$
|
|
25462
|
+
const { symbol } = TOKEN_REGISTRY$3.resolveByAddress(normalizedToken, chain.chain);
|
|
25195
25463
|
if (symbol === undefined) {
|
|
25196
25464
|
return null;
|
|
25197
25465
|
}
|
|
@@ -25322,7 +25590,7 @@ const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
|
25322
25590
|
return `Insufficient ${displaySymbol} balance for swap operation.\n\n` + `Wallet: ${walletAddress}\n` + `Current balance: ${currentDisplay}\n` + `Required: ${requiredDisplay}\n` + `Shortfall: ${shortfallDisplay}\n\n` + `This swap requires ${requiredSummary} to complete the transaction.\n\n` + `Action: Add at least ${actionAmount} to your wallet to complete this swap.`;
|
|
25323
25591
|
}
|
|
25324
25592
|
|
|
25325
|
-
const TOKEN_REGISTRY$
|
|
25593
|
+
const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
25326
25594
|
/**
|
|
25327
25595
|
* Format a raw base-unit amount into a human-readable decimal string.
|
|
25328
25596
|
*
|
|
@@ -25382,12 +25650,12 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
|
25382
25650
|
value,
|
|
25383
25651
|
token: resolvedSymbol,
|
|
25384
25652
|
chain,
|
|
25385
|
-
tokens: TOKEN_REGISTRY$
|
|
25653
|
+
tokens: TOKEN_REGISTRY$2
|
|
25386
25654
|
}),
|
|
25387
25655
|
token: resolvedSymbol
|
|
25388
25656
|
};
|
|
25389
25657
|
}
|
|
25390
|
-
const tokenDef = TOKEN_REGISTRY$
|
|
25658
|
+
const tokenDef = TOKEN_REGISTRY$2.get(resolvedSymbol);
|
|
25391
25659
|
if (tokenDef) {
|
|
25392
25660
|
const decimals = resolveTokenDecimals$1(tokenDef, chain.chain);
|
|
25393
25661
|
return {
|
|
@@ -25418,7 +25686,7 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
|
25418
25686
|
* i.e. 1 + 0.2 + 0.1 = 1.3. Use the greater of (local estimate × this multiplier)
|
|
25419
25687
|
* or the proxy's gasLimit.
|
|
25420
25688
|
*/ const GAS_SAFETY_MULTIPLIER = 1.3;
|
|
25421
|
-
const TOKEN_REGISTRY = createTokenRegistry();
|
|
25689
|
+
const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
25422
25690
|
/**
|
|
25423
25691
|
* Enhances a KitError with transaction details (txHash and explorerUrl).
|
|
25424
25692
|
*
|
|
@@ -25494,6 +25762,19 @@ const TOKEN_REGISTRY = createTokenRegistry();
|
|
|
25494
25762
|
*
|
|
25495
25763
|
* @internal
|
|
25496
25764
|
*/ const SUPPORTED_CHAINS$1 = getSwapSupportedChains(Chains);
|
|
25765
|
+
/**
|
|
25766
|
+
* Inter-poll delays (ms) for the same-chain `amountOut` enrichment loop.
|
|
25767
|
+
*
|
|
25768
|
+
* A same-chain swap is already terminal `DONE` once its source transaction
|
|
25769
|
+
* confirms; this short, escalating budget (~5s total across up to four polls)
|
|
25770
|
+
* gives the service a brief window to resolve the output amount before
|
|
25771
|
+
* `swap()` returns. The loop exits the instant `amountOut` is available.
|
|
25772
|
+
*/ const SAME_CHAIN_AMOUNT_OUT_POLL_DELAYS_MS = [
|
|
25773
|
+
1_000,
|
|
25774
|
+
2_000,
|
|
25775
|
+
2_000
|
|
25776
|
+
];
|
|
25777
|
+
const sleep$3 = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
|
|
25497
25778
|
function buildSwapProgress(statusResult) {
|
|
25498
25779
|
return {
|
|
25499
25780
|
status: statusResult.status,
|
|
@@ -25513,29 +25794,46 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
25513
25794
|
}
|
|
25514
25795
|
};
|
|
25515
25796
|
}
|
|
25516
|
-
|
|
25517
|
-
|
|
25518
|
-
|
|
25519
|
-
|
|
25520
|
-
|
|
25521
|
-
|
|
25522
|
-
|
|
25523
|
-
|
|
25797
|
+
// A same-chain swap completes atomically in the source transaction, which
|
|
25798
|
+
// has already been confirmed (and receipt-checked for revert) by the time we
|
|
25799
|
+
// get here. Its terminal status is therefore `DONE`. We briefly poll the
|
|
25800
|
+
// status endpoint to enrich `amountOut`, which the service usually resolves
|
|
25801
|
+
// within a few seconds. A non-DONE/erroneous peek never downgrades the
|
|
25802
|
+
// status — once the short budget is exhausted we return `DONE` without
|
|
25803
|
+
// `amountOut`, and the caller can fetch it later via `getSwapStatus`.
|
|
25804
|
+
for(let attempt = 0;; attempt += 1){
|
|
25805
|
+
try {
|
|
25806
|
+
const statusResult = await getSwapStatus$2({
|
|
25807
|
+
txHash,
|
|
25808
|
+
chain: chain.chain,
|
|
25809
|
+
apiKey
|
|
25810
|
+
});
|
|
25811
|
+
if (statusResult.status === 'DONE' && statusResult.amountOut !== undefined) {
|
|
25812
|
+
return {
|
|
25813
|
+
progress: buildSwapProgress(statusResult),
|
|
25814
|
+
amountOut: statusResult.amountOut
|
|
25815
|
+
};
|
|
25816
|
+
}
|
|
25817
|
+
} catch {
|
|
25818
|
+
// Reachability/parse failure during enrichment — non-fatal; the swap
|
|
25819
|
+
// already succeeded on-chain. `getSwapStatus` already retried transient
|
|
25820
|
+
// network errors internally, so further polling is unlikely to help.
|
|
25524
25821
|
return {
|
|
25525
|
-
progress
|
|
25526
|
-
|
|
25822
|
+
progress: {
|
|
25823
|
+
status: 'DONE'
|
|
25824
|
+
}
|
|
25527
25825
|
};
|
|
25528
25826
|
}
|
|
25529
|
-
|
|
25530
|
-
|
|
25531
|
-
|
|
25532
|
-
|
|
25533
|
-
|
|
25534
|
-
|
|
25535
|
-
|
|
25536
|
-
|
|
25537
|
-
|
|
25538
|
-
|
|
25827
|
+
const delayMs = SAME_CHAIN_AMOUNT_OUT_POLL_DELAYS_MS[attempt];
|
|
25828
|
+
if (delayMs === undefined) {
|
|
25829
|
+
// Budget exhausted — terminal `DONE`, `amountOut` not yet available.
|
|
25830
|
+
return {
|
|
25831
|
+
progress: {
|
|
25832
|
+
status: 'DONE'
|
|
25833
|
+
}
|
|
25834
|
+
};
|
|
25835
|
+
}
|
|
25836
|
+
await sleep$3(delayMs);
|
|
25539
25837
|
}
|
|
25540
25838
|
}
|
|
25541
25839
|
/**
|
|
@@ -25816,7 +26114,7 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
25816
26114
|
return true;
|
|
25817
26115
|
}
|
|
25818
26116
|
// At least one token must be supported for fee collection
|
|
25819
|
-
return getSwapOkTokenStatus(tokenInAddress, tokenOutAddress, chain, TOKEN_REGISTRY, OK_TOKEN_SYMBOLS$1).hasOkToken;
|
|
26117
|
+
return getSwapOkTokenStatus(tokenInAddress, tokenOutAddress, chain, TOKEN_REGISTRY$1, OK_TOKEN_SYMBOLS$1).hasOkToken;
|
|
25820
26118
|
}
|
|
25821
26119
|
/**
|
|
25822
26120
|
* Estimate swap costs and output amount by delegating to the Stablecoin Service quote API.
|
|
@@ -26413,14 +26711,14 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
26413
26711
|
}
|
|
26414
26712
|
// Build swap fees with adapter-backed formatting for unregistered tokens
|
|
26415
26713
|
const swapResultFees = serviceResponse.fees ? await this.buildFormattedFees(serviceResponse.fees, chain, destinationChain, adapter, config?.customFee?.recipientAddress) : undefined;
|
|
26416
|
-
// Best-effort enrichment:
|
|
26417
|
-
//
|
|
26418
|
-
//
|
|
26419
|
-
//
|
|
26420
|
-
// destination mint takes minutes (CCTPv2 attestation),
|
|
26421
|
-
//
|
|
26422
|
-
//
|
|
26423
|
-
//
|
|
26714
|
+
// Best-effort enrichment: briefly poll for amountOut on same-chain swaps.
|
|
26715
|
+
// They complete atomically in the (already-confirmed) source tx, so the
|
|
26716
|
+
// result is terminal `DONE` regardless; the short poll only adds amountOut
|
|
26717
|
+
// once the service has resolved it. Cross-chain swaps are skipped because
|
|
26718
|
+
// the destination mint takes minutes (CCTPv2 attestation), so polling would
|
|
26719
|
+
// always return PENDING/WAIT_DESTINATION_TRANSACTION while burning the
|
|
26720
|
+
// budget. Callers should use `kit.getSwapStatus()` to poll cross-chain
|
|
26721
|
+
// swaps to DONE.
|
|
26424
26722
|
const statusSnapshot = await fetchSameChainStatusSnapshot({
|
|
26425
26723
|
isCrossChainSwap,
|
|
26426
26724
|
txHash,
|
|
@@ -30047,7 +30345,7 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
30047
30345
|
ESTIMATE: 'swap_estimate'
|
|
30048
30346
|
};
|
|
30049
30347
|
|
|
30050
|
-
/** SDK name used in telemetry payloads. */ const SDK_NAME$1 = resolveKitSdkName(pkg$
|
|
30348
|
+
/** SDK name used in telemetry payloads. */ const SDK_NAME$1 = resolveKitSdkName(pkg$3.name);
|
|
30051
30349
|
/**
|
|
30052
30350
|
* A high-level class-based interface for same-chain and cross-chain token swap operations.
|
|
30053
30351
|
*
|
|
@@ -30170,7 +30468,7 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
30170
30468
|
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
30171
30469
|
this.telemetryConfig = {
|
|
30172
30470
|
sdkName: SDK_NAME$1,
|
|
30173
|
-
sdkVersion: pkg$
|
|
30471
|
+
sdkVersion: pkg$3.version,
|
|
30174
30472
|
disabled: this.disableErrorReporting
|
|
30175
30473
|
};
|
|
30176
30474
|
}
|
|
@@ -30626,7 +30924,7 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
30626
30924
|
}
|
|
30627
30925
|
|
|
30628
30926
|
// Auto-register this kit for user agent tracking
|
|
30629
|
-
registerKit(`${pkg$
|
|
30927
|
+
registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
30630
30928
|
|
|
30631
30929
|
/**
|
|
30632
30930
|
* Create a SwapKit instance with optional developer fee configuration.
|
|
@@ -30721,12 +31019,15 @@ registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
|
30721
31019
|
return kit;
|
|
30722
31020
|
};
|
|
30723
31021
|
|
|
30724
|
-
var name$
|
|
30725
|
-
var version$
|
|
30726
|
-
var pkg$
|
|
30727
|
-
name: name$
|
|
30728
|
-
version: version$
|
|
31022
|
+
var name$2 = "@circle-fin/earn-kit";
|
|
31023
|
+
var version$2 = "1.2.2";
|
|
31024
|
+
var pkg$2 = {
|
|
31025
|
+
name: name$2,
|
|
31026
|
+
version: version$2};
|
|
30729
31027
|
|
|
31028
|
+
const EARN_BRIDGE_ERC3009_TOKEN_SYMBOLS = [
|
|
31029
|
+
'USDC'
|
|
31030
|
+
];
|
|
30730
31031
|
/**
|
|
30731
31032
|
* Default base URL for the Earn Service API.
|
|
30732
31033
|
*
|
|
@@ -30771,20 +31072,7 @@ var pkg$1 = {
|
|
|
30771
31072
|
*/ const EARN_BRIDGE_DESTINATION_CHAIN_TO_API = {
|
|
30772
31073
|
[exports.Blockchain.Arc_Testnet]: CHAIN_TO_API[exports.Blockchain.Arc_Testnet]
|
|
30773
31074
|
};
|
|
30774
|
-
|
|
30775
|
-
* Expected EIP-712 domain of the ERC-3009 authorization token per source
|
|
30776
|
-
* chain.
|
|
30777
|
-
*
|
|
30778
|
-
* Cross-chain Earn deposits are USDC-only, but USDC deployments differ on the
|
|
30779
|
-
* EIP-712 domain name: newer deployments use `USDC` while older ones (for
|
|
30780
|
-
* example Arbitrum Sepolia) kept `USD Coin` from the FiatToken V2 upgrade.
|
|
30781
|
-
* These values mirror the bridge service's per-chain domain table and the
|
|
30782
|
-
* on-chain `DOMAIN_SEPARATOR` inputs. Asserted before signing so a tampered
|
|
30783
|
-
* prepare response cannot point the signature at another token. The
|
|
30784
|
-
* `satisfies` check forces a domain entry whenever a source chain is added.
|
|
30785
|
-
*
|
|
30786
|
-
* @internal
|
|
30787
|
-
*/ const EARN_BRIDGE_ERC3009_DOMAINS = {
|
|
31075
|
+
const EARN_BRIDGE_USDC_ERC3009_DOMAINS = {
|
|
30788
31076
|
[exports.Blockchain.Arbitrum_Sepolia]: {
|
|
30789
31077
|
name: 'USD Coin',
|
|
30790
31078
|
version: '2'
|
|
@@ -30798,6 +31086,21 @@ var pkg$1 = {
|
|
|
30798
31086
|
version: '2'
|
|
30799
31087
|
}
|
|
30800
31088
|
};
|
|
31089
|
+
/**
|
|
31090
|
+
* Expected EIP-712 domain of the ERC-3009 authorization token per
|
|
31091
|
+
* cross-chain-supported source token and source chain.
|
|
31092
|
+
*
|
|
31093
|
+
* The bridge service prepares an ERC-3009 payload for the deposited token. We
|
|
31094
|
+
* keep this table as an explicit SDK allowlist because token deployments can
|
|
31095
|
+
* differ by source chain and by domain name/version. These values mirror the
|
|
31096
|
+
* bridge service's per-chain domain table and the on-chain DOMAIN_SEPARATOR
|
|
31097
|
+
* inputs. Asserted before signing so a tampered prepare response cannot point
|
|
31098
|
+
* the signature at another token or unexpected token domain.
|
|
31099
|
+
*
|
|
31100
|
+
* @internal
|
|
31101
|
+
*/ const EARN_BRIDGE_ERC3009_DOMAINS = {
|
|
31102
|
+
USDC: EARN_BRIDGE_USDC_ERC3009_DOMAINS
|
|
31103
|
+
};
|
|
30801
31104
|
/**
|
|
30802
31105
|
* Maximum tolerated remaining lifetime of a prepared ERC-3009 authorization.
|
|
30803
31106
|
*
|
|
@@ -31257,6 +31560,16 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
31257
31560
|
return approvalTxHash;
|
|
31258
31561
|
}
|
|
31259
31562
|
|
|
31563
|
+
/** @internal */ function isSameAddress(actual, expected) {
|
|
31564
|
+
return actual.toLowerCase() === expected.toLowerCase();
|
|
31565
|
+
}
|
|
31566
|
+
/** @internal */ function assertDecimalPlaces(field, value, tokenDecimals, reason) {
|
|
31567
|
+
const decimals = value.split('.')[1]?.length ?? 0;
|
|
31568
|
+
if (decimals > tokenDecimals) {
|
|
31569
|
+
throw createValidationFailedError$1(field, value, reason);
|
|
31570
|
+
}
|
|
31571
|
+
}
|
|
31572
|
+
|
|
31260
31573
|
/**
|
|
31261
31574
|
* Build the `tokenInputs` array forwarded to the adapter contract's
|
|
31262
31575
|
* `execute(executeParams, tokenInputs, signature)` call.
|
|
@@ -31280,15 +31593,17 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
31280
31593
|
*
|
|
31281
31594
|
* @example
|
|
31282
31595
|
* ```typescript
|
|
31283
|
-
* const
|
|
31284
|
-
* 'chain.usdcAddress',
|
|
31285
|
-
* chain.usdcAddress,
|
|
31286
|
-
* )
|
|
31287
|
-
*
|
|
31288
|
-
* const tokenInputs = buildEarnTokenInputs(
|
|
31596
|
+
* const approvalToken = resolveEarnApprovalToken(
|
|
31289
31597
|
* executionPayload.executionParams,
|
|
31290
|
-
* approvedToken,
|
|
31291
31598
|
* )
|
|
31599
|
+
*
|
|
31600
|
+
* const tokenInputs =
|
|
31601
|
+
* approvalToken === undefined
|
|
31602
|
+
* ? []
|
|
31603
|
+
* : buildEarnTokenInputs(
|
|
31604
|
+
* executionPayload.executionParams,
|
|
31605
|
+
* approvalToken,
|
|
31606
|
+
* )
|
|
31292
31607
|
* ```
|
|
31293
31608
|
*
|
|
31294
31609
|
* @internal
|
|
@@ -31300,7 +31615,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
31300
31615
|
return;
|
|
31301
31616
|
}
|
|
31302
31617
|
const { tokenIn } = instruction;
|
|
31303
|
-
if (tokenIn
|
|
31618
|
+
if (!isSameAddress(tokenIn, approvedToken)) {
|
|
31304
31619
|
throw createValidationFailedError$1(`executionParams.instructions[${index.toString()}].tokenIn`, tokenIn, 'tokenIn must match the token approved for adapter spending');
|
|
31305
31620
|
}
|
|
31306
31621
|
tokenInputs.push({
|
|
@@ -31312,6 +31627,33 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
31312
31627
|
});
|
|
31313
31628
|
return tokenInputs;
|
|
31314
31629
|
}
|
|
31630
|
+
/**
|
|
31631
|
+
* Resolve the single token that needs adapter allowance from signed Earn
|
|
31632
|
+
* instructions.
|
|
31633
|
+
*
|
|
31634
|
+
* @param executionParams - Service-signed `ExecutionParams` forwarded to the adapter.
|
|
31635
|
+
* @returns The token requested by positive approval instructions, or `undefined`.
|
|
31636
|
+
* @throws {@link KitError} If positive approval instructions reference multiple tokens.
|
|
31637
|
+
*
|
|
31638
|
+
* @internal
|
|
31639
|
+
*/ function resolveEarnApprovalToken(executionParams) {
|
|
31640
|
+
let approvedToken;
|
|
31641
|
+
executionParams.instructions.forEach((instruction, index)=>{
|
|
31642
|
+
const amount = BigInt(instruction.amountToApprove);
|
|
31643
|
+
if (amount <= 0n) {
|
|
31644
|
+
return;
|
|
31645
|
+
}
|
|
31646
|
+
const { tokenIn } = instruction;
|
|
31647
|
+
if (approvedToken === undefined) {
|
|
31648
|
+
approvedToken = tokenIn;
|
|
31649
|
+
return;
|
|
31650
|
+
}
|
|
31651
|
+
if (!isSameAddress(tokenIn, approvedToken)) {
|
|
31652
|
+
throw createValidationFailedError$1(`executionParams.instructions[${index.toString()}].tokenIn`, tokenIn, 'tokenIn must match the token approved for adapter spending');
|
|
31653
|
+
}
|
|
31654
|
+
});
|
|
31655
|
+
return approvedToken;
|
|
31656
|
+
}
|
|
31315
31657
|
|
|
31316
31658
|
/**
|
|
31317
31659
|
* Prepare an earn adapter action, execute it, wait for confirmation, and
|
|
@@ -31803,6 +32145,7 @@ const hexSignatureSchema = evmSignatureSchema;
|
|
|
31803
32145
|
const hexAddressSchema = evmAddressSchema;
|
|
31804
32146
|
// '0x' prefix + 32 bytes * 2 hex chars.
|
|
31805
32147
|
const BYTES32_HEX_LENGTH = 66;
|
|
32148
|
+
const bridgeFeeTokenSchema = hexAddressSchema;
|
|
31806
32149
|
/**
|
|
31807
32150
|
* Zod schema for a non-negative uint256-like value.
|
|
31808
32151
|
*
|
|
@@ -32089,14 +32432,12 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32089
32432
|
*
|
|
32090
32433
|
* The bridge prepare path returns one item per collected source fee (e.g.
|
|
32091
32434
|
* `PRE_FINALITY` for the fast-burn fee and `FORWARD` for the destination
|
|
32092
|
-
* forward fee), all denominated in the shared `feeToken`.
|
|
32093
|
-
*
|
|
32094
|
-
* guard parses these to recompute the expected value. Each item's `amount` is
|
|
32095
|
-
* a base-unit decimal string in `feeToken` units.
|
|
32435
|
+
* forward fee), all denominated in the shared `feeToken`. Each item's `amount`
|
|
32436
|
+
* is a base-unit decimal string in `feeToken` units.
|
|
32096
32437
|
*
|
|
32097
32438
|
* @internal
|
|
32098
32439
|
*/ const bridgeFeeQuoteSchema = zod.z.object({
|
|
32099
|
-
feeToken:
|
|
32440
|
+
feeToken: bridgeFeeTokenSchema,
|
|
32100
32441
|
items: zod.z.array(zod.z.object({
|
|
32101
32442
|
type: zod.z.string(),
|
|
32102
32443
|
amount: uint256LikeSchema
|
|
@@ -32112,6 +32453,12 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32112
32453
|
erc3009TypedData: erc3009TypedDataSchema,
|
|
32113
32454
|
feeQuote: bridgeFeeQuoteSchema
|
|
32114
32455
|
}).passthrough();
|
|
32456
|
+
const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
32457
|
+
sourceChain: zod.z.string(),
|
|
32458
|
+
destinationChain: zod.z.string(),
|
|
32459
|
+
amount: amountJsonSchema,
|
|
32460
|
+
vaultAddress: hexAddressSchema
|
|
32461
|
+
}).passthrough();
|
|
32115
32462
|
/**
|
|
32116
32463
|
* Zod schema for the bridge deposit prepare payload.
|
|
32117
32464
|
*
|
|
@@ -32123,7 +32470,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32123
32470
|
execId: bridgeDepositExecIdSchema,
|
|
32124
32471
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
32125
32472
|
expiresAt: zod.z.string().datetime(),
|
|
32126
|
-
review:
|
|
32473
|
+
review: bridgeDepositPrepareReviewSchema
|
|
32127
32474
|
});
|
|
32128
32475
|
/**
|
|
32129
32476
|
* Zod schema for the `POST /v1/earnKit/bridge/deposit/prepare` API response.
|
|
@@ -32248,10 +32595,11 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32248
32595
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
32249
32596
|
*
|
|
32250
32597
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
32251
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
32252
|
-
*
|
|
32253
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
32254
|
-
* `'
|
|
32598
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
32599
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
32600
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
32601
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
32602
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
32255
32603
|
*
|
|
32256
32604
|
* @internal
|
|
32257
32605
|
*/ const feeSchema = zod.z.object({
|
|
@@ -32523,6 +32871,60 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32523
32871
|
return claimRewardsQuoteResponseSchema.safeParse(value).success;
|
|
32524
32872
|
}
|
|
32525
32873
|
|
|
32874
|
+
var name$1 = "@circle-fin/provider-earn-service";
|
|
32875
|
+
var version$1 = "1.2.2";
|
|
32876
|
+
var pkg$1 = {
|
|
32877
|
+
name: name$1,
|
|
32878
|
+
version: version$1};
|
|
32879
|
+
|
|
32880
|
+
/**
|
|
32881
|
+
* HTTP header name used to report the EarnKit SDK version to the backend.
|
|
32882
|
+
*
|
|
32883
|
+
* @internal
|
|
32884
|
+
*/ const SDK_VERSION_HEADER = 'X-EarnKit-SDK-Version';
|
|
32885
|
+
/**
|
|
32886
|
+
* Resolve the SDK version string from its source components.
|
|
32887
|
+
*
|
|
32888
|
+
* Resolution order:
|
|
32889
|
+
* 1. The registered kit identifier (preferred) — e.g. `@circle-fin/earn-kit/1.1.0`
|
|
32890
|
+
* becomes `earn-kit/1.1.0`.
|
|
32891
|
+
* 2. The provider package itself (fallback when no kit is registered) —
|
|
32892
|
+
* e.g. `provider-earn-service/1.1.0`.
|
|
32893
|
+
* 3. The literal `unknown` when neither source is available.
|
|
32894
|
+
*
|
|
32895
|
+
* Kept as a pure function (no global / module reads) so every branch is
|
|
32896
|
+
* unit-testable.
|
|
32897
|
+
*
|
|
32898
|
+
* @param kitId - The registered kit identifier, or `undefined`.
|
|
32899
|
+
* @param providerName - The provider package name (e.g. `@circle-fin/provider-earn-service`).
|
|
32900
|
+
* @param providerVersion - The provider package version, or `undefined`.
|
|
32901
|
+
* @returns The formatted SDK version string.
|
|
32902
|
+
*
|
|
32903
|
+
* @internal
|
|
32904
|
+
*/ function formatSdkVersion(kitId, providerName, providerVersion) {
|
|
32905
|
+
if (kitId !== undefined && kitId !== '') {
|
|
32906
|
+
// e.g. '@circle-fin/earn-kit/1.1.0' -> 'earn-kit/1.1.0'
|
|
32907
|
+
return resolveKitSdkName(kitId);
|
|
32908
|
+
}
|
|
32909
|
+
{
|
|
32910
|
+
// e.g. '@circle-fin/provider-earn-service' + '1.1.0' -> 'provider-earn-service/1.1.0'
|
|
32911
|
+
return `${resolveKitSdkName(providerName)}/${providerVersion}`;
|
|
32912
|
+
}
|
|
32913
|
+
}
|
|
32914
|
+
/**
|
|
32915
|
+
* Resolve the value for the {@link SDK_VERSION_HEADER} header.
|
|
32916
|
+
*
|
|
32917
|
+
* Reads the kit registered at runtime via {@link createRequestContext} and
|
|
32918
|
+
* falls back to this provider package's own version when no kit is registered.
|
|
32919
|
+
*
|
|
32920
|
+
* @returns The SDK version string, e.g. `earn-kit/1.1.0` or
|
|
32921
|
+
* `provider-earn-service/1.1.0`, or `unknown`.
|
|
32922
|
+
*
|
|
32923
|
+
* @internal
|
|
32924
|
+
*/ function resolveSdkVersionHeader() {
|
|
32925
|
+
return formatSdkVersion(createRequestContext().kit, pkg$1.name, pkg$1.version);
|
|
32926
|
+
}
|
|
32927
|
+
|
|
32526
32928
|
/**
|
|
32527
32929
|
* Build an API polling config with optional authorization header,
|
|
32528
32930
|
* and resolve the base URL (configurable for testing).
|
|
@@ -32533,9 +32935,16 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32533
32935
|
* @internal
|
|
32534
32936
|
*/ function buildConfig(serviceConfig) {
|
|
32535
32937
|
const baseUrl = serviceConfig?.baseUrl ?? EARN_SERVICE_BASE_URL;
|
|
32938
|
+
const sdkVersion = resolveSdkVersionHeader();
|
|
32536
32939
|
if (serviceConfig?.kitKey === undefined) {
|
|
32537
32940
|
return {
|
|
32538
|
-
pollingConfig:
|
|
32941
|
+
pollingConfig: {
|
|
32942
|
+
...DEFAULT_CONFIG,
|
|
32943
|
+
headers: {
|
|
32944
|
+
...DEFAULT_CONFIG.headers,
|
|
32945
|
+
[SDK_VERSION_HEADER]: sdkVersion
|
|
32946
|
+
}
|
|
32947
|
+
},
|
|
32539
32948
|
baseUrl
|
|
32540
32949
|
};
|
|
32541
32950
|
}
|
|
@@ -32551,6 +32960,7 @@ const eip712DomainSchema = eip712DomainSchema$1.extend({
|
|
|
32551
32960
|
...DEFAULT_CONFIG,
|
|
32552
32961
|
headers: {
|
|
32553
32962
|
...DEFAULT_CONFIG.headers,
|
|
32963
|
+
[SDK_VERSION_HEADER]: sdkVersion,
|
|
32554
32964
|
Authorization: `Bearer ${serviceConfig.kitKey}`
|
|
32555
32965
|
}
|
|
32556
32966
|
},
|
|
@@ -32851,7 +33261,8 @@ function toPositionInfo(data) {
|
|
|
32851
33261
|
return {
|
|
32852
33262
|
execId: response.data.execId,
|
|
32853
33263
|
preparedBundle,
|
|
32854
|
-
expiresAt: response.data.expiresAt
|
|
33264
|
+
expiresAt: response.data.expiresAt,
|
|
33265
|
+
review: response.data.review
|
|
32855
33266
|
};
|
|
32856
33267
|
} catch (error) {
|
|
32857
33268
|
throw parseEarnApiError(error, {
|
|
@@ -32962,47 +33373,34 @@ const VALID_AFTER_CLOCK_SKEW_SECONDS = 60n;
|
|
|
32962
33373
|
* @throws If any typed-data field does not match the expected bridge deposit intent.
|
|
32963
33374
|
* @internal
|
|
32964
33375
|
*/ function assertBridgeDepositTypedDataMatchesIntent(intent) {
|
|
32965
|
-
const { preparedBundle, sourceChain, sourceAddress, sourceTokenAddress, authorizationRecipient, amount, maxFee, tokenDecimals, nowSeconds = BigInt(Math.floor(Date.now() / 1000)) } = intent;
|
|
33376
|
+
const { preparedBundle, sourceChain, sourceAddress, sourceTokenAddress, expectedDomain, authorizationRecipient, amount, maxFee, tokenDecimals, amountRaw, nowSeconds = BigInt(Math.floor(Date.now() / 1000)) } = intent;
|
|
32966
33377
|
const { domain, message } = preparedBundle.erc3009TypedData;
|
|
32967
|
-
// USDC deployments differ on the EIP-712 domain name per chain, so the
|
|
32968
|
-
// expected domain is looked up for the source chain being signed on.
|
|
32969
|
-
const expectedDomain = EARN_BRIDGE_ERC3009_DOMAINS[sourceChain.chain];
|
|
32970
|
-
if (expectedDomain === undefined) {
|
|
32971
|
-
throw createValidationFailedError$1('sourceChain.chain', sourceChain.chain, 'no expected ERC-3009 domain is configured for the source chain');
|
|
32972
|
-
}
|
|
32973
|
-
if (domain.name !== expectedDomain.name) {
|
|
32974
|
-
throw createValidationFailedError$1('preparedBundle.erc3009TypedData.domain.name', domain.name, `domain name must be ${expectedDomain.name}`);
|
|
32975
|
-
}
|
|
32976
|
-
if (domain.version !== expectedDomain.version) {
|
|
32977
|
-
throw createValidationFailedError$1('preparedBundle.erc3009TypedData.domain.version', domain.version, `domain version must be ${expectedDomain.version}`);
|
|
32978
|
-
}
|
|
32979
33378
|
assertSameAddress('preparedBundle.erc3009TypedData.domain.verifyingContract', domain.verifyingContract, sourceTokenAddress, 'verifyingContract must match the source token contract');
|
|
32980
33379
|
assertSameBigInt('preparedBundle.erc3009TypedData.domain.chainId', domain.chainId, BigInt(sourceChain.chainId), 'chainId must match the source chain');
|
|
33380
|
+
assertSameString('preparedBundle.erc3009TypedData.domain.name', domain.name, expectedDomain.name, 'domain name must match the source token');
|
|
33381
|
+
assertSameString('preparedBundle.erc3009TypedData.domain.version', domain.version, expectedDomain.version, 'domain version must match the source token');
|
|
32981
33382
|
assertSameAddress('preparedBundle.erc3009TypedData.message.from', message.from, sourceAddress, 'from must match the source wallet');
|
|
32982
33383
|
assertSameAddress('preparedBundle.erc3009TypedData.message.to', message.to, authorizationRecipient, 'to must match the configured authorization recipient');
|
|
32983
|
-
//
|
|
32984
|
-
//
|
|
32985
|
-
|
|
32986
|
-
|
|
32987
|
-
// token to the source token contract before summing.
|
|
32988
|
-
assertSameAddress('preparedBundle.feeQuote.feeToken', preparedBundle.feeQuote.feeToken, sourceTokenAddress, 'feeQuote.feeToken must match the source token contract');
|
|
32989
|
-
// Recompute the expected value from locally trusted inputs (the caller
|
|
32990
|
-
// principal) plus the bundle's own fee items so the guard accepts fee-bearing
|
|
32991
|
-
// deposits while still rejecting any other value tampering. The fee quote is
|
|
32992
|
-
// service-supplied, so bound it to the caller-accepted quote-derived cap
|
|
32993
|
-
// before including it in the signed value.
|
|
32994
|
-
const principal = Amount.parse(amount, {
|
|
33384
|
+
// Recompute the expected ERC-3009 value from locally trusted inputs. Bridge
|
|
33385
|
+
// source fees are paid in the source ERC-20 and are part of the authorization.
|
|
33386
|
+
assertDecimalPlaces('amount', amount, tokenDecimals, `amount must have at most ${String(tokenDecimals)} decimal places for the cross-chain Earn deposit source token`);
|
|
33387
|
+
const parsedAmount = Amount.parse(amount, {
|
|
32995
33388
|
decimals: tokenDecimals
|
|
32996
33389
|
}).raw;
|
|
33390
|
+
const principal = amountRaw === undefined ? parsedAmount : parseReviewedAmount(amountRaw, parsedAmount);
|
|
33391
|
+
const feeQuote = preparedBundle.feeQuote;
|
|
32997
33392
|
const feeTotal = sumBridgeFeeItems(preparedBundle.feeQuote);
|
|
33393
|
+
assertFeeTokenMatchesSourceToken(feeQuote.feeToken, sourceTokenAddress);
|
|
33394
|
+
const feeDecimals = tokenDecimals;
|
|
33395
|
+
assertDecimalPlaces('maxFee', maxFee, feeDecimals, `maxFee must have at most ${String(feeDecimals)} decimal places for the cross-chain Earn deposit fee token`);
|
|
32998
33396
|
const maxFeeRaw = Amount.parse(maxFee, {
|
|
32999
|
-
decimals:
|
|
33397
|
+
decimals: feeDecimals
|
|
33000
33398
|
}).raw;
|
|
33001
33399
|
if (feeTotal > maxFeeRaw) {
|
|
33002
33400
|
throw createValidationFailedError$1('preparedBundle.feeQuote.items', feeTotal.toString(), 'fee total must not exceed maxFee in base units');
|
|
33003
33401
|
}
|
|
33004
33402
|
const expectedValue = principal + feeTotal;
|
|
33005
|
-
assertSameBigInt('preparedBundle.erc3009TypedData.message.value', message.value, expectedValue, 'value must match the requested amount plus
|
|
33403
|
+
assertSameBigInt('preparedBundle.erc3009TypedData.message.value', message.value, expectedValue, 'value must match the requested amount plus source-token fees in base units');
|
|
33006
33404
|
const window = checkErc3009ValidityWindow({
|
|
33007
33405
|
validAfter: BigInt(message.validAfter),
|
|
33008
33406
|
validBefore: BigInt(message.validBefore),
|
|
@@ -33076,14 +33474,19 @@ const VALID_AFTER_CLOCK_SKEW_SECONDS = 60n;
|
|
|
33076
33474
|
/**
|
|
33077
33475
|
* Sum the source-collected fee items in a prepared bundle's fee quote.
|
|
33078
33476
|
*
|
|
33079
|
-
* Each item amount is a base-unit value in the shared `feeToken
|
|
33080
|
-
* what the prepare path adds to the principal when building `message.value`.
|
|
33477
|
+
* Each item amount is a base-unit value in the shared `feeToken`.
|
|
33081
33478
|
*
|
|
33082
33479
|
* @param feeQuote - Fee quote parsed from the prepared bundle.
|
|
33083
|
-
* @returns Total fee in
|
|
33480
|
+
* @returns Total fee in fee-token base units (0n when there are no items).
|
|
33084
33481
|
*/ function sumBridgeFeeItems(feeQuote) {
|
|
33085
33482
|
return feeQuote.items.reduce((total, item)=>total + BigInt(item.amount), 0n);
|
|
33086
33483
|
}
|
|
33484
|
+
function assertFeeTokenMatchesSourceToken(feeToken, sourceTokenAddress) {
|
|
33485
|
+
if (isSameAddress(feeToken, sourceTokenAddress)) {
|
|
33486
|
+
return;
|
|
33487
|
+
}
|
|
33488
|
+
throw createValidationFailedError$1('preparedBundle.feeQuote.feeToken', feeToken, 'fee token must match the cross-chain Earn deposit source token');
|
|
33489
|
+
}
|
|
33087
33490
|
function assertNever(value) {
|
|
33088
33491
|
throw new KitError({
|
|
33089
33492
|
...EarnError.INTERNAL_ERROR,
|
|
@@ -33091,8 +33494,23 @@ function assertNever(value) {
|
|
|
33091
33494
|
message: `Unexpected validity window reason: ${String(value)}`
|
|
33092
33495
|
});
|
|
33093
33496
|
}
|
|
33497
|
+
function parseReviewedAmount(amountRaw, parsedAmount) {
|
|
33498
|
+
let reviewedAmount;
|
|
33499
|
+
try {
|
|
33500
|
+
reviewedAmount = BigInt(amountRaw);
|
|
33501
|
+
} catch {
|
|
33502
|
+
throw createValidationFailedError$1('prepared.review.amount.raw', amountRaw, 'amount must be a non-negative integer string');
|
|
33503
|
+
}
|
|
33504
|
+
if (reviewedAmount < 0n) {
|
|
33505
|
+
throw createValidationFailedError$1('prepared.review.amount.raw', amountRaw, 'amount must be a non-negative integer string');
|
|
33506
|
+
}
|
|
33507
|
+
if (reviewedAmount !== parsedAmount) {
|
|
33508
|
+
throw createValidationFailedError$1('prepared.review.amount.raw', amountRaw, 'review amount must match the requested amount');
|
|
33509
|
+
}
|
|
33510
|
+
return reviewedAmount;
|
|
33511
|
+
}
|
|
33094
33512
|
function assertSameAddress(field, actual, expected, reason) {
|
|
33095
|
-
if (actual
|
|
33513
|
+
if (!isSameAddress(actual, expected)) {
|
|
33096
33514
|
throw createValidationFailedError$1(field, actual, reason);
|
|
33097
33515
|
}
|
|
33098
33516
|
}
|
|
@@ -33101,6 +33519,11 @@ function assertSameBigInt(field, actual, expected, reason) {
|
|
|
33101
33519
|
throw createValidationFailedError$1(field, actual, reason);
|
|
33102
33520
|
}
|
|
33103
33521
|
}
|
|
33522
|
+
function assertSameString(field, actual, expected, reason) {
|
|
33523
|
+
if (actual !== expected) {
|
|
33524
|
+
throw createValidationFailedError$1(field, actual, reason);
|
|
33525
|
+
}
|
|
33526
|
+
}
|
|
33104
33527
|
|
|
33105
33528
|
/**
|
|
33106
33529
|
* Build signed withdrawal instructions via the Earn Service API.
|
|
@@ -33270,9 +33693,15 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
33270
33693
|
symbol: data.asset,
|
|
33271
33694
|
amount: Amount.fromJSON(data.maxWithdrawable)
|
|
33272
33695
|
},
|
|
33273
|
-
fees: data.fees.map((
|
|
33274
|
-
symbol:
|
|
33275
|
-
amount: Amount.fromJSON(
|
|
33696
|
+
fees: data.fees.map(({ token, amount, type, status })=>({
|
|
33697
|
+
symbol: token,
|
|
33698
|
+
amount: Amount.fromJSON(amount),
|
|
33699
|
+
...type !== undefined && {
|
|
33700
|
+
type
|
|
33701
|
+
},
|
|
33702
|
+
...status !== undefined && {
|
|
33703
|
+
status
|
|
33704
|
+
}
|
|
33276
33705
|
})),
|
|
33277
33706
|
gasFees: [],
|
|
33278
33707
|
// Wire format uses `warnings`, but the SDK surface uses
|
|
@@ -33458,6 +33887,9 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
33458
33887
|
'CONFIRMED',
|
|
33459
33888
|
'COMPLETE'
|
|
33460
33889
|
]);
|
|
33890
|
+
// Intentionally built-ins-only: Earn bridge support is limited to SDK-known
|
|
33891
|
+
// token contracts plus the explicit ERC-3009 domain allowlist below.
|
|
33892
|
+
const TOKEN_REGISTRY = createTokenRegistry();
|
|
33461
33893
|
/**
|
|
33462
33894
|
* Build the typed error raised when a cross-chain wait is cancelled via its
|
|
33463
33895
|
* `AbortSignal`. Mirrors `@core/adapter-base`'s `createAbortError` (same
|
|
@@ -33787,24 +34219,20 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
33787
34219
|
}
|
|
33788
34220
|
const { address, chain: apiChain, chainDefinition: chain } = await resolveAdapterContext(params.from);
|
|
33789
34221
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
33790
|
-
const rawUsdcAddress = chain.usdcAddress;
|
|
33791
|
-
if (rawUsdcAddress === null) {
|
|
33792
|
-
throw createUnsupportedTokenError('USDC', chain.name);
|
|
33793
|
-
}
|
|
33794
|
-
const usdcAddress = assertHexAddress('chain.usdcAddress', rawUsdcAddress, `USDC address for chain ${chain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
33795
34222
|
const { adapter } = params.from;
|
|
34223
|
+
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
33796
34224
|
const { executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
33797
|
-
vaultAddress
|
|
34225
|
+
vaultAddress,
|
|
33798
34226
|
amount: params.amount,
|
|
33799
34227
|
address,
|
|
33800
34228
|
chain: apiChain,
|
|
33801
34229
|
config
|
|
33802
34230
|
}), ()=>undefined);
|
|
33803
34231
|
validateExecutionDeadline(executionParams);
|
|
33804
|
-
const
|
|
33805
|
-
const
|
|
34232
|
+
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
34233
|
+
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
33806
34234
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
33807
|
-
if (!options.skipApprove && approvalToken !== undefined) {
|
|
34235
|
+
if (!options.skipApprove && approvalToken !== undefined && requiredAllowance > 0n) {
|
|
33808
34236
|
await this.runPhase(ctx, 'approve', 'approve', async ()=>approveAllowanceIfNeeded({
|
|
33809
34237
|
adapter,
|
|
33810
34238
|
chain,
|
|
@@ -33812,7 +34240,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
33812
34240
|
delegate: adapterContractAddress,
|
|
33813
34241
|
address,
|
|
33814
34242
|
requiredAllowance,
|
|
33815
|
-
revertMessage: '
|
|
34243
|
+
revertMessage: 'Earn deposit token approval reverted on-chain'
|
|
33816
34244
|
}), (txHash)=>txHash);
|
|
33817
34245
|
}
|
|
33818
34246
|
const { txHash, explorerUrl } = await this.runPhase(ctx, 'deposit', 'execute', async ()=>executeEarnAction({
|
|
@@ -33831,7 +34259,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
33831
34259
|
kind: 'same-chain',
|
|
33832
34260
|
txHash,
|
|
33833
34261
|
explorerUrl,
|
|
33834
|
-
vaultAddress
|
|
34262
|
+
vaultAddress,
|
|
33835
34263
|
amount: params.amount
|
|
33836
34264
|
};
|
|
33837
34265
|
} catch (error) {
|
|
@@ -33853,13 +34281,6 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
33853
34281
|
const sourceAddress = assertHexAddress('from.address', await resolveCrossChainSourceAddress(params.from, sourceChain), `Source address for chain ${sourceChain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
33854
34282
|
const destinationAddress = assertHexAddress('to.recipientAddress', params.to.recipientAddress, `Destination address for chain ${destinationChain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
33855
34283
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
33856
|
-
// The signed ERC-3009 value is denominated in USDC's 6 decimals. More
|
|
33857
|
-
// precise inputs would be silently truncated by Amount.parse, so the
|
|
33858
|
-
// result would claim a larger deposit than was actually authorized.
|
|
33859
|
-
const amountDecimals = params.amount.split('.')[1]?.length ?? 0;
|
|
33860
|
-
if (amountDecimals > TOKEN_DECIMALS_6) {
|
|
33861
|
-
throw createValidationFailedError$1('amount', params.amount, `amount must have at most ${String(TOKEN_DECIMALS_6)} decimal places for cross-chain Earn deposits`);
|
|
33862
|
-
}
|
|
33863
34284
|
const execId = params.idempotencyKey;
|
|
33864
34285
|
const prepared = await this.runPhase(ctx, 'crossChainDeposit', 'prepare', async ()=>fetchBridgeDepositPrepare({
|
|
33865
34286
|
execId,
|
|
@@ -33879,17 +34300,19 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
33879
34300
|
// the error trace, instead of ending the event stream unannounced
|
|
33880
34301
|
// after the prepare success event.
|
|
33881
34302
|
assertPreparedBundleMatchesTypedDataNonce(prepared.preparedBundle);
|
|
34303
|
+
const sourceToken = resolvePreparedBridgeSourceToken(prepared.preparedBundle, route.sourceChain);
|
|
34304
|
+
validatePreparedReviewAmountDecimals(prepared.review.amount.decimals, sourceToken.decimals);
|
|
33882
34305
|
assertBridgeDepositTypedDataMatchesIntent({
|
|
33883
34306
|
preparedBundle: prepared.preparedBundle,
|
|
33884
34307
|
sourceChain: route.sourceChain,
|
|
33885
34308
|
sourceAddress,
|
|
33886
|
-
sourceTokenAddress:
|
|
34309
|
+
sourceTokenAddress: sourceToken.address,
|
|
34310
|
+
expectedDomain: sourceToken.erc3009Domain,
|
|
33887
34311
|
authorizationRecipient: route.authorizationRecipient,
|
|
33888
34312
|
amount: params.amount,
|
|
33889
34313
|
maxFee: params.maxFee,
|
|
33890
|
-
|
|
33891
|
-
|
|
33892
|
-
tokenDecimals: TOKEN_DECIMALS_6
|
|
34314
|
+
tokenDecimals: sourceToken.decimals,
|
|
34315
|
+
amountRaw: prepared.review.amount.raw
|
|
33893
34316
|
});
|
|
33894
34317
|
return signBridgeDepositAuthorization({
|
|
33895
34318
|
adapter: bridgeSigningAdapter,
|
|
@@ -34112,21 +34535,17 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
34112
34535
|
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
34113
34536
|
try {
|
|
34114
34537
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
34115
|
-
const
|
|
34116
|
-
if (rawUsdcAddress === null) {
|
|
34117
|
-
throw createUnsupportedTokenError('USDC', chain.name);
|
|
34118
|
-
}
|
|
34119
|
-
const usdcAddress = assertHexAddress('chain.usdcAddress', rawUsdcAddress, `USDC address for chain ${chain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
34538
|
+
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
34120
34539
|
const { executionParams, signature } = await fetchDeposit({
|
|
34121
|
-
vaultAddress,
|
|
34540
|
+
vaultAddress: normalizedVaultAddress,
|
|
34122
34541
|
amount,
|
|
34123
34542
|
address,
|
|
34124
34543
|
chain: apiChain,
|
|
34125
34544
|
config
|
|
34126
34545
|
});
|
|
34127
34546
|
validateExecutionDeadline(executionParams);
|
|
34128
|
-
const
|
|
34129
|
-
const
|
|
34547
|
+
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
34548
|
+
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
34130
34549
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
34131
34550
|
return await estimateEarnQuoteGasFees({
|
|
34132
34551
|
adapter,
|
|
@@ -34139,7 +34558,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
34139
34558
|
tokenInputs,
|
|
34140
34559
|
signature
|
|
34141
34560
|
},
|
|
34142
|
-
approval: approvalToken !== undefined ? {
|
|
34561
|
+
approval: approvalToken !== undefined && requiredAllowance > 0n ? {
|
|
34143
34562
|
token: approvalToken,
|
|
34144
34563
|
delegate: adapterContractAddress,
|
|
34145
34564
|
requiredAllowance
|
|
@@ -34383,11 +34802,6 @@ function validateCrossChainDepositRoute(sourceChain, destinationChain) {
|
|
|
34383
34802
|
if (destinationApiChain === undefined) {
|
|
34384
34803
|
throw createUnsupportedCrossChainDepositError(destinationChain, 'destination chain is not enabled for cross-chain Earn deposits');
|
|
34385
34804
|
}
|
|
34386
|
-
const sourceTokenAddressRaw = sourceChain.usdcAddress;
|
|
34387
|
-
if (sourceTokenAddressRaw === null) {
|
|
34388
|
-
throw createUnsupportedTokenError('USDC', sourceChain.name);
|
|
34389
|
-
}
|
|
34390
|
-
const sourceTokenAddress = assertHexAddress('sourceChain.usdcAddress', sourceTokenAddressRaw, `USDC address for chain ${sourceChain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
34391
34805
|
if (sourceChain.cctp == null) {
|
|
34392
34806
|
throw createBridgeRouteNotConfiguredError(sourceChain, 'source chain does not support CCTP');
|
|
34393
34807
|
}
|
|
@@ -34411,10 +34825,50 @@ function validateCrossChainDepositRoute(sourceChain, destinationChain) {
|
|
|
34411
34825
|
destinationApiChain,
|
|
34412
34826
|
destinationDomain: destinationChain.cctp.domain,
|
|
34413
34827
|
sourceChain,
|
|
34414
|
-
sourceTokenAddress,
|
|
34415
34828
|
authorizationRecipient
|
|
34416
34829
|
};
|
|
34417
34830
|
}
|
|
34831
|
+
function resolvePreparedBridgeSourceToken(preparedBundle, sourceChain) {
|
|
34832
|
+
const sourceTokenAddress = assertHexAddress('preparedBundle.erc3009TypedData.domain.verifyingContract', preparedBundle.erc3009TypedData.domain.verifyingContract, `Source token for chain ${sourceChain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
34833
|
+
let sourceToken;
|
|
34834
|
+
try {
|
|
34835
|
+
sourceToken = TOKEN_REGISTRY.resolveByAddress(sourceTokenAddress, sourceChain.chain);
|
|
34836
|
+
} catch {
|
|
34837
|
+
throw createValidationFailedError$1('preparedBundle.erc3009TypedData.domain.verifyingContract', sourceTokenAddress, `source token ${sourceTokenAddress} is not configured on source chain ${sourceChain.name} for cross-chain Earn deposits`);
|
|
34838
|
+
}
|
|
34839
|
+
const registryAddress = assertHexAddress('sourceToken.locator', sourceToken.locator, `Source token ${sourceToken.symbol ?? sourceTokenAddress} for chain ${sourceChain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
34840
|
+
if (!isSameAddress(sourceTokenAddress, registryAddress)) {
|
|
34841
|
+
throw createValidationFailedError$1('preparedBundle.erc3009TypedData.domain.verifyingContract', sourceTokenAddress, `source token must match the configured ${sourceToken.symbol ?? 'token'} address on source chain ${sourceChain.name}`);
|
|
34842
|
+
}
|
|
34843
|
+
const { symbol } = sourceToken;
|
|
34844
|
+
if (symbol === undefined) {
|
|
34845
|
+
throw createValidationFailedError$1('preparedBundle.erc3009TypedData.domain.verifyingContract', sourceTokenAddress, `source token ${sourceTokenAddress} is not a registered Earn bridge token on source chain ${sourceChain.name}`);
|
|
34846
|
+
}
|
|
34847
|
+
return {
|
|
34848
|
+
address: sourceTokenAddress,
|
|
34849
|
+
erc3009Domain: resolveBridgeErc3009Domain(symbol, sourceChain),
|
|
34850
|
+
decimals: sourceToken.decimals
|
|
34851
|
+
};
|
|
34852
|
+
}
|
|
34853
|
+
function validatePreparedReviewAmountDecimals(reviewedDecimals, tokenDecimals) {
|
|
34854
|
+
if (reviewedDecimals !== tokenDecimals) {
|
|
34855
|
+
throw createValidationFailedError$1('prepared.review.amount.decimals', reviewedDecimals, `review amount decimals must match the cross-chain Earn deposit source token decimals ${String(tokenDecimals)}`);
|
|
34856
|
+
}
|
|
34857
|
+
}
|
|
34858
|
+
function resolveBridgeErc3009Domain(tokenSymbol, sourceChain) {
|
|
34859
|
+
if (!isEarnBridgeErc3009TokenSymbol(tokenSymbol)) {
|
|
34860
|
+
throw createValidationFailedError$1('sourceToken.symbol', tokenSymbol, `ERC-3009 domain is not configured for ${tokenSymbol} on source chain ${sourceChain.name}`);
|
|
34861
|
+
}
|
|
34862
|
+
const domainsByChain = EARN_BRIDGE_ERC3009_DOMAINS[tokenSymbol];
|
|
34863
|
+
const domain = domainsByChain[sourceChain.chain];
|
|
34864
|
+
if (domain === undefined) {
|
|
34865
|
+
throw createValidationFailedError$1('sourceToken.symbol', tokenSymbol, `ERC-3009 domain is not configured for ${tokenSymbol} on source chain ${sourceChain.name}`);
|
|
34866
|
+
}
|
|
34867
|
+
return domain;
|
|
34868
|
+
}
|
|
34869
|
+
function isEarnBridgeErc3009TokenSymbol(tokenSymbol) {
|
|
34870
|
+
return EARN_BRIDGE_ERC3009_TOKEN_SYMBOLS.includes(tokenSymbol);
|
|
34871
|
+
}
|
|
34418
34872
|
function createUnsupportedCrossChainDepositError(chain, reason) {
|
|
34419
34873
|
return new KitError({
|
|
34420
34874
|
...EarnError.UNSUPPORTED_CHAIN,
|
|
@@ -34487,7 +34941,6 @@ function createUnsupportedCrossChainDepositError(chain, reason) {
|
|
|
34487
34941
|
// Untyped callers can pass anything here; without these guards a null
|
|
34488
34942
|
// config crashes with a raw TypeError on `config.providers` instead of
|
|
34489
34943
|
// the structured validation error every other public surface throws.
|
|
34490
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS consumers may pass null or a non-object config
|
|
34491
34944
|
if (typeof config !== 'object' || config === null || Array.isArray(config)) {
|
|
34492
34945
|
throw createValidationFailedError$1('config', config, 'config must be a plain object when provided');
|
|
34493
34946
|
}
|
|
@@ -34854,10 +35307,9 @@ const sourceAdapterContextSchema = zod.z.object({
|
|
|
34854
35307
|
* Schema for validating human-readable decimal amount strings.
|
|
34855
35308
|
*
|
|
34856
35309
|
* Accept positive decimal strings like '100', '100.50', '0.001'. Reject
|
|
34857
|
-
* zero, negative, non-numeric, and non-canonical strings.
|
|
34858
|
-
*
|
|
34859
|
-
*
|
|
34860
|
-
* 7+ decimal-place inputs to the server.
|
|
35310
|
+
* zero, negative, non-numeric, and non-canonical strings. Same-chain
|
|
35311
|
+
* EarnKit vaults can use different asset precisions, so the service enforces
|
|
35312
|
+
* the vault-specific decimal cap after resolving the vault asset.
|
|
34861
35313
|
*
|
|
34862
35314
|
* @internal
|
|
34863
35315
|
*/ const amountSchema$1 = zod.z.string({
|
|
@@ -34866,32 +35318,15 @@ const sourceAdapterContextSchema = zod.z.object({
|
|
|
34866
35318
|
allowZero: false,
|
|
34867
35319
|
regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
|
|
34868
35320
|
attributeName: 'amount',
|
|
34869
|
-
maxDecimals:
|
|
34870
|
-
})(zod.z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
|
|
34871
|
-
/**
|
|
34872
|
-
* Schema for cross-chain deposit amount strings.
|
|
34873
|
-
*
|
|
34874
|
-
* Cross-chain Earn deposits are USDC-only, and the signed ERC-3009 value is
|
|
34875
|
-
* denominated in USDC's 6 decimals. Reject more precise inputs up front so
|
|
34876
|
-
* the signed value always equals the requested amount instead of a silent
|
|
34877
|
-
* truncation. Non-canonical forms (leading dot, leading zeros) are rejected
|
|
34878
|
-
* too, matching the Earn Service.
|
|
34879
|
-
*
|
|
34880
|
-
* @internal
|
|
34881
|
-
*/ const crossChainAmountSchema = zod.z.string({
|
|
34882
|
-
required_error: 'amount is required'
|
|
34883
|
-
}).min(1, 'amount is required').pipe(createDecimalStringValidator({
|
|
34884
|
-
allowZero: false,
|
|
34885
|
-
regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
|
|
34886
|
-
attributeName: 'amount',
|
|
34887
|
-
maxDecimals: 6
|
|
35321
|
+
maxDecimals: 18
|
|
34888
35322
|
})(zod.z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
|
|
34889
35323
|
/**
|
|
34890
35324
|
* Schema for cross-chain source fee caps.
|
|
34891
35325
|
*
|
|
34892
|
-
* Cross-chain source fees are denominated in
|
|
34893
|
-
* when the quote contains no source-collected fees; otherwise the cap
|
|
34894
|
-
* the caller-accepted total from a recent quote.
|
|
35326
|
+
* Cross-chain source fees are denominated in the quote's fee token. Zero is
|
|
35327
|
+
* valid when the quote contains no source-collected fees; otherwise the cap
|
|
35328
|
+
* should be the caller-accepted total from a recent quote. The provider
|
|
35329
|
+
* enforces the prepared bundle's fee-token precision before signing.
|
|
34895
35330
|
*
|
|
34896
35331
|
* @internal
|
|
34897
35332
|
*/ const crossChainMaxFeeSchema = zod.z.string({
|
|
@@ -34900,7 +35335,7 @@ const sourceAdapterContextSchema = zod.z.object({
|
|
|
34900
35335
|
allowZero: true,
|
|
34901
35336
|
regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
|
|
34902
35337
|
attributeName: 'maxFee',
|
|
34903
|
-
maxDecimals:
|
|
35338
|
+
maxDecimals: 18
|
|
34904
35339
|
})(zod.z.string())).refine((value)=>CANONICAL_AMOUNT_REGEX.test(value), AMOUNT_FORMAT_ERROR_MESSAGE);
|
|
34905
35340
|
/**
|
|
34906
35341
|
* Build a schema for an optional non-negative decimal filter string.
|
|
@@ -35061,7 +35496,7 @@ const crossChainDepositDestinationSchema = zod.z.object({
|
|
|
35061
35496
|
from: sourceAdapterContextSchema,
|
|
35062
35497
|
to: crossChainDepositDestinationSchema,
|
|
35063
35498
|
vaultAddress: vaultAddressSchema,
|
|
35064
|
-
amount:
|
|
35499
|
+
amount: amountSchema$1,
|
|
35065
35500
|
maxFee: crossChainMaxFeeSchema,
|
|
35066
35501
|
transferSpeed: zod.z.enum([
|
|
35067
35502
|
'FAST',
|
|
@@ -36485,7 +36920,7 @@ function formatRetryResult(operation, result) {
|
|
|
36485
36920
|
}
|
|
36486
36921
|
|
|
36487
36922
|
// Auto-register this kit for user agent tracking
|
|
36488
|
-
registerKit(`${pkg$
|
|
36923
|
+
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
36489
36924
|
|
|
36490
36925
|
/**
|
|
36491
36926
|
* Create an EarnKit instance for AppKit earn operations.
|
|
@@ -36580,12 +37015,17 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
36580
37015
|
* The type annotation `readonly TokenAlias[]` ensures this array stays in sync
|
|
36581
37016
|
* with the TokenAlias type definition - TypeScript will enforce any changes.
|
|
36582
37017
|
*
|
|
36583
|
-
*
|
|
37018
|
+
* `USDC`, `USDT`, and `NATIVE` map to dedicated adapter transfer actions.
|
|
37019
|
+
* `EURC` has no dedicated action — it resolves to the chain's `eurcAddress`
|
|
37020
|
+
* and uses the generic token transfer action (see {@link prepareSend}).
|
|
37021
|
+
*
|
|
37022
|
+
* For swap operations, additional tokens (DAI, USDE, PYUSD) are supported
|
|
36584
37023
|
* via SwapKit's SupportedToken type.
|
|
36585
37024
|
*/ const TOKEN_ALIASES = [
|
|
36586
37025
|
'USDC',
|
|
36587
37026
|
'USDT',
|
|
36588
|
-
'NATIVE'
|
|
37027
|
+
'NATIVE',
|
|
37028
|
+
'EURC'
|
|
36589
37029
|
];
|
|
36590
37030
|
/**
|
|
36591
37031
|
* Check if a token string is a known alias.
|
|
@@ -36612,7 +37052,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
36612
37052
|
* Type guard to check if a string is a valid token address for a chain.
|
|
36613
37053
|
*
|
|
36614
37054
|
* This function verifies that a token string is:
|
|
36615
|
-
* 1. Not a known alias ('USDC', 'USDT', 'NATIVE')
|
|
37055
|
+
* 1. Not a known alias ('USDC', 'USDT', 'NATIVE', 'EURC')
|
|
36616
37056
|
* 2. A valid address format for the specified chain
|
|
36617
37057
|
*
|
|
36618
37058
|
* Use this to narrow the type to `TokenAddress` in TypeScript.
|
|
@@ -36642,7 +37082,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
36642
37082
|
* Validate and classify a token identifier.
|
|
36643
37083
|
*
|
|
36644
37084
|
* This function determines whether a token string is:
|
|
36645
|
-
* 1. A known alias ('USDC', 'USDT', or '
|
|
37085
|
+
* 1. A known alias ('USDC', 'USDT', 'NATIVE', or 'EURC')
|
|
36646
37086
|
* 2. A valid token address for the given chain
|
|
36647
37087
|
* 3. An invalid/unrecognized token identifier
|
|
36648
37088
|
*
|
|
@@ -36896,8 +37336,11 @@ const tokens = createTokenRegistry();
|
|
|
36896
37336
|
* from `to` (explicit address string or adapter), and normalize the human‑readable
|
|
36897
37337
|
* `amount` into token units.
|
|
36898
37338
|
*
|
|
36899
|
-
* For
|
|
36900
|
-
* with hardcoded decimals (USDC and USDT use 6 decimals; native uses the source chain's native decimals).
|
|
37339
|
+
* For the `USDC`, `USDT`, and `NATIVE` aliases, uses dedicated transfer actions
|
|
37340
|
+
* with hardcoded decimals (USDC and USDT use 6 decimals; native uses the source chain's native decimals).
|
|
37341
|
+
* The `EURC` alias resolves to the chain's `eurcAddress` (6 decimals from the token
|
|
37342
|
+
* registry) and routes through the generic token.transfer action; it is rejected on
|
|
37343
|
+
* chains where `eurcAddress` is not set. For custom token addresses, uses the generic token.transfer
|
|
36901
37344
|
* action and fetches decimals dynamically from the contract.
|
|
36902
37345
|
*
|
|
36903
37346
|
* @param params - The send parameters including source context, destination, amount and token.
|
|
@@ -36990,6 +37433,21 @@ const tokens = createTokenRegistry();
|
|
|
36990
37433
|
preparedSendRequest = await fromAdapter.prepareAction('native.transfer', requestParams, operationContext);
|
|
36991
37434
|
break;
|
|
36992
37435
|
}
|
|
37436
|
+
case 'EURC':
|
|
37437
|
+
{
|
|
37438
|
+
// EURC has no dedicated transfer action. Resolve its contract address
|
|
37439
|
+
// from the chain definition and route through the generic
|
|
37440
|
+
// token.transfer action. `eurcAddress` is null where EURC isn't deployed.
|
|
37441
|
+
const eurcAddress = fromChain.eurcAddress;
|
|
37442
|
+
if (eurcAddress === null) {
|
|
37443
|
+
throw createUnsupportedTokenError(token, fromChain.name);
|
|
37444
|
+
}
|
|
37445
|
+
preparedSendRequest = await fromAdapter.prepareAction('token.transfer', {
|
|
37446
|
+
...requestParams,
|
|
37447
|
+
tokenAddress: eurcAddress
|
|
37448
|
+
}, operationContext);
|
|
37449
|
+
break;
|
|
37450
|
+
}
|
|
36993
37451
|
default:
|
|
36994
37452
|
{
|
|
36995
37453
|
throw createUnsupportedTokenError(String(token), fromChain.name);
|
|
@@ -37016,12 +37474,13 @@ const tokens = createTokenRegistry();
|
|
|
37016
37474
|
* Fully prepares and executes the send transaction to transfer the specified amount and
|
|
37017
37475
|
* token to the specified destination.
|
|
37018
37476
|
*
|
|
37019
|
-
* For
|
|
37020
|
-
*
|
|
37021
|
-
*
|
|
37477
|
+
* For the 'USDC', 'USDT', and 'NATIVE' aliases, uses optimized dedicated actions.
|
|
37478
|
+
* The 'EURC' alias resolves to the chain's `eurcAddress` and routes through the generic
|
|
37479
|
+
* token.transfer action. For custom token addresses, uses the generic token.transfer action
|
|
37480
|
+
* with dynamically fetched decimals.
|
|
37022
37481
|
*
|
|
37023
37482
|
* @param params - The send parameters: source context, destination (address or adapter),
|
|
37024
|
-
* human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE' or custom address, defaults to 'USDC').
|
|
37483
|
+
* human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE' | 'EURC' or custom address, defaults to 'USDC').
|
|
37025
37484
|
* @returns A BridgeStep object with transaction details including hash, status, and explorer URL.
|
|
37026
37485
|
* @throws KitError INPUT_VALIDATION_FAILED if parameters are invalid.
|
|
37027
37486
|
* @throws KitError INPUT_UNSUPPORTED_TOKEN if the token is invalid for the chain.
|
|
@@ -37039,6 +37498,17 @@ const tokens = createTokenRegistry();
|
|
|
37039
37498
|
* console.log('Transaction hash:', step.txHash)
|
|
37040
37499
|
* ```
|
|
37041
37500
|
*
|
|
37501
|
+
* @example Sending EURC on a chain where EURC is deployed (e.g. Arc Testnet)
|
|
37502
|
+
* ```typescript
|
|
37503
|
+
* const step = await send({
|
|
37504
|
+
* from: { adapter: sourceAdapter, chain: 'Arc_Testnet' },
|
|
37505
|
+
* to: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
|
|
37506
|
+
* amount: '5.0',
|
|
37507
|
+
* token: 'EURC',
|
|
37508
|
+
* })
|
|
37509
|
+
* console.log('Transaction hash:', step.txHash)
|
|
37510
|
+
* ```
|
|
37511
|
+
*
|
|
37042
37512
|
* @example Sending a custom token (DAI) to an explicit address
|
|
37043
37513
|
* ```typescript
|
|
37044
37514
|
* const step = await send({
|
|
@@ -37080,21 +37550,22 @@ const tokens = createTokenRegistry();
|
|
|
37080
37550
|
};
|
|
37081
37551
|
|
|
37082
37552
|
/**
|
|
37083
|
-
* Estimate the network fees to send USDC, USDT, or a supported native token.
|
|
37553
|
+
* Estimate the network fees to send USDC, USDT, EURC, or a supported native token.
|
|
37084
37554
|
*
|
|
37085
37555
|
* Prepare the send operation (including validating inputs and resolving the recipient when
|
|
37086
37556
|
* provided as an adapter) and return an {@link EstimatedGas} object. This function does
|
|
37087
37557
|
* not submit any transaction.
|
|
37088
37558
|
*
|
|
37089
37559
|
* @remarks
|
|
37090
|
-
* - Selects the transfer handler based on `token` ('USDC' by default, 'USDT', or '
|
|
37560
|
+
* - Selects the transfer handler based on `token` ('USDC' by default, 'USDT', 'NATIVE', or 'EURC').
|
|
37561
|
+
* 'EURC' is only supported on chains where `eurcAddress` is configured.
|
|
37091
37562
|
* - When `to` is an {@link Adapter}, the recipient address is derived from the adapter.
|
|
37092
37563
|
* - Rejects transfers where the resolved `to` equals the source `from` address.
|
|
37093
37564
|
* - Interprets `amount` as a human-readable decimal string (USDC and USDT scaled to 6 decimals,
|
|
37094
37565
|
* native EVM value typically scaled to 18 decimals).
|
|
37095
37566
|
*
|
|
37096
37567
|
* @param params - The send parameters: source context, destination (address or adapter),
|
|
37097
|
-
* human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE', defaults to 'USDC').
|
|
37568
|
+
* human-readable `amount`, and optional `token` ('USDC' | 'USDT' | 'NATIVE' | 'EURC', defaults to 'USDC').
|
|
37098
37569
|
* @returns The estimated gas information including `gas`, `gasPrice`, and total `fee`.
|
|
37099
37570
|
* @throws Error If parameters are invalid.
|
|
37100
37571
|
* @throws Error If the token is unsupported or the send cannot be prepared.
|
|
@@ -37801,7 +38272,7 @@ async function deposit$2(context, params) {
|
|
|
37801
38272
|
}
|
|
37802
38273
|
|
|
37803
38274
|
var name = "@circle-fin/unified-balance-kit";
|
|
37804
|
-
var version = "1.2.
|
|
38275
|
+
var version = "1.2.2";
|
|
37805
38276
|
var pkg = {
|
|
37806
38277
|
name: name,
|
|
37807
38278
|
version: version};
|