@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.cjs
CHANGED
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
|
|
21
21
|
var zod = require('zod');
|
|
22
22
|
require('pino');
|
|
23
|
+
require('@ethersproject/bytes');
|
|
24
|
+
require('@ethersproject/abi');
|
|
25
|
+
require('@ethersproject/address');
|
|
23
26
|
var web3_js = require('@solana/web3.js');
|
|
24
27
|
require('bn.js');
|
|
25
28
|
require('@coral-xyz/anchor');
|
|
@@ -1761,14 +1764,14 @@ class KitError extends Error {
|
|
|
1761
1764
|
}
|
|
1762
1765
|
|
|
1763
1766
|
/**
|
|
1764
|
-
* Standardized error definitions for Earn
|
|
1767
|
+
* Standardized error definitions for Earn operations.
|
|
1765
1768
|
*
|
|
1766
1769
|
* These error codes provide fine-grained categorization of failures
|
|
1767
|
-
* from the
|
|
1770
|
+
* from the Earn service, enabling SDK consumers to distinguish
|
|
1768
1771
|
* between input errors (fix your request) and service errors (retry later).
|
|
1769
1772
|
*
|
|
1770
1773
|
* Error code ranges:
|
|
1771
|
-
* - 1100-
|
|
1774
|
+
* - 1100-1106: INPUT errors — invalid, unsupported, or stale request state
|
|
1772
1775
|
* - 8100-8105: SERVICE errors — retryable backend/provider failures
|
|
1773
1776
|
*
|
|
1774
1777
|
* @example
|
|
@@ -1821,6 +1824,14 @@ class KitError extends Error {
|
|
|
1821
1824
|
name: 'EARN_UNSUPPORTED_BRIDGE_ROUTE',
|
|
1822
1825
|
type: 'INPUT'
|
|
1823
1826
|
},
|
|
1827
|
+
/**
|
|
1828
|
+
* The bridge quote expired. This is an INPUT error because the prepared
|
|
1829
|
+
* request is stale and must be replaced instead of retried.
|
|
1830
|
+
*/ BRIDGE_QUOTE_EXPIRED: {
|
|
1831
|
+
code: 1106,
|
|
1832
|
+
name: 'EARN_BRIDGE_QUOTE_EXPIRED',
|
|
1833
|
+
type: 'INPUT'
|
|
1834
|
+
},
|
|
1824
1835
|
/** The proxy signing call failed — retryable. */ SIGNING_FAILED: {
|
|
1825
1836
|
code: 8100,
|
|
1826
1837
|
name: 'EARN_SIGNING_FAILED',
|
|
@@ -1880,6 +1891,9 @@ function getOptionalString(value) {
|
|
|
1880
1891
|
* internal-error, vault-refresh-busy, off-chain-paused, position-PnL-pending,
|
|
1881
1892
|
* bridge failures/status lookup failures
|
|
1882
1893
|
*
|
|
1894
|
+
* Quote expiry is INPUT/FATAL because callers must start a fresh bridge prepare
|
|
1895
|
+
* flow rather than retry the stale prepared bundle.
|
|
1896
|
+
*
|
|
1883
1897
|
* Unrecognized codes fall through to `parseApiError` for HTTP-status-based
|
|
1884
1898
|
* handling.
|
|
1885
1899
|
*
|
|
@@ -2113,6 +2127,13 @@ function getOptionalString(value) {
|
|
|
2113
2127
|
errorDef: EarnError.PROVIDER_ERROR,
|
|
2114
2128
|
recoverability: 'FATAL'
|
|
2115
2129
|
}
|
|
2130
|
+
],
|
|
2131
|
+
[
|
|
2132
|
+
380506,
|
|
2133
|
+
{
|
|
2134
|
+
errorDef: EarnError.BRIDGE_QUOTE_EXPIRED,
|
|
2135
|
+
recoverability: 'FATAL'
|
|
2136
|
+
}
|
|
2116
2137
|
]
|
|
2117
2138
|
]);
|
|
2118
2139
|
/**
|
|
@@ -2836,7 +2857,10 @@ var EarnChain;
|
|
|
2836
2857
|
contracts: {
|
|
2837
2858
|
v1: {
|
|
2838
2859
|
wallet: GATEWAY_WALLET_EVM_TESTNET,
|
|
2839
|
-
minter: GATEWAY_MINTER_EVM_TESTNET
|
|
2860
|
+
minter: GATEWAY_MINTER_EVM_TESTNET,
|
|
2861
|
+
// DepositForHandler the GenericExecutor calls to run a fast cross-chain
|
|
2862
|
+
// deposit into the GatewayWallet above.
|
|
2863
|
+
depositForHandler: '0xD05E7D2E7d30b92c5F17d7d0fC575fce231F1A48'
|
|
2840
2864
|
}
|
|
2841
2865
|
},
|
|
2842
2866
|
forwarderSupported: {
|
|
@@ -5904,7 +5928,10 @@ var Chains = {
|
|
|
5904
5928
|
minter: zod.z.string({
|
|
5905
5929
|
required_error: 'Gateway minter address is required. Please provide a valid contract address.',
|
|
5906
5930
|
invalid_type_error: 'Gateway minter address must be a string.'
|
|
5907
|
-
}).min(1, 'Gateway minter address cannot be empty.')
|
|
5931
|
+
}).min(1, 'Gateway minter address cannot be empty.'),
|
|
5932
|
+
depositForHandler: zod.z.string({
|
|
5933
|
+
invalid_type_error: 'Gateway depositForHandler address must be a string.'
|
|
5934
|
+
}).min(1, 'Gateway depositForHandler address cannot be empty.').optional()
|
|
5908
5935
|
}).strict() // Reject any additional properties not defined in the schema
|
|
5909
5936
|
;
|
|
5910
5937
|
/**
|
|
@@ -8016,6 +8043,13 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8016
8043
|
return explorerUrl;
|
|
8017
8044
|
}
|
|
8018
8045
|
|
|
8046
|
+
/**
|
|
8047
|
+
* CCTP forwarding magic bytes prefix.
|
|
8048
|
+
*
|
|
8049
|
+
* The ASCII string "cctp-forward" (12 bytes) that identifies a forwarding request.
|
|
8050
|
+
* This prefix is right-padded to 24 bytes in the final hookData.
|
|
8051
|
+
*/ const CCTP_FORWARD_MAGIC_PREFIX = 'cctp-forward';
|
|
8052
|
+
|
|
8019
8053
|
/**
|
|
8020
8054
|
* Strip the `@circle-fin/` scope from a kit package name to produce the
|
|
8021
8055
|
* short SDK name used in telemetry payloads.
|
|
@@ -8035,7 +8069,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8035
8069
|
}
|
|
8036
8070
|
|
|
8037
8071
|
var name$3 = "@circle-fin/bridge-kit";
|
|
8038
|
-
var version$3 = "1.12.
|
|
8072
|
+
var version$3 = "1.12.1";
|
|
8039
8073
|
var pkg$3 = {
|
|
8040
8074
|
name: name$3,
|
|
8041
8075
|
version: version$3};
|
|
@@ -8860,6 +8894,11 @@ var TransferSpeed;
|
|
|
8860
8894
|
clock: zod.z.any().optional()
|
|
8861
8895
|
}).passthrough();
|
|
8862
8896
|
|
|
8897
|
+
/**
|
|
8898
|
+
* The ASCII "cctp-forward" magic, hex-encoded (no `0x`), that a forward-friendly
|
|
8899
|
+
* hookData must start with.
|
|
8900
|
+
*/ Buffer.from(CCTP_FORWARD_MAGIC_PREFIX, 'ascii').toString('hex');
|
|
8901
|
+
|
|
8863
8902
|
/**
|
|
8864
8903
|
* The minimum finality threshold for CCTPv2 transfers.
|
|
8865
8904
|
*
|
|
@@ -8892,7 +8931,7 @@ var TransferSpeed;
|
|
|
8892
8931
|
registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
8893
8932
|
|
|
8894
8933
|
var name$2 = "@circle-fin/swap-kit";
|
|
8895
|
-
var version$2 = "1.
|
|
8934
|
+
var version$2 = "1.4.0";
|
|
8896
8935
|
var pkg$2 = {
|
|
8897
8936
|
name: name$2,
|
|
8898
8937
|
version: version$2};
|
|
@@ -8957,7 +8996,10 @@ const optionalChainIdentifierField = chainIdentifierField.optional();
|
|
|
8957
8996
|
}).min(1, 'kitKey must be a non-empty string').optional(),
|
|
8958
8997
|
provider: zod.z.string({
|
|
8959
8998
|
invalid_type_error: 'provider must be a string'
|
|
8960
|
-
}).min(1, 'provider must be a non-empty string').optional()
|
|
8999
|
+
}).min(1, 'provider must be a non-empty string').optional(),
|
|
9000
|
+
batchTransactions: zod.z.boolean({
|
|
9001
|
+
invalid_type_error: 'batchTransactions must be a boolean'
|
|
9002
|
+
}).optional()
|
|
8961
9003
|
});
|
|
8962
9004
|
/**
|
|
8963
9005
|
* Zod schema for adapter context.
|
|
@@ -9396,7 +9438,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9396
9438
|
/**
|
|
9397
9439
|
* Circle Stablecoin Service API Key.
|
|
9398
9440
|
* Must be a valid API key format.
|
|
9399
|
-
*/ apiKey: apiKeySchema
|
|
9441
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9400
9442
|
}).superRefine(requireCrossChainQuoteToAddress);
|
|
9401
9443
|
/**
|
|
9402
9444
|
* Zod schema for validating CreateSwapRequest parameters.
|
|
@@ -9454,7 +9496,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9454
9496
|
/**
|
|
9455
9497
|
* Circle Stablecoin Service API Key.
|
|
9456
9498
|
* Must be a valid API key format.
|
|
9457
|
-
*/ apiKey: apiKeySchema
|
|
9499
|
+
*/ apiKey: apiKeySchema.optional()
|
|
9458
9500
|
});
|
|
9459
9501
|
/**
|
|
9460
9502
|
* Zod schema for validating GetSwapStatusResponse data.
|
|
@@ -9490,7 +9532,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9490
9532
|
toChain: zod.z.string({
|
|
9491
9533
|
invalid_type_error: 'toChain must be a string'
|
|
9492
9534
|
}).min(1, 'toChain must be a non-empty string if provided').optional(),
|
|
9493
|
-
apiKey: apiKeySchema
|
|
9535
|
+
apiKey: apiKeySchema.optional()
|
|
9494
9536
|
});
|
|
9495
9537
|
/**
|
|
9496
9538
|
* Zod schema for validating CreateSwapResponse payloads.
|
|
@@ -9499,13 +9541,15 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9499
9541
|
required_error: 'fee token is required',
|
|
9500
9542
|
invalid_type_error: 'fee token must be a string'
|
|
9501
9543
|
}).min(1, 'fee token must be a non-empty string'),
|
|
9502
|
-
amount: feeAmountSchema
|
|
9544
|
+
amount: feeAmountSchema,
|
|
9545
|
+
decimals: zod.z.number().int('fee token decimals must be an integer').nonnegative('fee token decimals must be a non-negative integer').optional(),
|
|
9546
|
+
symbol: zod.z.string({
|
|
9547
|
+
invalid_type_error: 'fee token symbol must be a string'
|
|
9548
|
+
}).min(1, 'fee token symbol must be a non-empty string').optional()
|
|
9503
9549
|
});
|
|
9504
9550
|
/**
|
|
9505
9551
|
* Developer fee item schema with basis field.
|
|
9506
|
-
*/ const createSwapDeveloperFeeItemSchema =
|
|
9507
|
-
token: zod.z.string().min(1, 'fee token must be a non-empty string'),
|
|
9508
|
-
amount: feeAmountSchema,
|
|
9552
|
+
*/ const createSwapDeveloperFeeItemSchema = createSwapFeeItemSchema.extend({
|
|
9509
9553
|
basis: zod.z.enum([
|
|
9510
9554
|
'inputAmount',
|
|
9511
9555
|
'estimatedAmount'
|
|
@@ -9597,7 +9641,7 @@ getQuoteRequestBaseSchema.superRefine(requireCrossChainQuoteToAddress);
|
|
|
9597
9641
|
addresses: zod.z.array(zod.z.string({
|
|
9598
9642
|
invalid_type_error: 'addresses entries must be strings'
|
|
9599
9643
|
}).min(1, 'addresses entries must be non-empty strings')).min(1, 'addresses must contain at least one entry when provided').max(MAX_RATE_ADDRESSES_PER_REQUEST, `addresses supports at most ${String(MAX_RATE_ADDRESSES_PER_REQUEST)} values per request`).optional(),
|
|
9600
|
-
apiKey: apiKeySchema
|
|
9644
|
+
apiKey: apiKeySchema.optional()
|
|
9601
9645
|
});
|
|
9602
9646
|
/**
|
|
9603
9647
|
* Zod schema for validating GetTokenRatesResponse payloads.
|
|
@@ -12186,7 +12230,7 @@ new Set(Object.values(Blockchain));
|
|
|
12186
12230
|
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
12187
12231
|
|
|
12188
12232
|
var name$1 = "@circle-fin/earn-kit";
|
|
12189
|
-
var version$1 = "1.
|
|
12233
|
+
var version$1 = "1.3.0";
|
|
12190
12234
|
var pkg$1 = {
|
|
12191
12235
|
name: name$1,
|
|
12192
12236
|
version: version$1};
|
|
@@ -12653,7 +12697,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12653
12697
|
*
|
|
12654
12698
|
* @param params - Adapter, chain, token/delegate/wallet addresses, the required
|
|
12655
12699
|
* allowance for the signed payload, and a revert message for on-chain failure.
|
|
12656
|
-
* @returns The approval transaction
|
|
12700
|
+
* @returns The approval transaction result when an approval was submitted, or
|
|
12657
12701
|
* `undefined` when the existing allowance already covers `requiredAllowance`
|
|
12658
12702
|
* (or `requiredAllowance` is zero).
|
|
12659
12703
|
* @throws {@link KitError} If the `token.allowance` response is malformed.
|
|
@@ -12661,7 +12705,7 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12661
12705
|
*
|
|
12662
12706
|
* @example
|
|
12663
12707
|
* ```typescript
|
|
12664
|
-
* const
|
|
12708
|
+
* const approval = await approveAllowanceIfNeeded({
|
|
12665
12709
|
* adapter,
|
|
12666
12710
|
* chain,
|
|
12667
12711
|
* tokenAddress: usdcAddress,
|
|
@@ -12723,7 +12767,15 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12723
12767
|
maxAttempts: params.allowancePropagation?.maxAttempts ?? DEFAULT_PROPAGATION_ATTEMPTS,
|
|
12724
12768
|
delayMs: params.allowancePropagation?.delayMs ?? DEFAULT_PROPAGATION_DELAY_MS
|
|
12725
12769
|
});
|
|
12726
|
-
return
|
|
12770
|
+
return {
|
|
12771
|
+
txHash: approvalTxHash,
|
|
12772
|
+
...approvalReceipt.gasUsed !== undefined && {
|
|
12773
|
+
gasUsed: approvalReceipt.gasUsed
|
|
12774
|
+
},
|
|
12775
|
+
...approvalReceipt.effectiveGasPrice !== undefined && {
|
|
12776
|
+
effectiveGasPrice: approvalReceipt.effectiveGasPrice
|
|
12777
|
+
}
|
|
12778
|
+
};
|
|
12727
12779
|
}
|
|
12728
12780
|
|
|
12729
12781
|
/** @internal */ function isSameAddress(actual, expected) {
|
|
@@ -12871,7 +12923,13 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
12871
12923
|
}
|
|
12872
12924
|
return {
|
|
12873
12925
|
txHash,
|
|
12874
|
-
explorerUrl
|
|
12926
|
+
explorerUrl,
|
|
12927
|
+
...receipt.gasUsed !== undefined && {
|
|
12928
|
+
gasUsed: receipt.gasUsed
|
|
12929
|
+
},
|
|
12930
|
+
...receipt.effectiveGasPrice !== undefined && {
|
|
12931
|
+
effectiveGasPrice: receipt.effectiveGasPrice
|
|
12932
|
+
}
|
|
12875
12933
|
};
|
|
12876
12934
|
}
|
|
12877
12935
|
|
|
@@ -13183,112 +13241,6 @@ const EARN_OPERATIONS = new Set([
|
|
|
13183
13241
|
return hasEarnServiceParamsShape(operation, candidate['params']);
|
|
13184
13242
|
}
|
|
13185
13243
|
|
|
13186
|
-
function buildGasFeeBase(name, chain) {
|
|
13187
|
-
return {
|
|
13188
|
-
name,
|
|
13189
|
-
token: chain.nativeCurrency.symbol,
|
|
13190
|
-
blockchain: chain.chain
|
|
13191
|
-
};
|
|
13192
|
-
}
|
|
13193
|
-
function buildGasFeeSuccess(name, chain, fees) {
|
|
13194
|
-
return {
|
|
13195
|
-
...buildGasFeeBase(name, chain),
|
|
13196
|
-
fees
|
|
13197
|
-
};
|
|
13198
|
-
}
|
|
13199
|
-
function buildGasFeeFailure(name, chain, error) {
|
|
13200
|
-
return {
|
|
13201
|
-
...buildGasFeeBase(name, chain),
|
|
13202
|
-
fees: null,
|
|
13203
|
-
error: getErrorMessage(error)
|
|
13204
|
-
};
|
|
13205
|
-
}
|
|
13206
|
-
async function estimatePreparedGasFee(name, chain, prepared) {
|
|
13207
|
-
try {
|
|
13208
|
-
const estimate = bufferEstimatedGas(await prepared.estimate());
|
|
13209
|
-
if (estimate.gas <= 0n) {
|
|
13210
|
-
throw createValidationFailedError('estimate.gas', estimate.gas.toString(), 'gas estimate must be greater than zero');
|
|
13211
|
-
}
|
|
13212
|
-
return buildGasFeeSuccess(name, chain, estimate);
|
|
13213
|
-
} catch (error) {
|
|
13214
|
-
return buildGasFeeFailure(name, chain, error);
|
|
13215
|
-
}
|
|
13216
|
-
}
|
|
13217
|
-
async function estimateApprovalGasFeeIfNeeded(params) {
|
|
13218
|
-
const { adapter, chain, address, tokenAddress, delegate, requiredAllowance } = params;
|
|
13219
|
-
if (requiredAllowance <= 0n) {
|
|
13220
|
-
return undefined;
|
|
13221
|
-
}
|
|
13222
|
-
try {
|
|
13223
|
-
const allowancePrepared = await adapter.prepareAction('token.allowance', {
|
|
13224
|
-
tokenAddress,
|
|
13225
|
-
delegate
|
|
13226
|
-
}, {
|
|
13227
|
-
chain,
|
|
13228
|
-
address
|
|
13229
|
-
});
|
|
13230
|
-
const allowanceRaw = await allowancePrepared.execute();
|
|
13231
|
-
const currentAllowance = parseAllowanceResponse(allowanceRaw);
|
|
13232
|
-
if (currentAllowance >= requiredAllowance) {
|
|
13233
|
-
return undefined;
|
|
13234
|
-
}
|
|
13235
|
-
// Reuse the execute path's approval builder so the estimate simulates the
|
|
13236
|
-
// exact approval (action, amount, and WARM_SLOT_RESIDUAL) that
|
|
13237
|
-
// approveAllowanceIfNeeded later submits.
|
|
13238
|
-
const approvalPrepared = await prepareApprovalAction({
|
|
13239
|
-
adapter,
|
|
13240
|
-
chain,
|
|
13241
|
-
address,
|
|
13242
|
-
tokenAddress,
|
|
13243
|
-
delegate,
|
|
13244
|
-
currentAllowance,
|
|
13245
|
-
requiredAllowance
|
|
13246
|
-
});
|
|
13247
|
-
return await estimatePreparedGasFee('Approve', chain, approvalPrepared);
|
|
13248
|
-
} catch (error) {
|
|
13249
|
-
return buildGasFeeFailure('Approve', chain, error);
|
|
13250
|
-
}
|
|
13251
|
-
}
|
|
13252
|
-
/**
|
|
13253
|
-
* Estimate gas fee entries for an earn quote without submitting transactions.
|
|
13254
|
-
*
|
|
13255
|
-
* Each entry is produced by simulating the prepared transaction against
|
|
13256
|
-
* current chain state. When an approval is required (allowance below the
|
|
13257
|
-
* signed payload's required amount), the subsequent action simulation runs
|
|
13258
|
-
* without that approval in place and is expected to revert — the action entry
|
|
13259
|
-
* then carries `fees: null` with the revert message while the approval entry
|
|
13260
|
-
* still estimates normally. Quote consumers must treat that as "estimate
|
|
13261
|
-
* pending approval", not a hard failure.
|
|
13262
|
-
*
|
|
13263
|
-
* @internal
|
|
13264
|
-
*/ async function estimateEarnQuoteGasFees(params) {
|
|
13265
|
-
const { adapter, chain, address, actionName, actionKey, actionParams, approval } = params;
|
|
13266
|
-
const gasFees = [];
|
|
13267
|
-
if (approval !== undefined) {
|
|
13268
|
-
const approvalEstimate = await estimateApprovalGasFeeIfNeeded({
|
|
13269
|
-
adapter,
|
|
13270
|
-
chain,
|
|
13271
|
-
address,
|
|
13272
|
-
tokenAddress: approval.token,
|
|
13273
|
-
delegate: approval.delegate,
|
|
13274
|
-
requiredAllowance: approval.requiredAllowance
|
|
13275
|
-
});
|
|
13276
|
-
if (approvalEstimate !== undefined) {
|
|
13277
|
-
gasFees.push(approvalEstimate);
|
|
13278
|
-
}
|
|
13279
|
-
}
|
|
13280
|
-
try {
|
|
13281
|
-
const actionPrepared = await adapter.prepareAction(actionKey, actionParams, {
|
|
13282
|
-
chain,
|
|
13283
|
-
address
|
|
13284
|
-
});
|
|
13285
|
-
gasFees.push(await estimatePreparedGasFee(actionName, chain, actionPrepared));
|
|
13286
|
-
} catch (error) {
|
|
13287
|
-
gasFees.push(buildGasFeeFailure(actionName, chain, error));
|
|
13288
|
-
}
|
|
13289
|
-
return gasFees;
|
|
13290
|
-
}
|
|
13291
|
-
|
|
13292
13244
|
// ---------------------------------------------------------------------------
|
|
13293
13245
|
// Shared primitives
|
|
13294
13246
|
// ---------------------------------------------------------------------------
|
|
@@ -13366,7 +13318,11 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13366
13318
|
asset: zod.z.string(),
|
|
13367
13319
|
assetAddress: zod.z.string(),
|
|
13368
13320
|
lltv: zod.z.number(),
|
|
13369
|
-
supplyUsd: zod.z.number()
|
|
13321
|
+
supplyUsd: zod.z.number(),
|
|
13322
|
+
// Optional during the expand/contract window (a backend that predates the
|
|
13323
|
+
// field omits the key), mirroring the `.optional()` facets on the base
|
|
13324
|
+
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
13325
|
+
allocationPct: zod.z.number().nullable().optional()
|
|
13370
13326
|
});
|
|
13371
13327
|
/**
|
|
13372
13328
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -13380,7 +13336,74 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13380
13336
|
])
|
|
13381
13337
|
});
|
|
13382
13338
|
/**
|
|
13383
|
-
* Zod schema for
|
|
13339
|
+
* Zod schema for the manager (curator) facet in the API response.
|
|
13340
|
+
*
|
|
13341
|
+
* @internal
|
|
13342
|
+
*/ const managerSchema = zod.z.object({
|
|
13343
|
+
name: zod.z.string(),
|
|
13344
|
+
address: zod.z.string().optional(),
|
|
13345
|
+
// Only 'curator' is emitted today (Morpho V1/V2). Additional manager roles
|
|
13346
|
+
// are added here as the providers that emit them land, rather than shipped
|
|
13347
|
+
// speculatively.
|
|
13348
|
+
type: zod.z.enum([
|
|
13349
|
+
'curator'
|
|
13350
|
+
])
|
|
13351
|
+
});
|
|
13352
|
+
/**
|
|
13353
|
+
* Zod schema for the APY profile facet in the API response.
|
|
13354
|
+
*
|
|
13355
|
+
* @internal
|
|
13356
|
+
*/ const apyProfileSchema = zod.z.object({
|
|
13357
|
+
current: zod.z.number(),
|
|
13358
|
+
native: zod.z.number().nullable(),
|
|
13359
|
+
d7: zod.z.number().nullable(),
|
|
13360
|
+
d30: zod.z.number().nullable(),
|
|
13361
|
+
d90: zod.z.number().nullable(),
|
|
13362
|
+
rewardShare: zod.z.number().nullable(),
|
|
13363
|
+
source: zod.z.string().optional(),
|
|
13364
|
+
asOf: zod.z.string().optional()
|
|
13365
|
+
});
|
|
13366
|
+
/**
|
|
13367
|
+
* Zod schema for the fee split facet in the API response.
|
|
13368
|
+
*
|
|
13369
|
+
* @internal
|
|
13370
|
+
*/ const feeInfoSchema = zod.z.object({
|
|
13371
|
+
performance: zod.z.number().nullable(),
|
|
13372
|
+
management: zod.z.number().nullable()
|
|
13373
|
+
});
|
|
13374
|
+
/**
|
|
13375
|
+
* Zod schema for the liquidity profile facet in the API response.
|
|
13376
|
+
*
|
|
13377
|
+
* `totalSupply` is the outstanding vault share tokens (ERC4626 totalSupply);
|
|
13378
|
+
* it is validated as a raw JSON amount, like `totalDeposits`/`available`.
|
|
13379
|
+
*
|
|
13380
|
+
* @internal
|
|
13381
|
+
*/ const liquidityProfileSchema = zod.z.object({
|
|
13382
|
+
totalDeposits: amountJsonSchema,
|
|
13383
|
+
available: amountJsonSchema,
|
|
13384
|
+
totalSupply: amountJsonSchema,
|
|
13385
|
+
status: zod.z.enum([
|
|
13386
|
+
'active',
|
|
13387
|
+
'low_liquidity'
|
|
13388
|
+
])
|
|
13389
|
+
});
|
|
13390
|
+
/**
|
|
13391
|
+
* Zod schema for the risk signals facet in the API response.
|
|
13392
|
+
*
|
|
13393
|
+
* @internal
|
|
13394
|
+
*/ const riskSignalsSchema = zod.z.object({
|
|
13395
|
+
circleSentinel: zod.z.boolean(),
|
|
13396
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
13397
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
13398
|
+
});
|
|
13399
|
+
/**
|
|
13400
|
+
* Zod schema for the universal earn-opportunity base in the API response.
|
|
13401
|
+
*
|
|
13402
|
+
* Retains every existing deprecated flat field (kept validated through the
|
|
13403
|
+
* expand/contract window so default-strip does not drop them) and adds the
|
|
13404
|
+
* new nested facets. The nested facets are `.optional()` during the
|
|
13405
|
+
* transition so the SDK still validates against a not-yet-fully-deployed
|
|
13406
|
+
* backend; they become required after Expand ships.
|
|
13384
13407
|
*
|
|
13385
13408
|
* @internal
|
|
13386
13409
|
*/ const vaultInfoResponseSchema = zod.z.object({
|
|
@@ -13405,6 +13428,96 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
13405
13428
|
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
13406
13429
|
earnKitWarnings: zod.z.array(zod.z.string()).optional()
|
|
13407
13430
|
});
|
|
13431
|
+
/**
|
|
13432
|
+
* Shared base schema: existing flat fields (kept) plus the new nested
|
|
13433
|
+
* facets and neutral identity. Facets are `.optional()` during the
|
|
13434
|
+
* transition; flip to required once the backend is confirmed emitting.
|
|
13435
|
+
*
|
|
13436
|
+
* @internal
|
|
13437
|
+
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
13438
|
+
address: zod.z.string().optional(),
|
|
13439
|
+
asOf: zod.z.string().optional(),
|
|
13440
|
+
manager: managerSchema.nullable().optional(),
|
|
13441
|
+
apyProfile: apyProfileSchema.optional(),
|
|
13442
|
+
fee: feeInfoSchema.optional(),
|
|
13443
|
+
liquidityProfile: liquidityProfileSchema.optional(),
|
|
13444
|
+
riskSignals: riskSignalsSchema.optional()
|
|
13445
|
+
});
|
|
13446
|
+
/**
|
|
13447
|
+
* Zod schema for the `vault` opportunity variant.
|
|
13448
|
+
*
|
|
13449
|
+
* @internal
|
|
13450
|
+
*/ const vaultOpportunitySchema = earnBaseSchema.extend({
|
|
13451
|
+
productType: zod.z.literal('vault'),
|
|
13452
|
+
collateral: zod.z.array(collateralSchema)
|
|
13453
|
+
});
|
|
13454
|
+
/**
|
|
13455
|
+
* Discriminated union over `productType`. Add union members here as new
|
|
13456
|
+
* product types (e.g. `lending_market`, `rwa_token`) land.
|
|
13457
|
+
*
|
|
13458
|
+
* @internal
|
|
13459
|
+
*/ const earnOpportunityVariants = [
|
|
13460
|
+
vaultOpportunitySchema
|
|
13461
|
+
];
|
|
13462
|
+
/** @internal */ const earnOpportunitySchema = zod.z.discriminatedUnion('productType', earnOpportunityVariants);
|
|
13463
|
+
/** Product types this SDK version knows how to parse. */ const knownProductTypes = new Set(earnOpportunityVariants.map((variant)=>variant.shape.productType.value));
|
|
13464
|
+
/**
|
|
13465
|
+
* Tolerant list parser for earn opportunities.
|
|
13466
|
+
*
|
|
13467
|
+
* `z.discriminatedUnion` throws on an unrecognized discriminant and
|
|
13468
|
+
* `z.array` fails the whole array if any element fails. Two migration-window
|
|
13469
|
+
* cases are smoothed over here so neither breaks an already-shipped SDK:
|
|
13470
|
+
*
|
|
13471
|
+
* - A backend that predates `productType` omits it entirely. `'vault'` was the
|
|
13472
|
+
* only opportunity type then, so default a missing discriminant to `'vault'`
|
|
13473
|
+
* rather than dropping every vault the backend returns.
|
|
13474
|
+
* - A future backend adds a *second* `productType` this SDK version does not
|
|
13475
|
+
* know. Drop those elements (a present-but-unrecognized discriminant) instead
|
|
13476
|
+
* of rejecting the whole list.
|
|
13477
|
+
*
|
|
13478
|
+
* Only the drop above is a *tolerant* case. Anything that is not a plain object
|
|
13479
|
+
* with a present-but-unknown string `productType` — `null`, `undefined`,
|
|
13480
|
+
* primitives, or an object whose `productType` is malformed — is passed through
|
|
13481
|
+
* untouched so `z.array(earnOpportunitySchema)` reports it as a normal
|
|
13482
|
+
* validation failure. It is deliberately not silently dropped (which would hide
|
|
13483
|
+
* malformed backend data) and never throws here (an unguarded property read on
|
|
13484
|
+
* a non-object would escape `safeParse` as a raw `TypeError` instead of a
|
|
13485
|
+
* `ZodError`).
|
|
13486
|
+
*
|
|
13487
|
+
* @internal
|
|
13488
|
+
*/ const earnOpportunityListSchema = zod.z.preprocess((raw)=>{
|
|
13489
|
+
if (!Array.isArray(raw)) {
|
|
13490
|
+
return raw;
|
|
13491
|
+
}
|
|
13492
|
+
// Array.isArray narrows `raw` to `any[]`; view it as `unknown[]` so the
|
|
13493
|
+
// map/filter chain stays type-safe and no `any` leaks into the return.
|
|
13494
|
+
const entries = raw;
|
|
13495
|
+
return entries.map((entry)=>{
|
|
13496
|
+
// Only touch plain objects; non-objects fall through to fail validation.
|
|
13497
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
13498
|
+
return entry;
|
|
13499
|
+
}
|
|
13500
|
+
const record = entry;
|
|
13501
|
+
// Older backend predating productType: default to the only type then.
|
|
13502
|
+
return record.productType === undefined ? {
|
|
13503
|
+
...record,
|
|
13504
|
+
productType: 'vault'
|
|
13505
|
+
} : record;
|
|
13506
|
+
}).filter((entry)=>{
|
|
13507
|
+
// Drop ONLY a present-but-unknown string discriminant (a future
|
|
13508
|
+
// productType this SDK version doesn't know). Everything else —
|
|
13509
|
+
// non-objects, a non-string productType — flows through to
|
|
13510
|
+
// z.array(earnOpportunitySchema) and fails/passes validation normally.
|
|
13511
|
+
if (typeof entry !== 'object' || entry === null) {
|
|
13512
|
+
return true;
|
|
13513
|
+
}
|
|
13514
|
+
const productType = entry.productType;
|
|
13515
|
+
if (typeof productType !== 'string') {
|
|
13516
|
+
return true;
|
|
13517
|
+
}
|
|
13518
|
+
return knownProductTypes.has(productType);
|
|
13519
|
+
});
|
|
13520
|
+
}, zod.z.array(earnOpportunitySchema));
|
|
13408
13521
|
// ---------------------------------------------------------------------------
|
|
13409
13522
|
// Position response schema
|
|
13410
13523
|
// ---------------------------------------------------------------------------
|
|
@@ -13534,6 +13647,7 @@ const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
|
13534
13647
|
*
|
|
13535
13648
|
* @internal
|
|
13536
13649
|
*/ const depositPayloadSchema = zod.z.object({
|
|
13650
|
+
execId: bridgeDepositExecIdSchema,
|
|
13537
13651
|
executionParams: depositExecutionParamsSchema,
|
|
13538
13652
|
signature: hexSignatureSchema
|
|
13539
13653
|
});
|
|
@@ -13625,6 +13739,21 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13625
13739
|
amount: amountJsonSchema,
|
|
13626
13740
|
vaultAddress: hexAddressSchema
|
|
13627
13741
|
}).passthrough();
|
|
13742
|
+
/** @internal */ const bridgeQuoteExpirySchema = zod.z.discriminatedUnion('mode', [
|
|
13743
|
+
zod.z.object({
|
|
13744
|
+
mode: zod.z.literal('TIMESTAMP'),
|
|
13745
|
+
expiresAt: zod.z.string().datetime({
|
|
13746
|
+
offset: true
|
|
13747
|
+
})
|
|
13748
|
+
}),
|
|
13749
|
+
zod.z.object({
|
|
13750
|
+
mode: zod.z.literal('BLOCK_NUMBER'),
|
|
13751
|
+
expiresAtBlock: zod.z.number().int(),
|
|
13752
|
+
blockEstimatedAt: zod.z.string().datetime({
|
|
13753
|
+
offset: true
|
|
13754
|
+
}).optional()
|
|
13755
|
+
})
|
|
13756
|
+
]).optional().catch(undefined);
|
|
13628
13757
|
/**
|
|
13629
13758
|
* Zod schema for the bridge deposit prepare payload.
|
|
13630
13759
|
*
|
|
@@ -13636,6 +13765,10 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13636
13765
|
execId: bridgeDepositExecIdSchema,
|
|
13637
13766
|
erc3009TypedData: bridgeDepositPreparedBundleSchema,
|
|
13638
13767
|
expiresAt: zod.z.string().datetime(),
|
|
13768
|
+
quoteIssuedAt: zod.z.string().datetime({
|
|
13769
|
+
offset: true
|
|
13770
|
+
}).optional().catch(undefined),
|
|
13771
|
+
quoteExpiry: bridgeQuoteExpirySchema,
|
|
13639
13772
|
review: bridgeDepositPrepareReviewSchema
|
|
13640
13773
|
});
|
|
13641
13774
|
/**
|
|
@@ -13701,6 +13834,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13701
13834
|
*
|
|
13702
13835
|
* @internal
|
|
13703
13836
|
*/ const withdrawPayloadSchema = zod.z.object({
|
|
13837
|
+
execId: bridgeDepositExecIdSchema,
|
|
13704
13838
|
executionParams: withdrawExecutionParamsSchema,
|
|
13705
13839
|
signature: hexSignatureSchema
|
|
13706
13840
|
});
|
|
@@ -13714,6 +13848,27 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13714
13848
|
data: withdrawPayloadSchema
|
|
13715
13849
|
});
|
|
13716
13850
|
// ---------------------------------------------------------------------------
|
|
13851
|
+
// Transaction report response schema
|
|
13852
|
+
// ---------------------------------------------------------------------------
|
|
13853
|
+
/**
|
|
13854
|
+
* Zod schema for the transaction report payload inside the API `data` envelope.
|
|
13855
|
+
*
|
|
13856
|
+
* The Earn Service returns an empty payload (`{"data":{}}`) on success, so the
|
|
13857
|
+
* schema accepts any object shape and does not require specific fields.
|
|
13858
|
+
*
|
|
13859
|
+
* @internal
|
|
13860
|
+
*/ const transactionReportPayloadSchema = zod.z.object({}).passthrough();
|
|
13861
|
+
/**
|
|
13862
|
+
* Zod schema for the `POST /v1/earnKit/transactions/report` API response.
|
|
13863
|
+
*
|
|
13864
|
+
* The Earn Service API wraps the transaction report payload in a `data`
|
|
13865
|
+
* envelope.
|
|
13866
|
+
*
|
|
13867
|
+
* @internal
|
|
13868
|
+
*/ const transactionReportResponseSchema = zod.z.object({
|
|
13869
|
+
data: transactionReportPayloadSchema
|
|
13870
|
+
});
|
|
13871
|
+
// ---------------------------------------------------------------------------
|
|
13717
13872
|
// Claim rewards response schema
|
|
13718
13873
|
// ---------------------------------------------------------------------------
|
|
13719
13874
|
/**
|
|
@@ -13774,6 +13929,30 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13774
13929
|
token: zod.z.string(),
|
|
13775
13930
|
amount: amountJsonSchema
|
|
13776
13931
|
});
|
|
13932
|
+
/**
|
|
13933
|
+
* Zod schema for a native gas-fee entry in an EarnKit quote response.
|
|
13934
|
+
*
|
|
13935
|
+
* The Earn Service backend estimates gas server-side and returns one entry per
|
|
13936
|
+
* action (`Approve`, `Deposit`, `Withdraw`). A successful estimate carries
|
|
13937
|
+
* `fees` in the SDK `EstimatedGas` shape (`{ gas, gasPrice, fee }`), each a raw
|
|
13938
|
+
* integer string in the chain's native base units. When the backend cannot
|
|
13939
|
+
* estimate an action it returns `fees: null` with an `error` message instead.
|
|
13940
|
+
*
|
|
13941
|
+
* The schema deliberately validates almost nothing beyond the envelope: `name`
|
|
13942
|
+
* is optional and `fees` is entirely unvalidated (`unknown`). ALL validation
|
|
13943
|
+
* of `fees` — that it is an object at all, and that `gas`, `gasPrice`, and
|
|
13944
|
+
* `fee` are parseable integer strings — is deferred to {@link toQuoteGasFees},
|
|
13945
|
+
* which degrades a malformed entry to a `fees: null` soft failure. This is
|
|
13946
|
+
* intentional: gas is best-effort, so a single unparseable gas entry (a wrong
|
|
13947
|
+
* type such as `fees: 123` or `fees: 'bad'`, a missing field, or a non-numeric
|
|
13948
|
+
* `fee`) must never fail Zod validation and reject the entire quote.
|
|
13949
|
+
*
|
|
13950
|
+
* @internal
|
|
13951
|
+
*/ const quoteGasFeeSchema = zod.z.object({
|
|
13952
|
+
name: zod.z.string().optional(),
|
|
13953
|
+
fees: zod.z.unknown(),
|
|
13954
|
+
error: zod.z.string().optional()
|
|
13955
|
+
}).passthrough();
|
|
13777
13956
|
/**
|
|
13778
13957
|
* Zod schema for the inner deposit quote payload.
|
|
13779
13958
|
*
|
|
@@ -13789,7 +13968,8 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13789
13968
|
expectedShares: amountJsonSchema,
|
|
13790
13969
|
sharePrice: zod.z.string(),
|
|
13791
13970
|
currentApy: zod.z.number(),
|
|
13792
|
-
fees: zod.z.array(feeSchema).optional()
|
|
13971
|
+
fees: zod.z.array(feeSchema).optional(),
|
|
13972
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional()
|
|
13793
13973
|
});
|
|
13794
13974
|
/**
|
|
13795
13975
|
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
@@ -13816,6 +13996,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13816
13996
|
sharePrice: zod.z.string(),
|
|
13817
13997
|
maxWithdrawable: amountJsonSchema,
|
|
13818
13998
|
fees: zod.z.array(feeSchema),
|
|
13999
|
+
gasFees: zod.z.array(quoteGasFeeSchema).optional(),
|
|
13819
14000
|
warnings: zod.z.array(zod.z.string()).optional()
|
|
13820
14001
|
});
|
|
13821
14002
|
/**
|
|
@@ -13873,7 +14054,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13873
14054
|
*
|
|
13874
14055
|
* @internal
|
|
13875
14056
|
*/ const getVaultsPayloadSchema = zod.z.object({
|
|
13876
|
-
vaults:
|
|
14057
|
+
vaults: earnOpportunityListSchema,
|
|
13877
14058
|
errors: zod.z.array(vaultErrorSchema)
|
|
13878
14059
|
});
|
|
13879
14060
|
/**
|
|
@@ -13903,7 +14084,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13903
14084
|
*
|
|
13904
14085
|
* @internal
|
|
13905
14086
|
*/ const exploreVaultsPayloadSchema = zod.z.object({
|
|
13906
|
-
vaults:
|
|
14087
|
+
vaults: earnOpportunityListSchema,
|
|
13907
14088
|
pagination: explorePaginationSchema
|
|
13908
14089
|
});
|
|
13909
14090
|
/**
|
|
@@ -13996,6 +14177,16 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
13996
14177
|
*/ function isWithdrawResponse(value) {
|
|
13997
14178
|
return withdrawResponseSchema.safeParse(value).success;
|
|
13998
14179
|
}
|
|
14180
|
+
/**
|
|
14181
|
+
* Type guard for the transaction report API response.
|
|
14182
|
+
*
|
|
14183
|
+
* @param value - Unknown response value to validate
|
|
14184
|
+
* @returns True when the value matches the transaction report response shape
|
|
14185
|
+
*
|
|
14186
|
+
* @internal
|
|
14187
|
+
*/ function isTransactionReportResponse(value) {
|
|
14188
|
+
return transactionReportResponseSchema.safeParse(value).success;
|
|
14189
|
+
}
|
|
13999
14190
|
/**
|
|
14000
14191
|
* Type guard for the claim rewards API response.
|
|
14001
14192
|
*
|
|
@@ -14038,7 +14229,7 @@ const bridgeDepositPrepareReviewSchema = zod.z.object({
|
|
|
14038
14229
|
}
|
|
14039
14230
|
|
|
14040
14231
|
var name = "@circle-fin/provider-earn-service";
|
|
14041
|
-
var version = "1.
|
|
14232
|
+
var version = "1.3.0";
|
|
14042
14233
|
var pkg = {
|
|
14043
14234
|
name: name,
|
|
14044
14235
|
version: version};
|
|
@@ -14158,7 +14349,7 @@ var pkg = {
|
|
|
14158
14349
|
}
|
|
14159
14350
|
|
|
14160
14351
|
/**
|
|
14161
|
-
* Convert an API vault info object into the SDK {@link
|
|
14352
|
+
* Convert an API vault info object into the SDK {@link EarnOpportunity} shape.
|
|
14162
14353
|
*
|
|
14163
14354
|
* Map the API chain code back to the SDK chain identifier and hydrate the
|
|
14164
14355
|
* amount payloads into {@link Amount} instances.
|
|
@@ -14169,16 +14360,29 @@ var pkg = {
|
|
|
14169
14360
|
*
|
|
14170
14361
|
* @internal
|
|
14171
14362
|
*/ function toVaultInfo(data) {
|
|
14172
|
-
const { totalDeposits, liquidity, ...vault } = data;
|
|
14363
|
+
const { totalDeposits, liquidity, liquidityProfile, ...vault } = data;
|
|
14173
14364
|
const chain = toSdkChain(vault.chain);
|
|
14174
14365
|
if (chain === undefined) {
|
|
14175
14366
|
throw createInvalidChainError(vault.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
14176
14367
|
}
|
|
14368
|
+
// The nested facets are `.optional()` in the schema (a backend that predates
|
|
14369
|
+
// them omits them) and are typed optional on `EarnOpportunity` to match.
|
|
14370
|
+
// Convert the nested liquidity amounts when present and pass the remaining
|
|
14371
|
+
// facets straight through; each absent facet stays absent rather than being
|
|
14372
|
+
// asserted present by a cast.
|
|
14177
14373
|
return {
|
|
14178
14374
|
...vault,
|
|
14179
14375
|
chain,
|
|
14180
14376
|
totalDeposits: Amount.fromJSON(totalDeposits),
|
|
14181
|
-
liquidity: Amount.fromJSON(liquidity)
|
|
14377
|
+
liquidity: Amount.fromJSON(liquidity),
|
|
14378
|
+
...liquidityProfile !== undefined && {
|
|
14379
|
+
liquidityProfile: {
|
|
14380
|
+
...liquidityProfile,
|
|
14381
|
+
totalDeposits: Amount.fromJSON(liquidityProfile.totalDeposits),
|
|
14382
|
+
available: Amount.fromJSON(liquidityProfile.available),
|
|
14383
|
+
totalSupply: Amount.fromJSON(liquidityProfile.totalSupply)
|
|
14384
|
+
}
|
|
14385
|
+
}
|
|
14182
14386
|
};
|
|
14183
14387
|
}
|
|
14184
14388
|
|
|
@@ -14213,8 +14417,11 @@ function toVaultError(error) {
|
|
|
14213
14417
|
}
|
|
14214
14418
|
try {
|
|
14215
14419
|
const response = await pollApiGet(url.toString(), isGetVaultsResponse, pollingConfig);
|
|
14420
|
+
// `pollApiGet` validates via a boolean guard and returns the raw JSON — it
|
|
14421
|
+
// does not run the schema's preprocess. Parse explicitly so unknown
|
|
14422
|
+
// `productType` values are dropped before `toVaultInfo`.
|
|
14216
14423
|
return {
|
|
14217
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14424
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14218
14425
|
errors: response.data.errors.map(toVaultError)
|
|
14219
14426
|
};
|
|
14220
14427
|
} catch (error) {
|
|
@@ -14263,8 +14470,11 @@ function toVaultError(error) {
|
|
|
14263
14470
|
}
|
|
14264
14471
|
try {
|
|
14265
14472
|
const response = await pollApiGet(url.toString(), isExploreVaultsResponse, pollingConfig);
|
|
14473
|
+
// `pollApiGet` validates via a boolean guard and returns the raw JSON — it
|
|
14474
|
+
// does not run the schema's preprocess. Parse explicitly so unknown
|
|
14475
|
+
// `productType` values are dropped before `toVaultInfo`.
|
|
14266
14476
|
return {
|
|
14267
|
-
vaults: response.data.vaults.map(toVaultInfo),
|
|
14477
|
+
vaults: earnOpportunityListSchema.parse(response.data.vaults).map(toVaultInfo),
|
|
14268
14478
|
pagination: response.data.pagination
|
|
14269
14479
|
};
|
|
14270
14480
|
} catch (error) {
|
|
@@ -14428,6 +14638,12 @@ function toPositionInfo(data) {
|
|
|
14428
14638
|
execId: response.data.execId,
|
|
14429
14639
|
preparedBundle,
|
|
14430
14640
|
expiresAt: response.data.expiresAt,
|
|
14641
|
+
...response.data.quoteIssuedAt !== undefined && {
|
|
14642
|
+
quoteIssuedAt: response.data.quoteIssuedAt
|
|
14643
|
+
},
|
|
14644
|
+
...response.data.quoteExpiry !== undefined && {
|
|
14645
|
+
quoteExpiry: response.data.quoteExpiry
|
|
14646
|
+
},
|
|
14431
14647
|
review: response.data.review
|
|
14432
14648
|
};
|
|
14433
14649
|
} catch (error) {
|
|
@@ -14769,7 +14985,110 @@ function toClaimedAmount(reward) {
|
|
|
14769
14985
|
}
|
|
14770
14986
|
}
|
|
14771
14987
|
|
|
14772
|
-
|
|
14988
|
+
/**
|
|
14989
|
+
* Map the Earn Service's server-side quote gas estimates into the SDK
|
|
14990
|
+
* {@link EarnGasFeeEstimate} shape.
|
|
14991
|
+
*
|
|
14992
|
+
* The Earn Service estimates gas for each action (`Approve`, `Deposit`,
|
|
14993
|
+
* `Withdraw`) and returns `{ name, fees: { gas, gasPrice, fee } }` with raw
|
|
14994
|
+
* integer strings.
|
|
14995
|
+
* The SDK type additionally carries `token` (the chain's native currency
|
|
14996
|
+
* symbol) and `blockchain`, which are filled in here from the chain
|
|
14997
|
+
* definition.
|
|
14998
|
+
*
|
|
14999
|
+
* Gas reporting is best-effort: a malformed entry (e.g. a non-integer string
|
|
15000
|
+
* that fails `BigInt` parsing) degrades to a `{ fees: null, error }` estimate
|
|
15001
|
+
* rather than throwing, so one bad entry never fails the whole quote.
|
|
15002
|
+
*
|
|
15003
|
+
* @param gasFees - Backend gas-fee entries from the quote response, if any.
|
|
15004
|
+
* @param chain - Chain definition, used for the native token symbol and
|
|
15005
|
+
* blockchain identifier.
|
|
15006
|
+
* @returns One {@link EarnGasFeeEstimate} per backend entry (empty when the
|
|
15007
|
+
* backend returned none).
|
|
15008
|
+
*
|
|
15009
|
+
* @example
|
|
15010
|
+
* ```typescript
|
|
15011
|
+
* toQuoteGasFees(
|
|
15012
|
+
* [{ name: 'Deposit', fees: { gas: '364142', gasPrice: '21000000000', fee: '7646982000000000' } }],
|
|
15013
|
+
* arcTestnet,
|
|
15014
|
+
* )
|
|
15015
|
+
* // [{ name: 'Deposit', token: 'USDC', blockchain: 'Arc_Testnet',
|
|
15016
|
+
* // fees: { gas: 364142n, gasPrice: 21000000000n, fee: '7646982000000000' } }]
|
|
15017
|
+
* ```
|
|
15018
|
+
*
|
|
15019
|
+
* @internal
|
|
15020
|
+
*/ function toQuoteGasFees(gasFees, chain) {
|
|
15021
|
+
if (gasFees === undefined) {
|
|
15022
|
+
return [];
|
|
15023
|
+
}
|
|
15024
|
+
return gasFees.map((entry)=>{
|
|
15025
|
+
const base = {
|
|
15026
|
+
// `name` is optional on the wire; label an unnamed entry rather than
|
|
15027
|
+
// emitting `name: undefined`.
|
|
15028
|
+
name: entry.name ?? 'Unknown',
|
|
15029
|
+
token: chain.nativeCurrency.symbol,
|
|
15030
|
+
blockchain: chain.chain
|
|
15031
|
+
};
|
|
15032
|
+
// The Earn Service itself reports a failed estimate as `fees: null` with
|
|
15033
|
+
// an error; propagate that soft failure verbatim.
|
|
15034
|
+
if (entry.fees === null || entry.fees === undefined) {
|
|
15035
|
+
return {
|
|
15036
|
+
...base,
|
|
15037
|
+
fees: null,
|
|
15038
|
+
error: entry.error ?? 'gas estimate unavailable'
|
|
15039
|
+
};
|
|
15040
|
+
}
|
|
15041
|
+
// `fees` is `unknown` at the schema layer, so ALL validation happens here:
|
|
15042
|
+
// that it is an object at all, and that `gas`, `gasPrice`, and `fee` are
|
|
15043
|
+
// each parseable integer strings (including `fee`, which the SDK contract
|
|
15044
|
+
// requires be a numeric base-unit string). Any failure — a wrong type
|
|
15045
|
+
// (`fees: 123`), a missing field, or a non-numeric value — degrades the
|
|
15046
|
+
// whole entry to a `fees: null` soft failure rather than surfacing a
|
|
15047
|
+
// malformed "successful" estimate or rejecting the quote.
|
|
15048
|
+
try {
|
|
15049
|
+
if (typeof entry.fees !== 'object') {
|
|
15050
|
+
throw new TypeError(`gas fees must be an object (got ${typeof entry.fees})`);
|
|
15051
|
+
}
|
|
15052
|
+
const { gas, gasPrice, fee } = entry.fees;
|
|
15053
|
+
return {
|
|
15054
|
+
...base,
|
|
15055
|
+
fees: {
|
|
15056
|
+
gas: toBigInt('gas', gas),
|
|
15057
|
+
gasPrice: toBigInt('gasPrice', gasPrice),
|
|
15058
|
+
fee: toBigInt('fee', fee).toString()
|
|
15059
|
+
}
|
|
15060
|
+
};
|
|
15061
|
+
} catch (error) {
|
|
15062
|
+
return {
|
|
15063
|
+
...base,
|
|
15064
|
+
fees: null,
|
|
15065
|
+
error: getErrorMessage(error)
|
|
15066
|
+
};
|
|
15067
|
+
}
|
|
15068
|
+
});
|
|
15069
|
+
}
|
|
15070
|
+
/**
|
|
15071
|
+
* Parse an unknown value into a `bigint`, rejecting anything that is not a
|
|
15072
|
+
* non-empty integer string. `BigInt` alone is too permissive for this path —
|
|
15073
|
+
* it accepts numbers, booleans, and empty strings — so guard the type first.
|
|
15074
|
+
*
|
|
15075
|
+
* @param field - Field name, used in the thrown error message.
|
|
15076
|
+
* @param value - Raw value from the backend gas entry.
|
|
15077
|
+
* @returns The parsed `bigint`.
|
|
15078
|
+
* @throws {TypeError} When `value` is not a non-empty integer string.
|
|
15079
|
+
*/ function toBigInt(field, value) {
|
|
15080
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
15081
|
+
throw new TypeError(`gas fee field "${field}" must be an integer string`);
|
|
15082
|
+
}
|
|
15083
|
+
try {
|
|
15084
|
+
// BigInt throws on non-integer strings (e.g. "1.5", "not-a-number").
|
|
15085
|
+
return BigInt(value);
|
|
15086
|
+
} catch {
|
|
15087
|
+
throw new Error(`gas fee field "${field}" is not a valid integer string: ${value}`);
|
|
15088
|
+
}
|
|
15089
|
+
}
|
|
15090
|
+
|
|
15091
|
+
function toDepositQuoteInfo(data, chain) {
|
|
14773
15092
|
const fees = (data.fees ?? []).map(({ token: feeTokenSymbol, ...fee })=>{
|
|
14774
15093
|
// Earn Service returns fee.token as a display symbol, for example "USDC".
|
|
14775
15094
|
return {
|
|
@@ -14798,7 +15117,10 @@ function toDepositQuoteInfo(data) {
|
|
|
14798
15117
|
sharePrice: data.sharePrice,
|
|
14799
15118
|
currentApy: data.currentApy,
|
|
14800
15119
|
fees,
|
|
14801
|
-
|
|
15120
|
+
// The Earn Service estimates gas server-side; the chain fills token/blockchain.
|
|
15121
|
+
// Cross-chain quotes resolve no local chain definition, so gasFees stays
|
|
15122
|
+
// empty there (unchanged behavior).
|
|
15123
|
+
gasFees: chain === undefined ? [] : toQuoteGasFees(data.gasFees, chain)
|
|
14802
15124
|
};
|
|
14803
15125
|
}
|
|
14804
15126
|
/**
|
|
@@ -14833,7 +15155,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14833
15155
|
};
|
|
14834
15156
|
try {
|
|
14835
15157
|
const response = await pollApiPost(url.toString(), requestBody, isDepositQuoteResponse, pollingConfig);
|
|
14836
|
-
return toDepositQuoteInfo(response.data);
|
|
15158
|
+
return toDepositQuoteInfo(response.data, params.chainDefinition);
|
|
14837
15159
|
} catch (error) {
|
|
14838
15160
|
throw parseEarnApiError(error, {
|
|
14839
15161
|
operation: 'getDepositQuote'
|
|
@@ -14841,7 +15163,7 @@ function toDepositQuoteInfo(data) {
|
|
|
14841
15163
|
}
|
|
14842
15164
|
}
|
|
14843
15165
|
|
|
14844
|
-
function toWithdrawalQuoteInfo(data) {
|
|
15166
|
+
function toWithdrawalQuoteInfo(data, chain) {
|
|
14845
15167
|
return {
|
|
14846
15168
|
vaultAddress: data.vaultAddress,
|
|
14847
15169
|
vaultName: data.vaultName,
|
|
@@ -14869,7 +15191,7 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14869
15191
|
status
|
|
14870
15192
|
}
|
|
14871
15193
|
})),
|
|
14872
|
-
gasFees: [],
|
|
15194
|
+
gasFees: chain === undefined ? [] : toQuoteGasFees(data.gasFees, chain),
|
|
14873
15195
|
// Wire format uses `warnings`, but the SDK surface uses
|
|
14874
15196
|
// `earnKitWarnings` to match the precedent set by `VaultInfo` —
|
|
14875
15197
|
// `warnings` is reserved for the structured `VaultWarning` shape.
|
|
@@ -14901,7 +15223,7 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14901
15223
|
};
|
|
14902
15224
|
try {
|
|
14903
15225
|
const response = await pollApiPost(url.toString(), requestBody, isWithdrawalQuoteResponse, pollingConfig);
|
|
14904
|
-
return toWithdrawalQuoteInfo(response.data);
|
|
15226
|
+
return toWithdrawalQuoteInfo(response.data, params.chainDefinition);
|
|
14905
15227
|
} catch (error) {
|
|
14906
15228
|
throw parseEarnApiError(error, {
|
|
14907
15229
|
operation: 'getWithdrawalQuote'
|
|
@@ -14937,6 +15259,8 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14937
15259
|
amount: Amount.fromJSON(r.amount),
|
|
14938
15260
|
address: r.token
|
|
14939
15261
|
})),
|
|
15262
|
+
// The claimRewards/quote response does not carry a gas estimate (unlike
|
|
15263
|
+
// deposit/withdrawal quotes), so there is nothing to surface here.
|
|
14940
15264
|
gasFees: []
|
|
14941
15265
|
};
|
|
14942
15266
|
} catch (error) {
|
|
@@ -14946,6 +15270,83 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
14946
15270
|
}
|
|
14947
15271
|
}
|
|
14948
15272
|
|
|
15273
|
+
/**
|
|
15274
|
+
* Build the native gas triple the backend expects for `gasUsed`.
|
|
15275
|
+
*
|
|
15276
|
+
* Returns `undefined` unless both receipt components are present, so the
|
|
15277
|
+
* caller can omit the field entirely — the Earn Service treats a missing
|
|
15278
|
+
* triple as "skip the gas cache write, still return 200".
|
|
15279
|
+
*
|
|
15280
|
+
* @param gasUsed - Receipt gas units used.
|
|
15281
|
+
* @param effectiveGasPrice - Receipt effective gas price.
|
|
15282
|
+
* @returns The `{ gas, gasPrice, fee }` triple, or `undefined` when either
|
|
15283
|
+
* component is missing.
|
|
15284
|
+
*
|
|
15285
|
+
* @example
|
|
15286
|
+
* ```typescript
|
|
15287
|
+
* buildReportedGasUsed(362454n, 29466364605n)
|
|
15288
|
+
* // { gas: '362454', gasPrice: '29466364605', fee: '10680201716540670' }
|
|
15289
|
+
* ```
|
|
15290
|
+
*
|
|
15291
|
+
* @internal
|
|
15292
|
+
*/ function buildReportedGasUsed(gasUsed, effectiveGasPrice) {
|
|
15293
|
+
if (gasUsed === undefined || effectiveGasPrice === undefined) {
|
|
15294
|
+
return undefined;
|
|
15295
|
+
}
|
|
15296
|
+
return {
|
|
15297
|
+
gas: gasUsed.toString(),
|
|
15298
|
+
gasPrice: effectiveGasPrice.toString(),
|
|
15299
|
+
fee: (gasUsed * effectiveGasPrice).toString()
|
|
15300
|
+
};
|
|
15301
|
+
}
|
|
15302
|
+
/**
|
|
15303
|
+
* Report the outcome of an SDK-submitted same-chain Earn transaction.
|
|
15304
|
+
*
|
|
15305
|
+
* @param params - Transaction report parameters.
|
|
15306
|
+
* @throws {@link KitError} When the API call fails.
|
|
15307
|
+
*
|
|
15308
|
+
* @internal
|
|
15309
|
+
*/ async function reportEarnTransaction(params) {
|
|
15310
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
15311
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/transactions/report`, baseUrl);
|
|
15312
|
+
// The report endpoint is not idempotent: success reports refresh the gas
|
|
15313
|
+
// cache and failure reports increment counts. If the first request succeeds
|
|
15314
|
+
// server-side but the client times out or sees a transient 5xx, retrying
|
|
15315
|
+
// would duplicate the report (double-writing an outcome or inflating failure
|
|
15316
|
+
// counts). Reporting is best-effort (see the fire-and-forget caller), so
|
|
15317
|
+
// make exactly one attempt and never retry — a single dropped report is
|
|
15318
|
+
// preferable to a duplicated one. `maxRetries` here is the total attempt
|
|
15319
|
+
// count in pollApiWithValidation (loop runs `attempt <= maxRetries`), so 1
|
|
15320
|
+
// means one request with no retry; 0 would skip the request entirely.
|
|
15321
|
+
const reportConfig = {
|
|
15322
|
+
...pollingConfig,
|
|
15323
|
+
maxRetries: 1
|
|
15324
|
+
};
|
|
15325
|
+
const gasUsed = buildReportedGasUsed(params.gasUsed, params.effectiveGasPrice);
|
|
15326
|
+
const requestBody = {
|
|
15327
|
+
execId: params.execId,
|
|
15328
|
+
chain: params.chain,
|
|
15329
|
+
status: params.status,
|
|
15330
|
+
action: params.action,
|
|
15331
|
+
...params.txHash !== undefined && {
|
|
15332
|
+
txHash: params.txHash
|
|
15333
|
+
},
|
|
15334
|
+
...gasUsed !== undefined && {
|
|
15335
|
+
gasUsed
|
|
15336
|
+
},
|
|
15337
|
+
...params.errorCode !== undefined && {
|
|
15338
|
+
errorCode: params.errorCode
|
|
15339
|
+
}
|
|
15340
|
+
};
|
|
15341
|
+
try {
|
|
15342
|
+
await pollApiPost(url.toString(), requestBody, isTransactionReportResponse, reportConfig);
|
|
15343
|
+
} catch (error) {
|
|
15344
|
+
throw parseEarnApiError(error, {
|
|
15345
|
+
operation: 'transactionReport'
|
|
15346
|
+
});
|
|
15347
|
+
}
|
|
15348
|
+
}
|
|
15349
|
+
|
|
14949
15350
|
/**
|
|
14950
15351
|
* Sum the amounts across every token input to size the allowance approval.
|
|
14951
15352
|
*
|
|
@@ -15056,6 +15457,59 @@ function toWithdrawalQuoteInfo(data) {
|
|
|
15056
15457
|
// Intentionally built-ins-only: Earn bridge support is limited to SDK-known
|
|
15057
15458
|
// token contracts plus the explicit ERC-3009 domain allowlist below.
|
|
15058
15459
|
const TOKEN_REGISTRY = createTokenRegistry();
|
|
15460
|
+
function submitTransactionReport(reportContext, action, status, details) {
|
|
15461
|
+
void reportEarnTransaction({
|
|
15462
|
+
execId: reportContext.execId,
|
|
15463
|
+
chain: reportContext.chain,
|
|
15464
|
+
config: reportContext.config,
|
|
15465
|
+
action,
|
|
15466
|
+
status,
|
|
15467
|
+
...details
|
|
15468
|
+
}).catch(()=>undefined);
|
|
15469
|
+
}
|
|
15470
|
+
function reportTransactionSuccess(reportContext, action, result) {
|
|
15471
|
+
if (result === undefined) {
|
|
15472
|
+
return;
|
|
15473
|
+
}
|
|
15474
|
+
submitTransactionReport(reportContext, action, 'success', {
|
|
15475
|
+
txHash: result.txHash,
|
|
15476
|
+
gasUsed: result.gasUsed,
|
|
15477
|
+
effectiveGasPrice: result.effectiveGasPrice
|
|
15478
|
+
});
|
|
15479
|
+
}
|
|
15480
|
+
function reportTransactionFailure(reportContext, action, error) {
|
|
15481
|
+
submitTransactionReport(reportContext, action, 'failure', {
|
|
15482
|
+
txHash: transactionReportTxHash(error),
|
|
15483
|
+
errorCode: transactionReportErrorCode(error)
|
|
15484
|
+
});
|
|
15485
|
+
}
|
|
15486
|
+
function transactionReportErrorCode(error) {
|
|
15487
|
+
if (isKitError(error)) {
|
|
15488
|
+
return error.name;
|
|
15489
|
+
}
|
|
15490
|
+
const message = getErrorMessage(error);
|
|
15491
|
+
if (/user (rejected|denied)|rejected by user/i.test(message)) {
|
|
15492
|
+
return 'USER_REJECTED';
|
|
15493
|
+
}
|
|
15494
|
+
if (/insufficient funds/i.test(message)) {
|
|
15495
|
+
return 'INSUFFICIENT_FUNDS';
|
|
15496
|
+
}
|
|
15497
|
+
if (/timeout|timed out/i.test(message)) {
|
|
15498
|
+
return 'TIMEOUT';
|
|
15499
|
+
}
|
|
15500
|
+
return 'UNKNOWN_ERROR';
|
|
15501
|
+
}
|
|
15502
|
+
function transactionReportTxHash(error) {
|
|
15503
|
+
if (!isKitError(error)) {
|
|
15504
|
+
return undefined;
|
|
15505
|
+
}
|
|
15506
|
+
const trace = error.cause?.trace;
|
|
15507
|
+
if (typeof trace !== 'object' || trace === null) {
|
|
15508
|
+
return undefined;
|
|
15509
|
+
}
|
|
15510
|
+
const txHash = trace['txHash'];
|
|
15511
|
+
return typeof txHash === 'string' && txHash !== '' ? txHash : undefined;
|
|
15512
|
+
}
|
|
15059
15513
|
/**
|
|
15060
15514
|
* Build the typed error raised when a cross-chain wait is cancelled via its
|
|
15061
15515
|
* `AbortSignal`. Mirrors `@core/adapter-base`'s `createAbortError` (same
|
|
@@ -15377,7 +15831,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15377
15831
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15378
15832
|
const { adapter } = params.from;
|
|
15379
15833
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15380
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15834
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'deposit', 'fetchParams', async ()=>fetchDeposit({
|
|
15381
15835
|
vaultAddress,
|
|
15382
15836
|
amount: params.amount,
|
|
15383
15837
|
address,
|
|
@@ -15385,32 +15839,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15385
15839
|
config
|
|
15386
15840
|
}), ()=>undefined);
|
|
15387
15841
|
validateExecutionDeadline(executionParams);
|
|
15842
|
+
const transactionReportContext = {
|
|
15843
|
+
execId,
|
|
15844
|
+
chain: apiChain,
|
|
15845
|
+
config
|
|
15846
|
+
};
|
|
15388
15847
|
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15389
15848
|
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15390
15849
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15391
15850
|
if (!options.skipApprove && approvalToken !== undefined && requiredAllowance > 0n) {
|
|
15392
|
-
await this.runPhase(ctx, 'approve', 'approve', async ()=>
|
|
15851
|
+
await this.runPhase(ctx, 'approve', 'approve', async ()=>{
|
|
15852
|
+
try {
|
|
15853
|
+
const approval = await approveAllowanceIfNeeded({
|
|
15854
|
+
adapter,
|
|
15855
|
+
chain,
|
|
15856
|
+
tokenAddress: approvalToken,
|
|
15857
|
+
delegate: adapterContractAddress,
|
|
15858
|
+
address,
|
|
15859
|
+
requiredAllowance,
|
|
15860
|
+
revertMessage: 'Earn deposit token approval reverted on-chain'
|
|
15861
|
+
});
|
|
15862
|
+
reportTransactionSuccess(transactionReportContext, 'Approve', approval);
|
|
15863
|
+
return approval;
|
|
15864
|
+
} catch (error) {
|
|
15865
|
+
reportTransactionFailure(transactionReportContext, 'Approve', error);
|
|
15866
|
+
throw error;
|
|
15867
|
+
}
|
|
15868
|
+
}, (approval)=>approval?.txHash);
|
|
15869
|
+
}
|
|
15870
|
+
const { txHash, explorerUrl } = await this.runPhase(ctx, 'deposit', 'execute', async ()=>{
|
|
15871
|
+
try {
|
|
15872
|
+
const result = await executeEarnAction({
|
|
15393
15873
|
adapter,
|
|
15394
15874
|
chain,
|
|
15395
|
-
tokenAddress: approvalToken,
|
|
15396
|
-
delegate: adapterContractAddress,
|
|
15397
15875
|
address,
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15402
|
-
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
}), ({ txHash })=>txHash);
|
|
15876
|
+
actionKey: 'earn.deposit',
|
|
15877
|
+
actionParams: {
|
|
15878
|
+
executeParams: executionParams,
|
|
15879
|
+
tokenInputs,
|
|
15880
|
+
signature
|
|
15881
|
+
},
|
|
15882
|
+
revertMessage: 'Earn deposit reverted on-chain'
|
|
15883
|
+
});
|
|
15884
|
+
reportTransactionSuccess(transactionReportContext, 'Deposit', result);
|
|
15885
|
+
return result;
|
|
15886
|
+
} catch (error) {
|
|
15887
|
+
reportTransactionFailure(transactionReportContext, 'Deposit', error);
|
|
15888
|
+
throw error;
|
|
15889
|
+
}
|
|
15890
|
+
}, ({ txHash })=>txHash);
|
|
15414
15891
|
return {
|
|
15415
15892
|
kind: 'same-chain',
|
|
15416
15893
|
txHash,
|
|
@@ -15490,7 +15967,13 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15490
15967
|
amount: params.amount,
|
|
15491
15968
|
sourceChain: sourceChain.chain,
|
|
15492
15969
|
destinationChain: destinationChain.chain,
|
|
15493
|
-
expiresAt: prepared.expiresAt
|
|
15970
|
+
expiresAt: prepared.expiresAt,
|
|
15971
|
+
...prepared.quoteIssuedAt !== undefined && {
|
|
15972
|
+
quoteIssuedAt: prepared.quoteIssuedAt
|
|
15973
|
+
},
|
|
15974
|
+
...prepared.quoteExpiry !== undefined && {
|
|
15975
|
+
quoteExpiry: prepared.quoteExpiry
|
|
15976
|
+
}
|
|
15494
15977
|
};
|
|
15495
15978
|
}
|
|
15496
15979
|
/** {@inheritdoc} */ async withdraw(params) {
|
|
@@ -15511,7 +15994,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15511
15994
|
const adapterContractAddress = requireAdapterContract(chain);
|
|
15512
15995
|
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15513
15996
|
const { adapter } = params.from;
|
|
15514
|
-
const { executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15997
|
+
const { execId, executionParams, signature } = await this.runPhase(ctx, 'withdraw', 'fetchParams', async ()=>fetchWithdraw({
|
|
15515
15998
|
vaultAddress,
|
|
15516
15999
|
amount: params.amount,
|
|
15517
16000
|
address,
|
|
@@ -15519,32 +16002,55 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15519
16002
|
config
|
|
15520
16003
|
}), ()=>undefined);
|
|
15521
16004
|
validateExecutionDeadline(executionParams);
|
|
16005
|
+
const transactionReportContext = {
|
|
16006
|
+
execId,
|
|
16007
|
+
chain: apiChain,
|
|
16008
|
+
config
|
|
16009
|
+
};
|
|
15522
16010
|
const tokenInputs = buildEarnTokenInputs(executionParams, vaultAddress);
|
|
15523
16011
|
const approvalToken = tokenInputs[0]?.token;
|
|
15524
16012
|
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15525
16013
|
if (!options.skipApprove && approvalToken !== undefined) {
|
|
15526
|
-
await this.runPhase(ctx, 'approve', 'approve', async ()=>
|
|
16014
|
+
await this.runPhase(ctx, 'approve', 'approve', async ()=>{
|
|
16015
|
+
try {
|
|
16016
|
+
const approval = await approveAllowanceIfNeeded({
|
|
16017
|
+
adapter,
|
|
16018
|
+
chain,
|
|
16019
|
+
tokenAddress: approvalToken,
|
|
16020
|
+
delegate: adapterContractAddress,
|
|
16021
|
+
address,
|
|
16022
|
+
requiredAllowance,
|
|
16023
|
+
revertMessage: 'Vault share token approval reverted on-chain'
|
|
16024
|
+
});
|
|
16025
|
+
reportTransactionSuccess(transactionReportContext, 'Approve', approval);
|
|
16026
|
+
return approval;
|
|
16027
|
+
} catch (error) {
|
|
16028
|
+
reportTransactionFailure(transactionReportContext, 'Approve', error);
|
|
16029
|
+
throw error;
|
|
16030
|
+
}
|
|
16031
|
+
}, (approval)=>approval?.txHash);
|
|
16032
|
+
}
|
|
16033
|
+
const { txHash, explorerUrl } = await this.runPhase(ctx, 'withdraw', 'execute', async ()=>{
|
|
16034
|
+
try {
|
|
16035
|
+
const result = await executeEarnAction({
|
|
15527
16036
|
adapter,
|
|
15528
16037
|
chain,
|
|
15529
|
-
tokenAddress: approvalToken,
|
|
15530
|
-
delegate: adapterContractAddress,
|
|
15531
16038
|
address,
|
|
15532
|
-
|
|
15533
|
-
|
|
15534
|
-
|
|
15535
|
-
|
|
15536
|
-
|
|
15537
|
-
|
|
15538
|
-
|
|
15539
|
-
|
|
15540
|
-
|
|
15541
|
-
|
|
15542
|
-
|
|
15543
|
-
|
|
15544
|
-
|
|
15545
|
-
|
|
15546
|
-
|
|
15547
|
-
}), ({ txHash })=>txHash);
|
|
16039
|
+
actionKey: 'earn.withdraw',
|
|
16040
|
+
actionParams: {
|
|
16041
|
+
executeParams: executionParams,
|
|
16042
|
+
tokenInputs,
|
|
16043
|
+
signature
|
|
16044
|
+
},
|
|
16045
|
+
revertMessage: 'Earn withdraw reverted on-chain'
|
|
16046
|
+
});
|
|
16047
|
+
reportTransactionSuccess(transactionReportContext, 'Withdraw', result);
|
|
16048
|
+
return result;
|
|
16049
|
+
} catch (error) {
|
|
16050
|
+
reportTransactionFailure(transactionReportContext, 'Withdraw', error);
|
|
16051
|
+
throw error;
|
|
16052
|
+
}
|
|
16053
|
+
}, ({ txHash })=>txHash);
|
|
15548
16054
|
return {
|
|
15549
16055
|
txHash,
|
|
15550
16056
|
explorerUrl,
|
|
@@ -15678,141 +16184,6 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15678
16184
|
}
|
|
15679
16185
|
}
|
|
15680
16186
|
}
|
|
15681
|
-
gasEstimateFailure(name, chain, error) {
|
|
15682
|
-
return {
|
|
15683
|
-
name,
|
|
15684
|
-
token: chain.nativeCurrency.symbol,
|
|
15685
|
-
blockchain: chain.chain,
|
|
15686
|
-
fees: null,
|
|
15687
|
-
error: getErrorMessage(error)
|
|
15688
|
-
};
|
|
15689
|
-
}
|
|
15690
|
-
async estimateDepositQuoteGasFees(params) {
|
|
15691
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15692
|
-
try {
|
|
15693
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15694
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15695
|
-
const { executionParams, signature } = await fetchDeposit({
|
|
15696
|
-
vaultAddress: normalizedVaultAddress,
|
|
15697
|
-
amount,
|
|
15698
|
-
address,
|
|
15699
|
-
chain: apiChain,
|
|
15700
|
-
config
|
|
15701
|
-
});
|
|
15702
|
-
validateExecutionDeadline(executionParams);
|
|
15703
|
-
const approvalToken = resolveEarnApprovalToken(executionParams);
|
|
15704
|
-
const tokenInputs = approvalToken === undefined ? [] : buildEarnTokenInputs(executionParams, approvalToken);
|
|
15705
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15706
|
-
return await estimateEarnQuoteGasFees({
|
|
15707
|
-
adapter,
|
|
15708
|
-
chain,
|
|
15709
|
-
address,
|
|
15710
|
-
actionName: 'Deposit',
|
|
15711
|
-
actionKey: 'earn.deposit',
|
|
15712
|
-
actionParams: {
|
|
15713
|
-
executeParams: executionParams,
|
|
15714
|
-
tokenInputs,
|
|
15715
|
-
signature
|
|
15716
|
-
},
|
|
15717
|
-
approval: approvalToken !== undefined && requiredAllowance > 0n ? {
|
|
15718
|
-
token: approvalToken,
|
|
15719
|
-
delegate: adapterContractAddress,
|
|
15720
|
-
requiredAllowance
|
|
15721
|
-
} : undefined
|
|
15722
|
-
});
|
|
15723
|
-
} catch (error) {
|
|
15724
|
-
return [
|
|
15725
|
-
this.gasEstimateFailure('Deposit', chain, error)
|
|
15726
|
-
];
|
|
15727
|
-
}
|
|
15728
|
-
}
|
|
15729
|
-
async estimateWithdrawalQuoteGasFees(params) {
|
|
15730
|
-
const { adapter, chain, apiChain, address, vaultAddress, amount, config } = params;
|
|
15731
|
-
try {
|
|
15732
|
-
const adapterContractAddress = requireAdapterContract(chain);
|
|
15733
|
-
const normalizedVaultAddress = assertHexAddress('vaultAddress', vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
15734
|
-
const { executionParams, signature } = await fetchWithdraw({
|
|
15735
|
-
vaultAddress: normalizedVaultAddress,
|
|
15736
|
-
amount,
|
|
15737
|
-
address,
|
|
15738
|
-
chain: apiChain,
|
|
15739
|
-
config
|
|
15740
|
-
});
|
|
15741
|
-
validateExecutionDeadline(executionParams);
|
|
15742
|
-
const tokenInputs = buildEarnTokenInputs(executionParams, normalizedVaultAddress);
|
|
15743
|
-
const approvalToken = tokenInputs[0]?.token;
|
|
15744
|
-
const requiredAllowance = sumTokenInputAmounts(tokenInputs);
|
|
15745
|
-
return await estimateEarnQuoteGasFees({
|
|
15746
|
-
adapter,
|
|
15747
|
-
chain,
|
|
15748
|
-
address,
|
|
15749
|
-
actionName: 'Withdraw',
|
|
15750
|
-
actionKey: 'earn.withdraw',
|
|
15751
|
-
actionParams: {
|
|
15752
|
-
executeParams: executionParams,
|
|
15753
|
-
tokenInputs,
|
|
15754
|
-
signature
|
|
15755
|
-
},
|
|
15756
|
-
approval: approvalToken !== undefined ? {
|
|
15757
|
-
token: approvalToken,
|
|
15758
|
-
delegate: adapterContractAddress,
|
|
15759
|
-
requiredAllowance
|
|
15760
|
-
} : undefined
|
|
15761
|
-
});
|
|
15762
|
-
} catch (error) {
|
|
15763
|
-
return [
|
|
15764
|
-
this.gasEstimateFailure('Withdraw', chain, error)
|
|
15765
|
-
];
|
|
15766
|
-
}
|
|
15767
|
-
}
|
|
15768
|
-
async estimateClaimRewardsQuoteGasFees(params) {
|
|
15769
|
-
const { adapter, chain, apiChain, address, vaultAddress, config } = params;
|
|
15770
|
-
try {
|
|
15771
|
-
requireAdapterContract(chain);
|
|
15772
|
-
const { rewards, executionParams, signature } = await fetchClaimRewards({
|
|
15773
|
-
address,
|
|
15774
|
-
chain: apiChain,
|
|
15775
|
-
vaultAddress,
|
|
15776
|
-
config
|
|
15777
|
-
});
|
|
15778
|
-
if (rewards.length === 0) {
|
|
15779
|
-
return [];
|
|
15780
|
-
}
|
|
15781
|
-
const missingExecutionParams = executionParams === undefined;
|
|
15782
|
-
const missingSignature = signature === undefined;
|
|
15783
|
-
if (missingExecutionParams || missingSignature) {
|
|
15784
|
-
throw new KitError({
|
|
15785
|
-
...EarnError.INTERNAL_ERROR,
|
|
15786
|
-
recoverability: 'RETRYABLE',
|
|
15787
|
-
message: 'Claim rewards response must include executionParams and signature when rewards are claimable',
|
|
15788
|
-
cause: {
|
|
15789
|
-
trace: {
|
|
15790
|
-
rewardsCount: rewards.length,
|
|
15791
|
-
missingExecutionParams,
|
|
15792
|
-
missingSignature
|
|
15793
|
-
}
|
|
15794
|
-
}
|
|
15795
|
-
});
|
|
15796
|
-
}
|
|
15797
|
-
validateExecutionDeadline(executionParams);
|
|
15798
|
-
return await estimateEarnQuoteGasFees({
|
|
15799
|
-
adapter,
|
|
15800
|
-
chain,
|
|
15801
|
-
address,
|
|
15802
|
-
actionName: 'Claim Rewards',
|
|
15803
|
-
actionKey: 'earn.claimRewards',
|
|
15804
|
-
actionParams: {
|
|
15805
|
-
executeParams: executionParams,
|
|
15806
|
-
tokenInputs: [],
|
|
15807
|
-
signature
|
|
15808
|
-
}
|
|
15809
|
-
});
|
|
15810
|
-
} catch (error) {
|
|
15811
|
-
return [
|
|
15812
|
-
this.gasEstimateFailure('Claim Rewards', chain, error)
|
|
15813
|
-
];
|
|
15814
|
-
}
|
|
15815
|
-
}
|
|
15816
16187
|
/** {@inheritdoc} */ async getDepositQuote(params) {
|
|
15817
16188
|
const config = this.resolveConfig(params.config);
|
|
15818
16189
|
if (hasQuoteDestinationChain(params)) {
|
|
@@ -15835,96 +16206,43 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
15835
16206
|
throw createValidationFailedError('chain', destinationChain.chain, 'chain is only supported for cross-chain Earn deposit quotes; omit chain/address when quoting on the source chain');
|
|
15836
16207
|
}
|
|
15837
16208
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15838
|
-
//
|
|
15839
|
-
//
|
|
15840
|
-
//
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
this.estimateDepositQuoteGasFees({
|
|
15850
|
-
adapter: params.from.adapter,
|
|
15851
|
-
chain: chainDefinition,
|
|
15852
|
-
apiChain: chain,
|
|
15853
|
-
address,
|
|
15854
|
-
vaultAddress: params.vaultAddress,
|
|
15855
|
-
amount: params.amount,
|
|
15856
|
-
config
|
|
15857
|
-
})
|
|
15858
|
-
]);
|
|
15859
|
-
return {
|
|
15860
|
-
...quote,
|
|
15861
|
-
gasFees
|
|
15862
|
-
};
|
|
16209
|
+
// Gas is estimated server-side by the Earn Service and returned on the quote, so the
|
|
16210
|
+
// SDK no longer simulates it locally. `chainDefinition` lets the fetch fill
|
|
16211
|
+
// the native token symbol / blockchain on each gas entry.
|
|
16212
|
+
return fetchDepositQuote({
|
|
16213
|
+
vaultAddress: params.vaultAddress,
|
|
16214
|
+
amount: params.amount,
|
|
16215
|
+
address,
|
|
16216
|
+
chain,
|
|
16217
|
+
config,
|
|
16218
|
+
chainDefinition
|
|
16219
|
+
});
|
|
15863
16220
|
}
|
|
15864
16221
|
/** {@inheritdoc} */ async getWithdrawalQuote(params) {
|
|
15865
16222
|
const config = this.resolveConfig(params.config);
|
|
15866
16223
|
const { address, chain, chainDefinition } = await resolveAdapterContext(params.from);
|
|
15867
|
-
//
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
config
|
|
15877
|
-
}),
|
|
15878
|
-
this.estimateWithdrawalQuoteGasFees({
|
|
15879
|
-
adapter: params.from.adapter,
|
|
15880
|
-
chain: chainDefinition,
|
|
15881
|
-
apiChain: chain,
|
|
15882
|
-
address,
|
|
15883
|
-
vaultAddress: params.vaultAddress,
|
|
15884
|
-
amount: params.amount,
|
|
15885
|
-
config
|
|
15886
|
-
})
|
|
15887
|
-
]);
|
|
15888
|
-
return {
|
|
15889
|
-
...quote,
|
|
15890
|
-
gasFees
|
|
15891
|
-
};
|
|
16224
|
+
// Gas is estimated server-side by the Earn Service and returned on the quote.
|
|
16225
|
+
return fetchWithdrawalQuote({
|
|
16226
|
+
vaultAddress: params.vaultAddress,
|
|
16227
|
+
amount: params.amount,
|
|
16228
|
+
address,
|
|
16229
|
+
chain,
|
|
16230
|
+
config,
|
|
16231
|
+
chainDefinition
|
|
16232
|
+
});
|
|
15892
16233
|
}
|
|
15893
16234
|
/** {@inheritdoc} */ async getClaimRewardsQuote(params) {
|
|
15894
16235
|
const config = this.resolveConfig(params.config);
|
|
15895
|
-
const { address, chain
|
|
15896
|
-
|
|
16236
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
16237
|
+
// The claimRewards/quote response carries no gas estimate (unlike
|
|
16238
|
+
// deposit/withdrawal quotes), and the SDK no longer estimates gas locally,
|
|
16239
|
+
// so gasFees is always empty for claim rewards.
|
|
16240
|
+
return fetchClaimRewardsQuote({
|
|
15897
16241
|
vaultAddress: params.vaultAddress,
|
|
15898
16242
|
address,
|
|
15899
16243
|
chain,
|
|
15900
16244
|
config
|
|
15901
16245
|
});
|
|
15902
|
-
// No claimable rewards means there is nothing to execute, so there is no
|
|
15903
|
-
// gas to estimate. Short-circuit on the already-fetched quote rather than
|
|
15904
|
-
// calling the (heavier) claim execution endpoint again — this also keeps
|
|
15905
|
-
// `gasFees` empty as documented, instead of risking a `{ fees: null }`
|
|
15906
|
-
// estimation-error entry when the adapter/RPC is unavailable. This
|
|
15907
|
-
// short-circuit is why the claim path stays sequential instead of using
|
|
15908
|
-
// the Promise.all pattern of the deposit/withdrawal quotes: estimating in
|
|
15909
|
-
// parallel would hit the signing endpoint even when nothing is claimable.
|
|
15910
|
-
if (quote.rewards.length === 0) {
|
|
15911
|
-
return {
|
|
15912
|
-
...quote,
|
|
15913
|
-
gasFees: []
|
|
15914
|
-
};
|
|
15915
|
-
}
|
|
15916
|
-
const gasFees = await this.estimateClaimRewardsQuoteGasFees({
|
|
15917
|
-
adapter: params.from.adapter,
|
|
15918
|
-
chain: chainDefinition,
|
|
15919
|
-
apiChain: chain,
|
|
15920
|
-
address,
|
|
15921
|
-
vaultAddress: params.vaultAddress,
|
|
15922
|
-
config
|
|
15923
|
-
});
|
|
15924
|
-
return {
|
|
15925
|
-
...quote,
|
|
15926
|
-
gasFees
|
|
15927
|
-
};
|
|
15928
16246
|
}
|
|
15929
16247
|
}
|
|
15930
16248
|
function hasDepositDestination(params) {
|
|
@@ -16162,11 +16480,27 @@ function formatPositionPnL(pnl) {
|
|
|
16162
16480
|
* @param vault - Provider vault info with raw amount objects
|
|
16163
16481
|
* @returns Vault info with total deposits and liquidity formatted as strings
|
|
16164
16482
|
*/ function formatVaultInfo(vault) {
|
|
16165
|
-
|
|
16483
|
+
// The flat `totalDeposits`/`liquidity` are deprecated aliases that are
|
|
16484
|
+
// intentionally dual-read through the migration window so existing
|
|
16485
|
+
// consumers keep receiving them until Contract.
|
|
16486
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
16487
|
+
const { totalDeposits, liquidity, liquidityProfile, ...rest } = vault;
|
|
16488
|
+
// `liquidityProfile` is `.optional()` in the response schema during the
|
|
16489
|
+
// expand/contract window (an old backend that predates the nested facets
|
|
16490
|
+
// omits it), so only format and re-attach it when present — matching the
|
|
16491
|
+
// provider-side `toVaultInfo` mapper.
|
|
16166
16492
|
return {
|
|
16167
16493
|
...rest,
|
|
16168
16494
|
totalDeposits: formatAmount(totalDeposits),
|
|
16169
|
-
liquidity: formatAmount(liquidity)
|
|
16495
|
+
liquidity: formatAmount(liquidity),
|
|
16496
|
+
...liquidityProfile !== undefined && {
|
|
16497
|
+
liquidityProfile: {
|
|
16498
|
+
...liquidityProfile,
|
|
16499
|
+
totalDeposits: formatAmount(liquidityProfile.totalDeposits),
|
|
16500
|
+
available: formatAmount(liquidityProfile.available),
|
|
16501
|
+
totalSupply: formatAmount(liquidityProfile.totalSupply)
|
|
16502
|
+
}
|
|
16503
|
+
}
|
|
16170
16504
|
};
|
|
16171
16505
|
}
|
|
16172
16506
|
/**
|
|
@@ -18078,27 +18412,95 @@ function formatRetryResult(operation, result) {
|
|
|
18078
18412
|
// Auto-register this kit for user agent tracking
|
|
18079
18413
|
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
18080
18414
|
|
|
18415
|
+
/**
|
|
18416
|
+
* Register event handlers from a context actions map to a kit instance.
|
|
18417
|
+
*
|
|
18418
|
+
* This utility function registers event handlers stored in a context actions map
|
|
18419
|
+
* with a kit instance that supports event handling via an `on` method. It handles
|
|
18420
|
+
* wildcard handlers ('*') and prefixed action handlers, stripping the prefix
|
|
18421
|
+
* before registration.
|
|
18422
|
+
*
|
|
18423
|
+
* The function is designed to be reusable across different operation types
|
|
18424
|
+
* (bridge, swap, stake, etc.) by accepting a configurable prefix parameter.
|
|
18425
|
+
*
|
|
18426
|
+
* @param kit - The kit instance to register handlers with (must have an `on` method)
|
|
18427
|
+
* @param handlers - Map of action names to arrays of handler functions
|
|
18428
|
+
* @param prefix - Optional prefix to strip from action names (e.g., 'bridge.')
|
|
18429
|
+
*
|
|
18430
|
+
* @example
|
|
18431
|
+
* ```typescript
|
|
18432
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
18433
|
+
* import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
18434
|
+
*
|
|
18435
|
+
* const kit = new BridgeKit()
|
|
18436
|
+
* const handlers = {
|
|
18437
|
+
* '*': [(payload) => console.log('All actions:', payload)],
|
|
18438
|
+
* 'bridge.approve': [(payload) => console.log('Approved:', payload)],
|
|
18439
|
+
* 'bridge.burn': [(payload) => console.log('Burned:', payload)],
|
|
18440
|
+
* }
|
|
18441
|
+
*
|
|
18442
|
+
* registerActionHandlers(kit, handlers, 'bridge.')
|
|
18443
|
+
* ```
|
|
18444
|
+
*
|
|
18445
|
+
* @example
|
|
18446
|
+
* ```typescript
|
|
18447
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
18448
|
+
* import { SwapKit } from '@circle-fin/swap-kit'
|
|
18449
|
+
*
|
|
18450
|
+
* const kit = new SwapKit()
|
|
18451
|
+
* const handlers = {
|
|
18452
|
+
* 'swap.initiate': [(payload) => console.log('Swap initiated:', payload)],
|
|
18453
|
+
* }
|
|
18454
|
+
*
|
|
18455
|
+
* registerActionHandlers(kit, handlers, 'swap.')
|
|
18456
|
+
* ```
|
|
18457
|
+
*/ const registerActionHandlers = (kit, handlers, prefix = '')=>{
|
|
18458
|
+
for (const [action, handlerArray] of Object.entries(handlers)){
|
|
18459
|
+
// Register all handlers for this action
|
|
18460
|
+
for (const handler of handlerArray){
|
|
18461
|
+
if (action === '*') {
|
|
18462
|
+
// Wildcard handlers are registered as-is
|
|
18463
|
+
kit.on('*', handler);
|
|
18464
|
+
} else if (prefix && action.startsWith(prefix)) {
|
|
18465
|
+
// Remove prefix to get the actual kit action name
|
|
18466
|
+
const kitAction = action.split('.').at(1);
|
|
18467
|
+
if (kitAction) {
|
|
18468
|
+
kit.on(kitAction, handler);
|
|
18469
|
+
}
|
|
18470
|
+
} else if (!prefix) {
|
|
18471
|
+
// No prefix configured, register action as-is
|
|
18472
|
+
kit.on(action, handler);
|
|
18473
|
+
}
|
|
18474
|
+
// Actions that don't match the prefix are silently ignored
|
|
18475
|
+
}
|
|
18476
|
+
}
|
|
18477
|
+
};
|
|
18478
|
+
|
|
18081
18479
|
/**
|
|
18082
18480
|
* Create an EarnKit instance for AppKit earn operations.
|
|
18083
18481
|
*
|
|
18084
|
-
*
|
|
18085
|
-
*
|
|
18086
|
-
*
|
|
18087
|
-
* reserved until EarnKit fee support ships.
|
|
18482
|
+
* Attaches any earn event handlers previously registered on the AppKit
|
|
18483
|
+
* context (via `kit.on('earn.*', …)` or `kit.on('*', …)`) so step events
|
|
18484
|
+
* fire during the returned kit's earn operations.
|
|
18088
18485
|
*
|
|
18089
|
-
*
|
|
18486
|
+
* @remarks Developer fee hooks from the AppKit context are not applied.
|
|
18487
|
+
* EarnKit does not yet support custom fee policies.
|
|
18090
18488
|
*
|
|
18091
|
-
* @param context - AppKit context
|
|
18092
|
-
* @returns
|
|
18489
|
+
* @param context - AppKit context with earn event handlers and kit options
|
|
18490
|
+
* @returns An EarnKit instance ready for AppKit earn operations
|
|
18093
18491
|
*
|
|
18094
18492
|
* @example
|
|
18095
18493
|
* ```typescript
|
|
18096
18494
|
* const earnKit = createEarnKit(context)
|
|
18097
18495
|
* ```
|
|
18098
|
-
*/ const createEarnKit = ()=>
|
|
18496
|
+
*/ const createEarnKit = (context)=>{
|
|
18497
|
+
const kit = new EarnKit();
|
|
18498
|
+
registerActionHandlers(kit, context.actions.earn, 'earn');
|
|
18499
|
+
return kit;
|
|
18500
|
+
};
|
|
18099
18501
|
|
|
18100
18502
|
async function deposit(context, params) {
|
|
18101
|
-
return createEarnKit().deposit(params);
|
|
18503
|
+
return createEarnKit(context).deposit(params);
|
|
18102
18504
|
}
|
|
18103
18505
|
/**
|
|
18104
18506
|
* Execute an earn withdrawal operation.
|
|
@@ -18122,7 +18524,7 @@ async function deposit(context, params) {
|
|
|
18122
18524
|
* })
|
|
18123
18525
|
* ```
|
|
18124
18526
|
*/ async function withdraw(context, params) {
|
|
18125
|
-
return createEarnKit().withdraw(params);
|
|
18527
|
+
return createEarnKit(context).withdraw(params);
|
|
18126
18528
|
}
|
|
18127
18529
|
/**
|
|
18128
18530
|
* Claim earn rewards.
|
|
@@ -18145,7 +18547,7 @@ async function deposit(context, params) {
|
|
|
18145
18547
|
* })
|
|
18146
18548
|
* ```
|
|
18147
18549
|
*/ async function claimRewards(context, params) {
|
|
18148
|
-
return createEarnKit().claimRewards(params);
|
|
18550
|
+
return createEarnKit(context).claimRewards(params);
|
|
18149
18551
|
}
|
|
18150
18552
|
/**
|
|
18151
18553
|
* Fetch vault information.
|
|
@@ -18167,7 +18569,7 @@ async function deposit(context, params) {
|
|
|
18167
18569
|
* })
|
|
18168
18570
|
* ```
|
|
18169
18571
|
*/ async function getVaults(context, params) {
|
|
18170
|
-
return createEarnKit().getVaults(params);
|
|
18572
|
+
return createEarnKit(context).getVaults(params);
|
|
18171
18573
|
}
|
|
18172
18574
|
/**
|
|
18173
18575
|
* Discover vaults available on a chain.
|
|
@@ -18191,7 +18593,7 @@ async function deposit(context, params) {
|
|
|
18191
18593
|
* })
|
|
18192
18594
|
* ```
|
|
18193
18595
|
*/ async function exploreVaults(context, params) {
|
|
18194
|
-
return createEarnKit().exploreVaults(params);
|
|
18596
|
+
return createEarnKit(context).exploreVaults(params);
|
|
18195
18597
|
}
|
|
18196
18598
|
/**
|
|
18197
18599
|
* Lazily iterate every vault available on a chain.
|
|
@@ -18215,7 +18617,7 @@ async function deposit(context, params) {
|
|
|
18215
18617
|
* }
|
|
18216
18618
|
* ```
|
|
18217
18619
|
*/ function exploreVaultsIterator(context, params) {
|
|
18218
|
-
return createEarnKit().exploreVaultsIterator(params);
|
|
18620
|
+
return createEarnKit(context).exploreVaultsIterator(params);
|
|
18219
18621
|
}
|
|
18220
18622
|
/**
|
|
18221
18623
|
* Fetch a wallet position in a vault.
|
|
@@ -18238,7 +18640,7 @@ async function deposit(context, params) {
|
|
|
18238
18640
|
* })
|
|
18239
18641
|
* ```
|
|
18240
18642
|
*/ async function getPosition(context, params) {
|
|
18241
|
-
return createEarnKit().getPosition(params);
|
|
18643
|
+
return createEarnKit(context).getPosition(params);
|
|
18242
18644
|
}
|
|
18243
18645
|
/**
|
|
18244
18646
|
* Fetch the current status of a cross-chain Earn deposit.
|
|
@@ -18260,7 +18662,7 @@ async function deposit(context, params) {
|
|
|
18260
18662
|
* console.log(status.status)
|
|
18261
18663
|
* ```
|
|
18262
18664
|
*/ async function getCrossChainDepositStatus(context, params) {
|
|
18263
|
-
return createEarnKit().getCrossChainDepositStatus(params);
|
|
18665
|
+
return createEarnKit(context).getCrossChainDepositStatus(params);
|
|
18264
18666
|
}
|
|
18265
18667
|
/**
|
|
18266
18668
|
* Poll a cross-chain Earn deposit until it reaches a terminal bridge state.
|
|
@@ -18283,7 +18685,7 @@ async function deposit(context, params) {
|
|
|
18283
18685
|
* console.log(result.outcome)
|
|
18284
18686
|
* ```
|
|
18285
18687
|
*/ async function waitForCrossChainDeposit(context, params) {
|
|
18286
|
-
return createEarnKit().waitForCrossChainDeposit(params);
|
|
18688
|
+
return createEarnKit(context).waitForCrossChainDeposit(params);
|
|
18287
18689
|
}
|
|
18288
18690
|
/**
|
|
18289
18691
|
* Fetch a deposit quote.
|
|
@@ -18307,7 +18709,7 @@ async function deposit(context, params) {
|
|
|
18307
18709
|
* })
|
|
18308
18710
|
* ```
|
|
18309
18711
|
*/ async function getDepositQuote(context, params) {
|
|
18310
|
-
return createEarnKit().getDepositQuote(params);
|
|
18712
|
+
return createEarnKit(context).getDepositQuote(params);
|
|
18311
18713
|
}
|
|
18312
18714
|
/**
|
|
18313
18715
|
* Fetch a withdrawal quote.
|
|
@@ -18331,7 +18733,7 @@ async function deposit(context, params) {
|
|
|
18331
18733
|
* })
|
|
18332
18734
|
* ```
|
|
18333
18735
|
*/ async function getWithdrawalQuote(context, params) {
|
|
18334
|
-
return createEarnKit().getWithdrawalQuote(params);
|
|
18736
|
+
return createEarnKit(context).getWithdrawalQuote(params);
|
|
18335
18737
|
}
|
|
18336
18738
|
/**
|
|
18337
18739
|
* Fetch a claim rewards quote.
|
|
@@ -18354,7 +18756,43 @@ async function deposit(context, params) {
|
|
|
18354
18756
|
* })
|
|
18355
18757
|
* ```
|
|
18356
18758
|
*/ async function getClaimRewardsQuote(context, params) {
|
|
18357
|
-
return createEarnKit().getClaimRewardsQuote(params);
|
|
18759
|
+
return createEarnKit(context).getClaimRewardsQuote(params);
|
|
18760
|
+
}
|
|
18761
|
+
/**
|
|
18762
|
+
* Resume a multi-phase earn operation that previously failed.
|
|
18763
|
+
*
|
|
18764
|
+
* Pass the {@link KitError} caught from `deposit`, `withdraw`, or
|
|
18765
|
+
* `claimRewards`. Completed phases can be skipped when the error carries
|
|
18766
|
+
* earn retry context. Call `isRetryableError(error)` first.
|
|
18767
|
+
*
|
|
18768
|
+
* @remarks
|
|
18769
|
+
* Retry re-fetches execution params and may re-submit the execute
|
|
18770
|
+
* transaction. Treat this as best-effort recovery if a prior execute
|
|
18771
|
+
* broadcast may still be in flight.
|
|
18772
|
+
*
|
|
18773
|
+
* @param context - AppKit context
|
|
18774
|
+
* @param error - The error caught from a previous multi-phase earn operation
|
|
18775
|
+
* @returns Promise resolving to the result of the resumed operation
|
|
18776
|
+
* @throws If the error is not retryable or lacks earn retry context
|
|
18777
|
+
*
|
|
18778
|
+
* @example
|
|
18779
|
+
* ```typescript
|
|
18780
|
+
* import { isRetryableError } from '@circle-fin/app-kit'
|
|
18781
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
18782
|
+
* import { retry } from '@circle-fin/app-kit/earn'
|
|
18783
|
+
*
|
|
18784
|
+
* const context = createContext()
|
|
18785
|
+
*
|
|
18786
|
+
* try {
|
|
18787
|
+
* await deposit(context, params)
|
|
18788
|
+
* } catch (error) {
|
|
18789
|
+
* if (isRetryableError(error)) {
|
|
18790
|
+
* const result = await retry(context, error)
|
|
18791
|
+
* }
|
|
18792
|
+
* }
|
|
18793
|
+
* ```
|
|
18794
|
+
*/ async function retry(context, error) {
|
|
18795
|
+
return createEarnKit(context).retry(error);
|
|
18358
18796
|
}
|
|
18359
18797
|
|
|
18360
18798
|
exports.claimRewards = claimRewards;
|
|
@@ -18367,6 +18805,7 @@ exports.getDepositQuote = getDepositQuote;
|
|
|
18367
18805
|
exports.getPosition = getPosition;
|
|
18368
18806
|
exports.getVaults = getVaults;
|
|
18369
18807
|
exports.getWithdrawalQuote = getWithdrawalQuote;
|
|
18808
|
+
exports.retry = retry;
|
|
18370
18809
|
exports.waitForCrossChainDeposit = waitForCrossChainDeposit;
|
|
18371
18810
|
exports.withdraw = withdraw;
|
|
18372
18811
|
//# sourceMappingURL=earn.cjs.map
|