@circle-fin/app-kit 1.8.1 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +3 -3
- package/bridge.cjs +1102 -260
- package/bridge.d.cts +161 -10
- package/bridge.d.mts +161 -10
- package/bridge.d.ts +161 -10
- package/bridge.mjs +1102 -260
- package/chains.cjs +102 -2
- package/chains.d.cts +3 -0
- package/chains.d.mts +3 -0
- package/chains.d.ts +3 -0
- package/chains.mjs +102 -2
- package/context.cjs +1 -0
- package/context.d.cts +166 -12
- package/context.d.mts +166 -12
- package/context.d.ts +166 -12
- package/context.mjs +1 -0
- package/earn.cjs +1074 -454
- package/earn.d.cts +546 -99
- package/earn.d.mts +546 -99
- package/earn.d.ts +546 -99
- package/earn.mjs +1074 -455
- package/estimateBridge.cjs +1102 -260
- package/estimateBridge.d.cts +161 -10
- package/estimateBridge.d.mts +161 -10
- package/estimateBridge.d.ts +161 -10
- package/estimateBridge.mjs +1102 -260
- package/estimateSwap.cjs +915 -96
- package/estimateSwap.d.cts +161 -10
- package/estimateSwap.d.mts +161 -10
- package/estimateSwap.d.ts +161 -10
- package/estimateSwap.mjs +915 -96
- package/index.cjs +3029 -862
- package/index.d.cts +1277 -143
- package/index.d.mts +1277 -143
- package/index.d.ts +1277 -143
- package/index.mjs +3029 -862
- package/package.json +12 -6
- package/swap.cjs +915 -96
- package/swap.d.cts +161 -10
- package/swap.d.mts +161 -10
- package/swap.d.ts +161 -10
- package/swap.mjs +915 -96
- package/unifiedBalance.cjs +822 -115
- package/unifiedBalance.d.cts +224 -4
- package/unifiedBalance.d.mts +224 -4
- package/unifiedBalance.d.ts +224 -4
- package/unifiedBalance.mjs +822 -115
package/estimateSwap.cjs
CHANGED
|
@@ -20,13 +20,14 @@
|
|
|
20
20
|
|
|
21
21
|
var zod = require('zod');
|
|
22
22
|
require('pino');
|
|
23
|
+
var bytes = require('@ethersproject/bytes');
|
|
24
|
+
require('@ethersproject/abi');
|
|
25
|
+
var address = require('@ethersproject/address');
|
|
23
26
|
var web3_js = require('@solana/web3.js');
|
|
24
27
|
require('bn.js');
|
|
25
28
|
require('@coral-xyz/anchor');
|
|
26
29
|
var bs58 = require('bs58');
|
|
27
30
|
require('@noble/curves/ed25519');
|
|
28
|
-
var bytes = require('@ethersproject/bytes');
|
|
29
|
-
var address = require('@ethersproject/address');
|
|
30
31
|
var units = require('@ethersproject/units');
|
|
31
32
|
var keccak256 = require('@ethersproject/keccak256');
|
|
32
33
|
|
|
@@ -2901,6 +2902,8 @@ class KitError extends Error {
|
|
|
2901
2902
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
2902
2903
|
Blockchain["Codex"] = "Codex";
|
|
2903
2904
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
2905
|
+
Blockchain["Cronos"] = "Cronos";
|
|
2906
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2904
2907
|
Blockchain["Edge"] = "Edge";
|
|
2905
2908
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
2906
2909
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -2983,6 +2986,7 @@ var BridgeChain;
|
|
|
2983
2986
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
2984
2987
|
BridgeChain["Base"] = "Base";
|
|
2985
2988
|
BridgeChain["Codex"] = "Codex";
|
|
2989
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
2986
2990
|
BridgeChain["Edge"] = "Edge";
|
|
2987
2991
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
2988
2992
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -3007,6 +3011,7 @@ var BridgeChain;
|
|
|
3007
3011
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
3008
3012
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
3009
3013
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
3014
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
3010
3015
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
3011
3016
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
3012
3017
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -3529,7 +3534,10 @@ var EarnChain;
|
|
|
3529
3534
|
contracts: {
|
|
3530
3535
|
v1: {
|
|
3531
3536
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3532
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
3537
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3538
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
3539
|
+
// deposit into the GatewayWallet above.
|
|
3540
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3533
3541
|
}
|
|
3534
3542
|
},
|
|
3535
3543
|
forwarderSupported: {
|
|
@@ -4063,6 +4071,96 @@ var EarnChain;
|
|
|
4063
4071
|
}
|
|
4064
4072
|
});
|
|
4065
4073
|
|
|
4074
|
+
/**
|
|
4075
|
+
* Cronos Mainnet chain definition
|
|
4076
|
+
* @remarks
|
|
4077
|
+
* This represents the official production network for the Cronos blockchain.
|
|
4078
|
+
* Cronos is an EVM-compatible blockchain.
|
|
4079
|
+
*/ const Cronos = defineChain({
|
|
4080
|
+
type: 'evm',
|
|
4081
|
+
chain: Blockchain.Cronos,
|
|
4082
|
+
name: 'Cronos',
|
|
4083
|
+
title: 'Cronos Mainnet',
|
|
4084
|
+
nativeCurrency: {
|
|
4085
|
+
name: 'Cronos',
|
|
4086
|
+
symbol: 'CRO',
|
|
4087
|
+
decimals: 18
|
|
4088
|
+
},
|
|
4089
|
+
chainId: 25,
|
|
4090
|
+
isTestnet: false,
|
|
4091
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
4092
|
+
rpcEndpoints: [
|
|
4093
|
+
'https://evm.cronos.org'
|
|
4094
|
+
],
|
|
4095
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
4096
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
4097
|
+
usdtAddress: null,
|
|
4098
|
+
cctp: {
|
|
4099
|
+
domain: 32,
|
|
4100
|
+
contracts: {
|
|
4101
|
+
v2: {
|
|
4102
|
+
type: 'split',
|
|
4103
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
4104
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
4105
|
+
confirmations: 1,
|
|
4106
|
+
fastConfirmations: 1
|
|
4107
|
+
}
|
|
4108
|
+
},
|
|
4109
|
+
forwarderSupported: {
|
|
4110
|
+
source: false,
|
|
4111
|
+
destination: false
|
|
4112
|
+
}
|
|
4113
|
+
},
|
|
4114
|
+
kitContracts: {
|
|
4115
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
4116
|
+
}
|
|
4117
|
+
});
|
|
4118
|
+
|
|
4119
|
+
/**
|
|
4120
|
+
* Cronos Testnet chain definition
|
|
4121
|
+
* @remarks
|
|
4122
|
+
* This represents the official test network for the Cronos blockchain.
|
|
4123
|
+
* Cronos is an EVM-compatible blockchain.
|
|
4124
|
+
*/ const CronosTestnet = defineChain({
|
|
4125
|
+
type: 'evm',
|
|
4126
|
+
chain: Blockchain.Cronos_Testnet,
|
|
4127
|
+
name: 'Cronos Testnet',
|
|
4128
|
+
title: 'Cronos Testnet',
|
|
4129
|
+
nativeCurrency: {
|
|
4130
|
+
name: 'CRO',
|
|
4131
|
+
symbol: 'tCRO',
|
|
4132
|
+
decimals: 18
|
|
4133
|
+
},
|
|
4134
|
+
chainId: 338,
|
|
4135
|
+
isTestnet: true,
|
|
4136
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
4137
|
+
rpcEndpoints: [
|
|
4138
|
+
'https://evm-t3.cronos.org'
|
|
4139
|
+
],
|
|
4140
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
4141
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
4142
|
+
usdtAddress: null,
|
|
4143
|
+
cctp: {
|
|
4144
|
+
domain: 32,
|
|
4145
|
+
contracts: {
|
|
4146
|
+
v2: {
|
|
4147
|
+
type: 'split',
|
|
4148
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
4149
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
4150
|
+
confirmations: 1,
|
|
4151
|
+
fastConfirmations: 1
|
|
4152
|
+
}
|
|
4153
|
+
},
|
|
4154
|
+
forwarderSupported: {
|
|
4155
|
+
source: false,
|
|
4156
|
+
destination: false
|
|
4157
|
+
}
|
|
4158
|
+
},
|
|
4159
|
+
kitContracts: {
|
|
4160
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
4161
|
+
}
|
|
4162
|
+
});
|
|
4163
|
+
|
|
4066
4164
|
/**
|
|
4067
4165
|
* Edge Mainnet chain definition
|
|
4068
4166
|
* @remarks
|
|
@@ -6414,6 +6512,8 @@ var Chains = {
|
|
|
6414
6512
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
6415
6513
|
Codex: Codex,
|
|
6416
6514
|
CodexTestnet: CodexTestnet,
|
|
6515
|
+
Cronos: Cronos,
|
|
6516
|
+
CronosTestnet: CronosTestnet,
|
|
6417
6517
|
Edge: Edge,
|
|
6418
6518
|
EdgeTestnet: EdgeTestnet,
|
|
6419
6519
|
Ethereum: Ethereum,
|
|
@@ -6505,7 +6605,10 @@ var Chains = {
|
|
|
6505
6605
|
minter: zod.z.string({
|
|
6506
6606
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6507
6607
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6508
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
6608
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
6609
|
+
depositForHandler: zod.z.string({
|
|
6610
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
6611
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
6509
6612
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6510
6613
|
;
|
|
6511
6614
|
/**
|
|
@@ -8463,6 +8566,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8463
8566
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8464
8567
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8465
8568
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8569
|
+
[Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
8466
8570
|
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
8467
8571
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8468
8572
|
[Blockchain.Hedera]: '0.0.456858',
|
|
@@ -8496,6 +8600,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8496
8600
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8497
8601
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8498
8602
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8603
|
+
[Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
8499
8604
|
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
8500
8605
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8501
8606
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -8568,6 +8673,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8568
8673
|
// =========================================================================
|
|
8569
8674
|
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
8570
8675
|
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
8676
|
+
[Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
8571
8677
|
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
8572
8678
|
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
8573
8679
|
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
@@ -8576,6 +8682,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8576
8682
|
// =========================================================================
|
|
8577
8683
|
[Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
8578
8684
|
[Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
8685
|
+
[Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
8579
8686
|
[Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
8580
8687
|
}
|
|
8581
8688
|
};
|
|
@@ -9386,6 +9493,13 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9386
9493
|
return explorerUrl;
|
|
9387
9494
|
}
|
|
9388
9495
|
|
|
9496
|
+
/**
|
|
9497
|
+
* CCTP forwarding magic bytes prefix.
|
|
9498
|
+
*
|
|
9499
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
9500
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
9501
|
+
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
9502
|
+
|
|
9389
9503
|
/**
|
|
9390
9504
|
* Project an arbitrary payload onto the exact set of fields the telemetry
|
|
9391
9505
|
* endpoint accepts.
|
|
@@ -9762,7 +9876,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
9762
9876
|
}
|
|
9763
9877
|
|
|
9764
9878
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9765
|
-
var version$2 = "1.
|
|
9879
|
+
var version$2 = "1.12.1";
|
|
9766
9880
|
var pkg$2 = {
|
|
9767
9881
|
name: name$2,
|
|
9768
9882
|
version: version$2};
|
|
@@ -10620,6 +10734,11 @@ var TransferSpeed;
|
|
|
10620
10734
|
clock: zod.z.any().optional()
|
|
10621
10735
|
}).passthrough();
|
|
10622
10736
|
|
|
10737
|
+
/**
|
|
10738
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
10739
|
+
* hookData must start with.
|
|
10740
|
+
*/ Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
10741
|
+
|
|
10623
10742
|
/**
|
|
10624
10743
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
10625
10744
|
*
|
|
@@ -10652,7 +10771,7 @@ var TransferSpeed;
|
|
|
10652
10771
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
10653
10772
|
|
|
10654
10773
|
var name$1 = "@circle-fin/swap-kit";
|
|
10655
|
-
var version$1 = "1.
|
|
10774
|
+
var version$1 = "1.4.0";
|
|
10656
10775
|
var pkg$1 = {
|
|
10657
10776
|
name: name$1,
|
|
10658
10777
|
version: version$1};
|
|
@@ -10717,7 +10836,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
10717
10836
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
10718
10837
|
provider: zod.z.string({
|
|
10719
10838
|
invalid_type_error: 'provider must be a string'
|
|
10720
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
10839
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
10840
|
+
batchTransactions: zod.z.boolean({
|
|
10841
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
10842
|
+
}).optional()
|
|
10721
10843
|
});
|
|
10722
10844
|
/**
|
|
10723
10845
|
* Zod schema for adapter context.
|
|
@@ -11248,7 +11370,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11248
11370
|
/**
|
|
11249
11371
|
* Circle Stablecoin Service API Key.
|
|
11250
11372
|
* Must be a valid API key format.
|
|
11251
|
-
*/ apiKey: apiKeySchema
|
|
11373
|
+
*/ apiKey: apiKeySchema.optional()
|
|
11252
11374
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
11253
11375
|
/**
|
|
11254
11376
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -11306,7 +11428,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11306
11428
|
/**
|
|
11307
11429
|
* Circle Stablecoin Service API Key.
|
|
11308
11430
|
* Must be a valid API key format.
|
|
11309
|
-
*/ apiKey: apiKeySchema
|
|
11431
|
+
*/ apiKey: apiKeySchema.optional()
|
|
11310
11432
|
});
|
|
11311
11433
|
/**
|
|
11312
11434
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -11342,7 +11464,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11342
11464
|
toChain: zod.z.string({
|
|
11343
11465
|
invalid_type_error: 'toChain must be a string'
|
|
11344
11466
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
11345
|
-
apiKey: apiKeySchema
|
|
11467
|
+
apiKey: apiKeySchema.optional()
|
|
11346
11468
|
});
|
|
11347
11469
|
/**
|
|
11348
11470
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -11351,13 +11473,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11351
11473
|
required_error: 'fee token is required',
|
|
11352
11474
|
invalid_type_error: 'fee token must be a string'
|
|
11353
11475
|
}).min(1, 'fee token must be a non-empty string'),
|
|
11354
|
-
amount: feeAmountSchema
|
|
11476
|
+
amount: feeAmountSchema,
|
|
11477
|
+
decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
11478
|
+
symbol: zod.z.string({
|
|
11479
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
11480
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
11355
11481
|
});
|
|
11356
11482
|
/**
|
|
11357
11483
|
* Developer fee item schema with basis field.
|
|
11358
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
11359
|
-
token: zod.z.string().min(1, 'fee token must be a non-empty string'),
|
|
11360
|
-
amount: feeAmountSchema,
|
|
11484
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
11361
11485
|
basis: zod.z.enum([
|
|
11362
11486
|
'inputAmount',
|
|
11363
11487
|
'estimatedAmount'
|
|
@@ -11449,7 +11573,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11449
11573
|
addresses: zod.z.array(zod.z.string({
|
|
11450
11574
|
invalid_type_error: 'addresses entries must be strings'
|
|
11451
11575
|
}).min(1, 'addresses entries must be non-empty strings')).min(1, 'addresses must contain at least one entry when provided').max(MAX_RATE_ADDRESSES_PER_REQUEST, `addresses supports at most ${String(MAX_RATE_ADDRESSES_PER_REQUEST)} values per request`).optional(),
|
|
11452
|
-
apiKey: apiKeySchema
|
|
11576
|
+
apiKey: apiKeySchema.optional()
|
|
11453
11577
|
});
|
|
11454
11578
|
/**
|
|
11455
11579
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -11627,7 +11751,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11627
11751
|
...DEFAULT_CONFIG,
|
|
11628
11752
|
headers: {
|
|
11629
11753
|
...DEFAULT_CONFIG.headers,
|
|
11630
|
-
|
|
11754
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11755
|
+
...apiKey !== undefined && {
|
|
11756
|
+
Authorization: `Bearer ${apiKey}`
|
|
11757
|
+
}
|
|
11631
11758
|
}
|
|
11632
11759
|
};
|
|
11633
11760
|
try {
|
|
@@ -11781,7 +11908,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11781
11908
|
...DEFAULT_CONFIG,
|
|
11782
11909
|
headers: {
|
|
11783
11910
|
...DEFAULT_CONFIG.headers,
|
|
11784
|
-
|
|
11911
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11912
|
+
...validatedParams.apiKey !== undefined && {
|
|
11913
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
11914
|
+
}
|
|
11785
11915
|
}
|
|
11786
11916
|
};
|
|
11787
11917
|
return pollApiGet(url, isGetQuoteResponse, effectiveConfig);
|
|
@@ -11836,7 +11966,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11836
11966
|
const validatedParams = {
|
|
11837
11967
|
txHash: result.data.txHash,
|
|
11838
11968
|
chain: result.data.chain,
|
|
11839
|
-
|
|
11969
|
+
...result.data.apiKey !== undefined && {
|
|
11970
|
+
apiKey: result.data.apiKey
|
|
11971
|
+
},
|
|
11840
11972
|
...result.data.toChain !== undefined && {
|
|
11841
11973
|
toChain: result.data.toChain
|
|
11842
11974
|
}
|
|
@@ -11846,7 +11978,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11846
11978
|
...DEFAULT_CONFIG,
|
|
11847
11979
|
headers: {
|
|
11848
11980
|
...DEFAULT_CONFIG.headers,
|
|
11849
|
-
|
|
11981
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11982
|
+
...validatedParams.apiKey !== undefined && {
|
|
11983
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
11984
|
+
}
|
|
11850
11985
|
}
|
|
11851
11986
|
};
|
|
11852
11987
|
return pollApiGet(url, isGetSwapStatusResponse, effectiveConfig);
|
|
@@ -11935,7 +12070,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11935
12070
|
}
|
|
11936
12071
|
const validatedParams = {
|
|
11937
12072
|
chain: result.data.chain,
|
|
11938
|
-
|
|
12073
|
+
...result.data.apiKey !== undefined && {
|
|
12074
|
+
apiKey: result.data.apiKey
|
|
12075
|
+
},
|
|
11939
12076
|
...result.data.addresses !== undefined && {
|
|
11940
12077
|
addresses: result.data.addresses
|
|
11941
12078
|
}
|
|
@@ -11945,7 +12082,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11945
12082
|
...DEFAULT_CONFIG,
|
|
11946
12083
|
headers: {
|
|
11947
12084
|
...DEFAULT_CONFIG.headers,
|
|
11948
|
-
|
|
12085
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
12086
|
+
...validatedParams.apiKey !== undefined && {
|
|
12087
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
12088
|
+
}
|
|
11949
12089
|
}
|
|
11950
12090
|
};
|
|
11951
12091
|
return pollApiGet(url, isGetTokenRatesResponse, effectiveConfig);
|
|
@@ -12755,6 +12895,47 @@ const S_HEX_LENGTH = 32 * HEX_CHARS_PER_BYTE$1 // 32 bytes for 's'
|
|
|
12755
12895
|
*/ function hasSignTypedData(adapter) {
|
|
12756
12896
|
return typeof adapter === 'object' && adapter !== null && 'signTypedData' in adapter && typeof adapter.signTypedData === 'function';
|
|
12757
12897
|
}
|
|
12898
|
+
/**
|
|
12899
|
+
* Type guard to check if an adapter can actually produce an EIP-712
|
|
12900
|
+
* typed-data signature.
|
|
12901
|
+
*
|
|
12902
|
+
* @remarks
|
|
12903
|
+
* Strengthens {@link hasSignTypedData}: having a `signTypedData` method
|
|
12904
|
+
* does not guarantee it can succeed. Adapters whose signer is delegated
|
|
12905
|
+
* (e.g. through a signing strategy backed by a smart contract account)
|
|
12906
|
+
* expose the method but reject typed-data payloads at runtime. Such
|
|
12907
|
+
* adapters report their real capability through an optional
|
|
12908
|
+
* `supportsSignTypedData()` method, which this guard consults when
|
|
12909
|
+
* present. Adapters without the capability method are assumed able to
|
|
12910
|
+
* sign, preserving the previous duck-typing behavior.
|
|
12911
|
+
*
|
|
12912
|
+
* @param adapter - The adapter to check
|
|
12913
|
+
* @returns True if calling `signTypedData` can be expected to succeed
|
|
12914
|
+
*
|
|
12915
|
+
* @example
|
|
12916
|
+
* ```typescript
|
|
12917
|
+
* import { canSignTypedData } from '@core/adapter-evm'
|
|
12918
|
+
*
|
|
12919
|
+
* if (canSignTypedData(adapter)) {
|
|
12920
|
+
* const signature = await adapter.signTypedData(typedData, context)
|
|
12921
|
+
* } else {
|
|
12922
|
+
* // take an on-chain approval path instead of a permit signature
|
|
12923
|
+
* }
|
|
12924
|
+
* ```
|
|
12925
|
+
*/ function canSignTypedData(adapter) {
|
|
12926
|
+
if (!hasSignTypedData(adapter)) {
|
|
12927
|
+
return false;
|
|
12928
|
+
}
|
|
12929
|
+
if (typeof adapter.supportsSignTypedData === 'function') {
|
|
12930
|
+
// The value is `boolean` per the interface, but a plain-JS adapter may
|
|
12931
|
+
// return anything; treat it as untrusted and coerce to a strict
|
|
12932
|
+
// boolean. Comparing an `unknown` (not a `boolean`) also keeps the
|
|
12933
|
+
// lint autofix from stripping this as a redundant `=== true`.
|
|
12934
|
+
const supported = adapter.supportsSignTypedData();
|
|
12935
|
+
return supported === true;
|
|
12936
|
+
}
|
|
12937
|
+
return true;
|
|
12938
|
+
}
|
|
12758
12939
|
|
|
12759
12940
|
/**
|
|
12760
12941
|
* Build EIP-2612 typed data for permit signing.
|
|
@@ -13177,10 +13358,13 @@ enc.encode('used_transfer_spec_hash');
|
|
|
13177
13358
|
* at usage time rather than construction time.
|
|
13178
13359
|
*
|
|
13179
13360
|
* Validates:
|
|
13180
|
-
* - Kit key
|
|
13361
|
+
* - Kit key matches the required format (KIT_KEY:id:secret) when provided.
|
|
13362
|
+
* An absent or empty kit key is permitted (permissionless mode) — the swap
|
|
13363
|
+
* service now treats the key as optional.
|
|
13181
13364
|
*
|
|
13182
|
-
* @param kitKey - The inline kit key from the swap operation config
|
|
13183
|
-
* @throws KitError with VALIDATION_FAILED if kit key is
|
|
13365
|
+
* @param kitKey - The inline kit key from the swap operation config (optional)
|
|
13366
|
+
* @throws KitError with VALIDATION_FAILED if a kit key is provided but does not
|
|
13367
|
+
* match the KIT_KEY:<keyId>:<keySecret> format
|
|
13184
13368
|
*
|
|
13185
13369
|
* @example
|
|
13186
13370
|
* ```typescript
|
|
@@ -13192,9 +13376,11 @@ enc.encode('used_transfer_spec_hash');
|
|
|
13192
13376
|
* assertKitKey(kitKey)
|
|
13193
13377
|
* ```
|
|
13194
13378
|
*/ function assertKitKey(kitKey) {
|
|
13195
|
-
//
|
|
13379
|
+
// Permissionless mode: the swap service treats the kit key as optional, so an
|
|
13380
|
+
// absent (or empty) key is valid. Only validate the format when a key is
|
|
13381
|
+
// actually provided.
|
|
13196
13382
|
if (!kitKey) {
|
|
13197
|
-
|
|
13383
|
+
return;
|
|
13198
13384
|
}
|
|
13199
13385
|
const apiKeyResult = apiKeySchema.safeParse(kitKey);
|
|
13200
13386
|
if (!apiKeyResult.success) {
|
|
@@ -13491,8 +13677,8 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
13491
13677
|
validateResolvedAddress(resolvedTokenInAddress, chain);
|
|
13492
13678
|
validateResolvedAddress(resolvedTokenOutAddress, destinationChain);
|
|
13493
13679
|
validateResolvedAddress(to, destinationChain);
|
|
13494
|
-
const kitKey = config?.kitKey
|
|
13495
|
-
//
|
|
13680
|
+
const kitKey = config?.kitKey;
|
|
13681
|
+
// Validate the kit key format when one is provided (permissionless otherwise).
|
|
13496
13682
|
assertKitKey(kitKey);
|
|
13497
13683
|
// Validate custom fee configuration if present
|
|
13498
13684
|
const customFee = config?.customFee;
|
|
@@ -13537,7 +13723,10 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
13537
13723
|
}
|
|
13538
13724
|
}
|
|
13539
13725
|
},
|
|
13540
|
-
apiKey
|
|
13726
|
+
// Map kitKey → apiKey for the service client; omitted in permissionless mode.
|
|
13727
|
+
...kitKey ? {
|
|
13728
|
+
apiKey: kitKey
|
|
13729
|
+
} : {}
|
|
13541
13730
|
};
|
|
13542
13731
|
}
|
|
13543
13732
|
|
|
@@ -14191,6 +14380,37 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
14191
14380
|
}
|
|
14192
14381
|
}
|
|
14193
14382
|
|
|
14383
|
+
/**
|
|
14384
|
+
* Determine whether an adapter can produce an EIP-2612 permit signature.
|
|
14385
|
+
*
|
|
14386
|
+
* @remarks
|
|
14387
|
+
* A gasless permit needs two adapter capabilities: fetching the token's
|
|
14388
|
+
* EIP-2612 nonce and producing an EIP-712 typed-data signature. The
|
|
14389
|
+
* typed-data check uses {@link canSignTypedData} rather than a bare
|
|
14390
|
+
* `hasSignTypedData` guard so that an adapter routed through a signing
|
|
14391
|
+
* strategy that cannot produce typed-data signatures — one whose manifest
|
|
14392
|
+
* omits `evm-typed-data`, surfaced through an optional `supportsSignTypedData()`
|
|
14393
|
+
* — is correctly excluded. Such an adapter falls back to an on-chain approval
|
|
14394
|
+
* (batched into a single submission when it supports atomic execution) instead
|
|
14395
|
+
* of attempting a permit its strategy would reject.
|
|
14396
|
+
*
|
|
14397
|
+
* @param adapter - The source adapter to inspect.
|
|
14398
|
+
* @returns `true` when the adapter can both fetch a nonce and sign typed data.
|
|
14399
|
+
*
|
|
14400
|
+
* @example
|
|
14401
|
+
* ```typescript
|
|
14402
|
+
* import { adapterSupportsPermit } from './utils'
|
|
14403
|
+
*
|
|
14404
|
+
* if (adapterSupportsPermit(adapter)) {
|
|
14405
|
+
* // gasless permit path — fold the approval into the swap transaction
|
|
14406
|
+
* } else {
|
|
14407
|
+
* // on-chain approval path (batched when supportsAtomicBatch is true)
|
|
14408
|
+
* }
|
|
14409
|
+
* ```
|
|
14410
|
+
*/ function adapterSupportsPermit(adapter) {
|
|
14411
|
+
return hasEIP2612NonceFetching(adapter) && canSignTypedData(adapter);
|
|
14412
|
+
}
|
|
14413
|
+
|
|
14194
14414
|
/**
|
|
14195
14415
|
* Generate EIP-2612 permit signature for token approval.
|
|
14196
14416
|
*
|
|
@@ -14326,8 +14546,7 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
14326
14546
|
}
|
|
14327
14547
|
// Skip permit generation if the adapter lacks the required capabilities.
|
|
14328
14548
|
// handleEvmTokenApproval will have already sent an on-chain approval in this case.
|
|
14329
|
-
|
|
14330
|
-
if (!adapterSupportsPermit) {
|
|
14549
|
+
if (!adapterSupportsPermit(adapter)) {
|
|
14331
14550
|
return [
|
|
14332
14551
|
createFallbackTokenInput(tokenInAddress, inputAmount)
|
|
14333
14552
|
];
|
|
@@ -14886,6 +15105,65 @@ const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
|
14886
15105
|
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.`;
|
|
14887
15106
|
}
|
|
14888
15107
|
|
|
15108
|
+
/**
|
|
15109
|
+
* Determine which chain a fee token should be resolved and formatted against.
|
|
15110
|
+
*
|
|
15111
|
+
* @remarks
|
|
15112
|
+
* Fees returned by the service may be denominated in either the input token
|
|
15113
|
+
* (on the source chain) or the output token (on the destination chain). A
|
|
15114
|
+
* contract address only resolves on the chain it belongs to, so formatting a
|
|
15115
|
+
* destination-denominated fee against the source chain causes
|
|
15116
|
+
* {@link resolveTokenSymbol} to miss and the amount to be returned as raw base
|
|
15117
|
+
* units (e.g. a cross-chain swap charging a fee in the destination output
|
|
15118
|
+
* token — an EURC-on-Base address shows `'13202'` instead of `'0.013202'` when
|
|
15119
|
+
* resolved against the source chain). This is the fallback for fee items that
|
|
15120
|
+
* are not self-described with their own `decimals`/`chain`.
|
|
15121
|
+
*
|
|
15122
|
+
* Prefer the source chain (covers same-chain swaps and input-denominated
|
|
15123
|
+
* fees), then fall back to the destination chain when the token only resolves
|
|
15124
|
+
* there. When neither chain recognises the token, default to the source chain
|
|
15125
|
+
* so existing on-chain decimal lookups via the source adapter still apply.
|
|
15126
|
+
*
|
|
15127
|
+
* Symbol tokens (`'USDC'`, `'NATIVE'`) resolve on either chain, so the
|
|
15128
|
+
* source-first preference keeps them on the source chain. That is correct for
|
|
15129
|
+
* registry stablecoins, and for `'NATIVE'` only when both chains share native
|
|
15130
|
+
* decimals (EVM↔EVM, 18). It does NOT honor per-chain native decimals: a
|
|
15131
|
+
* `'NATIVE'`-denominated fee on a Solana↔EVM swap (9 vs 18) would be
|
|
15132
|
+
* mis-scaled. This is latent — providers emit the address form, and
|
|
15133
|
+
* self-describing fee items carry their own `decimals` and never reach this
|
|
15134
|
+
* helper — so the gap only opens for a future `'NATIVE'` fee that arrives
|
|
15135
|
+
* without `decimals` on a cross-native-decimal route.
|
|
15136
|
+
*
|
|
15137
|
+
* @param token - The fee token identifier — a symbol (`'USDC'`) or contract address.
|
|
15138
|
+
* @param sourceChain - The chain the swap originates from.
|
|
15139
|
+
* @param destinationChain - The chain the swap settles on (equals `sourceChain` for same-chain swaps).
|
|
15140
|
+
* @returns The chain definition the fee token should be resolved against.
|
|
15141
|
+
*
|
|
15142
|
+
* @example
|
|
15143
|
+
* ```typescript
|
|
15144
|
+
* import { resolveFeeChain } from './resolveFeeChain'
|
|
15145
|
+
* import { Ethereum, Base } from '@core/chains'
|
|
15146
|
+
*
|
|
15147
|
+
* // Cross-chain swap fee charged in the destination (output) token
|
|
15148
|
+
* resolveFeeChain('0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42', Ethereum, Base)
|
|
15149
|
+
* // => Base (EURC resolves on Base, not Ethereum)
|
|
15150
|
+
*
|
|
15151
|
+
* // Symbol or source-token fees stay on the source chain
|
|
15152
|
+
* resolveFeeChain('USDC', Ethereum, Base) // => Ethereum
|
|
15153
|
+
* ```
|
|
15154
|
+
*/ function resolveFeeChain(token, sourceChain, destinationChain) {
|
|
15155
|
+
if (sourceChain.chain === destinationChain.chain) {
|
|
15156
|
+
return sourceChain;
|
|
15157
|
+
}
|
|
15158
|
+
if (resolveTokenSymbol(token, sourceChain) !== null) {
|
|
15159
|
+
return sourceChain;
|
|
15160
|
+
}
|
|
15161
|
+
if (resolveTokenSymbol(token, destinationChain) !== null) {
|
|
15162
|
+
return destinationChain;
|
|
15163
|
+
}
|
|
15164
|
+
return sourceChain;
|
|
15165
|
+
}
|
|
15166
|
+
|
|
14889
15167
|
const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
14890
15168
|
/**
|
|
14891
15169
|
* Format a raw base-unit amount into a human-readable decimal string.
|
|
@@ -14976,6 +15254,186 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
|
14976
15254
|
}
|
|
14977
15255
|
}
|
|
14978
15256
|
|
|
15257
|
+
/**
|
|
15258
|
+
* Runtime guard for {@link BatchCapableSwapAdapter}.
|
|
15259
|
+
*
|
|
15260
|
+
* @param adapter - The adapter to inspect.
|
|
15261
|
+
* @returns `true` when the adapter exposes both batch methods.
|
|
15262
|
+
*
|
|
15263
|
+
* @example
|
|
15264
|
+
* ```typescript
|
|
15265
|
+
* if (isBatchCapableSwapAdapter(adapter)) {
|
|
15266
|
+
* // adapter.supportsAtomicBatch / adapter.batchExecute are available
|
|
15267
|
+
* }
|
|
15268
|
+
* ```
|
|
15269
|
+
*/ function isBatchCapableSwapAdapter(adapter) {
|
|
15270
|
+
return typeof adapter === 'object' && adapter !== null && typeof adapter.supportsAtomicBatch === 'function' && typeof adapter.batchExecute === 'function';
|
|
15271
|
+
}
|
|
15272
|
+
/**
|
|
15273
|
+
* Decide whether the EVM swap should take the batched approve-and-swap path.
|
|
15274
|
+
*
|
|
15275
|
+
* @remarks
|
|
15276
|
+
* Batching only helps when an on-chain approval would otherwise be required, so
|
|
15277
|
+
* it is skipped for native tokens (no approval) and for the gasless permit path
|
|
15278
|
+
* (already a single transaction). USDT is skipped because its reset-to-zero
|
|
15279
|
+
* allowance flow cannot be expressed as a fixed approve+swap pair. When those
|
|
15280
|
+
* gates pass, the adapter's actual atomic-batch capability is queried; any
|
|
15281
|
+
* failure resolves to `false` so the swap falls back to the sequential path.
|
|
15282
|
+
*
|
|
15283
|
+
* @param args - The decision inputs.
|
|
15284
|
+
* @param args.adapter - The source adapter.
|
|
15285
|
+
* @param args.chain - The source chain definition.
|
|
15286
|
+
* @param args.tokenInAddress - The resolved input-token address.
|
|
15287
|
+
* @param args.allowanceStrategy - Optional allowance strategy override.
|
|
15288
|
+
* @param args.batchTransactions - Optional explicit opt-out (`false` disables).
|
|
15289
|
+
* @returns `true` when the batched approve-and-swap path should be used.
|
|
15290
|
+
*
|
|
15291
|
+
* @example
|
|
15292
|
+
* ```typescript
|
|
15293
|
+
* const useBatched = await shouldUseBatchedSwap({
|
|
15294
|
+
* adapter,
|
|
15295
|
+
* chain,
|
|
15296
|
+
* tokenInAddress: '0xA0b8...',
|
|
15297
|
+
* allowanceStrategy: config?.allowanceStrategy,
|
|
15298
|
+
* batchTransactions: config?.batchTransactions,
|
|
15299
|
+
* })
|
|
15300
|
+
* ```
|
|
15301
|
+
*/ async function shouldUseBatchedSwap({ adapter, chain, tokenInAddress, allowanceStrategy, batchTransactions }) {
|
|
15302
|
+
// Explicit opt-out.
|
|
15303
|
+
if (batchTransactions === false) {
|
|
15304
|
+
return false;
|
|
15305
|
+
}
|
|
15306
|
+
// Batching is an EVM capability (EIP-5792 or a signing strategy).
|
|
15307
|
+
if (chain.type !== 'evm') {
|
|
15308
|
+
return false;
|
|
15309
|
+
}
|
|
15310
|
+
// Native tokens need no approval — the swap is already a single transaction.
|
|
15311
|
+
if (isNativeEvmAddress(tokenInAddress)) {
|
|
15312
|
+
return false;
|
|
15313
|
+
}
|
|
15314
|
+
// A gasless permit folds the approval into the swap transaction, so there is
|
|
15315
|
+
// nothing to batch. Mirrors the permit gate in handleEvmTokenApproval.
|
|
15316
|
+
const canUsePermit = allowanceStrategy !== 'approve' && supportsEIP2612(tokenInAddress, chain) && adapterSupportsPermit(adapter);
|
|
15317
|
+
if (canUsePermit) {
|
|
15318
|
+
return false;
|
|
15319
|
+
}
|
|
15320
|
+
// USDT's reset-to-zero allowance dance cannot be expressed as a fixed
|
|
15321
|
+
// approve+swap pair; leave it on the sequential path.
|
|
15322
|
+
const usdt = chain.usdtAddress?.toLowerCase();
|
|
15323
|
+
if (usdt !== undefined && tokenInAddress.toLowerCase() === usdt) {
|
|
15324
|
+
return false;
|
|
15325
|
+
}
|
|
15326
|
+
if (!isBatchCapableSwapAdapter(adapter)) {
|
|
15327
|
+
return false;
|
|
15328
|
+
}
|
|
15329
|
+
try {
|
|
15330
|
+
return await adapter.supportsAtomicBatch(chain);
|
|
15331
|
+
} catch {
|
|
15332
|
+
return false;
|
|
15333
|
+
}
|
|
15334
|
+
}
|
|
15335
|
+
/**
|
|
15336
|
+
* Execute the approval and swap as a single atomic batch.
|
|
15337
|
+
*
|
|
15338
|
+
* @remarks
|
|
15339
|
+
* Extracts the raw call data from both prepared requests, submits them as one
|
|
15340
|
+
* batch via `adapter.batchExecute`, and maps the swap receipt back to a
|
|
15341
|
+
* transaction hash. The `fromAddress` is threaded for adapters routed through a
|
|
15342
|
+
* signing strategy (which have no wallet account to read the sender from); the
|
|
15343
|
+
* wallet-client path ignores it.
|
|
15344
|
+
*
|
|
15345
|
+
* Following the batch contract, `batchExecute` never throws once the batch is
|
|
15346
|
+
* submitted — a missing or failed swap receipt is surfaced here as a thrown
|
|
15347
|
+
* {@link KitError} (FATAL) so the caller does not resubmit an already-broadcast
|
|
15348
|
+
* batch and double-swap.
|
|
15349
|
+
*
|
|
15350
|
+
* @param args - The execution inputs.
|
|
15351
|
+
* @param args.adapter - The batch-capable source adapter.
|
|
15352
|
+
* @param args.chain - The EVM chain to execute on.
|
|
15353
|
+
* @param args.approveRequest - The prepared ERC-20 approval request.
|
|
15354
|
+
* @param args.swapRequest - The prepared swap request (pre-approval / NONE permit).
|
|
15355
|
+
* @param args.fromAddress - The address authorizing the batch.
|
|
15356
|
+
* @returns The swap transaction hash and the executed approval + swap records.
|
|
15357
|
+
* @throws {@link KitError} when the prepared requests cannot yield call data.
|
|
15358
|
+
* @throws {@link KitError} when the batch does not confirm or the swap reverts.
|
|
15359
|
+
*
|
|
15360
|
+
* @example
|
|
15361
|
+
* ```typescript
|
|
15362
|
+
* const { swapTxHash, executedTransactions } = await executeBatchedApproveAndSwap({
|
|
15363
|
+
* adapter,
|
|
15364
|
+
* chain,
|
|
15365
|
+
* approveRequest,
|
|
15366
|
+
* swapRequest,
|
|
15367
|
+
* fromAddress: '0x742d...',
|
|
15368
|
+
* })
|
|
15369
|
+
* ```
|
|
15370
|
+
*/ async function executeBatchedApproveAndSwap({ adapter, chain, approveRequest, swapRequest, fromAddress }) {
|
|
15371
|
+
if (approveRequest.type !== 'evm' || swapRequest.type !== 'evm' || !approveRequest.getCallData || !swapRequest.getCallData) {
|
|
15372
|
+
throw new KitError({
|
|
15373
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
15374
|
+
recoverability: 'FATAL',
|
|
15375
|
+
message: 'Batched swap requires EVM prepared requests with getCallData() support.'
|
|
15376
|
+
});
|
|
15377
|
+
}
|
|
15378
|
+
const approveCallData = approveRequest.getCallData();
|
|
15379
|
+
const swapCallData = swapRequest.getCallData();
|
|
15380
|
+
const batchResult = await adapter.batchExecute([
|
|
15381
|
+
approveCallData,
|
|
15382
|
+
swapCallData
|
|
15383
|
+
], chain, {
|
|
15384
|
+
fromAddress
|
|
15385
|
+
});
|
|
15386
|
+
const swapReceipt = batchResult.receipts[1];
|
|
15387
|
+
// A missing swap receipt means the batch never confirmed (polling timed out
|
|
15388
|
+
// or the wallet returned fewer receipts than calls). Re-throw the underlying
|
|
15389
|
+
// error when present (already FATAL); otherwise surface a FATAL timeout so the
|
|
15390
|
+
// caller checks the batch status rather than resubmitting.
|
|
15391
|
+
if (swapReceipt === undefined || swapReceipt.txHash === '') {
|
|
15392
|
+
if (isKitError(batchResult.error)) {
|
|
15393
|
+
throw batchResult.error;
|
|
15394
|
+
}
|
|
15395
|
+
throw new KitError({
|
|
15396
|
+
...NetworkError.TIMEOUT,
|
|
15397
|
+
recoverability: 'FATAL',
|
|
15398
|
+
message: `Batched swap did not confirm on-chain (batchId: ${batchResult.batchId}). ` + 'The batch was already submitted — check its status before retrying.',
|
|
15399
|
+
// Preserve the underlying confirmation failure when it isn't a KitError —
|
|
15400
|
+
// the signing-strategy path returns a raw viem error (e.g. a dropped or
|
|
15401
|
+
// replaced tx) — so the root cause survives behind the generic timeout.
|
|
15402
|
+
cause: {
|
|
15403
|
+
trace: {
|
|
15404
|
+
batchId: batchResult.batchId,
|
|
15405
|
+
...batchResult.error != null && {
|
|
15406
|
+
error: batchResult.error
|
|
15407
|
+
}
|
|
15408
|
+
}
|
|
15409
|
+
}
|
|
15410
|
+
});
|
|
15411
|
+
}
|
|
15412
|
+
if (swapReceipt.status !== 'success') {
|
|
15413
|
+
throw createTransactionRevertedError(chain.name, 'Batched swap transaction reverted on-chain', undefined, swapReceipt.txHash, buildExplorerUrl(chain, swapReceipt.txHash));
|
|
15414
|
+
}
|
|
15415
|
+
const executedTransactions = [];
|
|
15416
|
+
const approveReceipt = batchResult.receipts[0];
|
|
15417
|
+
// An atomic batch is a single on-chain transaction, so the approve and swap
|
|
15418
|
+
// receipts share one hash. Only surface a distinct approval record when it is
|
|
15419
|
+
// genuinely a separate transaction; otherwise the lone swap record represents
|
|
15420
|
+
// the batch, avoiding a phantom duplicate tx in executedTransactions.
|
|
15421
|
+
if (approveReceipt !== undefined && approveReceipt.txHash !== '' && approveReceipt.txHash !== swapReceipt.txHash) {
|
|
15422
|
+
executedTransactions.push({
|
|
15423
|
+
type: 'approval',
|
|
15424
|
+
txHash: approveReceipt.txHash
|
|
15425
|
+
});
|
|
15426
|
+
}
|
|
15427
|
+
executedTransactions.push({
|
|
15428
|
+
type: 'swap',
|
|
15429
|
+
txHash: swapReceipt.txHash
|
|
15430
|
+
});
|
|
15431
|
+
return {
|
|
15432
|
+
swapTxHash: swapReceipt.txHash,
|
|
15433
|
+
executedTransactions
|
|
15434
|
+
};
|
|
15435
|
+
}
|
|
15436
|
+
|
|
14979
15437
|
/**
|
|
14980
15438
|
* Safety multiplier applied to locally estimated gas for EVM swap execution.
|
|
14981
15439
|
* Derived from refund cap (max 1/5 of total gas used) plus an extra 0.1 margin,
|
|
@@ -15102,7 +15560,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15102
15560
|
const statusResult = await getSwapStatus$1({
|
|
15103
15561
|
txHash,
|
|
15104
15562
|
chain: chain.chain,
|
|
15105
|
-
apiKey
|
|
15563
|
+
...apiKey !== undefined && {
|
|
15564
|
+
apiKey
|
|
15565
|
+
}
|
|
15106
15566
|
});
|
|
15107
15567
|
if (statusResult.status === 'DONE' && statusResult.amountOut !== undefined) {
|
|
15108
15568
|
return {
|
|
@@ -15693,8 +16153,7 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15693
16153
|
// Note: tokenInAddress from executionCtx is already resolved (handles NATIVE alias, ETH, etc.)
|
|
15694
16154
|
const isNativeToken = isNativeEvmAddress(executionCtx.tokenInAddress);
|
|
15695
16155
|
const tokenSupportsPermit = supportsEIP2612(executionCtx.tokenInAddress, chain);
|
|
15696
|
-
const
|
|
15697
|
-
const canUsePermitFlow = tokenSupportsPermit && adapterSupportsPermit && allowanceStrategy !== 'approve';
|
|
16156
|
+
const canUsePermitFlow = tokenSupportsPermit && adapterSupportsPermit(adapter) && allowanceStrategy !== 'approve';
|
|
15698
16157
|
const needsApproval = !isNativeToken && !canUsePermitFlow;
|
|
15699
16158
|
if (!needsApproval) {
|
|
15700
16159
|
return;
|
|
@@ -15973,34 +16432,55 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15973
16432
|
const serviceResponse = await createSwap(serviceParams);
|
|
15974
16433
|
// Track executed transactions
|
|
15975
16434
|
const executedTransactions = [];
|
|
15976
|
-
// Prepare swap action based on chain type
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
}
|
|
16435
|
+
// Prepare swap action(s) based on chain type and batch capability.
|
|
16436
|
+
// Returns either a single prepared action (Solana / sequential EVM) or a
|
|
16437
|
+
// batched approve+swap plan (EVM atomic-batch path).
|
|
16438
|
+
const { preparedAction, batchedSwapPlan } = await this.prepareSwapRequests({
|
|
16439
|
+
adapter,
|
|
16440
|
+
chain,
|
|
16441
|
+
serviceResponse,
|
|
16442
|
+
resolvedContext,
|
|
16443
|
+
executionCtx,
|
|
16444
|
+
config,
|
|
16445
|
+
executedTransactions
|
|
16446
|
+
});
|
|
15989
16447
|
// Execute swap transaction via adapter
|
|
15990
16448
|
// For EVM chains, use gas limit from proxy service API
|
|
15991
16449
|
let txHash;
|
|
15992
16450
|
const evmGasLimit = 'gasLimit' in serviceResponse.transaction ? serviceResponse.transaction.gasLimit : undefined;
|
|
15993
16451
|
try {
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16452
|
+
if (batchedSwapPlan) {
|
|
16453
|
+
// Approve + swap submitted as one atomic batch. batchExecute confirms
|
|
16454
|
+
// the swap internally, so no separate waitForTransaction is needed.
|
|
16455
|
+
const batched = await executeBatchedApproveAndSwap({
|
|
16456
|
+
adapter: adapter,
|
|
16457
|
+
chain: chain,
|
|
16458
|
+
approveRequest: batchedSwapPlan.approveRequest,
|
|
16459
|
+
swapRequest: batchedSwapPlan.swapRequest,
|
|
16460
|
+
fromAddress: executionCtx.fromAddress
|
|
16461
|
+
});
|
|
16462
|
+
txHash = batched.swapTxHash;
|
|
16463
|
+
executedTransactions.push(...batched.executedTransactions);
|
|
16464
|
+
} else if (preparedAction) {
|
|
16465
|
+
txHash = await this.executeSwapTransaction(preparedAction, evmGasLimit);
|
|
16466
|
+
executedTransactions.push({
|
|
16467
|
+
type: 'swap',
|
|
16468
|
+
txHash
|
|
16469
|
+
});
|
|
16470
|
+
// Wait for transaction confirmation and verify success
|
|
16471
|
+
const txReceipt = await adapter.waitForTransaction(txHash, undefined, chain);
|
|
16472
|
+
if (txReceipt.status === 'reverted') {
|
|
16473
|
+
const explorerUrl = buildExplorerUrl(chain, txHash);
|
|
16474
|
+
throw createTransactionRevertedError(chain.name, 'Swap transaction reverted on-chain', undefined, txHash, explorerUrl);
|
|
16475
|
+
}
|
|
16476
|
+
} else {
|
|
16477
|
+
// Unreachable: the preparation step always yields either a batched plan
|
|
16478
|
+
// or a prepared action.
|
|
16479
|
+
throw new KitError({
|
|
16480
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
16481
|
+
recoverability: 'FATAL',
|
|
16482
|
+
message: 'No swap execution path was prepared.'
|
|
16483
|
+
});
|
|
16004
16484
|
}
|
|
16005
16485
|
} catch (err) {
|
|
16006
16486
|
handleSwapExecutionError(err, txHash, chain);
|
|
@@ -16019,7 +16499,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16019
16499
|
isCrossChainSwap,
|
|
16020
16500
|
txHash,
|
|
16021
16501
|
chain,
|
|
16022
|
-
|
|
16502
|
+
...serviceParams.apiKey !== undefined && {
|
|
16503
|
+
apiKey: serviceParams.apiKey
|
|
16504
|
+
}
|
|
16023
16505
|
});
|
|
16024
16506
|
// Build and return SwapResult
|
|
16025
16507
|
return {
|
|
@@ -16044,6 +16526,79 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16044
16526
|
};
|
|
16045
16527
|
}
|
|
16046
16528
|
/**
|
|
16529
|
+
* Prepare the swap execution request(s) for the source wallet's chain.
|
|
16530
|
+
*
|
|
16531
|
+
* Produces either a single {@link PreparedChainRequest} (Solana, or the
|
|
16532
|
+
* sequential EVM approve-then-swap path) or a `batchedSwapPlan` (the EVM
|
|
16533
|
+
* atomic approve+swap path chosen when the adapter supports EIP-5792 atomic
|
|
16534
|
+
* batching). The caller executes whichever field is populated. Any on-chain
|
|
16535
|
+
* approval sent on the sequential path is appended to `executedTransactions`.
|
|
16536
|
+
*
|
|
16537
|
+
* @typeParam TFromAdapterCapabilities - Source-adapter capability set.
|
|
16538
|
+
* @param args - Inputs derived from the validated swap request.
|
|
16539
|
+
* @param args.adapter - Source-chain wallet adapter.
|
|
16540
|
+
* @param args.chain - Source chain definition.
|
|
16541
|
+
* @param args.serviceResponse - Validated createSwap response.
|
|
16542
|
+
* @param args.resolvedContext - Resolved operation context.
|
|
16543
|
+
* @param args.executionCtx - Minimal on-chain execution context.
|
|
16544
|
+
* @param args.config - Optional swap configuration (allowance/batch flags).
|
|
16545
|
+
* @param args.executedTransactions - Array appended with any sent approval.
|
|
16546
|
+
* @returns The prepared action or the batched approve+swap plan.
|
|
16547
|
+
* @throws KitError when the EVM atomic-batch path is selected but the chain
|
|
16548
|
+
* has no configured adapter contract.
|
|
16549
|
+
*/ async prepareSwapRequests(args) {
|
|
16550
|
+
const { adapter, chain, serviceResponse, resolvedContext, executionCtx, config, executedTransactions } = args;
|
|
16551
|
+
if (chain.type === 'solana') {
|
|
16552
|
+
// Solana: No approval needed, directly prepare swap action
|
|
16553
|
+
return {
|
|
16554
|
+
preparedAction: await prepareSolanaSwapAction(adapter, serviceResponse, resolvedContext)
|
|
16555
|
+
};
|
|
16556
|
+
}
|
|
16557
|
+
const useBatch = await shouldUseBatchedSwap({
|
|
16558
|
+
adapter,
|
|
16559
|
+
chain,
|
|
16560
|
+
tokenInAddress: executionCtx.tokenInAddress,
|
|
16561
|
+
allowanceStrategy: config?.allowanceStrategy,
|
|
16562
|
+
batchTransactions: config?.batchTransactions
|
|
16563
|
+
});
|
|
16564
|
+
if (useBatch) {
|
|
16565
|
+
// EVM chains: fuse the ERC-20 approval and the swap into a single atomic
|
|
16566
|
+
// batch (one signing challenge for smart-contract wallets). Force the
|
|
16567
|
+
// swap onto the pre-approval (PermitType.NONE) path since the approval
|
|
16568
|
+
// rides in the same batch.
|
|
16569
|
+
const adapterContractAddress = chain.kitContracts?.adapter;
|
|
16570
|
+
if (!adapterContractAddress) {
|
|
16571
|
+
throw new KitError({
|
|
16572
|
+
...InputError.VALIDATION_FAILED,
|
|
16573
|
+
recoverability: 'FATAL',
|
|
16574
|
+
message: `Adapter contract not configured for chain ${chain.name}. Swap operations require an adapter contract.`,
|
|
16575
|
+
cause: {
|
|
16576
|
+
trace: {
|
|
16577
|
+
chain: chain.name
|
|
16578
|
+
}
|
|
16579
|
+
}
|
|
16580
|
+
});
|
|
16581
|
+
}
|
|
16582
|
+
const [approveRequest, swapRequest] = await Promise.all([
|
|
16583
|
+
this.approve(adapter, executionCtx.amount, executionCtx.tokenInAddress, adapterContractAddress, resolvedContext),
|
|
16584
|
+
prepareEvmSwapAction(adapter, serviceResponse, resolvedContext, 'approve')
|
|
16585
|
+
]);
|
|
16586
|
+
return {
|
|
16587
|
+
batchedSwapPlan: {
|
|
16588
|
+
approveRequest,
|
|
16589
|
+
swapRequest
|
|
16590
|
+
}
|
|
16591
|
+
};
|
|
16592
|
+
}
|
|
16593
|
+
// EVM chains: Handle token approval if needed, then prepare the swap.
|
|
16594
|
+
// prepareEvmSwapAction handles EIP-2612 permit generation; the adapter
|
|
16595
|
+
// contract address is read from chain.kitContracts.adapter.
|
|
16596
|
+
await this.handleEvmTokenApproval(adapter, chain, executionCtx, resolvedContext, executedTransactions, config?.allowanceStrategy);
|
|
16597
|
+
return {
|
|
16598
|
+
preparedAction: await prepareEvmSwapAction(adapter, serviceResponse, resolvedContext, config?.allowanceStrategy)
|
|
16599
|
+
};
|
|
16600
|
+
}
|
|
16601
|
+
/**
|
|
16047
16602
|
* Executes a swap transaction with the appropriate gas limit for the chain type.
|
|
16048
16603
|
*
|
|
16049
16604
|
* For EVM chains, performs a local eth_estimateGas call, applies a 1.3x safety
|
|
@@ -16092,8 +16647,8 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16092
16647
|
*/ async buildFormattedFees(fees, chain, destinationChain, adapter, recipientAddress) {
|
|
16093
16648
|
if (!fees) return [];
|
|
16094
16649
|
const [providerFees, swapFees, developerFees] = await Promise.all([
|
|
16095
|
-
this.formatServiceFees(fees.provider, chain, 'provider', adapter),
|
|
16096
|
-
this.formatServiceFees(fees.swap, chain, 'swap', adapter),
|
|
16650
|
+
this.formatServiceFees(fees.provider, chain, destinationChain, 'provider', adapter),
|
|
16651
|
+
this.formatServiceFees(fees.swap, chain, destinationChain, 'swap', adapter),
|
|
16097
16652
|
recipientAddress ? this.formatDeveloperFees(fees.developer, chain, destinationChain, recipientAddress, adapter) : Promise.resolve([])
|
|
16098
16653
|
]);
|
|
16099
16654
|
return [
|
|
@@ -16103,6 +16658,45 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16103
16658
|
];
|
|
16104
16659
|
}
|
|
16105
16660
|
/**
|
|
16661
|
+
* Resolve a single fee item to its display token and human-readable amount.
|
|
16662
|
+
*
|
|
16663
|
+
* @remarks
|
|
16664
|
+
* Prefer the self-describing metadata the service attaches to each fee:
|
|
16665
|
+
* `decimals` (and `symbol`) come straight from the provider quote, so they
|
|
16666
|
+
* are authoritative even for a token absent from the SDK registry on both
|
|
16667
|
+
* chains. That is the case {@link resolveFeeChain} cannot recover — a
|
|
16668
|
+
* destination-denominated fee token resolves on neither the source registry
|
|
16669
|
+
* nor the source-bound adapter, leaving the amount as raw base units. When
|
|
16670
|
+
* the service omits `decimals` (optional during rollout), fall back to
|
|
16671
|
+
* inferring the fee token's chain and resolving via the registry/adapter.
|
|
16672
|
+
*
|
|
16673
|
+
* Like {@link formatTokenValue}, this never throws: fee display is cosmetic
|
|
16674
|
+
* and must not fail an estimate/swap. A malformed self-describing `decimals`
|
|
16675
|
+
* (e.g. a non-numeric `amount` or invalid decimal count that makes
|
|
16676
|
+
* {@link formatUnits} throw) falls through to chain-based resolution rather
|
|
16677
|
+
* than propagating out of {@link buildFormattedFees}.
|
|
16678
|
+
*
|
|
16679
|
+
* @param fee - The fee item from the service response.
|
|
16680
|
+
* @param chain - The source chain definition.
|
|
16681
|
+
* @param destinationChain - The destination chain definition.
|
|
16682
|
+
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16683
|
+
* @returns Promise resolving to the formatted amount and display token.
|
|
16684
|
+
*/ async formatFeeValue(fee, chain, destinationChain, adapter) {
|
|
16685
|
+
if (fee.decimals != null) {
|
|
16686
|
+
try {
|
|
16687
|
+
return {
|
|
16688
|
+
amount: formatUnits(fee.amount, fee.decimals),
|
|
16689
|
+
token: fee.symbol ?? fee.token
|
|
16690
|
+
};
|
|
16691
|
+
} catch {
|
|
16692
|
+
// Malformed service metadata — fall through to chain-based resolution,
|
|
16693
|
+
// which never throws (worst case: raw passthrough).
|
|
16694
|
+
}
|
|
16695
|
+
}
|
|
16696
|
+
const feeChain = resolveFeeChain(fee.token, chain, destinationChain);
|
|
16697
|
+
return formatTokenValue(fee.amount, fee.token, feeChain, adapter);
|
|
16698
|
+
}
|
|
16699
|
+
/**
|
|
16106
16700
|
* Format service fee items into the SDK's ServiceSwapFee structure.
|
|
16107
16701
|
*
|
|
16108
16702
|
* @remarks
|
|
@@ -16113,14 +16707,15 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16113
16707
|
* - Raw passthrough only when both registry and adapter fail
|
|
16114
16708
|
*
|
|
16115
16709
|
* @param feeItems - Array of fee items from the service response.
|
|
16116
|
-
* @param chain - The chain definition for token resolution and formatting.
|
|
16710
|
+
* @param chain - The source chain definition for token resolution and formatting.
|
|
16711
|
+
* @param destinationChain - The destination chain, used to resolve fees denominated in the output token.
|
|
16117
16712
|
* @param type - The fee type to assign ('provider' or 'swap').
|
|
16118
16713
|
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16119
16714
|
* @returns Promise resolving to formatted ServiceSwapFee array.
|
|
16120
|
-
*/ async formatServiceFees(feeItems, chain, type, adapter) {
|
|
16715
|
+
*/ async formatServiceFees(feeItems, chain, destinationChain, type, adapter) {
|
|
16121
16716
|
if (!feeItems) return [];
|
|
16122
16717
|
return Promise.all(feeItems.map(async (fee)=>{
|
|
16123
|
-
const formatted = await
|
|
16718
|
+
const formatted = await this.formatFeeValue(fee, chain, destinationChain, adapter);
|
|
16124
16719
|
return {
|
|
16125
16720
|
token: formatted.token,
|
|
16126
16721
|
amount: formatted.amount,
|
|
@@ -16132,16 +16727,15 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16132
16727
|
* Format developer fee items into the SDK's ServiceSwapFee structure.
|
|
16133
16728
|
*
|
|
16134
16729
|
* @param feeItems - Array of developer fee items from the service response.
|
|
16135
|
-
* @param chain - The chain definition for token resolution and formatting.
|
|
16730
|
+
* @param chain - The source chain definition for token resolution and formatting.
|
|
16731
|
+
* @param destinationChain - The destination chain, used to resolve fees denominated in the output token.
|
|
16136
16732
|
* @param recipientAddress - The developer's fee recipient address from config.
|
|
16137
16733
|
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16138
16734
|
* @returns Promise resolving to formatted ServiceSwapFee array with developer entries.
|
|
16139
16735
|
*/ async formatDeveloperFees(feeItems, chain, destinationChain, recipientAddress, adapter) {
|
|
16140
16736
|
if (!feeItems) return [];
|
|
16141
|
-
const isCrossChainSwap = destinationChain.chain !== chain.chain;
|
|
16142
16737
|
return Promise.all(feeItems.map(async (fee)=>{
|
|
16143
|
-
const
|
|
16144
|
-
const formatted = await formatTokenValue(fee.amount, fee.token, feeChain, adapter);
|
|
16738
|
+
const formatted = await this.formatFeeValue(fee, chain, destinationChain, adapter);
|
|
16145
16739
|
return {
|
|
16146
16740
|
token: formatted.token,
|
|
16147
16741
|
amount: formatted.amount,
|
|
@@ -18536,22 +19130,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
|
|
|
18536
19130
|
try {
|
|
18537
19131
|
// Step 1: Build quote params directly (no need for buildServiceParams)
|
|
18538
19132
|
// Use chain.chain (Blockchain enum value like "World_Chain") not chain.name
|
|
19133
|
+
// The kit key is optional (permissionless mode); when absent the quote is
|
|
19134
|
+
// fetched without an Authorization header.
|
|
18539
19135
|
const kitKey = params.config?.kitKey;
|
|
18540
|
-
if (!kitKey) {
|
|
18541
|
-
throw new KitError({
|
|
18542
|
-
code: 1098,
|
|
18543
|
-
name: 'INPUT_VALIDATION_FAILED',
|
|
18544
|
-
type: 'INPUT',
|
|
18545
|
-
recoverability: 'FATAL',
|
|
18546
|
-
message: 'kitKey is required in config for callback-based fees',
|
|
18547
|
-
cause: {
|
|
18548
|
-
trace: {
|
|
18549
|
-
operation: 'handleOutputFeeCallback',
|
|
18550
|
-
params
|
|
18551
|
-
}
|
|
18552
|
-
}
|
|
18553
|
-
});
|
|
18554
|
-
}
|
|
18555
19136
|
// Resolve token aliases to addresses for the quote API
|
|
18556
19137
|
// The quote endpoint requires resolved addresses, not aliases like 'USDC'
|
|
18557
19138
|
const chain = params.from.chain;
|
|
@@ -18576,7 +19157,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
|
|
|
18576
19157
|
...params.config?.slippageBps !== undefined && {
|
|
18577
19158
|
slippageBps: params.config.slippageBps
|
|
18578
19159
|
},
|
|
18579
|
-
|
|
19160
|
+
...kitKey ? {
|
|
19161
|
+
apiKey: kitKey
|
|
19162
|
+
} : {}
|
|
18580
19163
|
};
|
|
18581
19164
|
// Step 2: Get quote from service
|
|
18582
19165
|
const quoteResponse = await getQuote(quoteParams);
|
|
@@ -19018,7 +19601,9 @@ const sleep$1 = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
|
|
|
19018
19601
|
...isCrossChain && {
|
|
19019
19602
|
toChain: chainOut
|
|
19020
19603
|
},
|
|
19021
|
-
|
|
19604
|
+
...params.kitKey ? {
|
|
19605
|
+
apiKey: params.kitKey
|
|
19606
|
+
} : {}
|
|
19022
19607
|
};
|
|
19023
19608
|
let raw = await getSwapStatus$1(request);
|
|
19024
19609
|
// When the service hasn't finished indexing a just-submitted swap it
|
|
@@ -19158,7 +19743,9 @@ const isResultShape = (params)=>'result' in params;
|
|
|
19158
19743
|
...chainOut !== undefined && {
|
|
19159
19744
|
chainOut
|
|
19160
19745
|
},
|
|
19161
|
-
|
|
19746
|
+
...params.kitKey ? {
|
|
19747
|
+
kitKey: params.kitKey
|
|
19748
|
+
} : {}
|
|
19162
19749
|
};
|
|
19163
19750
|
const deadline = Date.now() + timeoutMs;
|
|
19164
19751
|
let pollIndex = 0;
|
|
@@ -19319,7 +19906,9 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
19319
19906
|
const resolvedAddresses = params.tokens?.map((entry, index)=>resolveTokenEntry(entry, index, chain, chainDef, context));
|
|
19320
19907
|
return getTokenRates$1({
|
|
19321
19908
|
chain,
|
|
19322
|
-
|
|
19909
|
+
...params.kitKey ? {
|
|
19910
|
+
apiKey: params.kitKey
|
|
19911
|
+
} : {},
|
|
19323
19912
|
...resolvedAddresses !== undefined && {
|
|
19324
19913
|
addresses: resolvedAddresses
|
|
19325
19914
|
}
|
|
@@ -20316,7 +20905,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20316
20905
|
};
|
|
20317
20906
|
|
|
20318
20907
|
var name = "@circle-fin/earn-kit";
|
|
20319
|
-
var version = "1.
|
|
20908
|
+
var version = "1.3.0";
|
|
20320
20909
|
var pkg = {
|
|
20321
20910
|
name: name,
|
|
20322
20911
|
version: version};
|
|
@@ -20446,7 +21035,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20446
21035
|
asset: zod.z.string(),
|
|
20447
21036
|
assetAddress: zod.z.string(),
|
|
20448
21037
|
lltv: zod.z.number(),
|
|
20449
|
-
supplyUsd: zod.z.number()
|
|
21038
|
+
supplyUsd: zod.z.number(),
|
|
21039
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
21040
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
21041
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
21042
|
+
allocationPct: zod.z.number().nullable().optional()
|
|
20450
21043
|
});
|
|
20451
21044
|
/**
|
|
20452
21045
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -20460,7 +21053,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20460
21053
|
])
|
|
20461
21054
|
});
|
|
20462
21055
|
/**
|
|
20463
|
-
* Zod schema for
|
|
21056
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
21057
|
+
*
|
|
21058
|
+
* @internal
|
|
21059
|
+
*/ const managerSchema = zod.z.object({
|
|
21060
|
+
name: zod.z.string(),
|
|
21061
|
+
address: zod.z.string().optional(),
|
|
21062
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
21063
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
21064
|
+
// speculatively.
|
|
21065
|
+
type: zod.z.enum([
|
|
21066
|
+
'curator'
|
|
21067
|
+
])
|
|
21068
|
+
});
|
|
21069
|
+
/**
|
|
21070
|
+
* Zod schema for the APY profile facet in the API response.
|
|
21071
|
+
*
|
|
21072
|
+
* @internal
|
|
21073
|
+
*/ const apyProfileSchema = zod.z.object({
|
|
21074
|
+
current: zod.z.number(),
|
|
21075
|
+
native: zod.z.number().nullable(),
|
|
21076
|
+
d7: zod.z.number().nullable(),
|
|
21077
|
+
d30: zod.z.number().nullable(),
|
|
21078
|
+
d90: zod.z.number().nullable(),
|
|
21079
|
+
rewardShare: zod.z.number().nullable(),
|
|
21080
|
+
source: zod.z.string().optional(),
|
|
21081
|
+
asOf: zod.z.string().optional()
|
|
21082
|
+
});
|
|
21083
|
+
/**
|
|
21084
|
+
* Zod schema for the fee split facet in the API response.
|
|
21085
|
+
*
|
|
21086
|
+
* @internal
|
|
21087
|
+
*/ const feeInfoSchema = zod.z.object({
|
|
21088
|
+
performance: zod.z.number().nullable(),
|
|
21089
|
+
management: zod.z.number().nullable()
|
|
21090
|
+
});
|
|
21091
|
+
/**
|
|
21092
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
21093
|
+
*
|
|
21094
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
21095
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
21096
|
+
*
|
|
21097
|
+
* @internal
|
|
21098
|
+
*/ const liquidityProfileSchema = zod.z.object({
|
|
21099
|
+
totalDeposits: amountJsonSchema,
|
|
21100
|
+
available: amountJsonSchema,
|
|
21101
|
+
totalSupply: amountJsonSchema,
|
|
21102
|
+
status: zod.z.enum([
|
|
21103
|
+
'active',
|
|
21104
|
+
'low_liquidity'
|
|
21105
|
+
])
|
|
21106
|
+
});
|
|
21107
|
+
/**
|
|
21108
|
+
* Zod schema for the risk signals facet in the API response.
|
|
21109
|
+
*
|
|
21110
|
+
* @internal
|
|
21111
|
+
*/ const riskSignalsSchema = zod.z.object({
|
|
21112
|
+
circleSentinel: zod.z.boolean(),
|
|
21113
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
21114
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
21115
|
+
});
|
|
21116
|
+
/**
|
|
21117
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
21118
|
+
*
|
|
21119
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
21120
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
21121
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
21122
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
21123
|
+
* backend; they become required after Expand ships.
|
|
20464
21124
|
*
|
|
20465
21125
|
* @internal
|
|
20466
21126
|
*/ const vaultInfoResponseSchema = zod.z.object({
|
|
@@ -20485,6 +21145,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20485
21145
|
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
20486
21146
|
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
20487
21147
|
});
|
|
21148
|
+
/**
|
|
21149
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
21150
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
21151
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
21152
|
+
*
|
|
21153
|
+
* @internal
|
|
21154
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
21155
|
+
address: zod.z.string().optional(),
|
|
21156
|
+
asOf: zod.z.string().optional(),
|
|
21157
|
+
manager: managerSchema.nullable().optional(),
|
|
21158
|
+
apyProfile: apyProfileSchema.optional(),
|
|
21159
|
+
fee: feeInfoSchema.optional(),
|
|
21160
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
21161
|
+
riskSignals: riskSignalsSchema.optional()
|
|
21162
|
+
});
|
|
21163
|
+
/**
|
|
21164
|
+
* Zod schema for the `vault` opportunity variant.
|
|
21165
|
+
*
|
|
21166
|
+
* @internal
|
|
21167
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
21168
|
+
productType: zod.z.literal('vault'),
|
|
21169
|
+
collateral: zod.z.array(collateralSchema)
|
|
21170
|
+
});
|
|
21171
|
+
/**
|
|
21172
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
21173
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
21174
|
+
*
|
|
21175
|
+
* @internal
|
|
21176
|
+
*/ const earnOpportunityVariants = [
|
|
21177
|
+
vaultOpportunitySchema
|
|
21178
|
+
];
|
|
21179
|
+
/** @internal */ const earnOpportunitySchema = zod.z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
21180
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
21181
|
+
/**
|
|
21182
|
+
* Tolerant list parser for earn opportunities.
|
|
21183
|
+
*
|
|
21184
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
21185
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
21186
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
21187
|
+
*
|
|
21188
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
21189
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
21190
|
+
* rather than dropping every vault the backend returns.
|
|
21191
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
21192
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
21193
|
+
* of rejecting the whole list.
|
|
21194
|
+
*
|
|
21195
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
21196
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
21197
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
21198
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
21199
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
21200
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
21201
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
21202
|
+
* `ZodError`).
|
|
21203
|
+
*
|
|
21204
|
+
* @internal
|
|
21205
|
+
*/ const earnOpportunityListSchema = zod.z.preprocess((raw)=>{
|
|
21206
|
+
if (!Array.isArray(raw)) {
|
|
21207
|
+
return raw;
|
|
21208
|
+
}
|
|
21209
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
21210
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
21211
|
+
const entries = raw;
|
|
21212
|
+
return entries.map((entry)=>{
|
|
21213
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
21214
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
21215
|
+
return entry;
|
|
21216
|
+
}
|
|
21217
|
+
const record = entry;
|
|
21218
|
+
// Older backend predating productType: default to the only type then.
|
|
21219
|
+
return record.productType === undefined ? {
|
|
21220
|
+
...record,
|
|
21221
|
+
productType: 'vault'
|
|
21222
|
+
} : record;
|
|
21223
|
+
}).filter((entry)=>{
|
|
21224
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
21225
|
+
// productType this SDK version doesn't know). Everything else —
|
|
21226
|
+
// non-objects, a non-string productType — flows through to
|
|
21227
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
21228
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
21229
|
+
return true;
|
|
21230
|
+
}
|
|
21231
|
+
const productType = entry.productType;
|
|
21232
|
+
if (typeof productType !== 'string') {
|
|
21233
|
+
return true;
|
|
21234
|
+
}
|
|
21235
|
+
return knownProductTypes.has(productType);
|
|
21236
|
+
});
|
|
21237
|
+
}, zod.z.array(earnOpportunitySchema));
|
|
20488
21238
|
// ---------------------------------------------------------------------------
|
|
20489
21239
|
// Position response schema
|
|
20490
21240
|
// ---------------------------------------------------------------------------
|
|
@@ -20614,6 +21364,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
|
20614
21364
|
*
|
|
20615
21365
|
* @internal
|
|
20616
21366
|
*/ const depositPayloadSchema = zod.z.object({
|
|
21367
|
+
execId: bridgeDepositExecIdSchema,
|
|
20617
21368
|
executionParams: depositExecutionParamsSchema,
|
|
20618
21369
|
signature: hexSignatureSchema
|
|
20619
21370
|
});
|
|
@@ -20705,6 +21456,21 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20705
21456
|
amount: amountJsonSchema,
|
|
20706
21457
|
vaultAddress: hexAddressSchema
|
|
20707
21458
|
}).passthrough();
|
|
21459
|
+
/** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
|
|
21460
|
+
zod.z.object({
|
|
21461
|
+
mode: zod.z.literal('TIMESTAMP'),
|
|
21462
|
+
expiresAt: zod.z.string().datetime({
|
|
21463
|
+
offset: true
|
|
21464
|
+
})
|
|
21465
|
+
}),
|
|
21466
|
+
zod.z.object({
|
|
21467
|
+
mode: zod.z.literal('BLOCK_NUMBER'),
|
|
21468
|
+
expiresAtBlock: zod.z.number().int(),
|
|
21469
|
+
blockEstimatedAt: zod.z.string().datetime({
|
|
21470
|
+
offset: true
|
|
21471
|
+
}).optional()
|
|
21472
|
+
})
|
|
21473
|
+
]).optional().catch(undefined);
|
|
20708
21474
|
/**
|
|
20709
21475
|
* Zod schema for the bridge deposit prepare payload.
|
|
20710
21476
|
*
|
|
@@ -20716,6 +21482,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20716
21482
|
execId: bridgeDepositExecIdSchema,
|
|
20717
21483
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
20718
21484
|
expiresAt: zod.z.string().datetime(),
|
|
21485
|
+
quoteIssuedAt: zod.z.string().datetime({
|
|
21486
|
+
offset: true
|
|
21487
|
+
}).optional().catch(undefined),
|
|
21488
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
20719
21489
|
review: bridgeDepositPrepareReviewSchema
|
|
20720
21490
|
});
|
|
20721
21491
|
/**
|
|
@@ -20781,6 +21551,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20781
21551
|
*
|
|
20782
21552
|
* @internal
|
|
20783
21553
|
*/ const withdrawPayloadSchema = zod.z.object({
|
|
21554
|
+
execId: bridgeDepositExecIdSchema,
|
|
20784
21555
|
executionParams: withdrawExecutionParamsSchema,
|
|
20785
21556
|
signature: hexSignatureSchema
|
|
20786
21557
|
});
|
|
@@ -20794,6 +21565,27 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20794
21565
|
data: withdrawPayloadSchema
|
|
20795
21566
|
});
|
|
20796
21567
|
// ---------------------------------------------------------------------------
|
|
21568
|
+
// Transaction report response schema
|
|
21569
|
+
// ---------------------------------------------------------------------------
|
|
21570
|
+
/**
|
|
21571
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
21572
|
+
*
|
|
21573
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
21574
|
+
* schema accepts any object shape and does not require specific fields.
|
|
21575
|
+
*
|
|
21576
|
+
* @internal
|
|
21577
|
+
*/ const transactionReportPayloadSchema = zod.z.object({}).passthrough();
|
|
21578
|
+
/**
|
|
21579
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
21580
|
+
*
|
|
21581
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
21582
|
+
* envelope.
|
|
21583
|
+
*
|
|
21584
|
+
* @internal
|
|
21585
|
+
*/ zod.z.object({
|
|
21586
|
+
data: transactionReportPayloadSchema
|
|
21587
|
+
});
|
|
21588
|
+
// ---------------------------------------------------------------------------
|
|
20797
21589
|
// Claim rewards response schema
|
|
20798
21590
|
// ---------------------------------------------------------------------------
|
|
20799
21591
|
/**
|
|
@@ -20841,10 +21633,11 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20841
21633
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
20842
21634
|
*
|
|
20843
21635
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
20844
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
20845
|
-
*
|
|
20846
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
20847
|
-
* `'
|
|
21636
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
21637
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
21638
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
21639
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
21640
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
20848
21641
|
*
|
|
20849
21642
|
* @internal
|
|
20850
21643
|
*/ const feeSchema = zod.z.object({
|
|
@@ -20853,6 +21646,30 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20853
21646
|
token: zod.z.string(),
|
|
20854
21647
|
amount: amountJsonSchema
|
|
20855
21648
|
});
|
|
21649
|
+
/**
|
|
21650
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
21651
|
+
*
|
|
21652
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
21653
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
21654
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
21655
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
21656
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
21657
|
+
*
|
|
21658
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
21659
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
21660
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
21661
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
21662
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
21663
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
21664
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
21665
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
21666
|
+
*
|
|
21667
|
+
* @internal
|
|
21668
|
+
*/ const quoteGasFeeSchema = zod.z.object({
|
|
21669
|
+
name: zod.z.string().optional(),
|
|
21670
|
+
fees: zod.z.unknown(),
|
|
21671
|
+
error: zod.z.string().optional()
|
|
21672
|
+
}).passthrough();
|
|
20856
21673
|
/**
|
|
20857
21674
|
* Zod schema for the inner deposit quote payload.
|
|
20858
21675
|
*
|
|
@@ -20868,7 +21685,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20868
21685
|
expectedShares: amountJsonSchema,
|
|
20869
21686
|
sharePrice: zod.z.string(),
|
|
20870
21687
|
currentApy: zod.z.number(),
|
|
20871
|
-
fees: zod.z.array(feeSchema).optional()
|
|
21688
|
+
fees: zod.z.array(feeSchema).optional(),
|
|
21689
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional()
|
|
20872
21690
|
});
|
|
20873
21691
|
/**
|
|
20874
21692
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -20895,6 +21713,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20895
21713
|
sharePrice: zod.z.string(),
|
|
20896
21714
|
maxWithdrawable: amountJsonSchema,
|
|
20897
21715
|
fees: zod.z.array(feeSchema),
|
|
21716
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional(),
|
|
20898
21717
|
warnings: zod.z.array(zod.z.string()).optional()
|
|
20899
21718
|
});
|
|
20900
21719
|
/**
|
|
@@ -20952,7 +21771,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20952
21771
|
*
|
|
20953
21772
|
* @internal
|
|
20954
21773
|
*/ const getVaultsPayloadSchema = zod.z.object({
|
|
20955
|
-
vaults:
|
|
21774
|
+
vaults: earnOpportunityListSchema,
|
|
20956
21775
|
errors: zod.z.array(vaultErrorSchema)
|
|
20957
21776
|
});
|
|
20958
21777
|
/**
|
|
@@ -20982,7 +21801,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
20982
21801
|
*
|
|
20983
21802
|
* @internal
|
|
20984
21803
|
*/ const exploreVaultsPayloadSchema = zod.z.object({
|
|
20985
|
-
vaults:
|
|
21804
|
+
vaults: earnOpportunityListSchema,
|
|
20986
21805
|
pagination: explorePaginationSchema
|
|
20987
21806
|
});
|
|
20988
21807
|
/**
|