@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/earn.cjs
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
var zod = require('zod');
|
|
22
22
|
require('pino');
|
|
23
|
+
require('@ethersproject/bytes');
|
|
24
|
+
require('@ethersproject/abi');
|
|
25
|
+
require('@ethersproject/address');
|
|
23
26
|
var web3_js = require('@solana/web3.js');
|
|
24
27
|
require('bn.js');
|
|
25
28
|
require('@coral-xyz/anchor');
|
|
@@ -1761,15 +1764,15 @@ class KitError extends Error {
|
|
|
1761
1764
|
}
|
|
1762
1765
|
|
|
1763
1766
|
/**
|
|
1764
|
-
* Standardized error definitions for Earn
|
|
1767
|
+
* Standardized error definitions for Earn operations.
|
|
1765
1768
|
*
|
|
1766
1769
|
* These error codes provide fine-grained categorization of failures
|
|
1767
|
-
* from the
|
|
1770
|
+
* from the Earn service, enabling SDK consumers to distinguish
|
|
1768
1771
|
* between input errors (fix your request) and service errors (retry later).
|
|
1769
1772
|
*
|
|
1770
1773
|
* Error code ranges:
|
|
1771
|
-
* - 1100-
|
|
1772
|
-
* - 8100-
|
|
1774
|
+
* - 1100-1106: INPUT errors — invalid, unsupported, or stale request state
|
|
1775
|
+
* - 8100-8105: SERVICE errors — retryable backend/provider failures
|
|
1773
1776
|
*
|
|
1774
1777
|
* @example
|
|
1775
1778
|
* ```typescript
|
|
@@ -1821,6 +1824,14 @@ class KitError extends Error {
|
|
|
1821
1824
|
name: 'EARN_UNSUPPORTED_BRIDGE_ROUTE',
|
|
1822
1825
|
type: 'INPUT'
|
|
1823
1826
|
},
|
|
1827
|
+
/**
|
|
1828
|
+
* The bridge quote expired. This is an INPUT error because the prepared
|
|
1829
|
+
* request is stale and must be replaced instead of retried.
|
|
1830
|
+
*/ BRIDGE_QUOTE_EXPIRED: {
|
|
1831
|
+
code: 1106,
|
|
1832
|
+
name: 'EARN_BRIDGE_QUOTE_EXPIRED',
|
|
1833
|
+
type: 'INPUT'
|
|
1834
|
+
},
|
|
1824
1835
|
/** The proxy signing call failed — retryable. */ SIGNING_FAILED: {
|
|
1825
1836
|
code: 8100,
|
|
1826
1837
|
name: 'EARN_SIGNING_FAILED',
|
|
@@ -1845,6 +1856,11 @@ class KitError extends Error {
|
|
|
1845
1856
|
code: 8104,
|
|
1846
1857
|
name: 'EARN_PAUSED',
|
|
1847
1858
|
type: 'SERVICE'
|
|
1859
|
+
},
|
|
1860
|
+
/** Position PnL is still reconciling and can be retried. */ POSITION_PNL_PENDING: {
|
|
1861
|
+
code: 8105,
|
|
1862
|
+
name: 'EARN_POSITION_PNL_PENDING',
|
|
1863
|
+
type: 'SERVICE'
|
|
1848
1864
|
}
|
|
1849
1865
|
};
|
|
1850
1866
|
|
|
@@ -1872,9 +1888,12 @@ function getOptionalString(value) {
|
|
|
1872
1888
|
*
|
|
1873
1889
|
* SERVICE errors (RETRYABLE) — try again later:
|
|
1874
1890
|
* - signing-failed, provider-error, rewards-fetch-failed,
|
|
1875
|
-
* internal-error, vault-refresh-busy, off-chain-paused,
|
|
1891
|
+
* internal-error, vault-refresh-busy, off-chain-paused, position-PnL-pending,
|
|
1876
1892
|
* bridge failures/status lookup failures
|
|
1877
1893
|
*
|
|
1894
|
+
* Quote expiry is INPUT/FATAL because callers must start a fresh bridge prepare
|
|
1895
|
+
* flow rather than retry the stale prepared bundle.
|
|
1896
|
+
*
|
|
1878
1897
|
* Unrecognized codes fall through to `parseApiError` for HTTP-status-based
|
|
1879
1898
|
* handling.
|
|
1880
1899
|
*
|
|
@@ -2059,6 +2078,13 @@ function getOptionalString(value) {
|
|
|
2059
2078
|
recoverability: 'FATAL'
|
|
2060
2079
|
}
|
|
2061
2080
|
],
|
|
2081
|
+
[
|
|
2082
|
+
380416,
|
|
2083
|
+
{
|
|
2084
|
+
errorDef: EarnError.POSITION_PNL_PENDING,
|
|
2085
|
+
recoverability: 'RETRYABLE'
|
|
2086
|
+
}
|
|
2087
|
+
],
|
|
2062
2088
|
// Bridge (380_5XX)
|
|
2063
2089
|
[
|
|
2064
2090
|
380500,
|
|
@@ -2101,6 +2127,13 @@ function getOptionalString(value) {
|
|
|
2101
2127
|
errorDef: EarnError.PROVIDER_ERROR,
|
|
2102
2128
|
recoverability: 'FATAL'
|
|
2103
2129
|
}
|
|
2130
|
+
],
|
|
2131
|
+
[
|
|
2132
|
+
380506,
|
|
2133
|
+
{
|
|
2134
|
+
errorDef: EarnError.BRIDGE_QUOTE_EXPIRED,
|
|
2135
|
+
recoverability: 'FATAL'
|
|
2136
|
+
}
|
|
2104
2137
|
]
|
|
2105
2138
|
]);
|
|
2106
2139
|
/**
|
|
@@ -2203,6 +2236,8 @@ function getOptionalString(value) {
|
|
|
2203
2236
|
Blockchain["Celo_Alfajores_Testnet"] = "Celo_Alfajores_Testnet";
|
|
2204
2237
|
Blockchain["Codex"] = "Codex";
|
|
2205
2238
|
Blockchain["Codex_Testnet"] = "Codex_Testnet";
|
|
2239
|
+
Blockchain["Cronos"] = "Cronos";
|
|
2240
|
+
Blockchain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2206
2241
|
Blockchain["Edge"] = "Edge";
|
|
2207
2242
|
Blockchain["Edge_Testnet"] = "Edge_Testnet";
|
|
2208
2243
|
Blockchain["Ethereum"] = "Ethereum";
|
|
@@ -2285,6 +2320,7 @@ var BridgeChain;
|
|
|
2285
2320
|
BridgeChain["Avalanche"] = "Avalanche";
|
|
2286
2321
|
BridgeChain["Base"] = "Base";
|
|
2287
2322
|
BridgeChain["Codex"] = "Codex";
|
|
2323
|
+
BridgeChain["Cronos"] = "Cronos";
|
|
2288
2324
|
BridgeChain["Edge"] = "Edge";
|
|
2289
2325
|
BridgeChain["Ethereum"] = "Ethereum";
|
|
2290
2326
|
BridgeChain["HyperEVM"] = "HyperEVM";
|
|
@@ -2309,6 +2345,7 @@ var BridgeChain;
|
|
|
2309
2345
|
BridgeChain["Avalanche_Fuji"] = "Avalanche_Fuji";
|
|
2310
2346
|
BridgeChain["Base_Sepolia"] = "Base_Sepolia";
|
|
2311
2347
|
BridgeChain["Codex_Testnet"] = "Codex_Testnet";
|
|
2348
|
+
BridgeChain["Cronos_Testnet"] = "Cronos_Testnet";
|
|
2312
2349
|
BridgeChain["Edge_Testnet"] = "Edge_Testnet";
|
|
2313
2350
|
BridgeChain["Ethereum_Sepolia"] = "Ethereum_Sepolia";
|
|
2314
2351
|
BridgeChain["HyperEVM_Testnet"] = "HyperEVM_Testnet";
|
|
@@ -2820,7 +2857,10 @@ var EarnChain;
|
|
|
2820
2857
|
contracts: {
|
|
2821
2858
|
v1: {
|
|
2822
2859
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
2823
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
2860
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
2861
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
2862
|
+
// deposit into the GatewayWallet above.
|
|
2863
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
2824
2864
|
}
|
|
2825
2865
|
},
|
|
2826
2866
|
forwarderSupported: {
|
|
@@ -3354,6 +3394,96 @@ var EarnChain;
|
|
|
3354
3394
|
}
|
|
3355
3395
|
});
|
|
3356
3396
|
|
|
3397
|
+
/**
|
|
3398
|
+
* Cronos Mainnet chain definition
|
|
3399
|
+
* @remarks
|
|
3400
|
+
* This represents the official production network for the Cronos blockchain.
|
|
3401
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3402
|
+
*/ const Cronos = defineChain({
|
|
3403
|
+
type: 'evm',
|
|
3404
|
+
chain: Blockchain.Cronos,
|
|
3405
|
+
name: 'Cronos',
|
|
3406
|
+
title: 'Cronos Mainnet',
|
|
3407
|
+
nativeCurrency: {
|
|
3408
|
+
name: 'Cronos',
|
|
3409
|
+
symbol: 'CRO',
|
|
3410
|
+
decimals: 18
|
|
3411
|
+
},
|
|
3412
|
+
chainId: 25,
|
|
3413
|
+
isTestnet: false,
|
|
3414
|
+
explorerUrl: 'https://cronoscan.com/tx/{hash}',
|
|
3415
|
+
rpcEndpoints: [
|
|
3416
|
+
'https://evm.cronos.org'
|
|
3417
|
+
],
|
|
3418
|
+
eurcAddress: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
3419
|
+
usdcAddress: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
3420
|
+
usdtAddress: null,
|
|
3421
|
+
cctp: {
|
|
3422
|
+
domain: 32,
|
|
3423
|
+
contracts: {
|
|
3424
|
+
v2: {
|
|
3425
|
+
type: 'split',
|
|
3426
|
+
tokenMessenger: '0x28b5a0e9C621a5BadaA536219b3a228C8168cf5d',
|
|
3427
|
+
messageTransmitter: '0x81D40F21F12A8F0E3252Bccb954D722d4c464B64',
|
|
3428
|
+
confirmations: 1,
|
|
3429
|
+
fastConfirmations: 1
|
|
3430
|
+
}
|
|
3431
|
+
},
|
|
3432
|
+
forwarderSupported: {
|
|
3433
|
+
source: false,
|
|
3434
|
+
destination: false
|
|
3435
|
+
}
|
|
3436
|
+
},
|
|
3437
|
+
kitContracts: {
|
|
3438
|
+
bridge: BRIDGE_CONTRACT_EVM_MAINNET
|
|
3439
|
+
}
|
|
3440
|
+
});
|
|
3441
|
+
|
|
3442
|
+
/**
|
|
3443
|
+
* Cronos Testnet chain definition
|
|
3444
|
+
* @remarks
|
|
3445
|
+
* This represents the official test network for the Cronos blockchain.
|
|
3446
|
+
* Cronos is an EVM-compatible blockchain.
|
|
3447
|
+
*/ const CronosTestnet = defineChain({
|
|
3448
|
+
type: 'evm',
|
|
3449
|
+
chain: Blockchain.Cronos_Testnet,
|
|
3450
|
+
name: 'Cronos Testnet',
|
|
3451
|
+
title: 'Cronos Testnet',
|
|
3452
|
+
nativeCurrency: {
|
|
3453
|
+
name: 'CRO',
|
|
3454
|
+
symbol: 'tCRO',
|
|
3455
|
+
decimals: 18
|
|
3456
|
+
},
|
|
3457
|
+
chainId: 338,
|
|
3458
|
+
isTestnet: true,
|
|
3459
|
+
explorerUrl: 'https://explorer.cronos.org/testnet/tx/{hash}',
|
|
3460
|
+
rpcEndpoints: [
|
|
3461
|
+
'https://evm-t3.cronos.org'
|
|
3462
|
+
],
|
|
3463
|
+
eurcAddress: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
3464
|
+
usdcAddress: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
3465
|
+
usdtAddress: null,
|
|
3466
|
+
cctp: {
|
|
3467
|
+
domain: 32,
|
|
3468
|
+
contracts: {
|
|
3469
|
+
v2: {
|
|
3470
|
+
type: 'split',
|
|
3471
|
+
tokenMessenger: '0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA',
|
|
3472
|
+
messageTransmitter: '0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275',
|
|
3473
|
+
confirmations: 1,
|
|
3474
|
+
fastConfirmations: 1
|
|
3475
|
+
}
|
|
3476
|
+
},
|
|
3477
|
+
forwarderSupported: {
|
|
3478
|
+
source: false,
|
|
3479
|
+
destination: false
|
|
3480
|
+
}
|
|
3481
|
+
},
|
|
3482
|
+
kitContracts: {
|
|
3483
|
+
bridge: BRIDGE_CONTRACT_EVM_TESTNET
|
|
3484
|
+
}
|
|
3485
|
+
});
|
|
3486
|
+
|
|
3357
3487
|
/**
|
|
3358
3488
|
* Edge Mainnet chain definition
|
|
3359
3489
|
* @remarks
|
|
@@ -5705,6 +5835,8 @@ var Chains = {
|
|
|
5705
5835
|
CeloAlfajoresTestnet: CeloAlfajoresTestnet,
|
|
5706
5836
|
Codex: Codex,
|
|
5707
5837
|
CodexTestnet: CodexTestnet,
|
|
5838
|
+
Cronos: Cronos,
|
|
5839
|
+
CronosTestnet: CronosTestnet,
|
|
5708
5840
|
Edge: Edge,
|
|
5709
5841
|
EdgeTestnet: EdgeTestnet,
|
|
5710
5842
|
Ethereum: Ethereum,
|
|
@@ -5796,7 +5928,10 @@ var Chains = {
|
|
|
5796
5928
|
minter: zod.z.string({
|
|
5797
5929
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
5798
5930
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
5799
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
5931
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
5932
|
+
depositForHandler: zod.z.string({
|
|
5933
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
5934
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
5800
5935
|
}).strict() // Reject any additional properties not defined in the schema
|
|
5801
5936
|
;
|
|
5802
5937
|
/**
|
|
@@ -7136,6 +7271,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7136
7271
|
[Blockchain.Base]: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
7137
7272
|
[Blockchain.Celo]: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
|
|
7138
7273
|
[Blockchain.Codex]: '0xd996633a415985DBd7D6D12f4A4343E31f5037cf',
|
|
7274
|
+
[Blockchain.Cronos]: '0x3D7F2C478aAfdB65542BCB44bCeeC05849999d2D',
|
|
7139
7275
|
[Blockchain.Edge]: '0x98d2919b9A214E6Fa5384AC81E6864bA686Ad74c',
|
|
7140
7276
|
[Blockchain.Ethereum]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
|
7141
7277
|
[Blockchain.Hedera]: '0.0.456858',
|
|
@@ -7169,6 +7305,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7169
7305
|
[Blockchain.Avalanche_Fuji]: '0x5425890298aed601595a70AB815c96711a31Bc65',
|
|
7170
7306
|
[Blockchain.Base_Sepolia]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e',
|
|
7171
7307
|
[Blockchain.Codex_Testnet]: '0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f',
|
|
7308
|
+
[Blockchain.Cronos_Testnet]: '0xEb33dc5fac03833e132593659e1dE7256aB59794',
|
|
7172
7309
|
[Blockchain.Edge_Testnet]: '0x2d9F7CAD728051AA35Ecdc472a14cf8cDF5CFD6B',
|
|
7173
7310
|
[Blockchain.Ethereum_Sepolia]: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
|
|
7174
7311
|
[Blockchain.Hedera_Testnet]: '0.0.429274',
|
|
@@ -7241,6 +7378,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7241
7378
|
// =========================================================================
|
|
7242
7379
|
[Blockchain.Avalanche]: '0xc891EB4cbdEFf6e073e859e987815Ed1505c2ACD',
|
|
7243
7380
|
[Blockchain.Base]: '0x60a3E35Cc302bFA44Cb288Bc5a4F316Fdb1adb42',
|
|
7381
|
+
[Blockchain.Cronos]: '0xA6dE01a2d62C6B5f3525d768f34d276652C554c8',
|
|
7244
7382
|
[Blockchain.Ethereum]: '0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c',
|
|
7245
7383
|
[Blockchain.Solana]: 'HzwqbKZw8HxMN6bF2yFZNrht3c2iXXzpKcFu7uBEDKtr',
|
|
7246
7384
|
[Blockchain.World_Chain]: '0x1C60ba0A0eD1019e8Eb035E6daF4155A5cE2380B',
|
|
@@ -7249,6 +7387,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7249
7387
|
// =========================================================================
|
|
7250
7388
|
[Blockchain.Arc_Testnet]: '0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a',
|
|
7251
7389
|
[Blockchain.Base_Sepolia]: '0x808456652fdb597867f38412077A9182bf77359F',
|
|
7390
|
+
[Blockchain.Cronos_Testnet]: '0x31f7538adb53cF16350e6B0c89d03D91b7D12c46',
|
|
7252
7391
|
[Blockchain.Ethereum_Sepolia]: '0x08210F9170F89Ab7658F0B5E3fF39b0E03C594D4'
|
|
7253
7392
|
}
|
|
7254
7393
|
};
|
|
@@ -7904,6 +8043,13 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7904
8043
|
return explorerUrl;
|
|
7905
8044
|
}
|
|
7906
8045
|
|
|
8046
|
+
/**
|
|
8047
|
+
* CCTP forwarding magic bytes prefix.
|
|
8048
|
+
*
|
|
8049
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
8050
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
8051
|
+
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
8052
|
+
|
|
7907
8053
|
/**
|
|
7908
8054
|
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
7909
8055
|
* short SDK name used in telemetry payloads.
|
|
@@ -7922,11 +8068,11 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
7922
8068
|
return pkgName.replace('@circle-fin/', '');
|
|
7923
8069
|
}
|
|
7924
8070
|
|
|
7925
|
-
var name$
|
|
7926
|
-
var version$
|
|
7927
|
-
var pkg$
|
|
7928
|
-
name: name$
|
|
7929
|
-
version: version$
|
|
8071
|
+
var name$3 = "@circle-fin/bridge-kit";
|
|
8072
|
+
var version$3 = "1.12.1";
|
|
8073
|
+
var pkg$3 = {
|
|
8074
|
+
name: name$3,
|
|
8075
|
+
version: version$3};
|
|
7930
8076
|
|
|
7931
8077
|
/**
|
|
7932
8078
|
* Schema for validating BridgeKit custom fee policy.
|
|
@@ -8748,6 +8894,11 @@ var TransferSpeed;
|
|
|
8748
8894
|
clock: zod.z.any().optional()
|
|
8749
8895
|
}).passthrough();
|
|
8750
8896
|
|
|
8897
|
+
/**
|
|
8898
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
8899
|
+
* hookData must start with.
|
|
8900
|
+
*/ Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
8901
|
+
|
|
8751
8902
|
/**
|
|
8752
8903
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
8753
8904
|
*
|
|
@@ -8774,16 +8925,16 @@ var TransferSpeed;
|
|
|
8774
8925
|
* @internal
|
|
8775
8926
|
*/ Object.values(Chains).filter((chain)=>isCCTPV2Supported(chain));
|
|
8776
8927
|
|
|
8777
|
-
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$
|
|
8928
|
+
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$3.name);
|
|
8778
8929
|
|
|
8779
8930
|
// Auto-register this kit for user agent tracking
|
|
8780
|
-
registerKit(`${pkg$
|
|
8931
|
+
registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
8781
8932
|
|
|
8782
|
-
var name$
|
|
8783
|
-
var version$
|
|
8784
|
-
var pkg$
|
|
8785
|
-
name: name$
|
|
8786
|
-
version: version$
|
|
8933
|
+
var name$2 = "@circle-fin/swap-kit";
|
|
8934
|
+
var version$2 = "1.4.0";
|
|
8935
|
+
var pkg$2 = {
|
|
8936
|
+
name: name$2,
|
|
8937
|
+
version: version$2};
|
|
8787
8938
|
|
|
8788
8939
|
const chainIdentifierField = zod.z.custom((value)=>chainIdentifierSchema.safeParse(value).success, {
|
|
8789
8940
|
message: 'chain must be a valid chain identifier'
|
|
@@ -8845,7 +8996,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
8845
8996
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
8846
8997
|
provider: zod.z.string({
|
|
8847
8998
|
invalid_type_error: 'provider must be a string'
|
|
8848
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
8999
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
9000
|
+
batchTransactions: zod.z.boolean({
|
|
9001
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
9002
|
+
}).optional()
|
|
8849
9003
|
});
|
|
8850
9004
|
/**
|
|
8851
9005
|
* Zod schema for adapter context.
|
|
@@ -9284,7 +9438,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9284
9438
|
/**
|
|
9285
9439
|
* Circle Stablecoin Service API Key.
|
|
9286
9440
|
* Must be a valid API key format.
|
|
9287
|
-
*/ apiKey: apiKeySchema
|
|
9441
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9288
9442
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
9289
9443
|
/**
|
|
9290
9444
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -9342,7 +9496,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9342
9496
|
/**
|
|
9343
9497
|
* Circle Stablecoin Service API Key.
|
|
9344
9498
|
* Must be a valid API key format.
|
|
9345
|
-
*/ apiKey: apiKeySchema
|
|
9499
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9346
9500
|
});
|
|
9347
9501
|
/**
|
|
9348
9502
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -9378,7 +9532,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9378
9532
|
toChain: zod.z.string({
|
|
9379
9533
|
invalid_type_error: 'toChain must be a string'
|
|
9380
9534
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
9381
|
-
apiKey: apiKeySchema
|
|
9535
|
+
apiKey: apiKeySchema.optional()
|
|
9382
9536
|
});
|
|
9383
9537
|
/**
|
|
9384
9538
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -9387,13 +9541,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9387
9541
|
required_error: 'fee token is required',
|
|
9388
9542
|
invalid_type_error: 'fee token must be a string'
|
|
9389
9543
|
}).min(1, 'fee token must be a non-empty string'),
|
|
9390
|
-
amount: feeAmountSchema
|
|
9544
|
+
amount: feeAmountSchema,
|
|
9545
|
+
decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
9546
|
+
symbol: zod.z.string({
|
|
9547
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
9548
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
9391
9549
|
});
|
|
9392
9550
|
/**
|
|
9393
9551
|
* Developer fee item schema with basis field.
|
|
9394
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
9395
|
-
token: zod.z.string().min(1, 'fee token must be a non-empty string'),
|
|
9396
|
-
amount: feeAmountSchema,
|
|
9552
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
9397
9553
|
basis: zod.z.enum([
|
|
9398
9554
|
'inputAmount',
|
|
9399
9555
|
'estimatedAmount'
|
|
@@ -9485,7 +9641,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9485
9641
|
addresses: zod.z.array(zod.z.string({
|
|
9486
9642
|
invalid_type_error: 'addresses entries must be strings'
|
|
9487
9643
|
}).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(),
|
|
9488
|
-
apiKey: apiKeySchema
|
|
9644
|
+
apiKey: apiKeySchema.optional()
|
|
9489
9645
|
});
|
|
9490
9646
|
/**
|
|
9491
9647
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -12068,16 +12224,16 @@ new Set(Object.values(Blockchain));
|
|
|
12068
12224
|
|
|
12069
12225
|
new Set(Object.values(Blockchain));
|
|
12070
12226
|
|
|
12071
|
-
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$
|
|
12227
|
+
/** SDK name used in telemetry payloads. */ resolveKitSdkName(pkg$2.name);
|
|
12072
12228
|
|
|
12073
12229
|
// Auto-register this kit for user agent tracking
|
|
12074
|
-
registerKit(`${pkg$
|
|
12230
|
+
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
12075
12231
|
|
|
12076
|
-
var name = "@circle-fin/earn-kit";
|
|
12077
|
-
var version = "1.
|
|
12078
|
-
var pkg = {
|
|
12079
|
-
name: name,
|
|
12080
|
-
version: version};
|
|
12232
|
+
var name$1 = "@circle-fin/earn-kit";
|
|
12233
|
+
var version$1 = "1.3.0";
|
|
12234
|
+
var pkg$1 = {
|
|
12235
|
+
name: name$1,
|
|
12236
|
+
version: version$1};
|
|
12081
12237
|
|
|
12082
12238
|
const EARN_BRIDGE_ERC3009_TOKEN_SYMBOLS = [
|
|
12083
12239
|
'USDC'
|
|
@@ -12541,7 +12697,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12541
12697
|
*
|
|
12542
12698
|
* @param params - Adapter, chain, token/delegate/wallet addresses, the required
|
|
12543
12699
|
* allowance for the signed payload, and a revert message for on-chain failure.
|
|
12544
|
-
* @returns The approval transaction
|
|
12700
|
+
* @returns The approval transaction result when an approval was submitted, or
|
|
12545
12701
|
* `undefined` when the existing allowance already covers `requiredAllowance`
|
|
12546
12702
|
* (or `requiredAllowance` is zero).
|
|
12547
12703
|
* @throws {@link KitError} If the `token.allowance` response is malformed.
|
|
@@ -12549,7 +12705,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12549
12705
|
*
|
|
12550
12706
|
* @example
|
|
12551
12707
|
* ```typescript
|
|
12552
|
-
* const
|
|
12708
|
+
* const approval = await approveAllowanceIfNeeded({
|
|
12553
12709
|
* adapter,
|
|
12554
12710
|
* chain,
|
|
12555
12711
|
* tokenAddress: usdcAddress,
|
|
@@ -12611,7 +12767,15 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12611
12767
|
maxAttempts: params.allowancePropagation?.maxAttempts ?? DEFAULT_PROPAGATION_ATTEMPTS,
|
|
12612
12768
|
delayMs: params.allowancePropagation?.delayMs ?? DEFAULT_PROPAGATION_DELAY_MS
|
|
12613
12769
|
});
|
|
12614
|
-
return
|
|
12770
|
+
return {
|
|
12771
|
+
txHash: approvalTxHash,
|
|
12772
|
+
...approvalReceipt.gasUsed !== undefined && {
|
|
12773
|
+
gasUsed: approvalReceipt.gasUsed
|
|
12774
|
+
},
|
|
12775
|
+
...approvalReceipt.effectiveGasPrice !== undefined && {
|
|
12776
|
+
effectiveGasPrice: approvalReceipt.effectiveGasPrice
|
|
12777
|
+
}
|
|
12778
|
+
};
|
|
12615
12779
|
}
|
|
12616
12780
|
|
|
12617
12781
|
/** @internal */ function isSameAddress(actual, expected) {
|
|
@@ -12759,7 +12923,13 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12759
12923
|
}
|
|
12760
12924
|
return {
|
|
12761
12925
|
txHash,
|
|
12762
|
-
explorerUrl
|
|
12926
|
+
explorerUrl,
|
|
12927
|
+
...receipt.gasUsed !== undefined && {
|
|
12928
|
+
gasUsed: receipt.gasUsed
|
|
12929
|
+
},
|
|
12930
|
+
...receipt.effectiveGasPrice !== undefined && {
|
|
12931
|
+
effectiveGasPrice: receipt.effectiveGasPrice
|
|
12932
|
+
}
|
|
12763
12933
|
};
|
|
12764
12934
|
}
|
|
12765
12935
|
|
|
@@ -13071,112 +13241,6 @@ const EARN_OPERATIONS = new Set([
|
|
|
13071
13241
|
return hasEarnServiceParamsShape(operation, candidate['params']);
|
|
13072
13242
|
}
|
|
13073
13243
|
|
|
13074
|
-
function buildGasFeeBase(name, chain) {
|
|
13075
|
-
return {
|
|
13076
|
-
name,
|
|
13077
|
-
token: chain.nativeCurrency.symbol,
|
|
13078
|
-
blockchain: chain.chain
|
|
13079
|
-
};
|
|
13080
|
-
}
|
|
13081
|
-
function buildGasFeeSuccess(name, chain, fees) {
|
|
13082
|
-
return {
|
|
13083
|
-
...buildGasFeeBase(name, chain),
|
|
13084
|
-
fees
|
|
13085
|
-
};
|
|
13086
|
-
}
|
|
13087
|
-
function buildGasFeeFailure(name, chain, error) {
|
|
13088
|
-
return {
|
|
13089
|
-
...buildGasFeeBase(name, chain),
|
|
13090
|
-
fees: null,
|
|
13091
|
-
error: getErrorMessage(error)
|
|
13092
|
-
};
|
|
13093
|
-
}
|
|
13094
|
-
async function estimatePreparedGasFee(name, chain, prepared) {
|
|
13095
|
-
try {
|
|
13096
|
-
const estimate = bufferEstimatedGas(await prepared.estimate());
|
|
13097
|
-
if (estimate.gas <= 0n) {
|
|
13098
|
-
throw createValidationFailedError('estimate.gas', estimate.gas.toString(), 'gas estimate must be greater than zero');
|
|
13099
|
-
}
|
|
13100
|
-
return buildGasFeeSuccess(name, chain, estimate);
|
|
13101
|
-
} catch (error) {
|
|
13102
|
-
return buildGasFeeFailure(name, chain, error);
|
|
13103
|
-
}
|
|
13104
|
-
}
|
|
13105
|
-
async function estimateApprovalGasFeeIfNeeded(params) {
|
|
13106
|
-
const { adapter, chain, address, tokenAddress, delegate, requiredAllowance } = params;
|
|
13107
|
-
if (requiredAllowance <= 0n) {
|
|
13108
|
-
return undefined;
|
|
13109
|
-
}
|
|
13110
|
-
try {
|
|
13111
|
-
const allowancePrepared = await adapter.prepareAction('token.allowance', {
|
|
13112
|
-
tokenAddress,
|
|
13113
|
-
delegate
|
|
13114
|
-
}, {
|
|
13115
|
-
chain,
|
|
13116
|
-
address
|
|
13117
|
-
});
|
|
13118
|
-
const allowanceRaw = await allowancePrepared.execute();
|
|
13119
|
-
const currentAllowance = parseAllowanceResponse(allowanceRaw);
|
|
13120
|
-
if (currentAllowance >= requiredAllowance) {
|
|
13121
|
-
return undefined;
|
|
13122
|
-
}
|
|
13123
|
-
// Reuse the execute path's approval builder so the estimate simulates the
|
|
13124
|
-
// exact approval (action, amount, and WARM_SLOT_RESIDUAL) that
|
|
13125
|
-
// approveAllowanceIfNeeded later submits.
|
|
13126
|
-
const approvalPrepared = await prepareApprovalAction({
|
|
13127
|
-
adapter,
|
|
13128
|
-
chain,
|
|
13129
|
-
address,
|
|
13130
|
-
tokenAddress,
|
|
13131
|
-
delegate,
|
|
13132
|
-
currentAllowance,
|
|
13133
|
-
requiredAllowance
|
|
13134
|
-
});
|
|
13135
|
-
return await estimatePreparedGasFee('Approve', chain, approvalPrepared);
|
|
13136
|
-
} catch (error) {
|
|
13137
|
-
return buildGasFeeFailure('Approve', chain, error);
|
|
13138
|
-
}
|
|
13139
|
-
}
|
|
13140
|
-
/**
|
|
13141
|
-
* Estimate gas fee entries for an earn quote without submitting transactions.
|
|
13142
|
-
*
|
|
13143
|
-
* Each entry is produced by simulating the prepared transaction against
|
|
13144
|
-
* current chain state. When an approval is required (allowance below the
|
|
13145
|
-
* signed payload's required amount), the subsequent action simulation runs
|
|
13146
|
-
* without that approval in place and is expected to revert — the action entry
|
|
13147
|
-
* then carries `fees: null` with the revert message while the approval entry
|
|
13148
|
-
* still estimates normally. Quote consumers must treat that as "estimate
|
|
13149
|
-
* pending approval", not a hard failure.
|
|
13150
|
-
*
|
|
13151
|
-
* @internal
|
|
13152
|
-
*/ async function estimateEarnQuoteGasFees(params) {
|
|
13153
|
-
const { adapter, chain, address, actionName, actionKey, actionParams, approval } = params;
|
|
13154
|
-
const gasFees = [];
|
|
13155
|
-
if (approval !== undefined) {
|
|
13156
|
-
const approvalEstimate = await estimateApprovalGasFeeIfNeeded({
|
|
13157
|
-
adapter,
|
|
13158
|
-
chain,
|
|
13159
|
-
address,
|
|
13160
|
-
tokenAddress: approval.token,
|
|
13161
|
-
delegate: approval.delegate,
|
|
13162
|
-
requiredAllowance: approval.requiredAllowance
|
|
13163
|
-
});
|
|
13164
|
-
if (approvalEstimate !== undefined) {
|
|
13165
|
-
gasFees.push(approvalEstimate);
|
|
13166
|
-
}
|
|
13167
|
-
}
|
|
13168
|
-
try {
|
|
13169
|
-
const actionPrepared = await adapter.prepareAction(actionKey, actionParams, {
|
|
13170
|
-
chain,
|
|
13171
|
-
address
|
|
13172
|
-
});
|
|
13173
|
-
gasFees.push(await estimatePreparedGasFee(actionName, chain, actionPrepared));
|
|
13174
|
-
} catch (error) {
|
|
13175
|
-
gasFees.push(buildGasFeeFailure(actionName, chain, error));
|
|
13176
|
-
}
|
|
13177
|
-
return gasFees;
|
|
13178
|
-
}
|
|
13179
|
-
|
|
13180
13244
|
// ---------------------------------------------------------------------------
|
|
13181
13245
|
// Shared primitives
|
|
13182
13246
|
// ---------------------------------------------------------------------------
|
|
@@ -13254,7 +13318,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13254
13318
|
asset: zod.z.string(),
|
|
13255
13319
|
assetAddress: zod.z.string(),
|
|
13256
13320
|
lltv: zod.z.number(),
|
|
13257
|
-
supplyUsd: zod.z.number()
|
|
13321
|
+
supplyUsd: zod.z.number(),
|
|
13322
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
13323
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
13324
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
13325
|
+
allocationPct: zod.z.number().nullable().optional()
|
|
13258
13326
|
});
|
|
13259
13327
|
/**
|
|
13260
13328
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -13268,7 +13336,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13268
13336
|
])
|
|
13269
13337
|
});
|
|
13270
13338
|
/**
|
|
13271
|
-
* Zod schema for
|
|
13339
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
13340
|
+
*
|
|
13341
|
+
* @internal
|
|
13342
|
+
*/ const managerSchema = zod.z.object({
|
|
13343
|
+
name: zod.z.string(),
|
|
13344
|
+
address: zod.z.string().optional(),
|
|
13345
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
13346
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
13347
|
+
// speculatively.
|
|
13348
|
+
type: zod.z.enum([
|
|
13349
|
+
'curator'
|
|
13350
|
+
])
|
|
13351
|
+
});
|
|
13352
|
+
/**
|
|
13353
|
+
* Zod schema for the APY profile facet in the API response.
|
|
13354
|
+
*
|
|
13355
|
+
* @internal
|
|
13356
|
+
*/ const apyProfileSchema = zod.z.object({
|
|
13357
|
+
current: zod.z.number(),
|
|
13358
|
+
native: zod.z.number().nullable(),
|
|
13359
|
+
d7: zod.z.number().nullable(),
|
|
13360
|
+
d30: zod.z.number().nullable(),
|
|
13361
|
+
d90: zod.z.number().nullable(),
|
|
13362
|
+
rewardShare: zod.z.number().nullable(),
|
|
13363
|
+
source: zod.z.string().optional(),
|
|
13364
|
+
asOf: zod.z.string().optional()
|
|
13365
|
+
});
|
|
13366
|
+
/**
|
|
13367
|
+
* Zod schema for the fee split facet in the API response.
|
|
13368
|
+
*
|
|
13369
|
+
* @internal
|
|
13370
|
+
*/ const feeInfoSchema = zod.z.object({
|
|
13371
|
+
performance: zod.z.number().nullable(),
|
|
13372
|
+
management: zod.z.number().nullable()
|
|
13373
|
+
});
|
|
13374
|
+
/**
|
|
13375
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
13376
|
+
*
|
|
13377
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
13378
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
13379
|
+
*
|
|
13380
|
+
* @internal
|
|
13381
|
+
*/ const liquidityProfileSchema = zod.z.object({
|
|
13382
|
+
totalDeposits: amountJsonSchema,
|
|
13383
|
+
available: amountJsonSchema,
|
|
13384
|
+
totalSupply: amountJsonSchema,
|
|
13385
|
+
status: zod.z.enum([
|
|
13386
|
+
'active',
|
|
13387
|
+
'low_liquidity'
|
|
13388
|
+
])
|
|
13389
|
+
});
|
|
13390
|
+
/**
|
|
13391
|
+
* Zod schema for the risk signals facet in the API response.
|
|
13392
|
+
*
|
|
13393
|
+
* @internal
|
|
13394
|
+
*/ const riskSignalsSchema = zod.z.object({
|
|
13395
|
+
circleSentinel: zod.z.boolean(),
|
|
13396
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
13397
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
13398
|
+
});
|
|
13399
|
+
/**
|
|
13400
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
13401
|
+
*
|
|
13402
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
13403
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
13404
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
13405
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
13406
|
+
* backend; they become required after Expand ships.
|
|
13272
13407
|
*
|
|
13273
13408
|
* @internal
|
|
13274
13409
|
*/ const vaultInfoResponseSchema = zod.z.object({
|
|
@@ -13293,6 +13428,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13293
13428
|
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
13294
13429
|
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
13295
13430
|
});
|
|
13431
|
+
/**
|
|
13432
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
13433
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
13434
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
13435
|
+
*
|
|
13436
|
+
* @internal
|
|
13437
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
13438
|
+
address: zod.z.string().optional(),
|
|
13439
|
+
asOf: zod.z.string().optional(),
|
|
13440
|
+
manager: managerSchema.nullable().optional(),
|
|
13441
|
+
apyProfile: apyProfileSchema.optional(),
|
|
13442
|
+
fee: feeInfoSchema.optional(),
|
|
13443
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
13444
|
+
riskSignals: riskSignalsSchema.optional()
|
|
13445
|
+
});
|
|
13446
|
+
/**
|
|
13447
|
+
* Zod schema for the `vault` opportunity variant.
|
|
13448
|
+
*
|
|
13449
|
+
* @internal
|
|
13450
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
13451
|
+
productType: zod.z.literal('vault'),
|
|
13452
|
+
collateral: zod.z.array(collateralSchema)
|
|
13453
|
+
});
|
|
13454
|
+
/**
|
|
13455
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
13456
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
13457
|
+
*
|
|
13458
|
+
* @internal
|
|
13459
|
+
*/ const earnOpportunityVariants = [
|
|
13460
|
+
vaultOpportunitySchema
|
|
13461
|
+
];
|
|
13462
|
+
/** @internal */ const earnOpportunitySchema = zod.z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
13463
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
13464
|
+
/**
|
|
13465
|
+
* Tolerant list parser for earn opportunities.
|
|
13466
|
+
*
|
|
13467
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
13468
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
13469
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
13470
|
+
*
|
|
13471
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
13472
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
13473
|
+
* rather than dropping every vault the backend returns.
|
|
13474
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
13475
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
13476
|
+
* of rejecting the whole list.
|
|
13477
|
+
*
|
|
13478
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
13479
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
13480
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
13481
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
13482
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
13483
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
13484
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
13485
|
+
* `ZodError`).
|
|
13486
|
+
*
|
|
13487
|
+
* @internal
|
|
13488
|
+
*/ const earnOpportunityListSchema = zod.z.preprocess((raw)=>{
|
|
13489
|
+
if (!Array.isArray(raw)) {
|
|
13490
|
+
return raw;
|
|
13491
|
+
}
|
|
13492
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
13493
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
13494
|
+
const entries = raw;
|
|
13495
|
+
return entries.map((entry)=>{
|
|
13496
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
13497
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
13498
|
+
return entry;
|
|
13499
|
+
}
|
|
13500
|
+
const record = entry;
|
|
13501
|
+
// Older backend predating productType: default to the only type then.
|
|
13502
|
+
return record.productType === undefined ? {
|
|
13503
|
+
...record,
|
|
13504
|
+
productType: 'vault'
|
|
13505
|
+
} : record;
|
|
13506
|
+
}).filter((entry)=>{
|
|
13507
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
13508
|
+
// productType this SDK version doesn't know). Everything else —
|
|
13509
|
+
// non-objects, a non-string productType — flows through to
|
|
13510
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
13511
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
13512
|
+
return true;
|
|
13513
|
+
}
|
|
13514
|
+
const productType = entry.productType;
|
|
13515
|
+
if (typeof productType !== 'string') {
|
|
13516
|
+
return true;
|
|
13517
|
+
}
|
|
13518
|
+
return knownProductTypes.has(productType);
|
|
13519
|
+
});
|
|
13520
|
+
}, zod.z.array(earnOpportunitySchema));
|
|
13296
13521
|
// ---------------------------------------------------------------------------
|
|
13297
13522
|
// Position response schema
|
|
13298
13523
|
// ---------------------------------------------------------------------------
|
|
@@ -13422,6 +13647,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
|
13422
13647
|
*
|
|
13423
13648
|
* @internal
|
|
13424
13649
|
*/ const depositPayloadSchema = zod.z.object({
|
|
13650
|
+
execId: bridgeDepositExecIdSchema,
|
|
13425
13651
|
executionParams: depositExecutionParamsSchema,
|
|
13426
13652
|
signature: hexSignatureSchema
|
|
13427
13653
|
});
|
|
@@ -13513,6 +13739,21 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13513
13739
|
amount: amountJsonSchema,
|
|
13514
13740
|
vaultAddress: hexAddressSchema
|
|
13515
13741
|
}).passthrough();
|
|
13742
|
+
/** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
|
|
13743
|
+
zod.z.object({
|
|
13744
|
+
mode: zod.z.literal('TIMESTAMP'),
|
|
13745
|
+
expiresAt: zod.z.string().datetime({
|
|
13746
|
+
offset: true
|
|
13747
|
+
})
|
|
13748
|
+
}),
|
|
13749
|
+
zod.z.object({
|
|
13750
|
+
mode: zod.z.literal('BLOCK_NUMBER'),
|
|
13751
|
+
expiresAtBlock: zod.z.number().int(),
|
|
13752
|
+
blockEstimatedAt: zod.z.string().datetime({
|
|
13753
|
+
offset: true
|
|
13754
|
+
}).optional()
|
|
13755
|
+
})
|
|
13756
|
+
]).optional().catch(undefined);
|
|
13516
13757
|
/**
|
|
13517
13758
|
* Zod schema for the bridge deposit prepare payload.
|
|
13518
13759
|
*
|
|
@@ -13524,6 +13765,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13524
13765
|
execId: bridgeDepositExecIdSchema,
|
|
13525
13766
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
13526
13767
|
expiresAt: zod.z.string().datetime(),
|
|
13768
|
+
quoteIssuedAt: zod.z.string().datetime({
|
|
13769
|
+
offset: true
|
|
13770
|
+
}).optional().catch(undefined),
|
|
13771
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
13527
13772
|
review: bridgeDepositPrepareReviewSchema
|
|
13528
13773
|
});
|
|
13529
13774
|
/**
|
|
@@ -13589,6 +13834,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13589
13834
|
*
|
|
13590
13835
|
* @internal
|
|
13591
13836
|
*/ const withdrawPayloadSchema = zod.z.object({
|
|
13837
|
+
execId: bridgeDepositExecIdSchema,
|
|
13592
13838
|
executionParams: withdrawExecutionParamsSchema,
|
|
13593
13839
|
signature: hexSignatureSchema
|
|
13594
13840
|
});
|
|
@@ -13602,6 +13848,27 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13602
13848
|
data: withdrawPayloadSchema
|
|
13603
13849
|
});
|
|
13604
13850
|
// ---------------------------------------------------------------------------
|
|
13851
|
+
// Transaction report response schema
|
|
13852
|
+
// ---------------------------------------------------------------------------
|
|
13853
|
+
/**
|
|
13854
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
13855
|
+
*
|
|
13856
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
13857
|
+
* schema accepts any object shape and does not require specific fields.
|
|
13858
|
+
*
|
|
13859
|
+
* @internal
|
|
13860
|
+
*/ const transactionReportPayloadSchema = zod.z.object({}).passthrough();
|
|
13861
|
+
/**
|
|
13862
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
13863
|
+
*
|
|
13864
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
13865
|
+
* envelope.
|
|
13866
|
+
*
|
|
13867
|
+
* @internal
|
|
13868
|
+
*/ const transactionReportResponseSchema = zod.z.object({
|
|
13869
|
+
data: transactionReportPayloadSchema
|
|
13870
|
+
});
|
|
13871
|
+
// ---------------------------------------------------------------------------
|
|
13605
13872
|
// Claim rewards response schema
|
|
13606
13873
|
// ---------------------------------------------------------------------------
|
|
13607
13874
|
/**
|
|
@@ -13649,10 +13916,11 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13649
13916
|
* Zod schema for a fee entry in an EarnKit API response.
|
|
13650
13917
|
*
|
|
13651
13918
|
* Shared across deposit and withdrawal responses (and reusable for real
|
|
13652
|
-
* charged fees, not just quote estimates). `type` identifies the fee category
|
|
13653
|
-
*
|
|
13654
|
-
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`).
|
|
13655
|
-
* `'
|
|
13919
|
+
* charged fees, not just quote estimates). `type` identifies the fee category.
|
|
13920
|
+
* For cross-chain deposit quotes this is the kits-proxy fee-quote item type
|
|
13921
|
+
* (e.g. `'FORWARD'`, `'PRE_FINALITY'`). For withdrawal quotes, Circle fees use
|
|
13922
|
+
* `type: 'circle'`. `status` qualifies the fee (e.g. `'estimated'` for a
|
|
13923
|
+
* pre-sign cross-chain fee). Both are omitted on plain fees.
|
|
13656
13924
|
*
|
|
13657
13925
|
* @internal
|
|
13658
13926
|
*/ const feeSchema = zod.z.object({
|
|
@@ -13661,6 +13929,30 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13661
13929
|
token: zod.z.string(),
|
|
13662
13930
|
amount: amountJsonSchema
|
|
13663
13931
|
});
|
|
13932
|
+
/**
|
|
13933
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
13934
|
+
*
|
|
13935
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
13936
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
13937
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
13938
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
13939
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
13940
|
+
*
|
|
13941
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
13942
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
13943
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
13944
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
13945
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
13946
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
13947
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
13948
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
13949
|
+
*
|
|
13950
|
+
* @internal
|
|
13951
|
+
*/ const quoteGasFeeSchema = zod.z.object({
|
|
13952
|
+
name: zod.z.string().optional(),
|
|
13953
|
+
fees: zod.z.unknown(),
|
|
13954
|
+
error: zod.z.string().optional()
|
|
13955
|
+
}).passthrough();
|
|
13664
13956
|
/**
|
|
13665
13957
|
* Zod schema for the inner deposit quote payload.
|
|
13666
13958
|
*
|
|
@@ -13676,7 +13968,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13676
13968
|
expectedShares: amountJsonSchema,
|
|
13677
13969
|
sharePrice: zod.z.string(),
|
|
13678
13970
|
currentApy: zod.z.number(),
|
|
13679
|
-
fees: zod.z.array(feeSchema).optional()
|
|
13971
|
+
fees: zod.z.array(feeSchema).optional(),
|
|
13972
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional()
|
|
13680
13973
|
});
|
|
13681
13974
|
/**
|
|
13682
13975
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -13703,6 +13996,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13703
13996
|
sharePrice: zod.z.string(),
|
|
13704
13997
|
maxWithdrawable: amountJsonSchema,
|
|
13705
13998
|
fees: zod.z.array(feeSchema),
|
|
13999
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional(),
|
|
13706
14000
|
warnings: zod.z.array(zod.z.string()).optional()
|
|
13707
14001
|
});
|
|
13708
14002
|
/**
|
|
@@ -13760,7 +14054,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13760
14054
|
*
|
|
13761
14055
|
* @internal
|
|
13762
14056
|
*/ const getVaultsPayloadSchema = zod.z.object({
|
|
13763
|
-
vaults:
|
|
14057
|
+
vaults: earnOpportunityListSchema,
|
|
13764
14058
|
errors: zod.z.array(vaultErrorSchema)
|
|
13765
14059
|
});
|
|
13766
14060
|
/**
|
|
@@ -13790,7 +14084,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13790
14084
|
*
|
|
13791
14085
|
* @internal
|
|
13792
14086
|
*/ const exploreVaultsPayloadSchema = zod.z.object({
|
|
13793
|
-
vaults:
|
|
14087
|
+
vaults: earnOpportunityListSchema,
|
|
13794
14088
|
pagination: explorePaginationSchema
|
|
13795
14089
|
});
|
|
13796
14090
|
/**
|
|
@@ -13883,6 +14177,16 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13883
14177
|
*/ function isWithdrawResponse(value) {
|
|
13884
14178
|
return withdrawResponseSchema.safeParse(value).success;
|
|
13885
14179
|
}
|
|
14180
|
+
/**
|
|
14181
|
+
* Type guard for the transaction report API response.
|
|
14182
|
+
*
|
|
14183
|
+
* @param value - Unknown response value to validate
|
|
14184
|
+
* @returns True when the value matches the transaction report response shape
|
|
14185
|
+
*
|
|
14186
|
+
* @internal
|
|
14187
|
+
*/ function isTransactionReportResponse(value) {
|
|
14188
|
+
return transactionReportResponseSchema.safeParse(value).success;
|
|
14189
|
+
}
|
|
13886
14190
|
/**
|
|
13887
14191
|
* Type guard for the claim rewards API response.
|
|
13888
14192
|
*
|
|
@@ -13924,19 +14228,80 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13924
14228
|
return claimRewardsQuoteResponseSchema.safeParse(value).success;
|
|
13925
14229
|
}
|
|
13926
14230
|
|
|
14231
|
+
var name = "@circle-fin/provider-earn-service";
|
|
14232
|
+
var version = "1.3.0";
|
|
14233
|
+
var pkg = {
|
|
14234
|
+
name: name,
|
|
14235
|
+
version: version};
|
|
14236
|
+
|
|
13927
14237
|
/**
|
|
13928
|
-
*
|
|
13929
|
-
* and resolve the base URL (configurable for testing).
|
|
13930
|
-
*
|
|
13931
|
-
* @param serviceConfig - Optional earn service configuration
|
|
13932
|
-
* @returns Resolved polling config and base URL
|
|
14238
|
+
* HTTP header name used to report the EarnKit SDK version to the backend.
|
|
13933
14239
|
*
|
|
13934
14240
|
* @internal
|
|
13935
|
-
*/
|
|
13936
|
-
|
|
13937
|
-
|
|
14241
|
+
*/ const SDK_VERSION_HEADER = 'X-EarnKit-SDK-Version';
|
|
14242
|
+
/**
|
|
14243
|
+
* Resolve the SDK version string from its source components.
|
|
14244
|
+
*
|
|
14245
|
+
* Resolution order:
|
|
14246
|
+
* 1. The registered kit identifier (preferred) — e.g. `@circle-fin/earn-kit/1.1.0`
|
|
14247
|
+
* becomes `earn-kit/1.1.0`.
|
|
14248
|
+
* 2. The provider package itself (fallback when no kit is registered) —
|
|
14249
|
+
* e.g. `provider-earn-service/1.1.0`.
|
|
14250
|
+
* 3. The literal `unknown` when neither source is available.
|
|
14251
|
+
*
|
|
14252
|
+
* Kept as a pure function (no global / module reads) so every branch is
|
|
14253
|
+
* unit-testable.
|
|
14254
|
+
*
|
|
14255
|
+
* @param kitId - The registered kit identifier, or `undefined`.
|
|
14256
|
+
* @param providerName - The provider package name (e.g. `@circle-fin/provider-earn-service`).
|
|
14257
|
+
* @param providerVersion - The provider package version, or `undefined`.
|
|
14258
|
+
* @returns The formatted SDK version string.
|
|
14259
|
+
*
|
|
14260
|
+
* @internal
|
|
14261
|
+
*/ function formatSdkVersion(kitId, providerName, providerVersion) {
|
|
14262
|
+
if (kitId !== undefined && kitId !== '') {
|
|
14263
|
+
// e.g. '@circle-fin/earn-kit/1.1.0' -> 'earn-kit/1.1.0'
|
|
14264
|
+
return resolveKitSdkName(kitId);
|
|
14265
|
+
}
|
|
14266
|
+
{
|
|
14267
|
+
// e.g. '@circle-fin/provider-earn-service' + '1.1.0' -> 'provider-earn-service/1.1.0'
|
|
14268
|
+
return `${resolveKitSdkName(providerName)}/${providerVersion}`;
|
|
14269
|
+
}
|
|
14270
|
+
}
|
|
14271
|
+
/**
|
|
14272
|
+
* Resolve the value for the {@link SDK_VERSION_HEADER} header.
|
|
14273
|
+
*
|
|
14274
|
+
* Reads the kit registered at runtime via {@link createRequestContext} and
|
|
14275
|
+
* falls back to this provider package's own version when no kit is registered.
|
|
14276
|
+
*
|
|
14277
|
+
* @returns The SDK version string, e.g. `earn-kit/1.1.0` or
|
|
14278
|
+
* `provider-earn-service/1.1.0`, or `unknown`.
|
|
14279
|
+
*
|
|
14280
|
+
* @internal
|
|
14281
|
+
*/ function resolveSdkVersionHeader() {
|
|
14282
|
+
return formatSdkVersion(createRequestContext().kit, pkg.name, pkg.version);
|
|
14283
|
+
}
|
|
14284
|
+
|
|
14285
|
+
/**
|
|
14286
|
+
* Build an API polling config with optional authorization header,
|
|
14287
|
+
* and resolve the base URL (configurable for testing).
|
|
14288
|
+
*
|
|
14289
|
+
* @param serviceConfig - Optional earn service configuration
|
|
14290
|
+
* @returns Resolved polling config and base URL
|
|
14291
|
+
*
|
|
14292
|
+
* @internal
|
|
14293
|
+
*/ function buildConfig(serviceConfig) {
|
|
14294
|
+
const baseUrl = serviceConfig?.baseUrl ?? EARN_SERVICE_BASE_URL;
|
|
14295
|
+
const sdkVersion = resolveSdkVersionHeader();
|
|
14296
|
+
if (serviceConfig?.kitKey === undefined) {
|
|
13938
14297
|
return {
|
|
13939
|
-
pollingConfig:
|
|
14298
|
+
pollingConfig: {
|
|
14299
|
+
...DEFAULT_CONFIG,
|
|
14300
|
+
headers: {
|
|
14301
|
+
...DEFAULT_CONFIG.headers,
|
|
14302
|
+
[SDK_VERSION_HEADER]: sdkVersion
|
|
14303
|
+
}
|
|
14304
|
+
},
|
|
13940
14305
|
baseUrl
|
|
13941
14306
|
};
|
|
13942
14307
|
}
|
|
@@ -13952,6 +14317,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13952
14317
|
...DEFAULT_CONFIG,
|
|
13953
14318
|
headers: {
|
|
13954
14319
|
...DEFAULT_CONFIG.headers,
|
|
14320
|
+
[SDK_VERSION_HEADER]: sdkVersion,
|
|
13955
14321
|
Authorization: `Bearer ${serviceConfig.kitKey}`
|
|
13956
14322
|
}
|
|
13957
14323
|
},
|
|
@@ -13983,7 +14349,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13983
14349
|
}
|
|
13984
14350
|
|
|
13985
14351
|
/**
|
|
13986
|
-
* Convert an API vault info object into the SDK {@link
|
|
14352
|
+
* Convert an API vault info object into the SDK {@link EarnOpportunity} shape.
|
|
13987
14353
|
*
|
|
13988
14354
|
* Map the API chain code back to the SDK chain identifier and hydrate the
|
|
13989
14355
|
* amount payloads into {@link Amount} instances.
|
|
@@ -13994,16 +14360,29 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13994
14360
|
*
|
|
13995
14361
|
* @internal
|
|
13996
14362
|
*/ function toVaultInfo(data) {
|
|
13997
|
-
const { totalDeposits, liquidity, ...vault } = data;
|
|
14363
|
+
const { totalDeposits, liquidity, liquidityProfile, ...vault } = data;
|
|
13998
14364
|
const chain = toSdkChain(vault.chain);
|
|
13999
14365
|
if (chain === undefined) {
|
|
14000
14366
|
throw createInvalidChainError(vault.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
14001
14367
|
}
|
|
14368
|
+
// The nested facets are `.optional()` in the schema (a backend that predates
|
|
14369
|
+
// them omits them) and are typed optional on `EarnOpportunity` to match.
|
|
14370
|
+
// Convert the nested liquidity amounts when present and pass the remaining
|
|
14371
|
+
// facets straight through; each absent facet stays absent rather than being
|
|
14372
|
+
// asserted present by a cast.
|
|
14002
14373
|
return {
|
|
14003
14374
|
...vault,
|
|
14004
14375
|
chain,
|
|
14005
14376
|
totalDeposits: Amount.fromJSON(totalDeposits),
|
|
14006
|
-
liquidity: Amount.fromJSON(liquidity)
|
|
14377
|
+
liquidity: Amount.fromJSON(liquidity),
|
|
14378
|
+
...liquidityProfile !== undefined && {
|
|
14379
|
+
liquidityProfile: {
|
|
14380
|
+
...liquidityProfile,
|
|
14381
|
+
totalDeposits: Amount.fromJSON(liquidityProfile.totalDeposits),
|
|
14382
|
+
available: Amount.fromJSON(liquidityProfile.available),
|
|
14383
|
+
totalSupply: Amount.fromJSON(liquidityProfile.totalSupply)
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14007
14386
|
};
|
|
14008
14387
|
}
|
|
14009
14388
|
|
|
@@ -14038,8 +14417,11 @@ function toVaultError(error) {
|
|
|
14038
14417
|
}
|
|
14039
14418
|
try {
|
|
14040
14419
|
const response = await pollApiGet(url.toString(), isGetVaultsResponse, pollingConfig);
|
|
14420
|
+
// `pollApiGet` validates via a boolean guard and returns the raw JSON — it
|
|
14421
|
+
// does not run the schema's preprocess. Parse explicitly so unknown
|
|
14422
|
+
// `productType` values are dropped before `toVaultInfo`.
|
|
14041
14423
|
return {
|
|
14042
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14424
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14043
14425
|
errors: response.data.errors.map(toVaultError)
|
|
14044
14426
|
};
|
|
14045
14427
|
} catch (error) {
|
|
@@ -14088,8 +14470,11 @@ function toVaultError(error) {
|
|
|
14088
14470
|
}
|
|
14089
14471
|
try {
|
|
14090
14472
|
const response = await pollApiGet(url.toString(), isExploreVaultsResponse, pollingConfig);
|
|
14473
|
+
// `pollApiGet` validates via a boolean guard and returns the raw JSON — it
|
|
14474
|
+
// does not run the schema's preprocess. Parse explicitly so unknown
|
|
14475
|
+
// `productType` values are dropped before `toVaultInfo`.
|
|
14091
14476
|
return {
|
|
14092
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14477
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14093
14478
|
pagination: response.data.pagination
|
|
14094
14479
|
};
|
|
14095
14480
|
} catch (error) {
|
|
@@ -14253,6 +14638,12 @@ function toPositionInfo(data) {
|
|
|
14253
14638
|
execId: response.data.execId,
|
|
14254
14639
|
preparedBundle,
|
|
14255
14640
|
expiresAt: response.data.expiresAt,
|
|
14641
|
+
...response.data.quoteIssuedAt !== undefined && {
|
|
14642
|
+
quoteIssuedAt: response.data.quoteIssuedAt
|
|
14643
|
+
},
|
|
14644
|
+
...response.data.quoteExpiry !== undefined && {
|
|
14645
|
+
quoteExpiry: response.data.quoteExpiry
|
|
14646
|
+
},
|
|
14256
14647
|
review: response.data.review
|
|
14257
14648
|
};
|
|
14258
14649
|
} catch (error) {
|
|
@@ -14594,7 +14985,110 @@ function toClaimedAmount(reward) {
|
|
|
14594
14985
|
}
|
|
14595
14986
|
}
|
|
14596
14987
|
|
|
14597
|
-
|
|
14988
|
+
/**
|
|
14989
|
+
* Map the Earn Service's server-side quote gas estimates into the SDK
|
|
14990
|
+
* {@link EarnGasFeeEstimate} shape.
|
|
14991
|
+
*
|
|
14992
|
+
* The Earn Service estimates gas for each action (`Approve`, `Deposit`,
|
|
14993
|
+
* `Withdraw`) and returns `{ name, fees: { gas, gasPrice, fee } }` with raw
|
|
14994
|
+
* integer strings.
|
|
14995
|
+
* The SDK type additionally carries `token` (the chain's native currency
|
|
14996
|
+
* symbol) and `blockchain`, which are filled in here from the chain
|
|
14997
|
+
* definition.
|
|
14998
|
+
*
|
|
14999
|
+
* Gas reporting is best-effort: a malformed entry (e.g. a non-integer string
|
|
15000
|
+
* that fails `BigInt` parsing) degrades to a `{ fees: null, error }` estimate
|
|
15001
|
+
* rather than throwing, so one bad entry never fails the whole quote.
|
|
15002
|
+
*
|
|
15003
|
+
* @param gasFees - Backend gas-fee entries from the quote response, if any.
|
|
15004
|
+
* @param chain - Chain definition, used for the native token symbol and
|
|
15005
|
+
* blockchain identifier.
|
|
15006
|
+
* @returns One {@link EarnGasFeeEstimate} per backend entry (empty when the
|
|
15007
|
+
* backend returned none).
|
|
15008
|
+
*
|
|
15009
|
+
* @example
|
|
15010
|
+
* ```typescript
|
|
15011
|
+
* toQuoteGasFees(
|
|
15012
|
+
* [{ name: 'Deposit', fees: { gas: '364142', gasPrice: '21000000000', fee: '7646982000000000' } }],
|
|
15013
|
+
* arcTestnet,
|
|
15014
|
+
* )
|
|
15015
|
+
* // [{ name: 'Deposit', token: 'USDC', blockchain: 'Arc_Testnet',
|
|
15016
|
+
* // fees: { gas: 364142n, gasPrice: 21000000000n, fee: '7646982000000000' } }]
|
|
15017
|
+
* ```
|
|
15018
|
+
*
|
|
15019
|
+
* @internal
|
|
15020
|
+
*/ function toQuoteGasFees(gasFees, chain) {
|
|
15021
|
+
if (gasFees === undefined) {
|
|
15022
|
+
return [];
|
|
15023
|
+
}
|
|
15024
|
+
return gasFees.map((entry)=>{
|
|
15025
|
+
const base = {
|
|
15026
|
+
// `name` is optional on the wire; label an unnamed entry rather than
|
|
15027
|
+
// emitting `name: undefined`.
|
|
15028
|
+
name: entry.name ?? 'Unknown',
|
|
15029
|
+
token: chain.nativeCurrency.symbol,
|
|
15030
|
+
blockchain: chain.chain
|
|
15031
|
+
};
|
|
15032
|
+
// The Earn Service itself reports a failed estimate as `fees: null` with
|
|
15033
|
+
// an error; propagate that soft failure verbatim.
|
|
15034
|
+
if (entry.fees === null || entry.fees === undefined) {
|
|
15035
|
+
return {
|
|
15036
|
+
...base,
|
|
15037
|
+
fees: null,
|
|
15038
|
+
error: entry.error ?? 'gas estimate unavailable'
|
|
15039
|
+
};
|
|
15040
|
+
}
|
|
15041
|
+
// `fees` is `unknown` at the schema layer, so ALL validation happens here:
|
|
15042
|
+
// that it is an object at all, and that `gas`, `gasPrice`, and `fee` are
|
|
15043
|
+
// each parseable integer strings (including `fee`, which the SDK contract
|
|
15044
|
+
// requires be a numeric base-unit string). Any failure — a wrong type
|
|
15045
|
+
// (`fees: 123`), a missing field, or a non-numeric value — degrades the
|
|
15046
|
+
// whole entry to a `fees: null` soft failure rather than surfacing a
|
|
15047
|
+
// malformed "successful" estimate or rejecting the quote.
|
|
15048
|
+
try {
|
|
15049
|
+
if (typeof entry.fees !== 'object') {
|
|
15050
|
+
throw new TypeError(`gas fees must be an object (got ${typeof entry.fees})`);
|
|
15051
|
+
}
|
|
15052
|
+
const { gas, gasPrice, fee } = entry.fees;
|
|
15053
|
+
return {
|
|
15054
|
+
...base,
|
|
15055
|
+
fees: {
|
|
15056
|
+
gas: toBigInt('gas', gas),
|
|
15057
|
+
gasPrice: toBigInt('gasPrice', gasPrice),
|
|
15058
|
+
fee: toBigInt('fee', fee).toString()
|
|
15059
|
+
}
|
|
15060
|
+
};
|
|
15061
|
+
} catch (error) {
|
|
15062
|
+
return {
|
|
15063
|
+
...base,
|
|
15064
|
+
fees: null,
|
|
15065
|
+
error: getErrorMessage(error)
|
|
15066
|
+
};
|
|
15067
|
+
}
|
|
15068
|
+
});
|
|
15069
|
+
}
|
|
15070
|
+
/**
|
|
15071
|
+
* Parse an unknown value into a `bigint`, rejecting anything that is not a
|
|
15072
|
+
* non-empty integer string. `BigInt` alone is too permissive for this path —
|
|
15073
|
+
* it accepts numbers, booleans, and empty strings — so guard the type first.
|
|
15074
|
+
*
|
|
15075
|
+
* @param field - Field name, used in the thrown error message.
|
|
15076
|
+
* @param value - Raw value from the backend gas entry.
|
|
15077
|
+
* @returns The parsed `bigint`.
|
|
15078
|
+
* @throws {TypeError} When `value` is not a non-empty integer string.
|
|
15079
|
+
*/ function toBigInt(field, value) {
|
|
15080
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
15081
|
+
throw new TypeError(`gas fee field "${field}" must be an integer string`);
|
|
15082
|
+
}
|
|
15083
|
+
try {
|
|
15084
|
+
// BigInt throws on non-integer strings (e.g. "1.5", "not-a-number").
|
|
15085
|
+
return BigInt(value);
|
|
15086
|
+
} catch {
|
|
15087
|
+
throw new Error(`gas fee field "${field}" is not a valid integer string: ${value}`);
|
|
15088
|
+
}
|
|
15089
|
+
}
|
|
15090
|
+
|
|
15091
|
+
function toDepositQuoteInfo(data, chain) {
|
|
14598
15092
|
const fees = (data.fees ?? []).map(({ token: feeTokenSymbol, ...fee })=>{
|
|
14599
15093
|
// Earn Service returns fee.token as a display symbol, for example "USDC".
|
|
14600
15094
|
return {
|
|
@@ -14623,7 +15117,10 @@ function toDepositQuoteInfo(data) {
|
|
|
14623
15117
|
sharePrice: data.sharePrice,
|
|
14624
15118
|
currentApy: data.currentApy,
|
|
14625
15119
|
fees,
|
|
14626
|
-
|
|
15120
|
+
// The Earn Service estimates gas server-side; the chain fills token/blockchain.
|
|
15121
|
+
// Cross-chain quotes resolve no local chain definition, so gasFees stays
|
|
15122
|
+
// empty there (unchanged behavior).
|
|
15123
|
+
gasFees: chain === undefined ? [] : toQuoteGasFees(data.gasFees, chain)
|
|
14627
15124
|
};
|
|
14628
15125
|
}
|
|
14629
15126
|
/**
|
|
@@ -14658,7 +15155,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14658
15155
|
};
|
|
14659
15156
|
try {
|
|
14660
15157
|
const response = await pollApiPost(url.toString(), requestBody, isDepositQuoteResponse, pollingConfig);
|
|
14661
|
-
return toDepositQuoteInfo(response.data);
|
|
15158
|
+
return toDepositQuoteInfo(response.data, params.chainDefinition);
|
|
14662
15159
|
} catch (error) {
|
|
14663
15160
|
throw parseEarnApiError(error, {
|
|
14664
15161
|
operation: 'getDepositQuote'
|
|
@@ -14666,7 +15163,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14666
15163
|
}
|
|
14667
15164
|
}
|
|
14668
15165
|
|
|
14669
|
-
function toWithdrawalQuoteInfo(data) {
|
|
15166
|
+
function toWithdrawalQuoteInfo(data, chain) {
|
|
14670
15167
|
return {
|
|
14671
15168
|
vaultAddress: data.vaultAddress,
|
|
14672
15169
|
vaultName: data.vaultName,
|
|
@@ -14684,11 +15181,17 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14684
15181
|
symbol: data.asset,
|
|
14685
15182
|
amount: Amount.fromJSON(data.maxWithdrawable)
|
|
14686
15183
|
},
|
|
14687
|
-
fees: data.fees.map((
|
|
14688
|
-
symbol:
|
|
14689
|
-
amount: Amount.fromJSON(
|
|
15184
|
+
fees: data.fees.map(({ token, amount, type, status })=>({
|
|
15185
|
+
symbol: token,
|
|
15186
|
+
amount: Amount.fromJSON(amount),
|
|
15187
|
+
...type !== undefined && {
|
|
15188
|
+
type
|
|
15189
|
+
},
|
|
15190
|
+
...status !== undefined && {
|
|
15191
|
+
status
|
|
15192
|
+
}
|
|
14690
15193
|
})),
|
|
14691
|
-
gasFees: [],
|
|
15194
|
+
gasFees: chain === undefined ? [] : toQuoteGasFees(data.gasFees, chain),
|
|
14692
15195
|
// Wire format uses `warnings`, but the SDK surface uses
|
|
14693
15196
|
// `earnKitWarnings` to match the precedent set by `VaultInfo` —
|
|
14694
15197
|
// `warnings` is reserved for the structured `VaultWarning` shape.
|
|
@@ -14720,7 +15223,7 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14720
15223
|
};
|
|
14721
15224
|
try {
|
|
14722
15225
|
const response = await pollApiPost(url.toString(), requestBody, isWithdrawalQuoteResponse, pollingConfig);
|
|
14723
|
-
return toWithdrawalQuoteInfo(response.data);
|
|
15226
|
+
return toWithdrawalQuoteInfo(response.data, params.chainDefinition);
|
|
14724
15227
|
} catch (error) {
|
|
14725
15228
|
throw parseEarnApiError(error, {
|
|
14726
15229
|
operation: 'getWithdrawalQuote'
|
|
@@ -14756,6 +15259,8 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14756
15259
|
amount: Amount.fromJSON(r.amount),
|
|
14757
15260
|
address: r.token
|
|
14758
15261
|
})),
|
|
15262
|
+
// The claimRewards/quote response does not carry a gas estimate (unlike
|
|
15263
|
+
// deposit/withdrawal quotes), so there is nothing to surface here.
|
|
14759
15264
|
gasFees: []
|
|
14760
15265
|
};
|
|
14761
15266
|
} catch (error) {
|
|
@@ -14765,6 +15270,83 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14765
15270
|
}
|
|
14766
15271
|
}
|
|
14767
15272
|
|
|
15273
|
+
/**
|
|
15274
|
+
* Build the native gas triple the backend expects for `gasUsed`.
|
|
15275
|
+
*
|
|
15276
|
+
* Returns `undefined` unless both receipt components are present, so the
|
|
15277
|
+
* caller can omit the field entirely — the Earn Service treats a missing
|
|
15278
|
+
* triple as "skip the gas cache write, still return 200".
|
|
15279
|
+
*
|
|
15280
|
+
* @param gasUsed - Receipt gas units used.
|
|
15281
|
+
* @param effectiveGasPrice - Receipt effective gas price.
|
|
15282
|
+
* @returns The `{ gas, gasPrice, fee }` triple, or `undefined` when either
|
|
15283
|
+
* component is missing.
|
|
15284
|
+
*
|
|
15285
|
+
* @example
|
|
15286
|
+
* ```typescript
|
|
15287
|
+
* buildReportedGasUsed(362454n, 29466364605n)
|
|
15288
|
+
* // { gas: '362454', gasPrice: '29466364605', fee: '10680201716540670' }
|
|
15289
|
+
* ```
|
|
15290
|
+
*
|
|
15291
|
+
* @internal
|
|
15292
|
+
*/ function buildReportedGasUsed(gasUsed, effectiveGasPrice) {
|
|
15293
|
+
if (gasUsed === undefined || effectiveGasPrice === undefined) {
|
|
15294
|
+
return undefined;
|
|
15295
|
+
}
|
|
15296
|
+
return {
|
|
15297
|
+
gas: gasUsed.toString(),
|
|
15298
|
+
gasPrice: effectiveGasPrice.toString(),
|
|
15299
|
+
fee: (gasUsed * effectiveGasPrice).toString()
|
|
15300
|
+
};
|
|
15301
|
+
}
|
|
15302
|
+
/**
|
|
15303
|
+
* Report the outcome of an SDK-submitted same-chain Earn transaction.
|
|
15304
|
+
*
|
|
15305
|
+
* @param params - Transaction report parameters.
|
|
15306
|
+
* @throws {@link KitError} When the API call fails.
|
|
15307
|
+
*
|
|
15308
|
+
* @internal
|
|
15309
|
+
*/ async function reportEarnTransaction(params) {
|
|
15310
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
15311
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/transactions/report`, baseUrl);
|
|
15312
|
+
// The report endpoint is not idempotent: success reports refresh the gas
|
|
15313
|
+
// cache and failure reports increment counts. If the first request succeeds
|
|
15314
|
+
// server-side but the client times out or sees a transient 5xx, retrying
|
|
15315
|
+
// would duplicate the report (double-writing an outcome or inflating failure
|
|
15316
|
+
// counts). Reporting is best-effort (see the fire-and-forget caller), so
|
|
15317
|
+
// make exactly one attempt and never retry — a single dropped report is
|
|
15318
|
+
// preferable to a duplicated one. `maxRetries` here is the total attempt
|
|
15319
|
+
// count in pollApiWithValidation (loop runs `attempt <= maxRetries`), so 1
|
|
15320
|
+
// means one request with no retry; 0 would skip the request entirely.
|
|
15321
|
+
const reportConfig = {
|
|
15322
|
+
...pollingConfig,
|
|
15323
|
+
maxRetries: 1
|
|
15324
|
+
};
|
|
15325
|
+
const gasUsed = buildReportedGasUsed(params.gasUsed, params.effectiveGasPrice);
|
|
15326
|
+
const requestBody = {
|
|
15327
|
+
execId: params.execId,
|
|
15328
|
+
chain: params.chain,
|
|
15329
|
+
status: params.status,
|
|
15330
|
+
action: params.action,
|
|
15331
|
+
...params.txHash !== undefined && {
|
|
15332
|
+
txHash: params.txHash
|
|
15333
|
+
},
|
|
15334
|
+
...gasUsed !== undefined && {
|
|
15335
|
+
gasUsed
|
|
15336
|
+
},
|
|
15337
|
+
...params.errorCode !== undefined && {
|
|
15338
|
+
errorCode: params.errorCode
|
|
15339
|
+
}
|
|
15340
|
+
};
|
|
15341
|
+
try {
|
|
15342
|
+
await pollApiPost(url.toString(), requestBody, isTransactionReportResponse, reportConfig);
|
|
15343
|
+
} catch (error) {
|
|
15344
|
+
throw parseEarnApiError(error, {
|
|
15345
|
+
operation: 'transactionReport'
|
|
15346
|
+
});
|
|
15347
|
+
}
|
|
15348
|
+
}
|
|
15349
|
+
|
|
14768
15350
|
/**
|
|
14769
15351
|
* Sum the amounts across every token input to size the allowance approval.
|
|
14770
15352
|
*
|
|
@@ -14875,6 +15457,59 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14875
15457
|
// Intentionally built-ins-only: Earn bridge support is limited to SDK-known
|
|
14876
15458
|
// token contracts plus the explicit ERC-3009 domain allowlist below.
|
|
14877
15459
|
const TOKEN_REGISTRY = createTokenRegistry();
|
|
15460
|
+
function submitTransactionReport(reportContext, action, status, details) {
|
|
15461
|
+
void reportEarnTransaction({
|
|
15462
|
+
execId: reportContext.execId,
|
|
15463
|
+
chain: reportContext.chain,
|
|
15464
|
+
config: reportContext.config,
|
|
15465
|
+
action,
|
|
15466
|
+
status,
|
|
15467
|
+
...details
|
|
15468
|
+
}).catch(()=>undefined);
|
|
15469
|
+
}
|
|
15470
|
+
function reportTransactionSuccess(reportContext, action, result) {
|
|
15471
|
+
if (result === undefined) {
|
|
15472
|
+
return;
|
|
15473
|
+
}
|
|
15474
|
+
submitTransactionReport(reportContext, action, 'success', {
|
|
15475
|
+
txHash: result.txHash,
|
|
15476
|
+
gasUsed: result.gasUsed,
|
|
15477
|
+
effectiveGasPrice: result.effectiveGasPrice
|
|
15478
|
+
});
|
|
15479
|
+
}
|
|
15480
|
+
function reportTransactionFailure(reportContext, action, error) {
|
|
15481
|
+
submitTransactionReport(reportContext, action, 'failure', {
|
|
15482
|
+
txHash: transactionReportTxHash(error),
|
|
15483
|
+
errorCode: transactionReportErrorCode(error)
|
|
15484
|
+
});
|
|
15485
|
+
}
|
|
15486
|
+
function transactionReportErrorCode(error) {
|
|
15487
|
+
if (isKitError(error)) {
|
|
15488
|
+
return error.name;
|
|
15489
|
+
}
|
|
15490
|
+
const message = getErrorMessage(error);
|
|
15491
|
+
if (/user (rejected|denied)|rejected by user/i.test(message)) {
|
|
15492
|
+
return 'USER_REJECTED';
|
|
15493
|
+
}
|
|
15494
|
+
if (/insufficient funds/i.test(message)) {
|
|
15495
|
+
return 'INSUFFICIENT_FUNDS';
|
|
15496
|
+
}
|
|
15497
|
+
if (/timeout|timed out/i.test(message)) {
|
|
15498
|
+
return 'TIMEOUT';
|
|
15499
|
+
}
|
|
15500
|
+
return 'UNKNOWN_ERROR';
|
|
15501
|
+
}
|
|
15502
|
+
function transactionReportTxHash(error) {
|
|
15503
|
+
if (!isKitError(error)) {
|
|
15504
|
+
return undefined;
|
|
15505
|
+
}
|
|
15506
|
+
const trace = error.cause?.trace;
|
|
15507
|
+
if (typeof trace !== 'object' || trace === null) {
|
|
15508
|
+
return undefined;
|
|
15509
|
+
}
|
|
15510
|
+
const txHash = trace['txHash'];
|
|
15511
|
+
return typeof txHash === 'string' && txHash !== '' ? txHash : undefined;
|
|
15512
|
+
}
|
|
14878
15513
|
/**
|
|
14879
15514
|
* Build the typed error raised when a cross-chain wait is cancelled via its
|
|
14880
15515
|
* `AbortSignal`. Mirrors `@core/adapter-base`'s `createAbortError` (same
|
|
@@ -15196,7 +15831,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15196
15831
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15197
15832
|
const { adapter } = params.from;
|
|
15198
15833
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15199
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15834
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15200
15835
|
vaultAddress,
|
|
15201
15836
|
amount: params.amount,
|
|
15202
15837
|
address,
|
|
@@ -15204,32 +15839,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15204
15839
|
config
|
|
15205
15840
|
}), ()=>undefined);
|
|
15206
15841
|
validateExecutionDeadline(executionParams);
|
|
15842
|
+
const transactionReportContext = {
|
|
15843
|
+
execId,
|
|
15844
|
+
chain: apiChain,
|
|
15845
|
+
config
|
|
15846
|
+
};
|
|
15207
15847
|
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15208
15848
|
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15209
15849
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15210
15850
|
if (!options.skipApprove && approvalToken !== undefined && requiredAllowance > 0n) {
|
|
15211
|
-
await this.runPhase(ctx, 'approve', 'approve', async ()=>
|
|
15851
|
+
await this.runPhase(ctx, 'approve', 'approve', async ()=>{
|
|
15852
|
+
try {
|
|
15853
|
+
const approval = await approveAllowanceIfNeeded({
|
|
15854
|
+
adapter,
|
|
15855
|
+
chain,
|
|
15856
|
+
tokenAddress: approvalToken,
|
|
15857
|
+
delegate: adapterContractAddress,
|
|
15858
|
+
address,
|
|
15859
|
+
requiredAllowance,
|
|
15860
|
+
revertMessage: 'Earn deposit token approval reverted on-chain'
|
|
15861
|
+
});
|
|
15862
|
+
reportTransactionSuccess(transactionReportContext, 'Approve', approval);
|
|
15863
|
+
return approval;
|
|
15864
|
+
} catch (error) {
|
|
15865
|
+
reportTransactionFailure(transactionReportContext, 'Approve', error);
|
|
15866
|
+
throw error;
|
|
15867
|
+
}
|
|
15868
|
+
}, (approval)=>approval?.txHash);
|
|
15869
|
+
}
|
|
15870
|
+
const { txHash, explorerUrl } = await this.runPhase(ctx, 'deposit', 'execute', async ()=>{
|
|
15871
|
+
try {
|
|
15872
|
+
const result = await executeEarnAction({
|
|
15212
15873
|
adapter,
|
|
15213
15874
|
chain,
|
|
15214
|
-
tokenAddress: approvalToken,
|
|
15215
|
-
delegate: adapterContractAddress,
|
|
15216
15875
|
address,
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15228
|
-
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
}), ({ txHash })=>txHash);
|
|
15876
|
+
actionKey: 'earn.deposit',
|
|
15877
|
+
actionParams: {
|
|
15878
|
+
executeParams: executionParams,
|
|
15879
|
+
tokenInputs,
|
|
15880
|
+
signature
|
|
15881
|
+
},
|
|
15882
|
+
revertMessage: 'Earn deposit reverted on-chain'
|
|
15883
|
+
});
|
|
15884
|
+
reportTransactionSuccess(transactionReportContext, 'Deposit', result);
|
|
15885
|
+
return result;
|
|
15886
|
+
} catch (error) {
|
|
15887
|
+
reportTransactionFailure(transactionReportContext, 'Deposit', error);
|
|
15888
|
+
throw error;
|
|
15889
|
+
}
|
|
15890
|
+
}, ({ txHash })=>txHash);
|
|
15233
15891
|
return {
|
|
15234
15892
|
kind: 'same-chain',
|
|
15235
15893
|
txHash,
|
|
@@ -15309,7 +15967,13 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15309
15967
|
amount: params.amount,
|
|
15310
15968
|
sourceChain: sourceChain.chain,
|
|
15311
15969
|
destinationChain: destinationChain.chain,
|
|
15312
|
-
expiresAt: prepared.expiresAt
|
|
15970
|
+
expiresAt: prepared.expiresAt,
|
|
15971
|
+
...prepared.quoteIssuedAt !== undefined && {
|
|
15972
|
+
quoteIssuedAt: prepared.quoteIssuedAt
|
|
15973
|
+
},
|
|
15974
|
+
...prepared.quoteExpiry !== undefined && {
|
|
15975
|
+
quoteExpiry: prepared.quoteExpiry
|
|
15976
|
+
}
|
|
15313
15977
|
};
|
|
15314
15978
|
}
|
|
15315
15979
|
/** {@inheritdoc} */ async withdraw(params) {
|
|
@@ -15330,7 +15994,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15330
15994
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15331
15995
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15332
15996
|
const { adapter } = params.from;
|
|
15333
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15997
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15334
15998
|
vaultAddress,
|
|
15335
15999
|
amount: params.amount,
|
|
15336
16000
|
address,
|
|
@@ -15338,32 +16002,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15338
16002
|
config
|
|
15339
16003
|
}), ()=>undefined);
|
|
15340
16004
|
validateExecutionDeadline(executionParams);
|
|
16005
|
+
const transactionReportContext = {
|
|
16006
|
+
execId,
|
|
16007
|
+
chain: apiChain,
|
|
16008
|
+
config
|
|
16009
|
+
};
|
|
15341
16010
|
const tokenInputs = buildEarnTokenInputs(executionParams, vaultAddress);
|
|
15342
16011
|
const approvalToken = tokenInputs[0]?.token;
|
|
15343
16012
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15344
16013
|
if (!options.skipApprove && approvalToken !== undefined) {
|
|
15345
|
-
await this.runPhase(ctx, 'approve', 'approve', async ()=>
|
|
16014
|
+
await this.runPhase(ctx, 'approve', 'approve', async ()=>{
|
|
16015
|
+
try {
|
|
16016
|
+
const approval = await approveAllowanceIfNeeded({
|
|
16017
|
+
adapter,
|
|
16018
|
+
chain,
|
|
16019
|
+
tokenAddress: approvalToken,
|
|
16020
|
+
delegate: adapterContractAddress,
|
|
16021
|
+
address,
|
|
16022
|
+
requiredAllowance,
|
|
16023
|
+
revertMessage: 'Vault share token approval reverted on-chain'
|
|
16024
|
+
});
|
|
16025
|
+
reportTransactionSuccess(transactionReportContext, 'Approve', approval);
|
|
16026
|
+
return approval;
|
|
16027
|
+
} catch (error) {
|
|
16028
|
+
reportTransactionFailure(transactionReportContext, 'Approve', error);
|
|
16029
|
+
throw error;
|
|
16030
|
+
}
|
|
16031
|
+
}, (approval)=>approval?.txHash);
|
|
16032
|
+
}
|
|
16033
|
+
const { txHash, explorerUrl } = await this.runPhase(ctx, 'withdraw', 'execute', async ()=>{
|
|
16034
|
+
try {
|
|
16035
|
+
const result = await executeEarnAction({
|
|
15346
16036
|
adapter,
|
|
15347
16037
|
chain,
|
|
15348
|
-
tokenAddress: approvalToken,
|
|
15349
|
-
delegate: adapterContractAddress,
|
|
15350
16038
|
address,
|
|
15351
|
-
|
|
15352
|
-
|
|
15353
|
-
|
|
15354
|
-
|
|
15355
|
-
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
}), ({ txHash })=>txHash);
|
|
16039
|
+
actionKey: 'earn.withdraw',
|
|
16040
|
+
actionParams: {
|
|
16041
|
+
executeParams: executionParams,
|
|
16042
|
+
tokenInputs,
|
|
16043
|
+
signature
|
|
16044
|
+
},
|
|
16045
|
+
revertMessage: 'Earn withdraw reverted on-chain'
|
|
16046
|
+
});
|
|
16047
|
+
reportTransactionSuccess(transactionReportContext, 'Withdraw', result);
|
|
16048
|
+
return result;
|
|
16049
|
+
} catch (error) {
|
|
16050
|
+
reportTransactionFailure(transactionReportContext, 'Withdraw', error);
|
|
16051
|
+
throw error;
|
|
16052
|
+
}
|
|
16053
|
+
}, ({ txHash })=>txHash);
|
|
15367
16054
|
return {
|
|
15368
16055
|
txHash,
|
|
15369
16056
|
explorerUrl,
|
|
@@ -15497,141 +16184,6 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15497
16184
|
}
|
|
15498
16185
|
}
|
|
15499
16186
|
}
|
|
15500
|
-
gasEstimateFailure(name, chain, error) {
|
|
15501
|
-
return {
|
|
15502
|
-
name,
|
|
15503
|
-
token: chain.nativeCurrency.symbol,
|
|
15504
|
-
blockchain: chain.chain,
|
|
15505
|
-
fees: null,
|
|
15506
|
-
error: getErrorMessage(error)
|
|
15507
|
-
};
|
|
15508
|
-
}
|
|
15509
|
-
async estimateDepositQuoteGasFees(params) {
|
|
15510
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15511
|
-
try {
|
|
15512
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15513
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15514
|
-
const { executionParams, signature } = await fetchDeposit({
|
|
15515
|
-
vaultAddress: normalizedVaultAddress,
|
|
15516
|
-
amount,
|
|
15517
|
-
address,
|
|
15518
|
-
chain: apiChain,
|
|
15519
|
-
config
|
|
15520
|
-
});
|
|
15521
|
-
validateExecutionDeadline(executionParams);
|
|
15522
|
-
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15523
|
-
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15524
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15525
|
-
return await estimateEarnQuoteGasFees({
|
|
15526
|
-
adapter,
|
|
15527
|
-
chain,
|
|
15528
|
-
address,
|
|
15529
|
-
actionName: 'Deposit',
|
|
15530
|
-
actionKey: 'earn.deposit',
|
|
15531
|
-
actionParams: {
|
|
15532
|
-
executeParams: executionParams,
|
|
15533
|
-
tokenInputs,
|
|
15534
|
-
signature
|
|
15535
|
-
},
|
|
15536
|
-
approval: approvalToken !== undefined && requiredAllowance > 0n ? {
|
|
15537
|
-
token: approvalToken,
|
|
15538
|
-
delegate: adapterContractAddress,
|
|
15539
|
-
requiredAllowance
|
|
15540
|
-
} : undefined
|
|
15541
|
-
});
|
|
15542
|
-
} catch (error) {
|
|
15543
|
-
return [
|
|
15544
|
-
this.gasEstimateFailure('Deposit', chain, error)
|
|
15545
|
-
];
|
|
15546
|
-
}
|
|
15547
|
-
}
|
|
15548
|
-
async estimateWithdrawalQuoteGasFees(params) {
|
|
15549
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15550
|
-
try {
|
|
15551
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15552
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15553
|
-
const { executionParams, signature } = await fetchWithdraw({
|
|
15554
|
-
vaultAddress: normalizedVaultAddress,
|
|
15555
|
-
amount,
|
|
15556
|
-
address,
|
|
15557
|
-
chain: apiChain,
|
|
15558
|
-
config
|
|
15559
|
-
});
|
|
15560
|
-
validateExecutionDeadline(executionParams);
|
|
15561
|
-
const tokenInputs = buildEarnTokenInputs(executionParams, normalizedVaultAddress);
|
|
15562
|
-
const approvalToken = tokenInputs[0]?.token;
|
|
15563
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15564
|
-
return await estimateEarnQuoteGasFees({
|
|
15565
|
-
adapter,
|
|
15566
|
-
chain,
|
|
15567
|
-
address,
|
|
15568
|
-
actionName: 'Withdraw',
|
|
15569
|
-
actionKey: 'earn.withdraw',
|
|
15570
|
-
actionParams: {
|
|
15571
|
-
executeParams: executionParams,
|
|
15572
|
-
tokenInputs,
|
|
15573
|
-
signature
|
|
15574
|
-
},
|
|
15575
|
-
approval: approvalToken !== undefined ? {
|
|
15576
|
-
token: approvalToken,
|
|
15577
|
-
delegate: adapterContractAddress,
|
|
15578
|
-
requiredAllowance
|
|
15579
|
-
} : undefined
|
|
15580
|
-
});
|
|
15581
|
-
} catch (error) {
|
|
15582
|
-
return [
|
|
15583
|
-
this.gasEstimateFailure('Withdraw', chain, error)
|
|
15584
|
-
];
|
|
15585
|
-
}
|
|
15586
|
-
}
|
|
15587
|
-
async estimateClaimRewardsQuoteGasFees(params) {
|
|
15588
|
-
const { adapter, chain, apiChain, address, vaultAddress, config } = params;
|
|
15589
|
-
try {
|
|
15590
|
-
requireAdapterContract(chain);
|
|
15591
|
-
const { rewards, executionParams, signature } = await fetchClaimRewards({
|
|
15592
|
-
address,
|
|
15593
|
-
chain: apiChain,
|
|
15594
|
-
vaultAddress,
|
|
15595
|
-
config
|
|
15596
|
-
});
|
|
15597
|
-
if (rewards.length === 0) {
|
|
15598
|
-
return [];
|
|
15599
|
-
}
|
|
15600
|
-
const missingExecutionParams = executionParams === undefined;
|
|
15601
|
-
const missingSignature = signature === undefined;
|
|
15602
|
-
if (missingExecutionParams || missingSignature) {
|
|
15603
|
-
throw new KitError({
|
|
15604
|
-
...EarnError.INTERNAL_ERROR,
|
|
15605
|
-
recoverability: 'RETRYABLE',
|
|
15606
|
-
message: 'Claim rewards response must include executionParams and signature when rewards are claimable',
|
|
15607
|
-
cause: {
|
|
15608
|
-
trace: {
|
|
15609
|
-
rewardsCount: rewards.length,
|
|
15610
|
-
missingExecutionParams,
|
|
15611
|
-
missingSignature
|
|
15612
|
-
}
|
|
15613
|
-
}
|
|
15614
|
-
});
|
|
15615
|
-
}
|
|
15616
|
-
validateExecutionDeadline(executionParams);
|
|
15617
|
-
return await estimateEarnQuoteGasFees({
|
|
15618
|
-
adapter,
|
|
15619
|
-
chain,
|
|
15620
|
-
address,
|
|
15621
|
-
actionName: 'Claim Rewards',
|
|
15622
|
-
actionKey: 'earn.claimRewards',
|
|
15623
|
-
actionParams: {
|
|
15624
|
-
executeParams: executionParams,
|
|
15625
|
-
tokenInputs: [],
|
|
15626
|
-
signature
|
|
15627
|
-
}
|
|
15628
|
-
});
|
|
15629
|
-
} catch (error) {
|
|
15630
|
-
return [
|
|
15631
|
-
this.gasEstimateFailure('Claim Rewards', chain, error)
|
|
15632
|
-
];
|
|
15633
|
-
}
|
|
15634
|
-
}
|
|
15635
16187
|
/** {@inheritdoc} */ async getDepositQuote(params) {
|
|
15636
16188
|
const config = this.resolveConfig(params.config);
|
|
15637
16189
|
if (hasQuoteDestinationChain(params)) {
|
|
@@ -15654,96 +16206,43 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15654
16206
|
throw createValidationFailedError('chain', destinationChain.chain, 'chain is only supported for cross-chain Earn deposit quotes; omit chain/address when quoting on the source chain');
|
|
15655
16207
|
}
|
|
15656
16208
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15657
|
-
//
|
|
15658
|
-
//
|
|
15659
|
-
//
|
|
15660
|
-
|
|
15661
|
-
|
|
15662
|
-
|
|
15663
|
-
|
|
15664
|
-
|
|
15665
|
-
|
|
15666
|
-
|
|
15667
|
-
|
|
15668
|
-
this.estimateDepositQuoteGasFees({
|
|
15669
|
-
adapter: params.from.adapter,
|
|
15670
|
-
chain: chainDefinition,
|
|
15671
|
-
apiChain: chain,
|
|
15672
|
-
address,
|
|
15673
|
-
vaultAddress: params.vaultAddress,
|
|
15674
|
-
amount: params.amount,
|
|
15675
|
-
config
|
|
15676
|
-
})
|
|
15677
|
-
]);
|
|
15678
|
-
return {
|
|
15679
|
-
...quote,
|
|
15680
|
-
gasFees
|
|
15681
|
-
};
|
|
16209
|
+
// Gas is estimated server-side by the Earn Service and returned on the quote, so the
|
|
16210
|
+
// SDK no longer simulates it locally. `chainDefinition` lets the fetch fill
|
|
16211
|
+
// the native token symbol / blockchain on each gas entry.
|
|
16212
|
+
return fetchDepositQuote({
|
|
16213
|
+
vaultAddress: params.vaultAddress,
|
|
16214
|
+
amount: params.amount,
|
|
16215
|
+
address,
|
|
16216
|
+
chain,
|
|
16217
|
+
config,
|
|
16218
|
+
chainDefinition
|
|
16219
|
+
});
|
|
15682
16220
|
}
|
|
15683
16221
|
/** {@inheritdoc} */ async getWithdrawalQuote(params) {
|
|
15684
16222
|
const config = this.resolveConfig(params.config);
|
|
15685
16223
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15686
|
-
//
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
15695
|
-
config
|
|
15696
|
-
}),
|
|
15697
|
-
this.estimateWithdrawalQuoteGasFees({
|
|
15698
|
-
adapter: params.from.adapter,
|
|
15699
|
-
chain: chainDefinition,
|
|
15700
|
-
apiChain: chain,
|
|
15701
|
-
address,
|
|
15702
|
-
vaultAddress: params.vaultAddress,
|
|
15703
|
-
amount: params.amount,
|
|
15704
|
-
config
|
|
15705
|
-
})
|
|
15706
|
-
]);
|
|
15707
|
-
return {
|
|
15708
|
-
...quote,
|
|
15709
|
-
gasFees
|
|
15710
|
-
};
|
|
16224
|
+
// Gas is estimated server-side by the Earn Service and returned on the quote.
|
|
16225
|
+
return fetchWithdrawalQuote({
|
|
16226
|
+
vaultAddress: params.vaultAddress,
|
|
16227
|
+
amount: params.amount,
|
|
16228
|
+
address,
|
|
16229
|
+
chain,
|
|
16230
|
+
config,
|
|
16231
|
+
chainDefinition
|
|
16232
|
+
});
|
|
15711
16233
|
}
|
|
15712
16234
|
/** {@inheritdoc} */ async getClaimRewardsQuote(params) {
|
|
15713
16235
|
const config = this.resolveConfig(params.config);
|
|
15714
|
-
const { address, chain
|
|
15715
|
-
|
|
16236
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
16237
|
+
// The claimRewards/quote response carries no gas estimate (unlike
|
|
16238
|
+
// deposit/withdrawal quotes), and the SDK no longer estimates gas locally,
|
|
16239
|
+
// so gasFees is always empty for claim rewards.
|
|
16240
|
+
return fetchClaimRewardsQuote({
|
|
15716
16241
|
vaultAddress: params.vaultAddress,
|
|
15717
16242
|
address,
|
|
15718
16243
|
chain,
|
|
15719
16244
|
config
|
|
15720
16245
|
});
|
|
15721
|
-
// No claimable rewards means there is nothing to execute, so there is no
|
|
15722
|
-
// gas to estimate. Short-circuit on the already-fetched quote rather than
|
|
15723
|
-
// calling the (heavier) claim execution endpoint again — this also keeps
|
|
15724
|
-
// `gasFees` empty as documented, instead of risking a `{ fees: null }`
|
|
15725
|
-
// estimation-error entry when the adapter/RPC is unavailable. This
|
|
15726
|
-
// short-circuit is why the claim path stays sequential instead of using
|
|
15727
|
-
// the Promise.all pattern of the deposit/withdrawal quotes: estimating in
|
|
15728
|
-
// parallel would hit the signing endpoint even when nothing is claimable.
|
|
15729
|
-
if (quote.rewards.length === 0) {
|
|
15730
|
-
return {
|
|
15731
|
-
...quote,
|
|
15732
|
-
gasFees: []
|
|
15733
|
-
};
|
|
15734
|
-
}
|
|
15735
|
-
const gasFees = await this.estimateClaimRewardsQuoteGasFees({
|
|
15736
|
-
adapter: params.from.adapter,
|
|
15737
|
-
chain: chainDefinition,
|
|
15738
|
-
apiChain: chain,
|
|
15739
|
-
address,
|
|
15740
|
-
vaultAddress: params.vaultAddress,
|
|
15741
|
-
config
|
|
15742
|
-
});
|
|
15743
|
-
return {
|
|
15744
|
-
...quote,
|
|
15745
|
-
gasFees
|
|
15746
|
-
};
|
|
15747
16246
|
}
|
|
15748
16247
|
}
|
|
15749
16248
|
function hasDepositDestination(params) {
|
|
@@ -15981,11 +16480,27 @@ function formatPositionPnL(pnl) {
|
|
|
15981
16480
|
* @param vault - Provider vault info with raw amount objects
|
|
15982
16481
|
* @returns Vault info with total deposits and liquidity formatted as strings
|
|
15983
16482
|
*/ function formatVaultInfo(vault) {
|
|
15984
|
-
|
|
16483
|
+
// The flat `totalDeposits`/`liquidity` are deprecated aliases that are
|
|
16484
|
+
// intentionally dual-read through the migration window so existing
|
|
16485
|
+
// consumers keep receiving them until Contract.
|
|
16486
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
16487
|
+
const { totalDeposits, liquidity, liquidityProfile, ...rest } = vault;
|
|
16488
|
+
// `liquidityProfile` is `.optional()` in the response schema during the
|
|
16489
|
+
// expand/contract window (an old backend that predates the nested facets
|
|
16490
|
+
// omits it), so only format and re-attach it when present — matching the
|
|
16491
|
+
// provider-side `toVaultInfo` mapper.
|
|
15985
16492
|
return {
|
|
15986
16493
|
...rest,
|
|
15987
16494
|
totalDeposits: formatAmount(totalDeposits),
|
|
15988
|
-
liquidity: formatAmount(liquidity)
|
|
16495
|
+
liquidity: formatAmount(liquidity),
|
|
16496
|
+
...liquidityProfile !== undefined && {
|
|
16497
|
+
liquidityProfile: {
|
|
16498
|
+
...liquidityProfile,
|
|
16499
|
+
totalDeposits: formatAmount(liquidityProfile.totalDeposits),
|
|
16500
|
+
available: formatAmount(liquidityProfile.available),
|
|
16501
|
+
totalSupply: formatAmount(liquidityProfile.totalSupply)
|
|
16502
|
+
}
|
|
16503
|
+
}
|
|
15989
16504
|
};
|
|
15990
16505
|
}
|
|
15991
16506
|
/**
|
|
@@ -17895,29 +18410,97 @@ function formatRetryResult(operation, result) {
|
|
|
17895
18410
|
}
|
|
17896
18411
|
|
|
17897
18412
|
// Auto-register this kit for user agent tracking
|
|
17898
|
-
registerKit(`${pkg.name}/${pkg.version}`);
|
|
18413
|
+
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18414
|
+
|
|
18415
|
+
/**
|
|
18416
|
+
* Register event handlers from a context actions map to a kit instance.
|
|
18417
|
+
*
|
|
18418
|
+
* This utility function registers event handlers stored in a context actions map
|
|
18419
|
+
* with a kit instance that supports event handling via an `on` method. It handles
|
|
18420
|
+
* wildcard handlers ('*') and prefixed action handlers, stripping the prefix
|
|
18421
|
+
* before registration.
|
|
18422
|
+
*
|
|
18423
|
+
* The function is designed to be reusable across different operation types
|
|
18424
|
+
* (bridge, swap, stake, etc.) by accepting a configurable prefix parameter.
|
|
18425
|
+
*
|
|
18426
|
+
* @param kit - The kit instance to register handlers with (must have an `on` method)
|
|
18427
|
+
* @param handlers - Map of action names to arrays of handler functions
|
|
18428
|
+
* @param prefix - Optional prefix to strip from action names (e.g., 'bridge.')
|
|
18429
|
+
*
|
|
18430
|
+
* @example
|
|
18431
|
+
* ```typescript
|
|
18432
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
18433
|
+
* import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
18434
|
+
*
|
|
18435
|
+
* const kit = new BridgeKit()
|
|
18436
|
+
* const handlers = {
|
|
18437
|
+
* '*': [(payload) => console.log('All actions:', payload)],
|
|
18438
|
+
* 'bridge.approve': [(payload) => console.log('Approved:', payload)],
|
|
18439
|
+
* 'bridge.burn': [(payload) => console.log('Burned:', payload)],
|
|
18440
|
+
* }
|
|
18441
|
+
*
|
|
18442
|
+
* registerActionHandlers(kit, handlers, 'bridge.')
|
|
18443
|
+
* ```
|
|
18444
|
+
*
|
|
18445
|
+
* @example
|
|
18446
|
+
* ```typescript
|
|
18447
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
18448
|
+
* import { SwapKit } from '@circle-fin/swap-kit'
|
|
18449
|
+
*
|
|
18450
|
+
* const kit = new SwapKit()
|
|
18451
|
+
* const handlers = {
|
|
18452
|
+
* 'swap.initiate': [(payload) => console.log('Swap initiated:', payload)],
|
|
18453
|
+
* }
|
|
18454
|
+
*
|
|
18455
|
+
* registerActionHandlers(kit, handlers, 'swap.')
|
|
18456
|
+
* ```
|
|
18457
|
+
*/ const registerActionHandlers = (kit, handlers, prefix = '')=>{
|
|
18458
|
+
for (const [action, handlerArray] of Object.entries(handlers)){
|
|
18459
|
+
// Register all handlers for this action
|
|
18460
|
+
for (const handler of handlerArray){
|
|
18461
|
+
if (action === '*') {
|
|
18462
|
+
// Wildcard handlers are registered as-is
|
|
18463
|
+
kit.on('*', handler);
|
|
18464
|
+
} else if (prefix && action.startsWith(prefix)) {
|
|
18465
|
+
// Remove prefix to get the actual kit action name
|
|
18466
|
+
const kitAction = action.split('.').at(1);
|
|
18467
|
+
if (kitAction) {
|
|
18468
|
+
kit.on(kitAction, handler);
|
|
18469
|
+
}
|
|
18470
|
+
} else if (!prefix) {
|
|
18471
|
+
// No prefix configured, register action as-is
|
|
18472
|
+
kit.on(action, handler);
|
|
18473
|
+
}
|
|
18474
|
+
// Actions that don't match the prefix are silently ignored
|
|
18475
|
+
}
|
|
18476
|
+
}
|
|
18477
|
+
};
|
|
17899
18478
|
|
|
17900
18479
|
/**
|
|
17901
18480
|
* Create an EarnKit instance for AppKit earn operations.
|
|
17902
18481
|
*
|
|
17903
|
-
*
|
|
17904
|
-
*
|
|
17905
|
-
*
|
|
17906
|
-
* reserved until EarnKit fee support ships.
|
|
18482
|
+
* Attaches any earn event handlers previously registered on the AppKit
|
|
18483
|
+
* context (via `kit.on('earn.*', …)` or `kit.on('*', …)`) so step events
|
|
18484
|
+
* fire during the returned kit's earn operations.
|
|
17907
18485
|
*
|
|
17908
|
-
*
|
|
18486
|
+
* @remarks Developer fee hooks from the AppKit context are not applied.
|
|
18487
|
+
* EarnKit does not yet support custom fee policies.
|
|
17909
18488
|
*
|
|
17910
|
-
* @param context - AppKit context
|
|
17911
|
-
* @returns
|
|
18489
|
+
* @param context - AppKit context with earn event handlers and kit options
|
|
18490
|
+
* @returns An EarnKit instance ready for AppKit earn operations
|
|
17912
18491
|
*
|
|
17913
18492
|
* @example
|
|
17914
18493
|
* ```typescript
|
|
17915
18494
|
* const earnKit = createEarnKit(context)
|
|
17916
18495
|
* ```
|
|
17917
|
-
*/ const createEarnKit = ()=>
|
|
18496
|
+
*/ const createEarnKit = (context)=>{
|
|
18497
|
+
const kit = new EarnKit();
|
|
18498
|
+
registerActionHandlers(kit, context.actions.earn, 'earn');
|
|
18499
|
+
return kit;
|
|
18500
|
+
};
|
|
17918
18501
|
|
|
17919
18502
|
async function deposit(context, params) {
|
|
17920
|
-
return createEarnKit().deposit(params);
|
|
18503
|
+
return createEarnKit(context).deposit(params);
|
|
17921
18504
|
}
|
|
17922
18505
|
/**
|
|
17923
18506
|
* Execute an earn withdrawal operation.
|
|
@@ -17941,7 +18524,7 @@ async function deposit(context, params) {
|
|
|
17941
18524
|
* })
|
|
17942
18525
|
* ```
|
|
17943
18526
|
*/ async function withdraw(context, params) {
|
|
17944
|
-
return createEarnKit().withdraw(params);
|
|
18527
|
+
return createEarnKit(context).withdraw(params);
|
|
17945
18528
|
}
|
|
17946
18529
|
/**
|
|
17947
18530
|
* Claim earn rewards.
|
|
@@ -17964,7 +18547,7 @@ async function deposit(context, params) {
|
|
|
17964
18547
|
* })
|
|
17965
18548
|
* ```
|
|
17966
18549
|
*/ async function claimRewards(context, params) {
|
|
17967
|
-
return createEarnKit().claimRewards(params);
|
|
18550
|
+
return createEarnKit(context).claimRewards(params);
|
|
17968
18551
|
}
|
|
17969
18552
|
/**
|
|
17970
18553
|
* Fetch vault information.
|
|
@@ -17986,7 +18569,7 @@ async function deposit(context, params) {
|
|
|
17986
18569
|
* })
|
|
17987
18570
|
* ```
|
|
17988
18571
|
*/ async function getVaults(context, params) {
|
|
17989
|
-
return createEarnKit().getVaults(params);
|
|
18572
|
+
return createEarnKit(context).getVaults(params);
|
|
17990
18573
|
}
|
|
17991
18574
|
/**
|
|
17992
18575
|
* Discover vaults available on a chain.
|
|
@@ -18010,7 +18593,7 @@ async function deposit(context, params) {
|
|
|
18010
18593
|
* })
|
|
18011
18594
|
* ```
|
|
18012
18595
|
*/ async function exploreVaults(context, params) {
|
|
18013
|
-
return createEarnKit().exploreVaults(params);
|
|
18596
|
+
return createEarnKit(context).exploreVaults(params);
|
|
18014
18597
|
}
|
|
18015
18598
|
/**
|
|
18016
18599
|
* Lazily iterate every vault available on a chain.
|
|
@@ -18034,7 +18617,7 @@ async function deposit(context, params) {
|
|
|
18034
18617
|
* }
|
|
18035
18618
|
* ```
|
|
18036
18619
|
*/ function exploreVaultsIterator(context, params) {
|
|
18037
|
-
return createEarnKit().exploreVaultsIterator(params);
|
|
18620
|
+
return createEarnKit(context).exploreVaultsIterator(params);
|
|
18038
18621
|
}
|
|
18039
18622
|
/**
|
|
18040
18623
|
* Fetch a wallet position in a vault.
|
|
@@ -18057,7 +18640,7 @@ async function deposit(context, params) {
|
|
|
18057
18640
|
* })
|
|
18058
18641
|
* ```
|
|
18059
18642
|
*/ async function getPosition(context, params) {
|
|
18060
|
-
return createEarnKit().getPosition(params);
|
|
18643
|
+
return createEarnKit(context).getPosition(params);
|
|
18061
18644
|
}
|
|
18062
18645
|
/**
|
|
18063
18646
|
* Fetch the current status of a cross-chain Earn deposit.
|
|
@@ -18079,7 +18662,7 @@ async function deposit(context, params) {
|
|
|
18079
18662
|
* console.log(status.status)
|
|
18080
18663
|
* ```
|
|
18081
18664
|
*/ async function getCrossChainDepositStatus(context, params) {
|
|
18082
|
-
return createEarnKit().getCrossChainDepositStatus(params);
|
|
18665
|
+
return createEarnKit(context).getCrossChainDepositStatus(params);
|
|
18083
18666
|
}
|
|
18084
18667
|
/**
|
|
18085
18668
|
* Poll a cross-chain Earn deposit until it reaches a terminal bridge state.
|
|
@@ -18102,7 +18685,7 @@ async function deposit(context, params) {
|
|
|
18102
18685
|
* console.log(result.outcome)
|
|
18103
18686
|
* ```
|
|
18104
18687
|
*/ async function waitForCrossChainDeposit(context, params) {
|
|
18105
|
-
return createEarnKit().waitForCrossChainDeposit(params);
|
|
18688
|
+
return createEarnKit(context).waitForCrossChainDeposit(params);
|
|
18106
18689
|
}
|
|
18107
18690
|
/**
|
|
18108
18691
|
* Fetch a deposit quote.
|
|
@@ -18126,7 +18709,7 @@ async function deposit(context, params) {
|
|
|
18126
18709
|
* })
|
|
18127
18710
|
* ```
|
|
18128
18711
|
*/ async function getDepositQuote(context, params) {
|
|
18129
|
-
return createEarnKit().getDepositQuote(params);
|
|
18712
|
+
return createEarnKit(context).getDepositQuote(params);
|
|
18130
18713
|
}
|
|
18131
18714
|
/**
|
|
18132
18715
|
* Fetch a withdrawal quote.
|
|
@@ -18150,7 +18733,7 @@ async function deposit(context, params) {
|
|
|
18150
18733
|
* })
|
|
18151
18734
|
* ```
|
|
18152
18735
|
*/ async function getWithdrawalQuote(context, params) {
|
|
18153
|
-
return createEarnKit().getWithdrawalQuote(params);
|
|
18736
|
+
return createEarnKit(context).getWithdrawalQuote(params);
|
|
18154
18737
|
}
|
|
18155
18738
|
/**
|
|
18156
18739
|
* Fetch a claim rewards quote.
|
|
@@ -18173,7 +18756,43 @@ async function deposit(context, params) {
|
|
|
18173
18756
|
* })
|
|
18174
18757
|
* ```
|
|
18175
18758
|
*/ async function getClaimRewardsQuote(context, params) {
|
|
18176
|
-
return createEarnKit().getClaimRewardsQuote(params);
|
|
18759
|
+
return createEarnKit(context).getClaimRewardsQuote(params);
|
|
18760
|
+
}
|
|
18761
|
+
/**
|
|
18762
|
+
* Resume a multi-phase earn operation that previously failed.
|
|
18763
|
+
*
|
|
18764
|
+
* Pass the {@link KitError} caught from `deposit`, `withdraw`, or
|
|
18765
|
+
* `claimRewards`. Completed phases can be skipped when the error carries
|
|
18766
|
+
* earn retry context. Call `isRetryableError(error)` first.
|
|
18767
|
+
*
|
|
18768
|
+
* @remarks
|
|
18769
|
+
* Retry re-fetches execution params and may re-submit the execute
|
|
18770
|
+
* transaction. Treat this as best-effort recovery if a prior execute
|
|
18771
|
+
* broadcast may still be in flight.
|
|
18772
|
+
*
|
|
18773
|
+
* @param context - AppKit context
|
|
18774
|
+
* @param error - The error caught from a previous multi-phase earn operation
|
|
18775
|
+
* @returns Promise resolving to the result of the resumed operation
|
|
18776
|
+
* @throws If the error is not retryable or lacks earn retry context
|
|
18777
|
+
*
|
|
18778
|
+
* @example
|
|
18779
|
+
* ```typescript
|
|
18780
|
+
* import { isRetryableError } from '@circle-fin/app-kit'
|
|
18781
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
18782
|
+
* import { retry } from '@circle-fin/app-kit/earn'
|
|
18783
|
+
*
|
|
18784
|
+
* const context = createContext()
|
|
18785
|
+
*
|
|
18786
|
+
* try {
|
|
18787
|
+
* await deposit(context, params)
|
|
18788
|
+
* } catch (error) {
|
|
18789
|
+
* if (isRetryableError(error)) {
|
|
18790
|
+
* const result = await retry(context, error)
|
|
18791
|
+
* }
|
|
18792
|
+
* }
|
|
18793
|
+
* ```
|
|
18794
|
+
*/ async function retry(context, error) {
|
|
18795
|
+
return createEarnKit(context).retry(error);
|
|
18177
18796
|
}
|
|
18178
18797
|
|
|
18179
18798
|
exports.claimRewards = claimRewards;
|
|
@@ -18186,6 +18805,7 @@ exports.getDepositQuote = getDepositQuote;
|
|
|
18186
18805
|
exports.getPosition = getPosition;
|
|
18187
18806
|
exports.getVaults = getVaults;
|
|
18188
18807
|
exports.getWithdrawalQuote = getWithdrawalQuote;
|
|
18808
|
+
exports.retry = retry;
|
|
18189
18809
|
exports.waitForCrossChainDeposit = waitForCrossChainDeposit;
|
|
18190
18810
|
exports.withdraw = withdraw;
|
|
18191
18811
|
//# sourceMappingURL=earn.cjs.map
|