@circle-fin/app-kit 1.13.0 → 1.14.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 +56 -0
- package/bridge.cjs +910 -47
- package/bridge.d.cts +55 -0
- package/bridge.d.mts +55 -0
- package/bridge.d.ts +55 -0
- package/bridge.mjs +911 -48
- package/chains.cjs +129 -10
- package/chains.d.cts +9 -0
- package/chains.d.mts +9 -0
- package/chains.d.ts +9 -0
- package/chains.mjs +129 -10
- package/context.d.cts +55 -0
- package/context.d.mts +55 -0
- package/context.d.ts +55 -0
- package/earn.cjs +432 -27
- package/earn.d.cts +55 -0
- package/earn.d.mts +55 -0
- package/earn.d.ts +55 -0
- package/earn.mjs +428 -27
- package/estimateBridge.cjs +910 -47
- package/estimateBridge.d.cts +61 -0
- package/estimateBridge.d.mts +61 -0
- package/estimateBridge.d.ts +61 -0
- package/estimateBridge.mjs +911 -48
- package/estimateSwap.cjs +428 -26
- package/estimateSwap.d.cts +55 -0
- package/estimateSwap.d.mts +55 -0
- package/estimateSwap.d.ts +55 -0
- package/estimateSwap.mjs +427 -26
- package/index.cjs +4613 -346
- package/index.d.cts +777 -216
- package/index.d.mts +777 -216
- package/index.d.ts +777 -216
- package/index.mjs +4614 -347
- package/package.json +6 -6
- package/swap.cjs +428 -26
- package/swap.d.cts +55 -0
- package/swap.d.mts +55 -0
- package/swap.d.ts +55 -0
- package/swap.mjs +427 -26
- package/unifiedBalance.cjs +20602 -8389
- package/unifiedBalance.d.cts +544 -160
- package/unifiedBalance.d.mts +544 -160
- package/unifiedBalance.d.ts +544 -160
- package/unifiedBalance.mjs +20603 -8391
package/estimateBridge.cjs
CHANGED
|
@@ -33,7 +33,7 @@ var zod = require('zod');
|
|
|
33
33
|
var pino = require('pino');
|
|
34
34
|
var units = require('@ethersproject/units');
|
|
35
35
|
var bytes = require('@ethersproject/bytes');
|
|
36
|
-
require('@ethersproject/abi');
|
|
36
|
+
var abi = require('@ethersproject/abi');
|
|
37
37
|
var address = require('@ethersproject/address');
|
|
38
38
|
var bs58 = require('bs58');
|
|
39
39
|
var web3_js = require('@solana/web3.js');
|
|
@@ -3665,8 +3665,45 @@ var EarnChain;
|
|
|
3665
3665
|
* This program handles minting operations for Gateway transactions
|
|
3666
3666
|
* on Solana devnet.
|
|
3667
3667
|
*/ const GATEWAY_MINTER_SOLANA_DEVNET = 'GATEmKK2ECL1brEngQZWCgMWPbvrEYqsV6u29dAaHavr';
|
|
3668
|
-
/**
|
|
3669
|
-
|
|
3668
|
+
/**
|
|
3669
|
+
* The `TokenMessengerWithFees` proxy contract address for EVM mainnet networks
|
|
3670
|
+
* (all chains except Edge).
|
|
3671
|
+
*
|
|
3672
|
+
* Deployed at a CREATE3-derived address; identical across all mainnet EVM
|
|
3673
|
+
* source chains. Present on any chain that supports the prepaid FORWARD path
|
|
3674
|
+
* via `depositForBurnWithHookAndFees`.
|
|
3675
|
+
*/ const TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET = '0x71f54F818671cD0D7ea140Da213e5C8b5C92a408';
|
|
3676
|
+
/**
|
|
3677
|
+
* The `TokenMessengerWithFees` proxy contract address for EVM testnet networks.
|
|
3678
|
+
*
|
|
3679
|
+
* Identical across all testnet EVM source chains. Present on any testnet chain
|
|
3680
|
+
* that supports the prepaid FORWARD path via `depositForBurnWithHookAndFees`.
|
|
3681
|
+
*/ const TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET = '0x8745D906D67C346E5eb1aEEED38Eb87F34DF0C0A';
|
|
3682
|
+
/**
|
|
3683
|
+
* The `DepositForHandler` proxy contract address for EVM mainnet networks.
|
|
3684
|
+
*
|
|
3685
|
+
* The handler the GenericExecutor calls on a fast-deposit destination chain to
|
|
3686
|
+
* run a cross-chain deposit into the GatewayWallet. Deployed at the same
|
|
3687
|
+
* address across all mainnet EVM destination chains.
|
|
3688
|
+
*/ const DEPOSIT_FOR_HANDLER_EVM_MAINNET = '0x16529813203f77E036576666336554a1210dce4D';
|
|
3689
|
+
/**
|
|
3690
|
+
* The `DepositForHandler` proxy contract address for EVM testnet networks.
|
|
3691
|
+
*
|
|
3692
|
+
* Identical across all testnet EVM destination chains.
|
|
3693
|
+
*/ const DEPOSIT_FOR_HANDLER_EVM_TESTNET = '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48';
|
|
3694
|
+
/**
|
|
3695
|
+
* The `GenericExecutor` proxy contract address for EVM mainnet networks.
|
|
3696
|
+
*
|
|
3697
|
+
* The GenericExecutor is the `mintRecipient` and `destinationCaller` on the
|
|
3698
|
+
* destination chain for the CCTP v2 prepaid FORWARD path. It receives the CCTP
|
|
3699
|
+
* mint and calls the `DepositForHandler` to complete the fast deposit.
|
|
3700
|
+
* Deployed at the same address across all mainnet EVM destination chains.
|
|
3701
|
+
*/ const GENERIC_EXECUTOR_EVM_MAINNET = '0xFa7be2f04F3Ad4ca969260729c6d45B5625984A7';
|
|
3702
|
+
/**
|
|
3703
|
+
* The `GenericExecutor` proxy contract address for EVM testnet networks.
|
|
3704
|
+
*
|
|
3705
|
+
* Identical across all testnet EVM destination chains.
|
|
3706
|
+
*/ const GENERIC_EXECUTOR_EVM_TESTNET = '0xEdC81040756AcCfF070c21D37b265b9D0b5Ba45e';
|
|
3670
3707
|
|
|
3671
3708
|
/**
|
|
3672
3709
|
* Arc Testnet chain definition
|
|
@@ -3725,9 +3762,8 @@ var EarnChain;
|
|
|
3725
3762
|
v1: {
|
|
3726
3763
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3727
3764
|
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3765
|
+
depositForHandler: DEPOSIT_FOR_HANDLER_EVM_TESTNET,
|
|
3766
|
+
genericExecutor: GENERIC_EXECUTOR_EVM_TESTNET
|
|
3731
3767
|
}
|
|
3732
3768
|
},
|
|
3733
3769
|
forwarderSupported: {
|
|
@@ -3922,7 +3958,9 @@ var EarnChain;
|
|
|
3922
3958
|
contracts: {
|
|
3923
3959
|
v1: {
|
|
3924
3960
|
wallet: GATEWAY_WALLET_EVM_MAINNET,
|
|
3925
|
-
minter: GATEWAY_MINTER_EVM_MAINNET
|
|
3961
|
+
minter: GATEWAY_MINTER_EVM_MAINNET,
|
|
3962
|
+
depositForHandler: DEPOSIT_FOR_HANDLER_EVM_MAINNET,
|
|
3963
|
+
genericExecutor: GENERIC_EXECUTOR_EVM_MAINNET
|
|
3926
3964
|
}
|
|
3927
3965
|
},
|
|
3928
3966
|
forwarderSupported: {
|
|
@@ -3986,7 +4024,9 @@ var EarnChain;
|
|
|
3986
4024
|
contracts: {
|
|
3987
4025
|
v1: {
|
|
3988
4026
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3989
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
4027
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
4028
|
+
depositForHandler: DEPOSIT_FOR_HANDLER_EVM_TESTNET,
|
|
4029
|
+
genericExecutor: GENERIC_EXECUTOR_EVM_TESTNET
|
|
3990
4030
|
}
|
|
3991
4031
|
},
|
|
3992
4032
|
forwarderSupported: {
|
|
@@ -4299,6 +4339,7 @@ var EarnChain;
|
|
|
4299
4339
|
v2: {
|
|
4300
4340
|
type: 'split',
|
|
4301
4341
|
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
4342
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
|
|
4302
4343
|
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
4303
4344
|
confirmations: 1,
|
|
4304
4345
|
fastConfirmations: 1
|
|
@@ -4344,6 +4385,7 @@ var EarnChain;
|
|
|
4344
4385
|
v2: {
|
|
4345
4386
|
type: 'split',
|
|
4346
4387
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
4388
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
4347
4389
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
4348
4390
|
confirmations: 1,
|
|
4349
4391
|
fastConfirmations: 1
|
|
@@ -4389,6 +4431,7 @@ var EarnChain;
|
|
|
4389
4431
|
v2: {
|
|
4390
4432
|
type: 'split',
|
|
4391
4433
|
tokenMessenger: '0x98706A006bc632Df31CAdFCBD43F38887ce2ca5c',
|
|
4434
|
+
tokenMessengerWithFees: '0x3Ac96675F9a3E6922713e041645D82f3561d3686',
|
|
4392
4435
|
messageTransmitter: '0x5b61381Fc9e58E70EfC13a4A97516997019198ee',
|
|
4393
4436
|
confirmations: 65,
|
|
4394
4437
|
fastConfirmations: 1
|
|
@@ -4434,6 +4477,7 @@ var EarnChain;
|
|
|
4434
4477
|
v2: {
|
|
4435
4478
|
type: 'split',
|
|
4436
4479
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
4480
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
4437
4481
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
4438
4482
|
confirmations: 65,
|
|
4439
4483
|
fastConfirmations: 1
|
|
@@ -4782,6 +4826,7 @@ var EarnChain;
|
|
|
4782
4826
|
v2: {
|
|
4783
4827
|
type: 'split',
|
|
4784
4828
|
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
4829
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
|
|
4785
4830
|
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
4786
4831
|
confirmations: 1,
|
|
4787
4832
|
fastConfirmations: 1
|
|
@@ -4829,6 +4874,7 @@ var EarnChain;
|
|
|
4829
4874
|
v2: {
|
|
4830
4875
|
type: 'split',
|
|
4831
4876
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
4877
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
4832
4878
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
4833
4879
|
confirmations: 1,
|
|
4834
4880
|
fastConfirmations: 1
|
|
@@ -5110,6 +5156,7 @@ var EarnChain;
|
|
|
5110
5156
|
v2: {
|
|
5111
5157
|
type: 'split',
|
|
5112
5158
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5159
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
5113
5160
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5114
5161
|
confirmations: 1,
|
|
5115
5162
|
fastConfirmations: 1
|
|
@@ -5155,6 +5202,7 @@ var EarnChain;
|
|
|
5155
5202
|
v2: {
|
|
5156
5203
|
type: 'split',
|
|
5157
5204
|
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5205
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
|
|
5158
5206
|
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5159
5207
|
confirmations: 64,
|
|
5160
5208
|
fastConfirmations: 1
|
|
@@ -5200,6 +5248,7 @@ var EarnChain;
|
|
|
5200
5248
|
v2: {
|
|
5201
5249
|
type: 'split',
|
|
5202
5250
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5251
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
5203
5252
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5204
5253
|
confirmations: 64,
|
|
5205
5254
|
fastConfirmations: 1
|
|
@@ -5501,6 +5550,7 @@ var EarnChain;
|
|
|
5501
5550
|
v2: {
|
|
5502
5551
|
type: 'split',
|
|
5503
5552
|
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
5553
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_MAINNET,
|
|
5504
5554
|
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
5505
5555
|
confirmations: 1,
|
|
5506
5556
|
fastConfirmations: 1
|
|
@@ -5547,6 +5597,7 @@ var EarnChain;
|
|
|
5547
5597
|
v2: {
|
|
5548
5598
|
type: 'split',
|
|
5549
5599
|
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
5600
|
+
tokenMessengerWithFees: TOKEN_MESSENGER_WITH_FEES_EVM_TESTNET,
|
|
5550
5601
|
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
5551
5602
|
confirmations: 1,
|
|
5552
5603
|
fastConfirmations: 1
|
|
@@ -5854,7 +5905,9 @@ var EarnChain;
|
|
|
5854
5905
|
contracts: {
|
|
5855
5906
|
v1: {
|
|
5856
5907
|
wallet: GATEWAY_WALLET_EVM_MAINNET,
|
|
5857
|
-
minter: GATEWAY_MINTER_EVM_MAINNET
|
|
5908
|
+
minter: GATEWAY_MINTER_EVM_MAINNET,
|
|
5909
|
+
depositForHandler: DEPOSIT_FOR_HANDLER_EVM_MAINNET,
|
|
5910
|
+
genericExecutor: GENERIC_EXECUTOR_EVM_MAINNET
|
|
5858
5911
|
}
|
|
5859
5912
|
},
|
|
5860
5913
|
forwarderSupported: {
|
|
@@ -5919,7 +5972,9 @@ var EarnChain;
|
|
|
5919
5972
|
contracts: {
|
|
5920
5973
|
v1: {
|
|
5921
5974
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
5922
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
5975
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
5976
|
+
depositForHandler: DEPOSIT_FOR_HANDLER_EVM_TESTNET,
|
|
5977
|
+
genericExecutor: GENERIC_EXECUTOR_EVM_TESTNET
|
|
5923
5978
|
}
|
|
5924
5979
|
},
|
|
5925
5980
|
forwarderSupported: {
|
|
@@ -7005,18 +7060,48 @@ var Chains = {
|
|
|
7005
7060
|
return chain.cctp?.contracts.v2 !== undefined;
|
|
7006
7061
|
}
|
|
7007
7062
|
|
|
7063
|
+
/**
|
|
7064
|
+
* Chains the Fee Service accepts as a SOURCE for source-paid ("receive-exact")
|
|
7065
|
+
* CCTP v2 fees. An explicit allowlist is required because the
|
|
7066
|
+
* `TokenMessengerWithFees` wrapper address is now shared with the fast-deposit
|
|
7067
|
+
* forwarder path, so wrapper presence no longer implies source-fee support.
|
|
7068
|
+
* Keep in sync with backend coverage.
|
|
7069
|
+
*/ const SOURCE_FEE_SUPPORTED_ALLOWLIST = new Set([
|
|
7070
|
+
// Mainnet
|
|
7071
|
+
Blockchain.Ethereum,
|
|
7072
|
+
Blockchain.Base,
|
|
7073
|
+
Blockchain.Arbitrum,
|
|
7074
|
+
Blockchain.Unichain,
|
|
7075
|
+
Blockchain.Optimism,
|
|
7076
|
+
Blockchain.Codex,
|
|
7077
|
+
Blockchain.Ink,
|
|
7078
|
+
Blockchain.Plume,
|
|
7079
|
+
Blockchain.Linea,
|
|
7080
|
+
Blockchain.World_Chain,
|
|
7081
|
+
// Testnet counterparts
|
|
7082
|
+
Blockchain.Ethereum_Sepolia,
|
|
7083
|
+
Blockchain.Base_Sepolia,
|
|
7084
|
+
Blockchain.Arbitrum_Sepolia,
|
|
7085
|
+
Blockchain.Unichain_Sepolia,
|
|
7086
|
+
Blockchain.Optimism_Sepolia,
|
|
7087
|
+
Blockchain.Codex_Testnet,
|
|
7088
|
+
Blockchain.Ink_Testnet,
|
|
7089
|
+
Blockchain.Plume_Testnet,
|
|
7090
|
+
Blockchain.Linea_Sepolia,
|
|
7091
|
+
Blockchain.World_Chain_Sepolia
|
|
7092
|
+
]);
|
|
7008
7093
|
/**
|
|
7009
7094
|
* Check whether a chain supports source-paid ("receive-exact") CCTP v2 fees.
|
|
7010
7095
|
*
|
|
7011
|
-
* A chain
|
|
7012
|
-
*
|
|
7013
|
-
* `feePayment: 'source'` transfers through this wrapper via
|
|
7014
|
-
* `depositForBurnWithHookAndFees`, so a chain without the wrapper cannot be a
|
|
7015
|
-
* source for receive-exact bridging.
|
|
7096
|
+
* A chain qualifies when it supports CCTP v2, carries a `TokenMessengerWithFees`
|
|
7097
|
+
* wrapper, and is in {@link SOURCE_FEE_SUPPORTED_ALLOWLIST}.
|
|
7016
7098
|
*
|
|
7017
|
-
* @param chain - The chain definition to check.
|
|
7018
|
-
*
|
|
7019
|
-
*
|
|
7099
|
+
* @param chain - The chain definition to check. A nullish or non-object value
|
|
7100
|
+
* returns `false` rather than throwing, since consumers may call from plain
|
|
7101
|
+
* JavaScript.
|
|
7102
|
+
* @returns `true` when the chain supports CCTP v2, carries a
|
|
7103
|
+
* `TokenMessengerWithFees` wrapper, and is on the source-fee allowlist;
|
|
7104
|
+
* `false` otherwise.
|
|
7020
7105
|
*
|
|
7021
7106
|
* @example
|
|
7022
7107
|
* ```typescript
|
|
@@ -7026,11 +7111,18 @@ var Chains = {
|
|
|
7026
7111
|
* hasSourceFeeSupport(Chains.Solana) // false
|
|
7027
7112
|
* ```
|
|
7028
7113
|
*/ function hasSourceFeeSupport(chain) {
|
|
7114
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard for nullish/non-object input from plain JS
|
|
7115
|
+
if (chain === null || typeof chain !== 'object') {
|
|
7116
|
+
return false;
|
|
7117
|
+
}
|
|
7029
7118
|
if (!isCCTPV2Supported(chain)) {
|
|
7030
7119
|
return false;
|
|
7031
7120
|
}
|
|
7032
7121
|
const wrapper = chain.cctp.contracts.v2.tokenMessengerWithFees;
|
|
7033
|
-
|
|
7122
|
+
if (typeof wrapper !== 'string' || wrapper.length === 0) {
|
|
7123
|
+
return false;
|
|
7124
|
+
}
|
|
7125
|
+
return SOURCE_FEE_SUPPORTED_ALLOWLIST.has(chain.chain);
|
|
7034
7126
|
}
|
|
7035
7127
|
|
|
7036
7128
|
/**
|
|
@@ -7083,6 +7175,73 @@ var Chains = {
|
|
|
7083
7175
|
return typeof contractAddress === 'string' && contractAddress.trim().length > 0;
|
|
7084
7176
|
}
|
|
7085
7177
|
|
|
7178
|
+
/**
|
|
7179
|
+
* Check whether a given chain supports Gateway protocol version 1.
|
|
7180
|
+
*
|
|
7181
|
+
* This type guard function examines a chain definition to determine if it has Gateway v1
|
|
7182
|
+
* contract configurations. It checks that the chain has a gateway object with a
|
|
7183
|
+
* `contracts.v1` entry present.
|
|
7184
|
+
*
|
|
7185
|
+
* @param chain - The chain definition to check for Gateway v1 support
|
|
7186
|
+
* @returns `true` if `chain.gateway?.contracts?.v1` is defined, `false` otherwise
|
|
7187
|
+
*
|
|
7188
|
+
* @example
|
|
7189
|
+
* ```typescript
|
|
7190
|
+
* import { isGatewayV1Supported, Base } from '@core/chains'
|
|
7191
|
+
*
|
|
7192
|
+
* if (isGatewayV1Supported(Base)) {
|
|
7193
|
+
* // TypeScript knows Base.gateway is defined here
|
|
7194
|
+
* console.log('Gateway domain:', Base.gateway.domain)
|
|
7195
|
+
* console.log('Wallet address:', Base.gateway.contracts.v1.wallet)
|
|
7196
|
+
* console.log('Minter address:', Base.gateway.contracts.v1.minter)
|
|
7197
|
+
* }
|
|
7198
|
+
* ```
|
|
7199
|
+
*
|
|
7200
|
+
* @example
|
|
7201
|
+
* ```typescript
|
|
7202
|
+
* // Usage in conditional flow
|
|
7203
|
+
* function getGatewayWalletAddress(chain: ChainDefinition): string | null {
|
|
7204
|
+
* if (isGatewayV1Supported(chain)) {
|
|
7205
|
+
* return chain.gateway.contracts.v1.wallet
|
|
7206
|
+
* }
|
|
7207
|
+
* return null
|
|
7208
|
+
* }
|
|
7209
|
+
* ```
|
|
7210
|
+
*/ function isGatewayV1Supported(chain) {
|
|
7211
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- JS consumers may pass a gateway object without contracts
|
|
7212
|
+
return chain.gateway?.contracts?.v1 !== undefined;
|
|
7213
|
+
}
|
|
7214
|
+
|
|
7215
|
+
/**
|
|
7216
|
+
* Temporary allowlist of chains permitted to initiate Gateway fast deposits.
|
|
7217
|
+
* Only chains keyed here are eligible; all others are rejected. Using the
|
|
7218
|
+
* {@link Blockchain} enum keeps entries type-safe and catches typos at compile
|
|
7219
|
+
* time. Remove this allowlist once roll-out is complete.
|
|
7220
|
+
*/ new Set([
|
|
7221
|
+
// Mainnet
|
|
7222
|
+
Blockchain.Ethereum,
|
|
7223
|
+
Blockchain.Base,
|
|
7224
|
+
Blockchain.Arbitrum,
|
|
7225
|
+
Blockchain.Unichain,
|
|
7226
|
+
Blockchain.Optimism,
|
|
7227
|
+
Blockchain.Codex,
|
|
7228
|
+
Blockchain.Ink,
|
|
7229
|
+
Blockchain.Plume,
|
|
7230
|
+
Blockchain.Linea,
|
|
7231
|
+
Blockchain.World_Chain,
|
|
7232
|
+
// Testnet counterparts
|
|
7233
|
+
Blockchain.Ethereum_Sepolia,
|
|
7234
|
+
Blockchain.Base_Sepolia,
|
|
7235
|
+
Blockchain.Arbitrum_Sepolia,
|
|
7236
|
+
Blockchain.Unichain_Sepolia,
|
|
7237
|
+
Blockchain.Optimism_Sepolia,
|
|
7238
|
+
Blockchain.Codex_Testnet,
|
|
7239
|
+
Blockchain.Ink_Testnet,
|
|
7240
|
+
Blockchain.Plume_Testnet,
|
|
7241
|
+
Blockchain.Linea_Sepolia,
|
|
7242
|
+
Blockchain.World_Chain_Sepolia
|
|
7243
|
+
]);
|
|
7244
|
+
|
|
7086
7245
|
/**
|
|
7087
7246
|
* Zod schema for validating Gateway v1 contract addresses.
|
|
7088
7247
|
*
|
|
@@ -7104,7 +7263,10 @@ var Chains = {
|
|
|
7104
7263
|
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
7105
7264
|
depositForHandler: zod.z.string({
|
|
7106
7265
|
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
7107
|
-
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
7266
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional(),
|
|
7267
|
+
genericExecutor: zod.z.string({
|
|
7268
|
+
invalid_type_error: 'Gateway genericExecutor address must be a string.'
|
|
7269
|
+
}).min(1, 'Gateway genericExecutor address cannot be empty.').optional()
|
|
7108
7270
|
}).strict() // Reject any additional properties not defined in the schema
|
|
7109
7271
|
;
|
|
7110
7272
|
/**
|
|
@@ -9975,6 +10137,9 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9975
10137
|
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
9976
10138
|
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
9977
10139
|
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
10140
|
+
/**
|
|
10141
|
+
* Maximum value of the 32-bit `version` field in a `cctp-forward` frame.
|
|
10142
|
+
*/ const MAX_UINT32 = 0xffffffff;
|
|
9978
10143
|
/**
|
|
9979
10144
|
* CCTP forwarding version number.
|
|
9980
10145
|
*
|
|
@@ -10051,6 +10216,76 @@ function buildForwardingHookData() {
|
|
|
10051
10216
|
cachedHookDataHex = '0x' + Array.from(buffer).map((b)=>b.toString(16).padStart(2, '0')).join('');
|
|
10052
10217
|
return cachedHookDataHex;
|
|
10053
10218
|
}
|
|
10219
|
+
/**
|
|
10220
|
+
* Build a `cctp-forward` hookData frame with a versioned header and an appended
|
|
10221
|
+
* opaque payload.
|
|
10222
|
+
*
|
|
10223
|
+
* Produces the 32-byte `cctp-forward` header (24-byte ASCII magic + `uint32`
|
|
10224
|
+
* version + `uint32` `dataLength = 0`) followed by `payload` appended verbatim.
|
|
10225
|
+
* Unlike {@link buildForwardingHookData} — which emits only the fixed,
|
|
10226
|
+
* version-0 empty frame — this lets the caller set the frame `version` and
|
|
10227
|
+
* carry an inner payload such as a GenericExecutor blob.
|
|
10228
|
+
*
|
|
10229
|
+
* @remarks
|
|
10230
|
+
* The forwarder reads only the 32-byte header to decide that a hook is
|
|
10231
|
+
* forwardable, then strips it before the inner payload is consumed downstream
|
|
10232
|
+
* (e.g. the GenericExecutor `abi.decode`s the appended blob, never the frame).
|
|
10233
|
+
* `dataLength` stays `0` because the appended bytes are opaque to the forwarder
|
|
10234
|
+
* — it is not the payload's length.
|
|
10235
|
+
*
|
|
10236
|
+
* @param version - The `uint32` frame version (e.g. `1` for the GenericExecutor
|
|
10237
|
+
* FORWARD path). Must be an integer in `[0, 0xFFFFFFFF]`.
|
|
10238
|
+
* @param payload - A 0x-prefixed hex string appended after the header (e.g. the
|
|
10239
|
+
* bare GenericExecutor blob from `buildDepositForGenericExecutorPayload`).
|
|
10240
|
+
* @returns A 0x-prefixed hex string: the 32-byte frame followed by `payload`.
|
|
10241
|
+
* @throws {KitError} If `version` is out of `uint32` range or `payload` is not
|
|
10242
|
+
* a 0x-prefixed hex string (INPUT_VALIDATION_FAILED).
|
|
10243
|
+
*
|
|
10244
|
+
* @example
|
|
10245
|
+
* ```typescript
|
|
10246
|
+
* import {
|
|
10247
|
+
* buildDepositForGenericExecutorPayload,
|
|
10248
|
+
* buildForwardingHookDataWithPayload,
|
|
10249
|
+
* padAddressToBytes32,
|
|
10250
|
+
* } from '@core/utils'
|
|
10251
|
+
*
|
|
10252
|
+
* const { hookData: geBlob } = buildDepositForGenericExecutorPayload({
|
|
10253
|
+
* dappId: 'gateway_deposit',
|
|
10254
|
+
* domainId: 26,
|
|
10255
|
+
* handler: '0xHandlerAddressOnDestinationChain',
|
|
10256
|
+
* params: [USDC_ARC, user, 0],
|
|
10257
|
+
* recoveryAddress: padAddressToBytes32(user),
|
|
10258
|
+
* })
|
|
10259
|
+
*
|
|
10260
|
+
* // Wrap for the prepaid Quote-API FORWARD path (frame version 1).
|
|
10261
|
+
* const hookData = buildForwardingHookDataWithPayload(1, geBlob)
|
|
10262
|
+
* ```
|
|
10263
|
+
*/ function buildForwardingHookDataWithPayload(version, payload) {
|
|
10264
|
+
if (!Number.isInteger(version) || version < 0 || version > MAX_UINT32) {
|
|
10265
|
+
throw createValidationFailedError$1('version', version, 'Expected an integer in the uint32 range [0, 4294967295]');
|
|
10266
|
+
}
|
|
10267
|
+
if (!bytes.isHexString(payload)) {
|
|
10268
|
+
throw createValidationFailedError$1('payload', payload, 'Expected a 0x-prefixed hex string');
|
|
10269
|
+
}
|
|
10270
|
+
// `isHexString` accepts odd-length hex (e.g. '0xabc'); catch it here so it
|
|
10271
|
+
// surfaces as a KitError rather than ethers' raw "hex data is odd-length"
|
|
10272
|
+
// from `concat` below.
|
|
10273
|
+
if (payload.length % 2 !== 0) {
|
|
10274
|
+
throw createValidationFailedError$1('payload', payload, 'Expected an even-length (whole-byte) hex string');
|
|
10275
|
+
}
|
|
10276
|
+
// 32-byte header: 24-byte magic + uint32 version + uint32 dataLength (0).
|
|
10277
|
+
const frame = new Uint8Array(32);
|
|
10278
|
+
frame.set(new TextEncoder().encode(CCTP_FORWARD_MAGIC_PREFIX), 0);
|
|
10279
|
+
const view = new DataView(frame.buffer);
|
|
10280
|
+
view.setUint32(24, version, false) // big-endian
|
|
10281
|
+
;
|
|
10282
|
+
view.setUint32(28, CCTP_FORWARD_PAYLOAD_LENGTH, false) // big-endian, 0
|
|
10283
|
+
;
|
|
10284
|
+
return bytes.hexlify(bytes.concat([
|
|
10285
|
+
frame,
|
|
10286
|
+
payload
|
|
10287
|
+
]));
|
|
10288
|
+
}
|
|
10054
10289
|
/**
|
|
10055
10290
|
* Build a `cctp-forward` hookData frame that instructs Circle's Orbit relayer to
|
|
10056
10291
|
* create the recipient's Associated Token Account (ATA) before minting on Solana.
|
|
@@ -10128,6 +10363,43 @@ function buildForwardingHookData() {
|
|
|
10128
10363
|
]));
|
|
10129
10364
|
}
|
|
10130
10365
|
|
|
10366
|
+
/**
|
|
10367
|
+
* `version` field of the GenericExecutor hookData, in both the
|
|
10368
|
+
* `circle-generic-executor` header (`uint32`) and the ABI tuple (`uint8`). The
|
|
10369
|
+
* executor reverts if it is not `1`.
|
|
10370
|
+
*
|
|
10371
|
+
* @see https://circlepay.atlassian.net/wiki/spaces/~712020cd79585b52ea4353b4720c277fbfcca6/pages/3049291839
|
|
10372
|
+
*/ const GENERIC_EXECUTOR_HOOK_DATA_VERSION = 1;
|
|
10373
|
+
/**
|
|
10374
|
+
* ASCII magic that prefixes a GenericExecutor hookData blob.
|
|
10375
|
+
*
|
|
10376
|
+
* The executor auto-detects its payload by this string. It is left-aligned and
|
|
10377
|
+
* zero-padded to 24 bytes in the header, mirroring the `cctp-forward` frame
|
|
10378
|
+
* layout (magic + `uint32` version + `uint32` dataLength).
|
|
10379
|
+
*/ const GENERIC_EXECUTOR_MAGIC_PREFIX = 'circle-generic-executor';
|
|
10380
|
+
/**
|
|
10381
|
+
* Prepend the 32-byte `circle-generic-executor` header to the ABI tuple.
|
|
10382
|
+
*
|
|
10383
|
+
* Header layout (mirrors the `cctp-forward` frame): 24-byte zero-padded ASCII
|
|
10384
|
+
* magic + `uint32` version + `uint32` dataLength. Unlike the `cctp-forward`
|
|
10385
|
+
* frame (which the forwarder strips and so carries `dataLength = 0`), this
|
|
10386
|
+
* header's dataLength is the byte length of the ABI tuple that follows, since
|
|
10387
|
+
* the executor consumes both.
|
|
10388
|
+
*/ function prependGenericExecutorHeader(abiTuple) {
|
|
10389
|
+
const header = new Uint8Array(32);
|
|
10390
|
+
header.set(new TextEncoder().encode(GENERIC_EXECUTOR_MAGIC_PREFIX), 0);
|
|
10391
|
+
// Byte length of the ABI tuple that the header announces.
|
|
10392
|
+
const tupleByteLength = (abiTuple.length - 2) / 2;
|
|
10393
|
+
const view = new DataView(header.buffer);
|
|
10394
|
+
view.setUint32(24, GENERIC_EXECUTOR_HOOK_DATA_VERSION, false) // big-endian
|
|
10395
|
+
;
|
|
10396
|
+
view.setUint32(28, tupleByteLength, false) // big-endian
|
|
10397
|
+
;
|
|
10398
|
+
return bytes.hexlify(bytes.concat([
|
|
10399
|
+
header,
|
|
10400
|
+
abiTuple
|
|
10401
|
+
]));
|
|
10402
|
+
}
|
|
10131
10403
|
/**
|
|
10132
10404
|
* Left-pad a 20-byte EVM address to a 32-byte (`bytes32`) hex string.
|
|
10133
10405
|
*
|
|
@@ -10153,6 +10425,309 @@ function buildForwardingHookData() {
|
|
|
10153
10425
|
// matches ABI-decoded output.
|
|
10154
10426
|
return bytes.hexZeroPad(address.getAddress(address$1), 32).toLowerCase();
|
|
10155
10427
|
}
|
|
10428
|
+
/**
|
|
10429
|
+
* Encode the bare GenericExecutor + DepositForHandler payload for a CCTP v2
|
|
10430
|
+
* fast-transfer deposit into a dApp.
|
|
10431
|
+
*
|
|
10432
|
+
* Builds the layers inner→outer:
|
|
10433
|
+
* 1. dApp calldata — the dApp function selector + ABI params, with each amount
|
|
10434
|
+
* slot left as the caller-supplied placeholder.
|
|
10435
|
+
* 2. handler calldata — `(depositContract, approvalTarget, depositCalldata, amountIndices)`
|
|
10436
|
+
* for `DepositForHandler`.
|
|
10437
|
+
* 3. ABI tuple — `(uint8 version, bytes32 recoveryAddress, address handler, bytes handlerCalldata)`.
|
|
10438
|
+
* No handler selector travels on the wire; the executor applies a fixed one.
|
|
10439
|
+
* 4. header — the 32-byte `circle-generic-executor` magic frame prepended to the
|
|
10440
|
+
* tuple, by which the executor auto-detects the payload.
|
|
10441
|
+
*
|
|
10442
|
+
* The returned `hookData` is the bare GenericExecutor blob (header ‖ tuple) — the
|
|
10443
|
+
* exact bytes the executor consumes. It carries no `cctp-forward` envelope. For
|
|
10444
|
+
* the prepaid Quote-API FORWARD path, wrap it with
|
|
10445
|
+
* {@link buildForwardingHookDataWithPayload}; the forwarder strips that envelope
|
|
10446
|
+
* before the executor reads the blob.
|
|
10447
|
+
*
|
|
10448
|
+
* @param options - See {@link BuildDepositForGenericExecutorPayloadParams}.
|
|
10449
|
+
* @returns The encoded {@link DepositForGenericExecutorPayload} layers.
|
|
10450
|
+
* @throws {KitError} If `options` is not an object, `dappId` is unknown,
|
|
10451
|
+
* `config.deployments` is not an array, neither `domainId` nor
|
|
10452
|
+
* `destinationChain` resolves a domain (or the two disagree), no deployment
|
|
10453
|
+
* exists for the resolved domain, the deposit contract cannot be resolved (a
|
|
10454
|
+
* built-in deployment supplied without a `destinationChain`), no `handler` is
|
|
10455
|
+
* supplied and it cannot be resolved from `destinationChain`,
|
|
10456
|
+
* `recoveryAddress`/`handler`/contract addresses are malformed,
|
|
10457
|
+
* `config.function` is not a valid Solidity function signature, `params`
|
|
10458
|
+
* length does not match the dApp signature, `params` values fail ABI encoding
|
|
10459
|
+
* (type mismatch), `config.dynamicAmountIndices` is not an array, or an amount
|
|
10460
|
+
* index is out of range (all INPUT_VALIDATION_FAILED).
|
|
10461
|
+
*
|
|
10462
|
+
* @example Encode a 1-click cross-chain Circle Gateway deposit
|
|
10463
|
+
* ```typescript
|
|
10464
|
+
* import { buildDepositForGenericExecutorPayload, padAddressToBytes32 } from '@core/utils'
|
|
10465
|
+
* import { ArcTestnet } from '@core/chains'
|
|
10466
|
+
*
|
|
10467
|
+
* const user = '0x75275Aff2D01699D922f045b69ed291311209738'
|
|
10468
|
+
* const usdcArc = '0x3600000000000000000000000000000000000000'
|
|
10469
|
+
* const { hookData } = buildDepositForGenericExecutorPayload({
|
|
10470
|
+
* dappId: 'gateway_deposit',
|
|
10471
|
+
* destinationChain: ArcTestnet, // resolves the GatewayWallet + DepositForHandler
|
|
10472
|
+
* // depositFor(address token, address depositor, uint256 value), amount idx [2]
|
|
10473
|
+
* params: [usdcArc, user, 0],
|
|
10474
|
+
* recoveryAddress: padAddressToBytes32(user),
|
|
10475
|
+
* })
|
|
10476
|
+
*
|
|
10477
|
+
* // Pass hookData straight into the CCTP v2 fast transfer.
|
|
10478
|
+
* console.log(hookData)
|
|
10479
|
+
* ```
|
|
10480
|
+
*/ function buildDepositForGenericExecutorPayload(options) {
|
|
10481
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- runtime guard for plain-JS callers
|
|
10482
|
+
if (options === null || typeof options !== 'object') {
|
|
10483
|
+
throw createValidationFailedError$1('options', options, 'Expected an options object');
|
|
10484
|
+
}
|
|
10485
|
+
const { dappId, params: dappParams } = options;
|
|
10486
|
+
const registry = options.config ?? DAPP_CONFIG;
|
|
10487
|
+
// Look up the dApp before resolving the deposit contract or handler, so an
|
|
10488
|
+
// unknown dApp reports the actionable "Unknown dApp" error rather than an
|
|
10489
|
+
// unresolved-handler error.
|
|
10490
|
+
const config = registry[dappId];
|
|
10491
|
+
if (config === undefined) {
|
|
10492
|
+
throw createValidationFailedError$1('dappId', dappId, `Unknown dApp. Known dApps: ${Object.keys(registry).join(', ')}`);
|
|
10493
|
+
}
|
|
10494
|
+
if (!Array.isArray(config.deployments)) {
|
|
10495
|
+
throw createValidationFailedError$1('deployments', config.deployments, `Expected an array of deployments for dApp '${dappId}'`);
|
|
10496
|
+
}
|
|
10497
|
+
// Array.isArray narrows to `any[]`; re-assert the concrete type.
|
|
10498
|
+
const deployments = config.deployments;
|
|
10499
|
+
// Destination CCTP domain: taken from `destinationChain` when supplied (the
|
|
10500
|
+
// chain is the (network, domain) key), else the explicit `domainId`.
|
|
10501
|
+
const domainId = resolveDomainId(options);
|
|
10502
|
+
const deployment = deployments.find((d)=>d.domainId === domainId);
|
|
10503
|
+
if (deployment === undefined) {
|
|
10504
|
+
throw createValidationFailedError$1('domainId', domainId, `No '${dappId}' deployment for domain ${String(domainId)}`);
|
|
10505
|
+
}
|
|
10506
|
+
if (!Array.isArray(dappParams)) {
|
|
10507
|
+
throw createValidationFailedError$1('params', dappParams, 'Expected an array of ABI-ordered parameters');
|
|
10508
|
+
}
|
|
10509
|
+
if (!bytes.isHexString(options.recoveryAddress, 32)) {
|
|
10510
|
+
throw createValidationFailedError$1('recoveryAddress', options.recoveryAddress, 'Expected a 0x-prefixed 32-byte (bytes32) hex string');
|
|
10511
|
+
}
|
|
10512
|
+
// Deposit contract: the deployment's own address, or — for the built-in
|
|
10513
|
+
// gateway_deposit deployment, which carries none — the destination chain's
|
|
10514
|
+
// GatewayWallet, so the address lives only in @core/chains.
|
|
10515
|
+
const resolvedDepositContract = resolveDepositContract(deployment, options, dappId);
|
|
10516
|
+
// Handler: an explicit `handler` always wins; otherwise resolve the
|
|
10517
|
+
// DepositForHandler from `destinationChain`. The chain is the (network, domain)
|
|
10518
|
+
// key, so a shared CCTP domain (Arc is 26 on both testnet and mainnet) can
|
|
10519
|
+
// never resolve the wrong network's handler and strand funds.
|
|
10520
|
+
const handler = resolveDepositForHandler(options, domainId);
|
|
10521
|
+
if (!address.isAddress(handler)) {
|
|
10522
|
+
throw createValidationFailedError$1('handler', handler, 'Expected a valid EVM address');
|
|
10523
|
+
}
|
|
10524
|
+
const depositContract = assertAddress(resolvedDepositContract, 'depositContract');
|
|
10525
|
+
const approvalTarget = assertAddress(deployment.approvalTarget ?? resolvedDepositContract, 'approvalTarget');
|
|
10526
|
+
// 1. dApp calldata: selector + ABI-encoded params (amount slots stay as placeholders).
|
|
10527
|
+
let dappInterface;
|
|
10528
|
+
try {
|
|
10529
|
+
dappInterface = new abi.Interface([
|
|
10530
|
+
`function ${config.function}`
|
|
10531
|
+
]);
|
|
10532
|
+
} catch {
|
|
10533
|
+
throw createValidationFailedError$1('function', config.function, 'Expected a valid Solidity function signature');
|
|
10534
|
+
}
|
|
10535
|
+
const rawFragment = dappInterface.fragments[0];
|
|
10536
|
+
/* v8 ignore start -- defensive: guards against unexpected library behavior */ if (rawFragment === undefined || rawFragment.type !== 'function') {
|
|
10537
|
+
throw createValidationFailedError$1('function', config.function, 'Expected a valid Solidity function signature');
|
|
10538
|
+
}
|
|
10539
|
+
/* v8 ignore stop */ const fragment = rawFragment;
|
|
10540
|
+
if (dappParams.length !== fragment.inputs.length) {
|
|
10541
|
+
throw createValidationFailedError$1('params', dappParams, `'${config.function}' expects ${String(fragment.inputs.length)} params, got ${String(dappParams.length)}`);
|
|
10542
|
+
}
|
|
10543
|
+
let depositCalldata;
|
|
10544
|
+
try {
|
|
10545
|
+
depositCalldata = dappInterface.encodeFunctionData(fragment, dappParams);
|
|
10546
|
+
} catch {
|
|
10547
|
+
throw createValidationFailedError$1('params', dappParams, 'ABI encoding failed — check that each param matches the expected Solidity type');
|
|
10548
|
+
}
|
|
10549
|
+
if (!Array.isArray(config.dynamicAmountIndices)) {
|
|
10550
|
+
throw createValidationFailedError$1('dynamicAmountIndices', config.dynamicAmountIndices, `Expected an array of amount indices for dApp '${dappId}'`);
|
|
10551
|
+
}
|
|
10552
|
+
// Array.isArray narrows to `any[]`; re-assert the concrete type.
|
|
10553
|
+
const dynamicAmountIndices = config.dynamicAmountIndices;
|
|
10554
|
+
// Amount byte offsets in depositCalldata: 4 (selector) + paramIndex * 32.
|
|
10555
|
+
const amountIndices = dynamicAmountIndices.map((paramIndex)=>{
|
|
10556
|
+
if (!Number.isInteger(paramIndex) || paramIndex < 0 || paramIndex >= fragment.inputs.length) {
|
|
10557
|
+
throw createValidationFailedError$1('dynamicAmountIndices', paramIndex, `Index out of range for '${config.function}' (${String(fragment.inputs.length)} params)`);
|
|
10558
|
+
}
|
|
10559
|
+
return BigInt(4 + paramIndex * 32);
|
|
10560
|
+
});
|
|
10561
|
+
// 2. Handler layer.
|
|
10562
|
+
const handlerCalldata = abi.defaultAbiCoder.encode([
|
|
10563
|
+
'address',
|
|
10564
|
+
'address',
|
|
10565
|
+
'bytes',
|
|
10566
|
+
'uint256[]'
|
|
10567
|
+
], [
|
|
10568
|
+
depositContract,
|
|
10569
|
+
approvalTarget,
|
|
10570
|
+
depositCalldata,
|
|
10571
|
+
amountIndices
|
|
10572
|
+
]);
|
|
10573
|
+
// 3. Executor ABI tuple. No handler selector travels on the wire — the
|
|
10574
|
+
// executor applies a fixed selector internally.
|
|
10575
|
+
const executorTuple = abi.defaultAbiCoder.encode([
|
|
10576
|
+
'uint8',
|
|
10577
|
+
'bytes32',
|
|
10578
|
+
'address',
|
|
10579
|
+
'bytes'
|
|
10580
|
+
], [
|
|
10581
|
+
GENERIC_EXECUTOR_HOOK_DATA_VERSION,
|
|
10582
|
+
options.recoveryAddress,
|
|
10583
|
+
address.getAddress(handler),
|
|
10584
|
+
handlerCalldata
|
|
10585
|
+
]);
|
|
10586
|
+
// 4. Prepend the circle-generic-executor magic header; this is the final
|
|
10587
|
+
// bare GE blob the executor consumes.
|
|
10588
|
+
const hookData = prependGenericExecutorHeader(executorTuple);
|
|
10589
|
+
return {
|
|
10590
|
+
hookData,
|
|
10591
|
+
handlerCalldata,
|
|
10592
|
+
depositCalldata,
|
|
10593
|
+
amountIndices,
|
|
10594
|
+
depositContract,
|
|
10595
|
+
approvalTarget
|
|
10596
|
+
};
|
|
10597
|
+
}
|
|
10598
|
+
/**
|
|
10599
|
+
* Config key of the built-in Circle Gateway deposit dApp. Its deposit contract
|
|
10600
|
+
* is the destination chain's GatewayWallet, resolved from `destinationChain`
|
|
10601
|
+
* (not a hardcoded address), so this is the only dApp whose deployment may omit
|
|
10602
|
+
* `depositContract`.
|
|
10603
|
+
*/ const GATEWAY_DEPOSIT_DAPP_ID = 'gateway_deposit';
|
|
10604
|
+
/**
|
|
10605
|
+
* Built-in dApp registry. Adding a new `depositFor`-style dApp is a config entry
|
|
10606
|
+
* here (or via {@link BuildDepositForGenericExecutorPayloadParams.config}).
|
|
10607
|
+
*
|
|
10608
|
+
* @remarks
|
|
10609
|
+
* Only dApps with confirmed deployment addresses and active callers are included.
|
|
10610
|
+
* The built-in `gateway_deposit` entry omits `depositContract` — it is resolved
|
|
10611
|
+
* from the destination chain's GatewayWallet (`@core/chains`) rather than
|
|
10612
|
+
* duplicated here. Pass a custom registry via `config` for unlisted dApps.
|
|
10613
|
+
*/ const DAPP_CONFIG = {
|
|
10614
|
+
// Circle Gateway: depositFor(address token, address depositor, uint256 value)
|
|
10615
|
+
[GATEWAY_DEPOSIT_DAPP_ID]: {
|
|
10616
|
+
function: 'depositFor(address,address,uint256)',
|
|
10617
|
+
dynamicAmountIndices: [
|
|
10618
|
+
2
|
|
10619
|
+
],
|
|
10620
|
+
deployments: [
|
|
10621
|
+
// Arc Testnet (CCTP domain 26). The deposit contract is the chain's
|
|
10622
|
+
// GatewayWallet, resolved from `destinationChain` (@core/chains) rather
|
|
10623
|
+
// than duplicated here.
|
|
10624
|
+
{
|
|
10625
|
+
domainId: 26
|
|
10626
|
+
}
|
|
10627
|
+
]
|
|
10628
|
+
}
|
|
10629
|
+
};
|
|
10630
|
+
/**
|
|
10631
|
+
* Resolve the destination CCTP domain for an encode request.
|
|
10632
|
+
*
|
|
10633
|
+
* Prefers {@link BuildDepositForGenericExecutorPayloadParams.destinationChain}
|
|
10634
|
+
* (`chain.cctp.domain`) — the chain is the (network, domain) key. Falls back to
|
|
10635
|
+
* an explicit `domainId`. When both are supplied they must agree.
|
|
10636
|
+
*
|
|
10637
|
+
* @param options - The encode request.
|
|
10638
|
+
* @returns The destination CCTP domain.
|
|
10639
|
+
* @throws {KitError} If no domain is available, or `domainId` disagrees with
|
|
10640
|
+
* `destinationChain` (INPUT_VALIDATION_FAILED).
|
|
10641
|
+
* @internal
|
|
10642
|
+
*/ function resolveDomainId(options) {
|
|
10643
|
+
const chain = options.destinationChain;
|
|
10644
|
+
if (chain !== undefined) {
|
|
10645
|
+
const chainDomain = chain.cctp?.domain;
|
|
10646
|
+
if (chainDomain !== undefined) {
|
|
10647
|
+
if (options.domainId !== undefined && options.domainId !== chainDomain) {
|
|
10648
|
+
throw createValidationFailedError$1('domainId', options.domainId, `does not match destinationChain '${chain.name}' CCTP domain ` + String(chainDomain));
|
|
10649
|
+
}
|
|
10650
|
+
return chainDomain;
|
|
10651
|
+
}
|
|
10652
|
+
}
|
|
10653
|
+
if (options.domainId !== undefined) {
|
|
10654
|
+
return options.domainId;
|
|
10655
|
+
}
|
|
10656
|
+
throw createValidationFailedError$1('domainId', options.domainId, "Provide 'domainId', or a 'destinationChain' with a CCTP domain");
|
|
10657
|
+
}
|
|
10658
|
+
/**
|
|
10659
|
+
* Resolve the deposit contract the handler calls.
|
|
10660
|
+
*
|
|
10661
|
+
* Uses the deployment's own `depositContract` when present. Only the built-in
|
|
10662
|
+
* {@link GATEWAY_DEPOSIT_DAPP_ID} may omit it: its deposit contract is the
|
|
10663
|
+
* destination chain's Gateway v1 wallet, resolved from
|
|
10664
|
+
* {@link BuildDepositForGenericExecutorPayloadParams.destinationChain} so the
|
|
10665
|
+
* address is owned once in `@core/chains`. Any other dApp that omits
|
|
10666
|
+
* `depositContract` is a config error and fails here rather than silently
|
|
10667
|
+
* targeting the GatewayWallet.
|
|
10668
|
+
*
|
|
10669
|
+
* @param deployment - The resolved dApp deployment.
|
|
10670
|
+
* @param options - The encode request.
|
|
10671
|
+
* @param dappId - The dApp key, checked against {@link GATEWAY_DEPOSIT_DAPP_ID}.
|
|
10672
|
+
* @returns The deposit contract address (unvalidated; the caller checks it).
|
|
10673
|
+
* @throws {KitError} If a non-`gateway_deposit` deployment omits
|
|
10674
|
+
* `depositContract`, or if `gateway_deposit` has no Gateway v1
|
|
10675
|
+
* `destinationChain` to resolve one (INPUT_VALIDATION_FAILED).
|
|
10676
|
+
* @internal
|
|
10677
|
+
*/ function resolveDepositContract(deployment, options, dappId) {
|
|
10678
|
+
if (deployment.depositContract !== undefined) {
|
|
10679
|
+
return deployment.depositContract;
|
|
10680
|
+
}
|
|
10681
|
+
// Only gateway_deposit may omit its address (it targets the chain's
|
|
10682
|
+
// GatewayWallet). Any other addressless deployment is a config mistake and
|
|
10683
|
+
// must fail rather than silently resolve to the GatewayWallet.
|
|
10684
|
+
if (dappId !== GATEWAY_DEPOSIT_DAPP_ID) {
|
|
10685
|
+
throw createValidationFailedError$1('depositContract', dappId, `dApp '${dappId}' must declare a 'depositContract'; only the built-in ` + `'${GATEWAY_DEPOSIT_DAPP_ID}' resolves its address from the ` + "destination chain's GatewayWallet");
|
|
10686
|
+
}
|
|
10687
|
+
const chain = options.destinationChain;
|
|
10688
|
+
if (chain === undefined || !isGatewayV1Supported(chain)) {
|
|
10689
|
+
throw createValidationFailedError$1('depositContract', dappId, `'${GATEWAY_DEPOSIT_DAPP_ID}' needs a 'destinationChain' with Gateway v1 ` + 'support to resolve its GatewayWallet, or an explicit deployment address');
|
|
10690
|
+
}
|
|
10691
|
+
return chain.gateway.contracts.v1.wallet;
|
|
10692
|
+
}
|
|
10693
|
+
/**
|
|
10694
|
+
* Resolve the `DepositForHandler` address for an encode request.
|
|
10695
|
+
*
|
|
10696
|
+
* An explicit `options.handler` always wins. Otherwise the handler is resolved
|
|
10697
|
+
* from {@link BuildDepositForGenericExecutorPayloadParams.destinationChain}
|
|
10698
|
+
* (`chain.gateway.contracts.v1.depositForHandler`). The chain is the (network,
|
|
10699
|
+
* domain) key, so a CCTP domain shared across a chain's testnet and mainnet
|
|
10700
|
+
* cannot resolve the wrong network's handler; a missing chain or an unregistered
|
|
10701
|
+
* handler throws rather than guessing.
|
|
10702
|
+
*
|
|
10703
|
+
* @param options - The encode request.
|
|
10704
|
+
* @param domainId - The resolved destination domain, reported in the error.
|
|
10705
|
+
* @returns The resolved handler address (unvalidated; the caller checks it).
|
|
10706
|
+
* @throws {KitError} If `handler` is omitted and cannot be resolved
|
|
10707
|
+
* (INPUT_VALIDATION_FAILED).
|
|
10708
|
+
* @internal
|
|
10709
|
+
*/ function resolveDepositForHandler(options, domainId) {
|
|
10710
|
+
if (options.handler !== undefined) {
|
|
10711
|
+
return options.handler;
|
|
10712
|
+
}
|
|
10713
|
+
const chain = options.destinationChain;
|
|
10714
|
+
if (chain === undefined) {
|
|
10715
|
+
throw createValidationFailedError$1('handler', domainId, "No 'handler' supplied; pass 'handler' explicitly, or a " + "'destinationChain' whose Gateway config registers a DepositForHandler");
|
|
10716
|
+
}
|
|
10717
|
+
const registered = isGatewayV1Supported(chain) ? chain.gateway.contracts.v1.depositForHandler : undefined;
|
|
10718
|
+
if (registered === undefined) {
|
|
10719
|
+
throw createValidationFailedError$1('handler', domainId, `No DepositForHandler registered for domain ${String(domainId)} on ` + `chain '${chain.name}'; pass 'handler' explicitly`);
|
|
10720
|
+
}
|
|
10721
|
+
return registered;
|
|
10722
|
+
}
|
|
10723
|
+
/**
|
|
10724
|
+
* Validate and checksum an EVM address, throwing a consistent validation error.
|
|
10725
|
+
*/ function assertAddress(address$1, field) {
|
|
10726
|
+
if (!address.isAddress(address$1)) {
|
|
10727
|
+
throw createValidationFailedError$1(field, address$1, 'Expected a valid EVM address');
|
|
10728
|
+
}
|
|
10729
|
+
return address.getAddress(address$1);
|
|
10730
|
+
}
|
|
10156
10731
|
|
|
10157
10732
|
/**
|
|
10158
10733
|
* Configuration for {@link retryAsync}.
|
|
@@ -10242,7 +10817,7 @@ function resolveOptions(options) {
|
|
|
10242
10817
|
* allowlisted {@link ClientLogPayload} fields (and the allowlisted
|
|
10243
10818
|
* sub-fields of `errorDetails` / `clientContext`) are copied across.
|
|
10244
10819
|
* A regressing upstream mapper — or a plain-JS caller that bypasses the
|
|
10245
|
-
* type — therefore cannot exfiltrate stray properties (secrets,
|
|
10820
|
+
* type — therefore cannot exfiltrate stray properties (secrets,
|
|
10246
10821
|
* raw error stacks) through the analytics channel. Optional fields are
|
|
10247
10822
|
* only included when present so the serialised shape matches the
|
|
10248
10823
|
* server's strict schema.
|
|
@@ -10265,6 +10840,9 @@ function resolveOptions(options) {
|
|
|
10265
10840
|
if (payload.destinationChain !== undefined) safe['destinationChain'] = payload.destinationChain;
|
|
10266
10841
|
if (payload.tokenIn !== undefined) safe['tokenIn'] = payload.tokenIn;
|
|
10267
10842
|
if (payload.tokenOut !== undefined) safe['tokenOut'] = payload.tokenOut;
|
|
10843
|
+
if (payload.amountIn !== undefined) safe['amountIn'] = payload.amountIn;
|
|
10844
|
+
if (payload.durationMs !== undefined) safe['durationMs'] = payload.durationMs;
|
|
10845
|
+
if (payload.sourceAddress !== undefined) safe['sourceAddress'] = payload.sourceAddress;
|
|
10268
10846
|
if (payload.txHash !== undefined) safe['txHash'] = payload.txHash;
|
|
10269
10847
|
if (payload.correlationId !== undefined) safe['correlationId'] = payload.correlationId;
|
|
10270
10848
|
if (payload.errorDetails !== undefined) {
|
|
@@ -10461,14 +11039,28 @@ function resolveOptions(options) {
|
|
|
10461
11039
|
}
|
|
10462
11040
|
|
|
10463
11041
|
/**
|
|
10464
|
-
*
|
|
10465
|
-
*
|
|
11042
|
+
* Emit a stable console warning when building or emitting a telemetry payload
|
|
11043
|
+
* throws — for example, a buggy `TelemetryContextResolver`, a regression in
|
|
10466
11044
|
* `extractErrorDetails`, or a synchronous failure inside `emitAnalyticsLog`
|
|
10467
|
-
* before it could swallow the error itself.
|
|
10468
|
-
*
|
|
10469
|
-
*
|
|
11045
|
+
* before it could swallow the error itself. Uses a stable prefix so the
|
|
11046
|
+
* drop is discoverable via grep. Never re-throws: the caller's original
|
|
11047
|
+
* operation error must always win.
|
|
10470
11048
|
*
|
|
10471
11049
|
* @internal
|
|
11050
|
+
*
|
|
11051
|
+
* @param eventType - The telemetry event type that was being emitted.
|
|
11052
|
+
* @param cause - The error or value that caused the drop.
|
|
11053
|
+
*
|
|
11054
|
+
* @example
|
|
11055
|
+
* ```typescript
|
|
11056
|
+
* import { warnTelemetryDrop } from '@core/utils'
|
|
11057
|
+
*
|
|
11058
|
+
* try {
|
|
11059
|
+
* void emitAnalyticsLog(payload)
|
|
11060
|
+
* } catch (err) {
|
|
11061
|
+
* warnTelemetryDrop('my_event', err)
|
|
11062
|
+
* }
|
|
11063
|
+
* ```
|
|
10472
11064
|
*/ function warnTelemetryDrop(eventType, cause) {
|
|
10473
11065
|
try {
|
|
10474
11066
|
// Pass `cause` as the second console.warn argument rather than
|
|
@@ -10508,6 +11100,9 @@ function resolveOptions(options) {
|
|
|
10508
11100
|
...context?.tokenOut != null && {
|
|
10509
11101
|
tokenOut: context.tokenOut
|
|
10510
11102
|
},
|
|
11103
|
+
...context?.amountIn != null && {
|
|
11104
|
+
amountIn: context.amountIn
|
|
11105
|
+
},
|
|
10511
11106
|
...context?.txHash != null && {
|
|
10512
11107
|
txHash: context.txHash
|
|
10513
11108
|
},
|
|
@@ -10609,7 +11204,7 @@ function resolveOptions(options) {
|
|
|
10609
11204
|
const stepEntry = stepEventMap.find(([name])=>name === failedStep?.name);
|
|
10610
11205
|
// `failedStep.errorMessage` is intentionally **not** copied into the payload.
|
|
10611
11206
|
// Provider messages are unbounded and frequently contain operator data
|
|
10612
|
-
// (
|
|
11207
|
+
// (signatures, partial intent payloads, raw RPC responses). The
|
|
10613
11208
|
// step name plus the surrounding context fields already identify *which*
|
|
10614
11209
|
// phase failed; the *why* is left to the corresponding step-level logs that
|
|
10615
11210
|
// the provider emits separately. The thrown-error path (`extractErrorDetails`
|
|
@@ -10626,7 +11221,7 @@ function resolveOptions(options) {
|
|
|
10626
11221
|
}
|
|
10627
11222
|
|
|
10628
11223
|
var name$2 = "@circle-fin/bridge-kit";
|
|
10629
|
-
var version$3 = "1.14.
|
|
11224
|
+
var version$3 = "1.14.1";
|
|
10630
11225
|
var pkg$3 = {
|
|
10631
11226
|
name: name$2,
|
|
10632
11227
|
version: version$3};
|
|
@@ -12320,7 +12915,7 @@ var TransferSpeed;
|
|
|
12320
12915
|
* })
|
|
12321
12916
|
* ```
|
|
12322
12917
|
*/ function createLogger(options, stream) {
|
|
12323
|
-
const { redact, ...pinoOptions } = {};
|
|
12918
|
+
const { redact, ...pinoOptions } = options ?? {};
|
|
12324
12919
|
// Build redaction config
|
|
12325
12920
|
const redactConfig = buildRedactConfig(redact);
|
|
12326
12921
|
// Build final pino options, only include redact if defined
|
|
@@ -13674,6 +14269,8 @@ const CUSTOM_BURN_GAS_ESTIMATE_EVM = 201_525n // p99 and max are same here: 201_
|
|
|
13674
14269
|
;
|
|
13675
14270
|
const RECEIVE_MESSAGE_GAS_ESTIMATE_EVM = 237_401n // (99p: 163_963n + max: 310_839n) / 2 = 237_401n
|
|
13676
14271
|
;
|
|
14272
|
+
/** Gas units consumed by `depositForBurnWithHookAndFees` on an EVM chain (prepaid-FORWARD path). */ const DEPOSIT_FOR_BURN_WITH_FEES_GAS_ESTIMATE_EVM = 626_584n // avg of the last 10 txns
|
|
14273
|
+
;
|
|
13677
14274
|
// Gas FLOORS, not ceilings — kept separate from the fee-estimate averages
|
|
13678
14275
|
// above. `executePreparedChainRequest` submits
|
|
13679
14276
|
// max(estimate * buffer, floor), so a chain whose real cost exceeds the floor
|
|
@@ -15955,7 +16552,7 @@ const mockAttestationMessage = {
|
|
|
15955
16552
|
return step;
|
|
15956
16553
|
}
|
|
15957
16554
|
|
|
15958
|
-
var version$2 = "1.
|
|
16555
|
+
var version$2 = "1.13.0";
|
|
15959
16556
|
var pkg$2 = {
|
|
15960
16557
|
version: version$2};
|
|
15961
16558
|
|
|
@@ -16661,6 +17258,9 @@ var pkg$2 = {
|
|
|
16661
17258
|
}
|
|
16662
17259
|
}
|
|
16663
17260
|
|
|
17261
|
+
const logger = createLogger({
|
|
17262
|
+
name: 'provider-cctp-v2'
|
|
17263
|
+
});
|
|
16664
17264
|
function isPlainObject(value) {
|
|
16665
17265
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
16666
17266
|
return false;
|
|
@@ -17023,6 +17623,116 @@ function assertCCTPV2Config(config) {
|
|
|
17023
17623
|
return estimateResult;
|
|
17024
17624
|
}
|
|
17025
17625
|
/**
|
|
17626
|
+
* Estimate source-chain gas for a prepaid-FORWARD deposit burn via
|
|
17627
|
+
* `TokenMessengerWithFees.depositForBurnWithHookAndFees`.
|
|
17628
|
+
*
|
|
17629
|
+
* Builds a size-correct GenericExecutor hookData placeholder — using the
|
|
17630
|
+
* pre-validated `contracts.executor` and `contracts.depositForHandler` — so
|
|
17631
|
+
* the EVM calldata length matches production. Attempts a live
|
|
17632
|
+
* `eth_estimateGas` via the adapter's `cctp.v2.depositForBurnWithFees`
|
|
17633
|
+
* action and falls back to the static
|
|
17634
|
+
* {@link DEPOSIT_FOR_BURN_WITH_FEES_GAS_ESTIMATE_EVM} constant when the live
|
|
17635
|
+
* RPC call fails.
|
|
17636
|
+
*
|
|
17637
|
+
* Gateway eligibility is the caller's responsibility: validate the
|
|
17638
|
+
* destination chain with `resolveGatewayExecutorContracts` (UBK) before
|
|
17639
|
+
* calling this method.
|
|
17640
|
+
*
|
|
17641
|
+
* @param params - Estimation parameters including adapter, chains, amount,
|
|
17642
|
+
* the signed fee quote returned by the Quote API, and the pre-validated
|
|
17643
|
+
* Gateway executor contracts resolved by the caller.
|
|
17644
|
+
* @returns Promise resolving to the estimated (or fallback) gas cost.
|
|
17645
|
+
* @throws KitError `SERVICE_INTERNAL_ERROR` (FATAL) if `dstChain`'s
|
|
17646
|
+
* `usdcAddress` is `null`.
|
|
17647
|
+
*
|
|
17648
|
+
* @example
|
|
17649
|
+
* ```typescript
|
|
17650
|
+
* const contracts = resolveGatewayExecutorContracts(srcChain, dstChain)
|
|
17651
|
+
* const gasEstimate = await CCTPV2BridgingProvider.estimateDepositBurn({
|
|
17652
|
+
* adapter: evmAdapter,
|
|
17653
|
+
* srcChain: Ethereum,
|
|
17654
|
+
* dstChain: ArcTestnet,
|
|
17655
|
+
* amountMinorUnits: 100_000_000n,
|
|
17656
|
+
* refundAddress: '0xUserWallet',
|
|
17657
|
+
* signedQuote: quote.signedQuote,
|
|
17658
|
+
* feeToken: quote.feeToken,
|
|
17659
|
+
* feeTotalAmount: BigInt(quote.feeTotalAmount),
|
|
17660
|
+
* resolvedContext,
|
|
17661
|
+
* contracts,
|
|
17662
|
+
* })
|
|
17663
|
+
* ```
|
|
17664
|
+
*/ static async estimateDepositBurn(params) {
|
|
17665
|
+
const { adapter, srcChain, dstChain, amountMinorUnits, refundAddress, signedQuote, feeToken, feeTotalAmount, resolvedContext, contracts } = params;
|
|
17666
|
+
const { executor, depositForHandler } = contracts;
|
|
17667
|
+
if (dstChain.usdcAddress === null) {
|
|
17668
|
+
throw new KitError({
|
|
17669
|
+
...ServiceError.INTERNAL_ERROR,
|
|
17670
|
+
recoverability: 'FATAL',
|
|
17671
|
+
message: `Destination chain ${dstChain.name} has no USDC address configured`
|
|
17672
|
+
});
|
|
17673
|
+
}
|
|
17674
|
+
// Build a size-correct hookData for eth_estimateGas. The EVM uses calldata
|
|
17675
|
+
// length to compute gas, so the byte layout must match production even
|
|
17676
|
+
// though field values are not final.
|
|
17677
|
+
const { hookData: geBlob } = buildDepositForGenericExecutorPayload({
|
|
17678
|
+
dappId: 'gateway_deposit',
|
|
17679
|
+
destinationChain: dstChain,
|
|
17680
|
+
handler: depositForHandler,
|
|
17681
|
+
params: [
|
|
17682
|
+
dstChain.usdcAddress,
|
|
17683
|
+
refundAddress,
|
|
17684
|
+
0n
|
|
17685
|
+
],
|
|
17686
|
+
recoveryAddress: padAddressToBytes32(refundAddress),
|
|
17687
|
+
// Override deployments only — spread the canonical function signature
|
|
17688
|
+
// and amount indices from DAPP_CONFIG so they stay in sync.
|
|
17689
|
+
config: {
|
|
17690
|
+
gateway_deposit: {
|
|
17691
|
+
...DAPP_CONFIG.gateway_deposit,
|
|
17692
|
+
deployments: [
|
|
17693
|
+
{
|
|
17694
|
+
domainId: dstChain.cctp.domain
|
|
17695
|
+
}
|
|
17696
|
+
]
|
|
17697
|
+
}
|
|
17698
|
+
}
|
|
17699
|
+
});
|
|
17700
|
+
const hookData = buildForwardingHookDataWithPayload(GENERIC_EXECUTOR_HOOK_DATA_VERSION, geBlob);
|
|
17701
|
+
// Coupling guard: the prepaid FORWARD path always requests a FORWARD fee
|
|
17702
|
+
// item, so the hookData must carry a `cctp-forward` frame — matches the
|
|
17703
|
+
// assertion in `prepareDepositForBurn`.
|
|
17704
|
+
assertForwardHookData(hookData);
|
|
17705
|
+
try {
|
|
17706
|
+
const prepared = await adapter.prepareAction('cctp.v2.depositForBurnWithFees', {
|
|
17707
|
+
fromChain: srcChain,
|
|
17708
|
+
toChain: dstChain,
|
|
17709
|
+
amount: amountMinorUnits,
|
|
17710
|
+
mintRecipient: executor,
|
|
17711
|
+
destinationCaller: executor,
|
|
17712
|
+
claim: {
|
|
17713
|
+
signedQuote,
|
|
17714
|
+
refundAddress
|
|
17715
|
+
},
|
|
17716
|
+
feeToken,
|
|
17717
|
+
feeTotalAmount,
|
|
17718
|
+
hookData
|
|
17719
|
+
}, resolvedContext);
|
|
17720
|
+
return await prepared.estimate(undefined);
|
|
17721
|
+
} catch (err) {
|
|
17722
|
+
logger.debug('estimateDepositBurn: live eth_estimateGas failed, using static fallback', {
|
|
17723
|
+
err,
|
|
17724
|
+
chain: srcChain.name
|
|
17725
|
+
});
|
|
17726
|
+
try {
|
|
17727
|
+
return await adapter.calculateTransactionFee(DEPOSIT_FOR_BURN_WITH_FEES_GAS_ESTIMATE_EVM, undefined, srcChain);
|
|
17728
|
+
} catch (feeErr) {
|
|
17729
|
+
throw createRpcEndpointError(srcChain.name, {
|
|
17730
|
+
rawError: feeErr
|
|
17731
|
+
});
|
|
17732
|
+
}
|
|
17733
|
+
}
|
|
17734
|
+
}
|
|
17735
|
+
/**
|
|
17026
17736
|
* Extracts OperationContext from bridge parameters for a given wallet context.
|
|
17027
17737
|
*
|
|
17028
17738
|
* This method extracts the chain and address information from the wallet context
|
|
@@ -17649,6 +18359,99 @@ function assertCCTPV2Config(config) {
|
|
|
17649
18359
|
return await source.adapter.prepareAction('cctp.v2.depositForBurn', actionParams, resolvedContext);
|
|
17650
18360
|
}
|
|
17651
18361
|
/**
|
|
18362
|
+
* Prepare the source-chain `depositForBurnWithHookAndFees` call for the
|
|
18363
|
+
* GenericExecutor FORWARD path.
|
|
18364
|
+
*
|
|
18365
|
+
* Exposed as a public static method so the UBK fast-deposit flow can invoke
|
|
18366
|
+
* it directly without holding a provider instance. The byte layout mirrors
|
|
18367
|
+
* {@link CCTPV2BridgingProvider.estimateDepositBurn} so gas estimates and the
|
|
18368
|
+
* executed call agree.
|
|
18369
|
+
*
|
|
18370
|
+
* @typeParam TFromAdapterCapabilities - The source adapter's capabilities.
|
|
18371
|
+
* @param params - Burn parameters including adapter, chains, deposit action,
|
|
18372
|
+
* amount, signer address, signed fee quote, and pre-resolved adapter context.
|
|
18373
|
+
* @returns The prepared `depositForBurnWithHookAndFees` burn transaction.
|
|
18374
|
+
* @throws {KitError} `UNSUPPORTED_ROUTE` when `dstChain` lacks a
|
|
18375
|
+
* GenericExecutor or DepositForHandler, or the `deposit.dappId` is unknown.
|
|
18376
|
+
*
|
|
18377
|
+
* @example
|
|
18378
|
+
* ```typescript
|
|
18379
|
+
* import { CCTPV2BridgingProvider } from '@circle-fin/provider-cctp-v2'
|
|
18380
|
+
* import { Ethereum, ArcTestnet } from '@core/chains'
|
|
18381
|
+
*
|
|
18382
|
+
* const prepared = await CCTPV2BridgingProvider.prepareDepositForBurn({
|
|
18383
|
+
* adapter,
|
|
18384
|
+
* srcChain: Ethereum,
|
|
18385
|
+
* dstChain: ArcTestnet,
|
|
18386
|
+
* deposit: { dappId: 'gateway_deposit', params: [usdcAddress, recipient, 0n] },
|
|
18387
|
+
* amountMinorUnits: 100_000_000n,
|
|
18388
|
+
* refundAddress: '0xSender...',
|
|
18389
|
+
* signedQuote: quote.signedQuote,
|
|
18390
|
+
* feeToken: quote.feeToken,
|
|
18391
|
+
* feeTotalAmount: BigInt(quote.feeTotalAmount),
|
|
18392
|
+
* resolvedContext,
|
|
18393
|
+
* })
|
|
18394
|
+
* const txHash = await prepared.execute()
|
|
18395
|
+
* ```
|
|
18396
|
+
*/ static async prepareDepositForBurn(params) {
|
|
18397
|
+
const { adapter, srcChain, dstChain, deposit, amountMinorUnits, refundAddress, signedQuote, feeToken, feeTotalAmount, resolvedContext } = params;
|
|
18398
|
+
// Resolve executor and depositForHandler from the destination chain's
|
|
18399
|
+
// gateway config. Throw an unsupported-route error if either is absent.
|
|
18400
|
+
const executor = dstChain.gateway?.contracts?.v1?.genericExecutor;
|
|
18401
|
+
const depositForHandler = dstChain.gateway?.contracts?.v1?.depositForHandler;
|
|
18402
|
+
if (!executor || !depositForHandler) {
|
|
18403
|
+
throw createUnsupportedRouteError(srcChain.name, dstChain.name);
|
|
18404
|
+
}
|
|
18405
|
+
// Resolve the canonical dApp config (function signature + amount indices)
|
|
18406
|
+
// for THIS deposit's `dappId`. Reject an unknown `dappId` rather than
|
|
18407
|
+
// encoding the wrong ABI selector, which would burn on the source but
|
|
18408
|
+
// revert in the executor call on the destination.
|
|
18409
|
+
const dappConfig = DAPP_CONFIG[deposit.dappId];
|
|
18410
|
+
if (dappConfig === undefined) {
|
|
18411
|
+
throw createUnsupportedRouteError(srcChain.name, dstChain.name);
|
|
18412
|
+
}
|
|
18413
|
+
// Build the bare GenericExecutor payload, then wrap it in the `cctp-forward`
|
|
18414
|
+
// frame required by the prepaid-FORWARD wrapper.
|
|
18415
|
+
const { hookData: geBlob } = buildDepositForGenericExecutorPayload({
|
|
18416
|
+
dappId: deposit.dappId,
|
|
18417
|
+
destinationChain: dstChain,
|
|
18418
|
+
handler: depositForHandler,
|
|
18419
|
+
params: deposit.params,
|
|
18420
|
+
recoveryAddress: padAddressToBytes32(refundAddress),
|
|
18421
|
+
config: {
|
|
18422
|
+
[deposit.dappId]: {
|
|
18423
|
+
...dappConfig,
|
|
18424
|
+
deployments: [
|
|
18425
|
+
{
|
|
18426
|
+
domainId: dstChain.cctp.domain
|
|
18427
|
+
}
|
|
18428
|
+
]
|
|
18429
|
+
}
|
|
18430
|
+
}
|
|
18431
|
+
});
|
|
18432
|
+
const hookData = buildForwardingHookDataWithPayload(GENERIC_EXECUTOR_HOOK_DATA_VERSION, geBlob);
|
|
18433
|
+
// Coupling guard: the prepaid FORWARD path always requests a FORWARD fee
|
|
18434
|
+
// item, so the hookData must carry a `cctp-forward` frame; otherwise the
|
|
18435
|
+
// wrapper reverts `ForwardFeeWithoutHook`.
|
|
18436
|
+
assertForwardHookData(hookData);
|
|
18437
|
+
// Source-chain burn: `mintRecipient` AND `destinationCaller` are both the
|
|
18438
|
+
// executor; fees are prepaid against the signed quote.
|
|
18439
|
+
return adapter.prepareAction('cctp.v2.depositForBurnWithFees', {
|
|
18440
|
+
fromChain: srcChain,
|
|
18441
|
+
toChain: dstChain,
|
|
18442
|
+
amount: amountMinorUnits,
|
|
18443
|
+
mintRecipient: executor,
|
|
18444
|
+
destinationCaller: executor,
|
|
18445
|
+
hookData,
|
|
18446
|
+
claim: {
|
|
18447
|
+
signedQuote,
|
|
18448
|
+
refundAddress
|
|
18449
|
+
},
|
|
18450
|
+
feeToken,
|
|
18451
|
+
feeTotalAmount
|
|
18452
|
+
}, resolvedContext);
|
|
18453
|
+
}
|
|
18454
|
+
/**
|
|
17652
18455
|
* Prepare a prepaid-FORWARD burn through the `TokenMessengerWithFees` wrapper.
|
|
17653
18456
|
*
|
|
17654
18457
|
* Build the source-chain `depositForBurnWithHookAndFees` call. Fees are
|
|
@@ -17913,9 +18716,13 @@ function assertCCTPV2Config(config) {
|
|
|
17913
18716
|
|
|
17914
18717
|
/**
|
|
17915
18718
|
* Base URL for Circle's Quote API (hosted in Iris) on mainnet/production.
|
|
18719
|
+
*
|
|
18720
|
+
* @internal
|
|
17916
18721
|
*/ const IRIS_API_BASE_URL = 'https://iris-api.circle.com';
|
|
17917
18722
|
/**
|
|
17918
18723
|
* Base URL for Circle's Quote API (hosted in Iris) on testnet/sandbox.
|
|
18724
|
+
*
|
|
18725
|
+
* @internal
|
|
17919
18726
|
*/ const IRIS_API_SANDBOX_BASE_URL = 'https://iris-api-sandbox.circle.com';
|
|
17920
18727
|
/**
|
|
17921
18728
|
* Native fee-token sentinel (the zero address).
|
|
@@ -17923,19 +18730,25 @@ function assertCCTPV2Config(config) {
|
|
|
17923
18730
|
* When `feeToken` is the zero address the quote prices fees in the source
|
|
17924
18731
|
* chain's native gas token (paid as `msg.value` on-chain). Pass a USDC token
|
|
17925
18732
|
* address instead to denominate fees in USDC.
|
|
18733
|
+
*
|
|
18734
|
+
* @internal
|
|
17926
18735
|
*/ const NATIVE_FEE_TOKEN = '0x0000000000000000000000000000000000000000';
|
|
17927
18736
|
/**
|
|
17928
18737
|
* API path prefix for the CCTP v2 USDC burn quote endpoint.
|
|
17929
18738
|
*
|
|
17930
18739
|
* The full path is `${QUOTE_BURN_USDC_PATH}/{sourceDomain}/{destinationDomain}`;
|
|
17931
18740
|
* `usdc` is a fixed literal, not a token parameter.
|
|
18741
|
+
*
|
|
18742
|
+
* @internal
|
|
17932
18743
|
*/ const QUOTE_BURN_USDC_PATH = '/v2/quote/burn/usdc';
|
|
17933
18744
|
/**
|
|
17934
18745
|
* API path prefix for the CCTP v2 USDC quote validate endpoint.
|
|
17935
18746
|
*
|
|
17936
18747
|
* The full path is `${QUOTE_VALIDATE_USDC_PATH}/{sourceDomain}`; accepts a
|
|
17937
|
-
* `POST { abiSignature, args }` body and returns
|
|
17938
|
-
*
|
|
18748
|
+
* `POST { abiSignature, args }` body and returns `claimable`, `failedChecks`,
|
|
18749
|
+
* and the decoded `expiry`, `feeToken`, and `feeTotalAmount`.
|
|
18750
|
+
*
|
|
18751
|
+
* @internal
|
|
17939
18752
|
*/ const QUOTE_VALIDATE_USDC_PATH = '/v2/quote/validate/usdc';
|
|
17940
18753
|
/**
|
|
17941
18754
|
* Default polling configuration for Quote API calls.
|
|
@@ -17952,13 +18765,19 @@ function assertCCTPV2Config(config) {
|
|
|
17952
18765
|
* `Content-Type: application/json` and adds `User-Agent` in Node. Browser
|
|
17953
18766
|
* requests omit a user-agent header to avoid a CORS preflight, so duplicating
|
|
17954
18767
|
* either header here would be dead configuration.
|
|
18768
|
+
*
|
|
18769
|
+
* @internal
|
|
17955
18770
|
*/ const FEE_QUOTE_DEFAULT_CONFIG = {
|
|
17956
18771
|
timeout: 15_000,
|
|
17957
18772
|
maxRetries: 1,
|
|
17958
18773
|
retryDelay: 200
|
|
17959
18774
|
};
|
|
17960
18775
|
|
|
17961
|
-
/**
|
|
18776
|
+
/**
|
|
18777
|
+
* Decimal string in token minor units, constrained to be strictly positive.
|
|
18778
|
+
*
|
|
18779
|
+
* @internal
|
|
18780
|
+
*/ const positiveAmountSchema = zod.z.string().regex(/^\d+$/, 'must be a non-negative integer string')// Re-check the digit shape here: zod still runs this refinement when the
|
|
17962
18781
|
// regex check above fails ("dirty"), so guard BigInt() against throwing on a
|
|
17963
18782
|
// non-numeric value before comparing.
|
|
17964
18783
|
.refine((value)=>/^\d+$/.test(value) && BigInt(value) > 0n, 'must be greater than zero');
|
|
@@ -17993,11 +18812,19 @@ const forwardRequestSchema = zod.z.object({
|
|
|
17993
18812
|
const preFinalityRequestSchema = zod.z.object({
|
|
17994
18813
|
type: zod.z.literal('PRE_FINALITY')
|
|
17995
18814
|
}).strict();
|
|
17996
|
-
/**
|
|
18815
|
+
/**
|
|
18816
|
+
* A single quote request item (`FORWARD` or `PRE_FINALITY`).
|
|
18817
|
+
*
|
|
18818
|
+
* @internal
|
|
18819
|
+
*/ const feeQuoteRequestSchema = zod.z.discriminatedUnion('type', [
|
|
17997
18820
|
forwardRequestSchema,
|
|
17998
18821
|
preFinalityRequestSchema
|
|
17999
18822
|
]);
|
|
18000
|
-
/**
|
|
18823
|
+
/**
|
|
18824
|
+
* A non-empty list of quote request items with unique types.
|
|
18825
|
+
*
|
|
18826
|
+
* @internal
|
|
18827
|
+
*/ const feeQuoteRequestsSchema = zod.z.array(feeQuoteRequestSchema).min(1, 'at least one request item is required').refine((items)=>new Set(items.map((item)=>item.type)).size === items.length, 'request item types must be unique');
|
|
18001
18828
|
/**
|
|
18002
18829
|
* A structured `Partial<ApiPollingConfig>` polling override.
|
|
18003
18830
|
*
|
|
@@ -18025,6 +18852,8 @@ const preFinalityRequestSchema = zod.z.object({
|
|
|
18025
18852
|
* it `undefined`, which is falsy and silently selects the production base URL.
|
|
18026
18853
|
* (`buildFeeQuoteUrl` independently re-validates the domains for standalone
|
|
18027
18854
|
* callers.)
|
|
18855
|
+
*
|
|
18856
|
+
* @internal
|
|
18028
18857
|
*/ const fetchFeeQuoteInputSchema = zod.z.object({
|
|
18029
18858
|
sourceDomain: zod.z.number().int().nonnegative(),
|
|
18030
18859
|
destinationDomain: zod.z.number().int().nonnegative(),
|
|
@@ -18060,7 +18889,11 @@ const metadataSchema = zod.z.object({
|
|
|
18060
18889
|
blockEstimatedAt: zod.z.number().int().nonnegative().optional()
|
|
18061
18890
|
}).passthrough()
|
|
18062
18891
|
]);
|
|
18063
|
-
/**
|
|
18892
|
+
/**
|
|
18893
|
+
* Schema for a signed fee quote returned by the Quote API.
|
|
18894
|
+
*
|
|
18895
|
+
* @internal
|
|
18896
|
+
*/ const signedFeeQuoteSchema = zod.z.object({
|
|
18064
18897
|
// The runtime YAML spec maps signedQuote to a looser `hex` (which allows
|
|
18065
18898
|
// an empty `0x`); we keep the stricter non-empty form. Do not relax
|
|
18066
18899
|
// without a reason.
|
|
@@ -18089,10 +18922,16 @@ const metadataSchema = zod.z.object({
|
|
|
18089
18922
|
* console.log(payload.feeTotalAmount)
|
|
18090
18923
|
* }
|
|
18091
18924
|
* ```
|
|
18925
|
+
*
|
|
18926
|
+
* @internal
|
|
18092
18927
|
*/ function isSignedFeeQuote(value) {
|
|
18093
18928
|
return signedFeeQuoteSchema.safeParse(value).success;
|
|
18094
18929
|
}
|
|
18095
|
-
/**
|
|
18930
|
+
/**
|
|
18931
|
+
* Validates input to {@link validateQuote}.
|
|
18932
|
+
*
|
|
18933
|
+
* @internal
|
|
18934
|
+
*/ const validateQuoteInputSchema = zod.z.object({
|
|
18096
18935
|
sourceDomain: zod.z.number().int().nonnegative(),
|
|
18097
18936
|
abiSignature: zod.z.string().min(1),
|
|
18098
18937
|
args: zod.z.array(zod.z.union([
|
|
@@ -18127,11 +18966,13 @@ const validateQuoteItemSchema = zod.z.object({
|
|
|
18127
18966
|
computedArgsHash: bytes32Schema.optional()
|
|
18128
18967
|
}).passthrough();
|
|
18129
18968
|
/**
|
|
18130
|
-
* Schema for a
|
|
18969
|
+
* Schema for a validate-quote result returned by the Iris `/validate/usdc/:sourceDomain` endpoint.
|
|
18131
18970
|
*
|
|
18132
18971
|
* The endpoint takes the source domain as a URL path parameter and does not
|
|
18133
18972
|
* return it in the response body, so `sourceDomain` is intentionally not part
|
|
18134
18973
|
* of this schema.
|
|
18974
|
+
*
|
|
18975
|
+
* @internal
|
|
18135
18976
|
*/ const validateQuoteResultSchema = zod.z.object({
|
|
18136
18977
|
signedQuote: nonEmptyHexSchema,
|
|
18137
18978
|
expiry: quoteExpiryStatusSchema,
|
|
@@ -18145,20 +18986,22 @@ const validateQuoteItemSchema = zod.z.object({
|
|
|
18145
18986
|
items: zod.z.array(validateQuoteItemSchema)
|
|
18146
18987
|
}).passthrough();
|
|
18147
18988
|
/**
|
|
18148
|
-
* Validate
|
|
18989
|
+
* Validate that an unknown value is a validate-quote result.
|
|
18149
18990
|
*
|
|
18150
|
-
* @param value - The unknown
|
|
18151
|
-
* @returns `true` when the value
|
|
18991
|
+
* @param value - The unknown value to validate.
|
|
18992
|
+
* @returns `true` when the value matches the validate-quote response shape.
|
|
18152
18993
|
*
|
|
18153
18994
|
* @example
|
|
18154
18995
|
* ```typescript
|
|
18155
18996
|
* import { isValidateQuoteResult } from '@circle-fin/provider-fee-v1'
|
|
18156
18997
|
*
|
|
18157
|
-
* declare const
|
|
18158
|
-
* if (isValidateQuoteResult(
|
|
18159
|
-
* console.log(
|
|
18998
|
+
* declare const payload: unknown
|
|
18999
|
+
* if (isValidateQuoteResult(payload)) {
|
|
19000
|
+
* console.log(payload.claimable, payload.failedChecks)
|
|
18160
19001
|
* }
|
|
18161
19002
|
* ```
|
|
19003
|
+
*
|
|
19004
|
+
* @internal
|
|
18162
19005
|
*/ function isValidateQuoteResult(value) {
|
|
18163
19006
|
return validateQuoteResultSchema.safeParse(value).success;
|
|
18164
19007
|
}
|
|
@@ -18207,6 +19050,8 @@ const validateQuoteItemSchema = zod.z.object({
|
|
|
18207
19050
|
* })
|
|
18208
19051
|
* // => 'https://iris-api.circle.com/v2/quote/burn/usdc/3/26'
|
|
18209
19052
|
* ```
|
|
19053
|
+
*
|
|
19054
|
+
* @internal
|
|
18210
19055
|
*/ function buildFeeQuoteUrl(params) {
|
|
18211
19056
|
const { sourceDomain, destinationDomain, isTestnet, baseUrl } = params;
|
|
18212
19057
|
assertDomain(sourceDomain, 'sourceDomain');
|
|
@@ -18333,6 +19178,8 @@ const OPERATION$1 = 'getFeeQuote';
|
|
|
18333
19178
|
* })
|
|
18334
19179
|
* console.log(quote.feeTotalAmount, quote.expiry)
|
|
18335
19180
|
* ```
|
|
19181
|
+
*
|
|
19182
|
+
* @internal
|
|
18336
19183
|
*/ async function fetchFeeQuote(params) {
|
|
18337
19184
|
const { sourceDomain, destinationDomain, amount, requests, feeToken, isTestnet, baseUrl, config } = params;
|
|
18338
19185
|
const parsed = fetchFeeQuoteInputSchema.safeParse({
|
|
@@ -18407,7 +19254,13 @@ const OPERATION$1 = 'getFeeQuote';
|
|
|
18407
19254
|
const SERVICE = 'Quote API';
|
|
18408
19255
|
const OPERATION = 'validateQuote';
|
|
18409
19256
|
/**
|
|
18410
|
-
* Validate a signed quote against a
|
|
19257
|
+
* Validate a signed fee quote against a full on-chain call via Circle's Iris
|
|
19258
|
+
* `/v2/quote/validate/usdc/:sourceDomain` endpoint.
|
|
19259
|
+
*
|
|
19260
|
+
* POSTs the ABI function signature and the encoded call arguments to Iris,
|
|
19261
|
+
* which verifies the signature, checks expiry, confirms the argsHash committed
|
|
19262
|
+
* in the quote matches the submitted args, and returns `claimable` plus the
|
|
19263
|
+
* decoded `expiry`, `feeToken`, and `feeTotalAmount`.
|
|
18411
19264
|
*
|
|
18412
19265
|
* @param params - The source domain, ABI signature, call arguments, and environment.
|
|
18413
19266
|
* @returns The claimability, binding checks, and authoritative expiry status.
|
|
@@ -18434,7 +19287,12 @@ const OPERATION = 'validateQuote';
|
|
|
18434
19287
|
* isTestnet: false,
|
|
18435
19288
|
* })
|
|
18436
19289
|
* console.log(result.claimable, result.expiry.secondsRemaining)
|
|
19290
|
+
* if (!result.claimable) {
|
|
19291
|
+
* console.error('Quote rejected:', result.failedChecks)
|
|
19292
|
+
* }
|
|
18437
19293
|
* ```
|
|
19294
|
+
*
|
|
19295
|
+
* @internal
|
|
18438
19296
|
*/ async function validateQuote(params) {
|
|
18439
19297
|
const parsed = validateQuoteInputSchema.safeParse(params);
|
|
18440
19298
|
if (!parsed.success) {
|
|
@@ -18497,9 +19355,14 @@ function isQuoteNearEstimatedExpiry(quote) {
|
|
|
18497
19355
|
}
|
|
18498
19356
|
function assertSourceFeeRoute(params) {
|
|
18499
19357
|
const { source, destination, config } = params;
|
|
19358
|
+
// Keep these checks explicit so a successful assertion guarantees the CCTP
|
|
19359
|
+
// v2 narrowing; hasSourceFeeSupport returns a plain boolean.
|
|
18500
19360
|
if (source.chain.type !== 'evm' || destination.chain.type !== 'evm' || !isCCTPV2Supported(source.chain) || !isCCTPV2Supported(destination.chain)) {
|
|
18501
19361
|
throw createUnsupportedRouteError(source.chain.name, destination.chain.name);
|
|
18502
19362
|
}
|
|
19363
|
+
if (!hasSourceFeeSupport(source.chain)) {
|
|
19364
|
+
throw createValidationFailedError$1('config.feePayment', 'source', `Source-paid ("receive-exact") fees are not supported from ${source.chain.name}. ` + 'Use the default destination-paid fees for this source chain');
|
|
19365
|
+
}
|
|
18503
19366
|
const useForwarder = destination.useForwarder;
|
|
18504
19367
|
if (useForwarder !== true) {
|
|
18505
19368
|
throw createValidationFailedError$1('to.useForwarder', useForwarder, "feePayment: 'source' requires useForwarder: true");
|
|
@@ -19587,7 +20450,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
19587
20450
|
};
|
|
19588
20451
|
|
|
19589
20452
|
var name$1 = "@circle-fin/swap-kit";
|
|
19590
|
-
var version$1 = "1.6.
|
|
20453
|
+
var version$1 = "1.6.1";
|
|
19591
20454
|
var pkg$1 = {
|
|
19592
20455
|
name: name$1,
|
|
19593
20456
|
version: version$1};
|
|
@@ -21609,7 +22472,7 @@ new Set(Object.values(Blockchain));
|
|
|
21609
22472
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
21610
22473
|
|
|
21611
22474
|
var name = "@circle-fin/earn-kit";
|
|
21612
|
-
var version = "1.6.
|
|
22475
|
+
var version = "1.6.1";
|
|
21613
22476
|
var pkg = {
|
|
21614
22477
|
name: name,
|
|
21615
22478
|
version: version};
|