@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.mjs
CHANGED
|
@@ -18,13 +18,14 @@
|
|
|
18
18
|
|
|
19
19
|
import { z } from 'zod';
|
|
20
20
|
import 'pino';
|
|
21
|
+
import { hexlify, hexZeroPad } from '@ethersproject/bytes';
|
|
22
|
+
import '@ethersproject/abi';
|
|
23
|
+
import { getAddress } from '@ethersproject/address';
|
|
21
24
|
import { PublicKey } from '@solana/web3.js';
|
|
22
25
|
import 'bn.js';
|
|
23
26
|
import '@coral-xyz/anchor';
|
|
24
27
|
import bs58 from 'bs58';
|
|
25
28
|
import '@noble/curves/ed25519';
|
|
26
|
-
import { hexlify, hexZeroPad } from '@ethersproject/bytes';
|
|
27
|
-
import { getAddress } from '@ethersproject/address';
|
|
28
29
|
import { formatUnits as formatUnits$1 } from '@ethersproject/units';
|
|
29
30
|
import { keccak256 } from '@ethersproject/keccak256';
|
|
30
31
|
|
|
@@ -2895,6 +2896,8 @@ class KitError extends Error {
|
|
|
2895
2896
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
2896
2897
|
Blockchain["Codex"] = "Codex";
|
|
2897
2898
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
2899
|
+
Blockchain["Cronos"] = "Cronos";
|
|
2900
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2898
2901
|
Blockchain["Edge"] = "Edge";
|
|
2899
2902
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
2900
2903
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -2977,6 +2980,7 @@ var BridgeChain;
|
|
|
2977
2980
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
2978
2981
|
BridgeChain["Base"] = "Base";
|
|
2979
2982
|
BridgeChain["Codex"] = "Codex";
|
|
2983
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
2980
2984
|
BridgeChain["Edge"] = "Edge";
|
|
2981
2985
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
2982
2986
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -3001,6 +3005,7 @@ var BridgeChain;
|
|
|
3001
3005
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
3002
3006
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
3003
3007
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
3008
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
3004
3009
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
3005
3010
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
3006
3011
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -3523,7 +3528,10 @@ var EarnChain;
|
|
|
3523
3528
|
contracts: {
|
|
3524
3529
|
v1: {
|
|
3525
3530
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
3526
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
3531
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
3532
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
3533
|
+
// deposit into the GatewayWallet above.
|
|
3534
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
3527
3535
|
}
|
|
3528
3536
|
},
|
|
3529
3537
|
forwarderSupported: {
|
|
@@ -4057,6 +4065,96 @@ var EarnChain;
|
|
|
4057
4065
|
}
|
|
4058
4066
|
});
|
|
4059
4067
|
|
|
4068
|
+
/**
|
|
4069
|
+
* Cronos Mainnet chain definition
|
|
4070
|
+
* @remarks
|
|
4071
|
+
* This represents the official production network for the Cronos blockchain.
|
|
4072
|
+
* Cronos is an EVM-compatible blockchain.
|
|
4073
|
+
*/ const Cronos = defineChain({
|
|
4074
|
+
type: 'evm',
|
|
4075
|
+
chain: Blockchain.Cronos,
|
|
4076
|
+
name: 'Cronos',
|
|
4077
|
+
title: 'Cronos Mainnet',
|
|
4078
|
+
nativeCurrency: {
|
|
4079
|
+
name: 'Cronos',
|
|
4080
|
+
symbol: 'CRO',
|
|
4081
|
+
decimals: 18
|
|
4082
|
+
},
|
|
4083
|
+
chainId: 25,
|
|
4084
|
+
isTestnet: false,
|
|
4085
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
4086
|
+
rpcEndpoints: [
|
|
4087
|
+
'https://evm.cronos.org'
|
|
4088
|
+
],
|
|
4089
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
4090
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
4091
|
+
usdtAddress: null,
|
|
4092
|
+
cctp: {
|
|
4093
|
+
domain: 32,
|
|
4094
|
+
contracts: {
|
|
4095
|
+
v2: {
|
|
4096
|
+
type: 'split',
|
|
4097
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
4098
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
4099
|
+
confirmations: 1,
|
|
4100
|
+
fastConfirmations: 1
|
|
4101
|
+
}
|
|
4102
|
+
},
|
|
4103
|
+
forwarderSupported: {
|
|
4104
|
+
source: false,
|
|
4105
|
+
destination: false
|
|
4106
|
+
}
|
|
4107
|
+
},
|
|
4108
|
+
kitContracts: {
|
|
4109
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
4110
|
+
}
|
|
4111
|
+
});
|
|
4112
|
+
|
|
4113
|
+
/**
|
|
4114
|
+
* Cronos Testnet chain definition
|
|
4115
|
+
* @remarks
|
|
4116
|
+
* This represents the official test network for the Cronos blockchain.
|
|
4117
|
+
* Cronos is an EVM-compatible blockchain.
|
|
4118
|
+
*/ const CronosTestnet = defineChain({
|
|
4119
|
+
type: 'evm',
|
|
4120
|
+
chain: Blockchain.Cronos_Testnet,
|
|
4121
|
+
name: 'Cronos Testnet',
|
|
4122
|
+
title: 'Cronos Testnet',
|
|
4123
|
+
nativeCurrency: {
|
|
4124
|
+
name: 'CRO',
|
|
4125
|
+
symbol: 'tCRO',
|
|
4126
|
+
decimals: 18
|
|
4127
|
+
},
|
|
4128
|
+
chainId: 338,
|
|
4129
|
+
isTestnet: true,
|
|
4130
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
4131
|
+
rpcEndpoints: [
|
|
4132
|
+
'https://evm-t3.cronos.org'
|
|
4133
|
+
],
|
|
4134
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
4135
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
4136
|
+
usdtAddress: null,
|
|
4137
|
+
cctp: {
|
|
4138
|
+
domain: 32,
|
|
4139
|
+
contracts: {
|
|
4140
|
+
v2: {
|
|
4141
|
+
type: 'split',
|
|
4142
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
4143
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
4144
|
+
confirmations: 1,
|
|
4145
|
+
fastConfirmations: 1
|
|
4146
|
+
}
|
|
4147
|
+
},
|
|
4148
|
+
forwarderSupported: {
|
|
4149
|
+
source: false,
|
|
4150
|
+
destination: false
|
|
4151
|
+
}
|
|
4152
|
+
},
|
|
4153
|
+
kitContracts: {
|
|
4154
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
4155
|
+
}
|
|
4156
|
+
});
|
|
4157
|
+
|
|
4060
4158
|
/**
|
|
4061
4159
|
* Edge Mainnet chain definition
|
|
4062
4160
|
* @remarks
|
|
@@ -6408,6 +6506,8 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
6408
6506
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
6409
6507
|
Codex: Codex,
|
|
6410
6508
|
CodexTestnet: CodexTestnet,
|
|
6509
|
+
Cronos: Cronos,
|
|
6510
|
+
CronosTestnet: CronosTestnet,
|
|
6411
6511
|
Edge: Edge,
|
|
6412
6512
|
EdgeTestnet: EdgeTestnet,
|
|
6413
6513
|
Ethereum: Ethereum,
|
|
@@ -6499,7 +6599,10 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
6499
6599
|
minter: z.string({
|
|
6500
6600
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
6501
6601
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
6502
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
6602
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
6603
|
+
depositForHandler: z.string({
|
|
6604
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
6605
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
6503
6606
|
}).strict() // Reject any additional properties not defined in the schema
|
|
6504
6607
|
;
|
|
6505
6608
|
/**
|
|
@@ -8457,6 +8560,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8457
8560
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
8458
8561
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
8459
8562
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
8563
|
+
[Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
8460
8564
|
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
8461
8565
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
8462
8566
|
[Blockchain.Hedera]: '0.0.456858',
|
|
@@ -8490,6 +8594,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8490
8594
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
8491
8595
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
8492
8596
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
8597
|
+
[Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
8493
8598
|
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
8494
8599
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
8495
8600
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -8562,6 +8667,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8562
8667
|
// =========================================================================
|
|
8563
8668
|
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
8564
8669
|
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
8670
|
+
[Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
8565
8671
|
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
8566
8672
|
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
8567
8673
|
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
@@ -8570,6 +8676,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8570
8676
|
// =========================================================================
|
|
8571
8677
|
[Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
8572
8678
|
[Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
8679
|
+
[Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
8573
8680
|
[Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
8574
8681
|
}
|
|
8575
8682
|
};
|
|
@@ -9380,6 +9487,13 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9380
9487
|
return explorerUrl;
|
|
9381
9488
|
}
|
|
9382
9489
|
|
|
9490
|
+
/**
|
|
9491
|
+
* CCTP forwarding magic bytes prefix.
|
|
9492
|
+
*
|
|
9493
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
9494
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
9495
|
+
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
9496
|
+
|
|
9383
9497
|
/**
|
|
9384
9498
|
* Project an arbitrary payload onto the exact set of fields the telemetry
|
|
9385
9499
|
* endpoint accepts.
|
|
@@ -9756,7 +9870,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
9756
9870
|
}
|
|
9757
9871
|
|
|
9758
9872
|
var name$2 = "@circle-fin/bridge-kit";
|
|
9759
|
-
var version$2 = "1.
|
|
9873
|
+
var version$2 = "1.12.1";
|
|
9760
9874
|
var pkg$2 = {
|
|
9761
9875
|
name: name$2,
|
|
9762
9876
|
version: version$2};
|
|
@@ -10614,6 +10728,11 @@ var TransferSpeed;
|
|
|
10614
10728
|
clock: z.any().optional()
|
|
10615
10729
|
}).passthrough();
|
|
10616
10730
|
|
|
10731
|
+
/**
|
|
10732
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
10733
|
+
* hookData must start with.
|
|
10734
|
+
*/ Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
10735
|
+
|
|
10617
10736
|
/**
|
|
10618
10737
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
10619
10738
|
*
|
|
@@ -10646,7 +10765,7 @@ var TransferSpeed;
|
|
|
10646
10765
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
10647
10766
|
|
|
10648
10767
|
var name$1 = "@circle-fin/swap-kit";
|
|
10649
|
-
var version$1 = "1.
|
|
10768
|
+
var version$1 = "1.4.0";
|
|
10650
10769
|
var pkg$1 = {
|
|
10651
10770
|
name: name$1,
|
|
10652
10771
|
version: version$1};
|
|
@@ -10711,7 +10830,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
10711
10830
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
10712
10831
|
provider: z.string({
|
|
10713
10832
|
invalid_type_error: 'provider must be a string'
|
|
10714
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
10833
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
10834
|
+
batchTransactions: z.boolean({
|
|
10835
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
10836
|
+
}).optional()
|
|
10715
10837
|
});
|
|
10716
10838
|
/**
|
|
10717
10839
|
* Zod schema for adapter context.
|
|
@@ -11242,7 +11364,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11242
11364
|
/**
|
|
11243
11365
|
* Circle Stablecoin Service API Key.
|
|
11244
11366
|
* Must be a valid API key format.
|
|
11245
|
-
*/ apiKey: apiKeySchema
|
|
11367
|
+
*/ apiKey: apiKeySchema.optional()
|
|
11246
11368
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
11247
11369
|
/**
|
|
11248
11370
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -11300,7 +11422,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11300
11422
|
/**
|
|
11301
11423
|
* Circle Stablecoin Service API Key.
|
|
11302
11424
|
* Must be a valid API key format.
|
|
11303
|
-
*/ apiKey: apiKeySchema
|
|
11425
|
+
*/ apiKey: apiKeySchema.optional()
|
|
11304
11426
|
});
|
|
11305
11427
|
/**
|
|
11306
11428
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -11336,7 +11458,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11336
11458
|
toChain: z.string({
|
|
11337
11459
|
invalid_type_error: 'toChain must be a string'
|
|
11338
11460
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
11339
|
-
apiKey: apiKeySchema
|
|
11461
|
+
apiKey: apiKeySchema.optional()
|
|
11340
11462
|
});
|
|
11341
11463
|
/**
|
|
11342
11464
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -11345,13 +11467,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11345
11467
|
required_error: 'fee token is required',
|
|
11346
11468
|
invalid_type_error: 'fee token must be a string'
|
|
11347
11469
|
}).min(1, 'fee token must be a non-empty string'),
|
|
11348
|
-
amount: feeAmountSchema
|
|
11470
|
+
amount: feeAmountSchema,
|
|
11471
|
+
decimals: z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
11472
|
+
symbol: z.string({
|
|
11473
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
11474
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
11349
11475
|
});
|
|
11350
11476
|
/**
|
|
11351
11477
|
* Developer fee item schema with basis field.
|
|
11352
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
11353
|
-
token: z.string().min(1, 'fee token must be a non-empty string'),
|
|
11354
|
-
amount: feeAmountSchema,
|
|
11478
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
11355
11479
|
basis: z.enum([
|
|
11356
11480
|
'inputAmount',
|
|
11357
11481
|
'estimatedAmount'
|
|
@@ -11443,7 +11567,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11443
11567
|
addresses: z.array(z.string({
|
|
11444
11568
|
invalid_type_error: 'addresses entries must be strings'
|
|
11445
11569
|
}).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(),
|
|
11446
|
-
apiKey: apiKeySchema
|
|
11570
|
+
apiKey: apiKeySchema.optional()
|
|
11447
11571
|
});
|
|
11448
11572
|
/**
|
|
11449
11573
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -11621,7 +11745,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11621
11745
|
...DEFAULT_CONFIG,
|
|
11622
11746
|
headers: {
|
|
11623
11747
|
...DEFAULT_CONFIG.headers,
|
|
11624
|
-
|
|
11748
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11749
|
+
...apiKey !== undefined && {
|
|
11750
|
+
Authorization: `Bearer ${apiKey}`
|
|
11751
|
+
}
|
|
11625
11752
|
}
|
|
11626
11753
|
};
|
|
11627
11754
|
try {
|
|
@@ -11775,7 +11902,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11775
11902
|
...DEFAULT_CONFIG,
|
|
11776
11903
|
headers: {
|
|
11777
11904
|
...DEFAULT_CONFIG.headers,
|
|
11778
|
-
|
|
11905
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11906
|
+
...validatedParams.apiKey !== undefined && {
|
|
11907
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
11908
|
+
}
|
|
11779
11909
|
}
|
|
11780
11910
|
};
|
|
11781
11911
|
return pollApiGet(url, isGetQuoteResponse, effectiveConfig);
|
|
@@ -11830,7 +11960,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11830
11960
|
const validatedParams = {
|
|
11831
11961
|
txHash: result.data.txHash,
|
|
11832
11962
|
chain: result.data.chain,
|
|
11833
|
-
|
|
11963
|
+
...result.data.apiKey !== undefined && {
|
|
11964
|
+
apiKey: result.data.apiKey
|
|
11965
|
+
},
|
|
11834
11966
|
...result.data.toChain !== undefined && {
|
|
11835
11967
|
toChain: result.data.toChain
|
|
11836
11968
|
}
|
|
@@ -11840,7 +11972,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11840
11972
|
...DEFAULT_CONFIG,
|
|
11841
11973
|
headers: {
|
|
11842
11974
|
...DEFAULT_CONFIG.headers,
|
|
11843
|
-
|
|
11975
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
11976
|
+
...validatedParams.apiKey !== undefined && {
|
|
11977
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
11978
|
+
}
|
|
11844
11979
|
}
|
|
11845
11980
|
};
|
|
11846
11981
|
return pollApiGet(url, isGetSwapStatusResponse, effectiveConfig);
|
|
@@ -11929,7 +12064,9 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11929
12064
|
}
|
|
11930
12065
|
const validatedParams = {
|
|
11931
12066
|
chain: result.data.chain,
|
|
11932
|
-
|
|
12067
|
+
...result.data.apiKey !== undefined && {
|
|
12068
|
+
apiKey: result.data.apiKey
|
|
12069
|
+
},
|
|
11933
12070
|
...result.data.addresses !== undefined && {
|
|
11934
12071
|
addresses: result.data.addresses
|
|
11935
12072
|
}
|
|
@@ -11939,7 +12076,10 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
11939
12076
|
...DEFAULT_CONFIG,
|
|
11940
12077
|
headers: {
|
|
11941
12078
|
...DEFAULT_CONFIG.headers,
|
|
11942
|
-
|
|
12079
|
+
// Permissionless mode: no Authorization header when the kit key is absent.
|
|
12080
|
+
...validatedParams.apiKey !== undefined && {
|
|
12081
|
+
Authorization: `Bearer ${validatedParams.apiKey}`
|
|
12082
|
+
}
|
|
11943
12083
|
}
|
|
11944
12084
|
};
|
|
11945
12085
|
return pollApiGet(url, isGetTokenRatesResponse, effectiveConfig);
|
|
@@ -12749,6 +12889,47 @@ const S_HEX_LENGTH = 32 * HEX_CHARS_PER_BYTE$1 // 32 bytes for 's'
|
|
|
12749
12889
|
*/ function hasSignTypedData(adapter) {
|
|
12750
12890
|
return typeof adapter === 'object' && adapter !== null && 'signTypedData' in adapter && typeof adapter.signTypedData === 'function';
|
|
12751
12891
|
}
|
|
12892
|
+
/**
|
|
12893
|
+
* Type guard to check if an adapter can actually produce an EIP-712
|
|
12894
|
+
* typed-data signature.
|
|
12895
|
+
*
|
|
12896
|
+
* @remarks
|
|
12897
|
+
* Strengthens {@link hasSignTypedData}: having a `signTypedData` method
|
|
12898
|
+
* does not guarantee it can succeed. Adapters whose signer is delegated
|
|
12899
|
+
* (e.g. through a signing strategy backed by a smart contract account)
|
|
12900
|
+
* expose the method but reject typed-data payloads at runtime. Such
|
|
12901
|
+
* adapters report their real capability through an optional
|
|
12902
|
+
* `supportsSignTypedData()` method, which this guard consults when
|
|
12903
|
+
* present. Adapters without the capability method are assumed able to
|
|
12904
|
+
* sign, preserving the previous duck-typing behavior.
|
|
12905
|
+
*
|
|
12906
|
+
* @param adapter - The adapter to check
|
|
12907
|
+
* @returns True if calling `signTypedData` can be expected to succeed
|
|
12908
|
+
*
|
|
12909
|
+
* @example
|
|
12910
|
+
* ```typescript
|
|
12911
|
+
* import { canSignTypedData } from '@core/adapter-evm'
|
|
12912
|
+
*
|
|
12913
|
+
* if (canSignTypedData(adapter)) {
|
|
12914
|
+
* const signature = await adapter.signTypedData(typedData, context)
|
|
12915
|
+
* } else {
|
|
12916
|
+
* // take an on-chain approval path instead of a permit signature
|
|
12917
|
+
* }
|
|
12918
|
+
* ```
|
|
12919
|
+
*/ function canSignTypedData(adapter) {
|
|
12920
|
+
if (!hasSignTypedData(adapter)) {
|
|
12921
|
+
return false;
|
|
12922
|
+
}
|
|
12923
|
+
if (typeof adapter.supportsSignTypedData === 'function') {
|
|
12924
|
+
// The value is `boolean` per the interface, but a plain-JS adapter may
|
|
12925
|
+
// return anything; treat it as untrusted and coerce to a strict
|
|
12926
|
+
// boolean. Comparing an `unknown` (not a `boolean`) also keeps the
|
|
12927
|
+
// lint autofix from stripping this as a redundant `=== true`.
|
|
12928
|
+
const supported = adapter.supportsSignTypedData();
|
|
12929
|
+
return supported === true;
|
|
12930
|
+
}
|
|
12931
|
+
return true;
|
|
12932
|
+
}
|
|
12752
12933
|
|
|
12753
12934
|
/**
|
|
12754
12935
|
* Build EIP-2612 typed data for permit signing.
|
|
@@ -13171,10 +13352,13 @@ enc.encode('used_transfer_spec_hash');
|
|
|
13171
13352
|
* at usage time rather than construction time.
|
|
13172
13353
|
*
|
|
13173
13354
|
* Validates:
|
|
13174
|
-
* - Kit key
|
|
13355
|
+
* - Kit key matches the required format (KIT_KEY:id:secret) when provided.
|
|
13356
|
+
* An absent or empty kit key is permitted (permissionless mode) — the swap
|
|
13357
|
+
* service now treats the key as optional.
|
|
13175
13358
|
*
|
|
13176
|
-
* @param kitKey - The inline kit key from the swap operation config
|
|
13177
|
-
* @throws KitError with VALIDATION_FAILED if kit key is
|
|
13359
|
+
* @param kitKey - The inline kit key from the swap operation config (optional)
|
|
13360
|
+
* @throws KitError with VALIDATION_FAILED if a kit key is provided but does not
|
|
13361
|
+
* match the KIT_KEY:<keyId>:<keySecret> format
|
|
13178
13362
|
*
|
|
13179
13363
|
* @example
|
|
13180
13364
|
* ```typescript
|
|
@@ -13186,9 +13370,11 @@ enc.encode('used_transfer_spec_hash');
|
|
|
13186
13370
|
* assertKitKey(kitKey)
|
|
13187
13371
|
* ```
|
|
13188
13372
|
*/ function assertKitKey(kitKey) {
|
|
13189
|
-
//
|
|
13373
|
+
// Permissionless mode: the swap service treats the kit key as optional, so an
|
|
13374
|
+
// absent (or empty) key is valid. Only validate the format when a key is
|
|
13375
|
+
// actually provided.
|
|
13190
13376
|
if (!kitKey) {
|
|
13191
|
-
|
|
13377
|
+
return;
|
|
13192
13378
|
}
|
|
13193
13379
|
const apiKeyResult = apiKeySchema.safeParse(kitKey);
|
|
13194
13380
|
if (!apiKeyResult.success) {
|
|
@@ -13485,8 +13671,8 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
13485
13671
|
validateResolvedAddress(resolvedTokenInAddress, chain);
|
|
13486
13672
|
validateResolvedAddress(resolvedTokenOutAddress, destinationChain);
|
|
13487
13673
|
validateResolvedAddress(to, destinationChain);
|
|
13488
|
-
const kitKey = config?.kitKey
|
|
13489
|
-
//
|
|
13674
|
+
const kitKey = config?.kitKey;
|
|
13675
|
+
// Validate the kit key format when one is provided (permissionless otherwise).
|
|
13490
13676
|
assertKitKey(kitKey);
|
|
13491
13677
|
// Validate custom fee configuration if present
|
|
13492
13678
|
const customFee = config?.customFee;
|
|
@@ -13531,7 +13717,10 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
13531
13717
|
}
|
|
13532
13718
|
}
|
|
13533
13719
|
},
|
|
13534
|
-
apiKey
|
|
13720
|
+
// Map kitKey → apiKey for the service client; omitted in permissionless mode.
|
|
13721
|
+
...kitKey ? {
|
|
13722
|
+
apiKey: kitKey
|
|
13723
|
+
} : {}
|
|
13535
13724
|
};
|
|
13536
13725
|
}
|
|
13537
13726
|
|
|
@@ -14185,6 +14374,37 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
14185
14374
|
}
|
|
14186
14375
|
}
|
|
14187
14376
|
|
|
14377
|
+
/**
|
|
14378
|
+
* Determine whether an adapter can produce an EIP-2612 permit signature.
|
|
14379
|
+
*
|
|
14380
|
+
* @remarks
|
|
14381
|
+
* A gasless permit needs two adapter capabilities: fetching the token's
|
|
14382
|
+
* EIP-2612 nonce and producing an EIP-712 typed-data signature. The
|
|
14383
|
+
* typed-data check uses {@link canSignTypedData} rather than a bare
|
|
14384
|
+
* `hasSignTypedData` guard so that an adapter routed through a signing
|
|
14385
|
+
* strategy that cannot produce typed-data signatures — one whose manifest
|
|
14386
|
+
* omits `evm-typed-data`, surfaced through an optional `supportsSignTypedData()`
|
|
14387
|
+
* — is correctly excluded. Such an adapter falls back to an on-chain approval
|
|
14388
|
+
* (batched into a single submission when it supports atomic execution) instead
|
|
14389
|
+
* of attempting a permit its strategy would reject.
|
|
14390
|
+
*
|
|
14391
|
+
* @param adapter - The source adapter to inspect.
|
|
14392
|
+
* @returns `true` when the adapter can both fetch a nonce and sign typed data.
|
|
14393
|
+
*
|
|
14394
|
+
* @example
|
|
14395
|
+
* ```typescript
|
|
14396
|
+
* import { adapterSupportsPermit } from './utils'
|
|
14397
|
+
*
|
|
14398
|
+
* if (adapterSupportsPermit(adapter)) {
|
|
14399
|
+
* // gasless permit path — fold the approval into the swap transaction
|
|
14400
|
+
* } else {
|
|
14401
|
+
* // on-chain approval path (batched when supportsAtomicBatch is true)
|
|
14402
|
+
* }
|
|
14403
|
+
* ```
|
|
14404
|
+
*/ function adapterSupportsPermit(adapter) {
|
|
14405
|
+
return hasEIP2612NonceFetching(adapter) && canSignTypedData(adapter);
|
|
14406
|
+
}
|
|
14407
|
+
|
|
14188
14408
|
/**
|
|
14189
14409
|
* Generate EIP-2612 permit signature for token approval.
|
|
14190
14410
|
*
|
|
@@ -14320,8 +14540,7 @@ function resolveFeePayoutChain(tokenIn, tokenOut, sourceChain, destinationChain)
|
|
|
14320
14540
|
}
|
|
14321
14541
|
// Skip permit generation if the adapter lacks the required capabilities.
|
|
14322
14542
|
// handleEvmTokenApproval will have already sent an on-chain approval in this case.
|
|
14323
|
-
|
|
14324
|
-
if (!adapterSupportsPermit) {
|
|
14543
|
+
if (!adapterSupportsPermit(adapter)) {
|
|
14325
14544
|
return [
|
|
14326
14545
|
createFallbackTokenInput(tokenInAddress, inputAmount)
|
|
14327
14546
|
];
|
|
@@ -14880,6 +15099,65 @@ const TOKEN_REGISTRY$2 = createTokenRegistry();
|
|
|
14880
15099
|
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.`;
|
|
14881
15100
|
}
|
|
14882
15101
|
|
|
15102
|
+
/**
|
|
15103
|
+
* Determine which chain a fee token should be resolved and formatted against.
|
|
15104
|
+
*
|
|
15105
|
+
* @remarks
|
|
15106
|
+
* Fees returned by the service may be denominated in either the input token
|
|
15107
|
+
* (on the source chain) or the output token (on the destination chain). A
|
|
15108
|
+
* contract address only resolves on the chain it belongs to, so formatting a
|
|
15109
|
+
* destination-denominated fee against the source chain causes
|
|
15110
|
+
* {@link resolveTokenSymbol} to miss and the amount to be returned as raw base
|
|
15111
|
+
* units (e.g. a cross-chain swap charging a fee in the destination output
|
|
15112
|
+
* token — an EURC-on-Base address shows `'13202'` instead of `'0.013202'` when
|
|
15113
|
+
* resolved against the source chain). This is the fallback for fee items that
|
|
15114
|
+
* are not self-described with their own `decimals`/`chain`.
|
|
15115
|
+
*
|
|
15116
|
+
* Prefer the source chain (covers same-chain swaps and input-denominated
|
|
15117
|
+
* fees), then fall back to the destination chain when the token only resolves
|
|
15118
|
+
* there. When neither chain recognises the token, default to the source chain
|
|
15119
|
+
* so existing on-chain decimal lookups via the source adapter still apply.
|
|
15120
|
+
*
|
|
15121
|
+
* Symbol tokens (`'USDC'`, `'NATIVE'`) resolve on either chain, so the
|
|
15122
|
+
* source-first preference keeps them on the source chain. That is correct for
|
|
15123
|
+
* registry stablecoins, and for `'NATIVE'` only when both chains share native
|
|
15124
|
+
* decimals (EVM↔EVM, 18). It does NOT honor per-chain native decimals: a
|
|
15125
|
+
* `'NATIVE'`-denominated fee on a Solana↔EVM swap (9 vs 18) would be
|
|
15126
|
+
* mis-scaled. This is latent — providers emit the address form, and
|
|
15127
|
+
* self-describing fee items carry their own `decimals` and never reach this
|
|
15128
|
+
* helper — so the gap only opens for a future `'NATIVE'` fee that arrives
|
|
15129
|
+
* without `decimals` on a cross-native-decimal route.
|
|
15130
|
+
*
|
|
15131
|
+
* @param token - The fee token identifier — a symbol (`'USDC'`) or contract address.
|
|
15132
|
+
* @param sourceChain - The chain the swap originates from.
|
|
15133
|
+
* @param destinationChain - The chain the swap settles on (equals `sourceChain` for same-chain swaps).
|
|
15134
|
+
* @returns The chain definition the fee token should be resolved against.
|
|
15135
|
+
*
|
|
15136
|
+
* @example
|
|
15137
|
+
* ```typescript
|
|
15138
|
+
* import { resolveFeeChain } from './resolveFeeChain'
|
|
15139
|
+
* import { Ethereum, Base } from '@core/chains'
|
|
15140
|
+
*
|
|
15141
|
+
* // Cross-chain swap fee charged in the destination (output) token
|
|
15142
|
+
* resolveFeeChain('0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42', Ethereum, Base)
|
|
15143
|
+
* // => Base (EURC resolves on Base, not Ethereum)
|
|
15144
|
+
*
|
|
15145
|
+
* // Symbol or source-token fees stay on the source chain
|
|
15146
|
+
* resolveFeeChain('USDC', Ethereum, Base) // => Ethereum
|
|
15147
|
+
* ```
|
|
15148
|
+
*/ function resolveFeeChain(token, sourceChain, destinationChain) {
|
|
15149
|
+
if (sourceChain.chain === destinationChain.chain) {
|
|
15150
|
+
return sourceChain;
|
|
15151
|
+
}
|
|
15152
|
+
if (resolveTokenSymbol(token, sourceChain) !== null) {
|
|
15153
|
+
return sourceChain;
|
|
15154
|
+
}
|
|
15155
|
+
if (resolveTokenSymbol(token, destinationChain) !== null) {
|
|
15156
|
+
return destinationChain;
|
|
15157
|
+
}
|
|
15158
|
+
return sourceChain;
|
|
15159
|
+
}
|
|
15160
|
+
|
|
14883
15161
|
const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
14884
15162
|
/**
|
|
14885
15163
|
* Format a raw base-unit amount into a human-readable decimal string.
|
|
@@ -14970,6 +15248,186 @@ const TOKEN_REGISTRY$1 = createTokenRegistry();
|
|
|
14970
15248
|
}
|
|
14971
15249
|
}
|
|
14972
15250
|
|
|
15251
|
+
/**
|
|
15252
|
+
* Runtime guard for {@link BatchCapableSwapAdapter}.
|
|
15253
|
+
*
|
|
15254
|
+
* @param adapter - The adapter to inspect.
|
|
15255
|
+
* @returns `true` when the adapter exposes both batch methods.
|
|
15256
|
+
*
|
|
15257
|
+
* @example
|
|
15258
|
+
* ```typescript
|
|
15259
|
+
* if (isBatchCapableSwapAdapter(adapter)) {
|
|
15260
|
+
* // adapter.supportsAtomicBatch / adapter.batchExecute are available
|
|
15261
|
+
* }
|
|
15262
|
+
* ```
|
|
15263
|
+
*/ function isBatchCapableSwapAdapter(adapter) {
|
|
15264
|
+
return typeof adapter === 'object' && adapter !== null && typeof adapter.supportsAtomicBatch === 'function' && typeof adapter.batchExecute === 'function';
|
|
15265
|
+
}
|
|
15266
|
+
/**
|
|
15267
|
+
* Decide whether the EVM swap should take the batched approve-and-swap path.
|
|
15268
|
+
*
|
|
15269
|
+
* @remarks
|
|
15270
|
+
* Batching only helps when an on-chain approval would otherwise be required, so
|
|
15271
|
+
* it is skipped for native tokens (no approval) and for the gasless permit path
|
|
15272
|
+
* (already a single transaction). USDT is skipped because its reset-to-zero
|
|
15273
|
+
* allowance flow cannot be expressed as a fixed approve+swap pair. When those
|
|
15274
|
+
* gates pass, the adapter's actual atomic-batch capability is queried; any
|
|
15275
|
+
* failure resolves to `false` so the swap falls back to the sequential path.
|
|
15276
|
+
*
|
|
15277
|
+
* @param args - The decision inputs.
|
|
15278
|
+
* @param args.adapter - The source adapter.
|
|
15279
|
+
* @param args.chain - The source chain definition.
|
|
15280
|
+
* @param args.tokenInAddress - The resolved input-token address.
|
|
15281
|
+
* @param args.allowanceStrategy - Optional allowance strategy override.
|
|
15282
|
+
* @param args.batchTransactions - Optional explicit opt-out (`false` disables).
|
|
15283
|
+
* @returns `true` when the batched approve-and-swap path should be used.
|
|
15284
|
+
*
|
|
15285
|
+
* @example
|
|
15286
|
+
* ```typescript
|
|
15287
|
+
* const useBatched = await shouldUseBatchedSwap({
|
|
15288
|
+
* adapter,
|
|
15289
|
+
* chain,
|
|
15290
|
+
* tokenInAddress: '0xA0b8...',
|
|
15291
|
+
* allowanceStrategy: config?.allowanceStrategy,
|
|
15292
|
+
* batchTransactions: config?.batchTransactions,
|
|
15293
|
+
* })
|
|
15294
|
+
* ```
|
|
15295
|
+
*/ async function shouldUseBatchedSwap({ adapter, chain, tokenInAddress, allowanceStrategy, batchTransactions }) {
|
|
15296
|
+
// Explicit opt-out.
|
|
15297
|
+
if (batchTransactions === false) {
|
|
15298
|
+
return false;
|
|
15299
|
+
}
|
|
15300
|
+
// Batching is an EVM capability (EIP-5792 or a signing strategy).
|
|
15301
|
+
if (chain.type !== 'evm') {
|
|
15302
|
+
return false;
|
|
15303
|
+
}
|
|
15304
|
+
// Native tokens need no approval — the swap is already a single transaction.
|
|
15305
|
+
if (isNativeEvmAddress(tokenInAddress)) {
|
|
15306
|
+
return false;
|
|
15307
|
+
}
|
|
15308
|
+
// A gasless permit folds the approval into the swap transaction, so there is
|
|
15309
|
+
// nothing to batch. Mirrors the permit gate in handleEvmTokenApproval.
|
|
15310
|
+
const canUsePermit = allowanceStrategy !== 'approve' && supportsEIP2612(tokenInAddress, chain) && adapterSupportsPermit(adapter);
|
|
15311
|
+
if (canUsePermit) {
|
|
15312
|
+
return false;
|
|
15313
|
+
}
|
|
15314
|
+
// USDT's reset-to-zero allowance dance cannot be expressed as a fixed
|
|
15315
|
+
// approve+swap pair; leave it on the sequential path.
|
|
15316
|
+
const usdt = chain.usdtAddress?.toLowerCase();
|
|
15317
|
+
if (usdt !== undefined && tokenInAddress.toLowerCase() === usdt) {
|
|
15318
|
+
return false;
|
|
15319
|
+
}
|
|
15320
|
+
if (!isBatchCapableSwapAdapter(adapter)) {
|
|
15321
|
+
return false;
|
|
15322
|
+
}
|
|
15323
|
+
try {
|
|
15324
|
+
return await adapter.supportsAtomicBatch(chain);
|
|
15325
|
+
} catch {
|
|
15326
|
+
return false;
|
|
15327
|
+
}
|
|
15328
|
+
}
|
|
15329
|
+
/**
|
|
15330
|
+
* Execute the approval and swap as a single atomic batch.
|
|
15331
|
+
*
|
|
15332
|
+
* @remarks
|
|
15333
|
+
* Extracts the raw call data from both prepared requests, submits them as one
|
|
15334
|
+
* batch via `adapter.batchExecute`, and maps the swap receipt back to a
|
|
15335
|
+
* transaction hash. The `fromAddress` is threaded for adapters routed through a
|
|
15336
|
+
* signing strategy (which have no wallet account to read the sender from); the
|
|
15337
|
+
* wallet-client path ignores it.
|
|
15338
|
+
*
|
|
15339
|
+
* Following the batch contract, `batchExecute` never throws once the batch is
|
|
15340
|
+
* submitted — a missing or failed swap receipt is surfaced here as a thrown
|
|
15341
|
+
* {@link KitError} (FATAL) so the caller does not resubmit an already-broadcast
|
|
15342
|
+
* batch and double-swap.
|
|
15343
|
+
*
|
|
15344
|
+
* @param args - The execution inputs.
|
|
15345
|
+
* @param args.adapter - The batch-capable source adapter.
|
|
15346
|
+
* @param args.chain - The EVM chain to execute on.
|
|
15347
|
+
* @param args.approveRequest - The prepared ERC-20 approval request.
|
|
15348
|
+
* @param args.swapRequest - The prepared swap request (pre-approval / NONE permit).
|
|
15349
|
+
* @param args.fromAddress - The address authorizing the batch.
|
|
15350
|
+
* @returns The swap transaction hash and the executed approval + swap records.
|
|
15351
|
+
* @throws {@link KitError} when the prepared requests cannot yield call data.
|
|
15352
|
+
* @throws {@link KitError} when the batch does not confirm or the swap reverts.
|
|
15353
|
+
*
|
|
15354
|
+
* @example
|
|
15355
|
+
* ```typescript
|
|
15356
|
+
* const { swapTxHash, executedTransactions } = await executeBatchedApproveAndSwap({
|
|
15357
|
+
* adapter,
|
|
15358
|
+
* chain,
|
|
15359
|
+
* approveRequest,
|
|
15360
|
+
* swapRequest,
|
|
15361
|
+
* fromAddress: '0x742d...',
|
|
15362
|
+
* })
|
|
15363
|
+
* ```
|
|
15364
|
+
*/ async function executeBatchedApproveAndSwap({ adapter, chain, approveRequest, swapRequest, fromAddress }) {
|
|
15365
|
+
if (approveRequest.type !== 'evm' || swapRequest.type !== 'evm' || !approveRequest.getCallData || !swapRequest.getCallData) {
|
|
15366
|
+
throw new KitError({
|
|
15367
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
15368
|
+
recoverability: 'FATAL',
|
|
15369
|
+
message: 'Batched swap requires EVM prepared requests with getCallData() support.'
|
|
15370
|
+
});
|
|
15371
|
+
}
|
|
15372
|
+
const approveCallData = approveRequest.getCallData();
|
|
15373
|
+
const swapCallData = swapRequest.getCallData();
|
|
15374
|
+
const batchResult = await adapter.batchExecute([
|
|
15375
|
+
approveCallData,
|
|
15376
|
+
swapCallData
|
|
15377
|
+
], chain, {
|
|
15378
|
+
fromAddress
|
|
15379
|
+
});
|
|
15380
|
+
const swapReceipt = batchResult.receipts[1];
|
|
15381
|
+
// A missing swap receipt means the batch never confirmed (polling timed out
|
|
15382
|
+
// or the wallet returned fewer receipts than calls). Re-throw the underlying
|
|
15383
|
+
// error when present (already FATAL); otherwise surface a FATAL timeout so the
|
|
15384
|
+
// caller checks the batch status rather than resubmitting.
|
|
15385
|
+
if (swapReceipt === undefined || swapReceipt.txHash === '') {
|
|
15386
|
+
if (isKitError(batchResult.error)) {
|
|
15387
|
+
throw batchResult.error;
|
|
15388
|
+
}
|
|
15389
|
+
throw new KitError({
|
|
15390
|
+
...NetworkError.TIMEOUT,
|
|
15391
|
+
recoverability: 'FATAL',
|
|
15392
|
+
message: `Batched swap did not confirm on-chain (batchId: ${batchResult.batchId}). ` + 'The batch was already submitted — check its status before retrying.',
|
|
15393
|
+
// Preserve the underlying confirmation failure when it isn't a KitError —
|
|
15394
|
+
// the signing-strategy path returns a raw viem error (e.g. a dropped or
|
|
15395
|
+
// replaced tx) — so the root cause survives behind the generic timeout.
|
|
15396
|
+
cause: {
|
|
15397
|
+
trace: {
|
|
15398
|
+
batchId: batchResult.batchId,
|
|
15399
|
+
...batchResult.error != null && {
|
|
15400
|
+
error: batchResult.error
|
|
15401
|
+
}
|
|
15402
|
+
}
|
|
15403
|
+
}
|
|
15404
|
+
});
|
|
15405
|
+
}
|
|
15406
|
+
if (swapReceipt.status !== 'success') {
|
|
15407
|
+
throw createTransactionRevertedError(chain.name, 'Batched swap transaction reverted on-chain', undefined, swapReceipt.txHash, buildExplorerUrl(chain, swapReceipt.txHash));
|
|
15408
|
+
}
|
|
15409
|
+
const executedTransactions = [];
|
|
15410
|
+
const approveReceipt = batchResult.receipts[0];
|
|
15411
|
+
// An atomic batch is a single on-chain transaction, so the approve and swap
|
|
15412
|
+
// receipts share one hash. Only surface a distinct approval record when it is
|
|
15413
|
+
// genuinely a separate transaction; otherwise the lone swap record represents
|
|
15414
|
+
// the batch, avoiding a phantom duplicate tx in executedTransactions.
|
|
15415
|
+
if (approveReceipt !== undefined && approveReceipt.txHash !== '' && approveReceipt.txHash !== swapReceipt.txHash) {
|
|
15416
|
+
executedTransactions.push({
|
|
15417
|
+
type: 'approval',
|
|
15418
|
+
txHash: approveReceipt.txHash
|
|
15419
|
+
});
|
|
15420
|
+
}
|
|
15421
|
+
executedTransactions.push({
|
|
15422
|
+
type: 'swap',
|
|
15423
|
+
txHash: swapReceipt.txHash
|
|
15424
|
+
});
|
|
15425
|
+
return {
|
|
15426
|
+
swapTxHash: swapReceipt.txHash,
|
|
15427
|
+
executedTransactions
|
|
15428
|
+
};
|
|
15429
|
+
}
|
|
15430
|
+
|
|
14973
15431
|
/**
|
|
14974
15432
|
* Safety multiplier applied to locally estimated gas for EVM swap execution.
|
|
14975
15433
|
* Derived from refund cap (max 1/5 of total gas used) plus an extra 0.1 margin,
|
|
@@ -15096,7 +15554,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15096
15554
|
const statusResult = await getSwapStatus$1({
|
|
15097
15555
|
txHash,
|
|
15098
15556
|
chain: chain.chain,
|
|
15099
|
-
apiKey
|
|
15557
|
+
...apiKey !== undefined && {
|
|
15558
|
+
apiKey
|
|
15559
|
+
}
|
|
15100
15560
|
});
|
|
15101
15561
|
if (statusResult.status === 'DONE' && statusResult.amountOut !== undefined) {
|
|
15102
15562
|
return {
|
|
@@ -15687,8 +16147,7 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15687
16147
|
// Note: tokenInAddress from executionCtx is already resolved (handles NATIVE alias, ETH, etc.)
|
|
15688
16148
|
const isNativeToken = isNativeEvmAddress(executionCtx.tokenInAddress);
|
|
15689
16149
|
const tokenSupportsPermit = supportsEIP2612(executionCtx.tokenInAddress, chain);
|
|
15690
|
-
const
|
|
15691
|
-
const canUsePermitFlow = tokenSupportsPermit && adapterSupportsPermit && allowanceStrategy !== 'approve';
|
|
16150
|
+
const canUsePermitFlow = tokenSupportsPermit && adapterSupportsPermit(adapter) && allowanceStrategy !== 'approve';
|
|
15692
16151
|
const needsApproval = !isNativeToken && !canUsePermitFlow;
|
|
15693
16152
|
if (!needsApproval) {
|
|
15694
16153
|
return;
|
|
@@ -15967,34 +16426,55 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
15967
16426
|
const serviceResponse = await createSwap(serviceParams);
|
|
15968
16427
|
// Track executed transactions
|
|
15969
16428
|
const executedTransactions = [];
|
|
15970
|
-
// Prepare swap action based on chain type
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
|
|
15977
|
-
|
|
15978
|
-
|
|
15979
|
-
|
|
15980
|
-
|
|
15981
|
-
|
|
15982
|
-
}
|
|
16429
|
+
// Prepare swap action(s) based on chain type and batch capability.
|
|
16430
|
+
// Returns either a single prepared action (Solana / sequential EVM) or a
|
|
16431
|
+
// batched approve+swap plan (EVM atomic-batch path).
|
|
16432
|
+
const { preparedAction, batchedSwapPlan } = await this.prepareSwapRequests({
|
|
16433
|
+
adapter,
|
|
16434
|
+
chain,
|
|
16435
|
+
serviceResponse,
|
|
16436
|
+
resolvedContext,
|
|
16437
|
+
executionCtx,
|
|
16438
|
+
config,
|
|
16439
|
+
executedTransactions
|
|
16440
|
+
});
|
|
15983
16441
|
// Execute swap transaction via adapter
|
|
15984
16442
|
// For EVM chains, use gas limit from proxy service API
|
|
15985
16443
|
let txHash;
|
|
15986
16444
|
const evmGasLimit = 'gasLimit' in serviceResponse.transaction ? serviceResponse.transaction.gasLimit : undefined;
|
|
15987
16445
|
try {
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
|
|
15996
|
-
|
|
15997
|
-
|
|
16446
|
+
if (batchedSwapPlan) {
|
|
16447
|
+
// Approve + swap submitted as one atomic batch. batchExecute confirms
|
|
16448
|
+
// the swap internally, so no separate waitForTransaction is needed.
|
|
16449
|
+
const batched = await executeBatchedApproveAndSwap({
|
|
16450
|
+
adapter: adapter,
|
|
16451
|
+
chain: chain,
|
|
16452
|
+
approveRequest: batchedSwapPlan.approveRequest,
|
|
16453
|
+
swapRequest: batchedSwapPlan.swapRequest,
|
|
16454
|
+
fromAddress: executionCtx.fromAddress
|
|
16455
|
+
});
|
|
16456
|
+
txHash = batched.swapTxHash;
|
|
16457
|
+
executedTransactions.push(...batched.executedTransactions);
|
|
16458
|
+
} else if (preparedAction) {
|
|
16459
|
+
txHash = await this.executeSwapTransaction(preparedAction, evmGasLimit);
|
|
16460
|
+
executedTransactions.push({
|
|
16461
|
+
type: 'swap',
|
|
16462
|
+
txHash
|
|
16463
|
+
});
|
|
16464
|
+
// Wait for transaction confirmation and verify success
|
|
16465
|
+
const txReceipt = await adapter.waitForTransaction(txHash, undefined, chain);
|
|
16466
|
+
if (txReceipt.status === 'reverted') {
|
|
16467
|
+
const explorerUrl = buildExplorerUrl(chain, txHash);
|
|
16468
|
+
throw createTransactionRevertedError(chain.name, 'Swap transaction reverted on-chain', undefined, txHash, explorerUrl);
|
|
16469
|
+
}
|
|
16470
|
+
} else {
|
|
16471
|
+
// Unreachable: the preparation step always yields either a batched plan
|
|
16472
|
+
// or a prepared action.
|
|
16473
|
+
throw new KitError({
|
|
16474
|
+
...InputError.UNSUPPORTED_ACTION,
|
|
16475
|
+
recoverability: 'FATAL',
|
|
16476
|
+
message: 'No swap execution path was prepared.'
|
|
16477
|
+
});
|
|
15998
16478
|
}
|
|
15999
16479
|
} catch (err) {
|
|
16000
16480
|
handleSwapExecutionError(err, txHash, chain);
|
|
@@ -16013,7 +16493,9 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16013
16493
|
isCrossChainSwap,
|
|
16014
16494
|
txHash,
|
|
16015
16495
|
chain,
|
|
16016
|
-
|
|
16496
|
+
...serviceParams.apiKey !== undefined && {
|
|
16497
|
+
apiKey: serviceParams.apiKey
|
|
16498
|
+
}
|
|
16017
16499
|
});
|
|
16018
16500
|
// Build and return SwapResult
|
|
16019
16501
|
return {
|
|
@@ -16038,6 +16520,79 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16038
16520
|
};
|
|
16039
16521
|
}
|
|
16040
16522
|
/**
|
|
16523
|
+
* Prepare the swap execution request(s) for the source wallet's chain.
|
|
16524
|
+
*
|
|
16525
|
+
* Produces either a single {@link PreparedChainRequest} (Solana, or the
|
|
16526
|
+
* sequential EVM approve-then-swap path) or a `batchedSwapPlan` (the EVM
|
|
16527
|
+
* atomic approve+swap path chosen when the adapter supports EIP-5792 atomic
|
|
16528
|
+
* batching). The caller executes whichever field is populated. Any on-chain
|
|
16529
|
+
* approval sent on the sequential path is appended to `executedTransactions`.
|
|
16530
|
+
*
|
|
16531
|
+
* @typeParam TFromAdapterCapabilities - Source-adapter capability set.
|
|
16532
|
+
* @param args - Inputs derived from the validated swap request.
|
|
16533
|
+
* @param args.adapter - Source-chain wallet adapter.
|
|
16534
|
+
* @param args.chain - Source chain definition.
|
|
16535
|
+
* @param args.serviceResponse - Validated createSwap response.
|
|
16536
|
+
* @param args.resolvedContext - Resolved operation context.
|
|
16537
|
+
* @param args.executionCtx - Minimal on-chain execution context.
|
|
16538
|
+
* @param args.config - Optional swap configuration (allowance/batch flags).
|
|
16539
|
+
* @param args.executedTransactions - Array appended with any sent approval.
|
|
16540
|
+
* @returns The prepared action or the batched approve+swap plan.
|
|
16541
|
+
* @throws KitError when the EVM atomic-batch path is selected but the chain
|
|
16542
|
+
* has no configured adapter contract.
|
|
16543
|
+
*/ async prepareSwapRequests(args) {
|
|
16544
|
+
const { adapter, chain, serviceResponse, resolvedContext, executionCtx, config, executedTransactions } = args;
|
|
16545
|
+
if (chain.type === 'solana') {
|
|
16546
|
+
// Solana: No approval needed, directly prepare swap action
|
|
16547
|
+
return {
|
|
16548
|
+
preparedAction: await prepareSolanaSwapAction(adapter, serviceResponse, resolvedContext)
|
|
16549
|
+
};
|
|
16550
|
+
}
|
|
16551
|
+
const useBatch = await shouldUseBatchedSwap({
|
|
16552
|
+
adapter,
|
|
16553
|
+
chain,
|
|
16554
|
+
tokenInAddress: executionCtx.tokenInAddress,
|
|
16555
|
+
allowanceStrategy: config?.allowanceStrategy,
|
|
16556
|
+
batchTransactions: config?.batchTransactions
|
|
16557
|
+
});
|
|
16558
|
+
if (useBatch) {
|
|
16559
|
+
// EVM chains: fuse the ERC-20 approval and the swap into a single atomic
|
|
16560
|
+
// batch (one signing challenge for smart-contract wallets). Force the
|
|
16561
|
+
// swap onto the pre-approval (PermitType.NONE) path since the approval
|
|
16562
|
+
// rides in the same batch.
|
|
16563
|
+
const adapterContractAddress = chain.kitContracts?.adapter;
|
|
16564
|
+
if (!adapterContractAddress) {
|
|
16565
|
+
throw new KitError({
|
|
16566
|
+
...InputError.VALIDATION_FAILED,
|
|
16567
|
+
recoverability: 'FATAL',
|
|
16568
|
+
message: `Adapter contract not configured for chain ${chain.name}. Swap operations require an adapter contract.`,
|
|
16569
|
+
cause: {
|
|
16570
|
+
trace: {
|
|
16571
|
+
chain: chain.name
|
|
16572
|
+
}
|
|
16573
|
+
}
|
|
16574
|
+
});
|
|
16575
|
+
}
|
|
16576
|
+
const [approveRequest, swapRequest] = await Promise.all([
|
|
16577
|
+
this.approve(adapter, executionCtx.amount, executionCtx.tokenInAddress, adapterContractAddress, resolvedContext),
|
|
16578
|
+
prepareEvmSwapAction(adapter, serviceResponse, resolvedContext, 'approve')
|
|
16579
|
+
]);
|
|
16580
|
+
return {
|
|
16581
|
+
batchedSwapPlan: {
|
|
16582
|
+
approveRequest,
|
|
16583
|
+
swapRequest
|
|
16584
|
+
}
|
|
16585
|
+
};
|
|
16586
|
+
}
|
|
16587
|
+
// EVM chains: Handle token approval if needed, then prepare the swap.
|
|
16588
|
+
// prepareEvmSwapAction handles EIP-2612 permit generation; the adapter
|
|
16589
|
+
// contract address is read from chain.kitContracts.adapter.
|
|
16590
|
+
await this.handleEvmTokenApproval(adapter, chain, executionCtx, resolvedContext, executedTransactions, config?.allowanceStrategy);
|
|
16591
|
+
return {
|
|
16592
|
+
preparedAction: await prepareEvmSwapAction(adapter, serviceResponse, resolvedContext, config?.allowanceStrategy)
|
|
16593
|
+
};
|
|
16594
|
+
}
|
|
16595
|
+
/**
|
|
16041
16596
|
* Executes a swap transaction with the appropriate gas limit for the chain type.
|
|
16042
16597
|
*
|
|
16043
16598
|
* For EVM chains, performs a local eth_estimateGas call, applies a 1.3x safety
|
|
@@ -16086,8 +16641,8 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16086
16641
|
*/ async buildFormattedFees(fees, chain, destinationChain, adapter, recipientAddress) {
|
|
16087
16642
|
if (!fees) return [];
|
|
16088
16643
|
const [providerFees, swapFees, developerFees] = await Promise.all([
|
|
16089
|
-
this.formatServiceFees(fees.provider, chain, 'provider', adapter),
|
|
16090
|
-
this.formatServiceFees(fees.swap, chain, 'swap', adapter),
|
|
16644
|
+
this.formatServiceFees(fees.provider, chain, destinationChain, 'provider', adapter),
|
|
16645
|
+
this.formatServiceFees(fees.swap, chain, destinationChain, 'swap', adapter),
|
|
16091
16646
|
recipientAddress ? this.formatDeveloperFees(fees.developer, chain, destinationChain, recipientAddress, adapter) : Promise.resolve([])
|
|
16092
16647
|
]);
|
|
16093
16648
|
return [
|
|
@@ -16097,6 +16652,45 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16097
16652
|
];
|
|
16098
16653
|
}
|
|
16099
16654
|
/**
|
|
16655
|
+
* Resolve a single fee item to its display token and human-readable amount.
|
|
16656
|
+
*
|
|
16657
|
+
* @remarks
|
|
16658
|
+
* Prefer the self-describing metadata the service attaches to each fee:
|
|
16659
|
+
* `decimals` (and `symbol`) come straight from the provider quote, so they
|
|
16660
|
+
* are authoritative even for a token absent from the SDK registry on both
|
|
16661
|
+
* chains. That is the case {@link resolveFeeChain} cannot recover — a
|
|
16662
|
+
* destination-denominated fee token resolves on neither the source registry
|
|
16663
|
+
* nor the source-bound adapter, leaving the amount as raw base units. When
|
|
16664
|
+
* the service omits `decimals` (optional during rollout), fall back to
|
|
16665
|
+
* inferring the fee token's chain and resolving via the registry/adapter.
|
|
16666
|
+
*
|
|
16667
|
+
* Like {@link formatTokenValue}, this never throws: fee display is cosmetic
|
|
16668
|
+
* and must not fail an estimate/swap. A malformed self-describing `decimals`
|
|
16669
|
+
* (e.g. a non-numeric `amount` or invalid decimal count that makes
|
|
16670
|
+
* {@link formatUnits} throw) falls through to chain-based resolution rather
|
|
16671
|
+
* than propagating out of {@link buildFormattedFees}.
|
|
16672
|
+
*
|
|
16673
|
+
* @param fee - The fee item from the service response.
|
|
16674
|
+
* @param chain - The source chain definition.
|
|
16675
|
+
* @param destinationChain - The destination chain definition.
|
|
16676
|
+
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16677
|
+
* @returns Promise resolving to the formatted amount and display token.
|
|
16678
|
+
*/ async formatFeeValue(fee, chain, destinationChain, adapter) {
|
|
16679
|
+
if (fee.decimals != null) {
|
|
16680
|
+
try {
|
|
16681
|
+
return {
|
|
16682
|
+
amount: formatUnits(fee.amount, fee.decimals),
|
|
16683
|
+
token: fee.symbol ?? fee.token
|
|
16684
|
+
};
|
|
16685
|
+
} catch {
|
|
16686
|
+
// Malformed service metadata — fall through to chain-based resolution,
|
|
16687
|
+
// which never throws (worst case: raw passthrough).
|
|
16688
|
+
}
|
|
16689
|
+
}
|
|
16690
|
+
const feeChain = resolveFeeChain(fee.token, chain, destinationChain);
|
|
16691
|
+
return formatTokenValue(fee.amount, fee.token, feeChain, adapter);
|
|
16692
|
+
}
|
|
16693
|
+
/**
|
|
16100
16694
|
* Format service fee items into the SDK's ServiceSwapFee structure.
|
|
16101
16695
|
*
|
|
16102
16696
|
* @remarks
|
|
@@ -16107,14 +16701,15 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16107
16701
|
* - Raw passthrough only when both registry and adapter fail
|
|
16108
16702
|
*
|
|
16109
16703
|
* @param feeItems - Array of fee items from the service response.
|
|
16110
|
-
* @param chain - The chain definition for token resolution and formatting.
|
|
16704
|
+
* @param chain - The source chain definition for token resolution and formatting.
|
|
16705
|
+
* @param destinationChain - The destination chain, used to resolve fees denominated in the output token.
|
|
16111
16706
|
* @param type - The fee type to assign ('provider' or 'swap').
|
|
16112
16707
|
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16113
16708
|
* @returns Promise resolving to formatted ServiceSwapFee array.
|
|
16114
|
-
*/ async formatServiceFees(feeItems, chain, type, adapter) {
|
|
16709
|
+
*/ async formatServiceFees(feeItems, chain, destinationChain, type, adapter) {
|
|
16115
16710
|
if (!feeItems) return [];
|
|
16116
16711
|
return Promise.all(feeItems.map(async (fee)=>{
|
|
16117
|
-
const formatted = await
|
|
16712
|
+
const formatted = await this.formatFeeValue(fee, chain, destinationChain, adapter);
|
|
16118
16713
|
return {
|
|
16119
16714
|
token: formatted.token,
|
|
16120
16715
|
amount: formatted.amount,
|
|
@@ -16126,16 +16721,15 @@ async function fetchSameChainStatusSnapshot({ isCrossChainSwap, txHash, chain, a
|
|
|
16126
16721
|
* Format developer fee items into the SDK's ServiceSwapFee structure.
|
|
16127
16722
|
*
|
|
16128
16723
|
* @param feeItems - Array of developer fee items from the service response.
|
|
16129
|
-
* @param chain - The chain definition for token resolution and formatting.
|
|
16724
|
+
* @param chain - The source chain definition for token resolution and formatting.
|
|
16725
|
+
* @param destinationChain - The destination chain, used to resolve fees denominated in the output token.
|
|
16130
16726
|
* @param recipientAddress - The developer's fee recipient address from config.
|
|
16131
16727
|
* @param adapter - The adapter for on-chain decimals lookup of unregistered tokens.
|
|
16132
16728
|
* @returns Promise resolving to formatted ServiceSwapFee array with developer entries.
|
|
16133
16729
|
*/ async formatDeveloperFees(feeItems, chain, destinationChain, recipientAddress, adapter) {
|
|
16134
16730
|
if (!feeItems) return [];
|
|
16135
|
-
const isCrossChainSwap = destinationChain.chain !== chain.chain;
|
|
16136
16731
|
return Promise.all(feeItems.map(async (fee)=>{
|
|
16137
|
-
const
|
|
16138
|
-
const formatted = await formatTokenValue(fee.amount, fee.token, feeChain, adapter);
|
|
16732
|
+
const formatted = await this.formatFeeValue(fee, chain, destinationChain, adapter);
|
|
16139
16733
|
return {
|
|
16140
16734
|
token: formatted.token,
|
|
16141
16735
|
amount: formatted.amount,
|
|
@@ -18530,22 +19124,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
|
|
|
18530
19124
|
try {
|
|
18531
19125
|
// Step 1: Build quote params directly (no need for buildServiceParams)
|
|
18532
19126
|
// Use chain.chain (Blockchain enum value like "World_Chain") not chain.name
|
|
19127
|
+
// The kit key is optional (permissionless mode); when absent the quote is
|
|
19128
|
+
// fetched without an Authorization header.
|
|
18533
19129
|
const kitKey = params.config?.kitKey;
|
|
18534
|
-
if (!kitKey) {
|
|
18535
|
-
throw new KitError({
|
|
18536
|
-
code: 1098,
|
|
18537
|
-
name: 'INPUT_VALIDATION_FAILED',
|
|
18538
|
-
type: 'INPUT',
|
|
18539
|
-
recoverability: 'FATAL',
|
|
18540
|
-
message: 'kitKey is required in config for callback-based fees',
|
|
18541
|
-
cause: {
|
|
18542
|
-
trace: {
|
|
18543
|
-
operation: 'handleOutputFeeCallback',
|
|
18544
|
-
params
|
|
18545
|
-
}
|
|
18546
|
-
}
|
|
18547
|
-
});
|
|
18548
|
-
}
|
|
18549
19130
|
// Resolve token aliases to addresses for the quote API
|
|
18550
19131
|
// The quote endpoint requires resolved addresses, not aliases like 'USDC'
|
|
18551
19132
|
const chain = params.from.chain;
|
|
@@ -18570,7 +19151,9 @@ const transformAmount = (value, direction, decimals)=>formatUnits(value, decimal
|
|
|
18570
19151
|
...params.config?.slippageBps !== undefined && {
|
|
18571
19152
|
slippageBps: params.config.slippageBps
|
|
18572
19153
|
},
|
|
18573
|
-
|
|
19154
|
+
...kitKey ? {
|
|
19155
|
+
apiKey: kitKey
|
|
19156
|
+
} : {}
|
|
18574
19157
|
};
|
|
18575
19158
|
// Step 2: Get quote from service
|
|
18576
19159
|
const quoteResponse = await getQuote(quoteParams);
|
|
@@ -19012,7 +19595,9 @@ const sleep$1 = async (ms)=>new Promise((resolve)=>setTimeout(resolve, ms));
|
|
|
19012
19595
|
...isCrossChain && {
|
|
19013
19596
|
toChain: chainOut
|
|
19014
19597
|
},
|
|
19015
|
-
|
|
19598
|
+
...params.kitKey ? {
|
|
19599
|
+
apiKey: params.kitKey
|
|
19600
|
+
} : {}
|
|
19016
19601
|
};
|
|
19017
19602
|
let raw = await getSwapStatus$1(request);
|
|
19018
19603
|
// When the service hasn't finished indexing a just-submitted swap it
|
|
@@ -19152,7 +19737,9 @@ const isResultShape = (params)=>'result' in params;
|
|
|
19152
19737
|
...chainOut !== undefined && {
|
|
19153
19738
|
chainOut
|
|
19154
19739
|
},
|
|
19155
|
-
|
|
19740
|
+
...params.kitKey ? {
|
|
19741
|
+
kitKey: params.kitKey
|
|
19742
|
+
} : {}
|
|
19156
19743
|
};
|
|
19157
19744
|
const deadline = Date.now() + timeoutMs;
|
|
19158
19745
|
let pollIndex = 0;
|
|
@@ -19313,7 +19900,9 @@ function resolveTokenEntry(entry, index, chain, chainDef, context) {
|
|
|
19313
19900
|
const resolvedAddresses = params.tokens?.map((entry, index)=>resolveTokenEntry(entry, index, chain, chainDef, context));
|
|
19314
19901
|
return getTokenRates$1({
|
|
19315
19902
|
chain,
|
|
19316
|
-
|
|
19903
|
+
...params.kitKey ? {
|
|
19904
|
+
apiKey: params.kitKey
|
|
19905
|
+
} : {},
|
|
19317
19906
|
...resolvedAddresses !== undefined && {
|
|
19318
19907
|
addresses: resolvedAddresses
|
|
19319
19908
|
}
|
|
@@ -20310,7 +20899,7 @@ registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
|
20310
20899
|
};
|
|
20311
20900
|
|
|
20312
20901
|
var name = "@circle-fin/earn-kit";
|
|
20313
|
-
var version = "1.
|
|
20902
|
+
var version = "1.3.0";
|
|
20314
20903
|
var pkg = {
|
|
20315
20904
|
name: name,
|
|
20316
20905
|
version: version};
|
|
@@ -20440,7 +21029,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20440
21029
|
asset: z.string(),
|
|
20441
21030
|
assetAddress: z.string(),
|
|
20442
21031
|
lltv: z.number(),
|
|
20443
|
-
supplyUsd: z.number()
|
|
21032
|
+
supplyUsd: z.number(),
|
|
21033
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
21034
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
21035
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
21036
|
+
allocationPct: z.number().nullable().optional()
|
|
20444
21037
|
});
|
|
20445
21038
|
/**
|
|
20446
21039
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -20454,7 +21047,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20454
21047
|
])
|
|
20455
21048
|
});
|
|
20456
21049
|
/**
|
|
20457
|
-
* Zod schema for
|
|
21050
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
21051
|
+
*
|
|
21052
|
+
* @internal
|
|
21053
|
+
*/ const managerSchema = z.object({
|
|
21054
|
+
name: z.string(),
|
|
21055
|
+
address: z.string().optional(),
|
|
21056
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
21057
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
21058
|
+
// speculatively.
|
|
21059
|
+
type: z.enum([
|
|
21060
|
+
'curator'
|
|
21061
|
+
])
|
|
21062
|
+
});
|
|
21063
|
+
/**
|
|
21064
|
+
* Zod schema for the APY profile facet in the API response.
|
|
21065
|
+
*
|
|
21066
|
+
* @internal
|
|
21067
|
+
*/ const apyProfileSchema = z.object({
|
|
21068
|
+
current: z.number(),
|
|
21069
|
+
native: z.number().nullable(),
|
|
21070
|
+
d7: z.number().nullable(),
|
|
21071
|
+
d30: z.number().nullable(),
|
|
21072
|
+
d90: z.number().nullable(),
|
|
21073
|
+
rewardShare: z.number().nullable(),
|
|
21074
|
+
source: z.string().optional(),
|
|
21075
|
+
asOf: z.string().optional()
|
|
21076
|
+
});
|
|
21077
|
+
/**
|
|
21078
|
+
* Zod schema for the fee split facet in the API response.
|
|
21079
|
+
*
|
|
21080
|
+
* @internal
|
|
21081
|
+
*/ const feeInfoSchema = z.object({
|
|
21082
|
+
performance: z.number().nullable(),
|
|
21083
|
+
management: z.number().nullable()
|
|
21084
|
+
});
|
|
21085
|
+
/**
|
|
21086
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
21087
|
+
*
|
|
21088
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
21089
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
21090
|
+
*
|
|
21091
|
+
* @internal
|
|
21092
|
+
*/ const liquidityProfileSchema = z.object({
|
|
21093
|
+
totalDeposits: amountJsonSchema,
|
|
21094
|
+
available: amountJsonSchema,
|
|
21095
|
+
totalSupply: amountJsonSchema,
|
|
21096
|
+
status: z.enum([
|
|
21097
|
+
'active',
|
|
21098
|
+
'low_liquidity'
|
|
21099
|
+
])
|
|
21100
|
+
});
|
|
21101
|
+
/**
|
|
21102
|
+
* Zod schema for the risk signals facet in the API response.
|
|
21103
|
+
*
|
|
21104
|
+
* @internal
|
|
21105
|
+
*/ const riskSignalsSchema = z.object({
|
|
21106
|
+
circleSentinel: z.boolean(),
|
|
21107
|
+
warnings: z.array(vaultWarningSchema).optional(),
|
|
21108
|
+
earnKitWarnings: z.array(z.string()).optional()
|
|
21109
|
+
});
|
|
21110
|
+
/**
|
|
21111
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
21112
|
+
*
|
|
21113
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
21114
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
21115
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
21116
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
21117
|
+
* backend; they become required after Expand ships.
|
|
20458
21118
|
*
|
|
20459
21119
|
* @internal
|
|
20460
21120
|
*/ const vaultInfoResponseSchema = z.object({
|
|
@@ -20479,6 +21139,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
20479
21139
|
warnings: z.array(vaultWarningSchema).optional(),
|
|
20480
21140
|
earnKitWarnings: z.array(z.string()).optional()
|
|
20481
21141
|
});
|
|
21142
|
+
/**
|
|
21143
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
21144
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
21145
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
21146
|
+
*
|
|
21147
|
+
* @internal
|
|
21148
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
21149
|
+
address: z.string().optional(),
|
|
21150
|
+
asOf: z.string().optional(),
|
|
21151
|
+
manager: managerSchema.nullable().optional(),
|
|
21152
|
+
apyProfile: apyProfileSchema.optional(),
|
|
21153
|
+
fee: feeInfoSchema.optional(),
|
|
21154
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
21155
|
+
riskSignals: riskSignalsSchema.optional()
|
|
21156
|
+
});
|
|
21157
|
+
/**
|
|
21158
|
+
* Zod schema for the `vault` opportunity variant.
|
|
21159
|
+
*
|
|
21160
|
+
* @internal
|
|
21161
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
21162
|
+
productType: z.literal('vault'),
|
|
21163
|
+
collateral: z.array(collateralSchema)
|
|
21164
|
+
});
|
|
21165
|
+
/**
|
|
21166
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
21167
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
21168
|
+
*
|
|
21169
|
+
* @internal
|
|
21170
|
+
*/ const earnOpportunityVariants = [
|
|
21171
|
+
vaultOpportunitySchema
|
|
21172
|
+
];
|
|
21173
|
+
/** @internal */ const earnOpportunitySchema = z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
21174
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
21175
|
+
/**
|
|
21176
|
+
* Tolerant list parser for earn opportunities.
|
|
21177
|
+
*
|
|
21178
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
21179
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
21180
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
21181
|
+
*
|
|
21182
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
21183
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
21184
|
+
* rather than dropping every vault the backend returns.
|
|
21185
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
21186
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
21187
|
+
* of rejecting the whole list.
|
|
21188
|
+
*
|
|
21189
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
21190
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
21191
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
21192
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
21193
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
21194
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
21195
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
21196
|
+
* `ZodError`).
|
|
21197
|
+
*
|
|
21198
|
+
* @internal
|
|
21199
|
+
*/ const earnOpportunityListSchema = z.preprocess((raw)=>{
|
|
21200
|
+
if (!Array.isArray(raw)) {
|
|
21201
|
+
return raw;
|
|
21202
|
+
}
|
|
21203
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
21204
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
21205
|
+
const entries = raw;
|
|
21206
|
+
return entries.map((entry)=>{
|
|
21207
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
21208
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
21209
|
+
return entry;
|
|
21210
|
+
}
|
|
21211
|
+
const record = entry;
|
|
21212
|
+
// Older backend predating productType: default to the only type then.
|
|
21213
|
+
return record.productType === undefined ? {
|
|
21214
|
+
...record,
|
|
21215
|
+
productType: 'vault'
|
|
21216
|
+
} : record;
|
|
21217
|
+
}).filter((entry)=>{
|
|
21218
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
21219
|
+
// productType this SDK version doesn't know). Everything else —
|
|
21220
|
+
// non-objects, a non-string productType — flows through to
|
|
21221
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
21222
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
21223
|
+
return true;
|
|
21224
|
+
}
|
|
21225
|
+
const productType = entry.productType;
|
|
21226
|
+
if (typeof productType !== 'string') {
|
|
21227
|
+
return true;
|
|
21228
|
+
}
|
|
21229
|
+
return knownProductTypes.has(productType);
|
|
21230
|
+
});
|
|
21231
|
+
}, z.array(earnOpportunitySchema));
|
|
20482
21232
|
// ---------------------------------------------------------------------------
|
|
20483
21233
|
// Position response schema
|
|
20484
21234
|
// ---------------------------------------------------------------------------
|
|
@@ -20608,6 +21358,7 @@ const positionPnlSchema = z.discriminatedUnion('status', [
|
|
|
20608
21358
|
*
|
|
20609
21359
|
* @internal
|
|
20610
21360
|
*/ const depositPayloadSchema = z.object({
|
|
21361
|
+
execId: bridgeDepositExecIdSchema,
|
|
20611
21362
|
executionParams: depositExecutionParamsSchema,
|
|
20612
21363
|
signature: hexSignatureSchema
|
|
20613
21364
|
});
|
|
@@ -20699,6 +21450,21 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20699
21450
|
amount: amountJsonSchema,
|
|
20700
21451
|
vaultAddress: hexAddressSchema
|
|
20701
21452
|
}).passthrough();
|
|
21453
|
+
/** @internal */ const bridgeQuoteExpirySchema = z.discriminatedUnion('mode', [
|
|
21454
|
+
z.object({
|
|
21455
|
+
mode: z.literal('TIMESTAMP'),
|
|
21456
|
+
expiresAt: z.string().datetime({
|
|
21457
|
+
offset: true
|
|
21458
|
+
})
|
|
21459
|
+
}),
|
|
21460
|
+
z.object({
|
|
21461
|
+
mode: z.literal('BLOCK_NUMBER'),
|
|
21462
|
+
expiresAtBlock: z.number().int(),
|
|
21463
|
+
blockEstimatedAt: z.string().datetime({
|
|
21464
|
+
offset: true
|
|
21465
|
+
}).optional()
|
|
21466
|
+
})
|
|
21467
|
+
]).optional().catch(undefined);
|
|
20702
21468
|
/**
|
|
20703
21469
|
* Zod schema for the bridge deposit prepare payload.
|
|
20704
21470
|
*
|
|
@@ -20710,6 +21476,10 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20710
21476
|
execId: bridgeDepositExecIdSchema,
|
|
20711
21477
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
20712
21478
|
expiresAt: z.string().datetime(),
|
|
21479
|
+
quoteIssuedAt: z.string().datetime({
|
|
21480
|
+
offset: true
|
|
21481
|
+
}).optional().catch(undefined),
|
|
21482
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
20713
21483
|
review: bridgeDepositPrepareReviewSchema
|
|
20714
21484
|
});
|
|
20715
21485
|
/**
|
|
@@ -20775,6 +21545,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20775
21545
|
*
|
|
20776
21546
|
* @internal
|
|
20777
21547
|
*/ const withdrawPayloadSchema = z.object({
|
|
21548
|
+
execId: bridgeDepositExecIdSchema,
|
|
20778
21549
|
executionParams: withdrawExecutionParamsSchema,
|
|
20779
21550
|
signature: hexSignatureSchema
|
|
20780
21551
|
});
|
|
@@ -20788,6 +21559,27 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20788
21559
|
data: withdrawPayloadSchema
|
|
20789
21560
|
});
|
|
20790
21561
|
// ---------------------------------------------------------------------------
|
|
21562
|
+
// Transaction report response schema
|
|
21563
|
+
// ---------------------------------------------------------------------------
|
|
21564
|
+
/**
|
|
21565
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
21566
|
+
*
|
|
21567
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
21568
|
+
* schema accepts any object shape and does not require specific fields.
|
|
21569
|
+
*
|
|
21570
|
+
* @internal
|
|
21571
|
+
*/ const transactionReportPayloadSchema = z.object({}).passthrough();
|
|
21572
|
+
/**
|
|
21573
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
21574
|
+
*
|
|
21575
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
21576
|
+
* envelope.
|
|
21577
|
+
*
|
|
21578
|
+
* @internal
|
|
21579
|
+
*/ z.object({
|
|
21580
|
+
data: transactionReportPayloadSchema
|
|
21581
|
+
});
|
|
21582
|
+
// ---------------------------------------------------------------------------
|
|
20791
21583
|
// Claim rewards response schema
|
|
20792
21584
|
// ---------------------------------------------------------------------------
|
|
20793
21585
|
/**
|
|
@@ -20835,10 +21627,11 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20835
21627
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
20836
21628
|
*
|
|
20837
21629
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
20838
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
20839
|
-
*
|
|
20840
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
20841
|
-
* `'
|
|
21630
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
21631
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
21632
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
21633
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
21634
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
20842
21635
|
*
|
|
20843
21636
|
* @internal
|
|
20844
21637
|
*/ const feeSchema = z.object({
|
|
@@ -20847,6 +21640,30 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20847
21640
|
token: z.string(),
|
|
20848
21641
|
amount: amountJsonSchema
|
|
20849
21642
|
});
|
|
21643
|
+
/**
|
|
21644
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
21645
|
+
*
|
|
21646
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
21647
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
21648
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
21649
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
21650
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
21651
|
+
*
|
|
21652
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
21653
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
21654
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
21655
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
21656
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
21657
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
21658
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
21659
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
21660
|
+
*
|
|
21661
|
+
* @internal
|
|
21662
|
+
*/ const quoteGasFeeSchema = z.object({
|
|
21663
|
+
name: z.string().optional(),
|
|
21664
|
+
fees: z.unknown(),
|
|
21665
|
+
error: z.string().optional()
|
|
21666
|
+
}).passthrough();
|
|
20850
21667
|
/**
|
|
20851
21668
|
* Zod schema for the inner deposit quote payload.
|
|
20852
21669
|
*
|
|
@@ -20862,7 +21679,8 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20862
21679
|
expectedShares: amountJsonSchema,
|
|
20863
21680
|
sharePrice: z.string(),
|
|
20864
21681
|
currentApy: z.number(),
|
|
20865
|
-
fees: z.array(feeSchema).optional()
|
|
21682
|
+
fees: z.array(feeSchema).optional(),
|
|
21683
|
+
gasFees: z.array(quoteGasFeeSchema).optional()
|
|
20866
21684
|
});
|
|
20867
21685
|
/**
|
|
20868
21686
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -20889,6 +21707,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20889
21707
|
sharePrice: z.string(),
|
|
20890
21708
|
maxWithdrawable: amountJsonSchema,
|
|
20891
21709
|
fees: z.array(feeSchema),
|
|
21710
|
+
gasFees: z.array(quoteGasFeeSchema).optional(),
|
|
20892
21711
|
warnings: z.array(z.string()).optional()
|
|
20893
21712
|
});
|
|
20894
21713
|
/**
|
|
@@ -20946,7 +21765,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20946
21765
|
*
|
|
20947
21766
|
* @internal
|
|
20948
21767
|
*/ const getVaultsPayloadSchema = z.object({
|
|
20949
|
-
vaults:
|
|
21768
|
+
vaults: earnOpportunityListSchema,
|
|
20950
21769
|
errors: z.array(vaultErrorSchema)
|
|
20951
21770
|
});
|
|
20952
21771
|
/**
|
|
@@ -20976,7 +21795,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
20976
21795
|
*
|
|
20977
21796
|
* @internal
|
|
20978
21797
|
*/ const exploreVaultsPayloadSchema = z.object({
|
|
20979
|
-
vaults:
|
|
21798
|
+
vaults: earnOpportunityListSchema,
|
|
20980
21799
|
pagination: explorePaginationSchema
|
|
20981
21800
|
});
|
|
20982
21801
|
/**
|