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