@circle-fin/app-kit 1.9.0 → 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 +26 -0
- package/bridge.cjs +622 -26
- package/bridge.d.cts +147 -10
- package/bridge.d.mts +147 -10
- package/bridge.d.ts +147 -10
- package/bridge.mjs +622 -26
- package/chains.cjs +8 -2
- package/chains.d.cts +1 -0
- package/chains.d.mts +1 -0
- package/chains.d.ts +1 -0
- package/chains.mjs +8 -2
- package/context.cjs +1 -0
- package/context.d.cts +152 -12
- package/context.d.mts +152 -12
- package/context.d.ts +152 -12
- package/context.mjs +1 -0
- package/earn.cjs +859 -420
- package/earn.d.cts +521 -94
- package/earn.d.mts +521 -94
- package/earn.d.ts +521 -94
- package/earn.mjs +859 -421
- package/estimateBridge.cjs +622 -26
- package/estimateBridge.d.cts +147 -10
- package/estimateBridge.d.mts +147 -10
- package/estimateBridge.d.ts +147 -10
- package/estimateBridge.mjs +622 -26
- package/estimateSwap.cjs +810 -92
- package/estimateSwap.d.cts +147 -10
- package/estimateSwap.d.mts +147 -10
- package/estimateSwap.d.ts +147 -10
- package/estimateSwap.mjs +810 -92
- package/index.cjs +2450 -645
- package/index.d.cts +1003 -126
- package/index.d.mts +1003 -126
- package/index.d.ts +1003 -126
- package/index.mjs +2450 -645
- package/package.json +6 -6
- package/swap.cjs +810 -92
- package/swap.d.cts +147 -10
- package/swap.d.mts +147 -10
- package/swap.d.ts +147 -10
- package/swap.mjs +810 -92
- package/unifiedBalance.cjs +722 -115
- package/unifiedBalance.d.cts +222 -4
- package/unifiedBalance.d.mts +222 -4
- package/unifiedBalance.d.ts +222 -4
- package/unifiedBalance.mjs +722 -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,14 +1762,14 @@ 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-
|
|
1772
|
+
* - 1100-1106: INPUT errors — invalid, unsupported, or stale request state
|
|
1770
1773
|
* - 8100-8105: SERVICE errors — retryable backend/provider failures
|
|
1771
1774
|
*
|
|
1772
1775
|
* @example
|
|
@@ -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',
|
|
@@ -1878,6 +1889,9 @@ function getOptionalString(value) {
|
|
|
1878
1889
|
* internal-error, vault-refresh-busy, off-chain-paused, position-PnL-pending,
|
|
1879
1890
|
* bridge failures/status lookup failures
|
|
1880
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
|
+
*
|
|
1881
1895
|
* Unrecognized codes fall through to `parseApiError` for HTTP-status-based
|
|
1882
1896
|
* handling.
|
|
1883
1897
|
*
|
|
@@ -2111,6 +2125,13 @@ function getOptionalString(value) {
|
|
|
2111
2125
|
errorDef: EarnError.PROVIDER_ERROR,
|
|
2112
2126
|
recoverability: 'FATAL'
|
|
2113
2127
|
}
|
|
2128
|
+
],
|
|
2129
|
+
[
|
|
2130
|
+
380506,
|
|
2131
|
+
{
|
|
2132
|
+
errorDef: EarnError.BRIDGE_QUOTE_EXPIRED,
|
|
2133
|
+
recoverability: 'FATAL'
|
|
2134
|
+
}
|
|
2114
2135
|
]
|
|
2115
2136
|
]);
|
|
2116
2137
|
/**
|
|
@@ -2834,7 +2855,10 @@ var EarnChain;
|
|
|
2834
2855
|
contracts: {
|
|
2835
2856
|
v1: {
|
|
2836
2857
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
2837
|
-
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'
|
|
2838
2862
|
}
|
|
2839
2863
|
},
|
|
2840
2864
|
forwarderSupported: {
|
|
@@ -5902,7 +5926,10 @@ var Chains = /*#__PURE__*/Object.freeze({
|
|
|
5902
5926
|
minter: z.string({
|
|
5903
5927
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
5904
5928
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
5905
|
-
}).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()
|
|
5906
5933
|
}).strict() // Reject any additional properties not defined in the schema
|
|
5907
5934
|
;
|
|
5908
5935
|
/**
|
|
@@ -8014,6 +8041,13 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8014
8041
|
return explorerUrl;
|
|
8015
8042
|
}
|
|
8016
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
|
+
|
|
8017
8051
|
/**
|
|
8018
8052
|
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
8019
8053
|
* short SDK name used in telemetry payloads.
|
|
@@ -8033,7 +8067,7 @@ const swapTokenEnumSchema = z.enum([
|
|
|
8033
8067
|
}
|
|
8034
8068
|
|
|
8035
8069
|
var name$3 = "@circle-fin/bridge-kit";
|
|
8036
|
-
var version$3 = "1.12.
|
|
8070
|
+
var version$3 = "1.12.1";
|
|
8037
8071
|
var pkg$3 = {
|
|
8038
8072
|
name: name$3,
|
|
8039
8073
|
version: version$3};
|
|
@@ -8858,6 +8892,11 @@ var TransferSpeed;
|
|
|
8858
8892
|
clock: z.any().optional()
|
|
8859
8893
|
}).passthrough();
|
|
8860
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
|
+
|
|
8861
8900
|
/**
|
|
8862
8901
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
8863
8902
|
*
|
|
@@ -8890,7 +8929,7 @@ var TransferSpeed;
|
|
|
8890
8929
|
registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
8891
8930
|
|
|
8892
8931
|
var name$2 = "@circle-fin/swap-kit";
|
|
8893
|
-
var version$2 = "1.
|
|
8932
|
+
var version$2 = "1.4.0";
|
|
8894
8933
|
var pkg$2 = {
|
|
8895
8934
|
name: name$2,
|
|
8896
8935
|
version: version$2};
|
|
@@ -8955,7 +8994,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
8955
8994
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
8956
8995
|
provider: z.string({
|
|
8957
8996
|
invalid_type_error: 'provider must be a string'
|
|
8958
|
-
}).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()
|
|
8959
9001
|
});
|
|
8960
9002
|
/**
|
|
8961
9003
|
* Zod schema for adapter context.
|
|
@@ -9394,7 +9436,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9394
9436
|
/**
|
|
9395
9437
|
* Circle Stablecoin Service API Key.
|
|
9396
9438
|
* Must be a valid API key format.
|
|
9397
|
-
*/ apiKey: apiKeySchema
|
|
9439
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9398
9440
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
9399
9441
|
/**
|
|
9400
9442
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -9452,7 +9494,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9452
9494
|
/**
|
|
9453
9495
|
* Circle Stablecoin Service API Key.
|
|
9454
9496
|
* Must be a valid API key format.
|
|
9455
|
-
*/ apiKey: apiKeySchema
|
|
9497
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9456
9498
|
});
|
|
9457
9499
|
/**
|
|
9458
9500
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -9488,7 +9530,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9488
9530
|
toChain: z.string({
|
|
9489
9531
|
invalid_type_error: 'toChain must be a string'
|
|
9490
9532
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
9491
|
-
apiKey: apiKeySchema
|
|
9533
|
+
apiKey: apiKeySchema.optional()
|
|
9492
9534
|
});
|
|
9493
9535
|
/**
|
|
9494
9536
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -9497,13 +9539,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9497
9539
|
required_error: 'fee token is required',
|
|
9498
9540
|
invalid_type_error: 'fee token must be a string'
|
|
9499
9541
|
}).min(1, 'fee token must be a non-empty string'),
|
|
9500
|
-
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()
|
|
9501
9547
|
});
|
|
9502
9548
|
/**
|
|
9503
9549
|
* Developer fee item schema with basis field.
|
|
9504
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
9505
|
-
token: z.string().min(1, 'fee token must be a non-empty string'),
|
|
9506
|
-
amount: feeAmountSchema,
|
|
9550
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
9507
9551
|
basis: z.enum([
|
|
9508
9552
|
'inputAmount',
|
|
9509
9553
|
'estimatedAmount'
|
|
@@ -9595,7 +9639,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9595
9639
|
addresses: z.array(z.string({
|
|
9596
9640
|
invalid_type_error: 'addresses entries must be strings'
|
|
9597
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(),
|
|
9598
|
-
apiKey: apiKeySchema
|
|
9642
|
+
apiKey: apiKeySchema.optional()
|
|
9599
9643
|
});
|
|
9600
9644
|
/**
|
|
9601
9645
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -12184,7 +12228,7 @@ new Set(Object.values(Blockchain));
|
|
|
12184
12228
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
12185
12229
|
|
|
12186
12230
|
var name$1 = "@circle-fin/earn-kit";
|
|
12187
|
-
var version$1 = "1.
|
|
12231
|
+
var version$1 = "1.3.0";
|
|
12188
12232
|
var pkg$1 = {
|
|
12189
12233
|
name: name$1,
|
|
12190
12234
|
version: version$1};
|
|
@@ -12651,7 +12695,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12651
12695
|
*
|
|
12652
12696
|
* @param params - Adapter, chain, token/delegate/wallet addresses, the required
|
|
12653
12697
|
* allowance for the signed payload, and a revert message for on-chain failure.
|
|
12654
|
-
* @returns The approval transaction
|
|
12698
|
+
* @returns The approval transaction result when an approval was submitted, or
|
|
12655
12699
|
* `undefined` when the existing allowance already covers `requiredAllowance`
|
|
12656
12700
|
* (or `requiredAllowance` is zero).
|
|
12657
12701
|
* @throws {@link KitError} If the `token.allowance` response is malformed.
|
|
@@ -12659,7 +12703,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12659
12703
|
*
|
|
12660
12704
|
* @example
|
|
12661
12705
|
* ```typescript
|
|
12662
|
-
* const
|
|
12706
|
+
* const approval = await approveAllowanceIfNeeded({
|
|
12663
12707
|
* adapter,
|
|
12664
12708
|
* chain,
|
|
12665
12709
|
* tokenAddress: usdcAddress,
|
|
@@ -12721,7 +12765,15 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12721
12765
|
maxAttempts: params.allowancePropagation?.maxAttempts ?? DEFAULT_PROPAGATION_ATTEMPTS,
|
|
12722
12766
|
delayMs: params.allowancePropagation?.delayMs ?? DEFAULT_PROPAGATION_DELAY_MS
|
|
12723
12767
|
});
|
|
12724
|
-
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
|
+
};
|
|
12725
12777
|
}
|
|
12726
12778
|
|
|
12727
12779
|
/** @internal */ function isSameAddress(actual, expected) {
|
|
@@ -12869,7 +12921,13 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12869
12921
|
}
|
|
12870
12922
|
return {
|
|
12871
12923
|
txHash,
|
|
12872
|
-
explorerUrl
|
|
12924
|
+
explorerUrl,
|
|
12925
|
+
...receipt.gasUsed !== undefined && {
|
|
12926
|
+
gasUsed: receipt.gasUsed
|
|
12927
|
+
},
|
|
12928
|
+
...receipt.effectiveGasPrice !== undefined && {
|
|
12929
|
+
effectiveGasPrice: receipt.effectiveGasPrice
|
|
12930
|
+
}
|
|
12873
12931
|
};
|
|
12874
12932
|
}
|
|
12875
12933
|
|
|
@@ -13181,112 +13239,6 @@ const EARN_OPERATIONS = new Set([
|
|
|
13181
13239
|
return hasEarnServiceParamsShape(operation, candidate['params']);
|
|
13182
13240
|
}
|
|
13183
13241
|
|
|
13184
|
-
function buildGasFeeBase(name, chain) {
|
|
13185
|
-
return {
|
|
13186
|
-
name,
|
|
13187
|
-
token: chain.nativeCurrency.symbol,
|
|
13188
|
-
blockchain: chain.chain
|
|
13189
|
-
};
|
|
13190
|
-
}
|
|
13191
|
-
function buildGasFeeSuccess(name, chain, fees) {
|
|
13192
|
-
return {
|
|
13193
|
-
...buildGasFeeBase(name, chain),
|
|
13194
|
-
fees
|
|
13195
|
-
};
|
|
13196
|
-
}
|
|
13197
|
-
function buildGasFeeFailure(name, chain, error) {
|
|
13198
|
-
return {
|
|
13199
|
-
...buildGasFeeBase(name, chain),
|
|
13200
|
-
fees: null,
|
|
13201
|
-
error: getErrorMessage(error)
|
|
13202
|
-
};
|
|
13203
|
-
}
|
|
13204
|
-
async function estimatePreparedGasFee(name, chain, prepared) {
|
|
13205
|
-
try {
|
|
13206
|
-
const estimate = bufferEstimatedGas(await prepared.estimate());
|
|
13207
|
-
if (estimate.gas <= 0n) {
|
|
13208
|
-
throw createValidationFailedError('estimate.gas', estimate.gas.toString(), 'gas estimate must be greater than zero');
|
|
13209
|
-
}
|
|
13210
|
-
return buildGasFeeSuccess(name, chain, estimate);
|
|
13211
|
-
} catch (error) {
|
|
13212
|
-
return buildGasFeeFailure(name, chain, error);
|
|
13213
|
-
}
|
|
13214
|
-
}
|
|
13215
|
-
async function estimateApprovalGasFeeIfNeeded(params) {
|
|
13216
|
-
const { adapter, chain, address, tokenAddress, delegate, requiredAllowance } = params;
|
|
13217
|
-
if (requiredAllowance <= 0n) {
|
|
13218
|
-
return undefined;
|
|
13219
|
-
}
|
|
13220
|
-
try {
|
|
13221
|
-
const allowancePrepared = await adapter.prepareAction('token.allowance', {
|
|
13222
|
-
tokenAddress,
|
|
13223
|
-
delegate
|
|
13224
|
-
}, {
|
|
13225
|
-
chain,
|
|
13226
|
-
address
|
|
13227
|
-
});
|
|
13228
|
-
const allowanceRaw = await allowancePrepared.execute();
|
|
13229
|
-
const currentAllowance = parseAllowanceResponse(allowanceRaw);
|
|
13230
|
-
if (currentAllowance >= requiredAllowance) {
|
|
13231
|
-
return undefined;
|
|
13232
|
-
}
|
|
13233
|
-
// Reuse the execute path's approval builder so the estimate simulates the
|
|
13234
|
-
// exact approval (action, amount, and WARM_SLOT_RESIDUAL) that
|
|
13235
|
-
// approveAllowanceIfNeeded later submits.
|
|
13236
|
-
const approvalPrepared = await prepareApprovalAction({
|
|
13237
|
-
adapter,
|
|
13238
|
-
chain,
|
|
13239
|
-
address,
|
|
13240
|
-
tokenAddress,
|
|
13241
|
-
delegate,
|
|
13242
|
-
currentAllowance,
|
|
13243
|
-
requiredAllowance
|
|
13244
|
-
});
|
|
13245
|
-
return await estimatePreparedGasFee('Approve', chain, approvalPrepared);
|
|
13246
|
-
} catch (error) {
|
|
13247
|
-
return buildGasFeeFailure('Approve', chain, error);
|
|
13248
|
-
}
|
|
13249
|
-
}
|
|
13250
|
-
/**
|
|
13251
|
-
* Estimate gas fee entries for an earn quote without submitting transactions.
|
|
13252
|
-
*
|
|
13253
|
-
* Each entry is produced by simulating the prepared transaction against
|
|
13254
|
-
* current chain state. When an approval is required (allowance below the
|
|
13255
|
-
* signed payload's required amount), the subsequent action simulation runs
|
|
13256
|
-
* without that approval in place and is expected to revert — the action entry
|
|
13257
|
-
* then carries `fees: null` with the revert message while the approval entry
|
|
13258
|
-
* still estimates normally. Quote consumers must treat that as "estimate
|
|
13259
|
-
* pending approval", not a hard failure.
|
|
13260
|
-
*
|
|
13261
|
-
* @internal
|
|
13262
|
-
*/ async function estimateEarnQuoteGasFees(params) {
|
|
13263
|
-
const { adapter, chain, address, actionName, actionKey, actionParams, approval } = params;
|
|
13264
|
-
const gasFees = [];
|
|
13265
|
-
if (approval !== undefined) {
|
|
13266
|
-
const approvalEstimate = await estimateApprovalGasFeeIfNeeded({
|
|
13267
|
-
adapter,
|
|
13268
|
-
chain,
|
|
13269
|
-
address,
|
|
13270
|
-
tokenAddress: approval.token,
|
|
13271
|
-
delegate: approval.delegate,
|
|
13272
|
-
requiredAllowance: approval.requiredAllowance
|
|
13273
|
-
});
|
|
13274
|
-
if (approvalEstimate !== undefined) {
|
|
13275
|
-
gasFees.push(approvalEstimate);
|
|
13276
|
-
}
|
|
13277
|
-
}
|
|
13278
|
-
try {
|
|
13279
|
-
const actionPrepared = await adapter.prepareAction(actionKey, actionParams, {
|
|
13280
|
-
chain,
|
|
13281
|
-
address
|
|
13282
|
-
});
|
|
13283
|
-
gasFees.push(await estimatePreparedGasFee(actionName, chain, actionPrepared));
|
|
13284
|
-
} catch (error) {
|
|
13285
|
-
gasFees.push(buildGasFeeFailure(actionName, chain, error));
|
|
13286
|
-
}
|
|
13287
|
-
return gasFees;
|
|
13288
|
-
}
|
|
13289
|
-
|
|
13290
13242
|
// ---------------------------------------------------------------------------
|
|
13291
13243
|
// Shared primitives
|
|
13292
13244
|
// ---------------------------------------------------------------------------
|
|
@@ -13364,7 +13316,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13364
13316
|
asset: z.string(),
|
|
13365
13317
|
assetAddress: z.string(),
|
|
13366
13318
|
lltv: z.number(),
|
|
13367
|
-
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()
|
|
13368
13324
|
});
|
|
13369
13325
|
/**
|
|
13370
13326
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -13378,7 +13334,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13378
13334
|
])
|
|
13379
13335
|
});
|
|
13380
13336
|
/**
|
|
13381
|
-
* 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.
|
|
13382
13405
|
*
|
|
13383
13406
|
* @internal
|
|
13384
13407
|
*/ const vaultInfoResponseSchema = z.object({
|
|
@@ -13403,6 +13426,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13403
13426
|
warnings: z.array(vaultWarningSchema).optional(),
|
|
13404
13427
|
earnKitWarnings: z.array(z.string()).optional()
|
|
13405
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));
|
|
13406
13519
|
// ---------------------------------------------------------------------------
|
|
13407
13520
|
// Position response schema
|
|
13408
13521
|
// ---------------------------------------------------------------------------
|
|
@@ -13532,6 +13645,7 @@ const positionPnlSchema = z.discriminatedUnion('status', [
|
|
|
13532
13645
|
*
|
|
13533
13646
|
* @internal
|
|
13534
13647
|
*/ const depositPayloadSchema = z.object({
|
|
13648
|
+
execId: bridgeDepositExecIdSchema,
|
|
13535
13649
|
executionParams: depositExecutionParamsSchema,
|
|
13536
13650
|
signature: hexSignatureSchema
|
|
13537
13651
|
});
|
|
@@ -13623,6 +13737,21 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13623
13737
|
amount: amountJsonSchema,
|
|
13624
13738
|
vaultAddress: hexAddressSchema
|
|
13625
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);
|
|
13626
13755
|
/**
|
|
13627
13756
|
* Zod schema for the bridge deposit prepare payload.
|
|
13628
13757
|
*
|
|
@@ -13634,6 +13763,10 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13634
13763
|
execId: bridgeDepositExecIdSchema,
|
|
13635
13764
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
13636
13765
|
expiresAt: z.string().datetime(),
|
|
13766
|
+
quoteIssuedAt: z.string().datetime({
|
|
13767
|
+
offset: true
|
|
13768
|
+
}).optional().catch(undefined),
|
|
13769
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
13637
13770
|
review: bridgeDepositPrepareReviewSchema
|
|
13638
13771
|
});
|
|
13639
13772
|
/**
|
|
@@ -13699,6 +13832,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13699
13832
|
*
|
|
13700
13833
|
* @internal
|
|
13701
13834
|
*/ const withdrawPayloadSchema = z.object({
|
|
13835
|
+
execId: bridgeDepositExecIdSchema,
|
|
13702
13836
|
executionParams: withdrawExecutionParamsSchema,
|
|
13703
13837
|
signature: hexSignatureSchema
|
|
13704
13838
|
});
|
|
@@ -13712,6 +13846,27 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13712
13846
|
data: withdrawPayloadSchema
|
|
13713
13847
|
});
|
|
13714
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
|
+
// ---------------------------------------------------------------------------
|
|
13715
13870
|
// Claim rewards response schema
|
|
13716
13871
|
// ---------------------------------------------------------------------------
|
|
13717
13872
|
/**
|
|
@@ -13772,6 +13927,30 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13772
13927
|
token: z.string(),
|
|
13773
13928
|
amount: amountJsonSchema
|
|
13774
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();
|
|
13775
13954
|
/**
|
|
13776
13955
|
* Zod schema for the inner deposit quote payload.
|
|
13777
13956
|
*
|
|
@@ -13787,7 +13966,8 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13787
13966
|
expectedShares: amountJsonSchema,
|
|
13788
13967
|
sharePrice: z.string(),
|
|
13789
13968
|
currentApy: z.number(),
|
|
13790
|
-
fees: z.array(feeSchema).optional()
|
|
13969
|
+
fees: z.array(feeSchema).optional(),
|
|
13970
|
+
gasFees: z.array(quoteGasFeeSchema).optional()
|
|
13791
13971
|
});
|
|
13792
13972
|
/**
|
|
13793
13973
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -13814,6 +13994,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13814
13994
|
sharePrice: z.string(),
|
|
13815
13995
|
maxWithdrawable: amountJsonSchema,
|
|
13816
13996
|
fees: z.array(feeSchema),
|
|
13997
|
+
gasFees: z.array(quoteGasFeeSchema).optional(),
|
|
13817
13998
|
warnings: z.array(z.string()).optional()
|
|
13818
13999
|
});
|
|
13819
14000
|
/**
|
|
@@ -13871,7 +14052,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13871
14052
|
*
|
|
13872
14053
|
* @internal
|
|
13873
14054
|
*/ const getVaultsPayloadSchema = z.object({
|
|
13874
|
-
vaults:
|
|
14055
|
+
vaults: earnOpportunityListSchema,
|
|
13875
14056
|
errors: z.array(vaultErrorSchema)
|
|
13876
14057
|
});
|
|
13877
14058
|
/**
|
|
@@ -13901,7 +14082,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13901
14082
|
*
|
|
13902
14083
|
* @internal
|
|
13903
14084
|
*/ const exploreVaultsPayloadSchema = z.object({
|
|
13904
|
-
vaults:
|
|
14085
|
+
vaults: earnOpportunityListSchema,
|
|
13905
14086
|
pagination: explorePaginationSchema
|
|
13906
14087
|
});
|
|
13907
14088
|
/**
|
|
@@ -13994,6 +14175,16 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
13994
14175
|
*/ function isWithdrawResponse(value) {
|
|
13995
14176
|
return withdrawResponseSchema.safeParse(value).success;
|
|
13996
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
|
+
}
|
|
13997
14188
|
/**
|
|
13998
14189
|
* Type guard for the claim rewards API response.
|
|
13999
14190
|
*
|
|
@@ -14036,7 +14227,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
14036
14227
|
}
|
|
14037
14228
|
|
|
14038
14229
|
var name = "@circle-fin/provider-earn-service";
|
|
14039
|
-
var version = "1.
|
|
14230
|
+
var version = "1.3.0";
|
|
14040
14231
|
var pkg = {
|
|
14041
14232
|
name: name,
|
|
14042
14233
|
version: version};
|
|
@@ -14156,7 +14347,7 @@ var pkg = {
|
|
|
14156
14347
|
}
|
|
14157
14348
|
|
|
14158
14349
|
/**
|
|
14159
|
-
* Convert an API vault info object into the SDK {@link
|
|
14350
|
+
* Convert an API vault info object into the SDK {@link EarnOpportunity} shape.
|
|
14160
14351
|
*
|
|
14161
14352
|
* Map the API chain code back to the SDK chain identifier and hydrate the
|
|
14162
14353
|
* amount payloads into {@link Amount} instances.
|
|
@@ -14167,16 +14358,29 @@ var pkg = {
|
|
|
14167
14358
|
*
|
|
14168
14359
|
* @internal
|
|
14169
14360
|
*/ function toVaultInfo(data) {
|
|
14170
|
-
const { totalDeposits, liquidity, ...vault } = data;
|
|
14361
|
+
const { totalDeposits, liquidity, liquidityProfile, ...vault } = data;
|
|
14171
14362
|
const chain = toSdkChain(vault.chain);
|
|
14172
14363
|
if (chain === undefined) {
|
|
14173
14364
|
throw createInvalidChainError(vault.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
14174
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.
|
|
14175
14371
|
return {
|
|
14176
14372
|
...vault,
|
|
14177
14373
|
chain,
|
|
14178
14374
|
totalDeposits: Amount.fromJSON(totalDeposits),
|
|
14179
|
-
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
|
+
}
|
|
14180
14384
|
};
|
|
14181
14385
|
}
|
|
14182
14386
|
|
|
@@ -14211,8 +14415,11 @@ function toVaultError(error) {
|
|
|
14211
14415
|
}
|
|
14212
14416
|
try {
|
|
14213
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`.
|
|
14214
14421
|
return {
|
|
14215
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14422
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14216
14423
|
errors: response.data.errors.map(toVaultError)
|
|
14217
14424
|
};
|
|
14218
14425
|
} catch (error) {
|
|
@@ -14261,8 +14468,11 @@ function toVaultError(error) {
|
|
|
14261
14468
|
}
|
|
14262
14469
|
try {
|
|
14263
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`.
|
|
14264
14474
|
return {
|
|
14265
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14475
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14266
14476
|
pagination: response.data.pagination
|
|
14267
14477
|
};
|
|
14268
14478
|
} catch (error) {
|
|
@@ -14426,6 +14636,12 @@ function toPositionInfo(data) {
|
|
|
14426
14636
|
execId: response.data.execId,
|
|
14427
14637
|
preparedBundle,
|
|
14428
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
|
+
},
|
|
14429
14645
|
review: response.data.review
|
|
14430
14646
|
};
|
|
14431
14647
|
} catch (error) {
|
|
@@ -14767,7 +14983,110 @@ function toClaimedAmount(reward) {
|
|
|
14767
14983
|
}
|
|
14768
14984
|
}
|
|
14769
14985
|
|
|
14770
|
-
|
|
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) {
|
|
14771
15090
|
const fees = (data.fees ?? []).map(({ token: feeTokenSymbol, ...fee })=>{
|
|
14772
15091
|
// Earn Service returns fee.token as a display symbol, for example "USDC".
|
|
14773
15092
|
return {
|
|
@@ -14796,7 +15115,10 @@ function toDepositQuoteInfo(data) {
|
|
|
14796
15115
|
sharePrice: data.sharePrice,
|
|
14797
15116
|
currentApy: data.currentApy,
|
|
14798
15117
|
fees,
|
|
14799
|
-
|
|
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)
|
|
14800
15122
|
};
|
|
14801
15123
|
}
|
|
14802
15124
|
/**
|
|
@@ -14831,7 +15153,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14831
15153
|
};
|
|
14832
15154
|
try {
|
|
14833
15155
|
const response = await pollApiPost(url.toString(), requestBody, isDepositQuoteResponse, pollingConfig);
|
|
14834
|
-
return toDepositQuoteInfo(response.data);
|
|
15156
|
+
return toDepositQuoteInfo(response.data, params.chainDefinition);
|
|
14835
15157
|
} catch (error) {
|
|
14836
15158
|
throw parseEarnApiError(error, {
|
|
14837
15159
|
operation: 'getDepositQuote'
|
|
@@ -14839,7 +15161,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14839
15161
|
}
|
|
14840
15162
|
}
|
|
14841
15163
|
|
|
14842
|
-
function toWithdrawalQuoteInfo(data) {
|
|
15164
|
+
function toWithdrawalQuoteInfo(data, chain) {
|
|
14843
15165
|
return {
|
|
14844
15166
|
vaultAddress: data.vaultAddress,
|
|
14845
15167
|
vaultName: data.vaultName,
|
|
@@ -14867,7 +15189,7 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14867
15189
|
status
|
|
14868
15190
|
}
|
|
14869
15191
|
})),
|
|
14870
|
-
gasFees: [],
|
|
15192
|
+
gasFees: chain === undefined ? [] : toQuoteGasFees(data.gasFees, chain),
|
|
14871
15193
|
// Wire format uses `warnings`, but the SDK surface uses
|
|
14872
15194
|
// `earnKitWarnings` to match the precedent set by `VaultInfo` —
|
|
14873
15195
|
// `warnings` is reserved for the structured `VaultWarning` shape.
|
|
@@ -14899,7 +15221,7 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14899
15221
|
};
|
|
14900
15222
|
try {
|
|
14901
15223
|
const response = await pollApiPost(url.toString(), requestBody, isWithdrawalQuoteResponse, pollingConfig);
|
|
14902
|
-
return toWithdrawalQuoteInfo(response.data);
|
|
15224
|
+
return toWithdrawalQuoteInfo(response.data, params.chainDefinition);
|
|
14903
15225
|
} catch (error) {
|
|
14904
15226
|
throw parseEarnApiError(error, {
|
|
14905
15227
|
operation: 'getWithdrawalQuote'
|
|
@@ -14935,6 +15257,8 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14935
15257
|
amount: Amount.fromJSON(r.amount),
|
|
14936
15258
|
address: r.token
|
|
14937
15259
|
})),
|
|
15260
|
+
// The claimRewards/quote response does not carry a gas estimate (unlike
|
|
15261
|
+
// deposit/withdrawal quotes), so there is nothing to surface here.
|
|
14938
15262
|
gasFees: []
|
|
14939
15263
|
};
|
|
14940
15264
|
} catch (error) {
|
|
@@ -14944,6 +15268,83 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14944
15268
|
}
|
|
14945
15269
|
}
|
|
14946
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
|
+
|
|
14947
15348
|
/**
|
|
14948
15349
|
* Sum the amounts across every token input to size the allowance approval.
|
|
14949
15350
|
*
|
|
@@ -15054,6 +15455,59 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
15054
15455
|
// Intentionally built-ins-only: Earn bridge support is limited to SDK-known
|
|
15055
15456
|
// token contracts plus the explicit ERC-3009 domain allowlist below.
|
|
15056
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
|
+
}
|
|
15057
15511
|
/**
|
|
15058
15512
|
* Build the typed error raised when a cross-chain wait is cancelled via its
|
|
15059
15513
|
* `AbortSignal`. Mirrors `@core/adapter-base`'s `createAbortError` (same
|
|
@@ -15375,7 +15829,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15375
15829
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15376
15830
|
const { adapter } = params.from;
|
|
15377
15831
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15378
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15832
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15379
15833
|
vaultAddress,
|
|
15380
15834
|
amount: params.amount,
|
|
15381
15835
|
address,
|
|
@@ -15383,32 +15837,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15383
15837
|
config
|
|
15384
15838
|
}), ()=>undefined);
|
|
15385
15839
|
validateExecutionDeadline(executionParams);
|
|
15840
|
+
const transactionReportContext = {
|
|
15841
|
+
execId,
|
|
15842
|
+
chain: apiChain,
|
|
15843
|
+
config
|
|
15844
|
+
};
|
|
15386
15845
|
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15387
15846
|
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15388
15847
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15389
15848
|
if (!options.skipApprove && approvalToken !== undefined && requiredAllowance > 0n) {
|
|
15390
|
-
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({
|
|
15391
15871
|
adapter,
|
|
15392
15872
|
chain,
|
|
15393
|
-
tokenAddress: approvalToken,
|
|
15394
|
-
delegate: adapterContractAddress,
|
|
15395
15873
|
address,
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
}), ({ 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);
|
|
15412
15889
|
return {
|
|
15413
15890
|
kind: 'same-chain',
|
|
15414
15891
|
txHash,
|
|
@@ -15488,7 +15965,13 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15488
15965
|
amount: params.amount,
|
|
15489
15966
|
sourceChain: sourceChain.chain,
|
|
15490
15967
|
destinationChain: destinationChain.chain,
|
|
15491
|
-
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
|
+
}
|
|
15492
15975
|
};
|
|
15493
15976
|
}
|
|
15494
15977
|
/** {@inheritdoc} */ async withdraw(params) {
|
|
@@ -15509,7 +15992,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15509
15992
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15510
15993
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15511
15994
|
const { adapter } = params.from;
|
|
15512
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15995
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15513
15996
|
vaultAddress,
|
|
15514
15997
|
amount: params.amount,
|
|
15515
15998
|
address,
|
|
@@ -15517,32 +16000,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15517
16000
|
config
|
|
15518
16001
|
}), ()=>undefined);
|
|
15519
16002
|
validateExecutionDeadline(executionParams);
|
|
16003
|
+
const transactionReportContext = {
|
|
16004
|
+
execId,
|
|
16005
|
+
chain: apiChain,
|
|
16006
|
+
config
|
|
16007
|
+
};
|
|
15520
16008
|
const tokenInputs = buildEarnTokenInputs(executionParams, vaultAddress);
|
|
15521
16009
|
const approvalToken = tokenInputs[0]?.token;
|
|
15522
16010
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15523
16011
|
if (!options.skipApprove && approvalToken !== undefined) {
|
|
15524
|
-
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({
|
|
15525
16034
|
adapter,
|
|
15526
16035
|
chain,
|
|
15527
|
-
tokenAddress: approvalToken,
|
|
15528
|
-
delegate: adapterContractAddress,
|
|
15529
16036
|
address,
|
|
15530
|
-
|
|
15531
|
-
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
}), ({ 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);
|
|
15546
16052
|
return {
|
|
15547
16053
|
txHash,
|
|
15548
16054
|
explorerUrl,
|
|
@@ -15676,141 +16182,6 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15676
16182
|
}
|
|
15677
16183
|
}
|
|
15678
16184
|
}
|
|
15679
|
-
gasEstimateFailure(name, chain, error) {
|
|
15680
|
-
return {
|
|
15681
|
-
name,
|
|
15682
|
-
token: chain.nativeCurrency.symbol,
|
|
15683
|
-
blockchain: chain.chain,
|
|
15684
|
-
fees: null,
|
|
15685
|
-
error: getErrorMessage(error)
|
|
15686
|
-
};
|
|
15687
|
-
}
|
|
15688
|
-
async estimateDepositQuoteGasFees(params) {
|
|
15689
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15690
|
-
try {
|
|
15691
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15692
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15693
|
-
const { executionParams, signature } = await fetchDeposit({
|
|
15694
|
-
vaultAddress: normalizedVaultAddress,
|
|
15695
|
-
amount,
|
|
15696
|
-
address,
|
|
15697
|
-
chain: apiChain,
|
|
15698
|
-
config
|
|
15699
|
-
});
|
|
15700
|
-
validateExecutionDeadline(executionParams);
|
|
15701
|
-
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15702
|
-
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15703
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15704
|
-
return await estimateEarnQuoteGasFees({
|
|
15705
|
-
adapter,
|
|
15706
|
-
chain,
|
|
15707
|
-
address,
|
|
15708
|
-
actionName: 'Deposit',
|
|
15709
|
-
actionKey: 'earn.deposit',
|
|
15710
|
-
actionParams: {
|
|
15711
|
-
executeParams: executionParams,
|
|
15712
|
-
tokenInputs,
|
|
15713
|
-
signature
|
|
15714
|
-
},
|
|
15715
|
-
approval: approvalToken !== undefined && requiredAllowance > 0n ? {
|
|
15716
|
-
token: approvalToken,
|
|
15717
|
-
delegate: adapterContractAddress,
|
|
15718
|
-
requiredAllowance
|
|
15719
|
-
} : undefined
|
|
15720
|
-
});
|
|
15721
|
-
} catch (error) {
|
|
15722
|
-
return [
|
|
15723
|
-
this.gasEstimateFailure('Deposit', chain, error)
|
|
15724
|
-
];
|
|
15725
|
-
}
|
|
15726
|
-
}
|
|
15727
|
-
async estimateWithdrawalQuoteGasFees(params) {
|
|
15728
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15729
|
-
try {
|
|
15730
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15731
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15732
|
-
const { executionParams, signature } = await fetchWithdraw({
|
|
15733
|
-
vaultAddress: normalizedVaultAddress,
|
|
15734
|
-
amount,
|
|
15735
|
-
address,
|
|
15736
|
-
chain: apiChain,
|
|
15737
|
-
config
|
|
15738
|
-
});
|
|
15739
|
-
validateExecutionDeadline(executionParams);
|
|
15740
|
-
const tokenInputs = buildEarnTokenInputs(executionParams, normalizedVaultAddress);
|
|
15741
|
-
const approvalToken = tokenInputs[0]?.token;
|
|
15742
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15743
|
-
return await estimateEarnQuoteGasFees({
|
|
15744
|
-
adapter,
|
|
15745
|
-
chain,
|
|
15746
|
-
address,
|
|
15747
|
-
actionName: 'Withdraw',
|
|
15748
|
-
actionKey: 'earn.withdraw',
|
|
15749
|
-
actionParams: {
|
|
15750
|
-
executeParams: executionParams,
|
|
15751
|
-
tokenInputs,
|
|
15752
|
-
signature
|
|
15753
|
-
},
|
|
15754
|
-
approval: approvalToken !== undefined ? {
|
|
15755
|
-
token: approvalToken,
|
|
15756
|
-
delegate: adapterContractAddress,
|
|
15757
|
-
requiredAllowance
|
|
15758
|
-
} : undefined
|
|
15759
|
-
});
|
|
15760
|
-
} catch (error) {
|
|
15761
|
-
return [
|
|
15762
|
-
this.gasEstimateFailure('Withdraw', chain, error)
|
|
15763
|
-
];
|
|
15764
|
-
}
|
|
15765
|
-
}
|
|
15766
|
-
async estimateClaimRewardsQuoteGasFees(params) {
|
|
15767
|
-
const { adapter, chain, apiChain, address, vaultAddress, config } = params;
|
|
15768
|
-
try {
|
|
15769
|
-
requireAdapterContract(chain);
|
|
15770
|
-
const { rewards, executionParams, signature } = await fetchClaimRewards({
|
|
15771
|
-
address,
|
|
15772
|
-
chain: apiChain,
|
|
15773
|
-
vaultAddress,
|
|
15774
|
-
config
|
|
15775
|
-
});
|
|
15776
|
-
if (rewards.length === 0) {
|
|
15777
|
-
return [];
|
|
15778
|
-
}
|
|
15779
|
-
const missingExecutionParams = executionParams === undefined;
|
|
15780
|
-
const missingSignature = signature === undefined;
|
|
15781
|
-
if (missingExecutionParams || missingSignature) {
|
|
15782
|
-
throw new KitError({
|
|
15783
|
-
...EarnError.INTERNAL_ERROR,
|
|
15784
|
-
recoverability: 'RETRYABLE',
|
|
15785
|
-
message: 'Claim rewards response must include executionParams and signature when rewards are claimable',
|
|
15786
|
-
cause: {
|
|
15787
|
-
trace: {
|
|
15788
|
-
rewardsCount: rewards.length,
|
|
15789
|
-
missingExecutionParams,
|
|
15790
|
-
missingSignature
|
|
15791
|
-
}
|
|
15792
|
-
}
|
|
15793
|
-
});
|
|
15794
|
-
}
|
|
15795
|
-
validateExecutionDeadline(executionParams);
|
|
15796
|
-
return await estimateEarnQuoteGasFees({
|
|
15797
|
-
adapter,
|
|
15798
|
-
chain,
|
|
15799
|
-
address,
|
|
15800
|
-
actionName: 'Claim Rewards',
|
|
15801
|
-
actionKey: 'earn.claimRewards',
|
|
15802
|
-
actionParams: {
|
|
15803
|
-
executeParams: executionParams,
|
|
15804
|
-
tokenInputs: [],
|
|
15805
|
-
signature
|
|
15806
|
-
}
|
|
15807
|
-
});
|
|
15808
|
-
} catch (error) {
|
|
15809
|
-
return [
|
|
15810
|
-
this.gasEstimateFailure('Claim Rewards', chain, error)
|
|
15811
|
-
];
|
|
15812
|
-
}
|
|
15813
|
-
}
|
|
15814
16185
|
/** {@inheritdoc} */ async getDepositQuote(params) {
|
|
15815
16186
|
const config = this.resolveConfig(params.config);
|
|
15816
16187
|
if (hasQuoteDestinationChain(params)) {
|
|
@@ -15833,96 +16204,43 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15833
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');
|
|
15834
16205
|
}
|
|
15835
16206
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15836
|
-
//
|
|
15837
|
-
//
|
|
15838
|
-
//
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
this.estimateDepositQuoteGasFees({
|
|
15848
|
-
adapter: params.from.adapter,
|
|
15849
|
-
chain: chainDefinition,
|
|
15850
|
-
apiChain: chain,
|
|
15851
|
-
address,
|
|
15852
|
-
vaultAddress: params.vaultAddress,
|
|
15853
|
-
amount: params.amount,
|
|
15854
|
-
config
|
|
15855
|
-
})
|
|
15856
|
-
]);
|
|
15857
|
-
return {
|
|
15858
|
-
...quote,
|
|
15859
|
-
gasFees
|
|
15860
|
-
};
|
|
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
|
+
});
|
|
15861
16218
|
}
|
|
15862
16219
|
/** {@inheritdoc} */ async getWithdrawalQuote(params) {
|
|
15863
16220
|
const config = this.resolveConfig(params.config);
|
|
15864
16221
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15865
|
-
//
|
|
15866
|
-
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
config
|
|
15875
|
-
}),
|
|
15876
|
-
this.estimateWithdrawalQuoteGasFees({
|
|
15877
|
-
adapter: params.from.adapter,
|
|
15878
|
-
chain: chainDefinition,
|
|
15879
|
-
apiChain: chain,
|
|
15880
|
-
address,
|
|
15881
|
-
vaultAddress: params.vaultAddress,
|
|
15882
|
-
amount: params.amount,
|
|
15883
|
-
config
|
|
15884
|
-
})
|
|
15885
|
-
]);
|
|
15886
|
-
return {
|
|
15887
|
-
...quote,
|
|
15888
|
-
gasFees
|
|
15889
|
-
};
|
|
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
|
+
});
|
|
15890
16231
|
}
|
|
15891
16232
|
/** {@inheritdoc} */ async getClaimRewardsQuote(params) {
|
|
15892
16233
|
const config = this.resolveConfig(params.config);
|
|
15893
|
-
const { address, chain
|
|
15894
|
-
|
|
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({
|
|
15895
16239
|
vaultAddress: params.vaultAddress,
|
|
15896
16240
|
address,
|
|
15897
16241
|
chain,
|
|
15898
16242
|
config
|
|
15899
16243
|
});
|
|
15900
|
-
// No claimable rewards means there is nothing to execute, so there is no
|
|
15901
|
-
// gas to estimate. Short-circuit on the already-fetched quote rather than
|
|
15902
|
-
// calling the (heavier) claim execution endpoint again — this also keeps
|
|
15903
|
-
// `gasFees` empty as documented, instead of risking a `{ fees: null }`
|
|
15904
|
-
// estimation-error entry when the adapter/RPC is unavailable. This
|
|
15905
|
-
// short-circuit is why the claim path stays sequential instead of using
|
|
15906
|
-
// the Promise.all pattern of the deposit/withdrawal quotes: estimating in
|
|
15907
|
-
// parallel would hit the signing endpoint even when nothing is claimable.
|
|
15908
|
-
if (quote.rewards.length === 0) {
|
|
15909
|
-
return {
|
|
15910
|
-
...quote,
|
|
15911
|
-
gasFees: []
|
|
15912
|
-
};
|
|
15913
|
-
}
|
|
15914
|
-
const gasFees = await this.estimateClaimRewardsQuoteGasFees({
|
|
15915
|
-
adapter: params.from.adapter,
|
|
15916
|
-
chain: chainDefinition,
|
|
15917
|
-
apiChain: chain,
|
|
15918
|
-
address,
|
|
15919
|
-
vaultAddress: params.vaultAddress,
|
|
15920
|
-
config
|
|
15921
|
-
});
|
|
15922
|
-
return {
|
|
15923
|
-
...quote,
|
|
15924
|
-
gasFees
|
|
15925
|
-
};
|
|
15926
16244
|
}
|
|
15927
16245
|
}
|
|
15928
16246
|
function hasDepositDestination(params) {
|
|
@@ -16160,11 +16478,27 @@ function formatPositionPnL(pnl) {
|
|
|
16160
16478
|
* @param vault - Provider vault info with raw amount objects
|
|
16161
16479
|
* @returns Vault info with total deposits and liquidity formatted as strings
|
|
16162
16480
|
*/ function formatVaultInfo(vault) {
|
|
16163
|
-
|
|
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.
|
|
16164
16490
|
return {
|
|
16165
16491
|
...rest,
|
|
16166
16492
|
totalDeposits: formatAmount(totalDeposits),
|
|
16167
|
-
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
|
+
}
|
|
16168
16502
|
};
|
|
16169
16503
|
}
|
|
16170
16504
|
/**
|
|
@@ -18076,27 +18410,95 @@ function formatRetryResult(operation, result) {
|
|
|
18076
18410
|
// Auto-register this kit for user agent tracking
|
|
18077
18411
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18078
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
|
+
};
|
|
18476
|
+
|
|
18079
18477
|
/**
|
|
18080
18478
|
* Create an EarnKit instance for AppKit earn operations.
|
|
18081
18479
|
*
|
|
18082
|
-
*
|
|
18083
|
-
*
|
|
18084
|
-
*
|
|
18085
|
-
* 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.
|
|
18086
18483
|
*
|
|
18087
|
-
*
|
|
18484
|
+
* @remarks Developer fee hooks from the AppKit context are not applied.
|
|
18485
|
+
* EarnKit does not yet support custom fee policies.
|
|
18088
18486
|
*
|
|
18089
|
-
* @param context - AppKit context
|
|
18090
|
-
* @returns
|
|
18487
|
+
* @param context - AppKit context with earn event handlers and kit options
|
|
18488
|
+
* @returns An EarnKit instance ready for AppKit earn operations
|
|
18091
18489
|
*
|
|
18092
18490
|
* @example
|
|
18093
18491
|
* ```typescript
|
|
18094
18492
|
* const earnKit = createEarnKit(context)
|
|
18095
18493
|
* ```
|
|
18096
|
-
*/ const createEarnKit = ()=>
|
|
18494
|
+
*/ const createEarnKit = (context)=>{
|
|
18495
|
+
const kit = new EarnKit();
|
|
18496
|
+
registerActionHandlers(kit, context.actions.earn, 'earn');
|
|
18497
|
+
return kit;
|
|
18498
|
+
};
|
|
18097
18499
|
|
|
18098
18500
|
async function deposit(context, params) {
|
|
18099
|
-
return createEarnKit().deposit(params);
|
|
18501
|
+
return createEarnKit(context).deposit(params);
|
|
18100
18502
|
}
|
|
18101
18503
|
/**
|
|
18102
18504
|
* Execute an earn withdrawal operation.
|
|
@@ -18120,7 +18522,7 @@ async function deposit(context, params) {
|
|
|
18120
18522
|
* })
|
|
18121
18523
|
* ```
|
|
18122
18524
|
*/ async function withdraw(context, params) {
|
|
18123
|
-
return createEarnKit().withdraw(params);
|
|
18525
|
+
return createEarnKit(context).withdraw(params);
|
|
18124
18526
|
}
|
|
18125
18527
|
/**
|
|
18126
18528
|
* Claim earn rewards.
|
|
@@ -18143,7 +18545,7 @@ async function deposit(context, params) {
|
|
|
18143
18545
|
* })
|
|
18144
18546
|
* ```
|
|
18145
18547
|
*/ async function claimRewards(context, params) {
|
|
18146
|
-
return createEarnKit().claimRewards(params);
|
|
18548
|
+
return createEarnKit(context).claimRewards(params);
|
|
18147
18549
|
}
|
|
18148
18550
|
/**
|
|
18149
18551
|
* Fetch vault information.
|
|
@@ -18165,7 +18567,7 @@ async function deposit(context, params) {
|
|
|
18165
18567
|
* })
|
|
18166
18568
|
* ```
|
|
18167
18569
|
*/ async function getVaults(context, params) {
|
|
18168
|
-
return createEarnKit().getVaults(params);
|
|
18570
|
+
return createEarnKit(context).getVaults(params);
|
|
18169
18571
|
}
|
|
18170
18572
|
/**
|
|
18171
18573
|
* Discover vaults available on a chain.
|
|
@@ -18189,7 +18591,7 @@ async function deposit(context, params) {
|
|
|
18189
18591
|
* })
|
|
18190
18592
|
* ```
|
|
18191
18593
|
*/ async function exploreVaults(context, params) {
|
|
18192
|
-
return createEarnKit().exploreVaults(params);
|
|
18594
|
+
return createEarnKit(context).exploreVaults(params);
|
|
18193
18595
|
}
|
|
18194
18596
|
/**
|
|
18195
18597
|
* Lazily iterate every vault available on a chain.
|
|
@@ -18213,7 +18615,7 @@ async function deposit(context, params) {
|
|
|
18213
18615
|
* }
|
|
18214
18616
|
* ```
|
|
18215
18617
|
*/ function exploreVaultsIterator(context, params) {
|
|
18216
|
-
return createEarnKit().exploreVaultsIterator(params);
|
|
18618
|
+
return createEarnKit(context).exploreVaultsIterator(params);
|
|
18217
18619
|
}
|
|
18218
18620
|
/**
|
|
18219
18621
|
* Fetch a wallet position in a vault.
|
|
@@ -18236,7 +18638,7 @@ async function deposit(context, params) {
|
|
|
18236
18638
|
* })
|
|
18237
18639
|
* ```
|
|
18238
18640
|
*/ async function getPosition(context, params) {
|
|
18239
|
-
return createEarnKit().getPosition(params);
|
|
18641
|
+
return createEarnKit(context).getPosition(params);
|
|
18240
18642
|
}
|
|
18241
18643
|
/**
|
|
18242
18644
|
* Fetch the current status of a cross-chain Earn deposit.
|
|
@@ -18258,7 +18660,7 @@ async function deposit(context, params) {
|
|
|
18258
18660
|
* console.log(status.status)
|
|
18259
18661
|
* ```
|
|
18260
18662
|
*/ async function getCrossChainDepositStatus(context, params) {
|
|
18261
|
-
return createEarnKit().getCrossChainDepositStatus(params);
|
|
18663
|
+
return createEarnKit(context).getCrossChainDepositStatus(params);
|
|
18262
18664
|
}
|
|
18263
18665
|
/**
|
|
18264
18666
|
* Poll a cross-chain Earn deposit until it reaches a terminal bridge state.
|
|
@@ -18281,7 +18683,7 @@ async function deposit(context, params) {
|
|
|
18281
18683
|
* console.log(result.outcome)
|
|
18282
18684
|
* ```
|
|
18283
18685
|
*/ async function waitForCrossChainDeposit(context, params) {
|
|
18284
|
-
return createEarnKit().waitForCrossChainDeposit(params);
|
|
18686
|
+
return createEarnKit(context).waitForCrossChainDeposit(params);
|
|
18285
18687
|
}
|
|
18286
18688
|
/**
|
|
18287
18689
|
* Fetch a deposit quote.
|
|
@@ -18305,7 +18707,7 @@ async function deposit(context, params) {
|
|
|
18305
18707
|
* })
|
|
18306
18708
|
* ```
|
|
18307
18709
|
*/ async function getDepositQuote(context, params) {
|
|
18308
|
-
return createEarnKit().getDepositQuote(params);
|
|
18710
|
+
return createEarnKit(context).getDepositQuote(params);
|
|
18309
18711
|
}
|
|
18310
18712
|
/**
|
|
18311
18713
|
* Fetch a withdrawal quote.
|
|
@@ -18329,7 +18731,7 @@ async function deposit(context, params) {
|
|
|
18329
18731
|
* })
|
|
18330
18732
|
* ```
|
|
18331
18733
|
*/ async function getWithdrawalQuote(context, params) {
|
|
18332
|
-
return createEarnKit().getWithdrawalQuote(params);
|
|
18734
|
+
return createEarnKit(context).getWithdrawalQuote(params);
|
|
18333
18735
|
}
|
|
18334
18736
|
/**
|
|
18335
18737
|
* Fetch a claim rewards quote.
|
|
@@ -18352,8 +18754,44 @@ async function deposit(context, params) {
|
|
|
18352
18754
|
* })
|
|
18353
18755
|
* ```
|
|
18354
18756
|
*/ async function getClaimRewardsQuote(context, params) {
|
|
18355
|
-
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);
|
|
18356
18794
|
}
|
|
18357
18795
|
|
|
18358
|
-
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 };
|
|
18359
18797
|
//# sourceMappingURL=earn.mjs.map
|