@circle-fin/app-kit 1.5.1 → 1.6.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 +6 -0
- package/README.md +81 -33
- package/chains.cjs +8 -10
- package/chains.mjs +8 -10
- package/earn.cjs +14828 -0
- package/earn.cjs.map +1 -0
- package/earn.d.ts +7438 -0
- package/earn.mjs +14819 -0
- package/earn.mjs.map +1 -0
- package/index.cjs +3761 -308
- package/index.d.ts +6750 -2849
- package/index.mjs +3735 -302
- package/package.json +12 -5
package/index.cjs
CHANGED
|
@@ -1074,6 +1074,35 @@ function createUnsupportedSwapRouteError(tokenIn, tokenOut, chain) {
|
|
|
1074
1074
|
};
|
|
1075
1075
|
return new KitError(errorDetails);
|
|
1076
1076
|
}
|
|
1077
|
+
/**
|
|
1078
|
+
* Creates error for unsupported earn route.
|
|
1079
|
+
*
|
|
1080
|
+
* This error is thrown when no available earn provider supports the requested
|
|
1081
|
+
* operation on the specified chain.
|
|
1082
|
+
*
|
|
1083
|
+
* @param operation - Earn operation name
|
|
1084
|
+
* @param chain - Chain name where the earn operation was attempted
|
|
1085
|
+
* @returns KitError with specific earn route details
|
|
1086
|
+
*
|
|
1087
|
+
* @example
|
|
1088
|
+
* ```typescript
|
|
1089
|
+
* import { createUnsupportedEarnRouteError } from '@core/errors'
|
|
1090
|
+
*
|
|
1091
|
+
* throw createUnsupportedEarnRouteError('deposit', 'Ethereum')
|
|
1092
|
+
* // Message: "Earn deposit on Ethereum is not supported by any available provider."
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
function createUnsupportedEarnRouteError(operation, chain) {
|
|
1096
|
+
const errorDetails = {
|
|
1097
|
+
...InputError.UNSUPPORTED_ROUTE,
|
|
1098
|
+
recoverability: 'FATAL',
|
|
1099
|
+
message: `Earn ${operation} on ${chain} is not supported by any available provider.`,
|
|
1100
|
+
cause: {
|
|
1101
|
+
trace: { operation, chain },
|
|
1102
|
+
},
|
|
1103
|
+
};
|
|
1104
|
+
return new KitError(errorDetails);
|
|
1105
|
+
}
|
|
1077
1106
|
/**
|
|
1078
1107
|
* Creates error for unsupported token on chain.
|
|
1079
1108
|
*
|
|
@@ -3217,7 +3246,7 @@ function handleTimeoutError(serviceName, operation, error) {
|
|
|
3217
3246
|
* @returns `true` when `error.responseBody` is a non-null object
|
|
3218
3247
|
* @internal
|
|
3219
3248
|
*/
|
|
3220
|
-
function hasResponseBody(error) {
|
|
3249
|
+
function hasResponseBody$1(error) {
|
|
3221
3250
|
return (typeof error === 'object' &&
|
|
3222
3251
|
error !== null &&
|
|
3223
3252
|
'responseBody' in error &&
|
|
@@ -3230,10 +3259,12 @@ function hasResponseBody(error) {
|
|
|
3230
3259
|
*
|
|
3231
3260
|
* @param error - The raw error from the HTTP layer
|
|
3232
3261
|
* @returns The parsed body cast to {@link ApiErrorResponseBody}, or undefined
|
|
3262
|
+
* @throws Never. Returns `undefined` when the error does not carry a valid
|
|
3263
|
+
* `responseBody`.
|
|
3233
3264
|
* @internal
|
|
3234
3265
|
*/
|
|
3235
3266
|
function extractResponseBody(error) {
|
|
3236
|
-
if (!hasResponseBody(error)) {
|
|
3267
|
+
if (!hasResponseBody$1(error)) {
|
|
3237
3268
|
return undefined;
|
|
3238
3269
|
}
|
|
3239
3270
|
return error.responseBody;
|
|
@@ -3365,6 +3396,224 @@ function extractHttpStatusCode(msg) {
|
|
|
3365
3396
|
return null;
|
|
3366
3397
|
}
|
|
3367
3398
|
|
|
3399
|
+
/**
|
|
3400
|
+
* Standardized error definitions for Earn/Zenith operations.
|
|
3401
|
+
*
|
|
3402
|
+
* These error codes provide fine-grained categorization of failures
|
|
3403
|
+
* from the Zenith earn service, enabling SDK consumers to distinguish
|
|
3404
|
+
* between input errors (fix your request) and service errors (retry later).
|
|
3405
|
+
*
|
|
3406
|
+
* Error code ranges:
|
|
3407
|
+
* - 1100-1104: INPUT errors — invalid inputs, unsupported configurations
|
|
3408
|
+
* - 8100-8103: SERVICE errors — retryable backend/provider failures
|
|
3409
|
+
*
|
|
3410
|
+
* @example
|
|
3411
|
+
* ```typescript
|
|
3412
|
+
* import { EarnError, isInputError, isRetryableError } from '@circle-fin/earn-kit'
|
|
3413
|
+
*
|
|
3414
|
+
* try {
|
|
3415
|
+
* await earnKit.deposit(params)
|
|
3416
|
+
* } catch (error) {
|
|
3417
|
+
* if (isInputError(error)) {
|
|
3418
|
+
* // Fix the request: vault doesn't exist, chain not supported, etc.
|
|
3419
|
+
* }
|
|
3420
|
+
* if (isRetryableError(error)) {
|
|
3421
|
+
* // Try again: signing timed out, provider temporarily unavailable, etc.
|
|
3422
|
+
* }
|
|
3423
|
+
* }
|
|
3424
|
+
* ```
|
|
3425
|
+
*/
|
|
3426
|
+
const EarnError = {
|
|
3427
|
+
/** The requested vault does not exist for the provided chain. */
|
|
3428
|
+
VAULT_NOT_FOUND: {
|
|
3429
|
+
code: 1100,
|
|
3430
|
+
name: 'EARN_VAULT_NOT_FOUND',
|
|
3431
|
+
type: 'INPUT',
|
|
3432
|
+
},
|
|
3433
|
+
/** The specified blockchain is not supported for earn operations. */
|
|
3434
|
+
UNSUPPORTED_CHAIN: {
|
|
3435
|
+
code: 1101,
|
|
3436
|
+
name: 'EARN_UNSUPPORTED_CHAIN',
|
|
3437
|
+
type: 'INPUT',
|
|
3438
|
+
},
|
|
3439
|
+
/** The vault's underlying asset is not supported. */
|
|
3440
|
+
UNSUPPORTED_VAULT: {
|
|
3441
|
+
code: 1102,
|
|
3442
|
+
name: 'EARN_UNSUPPORTED_VAULT',
|
|
3443
|
+
type: 'INPUT',
|
|
3444
|
+
},
|
|
3445
|
+
/** The submitted signature could not be verified. */
|
|
3446
|
+
SIGNATURE_REJECTED: {
|
|
3447
|
+
code: 1103,
|
|
3448
|
+
name: 'EARN_SIGNATURE_REJECTED',
|
|
3449
|
+
type: 'INPUT',
|
|
3450
|
+
},
|
|
3451
|
+
/** General input validation failure (invalid ID, batch size, etc.). */
|
|
3452
|
+
INVALID_INPUT: {
|
|
3453
|
+
code: 1104,
|
|
3454
|
+
name: 'EARN_INVALID_INPUT',
|
|
3455
|
+
type: 'INPUT',
|
|
3456
|
+
},
|
|
3457
|
+
/** The proxy signing call failed — retryable. */
|
|
3458
|
+
SIGNING_FAILED: {
|
|
3459
|
+
code: 8100,
|
|
3460
|
+
name: 'EARN_SIGNING_FAILED',
|
|
3461
|
+
type: 'SERVICE',
|
|
3462
|
+
},
|
|
3463
|
+
/** An external provider API request failed — retryable. */
|
|
3464
|
+
PROVIDER_ERROR: {
|
|
3465
|
+
code: 8101,
|
|
3466
|
+
name: 'EARN_PROVIDER_ERROR',
|
|
3467
|
+
type: 'SERVICE',
|
|
3468
|
+
},
|
|
3469
|
+
/** Failed to fetch reward data — retryable. */
|
|
3470
|
+
REWARDS_FETCH_FAILED: {
|
|
3471
|
+
code: 8102,
|
|
3472
|
+
name: 'EARN_REWARDS_FETCH_FAILED',
|
|
3473
|
+
type: 'SERVICE',
|
|
3474
|
+
},
|
|
3475
|
+
/** An internal earn service error occurred — retryable. */
|
|
3476
|
+
INTERNAL_ERROR: {
|
|
3477
|
+
code: 8103,
|
|
3478
|
+
name: 'EARN_INTERNAL_ERROR',
|
|
3479
|
+
type: 'SERVICE',
|
|
3480
|
+
},
|
|
3481
|
+
};
|
|
3482
|
+
|
|
3483
|
+
function hasResponseBody(error) {
|
|
3484
|
+
return (typeof error === 'object' &&
|
|
3485
|
+
error !== null &&
|
|
3486
|
+
'responseBody' in error &&
|
|
3487
|
+
typeof error['responseBody'] === 'object' &&
|
|
3488
|
+
error['responseBody'] !== null);
|
|
3489
|
+
}
|
|
3490
|
+
function extractEarnResponseBody(error) {
|
|
3491
|
+
if (!hasResponseBody(error)) {
|
|
3492
|
+
return undefined;
|
|
3493
|
+
}
|
|
3494
|
+
return error.responseBody;
|
|
3495
|
+
}
|
|
3496
|
+
function getOptionalString(value) {
|
|
3497
|
+
return typeof value === 'string' ? value : undefined;
|
|
3498
|
+
}
|
|
3499
|
+
/**
|
|
3500
|
+
* Maps earn service backend error codes (380xxx) to typed EarnError constants
|
|
3501
|
+
* with correct recoverability.
|
|
3502
|
+
*
|
|
3503
|
+
* INPUT errors (FATAL) — fix your request:
|
|
3504
|
+
* - vault-not-found, unsupported-chain, unsupported-vault,
|
|
3505
|
+
* signature-rejected, invalid-id, invalid-batch-size, position-not-registered,
|
|
3506
|
+
* withdrawal-max-exceeded, insufficient-balance
|
|
3507
|
+
*
|
|
3508
|
+
* SERVICE errors (RETRYABLE) — try again later:
|
|
3509
|
+
* - signing-failed, provider-error, rewards-fetch-failed,
|
|
3510
|
+
* internal-error, vault-refresh-busy, bridge failures
|
|
3511
|
+
*
|
|
3512
|
+
* Unrecognized codes fall through to `parseApiError` for HTTP-status-based
|
|
3513
|
+
* handling.
|
|
3514
|
+
*
|
|
3515
|
+
* @internal
|
|
3516
|
+
*/
|
|
3517
|
+
const EARN_CODE_MAP = new Map([
|
|
3518
|
+
// Common (380_0XX)
|
|
3519
|
+
[380001, { errorDef: EarnError.INVALID_INPUT, recoverability: 'FATAL' }],
|
|
3520
|
+
[
|
|
3521
|
+
380002,
|
|
3522
|
+
{
|
|
3523
|
+
errorDef: RateLimitError.RATE_LIMIT_EXCEEDED,
|
|
3524
|
+
recoverability: 'RETRYABLE',
|
|
3525
|
+
},
|
|
3526
|
+
],
|
|
3527
|
+
// Shared (380_1XX)
|
|
3528
|
+
[380100, { errorDef: EarnError.VAULT_NOT_FOUND, recoverability: 'FATAL' }],
|
|
3529
|
+
[380101, { errorDef: EarnError.SIGNATURE_REJECTED, recoverability: 'FATAL' }],
|
|
3530
|
+
[380102, { errorDef: EarnError.UNSUPPORTED_CHAIN, recoverability: 'FATAL' }],
|
|
3531
|
+
// Vault Discovery (380_3XX)
|
|
3532
|
+
[380300, { errorDef: EarnError.VAULT_NOT_FOUND, recoverability: 'FATAL' }],
|
|
3533
|
+
[380301, { errorDef: EarnError.INVALID_INPUT, recoverability: 'FATAL' }],
|
|
3534
|
+
[380302, { errorDef: EarnError.PROVIDER_ERROR, recoverability: 'RETRYABLE' }],
|
|
3535
|
+
[380303, { errorDef: EarnError.UNSUPPORTED_VAULT, recoverability: 'FATAL' }],
|
|
3536
|
+
// EarnKit (380_4XX)
|
|
3537
|
+
[380400, { errorDef: EarnError.UNSUPPORTED_CHAIN, recoverability: 'FATAL' }],
|
|
3538
|
+
[380401, { errorDef: EarnError.SIGNING_FAILED, recoverability: 'RETRYABLE' }],
|
|
3539
|
+
[
|
|
3540
|
+
380402,
|
|
3541
|
+
{ errorDef: EarnError.REWARDS_FETCH_FAILED, recoverability: 'RETRYABLE' },
|
|
3542
|
+
],
|
|
3543
|
+
[380403, { errorDef: EarnError.INTERNAL_ERROR, recoverability: 'RETRYABLE' }],
|
|
3544
|
+
[380404, { errorDef: EarnError.PROVIDER_ERROR, recoverability: 'RETRYABLE' }],
|
|
3545
|
+
[380405, { errorDef: EarnError.PROVIDER_ERROR, recoverability: 'RETRYABLE' }],
|
|
3546
|
+
[380406, { errorDef: EarnError.INTERNAL_ERROR, recoverability: 'RETRYABLE' }],
|
|
3547
|
+
[380407, { errorDef: EarnError.INVALID_INPUT, recoverability: 'FATAL' }],
|
|
3548
|
+
[380408, { errorDef: EarnError.INVALID_INPUT, recoverability: 'FATAL' }],
|
|
3549
|
+
[380409, { errorDef: EarnError.INVALID_INPUT, recoverability: 'FATAL' }],
|
|
3550
|
+
// Bridge (380_5XX)
|
|
3551
|
+
[380500, { errorDef: EarnError.PROVIDER_ERROR, recoverability: 'RETRYABLE' }],
|
|
3552
|
+
[380501, { errorDef: EarnError.SIGNING_FAILED, recoverability: 'RETRYABLE' }],
|
|
3553
|
+
[380502, { errorDef: EarnError.PROVIDER_ERROR, recoverability: 'RETRYABLE' }],
|
|
3554
|
+
]);
|
|
3555
|
+
/**
|
|
3556
|
+
* Parses Earn Service API errors into typed KitError instances using
|
|
3557
|
+
* earn service backend error codes for fine-grained categorization.
|
|
3558
|
+
*
|
|
3559
|
+
* When the response body contains a recognized earn service backend code
|
|
3560
|
+
* (380xxx), the error is mapped to a specific EarnError constant with the
|
|
3561
|
+
* correct recoverability. The original backend error code is preserved in
|
|
3562
|
+
* `error.cause.trace.earnServiceCode`.
|
|
3563
|
+
*
|
|
3564
|
+
* When the code is unrecognized or the response body is unavailable,
|
|
3565
|
+
* falls through to the generic `parseApiError` for HTTP-status-based handling.
|
|
3566
|
+
*
|
|
3567
|
+
* @param error - The raw error from the API call
|
|
3568
|
+
* @param context - Context information (operation name)
|
|
3569
|
+
* @returns A structured KitError instance
|
|
3570
|
+
* @throws Never — all error paths are caught and returned as a `KitError`
|
|
3571
|
+
* instance
|
|
3572
|
+
*
|
|
3573
|
+
* @example
|
|
3574
|
+
* ```typescript
|
|
3575
|
+
* try {
|
|
3576
|
+
* await earnServiceApi.deposit(params)
|
|
3577
|
+
* } catch (error) {
|
|
3578
|
+
* throw parseEarnApiError(error, { operation: 'deposit' })
|
|
3579
|
+
* }
|
|
3580
|
+
* ```
|
|
3581
|
+
*/
|
|
3582
|
+
function parseEarnApiError(error, context) {
|
|
3583
|
+
// If it's already a KitError, return it as-is
|
|
3584
|
+
if (error instanceof KitError) {
|
|
3585
|
+
return error;
|
|
3586
|
+
}
|
|
3587
|
+
const responseBody = extractEarnResponseBody(error);
|
|
3588
|
+
const earnServiceCode = typeof responseBody?.['code'] === 'number'
|
|
3589
|
+
? responseBody['code']
|
|
3590
|
+
: undefined;
|
|
3591
|
+
if (earnServiceCode !== undefined) {
|
|
3592
|
+
const mapping = EARN_CODE_MAP.get(earnServiceCode);
|
|
3593
|
+
if (mapping !== undefined) {
|
|
3594
|
+
const message = getOptionalString(responseBody?.['externalMessage']) ??
|
|
3595
|
+
getOptionalString(responseBody?.['message']) ??
|
|
3596
|
+
`Earn Service ${context.operation ?? 'API'} failed`;
|
|
3597
|
+
return new KitError({
|
|
3598
|
+
...mapping.errorDef,
|
|
3599
|
+
recoverability: mapping.recoverability,
|
|
3600
|
+
message,
|
|
3601
|
+
cause: {
|
|
3602
|
+
trace: {
|
|
3603
|
+
earnServiceCode,
|
|
3604
|
+
originalError: error,
|
|
3605
|
+
},
|
|
3606
|
+
},
|
|
3607
|
+
});
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
// Fallthrough: unrecognized code or no response body — use HTTP-status-based parsing
|
|
3611
|
+
return parseApiError(error, {
|
|
3612
|
+
...context,
|
|
3613
|
+
service: context.service ?? 'Earn Service',
|
|
3614
|
+
});
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3368
3617
|
// -----------------------------------------------------------------------------
|
|
3369
3618
|
// Blockchain Enum
|
|
3370
3619
|
// -----------------------------------------------------------------------------
|
|
@@ -3724,24 +3973,22 @@ exports.UnifiedBalanceChain = void 0;
|
|
|
3724
3973
|
* Enumeration of blockchains that support earn (vault deposit/withdraw)
|
|
3725
3974
|
* operations through the Earn Kit.
|
|
3726
3975
|
*
|
|
3727
|
-
* Currently only Ethereum mainnet is supported. Additional chains
|
|
3728
|
-
* will be added as vault protocol support expands.
|
|
3729
|
-
*
|
|
3730
3976
|
* @example
|
|
3731
3977
|
* ```typescript
|
|
3732
3978
|
* import { EarnChain } from '@core/chains'
|
|
3733
3979
|
*
|
|
3734
3980
|
* const result = await earnKit.deposit({
|
|
3735
|
-
* from: { adapter, chain: EarnChain.
|
|
3981
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
3736
3982
|
* vaultAddress: '0x...',
|
|
3737
3983
|
* amount: '100',
|
|
3738
3984
|
* })
|
|
3739
3985
|
* ```
|
|
3740
3986
|
*/
|
|
3741
|
-
|
|
3987
|
+
// Values must match Blockchain enum members exactly.
|
|
3988
|
+
exports.EarnChain = void 0;
|
|
3742
3989
|
(function (EarnChain) {
|
|
3743
|
-
EarnChain["
|
|
3744
|
-
})(EarnChain || (EarnChain = {}));
|
|
3990
|
+
EarnChain["Arc_Testnet"] = "Arc_Testnet";
|
|
3991
|
+
})(exports.EarnChain || (exports.EarnChain = {}));
|
|
3745
3992
|
|
|
3746
3993
|
/**
|
|
3747
3994
|
* Helper function to define a chain with proper TypeScript typing.
|
|
@@ -7481,7 +7728,7 @@ const bridgeChainIdentifierSchema = zod.z.union([
|
|
|
7481
7728
|
* Zod schema for validating earn-specific chain identifiers.
|
|
7482
7729
|
*
|
|
7483
7730
|
* Validate that the provided chain is supported for earn (vault
|
|
7484
|
-
* deposit/withdraw) operations. Currently only
|
|
7731
|
+
* deposit/withdraw) operations. Currently only Arc Testnet is
|
|
7485
7732
|
* supported.
|
|
7486
7733
|
*
|
|
7487
7734
|
* Accept an EarnChain enum value, a matching string literal, or
|
|
@@ -7490,26 +7737,26 @@ const bridgeChainIdentifierSchema = zod.z.union([
|
|
|
7490
7737
|
* @example
|
|
7491
7738
|
* ```typescript
|
|
7492
7739
|
* import { earnChainIdentifierSchema } from '@core/chains'
|
|
7493
|
-
* import {
|
|
7740
|
+
* import { ArcTestnet, EarnChain } from '@core/chains'
|
|
7494
7741
|
*
|
|
7495
7742
|
* // Valid
|
|
7496
|
-
* earnChainIdentifierSchema.parse(EarnChain.
|
|
7497
|
-
* earnChainIdentifierSchema.parse('
|
|
7498
|
-
* earnChainIdentifierSchema.parse(
|
|
7743
|
+
* earnChainIdentifierSchema.parse(EarnChain.Arc_Testnet)
|
|
7744
|
+
* earnChainIdentifierSchema.parse('Arc_Testnet')
|
|
7745
|
+
* earnChainIdentifierSchema.parse(ArcTestnet)
|
|
7499
7746
|
*
|
|
7500
7747
|
* // Invalid (throws ZodError)
|
|
7501
7748
|
* earnChainIdentifierSchema.parse('Solana')
|
|
7502
7749
|
* ```
|
|
7503
7750
|
*/
|
|
7504
|
-
zod.z.union([
|
|
7505
|
-
zod.z.string().refine((val) => val in EarnChain, (val) => ({
|
|
7751
|
+
const earnChainIdentifierSchema = zod.z.union([
|
|
7752
|
+
zod.z.string().refine((val) => val in exports.EarnChain, (val) => ({
|
|
7506
7753
|
message: `"${val}" is not a supported earn chain. ` +
|
|
7507
|
-
`Supported chains: ${Object.values(EarnChain).join(', ')}`,
|
|
7754
|
+
`Supported chains: ${Object.values(exports.EarnChain).join(', ')}`,
|
|
7508
7755
|
})),
|
|
7509
|
-
zod.z.nativeEnum(EarnChain),
|
|
7510
|
-
chainDefinitionSchema$2.refine((chain) => chain.chain in EarnChain, (chain) => ({
|
|
7756
|
+
zod.z.nativeEnum(exports.EarnChain),
|
|
7757
|
+
chainDefinitionSchema$2.refine((chain) => chain.chain in exports.EarnChain, (chain) => ({
|
|
7511
7758
|
message: `"${chain.chain}" is not a supported earn chain. ` +
|
|
7512
|
-
`Supported chains: ${Object.values(EarnChain).join(', ')}`,
|
|
7759
|
+
`Supported chains: ${Object.values(exports.EarnChain).join(', ')}`,
|
|
7513
7760
|
})),
|
|
7514
7761
|
]);
|
|
7515
7762
|
/**
|
|
@@ -8359,7 +8606,7 @@ function handleAddressError(path, _code, _message, paramsObj) {
|
|
|
8359
8606
|
* Default configuration values for the API polling utility.
|
|
8360
8607
|
* @internal
|
|
8361
8608
|
*/
|
|
8362
|
-
const DEFAULT_CONFIG$
|
|
8609
|
+
const DEFAULT_CONFIG$3 = {
|
|
8363
8610
|
timeout: 2_000,
|
|
8364
8611
|
maxRetries: 10,
|
|
8365
8612
|
retryDelay: 200,
|
|
@@ -8568,10 +8815,10 @@ const isRetryableError = (error) => {
|
|
|
8568
8815
|
const pollApiWithValidation = async (url, method, isValidType, config = {}, body) => {
|
|
8569
8816
|
// Merge headers so that 'User-Agent' is always present and not overwritten
|
|
8570
8817
|
const effectiveConfig = {
|
|
8571
|
-
...DEFAULT_CONFIG$
|
|
8818
|
+
...DEFAULT_CONFIG$3,
|
|
8572
8819
|
...config,
|
|
8573
8820
|
headers: {
|
|
8574
|
-
...DEFAULT_CONFIG$
|
|
8821
|
+
...DEFAULT_CONFIG$3.headers,
|
|
8575
8822
|
...(config.headers ?? {}),
|
|
8576
8823
|
// In browser environments, directly setting the 'User-Agent' or similar headers is restricted and may be ignored or cause errors.
|
|
8577
8824
|
// This is why we use the 'X-User-Agent' header instead.
|
|
@@ -10078,7 +10325,7 @@ zod.z.custom((value) => {
|
|
|
10078
10325
|
* formatAmount({ value: '3141592000000000000', token: 'NATIVE', chain: Ethereum }) // "3.141592"
|
|
10079
10326
|
* ```
|
|
10080
10327
|
*/
|
|
10081
|
-
const formatAmount$
|
|
10328
|
+
const formatAmount$2 = (params) => {
|
|
10082
10329
|
const { value, token, tokens } = params;
|
|
10083
10330
|
// Handle NATIVE token first (chain-specific decimals)
|
|
10084
10331
|
if (token === 'NATIVE') {
|
|
@@ -10798,11 +11045,11 @@ function emitResultStepErrorTelemetry(failedStep, stepEventMap, fallbackEventTyp
|
|
|
10798
11045
|
void emitAnalyticsLog(buildPayload$1(config, stepEntry?.[1] ?? fallbackEventType, errorDetails, context));
|
|
10799
11046
|
}
|
|
10800
11047
|
|
|
10801
|
-
var name$
|
|
10802
|
-
var version$
|
|
10803
|
-
var pkg$
|
|
10804
|
-
name: name$
|
|
10805
|
-
version: version$
|
|
11048
|
+
var name$3 = "@circle-fin/bridge-kit";
|
|
11049
|
+
var version$4 = "1.10.1";
|
|
11050
|
+
var pkg$4 = {
|
|
11051
|
+
name: name$3,
|
|
11052
|
+
version: version$4};
|
|
10806
11053
|
|
|
10807
11054
|
const assertCustomFeePolicySymbol$2 = Symbol('assertCustomFeePolicy');
|
|
10808
11055
|
/**
|
|
@@ -11098,7 +11345,9 @@ const hexStringSchema = zod.z
|
|
|
11098
11345
|
* console.log(result.success) // true
|
|
11099
11346
|
* ```
|
|
11100
11347
|
*/
|
|
11101
|
-
const evmAddressSchema = hexStringSchema
|
|
11348
|
+
const evmAddressSchema = hexStringSchema
|
|
11349
|
+
.refine((value) => value.length === 42, 'EVM address must be exactly 42 characters long (0x + 40 hex characters)')
|
|
11350
|
+
.transform((value) => value);
|
|
11102
11351
|
/**
|
|
11103
11352
|
* Schema for validating transaction hashes.
|
|
11104
11353
|
*
|
|
@@ -11119,6 +11368,29 @@ const evmAddressSchema = hexStringSchema.refine((value) => value.length === 42,
|
|
|
11119
11368
|
* ```
|
|
11120
11369
|
*/
|
|
11121
11370
|
hexStringSchema.refine((value) => value.length === 66, 'Transaction hash must be exactly 66 characters long (0x + 64 hex characters)');
|
|
11371
|
+
/**
|
|
11372
|
+
* Schema for validating EVM signatures.
|
|
11373
|
+
*
|
|
11374
|
+
* This schema validates that a string is a properly formatted 65-byte EVM
|
|
11375
|
+
* signature:
|
|
11376
|
+
* - Must be a valid hex string with '0x' prefix
|
|
11377
|
+
* - Must be exactly 132 characters long (0x + 130 hex characters)
|
|
11378
|
+
*
|
|
11379
|
+
* @throws {KitError} If validation fails with INPUT_VALIDATION_FAILED code (1098), with details about which properties failed
|
|
11380
|
+
*
|
|
11381
|
+
* @example
|
|
11382
|
+
* ```typescript
|
|
11383
|
+
* import { evmSignatureSchema } from '@core/adapter'
|
|
11384
|
+
*
|
|
11385
|
+
* const validSignature = `0x${'ab'.repeat(65)}`
|
|
11386
|
+
*
|
|
11387
|
+
* const result = evmSignatureSchema.safeParse(validSignature)
|
|
11388
|
+
* console.log(result.success) // true
|
|
11389
|
+
* ```
|
|
11390
|
+
*/
|
|
11391
|
+
const evmSignatureSchema = hexStringSchema
|
|
11392
|
+
.refine((value) => value.length === 132, 'EVM signature must be exactly 132 characters long (0x + 130 hex characters)')
|
|
11393
|
+
.transform((value) => value);
|
|
11122
11394
|
/**
|
|
11123
11395
|
* Schema for validating base58-encoded strings.
|
|
11124
11396
|
*
|
|
@@ -11773,7 +12045,7 @@ function createRecipientAddressValidator() {
|
|
|
11773
12045
|
*
|
|
11774
12046
|
* Optionally includes address for developer-controlled adapters.
|
|
11775
12047
|
*/
|
|
11776
|
-
const adapterContextSchema$
|
|
12048
|
+
const adapterContextSchema$7 = zod.z.object({
|
|
11777
12049
|
adapter: adapterSchema$1,
|
|
11778
12050
|
chain: bridgeChainIdentifierSchema,
|
|
11779
12051
|
address: zod.z.string().optional(),
|
|
@@ -11783,7 +12055,7 @@ const adapterContextSchema$6 = zod.z.object({
|
|
|
11783
12055
|
* Contains an explicit recipientAddress along with adapter and chain.
|
|
11784
12056
|
* The address format is validated based on the chain type (EVM or Solana).
|
|
11785
12057
|
*/
|
|
11786
|
-
const bridgeDestinationWithAddressSchema = adapterContextSchema$
|
|
12058
|
+
const bridgeDestinationWithAddressSchema = adapterContextSchema$7
|
|
11787
12059
|
.extend({
|
|
11788
12060
|
recipientAddress: zod.z.string().min(1, 'Recipient address is required'),
|
|
11789
12061
|
useForwarder: zod.z.boolean().optional(),
|
|
@@ -11793,7 +12065,7 @@ const bridgeDestinationWithAddressSchema = adapterContextSchema$6
|
|
|
11793
12065
|
* Schema for validating AdapterContext with optional useForwarder.
|
|
11794
12066
|
* Extends adapterContextSchema with the useForwarder flag.
|
|
11795
12067
|
*/
|
|
11796
|
-
const adapterContextWithForwarderSchema = adapterContextSchema$
|
|
12068
|
+
const adapterContextWithForwarderSchema = adapterContextSchema$7.extend({
|
|
11797
12069
|
useForwarder: zod.z.boolean().optional(),
|
|
11798
12070
|
});
|
|
11799
12071
|
/**
|
|
@@ -11874,7 +12146,7 @@ const bridgeDestinationSchema = zod.z.union([
|
|
|
11874
12146
|
* ```
|
|
11875
12147
|
*/
|
|
11876
12148
|
const bridgeParamsWithChainIdentifierSchema = zod.z.object({
|
|
11877
|
-
from: adapterContextSchema$
|
|
12149
|
+
from: adapterContextSchema$7.strict(),
|
|
11878
12150
|
to: bridgeDestinationSchema,
|
|
11879
12151
|
amount: zod.z
|
|
11880
12152
|
.string()
|
|
@@ -12940,7 +13212,7 @@ function resolveBridgeInvocation$1(invocationMeta) {
|
|
|
12940
13212
|
const bridgeKitCaller = {
|
|
12941
13213
|
type: 'kit',
|
|
12942
13214
|
name: 'BridgeKit',
|
|
12943
|
-
version: pkg$
|
|
13215
|
+
version: pkg$4.version,
|
|
12944
13216
|
};
|
|
12945
13217
|
// Create default runtime and tokens for invocation context resolution
|
|
12946
13218
|
const defaults = {
|
|
@@ -13210,7 +13482,7 @@ async function fetchUsdcFastBurnFee(sourceDomain, destinationDomain, isTestnet)
|
|
|
13210
13482
|
}
|
|
13211
13483
|
// Fetch the fee tiers from the API
|
|
13212
13484
|
const url = buildFastBurnFeeUrl(sourceDomain, destinationDomain, isTestnet);
|
|
13213
|
-
const response = await pollApiGet(url, isFastBurnFeeResponse, DEFAULT_CONFIG$
|
|
13485
|
+
const response = await pollApiGet(url, isFastBurnFeeResponse, DEFAULT_CONFIG$3);
|
|
13214
13486
|
// Validate that we have at least one fee tier
|
|
13215
13487
|
if (response.length === 0) {
|
|
13216
13488
|
throw new KitError({
|
|
@@ -13559,7 +13831,7 @@ async function fetchForwardingFee(sourceDomain, destinationDomain, isTestnet, fi
|
|
|
13559
13831
|
}
|
|
13560
13832
|
// Fetch the fee tiers from the API with forward=true
|
|
13561
13833
|
const url = buildForwardingFeeUrl(sourceDomain, destinationDomain, isTestnet);
|
|
13562
|
-
const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$
|
|
13834
|
+
const response = await pollApiGet(url, isForwardingFeeResponse, DEFAULT_CONFIG$3);
|
|
13563
13835
|
// Validate that we have at least one fee tier
|
|
13564
13836
|
if (response.length === 0) {
|
|
13565
13837
|
throw new KitError({
|
|
@@ -13626,7 +13898,7 @@ const CCTPv2MinFinalityThreshold = {
|
|
|
13626
13898
|
* Default configuration values for the attestation fetcher.
|
|
13627
13899
|
* @internal
|
|
13628
13900
|
*/
|
|
13629
|
-
const DEFAULT_CONFIG$
|
|
13901
|
+
const DEFAULT_CONFIG$2 = {
|
|
13630
13902
|
timeout: 2_000, // 2 seconds
|
|
13631
13903
|
maxRetries: 30 * 20, // 30 * 20 * 2 seconds (from the retry delay) = 20 minutes (to account for slow transfers maximum time based on confirmations)
|
|
13632
13904
|
retryDelay: 2_000, // 2 seconds
|
|
@@ -13797,7 +14069,7 @@ const buildIrisUrl = (sourceDomainId, transactionHash, isTestnet) => {
|
|
|
13797
14069
|
*/
|
|
13798
14070
|
const fetchAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {}) => {
|
|
13799
14071
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
13800
|
-
const effectiveConfig = { ...DEFAULT_CONFIG$
|
|
14072
|
+
const effectiveConfig = { ...DEFAULT_CONFIG$2, ...config };
|
|
13801
14073
|
return await pollApiGet(url, isAttestationResponse, effectiveConfig);
|
|
13802
14074
|
};
|
|
13803
14075
|
/**
|
|
@@ -13843,7 +14115,7 @@ const fetchAttestationWithoutStatusCheck = async (sourceDomainId, transactionHas
|
|
|
13843
14115
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
13844
14116
|
// Use minimal retries since we're just fetching existing data
|
|
13845
14117
|
const effectiveConfig = {
|
|
13846
|
-
...DEFAULT_CONFIG$
|
|
14118
|
+
...DEFAULT_CONFIG$2,
|
|
13847
14119
|
maxRetries: 3,
|
|
13848
14120
|
...config,
|
|
13849
14121
|
};
|
|
@@ -13908,7 +14180,7 @@ const isReAttestedAttestationResponse = (obj) => {
|
|
|
13908
14180
|
*/
|
|
13909
14181
|
const fetchReAttestedAttestation = async (sourceDomainId, transactionHash, isTestnet, config = {}) => {
|
|
13910
14182
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
13911
|
-
const effectiveConfig = { ...DEFAULT_CONFIG$
|
|
14183
|
+
const effectiveConfig = { ...DEFAULT_CONFIG$2, ...config };
|
|
13912
14184
|
return await pollApiGet(url, isReAttestedAttestationResponse, effectiveConfig);
|
|
13913
14185
|
};
|
|
13914
14186
|
/**
|
|
@@ -13983,7 +14255,7 @@ const requestReAttestation = async (nonce, isTestnet, config = {}) => {
|
|
|
13983
14255
|
const url = buildReAttestUrl(nonce, isTestnet);
|
|
13984
14256
|
// Use minimal retries since we're just submitting a request, not polling for state
|
|
13985
14257
|
const effectiveConfig = {
|
|
13986
|
-
...DEFAULT_CONFIG$
|
|
14258
|
+
...DEFAULT_CONFIG$2,
|
|
13987
14259
|
maxRetries: 3,
|
|
13988
14260
|
...config,
|
|
13989
14261
|
};
|
|
@@ -15238,7 +15510,7 @@ const isRelayerMintConfirmed = (obj) => {
|
|
|
15238
15510
|
*/
|
|
15239
15511
|
const fetchRelayerMint = async (sourceDomainId, transactionHash, isTestnet, config = {}) => {
|
|
15240
15512
|
const url = buildIrisUrl(sourceDomainId, transactionHash, isTestnet);
|
|
15241
|
-
const effectiveConfig = { ...DEFAULT_CONFIG$
|
|
15513
|
+
const effectiveConfig = { ...DEFAULT_CONFIG$2, ...config };
|
|
15242
15514
|
let response;
|
|
15243
15515
|
try {
|
|
15244
15516
|
response = await pollApiGet(url, isRelayerMintConfirmed, effectiveConfig);
|
|
@@ -15750,9 +16022,9 @@ async function buildBatchedStep(name, receipt, batchId, adapter, chain, statusCo
|
|
|
15750
16022
|
return step;
|
|
15751
16023
|
}
|
|
15752
16024
|
|
|
15753
|
-
var version$
|
|
15754
|
-
var pkg$
|
|
15755
|
-
version: version$
|
|
16025
|
+
var version$3 = "1.8.2";
|
|
16026
|
+
var pkg$3 = {
|
|
16027
|
+
version: version$3};
|
|
15756
16028
|
|
|
15757
16029
|
/**
|
|
15758
16030
|
* Provider caller component for bridge operations.
|
|
@@ -15760,7 +16032,7 @@ var pkg$2 = {
|
|
|
15760
16032
|
const BRIDGE_CALLER = {
|
|
15761
16033
|
type: 'provider',
|
|
15762
16034
|
name: 'CCTPV2BridgingProvider.bridge',
|
|
15763
|
-
version: pkg$
|
|
16035
|
+
version: pkg$3.version,
|
|
15764
16036
|
};
|
|
15765
16037
|
/**
|
|
15766
16038
|
* Resolve invocation context for bridge operations.
|
|
@@ -16140,7 +16412,7 @@ async function bridgeReAttest({ params, provider, }, burnTxHash) {
|
|
|
16140
16412
|
const RETRY_CALLER = {
|
|
16141
16413
|
type: 'provider',
|
|
16142
16414
|
name: 'CCTPV2BridgingProvider.retry',
|
|
16143
|
-
version: pkg$
|
|
16415
|
+
version: pkg$3.version,
|
|
16144
16416
|
};
|
|
16145
16417
|
/**
|
|
16146
16418
|
* Resolve invocation context for retry operations.
|
|
@@ -17346,7 +17618,7 @@ class CCTPV2BridgingProvider extends BridgingProvider {
|
|
|
17346
17618
|
* The default providers that will be used in addition to the providers provided
|
|
17347
17619
|
* to the BridgeKit constructor.
|
|
17348
17620
|
*/
|
|
17349
|
-
const getDefaultProviders$
|
|
17621
|
+
const getDefaultProviders$3 = () => [new CCTPV2BridgingProvider()];
|
|
17350
17622
|
|
|
17351
17623
|
/**
|
|
17352
17624
|
* A helper function to get a function that transforms an amount into a human-readable string or a bigint string.
|
|
@@ -17354,7 +17626,7 @@ const getDefaultProviders$2 = () => [new CCTPV2BridgingProvider()];
|
|
|
17354
17626
|
* @returns A function that transforms an amount into a human-readable string or a bigint string.
|
|
17355
17627
|
*/
|
|
17356
17628
|
const getAmountTransformer = (formatDirection) => formatDirection === 'to-human-readable'
|
|
17357
|
-
? (params) => formatAmount$
|
|
17629
|
+
? (params) => formatAmount$2(params)
|
|
17358
17630
|
: (params) => parseAmount(params).toString();
|
|
17359
17631
|
/**
|
|
17360
17632
|
* Format the bridge result into human-readable string values for the user or bigint string values for internal use.
|
|
@@ -17444,14 +17716,14 @@ const BRIDGE_STEP_EVENT_MAP = [
|
|
|
17444
17716
|
];
|
|
17445
17717
|
|
|
17446
17718
|
/** SDK name used in telemetry payloads. */
|
|
17447
|
-
const SDK_NAME$2 = resolveKitSdkName(pkg$
|
|
17719
|
+
const SDK_NAME$2 = resolveKitSdkName(pkg$4.name);
|
|
17448
17720
|
/**
|
|
17449
17721
|
* BridgeKit caller component for retry and estimate operations.
|
|
17450
17722
|
*/
|
|
17451
17723
|
const BRIDGE_KIT_CALLER = {
|
|
17452
17724
|
type: 'kit',
|
|
17453
17725
|
name: 'BridgeKit',
|
|
17454
|
-
version: pkg$
|
|
17726
|
+
version: pkg$4.version,
|
|
17455
17727
|
};
|
|
17456
17728
|
/**
|
|
17457
17729
|
* Merge BridgeKit's caller into the invocation metadata for retry operations.
|
|
@@ -17546,13 +17818,13 @@ class BridgeKit {
|
|
|
17546
17818
|
*/
|
|
17547
17819
|
constructor(config = {}) {
|
|
17548
17820
|
// Handle provider configuration
|
|
17549
|
-
const defaultProviders = getDefaultProviders$
|
|
17821
|
+
const defaultProviders = getDefaultProviders$3();
|
|
17550
17822
|
this.providers = [...defaultProviders, ...(config.providers ?? [])];
|
|
17551
17823
|
this.actionDispatcher = new Actionable();
|
|
17552
17824
|
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
17553
17825
|
this.telemetryConfig = {
|
|
17554
17826
|
sdkName: SDK_NAME$2,
|
|
17555
|
-
sdkVersion: pkg$
|
|
17827
|
+
sdkVersion: pkg$4.version,
|
|
17556
17828
|
disabled: this.disableErrorReporting,
|
|
17557
17829
|
};
|
|
17558
17830
|
for (const provider of this.providers) {
|
|
@@ -18081,7 +18353,7 @@ class BridgeKit {
|
|
|
18081
18353
|
* @packageDocumentation
|
|
18082
18354
|
*/
|
|
18083
18355
|
// Auto-register this kit for user agent tracking
|
|
18084
|
-
registerKit(`${pkg$
|
|
18356
|
+
registerKit(`${pkg$4.name}/${pkg$4.version}`);
|
|
18085
18357
|
|
|
18086
18358
|
/**
|
|
18087
18359
|
* Create a BridgeKit instance with optional developer fee configuration.
|
|
@@ -18148,11 +18420,11 @@ const createBridgeKit = (context) => {
|
|
|
18148
18420
|
return kit;
|
|
18149
18421
|
};
|
|
18150
18422
|
|
|
18151
|
-
var name$
|
|
18152
|
-
var version$
|
|
18153
|
-
var pkg$
|
|
18154
|
-
name: name$
|
|
18155
|
-
version: version$
|
|
18423
|
+
var name$2 = "@circle-fin/swap-kit";
|
|
18424
|
+
var version$2 = "1.2.2";
|
|
18425
|
+
var pkg$2 = {
|
|
18426
|
+
name: name$2,
|
|
18427
|
+
version: version$2};
|
|
18156
18428
|
|
|
18157
18429
|
/**
|
|
18158
18430
|
* @packageDocumentation
|
|
@@ -18249,7 +18521,7 @@ const serviceSwapConfigSchema = zod.z.object({
|
|
|
18249
18521
|
* @remarks
|
|
18250
18522
|
* Optionally includes address for developer-controlled adapters.
|
|
18251
18523
|
*/
|
|
18252
|
-
const adapterContextSchema$
|
|
18524
|
+
const adapterContextSchema$6 = zod.z.object({
|
|
18253
18525
|
adapter: adapterSchema$1,
|
|
18254
18526
|
chain: chainIdentifierSchema,
|
|
18255
18527
|
address: zod.z.string().optional(),
|
|
@@ -18271,7 +18543,7 @@ const adapterContextSchema$5 = zod.z.object({
|
|
|
18271
18543
|
* ```
|
|
18272
18544
|
*/
|
|
18273
18545
|
const serviceSwapParamsSchema = zod.z.object({
|
|
18274
|
-
from: adapterContextSchema$
|
|
18546
|
+
from: adapterContextSchema$6,
|
|
18275
18547
|
tokenIn: zod.z
|
|
18276
18548
|
.string({
|
|
18277
18549
|
required_error: 'tokenIn is required',
|
|
@@ -18486,7 +18758,7 @@ const validateServiceSwapParams = (params) => {
|
|
|
18486
18758
|
*
|
|
18487
18759
|
* @internal
|
|
18488
18760
|
*/
|
|
18489
|
-
const DEFAULT_CONFIG = {
|
|
18761
|
+
const DEFAULT_CONFIG$1 = {
|
|
18490
18762
|
timeout: 30_000, // 30 seconds - matches load balancer timeout
|
|
18491
18763
|
maxRetries: 3, // 3 retries as per requirements
|
|
18492
18764
|
retryDelay: 200, // 200ms between retries
|
|
@@ -19151,6 +19423,46 @@ const parseCreateSwapResponse = (obj) => createSwapResponseSchema.parse(obj);
|
|
|
19151
19423
|
* ```
|
|
19152
19424
|
*/
|
|
19153
19425
|
const isGetSwapStatusResponse = (obj) => getSwapStatusResponseSchema.safeParse(obj).success;
|
|
19426
|
+
/**
|
|
19427
|
+
* Validates that an API key is properly formatted for Circle Stablecoin Service.
|
|
19428
|
+
*
|
|
19429
|
+
* This function performs validation on API keys to ensure they conform to the
|
|
19430
|
+
* expected format before making API requests. The key must follow the structure:
|
|
19431
|
+
* `KIT_KEY:keyId:keySecret`
|
|
19432
|
+
*
|
|
19433
|
+
* @param apiKey - The API key to validate (can be any type for graceful handling).
|
|
19434
|
+
* @returns True if the API key is valid, false otherwise.
|
|
19435
|
+
*
|
|
19436
|
+
* @remarks
|
|
19437
|
+
* This function handles invalid inputs gracefully by returning false rather than
|
|
19438
|
+
* throwing errors. It validates:
|
|
19439
|
+
* - The key starts with the `KIT_KEY:` prefix
|
|
19440
|
+
* - Contains exactly three colon-separated parts
|
|
19441
|
+
* - keyId and keySecret contain only valid characters (alphanumeric, `-`, `_`, `.`)
|
|
19442
|
+
* - keyId and keySecret are non-empty
|
|
19443
|
+
* - No whitespace anywhere in the API key (including leading, trailing, or internal)
|
|
19444
|
+
*
|
|
19445
|
+
* Valid characters in keyId and keySecret: `a-z`, `A-Z`, `0-9`, `-`, `_`, `.`
|
|
19446
|
+
*
|
|
19447
|
+
* @example
|
|
19448
|
+
* ```typescript
|
|
19449
|
+
* import { isValidApiKey } from '@core/service-client'
|
|
19450
|
+
*
|
|
19451
|
+
* // Valid API key
|
|
19452
|
+
* const isValid = isValidApiKey('KIT_KEY:e84d2546d4e321b2ff427dc988c89503:f84d2548d4e322b2ff427fc989c87503')
|
|
19453
|
+
* console.log(isValid) // true
|
|
19454
|
+
*
|
|
19455
|
+
* ```
|
|
19456
|
+
*/
|
|
19457
|
+
const isValidApiKey = (apiKey) => {
|
|
19458
|
+
// Handle invalid input types
|
|
19459
|
+
if (typeof apiKey !== 'string') {
|
|
19460
|
+
return false;
|
|
19461
|
+
}
|
|
19462
|
+
const apiKeyPattern = /^KIT_KEY:[a-zA-Z0-9._-]+:[a-zA-Z0-9._-]+$/;
|
|
19463
|
+
// Validate without trimming - any whitespace will cause validation to fail
|
|
19464
|
+
return apiKeyPattern.test(apiKey);
|
|
19465
|
+
};
|
|
19154
19466
|
|
|
19155
19467
|
/**
|
|
19156
19468
|
* @packageDocumentation
|
|
@@ -19221,9 +19533,9 @@ const createSwap = async (params) => {
|
|
|
19221
19533
|
// Remove the API key from the request body
|
|
19222
19534
|
const { apiKey, ...requestBody } = validatedParams;
|
|
19223
19535
|
const effectiveConfig = {
|
|
19224
|
-
...DEFAULT_CONFIG,
|
|
19536
|
+
...DEFAULT_CONFIG$1,
|
|
19225
19537
|
headers: {
|
|
19226
|
-
...DEFAULT_CONFIG.headers,
|
|
19538
|
+
...DEFAULT_CONFIG$1.headers,
|
|
19227
19539
|
Authorization: `Bearer ${apiKey}`,
|
|
19228
19540
|
},
|
|
19229
19541
|
};
|
|
@@ -19376,9 +19688,9 @@ const getQuote = async (params) => {
|
|
|
19376
19688
|
const url = buildQuoteUrl(validatedParams);
|
|
19377
19689
|
// Merge default config with Authorization header
|
|
19378
19690
|
const effectiveConfig = {
|
|
19379
|
-
...DEFAULT_CONFIG,
|
|
19691
|
+
...DEFAULT_CONFIG$1,
|
|
19380
19692
|
headers: {
|
|
19381
|
-
...DEFAULT_CONFIG.headers,
|
|
19693
|
+
...DEFAULT_CONFIG$1.headers,
|
|
19382
19694
|
Authorization: `Bearer ${validatedParams.apiKey}`,
|
|
19383
19695
|
},
|
|
19384
19696
|
};
|
|
@@ -19431,9 +19743,9 @@ const getSwapStatus = async (params) => {
|
|
|
19431
19743
|
}
|
|
19432
19744
|
const url = buildSwapStatusUrl(result.data);
|
|
19433
19745
|
const effectiveConfig = {
|
|
19434
|
-
...DEFAULT_CONFIG,
|
|
19746
|
+
...DEFAULT_CONFIG$1,
|
|
19435
19747
|
headers: {
|
|
19436
|
-
...DEFAULT_CONFIG.headers,
|
|
19748
|
+
...DEFAULT_CONFIG$1.headers,
|
|
19437
19749
|
Authorization: `Bearer ${result.data.apiKey}`,
|
|
19438
19750
|
},
|
|
19439
19751
|
};
|
|
@@ -22308,6 +22620,27 @@ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
|
22308
22620
|
*/
|
|
22309
22621
|
const NATIVE_TOKEN_ADDRESS$1 = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
22310
22622
|
|
|
22623
|
+
const hexBytesSchema$1 = zod.z
|
|
22624
|
+
.string()
|
|
22625
|
+
.regex(/^0x([0-9a-fA-F]{2})*$/, {
|
|
22626
|
+
message: 'value must be a 0x-prefixed even-length hex string',
|
|
22627
|
+
})
|
|
22628
|
+
.transform((value) => value);
|
|
22629
|
+
zod.z
|
|
22630
|
+
.object({
|
|
22631
|
+
executeParams: zod.z.object({}).passthrough(),
|
|
22632
|
+
signature: evmSignatureSchema,
|
|
22633
|
+
tokenInputs: zod.z.array(zod.z.object({
|
|
22634
|
+
permitType: zod.z.nativeEnum(PermitType),
|
|
22635
|
+
token: evmAddressSchema,
|
|
22636
|
+
amount: zod.z.bigint().refine((value) => value >= 0n, {
|
|
22637
|
+
message: 'amount must be a non-negative bigint',
|
|
22638
|
+
}),
|
|
22639
|
+
permitCalldata: hexBytesSchema$1,
|
|
22640
|
+
})),
|
|
22641
|
+
})
|
|
22642
|
+
.passthrough();
|
|
22643
|
+
|
|
22311
22644
|
/**
|
|
22312
22645
|
* Solana mainnet genesis hash
|
|
22313
22646
|
*/
|
|
@@ -24518,21 +24851,21 @@ function buildInsufficientSwapBalanceError(tokenSymbol, walletAddress, currentBa
|
|
|
24518
24851
|
const displaySymbol = resolvedSymbol ?? tokenSymbol;
|
|
24519
24852
|
// Format human-readable amounts if we can resolve the token, otherwise use base units only
|
|
24520
24853
|
const currentFormatted = canFormat
|
|
24521
|
-
? formatAmount$
|
|
24854
|
+
? formatAmount$2({
|
|
24522
24855
|
value: currentBalance.toString(),
|
|
24523
24856
|
token: resolvedSymbol,
|
|
24524
24857
|
chain,
|
|
24525
24858
|
})
|
|
24526
24859
|
: null;
|
|
24527
24860
|
const requiredFormatted = canFormat
|
|
24528
|
-
? formatAmount$
|
|
24861
|
+
? formatAmount$2({
|
|
24529
24862
|
value: requiredAmount.toString(),
|
|
24530
24863
|
token: resolvedSymbol,
|
|
24531
24864
|
chain,
|
|
24532
24865
|
})
|
|
24533
24866
|
: null;
|
|
24534
24867
|
const shortfallFormatted = canFormat
|
|
24535
|
-
? formatAmount$
|
|
24868
|
+
? formatAmount$2({
|
|
24536
24869
|
value: shortfall.toString(),
|
|
24537
24870
|
token: resolvedSymbol,
|
|
24538
24871
|
chain,
|
|
@@ -24618,7 +24951,7 @@ async function formatTokenValue(value, token, chain, adapter) {
|
|
|
24618
24951
|
if (resolvedSymbol) {
|
|
24619
24952
|
if (isSwapToken(resolvedSymbol)) {
|
|
24620
24953
|
return {
|
|
24621
|
-
amount: formatAmount$
|
|
24954
|
+
amount: formatAmount$2({
|
|
24622
24955
|
value,
|
|
24623
24956
|
token: resolvedSymbol,
|
|
24624
24957
|
chain,
|
|
@@ -24659,7 +24992,7 @@ async function formatTokenValue(value, token, chain, adapter) {
|
|
|
24659
24992
|
* i.e. 1 + 0.2 + 0.1 = 1.3. Use the greater of (local estimate × this multiplier)
|
|
24660
24993
|
* or the proxy's gasLimit.
|
|
24661
24994
|
*/
|
|
24662
|
-
const GAS_SAFETY_MULTIPLIER = 1.3;
|
|
24995
|
+
const GAS_SAFETY_MULTIPLIER$1 = 1.3;
|
|
24663
24996
|
const TOKEN_REGISTRY = createTokenRegistry();
|
|
24664
24997
|
/**
|
|
24665
24998
|
* Enhances a KitError with transaction details (txHash and explorerUrl).
|
|
@@ -25092,7 +25425,7 @@ class StablecoinServiceSwapProvider {
|
|
|
25092
25425
|
const gasEstimate = await params.from.adapter.calculateTransactionFee(gasLimitUnits, undefined, // Use default 5% buffer
|
|
25093
25426
|
chain);
|
|
25094
25427
|
// Format the fee from wei to human-readable native currency amount
|
|
25095
|
-
estimatedGasFee = formatAmount$
|
|
25428
|
+
estimatedGasFee = formatAmount$2({
|
|
25096
25429
|
value: gasEstimate.fee,
|
|
25097
25430
|
token: 'NATIVE',
|
|
25098
25431
|
chain,
|
|
@@ -25105,7 +25438,7 @@ class StablecoinServiceSwapProvider {
|
|
|
25105
25438
|
const gasEstimate = await params.from.adapter.calculateTransactionFee(300000n, undefined, // Use default buffer
|
|
25106
25439
|
chain);
|
|
25107
25440
|
// Format the fee from lamports to human-readable SOL amount
|
|
25108
|
-
estimatedGasFee = formatAmount$
|
|
25441
|
+
estimatedGasFee = formatAmount$2({
|
|
25109
25442
|
value: gasEstimate.fee,
|
|
25110
25443
|
token: 'NATIVE',
|
|
25111
25444
|
chain,
|
|
@@ -25639,7 +25972,7 @@ class StablecoinServiceSwapProvider {
|
|
|
25639
25972
|
const localEstimate = await preparedAction.estimate();
|
|
25640
25973
|
const localGas = Number(localEstimate?.gas);
|
|
25641
25974
|
if (Number.isFinite(localGas) && localGas > 0) {
|
|
25642
|
-
const localWithBuffer = Math.ceil(localGas * GAS_SAFETY_MULTIPLIER);
|
|
25975
|
+
const localWithBuffer = Math.ceil(localGas * GAS_SAFETY_MULTIPLIER$1);
|
|
25643
25976
|
if (Number.isFinite(localWithBuffer) && localWithBuffer > 0) {
|
|
25644
25977
|
effectiveGasLimit = Math.max(localWithBuffer, proxyGasLimit);
|
|
25645
25978
|
}
|
|
@@ -25735,7 +26068,7 @@ class StablecoinServiceSwapProvider {
|
|
|
25735
26068
|
* Must always contain both adapter and chain explicitly.
|
|
25736
26069
|
* Optionally includes address for developer-controlled adapters.
|
|
25737
26070
|
*/
|
|
25738
|
-
const adapterContextSchema$
|
|
26071
|
+
const adapterContextSchema$5 = zod.z.object({
|
|
25739
26072
|
adapter: adapterSchema$1,
|
|
25740
26073
|
chain: swapChainIdentifierSchema,
|
|
25741
26074
|
address: zod.z.string().optional(),
|
|
@@ -25951,7 +26284,7 @@ const amountInSchema = zod.z
|
|
|
25951
26284
|
* ```
|
|
25952
26285
|
*/
|
|
25953
26286
|
const swapParamsSchema = zod.z.object({
|
|
25954
|
-
from: adapterContextSchema$
|
|
26287
|
+
from: adapterContextSchema$5,
|
|
25955
26288
|
tokenIn: swapTokenSchema,
|
|
25956
26289
|
tokenOut: swapTokenSchema,
|
|
25957
26290
|
amountIn: amountInSchema,
|
|
@@ -28482,7 +28815,7 @@ async function swap$1(context, params) {
|
|
|
28482
28815
|
* )
|
|
28483
28816
|
* ```
|
|
28484
28817
|
*/
|
|
28485
|
-
function getSupportedChains$
|
|
28818
|
+
function getSupportedChains$4(context) {
|
|
28486
28819
|
const swapChains = new Set(Object.values(exports.SwapChain));
|
|
28487
28820
|
// Collect all supported chains from all providers
|
|
28488
28821
|
// Use optional chaining to gracefully handle providers without supportedChains
|
|
@@ -28669,7 +29002,7 @@ function removeCustomFeePolicy(context) {
|
|
|
28669
29002
|
* @returns An array containing the default StablecoinServiceSwapProvider
|
|
28670
29003
|
* @internal
|
|
28671
29004
|
*/
|
|
28672
|
-
const getDefaultProviders$
|
|
29005
|
+
const getDefaultProviders$2 = () => [new StablecoinServiceSwapProvider()];
|
|
28673
29006
|
/**
|
|
28674
29007
|
* Create a SwapKit context with validated configuration.
|
|
28675
29008
|
*
|
|
@@ -28729,7 +29062,7 @@ const getDefaultProviders$1 = () => [new StablecoinServiceSwapProvider()];
|
|
|
28729
29062
|
*/
|
|
28730
29063
|
function createSwapKitContext(config = {}) {
|
|
28731
29064
|
// Initialize default providers
|
|
28732
|
-
const defaultProviders = getDefaultProviders$
|
|
29065
|
+
const defaultProviders = getDefaultProviders$2();
|
|
28733
29066
|
// Merge default and custom providers
|
|
28734
29067
|
const providers = [...defaultProviders, ...(config.providers ?? [])];
|
|
28735
29068
|
// Build base context without fee policy
|
|
@@ -28757,7 +29090,7 @@ const SWAP_EVENT_TYPES = {
|
|
|
28757
29090
|
};
|
|
28758
29091
|
|
|
28759
29092
|
/** SDK name used in telemetry payloads. */
|
|
28760
|
-
const SDK_NAME$1 = resolveKitSdkName(pkg$
|
|
29093
|
+
const SDK_NAME$1 = resolveKitSdkName(pkg$2.name);
|
|
28761
29094
|
/**
|
|
28762
29095
|
* A high-level class-based interface for single-chain token swap operations.
|
|
28763
29096
|
*
|
|
@@ -28884,7 +29217,7 @@ class SwapKit {
|
|
|
28884
29217
|
this.disableErrorReporting = config.disableErrorReporting === true;
|
|
28885
29218
|
this.telemetryConfig = {
|
|
28886
29219
|
sdkName: SDK_NAME$1,
|
|
28887
|
-
sdkVersion: pkg$
|
|
29220
|
+
sdkVersion: pkg$2.version,
|
|
28888
29221
|
disabled: this.disableErrorReporting,
|
|
28889
29222
|
};
|
|
28890
29223
|
}
|
|
@@ -29028,7 +29361,7 @@ class SwapKit {
|
|
|
29028
29361
|
* ```
|
|
29029
29362
|
*/
|
|
29030
29363
|
getSupportedChains() {
|
|
29031
|
-
return getSupportedChains$
|
|
29364
|
+
return getSupportedChains$4(this.context);
|
|
29032
29365
|
}
|
|
29033
29366
|
/**
|
|
29034
29367
|
* Set a custom fee policy for all swap operations.
|
|
@@ -29152,7 +29485,7 @@ class SwapKit {
|
|
|
29152
29485
|
* @packageDocumentation
|
|
29153
29486
|
*/
|
|
29154
29487
|
// Auto-register this kit for user agent tracking
|
|
29155
|
-
registerKit(`${pkg$
|
|
29488
|
+
registerKit(`${pkg$2.name}/${pkg$2.version}`);
|
|
29156
29489
|
|
|
29157
29490
|
/**
|
|
29158
29491
|
* Create a SwapKit instance with optional developer fee configuration.
|
|
@@ -29250,288 +29583,3138 @@ const createSwapKit = (context) => {
|
|
|
29250
29583
|
return kit;
|
|
29251
29584
|
};
|
|
29252
29585
|
|
|
29586
|
+
var name$1 = "@circle-fin/earn-kit";
|
|
29587
|
+
var version$1 = "1.0.0";
|
|
29588
|
+
var pkg$1 = {
|
|
29589
|
+
name: name$1,
|
|
29590
|
+
version: version$1};
|
|
29591
|
+
|
|
29253
29592
|
/**
|
|
29254
|
-
*
|
|
29255
|
-
*
|
|
29256
|
-
* This utility function registers event handlers stored in a context actions map
|
|
29257
|
-
* with a kit instance that supports event handling via an `on` method. It handles
|
|
29258
|
-
* wildcard handlers ('*') and prefixed action handlers, stripping the prefix
|
|
29259
|
-
* before registration.
|
|
29593
|
+
* Default base URL for the Earn Service API.
|
|
29260
29594
|
*
|
|
29261
|
-
*
|
|
29262
|
-
|
|
29263
|
-
|
|
29264
|
-
|
|
29265
|
-
*
|
|
29266
|
-
* @param prefix - Optional prefix to strip from action names (e.g., 'bridge.')
|
|
29595
|
+
* @internal
|
|
29596
|
+
*/
|
|
29597
|
+
const EARN_SERVICE_BASE_URL = 'https://api.circle.com';
|
|
29598
|
+
/**
|
|
29599
|
+
* API path prefix for all EarnKit endpoints.
|
|
29267
29600
|
*
|
|
29268
|
-
* @
|
|
29269
|
-
|
|
29270
|
-
|
|
29271
|
-
|
|
29601
|
+
* @internal
|
|
29602
|
+
*/
|
|
29603
|
+
const EARN_KIT_API_PREFIX = '/v1/earnKit';
|
|
29604
|
+
/**
|
|
29605
|
+
* Map SDK chain identifiers to Zenith API chain strings.
|
|
29272
29606
|
*
|
|
29273
|
-
*
|
|
29274
|
-
*
|
|
29275
|
-
*
|
|
29276
|
-
*
|
|
29277
|
-
* 'bridge.burn': [(payload) => console.log('Burned:', payload)],
|
|
29278
|
-
* }
|
|
29607
|
+
* The Zenith backend uses short-form blockchain identifiers (e.g., 'ARC-TESTNET')
|
|
29608
|
+
* while the SDK uses the {@link Blockchain} enum (e.g., 'Arc_Testnet').
|
|
29609
|
+
* Adding a new {@link EarnSupportedBlockchain} without a corresponding
|
|
29610
|
+
* entry here produces a compile error.
|
|
29279
29611
|
*
|
|
29280
|
-
*
|
|
29281
|
-
|
|
29612
|
+
* @internal
|
|
29613
|
+
*/
|
|
29614
|
+
const CHAIN_TO_API = {
|
|
29615
|
+
[exports.Blockchain.Arc_Testnet]: 'ARC-TESTNET',
|
|
29616
|
+
};
|
|
29617
|
+
/**
|
|
29618
|
+
* Display symbol for vault share tokens.
|
|
29282
29619
|
*
|
|
29283
|
-
* @
|
|
29284
|
-
|
|
29285
|
-
|
|
29286
|
-
|
|
29620
|
+
* @internal
|
|
29621
|
+
*/
|
|
29622
|
+
const VAULT_SHARE_SYMBOL = 'shares';
|
|
29623
|
+
/**
|
|
29624
|
+
* Default polling configuration for Earn Service API calls.
|
|
29287
29625
|
*
|
|
29288
|
-
*
|
|
29289
|
-
*
|
|
29290
|
-
* 'swap.initiate': [(payload) => console.log('Swap initiated:', payload)],
|
|
29291
|
-
* }
|
|
29626
|
+
* Match the load-balancer timeout (30 s) with retry settings consistent
|
|
29627
|
+
* with `@core/service-client` defaults.
|
|
29292
29628
|
*
|
|
29293
|
-
*
|
|
29294
|
-
* ```
|
|
29629
|
+
* @internal
|
|
29295
29630
|
*/
|
|
29296
|
-
const
|
|
29297
|
-
|
|
29298
|
-
|
|
29299
|
-
|
|
29300
|
-
|
|
29301
|
-
|
|
29302
|
-
|
|
29303
|
-
}
|
|
29304
|
-
else if (prefix && action.startsWith(prefix)) {
|
|
29305
|
-
// Remove prefix to get the actual kit action name
|
|
29306
|
-
const kitAction = action.split('.').at(1);
|
|
29307
|
-
if (kitAction) {
|
|
29308
|
-
kit.on(kitAction, handler);
|
|
29309
|
-
}
|
|
29310
|
-
}
|
|
29311
|
-
else if (!prefix) {
|
|
29312
|
-
// No prefix configured, register action as-is
|
|
29313
|
-
kit.on(action, handler);
|
|
29314
|
-
}
|
|
29315
|
-
// Actions that don't match the prefix are silently ignored
|
|
29316
|
-
}
|
|
29317
|
-
}
|
|
29631
|
+
const DEFAULT_CONFIG = {
|
|
29632
|
+
timeout: 30_000,
|
|
29633
|
+
maxRetries: 3,
|
|
29634
|
+
retryDelay: 200,
|
|
29635
|
+
headers: {
|
|
29636
|
+
'Content-Type': 'application/json',
|
|
29637
|
+
},
|
|
29318
29638
|
};
|
|
29319
29639
|
|
|
29640
|
+
const API_TO_CHAIN = Object.fromEntries(Object.entries(CHAIN_TO_API).map(([sdkChain, apiChain]) => [
|
|
29641
|
+
apiChain,
|
|
29642
|
+
sdkChain,
|
|
29643
|
+
]));
|
|
29644
|
+
function toApiChain(chain) {
|
|
29645
|
+
if (!Object.hasOwn(CHAIN_TO_API, chain)) {
|
|
29646
|
+
return undefined;
|
|
29647
|
+
}
|
|
29648
|
+
return CHAIN_TO_API[chain];
|
|
29649
|
+
}
|
|
29650
|
+
function toSdkChain(chain) {
|
|
29651
|
+
if (Object.hasOwn(CHAIN_TO_API, chain)) {
|
|
29652
|
+
return chain;
|
|
29653
|
+
}
|
|
29654
|
+
if (!Object.hasOwn(API_TO_CHAIN, chain)) {
|
|
29655
|
+
return undefined;
|
|
29656
|
+
}
|
|
29657
|
+
return API_TO_CHAIN[chain];
|
|
29658
|
+
}
|
|
29659
|
+
|
|
29320
29660
|
/**
|
|
29321
|
-
*
|
|
29661
|
+
* Extract address and chain string from an adapter context.
|
|
29322
29662
|
*
|
|
29323
|
-
*
|
|
29324
|
-
*
|
|
29663
|
+
* Handle both user-controlled adapters (address resolved via
|
|
29664
|
+
* `adapter.getAddress()`) and developer-controlled adapters
|
|
29665
|
+
* (address provided explicitly in the context).
|
|
29325
29666
|
*
|
|
29326
|
-
* @
|
|
29327
|
-
*
|
|
29328
|
-
*
|
|
29667
|
+
* @param from - Adapter context containing adapter, chain, and optional address
|
|
29668
|
+
* @returns Resolved wallet address, API chain string, and chain definition
|
|
29669
|
+
* @throws {@link KitError} If the chain is unsupported by the Earn Service provider.
|
|
29670
|
+
* @throws Propagates errors from `adapter.getAddress(chain)` when
|
|
29671
|
+
* `from.address` is not supplied.
|
|
29329
29672
|
*
|
|
29330
|
-
*
|
|
29331
|
-
*
|
|
29673
|
+
* @example
|
|
29674
|
+
* ```typescript
|
|
29675
|
+
* const { address, chain, chainDefinition } =
|
|
29676
|
+
* await resolveAdapterContext(params.from)
|
|
29677
|
+
* ```
|
|
29678
|
+
*
|
|
29679
|
+
* @internal
|
|
29332
29680
|
*/
|
|
29333
|
-
|
|
29681
|
+
async function resolveAdapterContext(from) {
|
|
29682
|
+
const chainDef = resolveChainIdentifier(from.chain);
|
|
29683
|
+
const apiChain = toApiChain(chainDef.chain);
|
|
29684
|
+
if (apiChain === undefined) {
|
|
29685
|
+
throw createInvalidChainError(chainDef.chain, 'Chain is not supported by the Earn Service provider');
|
|
29686
|
+
}
|
|
29687
|
+
const hasAddress = 'address' in from &&
|
|
29688
|
+
typeof from.address === 'string' &&
|
|
29689
|
+
from.address.length > 0;
|
|
29690
|
+
const address = hasAddress
|
|
29691
|
+
? from.address
|
|
29692
|
+
: await from.adapter.getAddress(chainDef);
|
|
29693
|
+
return { address, chain: apiChain, chainDefinition: chainDef };
|
|
29694
|
+
}
|
|
29695
|
+
|
|
29334
29696
|
/**
|
|
29335
|
-
*
|
|
29336
|
-
*
|
|
29337
|
-
* This function performs case-sensitive matching against the list of known
|
|
29338
|
-
* token aliases. Known aliases take precedence over custom addresses in the
|
|
29339
|
-
* send operation logic.
|
|
29697
|
+
* Assert that a value is a 0x-prefixed 20-byte hex address.
|
|
29340
29698
|
*
|
|
29341
|
-
* @param
|
|
29342
|
-
* @
|
|
29699
|
+
* @param field - Name of the field being validated.
|
|
29700
|
+
* @param value - Runtime value to validate.
|
|
29701
|
+
* @param message - Optional message describing the expected address.
|
|
29702
|
+
* @returns The validated value narrowed to a 0x-prefixed string.
|
|
29703
|
+
* @throws {@link KitError} If the value is not an EVM address.
|
|
29343
29704
|
*
|
|
29344
29705
|
* @example
|
|
29345
29706
|
* ```typescript
|
|
29346
|
-
*
|
|
29347
|
-
*
|
|
29348
|
-
*
|
|
29349
|
-
*
|
|
29350
|
-
* console.log(isTokenAlias('0x6B175474E89094C44Da98b954EedeAC495271d0F')) // false
|
|
29707
|
+
* const token = assertHexAddress(
|
|
29708
|
+
* 'chain.usdcAddress',
|
|
29709
|
+
* '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
29710
|
+
* )
|
|
29351
29711
|
* ```
|
|
29712
|
+
*
|
|
29713
|
+
* @internal
|
|
29352
29714
|
*/
|
|
29353
|
-
function
|
|
29354
|
-
|
|
29715
|
+
function assertHexAddress(field, value, message = `${field} must be a 0x-prefixed 20-byte hex address`) {
|
|
29716
|
+
const result = evmAddressSchema.safeParse(value);
|
|
29717
|
+
if (!result.success) {
|
|
29718
|
+
throw createValidationFailedError$1(field, value, message);
|
|
29719
|
+
}
|
|
29720
|
+
return result.data;
|
|
29355
29721
|
}
|
|
29722
|
+
|
|
29356
29723
|
/**
|
|
29357
|
-
*
|
|
29358
|
-
*
|
|
29359
|
-
*
|
|
29360
|
-
* 1. Not a known alias ('USDC', 'USDT', 'NATIVE')
|
|
29361
|
-
* 2. A valid address format for the specified chain
|
|
29362
|
-
*
|
|
29363
|
-
* Use this to narrow the type to `TokenAddress` in TypeScript.
|
|
29724
|
+
* Return the adapter contract address configured for the chain, or throw a
|
|
29725
|
+
* fatal KitError if unavailable. Earn operations require an adapter contract
|
|
29726
|
+
* to forward service-signed payloads.
|
|
29364
29727
|
*
|
|
29365
|
-
* @param
|
|
29366
|
-
* @
|
|
29367
|
-
* @
|
|
29728
|
+
* @param chain - Resolved chain definition.
|
|
29729
|
+
* @returns Adapter contract address as a 0x-prefixed hex string.
|
|
29730
|
+
* @throws {@link KitError} If `chain.kitContracts.adapter` is undefined.
|
|
29731
|
+
* @throws {@link KitError} If `chain.kitContracts.adapter` is malformed.
|
|
29368
29732
|
*
|
|
29369
29733
|
* @example
|
|
29370
29734
|
* ```typescript
|
|
29371
|
-
*
|
|
29372
|
-
* import { Ethereum } from '@core/chains'
|
|
29373
|
-
*
|
|
29374
|
-
* const daiAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
|
|
29375
|
-
* if (isTokenAddress(daiAddress, Ethereum)) {
|
|
29376
|
-
* // TypeScript knows daiAddress is TokenAddress here
|
|
29377
|
-
* console.log('Valid token address:', daiAddress)
|
|
29378
|
-
* }
|
|
29379
|
-
*
|
|
29380
|
-
* console.log(isTokenAddress('USDC', Ethereum)) // false - it's an alias
|
|
29381
|
-
* console.log(isTokenAddress('invalid', Ethereum)) // false - invalid format
|
|
29735
|
+
* const adapterContract = requireAdapterContract(chain)
|
|
29382
29736
|
* ```
|
|
29737
|
+
*
|
|
29738
|
+
* @internal
|
|
29383
29739
|
*/
|
|
29384
|
-
function
|
|
29385
|
-
|
|
29740
|
+
function requireAdapterContract(chain) {
|
|
29741
|
+
const adapterContractAddress = chain.kitContracts?.adapter;
|
|
29742
|
+
if (adapterContractAddress === undefined) {
|
|
29743
|
+
throw createValidationFailedError$1('chain.kitContracts.adapter', adapterContractAddress, `Adapter contract not configured for chain ${chain.name}. Earn operations require an adapter contract.`);
|
|
29744
|
+
}
|
|
29745
|
+
return assertHexAddress('chain.kitContracts.adapter', adapterContractAddress, `Adapter contract for chain ${chain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
29386
29746
|
}
|
|
29747
|
+
|
|
29387
29748
|
/**
|
|
29388
|
-
*
|
|
29389
|
-
*
|
|
29390
|
-
* This function determines whether a token string is:
|
|
29391
|
-
* 1. A known alias ('USDC', 'USDT', or 'NATIVE')
|
|
29392
|
-
* 2. A valid token address for the given chain
|
|
29393
|
-
* 3. An invalid/unrecognized token identifier
|
|
29749
|
+
* Safety multiplier applied to locally estimated gas for earn transactions.
|
|
29394
29750
|
*
|
|
29395
|
-
*
|
|
29396
|
-
*
|
|
29751
|
+
* Earn transactions can include nested vault and token contract calls.
|
|
29752
|
+
* Local gas estimation has undercounted those execution paths in production.
|
|
29753
|
+
* A 1.3x buffer matching swap-kit reduces out-of-gas risk while preserving
|
|
29754
|
+
* the adapter fallback path when local estimation fails.
|
|
29397
29755
|
*
|
|
29398
|
-
* @
|
|
29399
|
-
|
|
29400
|
-
|
|
29756
|
+
* @internal
|
|
29757
|
+
*/
|
|
29758
|
+
const GAS_SAFETY_MULTIPLIER = 1.3;
|
|
29759
|
+
/**
|
|
29760
|
+
* Estimate gas for a prepared chain request and apply {@link GAS_SAFETY_MULTIPLIER}.
|
|
29401
29761
|
*
|
|
29402
|
-
*
|
|
29403
|
-
*
|
|
29404
|
-
*
|
|
29405
|
-
* import { Ethereum } from '@core/chains'
|
|
29762
|
+
* Returns the buffered gas limit, or `undefined` if estimation fails or
|
|
29763
|
+
* produces an invalid value. Callers should fall through to the adapter's
|
|
29764
|
+
* default gas handling when `undefined` is returned.
|
|
29406
29765
|
*
|
|
29407
|
-
*
|
|
29408
|
-
|
|
29409
|
-
|
|
29766
|
+
* @internal
|
|
29767
|
+
*/
|
|
29768
|
+
async function estimateBufferedGasLimit(prepared) {
|
|
29769
|
+
try {
|
|
29770
|
+
const estimate = await prepared.estimate();
|
|
29771
|
+
const estimatedGas = Number(estimate.gas);
|
|
29772
|
+
if (Number.isFinite(estimatedGas) && estimatedGas > 0) {
|
|
29773
|
+
const buffered = Math.ceil(estimatedGas * GAS_SAFETY_MULTIPLIER);
|
|
29774
|
+
if (Number.isFinite(buffered) && buffered > 0) {
|
|
29775
|
+
return buffered;
|
|
29776
|
+
}
|
|
29777
|
+
}
|
|
29778
|
+
}
|
|
29779
|
+
catch {
|
|
29780
|
+
// If estimation fails, fall through and let the adapter handle gas internally
|
|
29781
|
+
}
|
|
29782
|
+
return undefined;
|
|
29783
|
+
}
|
|
29784
|
+
|
|
29785
|
+
/**
|
|
29786
|
+
* Maximum `uint256` value. The approval amount used when this helper needs
|
|
29787
|
+
* to send a token approval.
|
|
29410
29788
|
*
|
|
29411
|
-
*
|
|
29412
|
-
|
|
29413
|
-
|
|
29789
|
+
* @internal
|
|
29790
|
+
*/
|
|
29791
|
+
const MAX_UINT256$1 = 2n ** 256n - 1n;
|
|
29792
|
+
/**
|
|
29793
|
+
* Allowance threshold above which a prior max-approve is assumed to still
|
|
29794
|
+
* cover any earn operation. Detects prior max-approvals even when the token
|
|
29795
|
+
* decrements allowance on `transferFrom`, since that decay is negligible
|
|
29796
|
+
* relative to 2^255.
|
|
29414
29797
|
*
|
|
29415
|
-
*
|
|
29416
|
-
* const invalid = validateToken('invalid', Ethereum)
|
|
29417
|
-
* console.log(invalid) // { isAlias: false, isAddress: false, isValid: false }
|
|
29418
|
-
* ```
|
|
29798
|
+
* @internal
|
|
29419
29799
|
*/
|
|
29420
|
-
|
|
29421
|
-
|
|
29422
|
-
|
|
29423
|
-
|
|
29424
|
-
return {
|
|
29425
|
-
isAlias: true,
|
|
29426
|
-
isAddress: false,
|
|
29427
|
-
isValid: true,
|
|
29428
|
-
};
|
|
29800
|
+
const ALLOWANCE_THRESHOLD = MAX_UINT256$1 / 2n;
|
|
29801
|
+
function parseAllowanceResponse(allowanceRaw) {
|
|
29802
|
+
if (allowanceRaw === undefined || allowanceRaw === null) {
|
|
29803
|
+
return 0n;
|
|
29429
29804
|
}
|
|
29430
|
-
|
|
29431
|
-
|
|
29432
|
-
|
|
29433
|
-
|
|
29434
|
-
|
|
29435
|
-
|
|
29436
|
-
|
|
29805
|
+
let allowance;
|
|
29806
|
+
if (typeof allowanceRaw === 'bigint') {
|
|
29807
|
+
allowance = allowanceRaw;
|
|
29808
|
+
}
|
|
29809
|
+
else if (typeof allowanceRaw === 'string') {
|
|
29810
|
+
try {
|
|
29811
|
+
allowance = BigInt(allowanceRaw);
|
|
29812
|
+
}
|
|
29813
|
+
catch {
|
|
29814
|
+
allowance = undefined;
|
|
29815
|
+
}
|
|
29816
|
+
}
|
|
29817
|
+
if (allowance === undefined || allowance < 0n) {
|
|
29818
|
+
throw createValidationFailedError$1('token.allowance', allowanceRaw, 'token.allowance response must be a non-negative bigint-compatible string or bigint');
|
|
29819
|
+
}
|
|
29820
|
+
return allowance;
|
|
29437
29821
|
}
|
|
29438
|
-
|
|
29439
29822
|
/**
|
|
29440
|
-
*
|
|
29823
|
+
* Read the current ERC-20 allowance and, if below threshold, send a
|
|
29824
|
+
* max-approval transaction and wait for confirmation.
|
|
29441
29825
|
*
|
|
29442
|
-
*
|
|
29443
|
-
*
|
|
29444
|
-
*
|
|
29826
|
+
* Uses the generalised `token.allowance` + `token.approve` adapter actions so
|
|
29827
|
+
* the kit stays chain-agnostic. Assumes the target token supports
|
|
29828
|
+
* non-zero-to-non-zero approve (USDC, ERC-4626 share tokens). Tokens with
|
|
29829
|
+
* USDT-style semantics (require allowance == 0 before non-zero approve) need
|
|
29830
|
+
* a different pattern.
|
|
29445
29831
|
*
|
|
29446
|
-
*
|
|
29447
|
-
*
|
|
29448
|
-
* transaction parameters without executing the actual transfer.
|
|
29832
|
+
* Approval status is checked explicitly because `waitForTransaction` returns
|
|
29833
|
+
* a receipt with `status: 'reverted'` rather than throwing on revert.
|
|
29449
29834
|
*
|
|
29450
|
-
* @
|
|
29451
|
-
*
|
|
29452
|
-
* @
|
|
29453
|
-
* @throws If
|
|
29454
|
-
* @throws If the bridge route is not supported
|
|
29455
|
-
* @throws If estimation fails due to network or configuration issues
|
|
29835
|
+
* @returns The approval tx hash when an approval was sent, or `undefined` if
|
|
29836
|
+
* the existing allowance was already above threshold.
|
|
29837
|
+
* @throws {@link KitError} If the allowance response is malformed.
|
|
29838
|
+
* @throws {@link KitError} If the approval transaction reverts on-chain.
|
|
29456
29839
|
*
|
|
29457
29840
|
* @example
|
|
29458
29841
|
* ```typescript
|
|
29459
|
-
*
|
|
29460
|
-
* import { createContext } from '@circle-fin/app-kit/context'
|
|
29461
|
-
*
|
|
29462
|
-
* const context = createContext({
|
|
29463
|
-
* getFee: async (type, params) => '1000000', // 1 USDC fee
|
|
29464
|
-
* getFeeRecipient: async (type, info) => '0xfee-recipient-address'
|
|
29465
|
-
* })
|
|
29842
|
+
* const delegate = requireAdapterContract(chain)
|
|
29466
29843
|
*
|
|
29467
|
-
* const
|
|
29468
|
-
*
|
|
29469
|
-
*
|
|
29470
|
-
*
|
|
29471
|
-
*
|
|
29844
|
+
* const approvalTxHash = await approveMaxIfNeeded({
|
|
29845
|
+
* adapter,
|
|
29846
|
+
* chain,
|
|
29847
|
+
* tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
29848
|
+
* delegate,
|
|
29849
|
+
* address,
|
|
29850
|
+
* revertMessage: 'USDC approval reverted on-chain',
|
|
29472
29851
|
* })
|
|
29473
|
-
*
|
|
29474
|
-
* console.log('Estimated total fee:', estimate.fee)
|
|
29475
|
-
* console.log('Estimated gas cost:', estimate.gasEstimate)
|
|
29476
29852
|
* ```
|
|
29853
|
+
*
|
|
29854
|
+
* @internal
|
|
29477
29855
|
*/
|
|
29478
|
-
|
|
29479
|
-
const
|
|
29480
|
-
|
|
29481
|
-
|
|
29482
|
-
|
|
29856
|
+
async function approveMaxIfNeeded(params) {
|
|
29857
|
+
const { adapter, chain, tokenAddress, delegate, address, revertMessage } = params;
|
|
29858
|
+
const allowancePrepared = await adapter.prepareAction('token.allowance', { tokenAddress, delegate }, { chain, address });
|
|
29859
|
+
const allowanceRaw = await allowancePrepared.execute();
|
|
29860
|
+
const currentAllowance = parseAllowanceResponse(allowanceRaw);
|
|
29861
|
+
if (currentAllowance >= ALLOWANCE_THRESHOLD) {
|
|
29862
|
+
return undefined;
|
|
29863
|
+
}
|
|
29864
|
+
const approvalPrepared = await adapter.prepareAction('token.approve', { tokenAddress, delegate, amount: MAX_UINT256$1 }, { chain, address });
|
|
29865
|
+
const gasLimitOverride = await estimateBufferedGasLimit(approvalPrepared);
|
|
29866
|
+
const approvalTxHash = approvalPrepared.type === 'evm' && gasLimitOverride !== undefined
|
|
29867
|
+
? await approvalPrepared.execute({ gasLimit: gasLimitOverride })
|
|
29868
|
+
: await approvalPrepared.execute();
|
|
29869
|
+
const approvalReceipt = await adapter.waitForTransaction(approvalTxHash, { confirmations: 1 }, chain);
|
|
29870
|
+
if (approvalReceipt.status === 'reverted') {
|
|
29871
|
+
throw createTransactionRevertedError(chain.name, revertMessage, undefined, approvalTxHash);
|
|
29872
|
+
}
|
|
29873
|
+
return approvalTxHash;
|
|
29874
|
+
}
|
|
29483
29875
|
|
|
29484
|
-
const assertSendParamsSymbol = Symbol('assertSendParams');
|
|
29485
29876
|
/**
|
|
29486
|
-
*
|
|
29877
|
+
* Build the `tokenInputs` array forwarded to the adapter contract's
|
|
29878
|
+
* `execute(executeParams, tokenInputs, signature)` call.
|
|
29487
29879
|
*
|
|
29488
|
-
*
|
|
29489
|
-
*
|
|
29490
|
-
*
|
|
29491
|
-
|
|
29492
|
-
|
|
29493
|
-
|
|
29494
|
-
* Schema describing the minimal adapter surface required by the kit.
|
|
29880
|
+
* The adapter contract pulls ERC-20 tokens from `msg.sender` using the
|
|
29881
|
+
* entries in `tokenInputs`, combined either with a pre-existing allowance
|
|
29882
|
+
* ({@link PermitType.NONE}) or a permit signature ({@link PermitType.EIP2612}).
|
|
29883
|
+
* Without an entry, the contract never moves the user's tokens and the
|
|
29884
|
+
* nested instruction reverts with "ERC20: transfer amount exceeds balance"
|
|
29885
|
+
* when the adapter tries to forward tokens it does not hold.
|
|
29495
29886
|
*
|
|
29496
|
-
*
|
|
29497
|
-
*
|
|
29498
|
-
*
|
|
29887
|
+
* Earn deposit and withdraw responses are schema-validated to contain at
|
|
29888
|
+
* least one instruction. This helper emits one `PermitType.NONE` entry per
|
|
29889
|
+
* instruction with a positive `amountToApprove`. Return an empty array when
|
|
29890
|
+
* the service did not request any token pulls.
|
|
29499
29891
|
*
|
|
29500
|
-
* @
|
|
29892
|
+
* @param executionParams - Service-signed `ExecutionParams` forwarded to the adapter.
|
|
29893
|
+
* @param approvedToken - Token approved for adapter spending on this chain.
|
|
29894
|
+
* @returns `TokenInput[]` entries when pulls are required, `[]` otherwise.
|
|
29895
|
+
* @throws {@link KitError} If `tokenIn` differs from the approved token.
|
|
29501
29896
|
*
|
|
29502
29897
|
* @example
|
|
29503
29898
|
* ```typescript
|
|
29504
|
-
*
|
|
29899
|
+
* const approvedToken = assertHexAddress(
|
|
29900
|
+
* 'chain.usdcAddress',
|
|
29901
|
+
* chain.usdcAddress,
|
|
29902
|
+
* )
|
|
29505
29903
|
*
|
|
29506
|
-
*
|
|
29904
|
+
* const tokenInputs = buildEarnTokenInputs(
|
|
29905
|
+
* executionPayload.executionParams,
|
|
29906
|
+
* approvedToken,
|
|
29907
|
+
* )
|
|
29507
29908
|
* ```
|
|
29909
|
+
*
|
|
29910
|
+
* @internal
|
|
29508
29911
|
*/
|
|
29509
|
-
|
|
29510
|
-
|
|
29511
|
-
|
|
29512
|
-
|
|
29912
|
+
function buildEarnTokenInputs(executionParams, approvedToken) {
|
|
29913
|
+
const tokenInputs = [];
|
|
29914
|
+
executionParams.instructions.forEach((instruction, index) => {
|
|
29915
|
+
const amount = BigInt(instruction.amountToApprove);
|
|
29916
|
+
if (amount <= 0n) {
|
|
29917
|
+
return;
|
|
29918
|
+
}
|
|
29919
|
+
const { tokenIn } = instruction;
|
|
29920
|
+
if (tokenIn.toLowerCase() !== approvedToken.toLowerCase()) {
|
|
29921
|
+
throw createValidationFailedError$1(`executionParams.instructions[${index.toString()}].tokenIn`, tokenIn, 'tokenIn must match the token approved for adapter spending');
|
|
29922
|
+
}
|
|
29923
|
+
tokenInputs.push({
|
|
29924
|
+
permitType: PermitType.NONE,
|
|
29925
|
+
token: tokenIn,
|
|
29926
|
+
amount,
|
|
29927
|
+
permitCalldata: '0x',
|
|
29928
|
+
});
|
|
29929
|
+
});
|
|
29930
|
+
return tokenInputs;
|
|
29931
|
+
}
|
|
29932
|
+
|
|
29513
29933
|
/**
|
|
29514
|
-
*
|
|
29515
|
-
*
|
|
29516
|
-
* - A valid adapter with `prepare` and `waitForTransaction` methods.
|
|
29517
|
-
* - A valid chain identifier (string literal or chain object recognized by the kit).
|
|
29934
|
+
* Prepare an earn adapter action, execute it, wait for confirmation, and
|
|
29935
|
+
* throw a structured revert error if the receipt status is `'reverted'`.
|
|
29518
29936
|
*
|
|
29519
|
-
*
|
|
29520
|
-
*
|
|
29937
|
+
* Wraps the prepareAction, execute, waitForTransaction, and status check
|
|
29938
|
+
* sequence so the provider can dispatch any `earn.*` action key with
|
|
29939
|
+
* consistent revert handling.
|
|
29940
|
+
*
|
|
29941
|
+
* Gas estimation: after preparing the action the helper calls
|
|
29942
|
+
* {@link estimateBufferedGasLimit}, which applies a safety buffer to the
|
|
29943
|
+
* returned gas value. If estimation fails, execution falls through to the
|
|
29944
|
+
* adapter's default gas handling.
|
|
29945
|
+
*
|
|
29946
|
+
* @typeParam TActionKey - Earn action key being executed.
|
|
29947
|
+
* @param params - Adapter action, execution context, and revert message.
|
|
29948
|
+
* @returns The confirmed on-chain transaction hash and explorer URL.
|
|
29949
|
+
* @throws {@link KitError} If the transaction reverts on-chain.
|
|
29521
29950
|
*
|
|
29522
29951
|
* @example
|
|
29523
29952
|
* ```typescript
|
|
29524
|
-
*
|
|
29525
|
-
*
|
|
29526
|
-
*
|
|
29527
|
-
*
|
|
29953
|
+
* const { txHash, explorerUrl } = await executeEarnAction({
|
|
29954
|
+
* adapter,
|
|
29955
|
+
* chain,
|
|
29956
|
+
* address,
|
|
29957
|
+
* actionKey: 'earn.deposit',
|
|
29958
|
+
* actionParams: { executeParams, tokenInputs, signature },
|
|
29959
|
+
* revertMessage: 'Earn deposit reverted on-chain',
|
|
29960
|
+
* })
|
|
29528
29961
|
* ```
|
|
29962
|
+
*
|
|
29963
|
+
* @internal
|
|
29529
29964
|
*/
|
|
29530
|
-
|
|
29531
|
-
adapter
|
|
29532
|
-
|
|
29533
|
-
|
|
29534
|
-
|
|
29965
|
+
async function executeEarnAction(params) {
|
|
29966
|
+
const { adapter, chain, address, actionKey, actionParams, revertMessage } = params;
|
|
29967
|
+
const prepared = await adapter.prepareAction(actionKey, actionParams, {
|
|
29968
|
+
chain,
|
|
29969
|
+
address,
|
|
29970
|
+
});
|
|
29971
|
+
const gasLimitOverride = await estimateBufferedGasLimit(prepared);
|
|
29972
|
+
const txHash = prepared.type === 'evm' && gasLimitOverride !== undefined
|
|
29973
|
+
? await prepared.execute({ gasLimit: gasLimitOverride })
|
|
29974
|
+
: await prepared.execute();
|
|
29975
|
+
const explorerUrl = buildExplorerUrl(chain, txHash);
|
|
29976
|
+
const receipt = await adapter.waitForTransaction(txHash, { confirmations: 1 }, chain);
|
|
29977
|
+
if (receipt.status === 'reverted') {
|
|
29978
|
+
throw createTransactionRevertedError(chain.name, revertMessage, undefined, txHash, explorerUrl);
|
|
29979
|
+
}
|
|
29980
|
+
return { txHash, explorerUrl };
|
|
29981
|
+
}
|
|
29982
|
+
|
|
29983
|
+
/**
|
|
29984
|
+
* Validate that a service-signed execution payload has not expired before
|
|
29985
|
+
* the SDK asks the wallet to broadcast a transaction.
|
|
29986
|
+
*
|
|
29987
|
+
* @internal
|
|
29988
|
+
*/
|
|
29989
|
+
function validateExecutionDeadline(executionParams) {
|
|
29990
|
+
const deadline = BigInt(executionParams.deadline);
|
|
29991
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
29992
|
+
if (deadline <= now) {
|
|
29993
|
+
throw createValidationFailedError$1('executionParams.deadline', executionParams.deadline, 'Earn execution deadline has expired');
|
|
29994
|
+
}
|
|
29995
|
+
}
|
|
29996
|
+
|
|
29997
|
+
// ---------------------------------------------------------------------------
|
|
29998
|
+
// Shared primitives
|
|
29999
|
+
// ---------------------------------------------------------------------------
|
|
30000
|
+
function isBigIntLike(value) {
|
|
30001
|
+
try {
|
|
30002
|
+
BigInt(value);
|
|
30003
|
+
return true;
|
|
30004
|
+
}
|
|
30005
|
+
catch {
|
|
30006
|
+
return false;
|
|
30007
|
+
}
|
|
30008
|
+
}
|
|
30009
|
+
function isNonNegativeBigIntLike(value) {
|
|
30010
|
+
try {
|
|
30011
|
+
return BigInt(value) >= 0n;
|
|
30012
|
+
}
|
|
30013
|
+
catch {
|
|
30014
|
+
return false;
|
|
30015
|
+
}
|
|
30016
|
+
}
|
|
30017
|
+
const hexSignatureSchema = evmSignatureSchema;
|
|
30018
|
+
const hexAddressSchema = evmAddressSchema;
|
|
30019
|
+
/**
|
|
30020
|
+
* Zod schema for a non-negative uint256-like value.
|
|
30021
|
+
*
|
|
30022
|
+
* The service emits uint256 fields as decimal strings in JSON, while tests and
|
|
30023
|
+
* lower-level SDK callers may already hold bigint values. Keep the parsed value
|
|
30024
|
+
* unchanged so signed execution params can be forwarded verbatim.
|
|
30025
|
+
*
|
|
30026
|
+
* @internal
|
|
30027
|
+
*/
|
|
30028
|
+
const uint256LikeSchema = zod.z
|
|
30029
|
+
.union([zod.z.string(), zod.z.bigint()])
|
|
30030
|
+
.refine(isNonNegativeBigIntLike, {
|
|
30031
|
+
message: 'value must be a non-negative bigint-compatible string or bigint',
|
|
30032
|
+
});
|
|
30033
|
+
/**
|
|
30034
|
+
* Zod schema for typed amount objects emitted by the API.
|
|
30035
|
+
*
|
|
30036
|
+
* @internal
|
|
30037
|
+
*/
|
|
30038
|
+
const amountJsonSchema = zod.z.object({
|
|
30039
|
+
raw: zod.z.string().refine(isBigIntLike, {
|
|
30040
|
+
message: 'raw must be a bigint-compatible string',
|
|
30041
|
+
}),
|
|
30042
|
+
decimals: zod.z.number().int().nonnegative(),
|
|
30043
|
+
});
|
|
30044
|
+
/** @internal */
|
|
30045
|
+
const hexBytesSchema = zod.z.string().regex(/^0x([0-9a-fA-F]{2})*$/, {
|
|
30046
|
+
message: 'value must be a 0x-prefixed even-length hex string',
|
|
30047
|
+
});
|
|
30048
|
+
// ---------------------------------------------------------------------------
|
|
30049
|
+
// Vault response schemas
|
|
30050
|
+
// ---------------------------------------------------------------------------
|
|
30051
|
+
/**
|
|
30052
|
+
* Zod schema for a vault reward token in the API response.
|
|
30053
|
+
*
|
|
30054
|
+
* @internal
|
|
30055
|
+
*/
|
|
30056
|
+
const vaultRewardSchema = zod.z.object({
|
|
30057
|
+
token: zod.z.string(),
|
|
30058
|
+
tokenAddress: zod.z.string(),
|
|
30059
|
+
apy: zod.z.number(),
|
|
30060
|
+
});
|
|
30061
|
+
/**
|
|
30062
|
+
* Zod schema for a vault collateral market in the API response.
|
|
30063
|
+
*
|
|
30064
|
+
* @internal
|
|
30065
|
+
*/
|
|
30066
|
+
const collateralSchema = zod.z.object({
|
|
30067
|
+
asset: zod.z.string(),
|
|
30068
|
+
assetAddress: zod.z.string(),
|
|
30069
|
+
lltv: zod.z.number(),
|
|
30070
|
+
supplyUsd: zod.z.number(),
|
|
30071
|
+
});
|
|
30072
|
+
/**
|
|
30073
|
+
* Zod schema for a Morpho vault warning in the API response.
|
|
30074
|
+
*
|
|
30075
|
+
* @internal
|
|
30076
|
+
*/
|
|
30077
|
+
const vaultWarningSchema = zod.z.object({
|
|
30078
|
+
type: zod.z.string(),
|
|
30079
|
+
level: zod.z.enum(['YELLOW', 'RED']),
|
|
30080
|
+
});
|
|
30081
|
+
/**
|
|
30082
|
+
* Zod schema for a single vault info object in the API response.
|
|
30083
|
+
*
|
|
30084
|
+
* @internal
|
|
30085
|
+
*/
|
|
30086
|
+
const vaultInfoResponseSchema = zod.z.object({
|
|
30087
|
+
vaultAddress: zod.z.string(),
|
|
30088
|
+
chain: zod.z.string(),
|
|
30089
|
+
name: zod.z.string(),
|
|
30090
|
+
protocol: zod.z.string(),
|
|
30091
|
+
asset: zod.z.string(),
|
|
30092
|
+
assetAddress: zod.z.string(),
|
|
30093
|
+
currentApy: zod.z.number(),
|
|
30094
|
+
nativeApy: zod.z.number(),
|
|
30095
|
+
vaultFee: zod.z.number(),
|
|
30096
|
+
rewards: zod.z.array(vaultRewardSchema),
|
|
30097
|
+
collateral: zod.z.array(collateralSchema),
|
|
30098
|
+
totalDeposits: amountJsonSchema,
|
|
30099
|
+
liquidity: amountJsonSchema,
|
|
30100
|
+
status: zod.z.enum(['active', 'low_liquidity']),
|
|
30101
|
+
warnings: zod.z.array(vaultWarningSchema).optional(),
|
|
30102
|
+
earnKitWarnings: zod.z.array(zod.z.string()).optional(),
|
|
30103
|
+
});
|
|
30104
|
+
// ---------------------------------------------------------------------------
|
|
30105
|
+
// Position response schema
|
|
30106
|
+
// ---------------------------------------------------------------------------
|
|
30107
|
+
/**
|
|
30108
|
+
* Zod schema for an accrued reward in the position API response.
|
|
30109
|
+
*
|
|
30110
|
+
* @internal
|
|
30111
|
+
*/
|
|
30112
|
+
const accruedRewardSchema = zod.z.object({
|
|
30113
|
+
token: zod.z.string(),
|
|
30114
|
+
symbol: zod.z.string(),
|
|
30115
|
+
amount: amountJsonSchema,
|
|
30116
|
+
});
|
|
30117
|
+
const positionPnlSchema = zod.z.discriminatedUnion('status', [
|
|
30118
|
+
zod.z.object({
|
|
30119
|
+
status: zod.z.literal('available'),
|
|
30120
|
+
principalDeposited: amountJsonSchema,
|
|
30121
|
+
totalYieldEarned: amountJsonSchema,
|
|
30122
|
+
}),
|
|
30123
|
+
zod.z.object({
|
|
30124
|
+
status: zod.z.literal('pending'),
|
|
30125
|
+
}),
|
|
30126
|
+
zod.z.object({
|
|
30127
|
+
status: zod.z.literal('unavailable'),
|
|
30128
|
+
reason: zod.z.string(),
|
|
30129
|
+
}),
|
|
30130
|
+
]);
|
|
30131
|
+
/**
|
|
30132
|
+
* Zod schema for the inner position payload.
|
|
30133
|
+
*
|
|
30134
|
+
* @internal
|
|
30135
|
+
*/
|
|
30136
|
+
const positionPayloadSchema = zod.z.object({
|
|
30137
|
+
wallet: zod.z.string(),
|
|
30138
|
+
chain: zod.z.string(),
|
|
30139
|
+
vaultAddress: zod.z.string(),
|
|
30140
|
+
vaultName: zod.z.string(),
|
|
30141
|
+
asset: zod.z.string(),
|
|
30142
|
+
currentBalance: amountJsonSchema,
|
|
30143
|
+
currentApy: zod.z.number(),
|
|
30144
|
+
shares: amountJsonSchema,
|
|
30145
|
+
pnl: positionPnlSchema,
|
|
30146
|
+
accruedRewards: zod.z.array(accruedRewardSchema).optional(),
|
|
30147
|
+
rewardsUnavailableReason: zod.z.string().optional(),
|
|
30148
|
+
});
|
|
30149
|
+
/**
|
|
30150
|
+
* Zod schema for the `GET /v1/earnKit/position/{address}` API response.
|
|
30151
|
+
*
|
|
30152
|
+
* The Earn Service API wraps the position payload in a `data` envelope.
|
|
30153
|
+
*
|
|
30154
|
+
* @internal
|
|
30155
|
+
*/
|
|
30156
|
+
const positionResponseSchema = zod.z.object({
|
|
30157
|
+
data: positionPayloadSchema,
|
|
30158
|
+
});
|
|
30159
|
+
// ---------------------------------------------------------------------------
|
|
30160
|
+
// Deposit response schema
|
|
30161
|
+
// ---------------------------------------------------------------------------
|
|
30162
|
+
/**
|
|
30163
|
+
* Zod schema for the deposit instruction fields used by the provider.
|
|
30164
|
+
*
|
|
30165
|
+
* The canonical instruction shape includes more fields, but deposit
|
|
30166
|
+
* orchestration only depends on `tokenIn` and `amountToApprove` to build the
|
|
30167
|
+
* token input and approval flow. Preserve additional signed fields with
|
|
30168
|
+
* `passthrough()` so the adapter receives the full service payload.
|
|
30169
|
+
*
|
|
30170
|
+
* @internal
|
|
30171
|
+
*/
|
|
30172
|
+
const earnInstructionSchema = zod.z
|
|
30173
|
+
.object({
|
|
30174
|
+
tokenIn: hexAddressSchema,
|
|
30175
|
+
amountToApprove: uint256LikeSchema,
|
|
30176
|
+
})
|
|
30177
|
+
.passthrough();
|
|
30178
|
+
/**
|
|
30179
|
+
* Zod schema for earn execution params returned by the earn service.
|
|
30180
|
+
*
|
|
30181
|
+
* Require at least one instruction so the provider can derive token pulls
|
|
30182
|
+
* before it submits the signed params on-chain. Claim rewards has its own
|
|
30183
|
+
* schema because it does not run approval preflight.
|
|
30184
|
+
*
|
|
30185
|
+
* @internal
|
|
30186
|
+
*/
|
|
30187
|
+
const earnExecutionParamsSchema = zod.z
|
|
30188
|
+
.object({
|
|
30189
|
+
instructions: zod.z.tuple([earnInstructionSchema]).rest(earnInstructionSchema),
|
|
30190
|
+
deadline: uint256LikeSchema,
|
|
30191
|
+
})
|
|
30192
|
+
.passthrough();
|
|
30193
|
+
/** @internal */
|
|
30194
|
+
const depositExecutionParamsSchema = earnExecutionParamsSchema;
|
|
30195
|
+
/** @internal */
|
|
30196
|
+
const withdrawExecutionParamsSchema = earnExecutionParamsSchema;
|
|
30197
|
+
/**
|
|
30198
|
+
* Zod schema for the claim rewards instruction fields that must be safe to
|
|
30199
|
+
* ABI-encode.
|
|
30200
|
+
*
|
|
30201
|
+
* Claim rewards has no approval preflight, so this validates the forwarded
|
|
30202
|
+
* signed payload at the provider boundary. Additional instruction fields are
|
|
30203
|
+
* accepted and preserved.
|
|
30204
|
+
*
|
|
30205
|
+
* @internal
|
|
30206
|
+
*/
|
|
30207
|
+
const claimRewardsInstructionSchema = zod.z
|
|
30208
|
+
.object({
|
|
30209
|
+
target: hexAddressSchema,
|
|
30210
|
+
data: hexBytesSchema,
|
|
30211
|
+
value: uint256LikeSchema,
|
|
30212
|
+
tokenIn: hexAddressSchema,
|
|
30213
|
+
amountToApprove: uint256LikeSchema,
|
|
30214
|
+
tokenOut: hexAddressSchema,
|
|
30215
|
+
minTokenOut: uint256LikeSchema,
|
|
30216
|
+
})
|
|
30217
|
+
.passthrough();
|
|
30218
|
+
/** @internal */
|
|
30219
|
+
const claimRewardsTokenSchema = zod.z
|
|
30220
|
+
.object({
|
|
30221
|
+
token: hexAddressSchema,
|
|
30222
|
+
beneficiary: hexAddressSchema,
|
|
30223
|
+
})
|
|
30224
|
+
.passthrough();
|
|
30225
|
+
/**
|
|
30226
|
+
* Zod schema for signed claim rewards execution params.
|
|
30227
|
+
*
|
|
30228
|
+
* This enforces the required envelope and preserves additive fields so the
|
|
30229
|
+
* adapter receives the signed params verbatim.
|
|
30230
|
+
*
|
|
30231
|
+
* @internal
|
|
30232
|
+
*/
|
|
30233
|
+
const claimRewardsExecutionParamsSchema = zod.z
|
|
30234
|
+
.object({
|
|
30235
|
+
instructions: zod.z
|
|
30236
|
+
.tuple([claimRewardsInstructionSchema])
|
|
30237
|
+
.rest(claimRewardsInstructionSchema),
|
|
30238
|
+
tokens: zod.z.tuple([claimRewardsTokenSchema]).rest(claimRewardsTokenSchema),
|
|
30239
|
+
execId: uint256LikeSchema,
|
|
30240
|
+
deadline: uint256LikeSchema,
|
|
30241
|
+
metadata: hexBytesSchema,
|
|
30242
|
+
})
|
|
30243
|
+
.passthrough();
|
|
30244
|
+
/**
|
|
30245
|
+
* Zod schema for the deposit payload inside the API `data` envelope.
|
|
30246
|
+
*
|
|
30247
|
+
* @internal
|
|
30248
|
+
*/
|
|
30249
|
+
const depositPayloadSchema = zod.z.object({
|
|
30250
|
+
executionParams: depositExecutionParamsSchema,
|
|
30251
|
+
signature: hexSignatureSchema,
|
|
30252
|
+
});
|
|
30253
|
+
/**
|
|
30254
|
+
* Zod schema for the `POST /v1/earnKit/deposit` API response.
|
|
30255
|
+
*
|
|
30256
|
+
* The API wraps the deposit payload in a `data` envelope.
|
|
30257
|
+
*
|
|
30258
|
+
* @internal
|
|
30259
|
+
*/
|
|
30260
|
+
const depositResponseSchema = zod.z.object({
|
|
30261
|
+
data: depositPayloadSchema,
|
|
30262
|
+
});
|
|
30263
|
+
// ---------------------------------------------------------------------------
|
|
30264
|
+
// Withdraw response schema
|
|
30265
|
+
// ---------------------------------------------------------------------------
|
|
30266
|
+
/**
|
|
30267
|
+
* Zod schema for the withdraw payload inside the API `data` envelope.
|
|
30268
|
+
*
|
|
30269
|
+
* @internal
|
|
30270
|
+
*/
|
|
30271
|
+
const withdrawPayloadSchema = zod.z.object({
|
|
30272
|
+
executionParams: withdrawExecutionParamsSchema,
|
|
30273
|
+
signature: hexSignatureSchema,
|
|
30274
|
+
});
|
|
30275
|
+
/**
|
|
30276
|
+
* Zod schema for the `POST /v1/earnKit/withdraw` API response.
|
|
30277
|
+
*
|
|
30278
|
+
* The Earn Service API wraps the withdraw payload in a `data` envelope.
|
|
30279
|
+
*
|
|
30280
|
+
* @internal
|
|
30281
|
+
*/
|
|
30282
|
+
const withdrawResponseSchema = zod.z.object({
|
|
30283
|
+
data: withdrawPayloadSchema,
|
|
30284
|
+
});
|
|
30285
|
+
// ---------------------------------------------------------------------------
|
|
30286
|
+
// Claim rewards response schema
|
|
30287
|
+
// ---------------------------------------------------------------------------
|
|
30288
|
+
/**
|
|
30289
|
+
* Zod schema for a claimed reward amount in the API response.
|
|
30290
|
+
*
|
|
30291
|
+
* @internal
|
|
30292
|
+
*/
|
|
30293
|
+
const claimedAmountSchema = zod.z.object({
|
|
30294
|
+
token: hexAddressSchema,
|
|
30295
|
+
symbol: zod.z.string(),
|
|
30296
|
+
amount: amountJsonSchema,
|
|
30297
|
+
});
|
|
30298
|
+
/**
|
|
30299
|
+
* Zod schema for the claim rewards payload inside the API `data` envelope.
|
|
30300
|
+
*
|
|
30301
|
+
* Enforce that `executionParams` and `signature` are either both
|
|
30302
|
+
* present (claimable rewards) or both absent (nothing to claim).
|
|
30303
|
+
*
|
|
30304
|
+
* @internal
|
|
30305
|
+
*/
|
|
30306
|
+
const claimRewardsPayloadSchema = zod.z
|
|
30307
|
+
.object({
|
|
30308
|
+
rewards: zod.z.array(claimedAmountSchema),
|
|
30309
|
+
executionParams: claimRewardsExecutionParamsSchema.optional(),
|
|
30310
|
+
signature: hexSignatureSchema.optional(),
|
|
30311
|
+
})
|
|
30312
|
+
.refine((data) => {
|
|
30313
|
+
const signedFieldCount = (data.executionParams === undefined ? 0 : 1) +
|
|
30314
|
+
(data.signature === undefined ? 0 : 1);
|
|
30315
|
+
if (data.rewards.length > 0) {
|
|
30316
|
+
return signedFieldCount === 2;
|
|
30317
|
+
}
|
|
30318
|
+
return signedFieldCount === 0;
|
|
30319
|
+
}, {
|
|
30320
|
+
message: 'claim rewards response must include executionParams and signature only when rewards are claimable',
|
|
30321
|
+
});
|
|
30322
|
+
/**
|
|
30323
|
+
* Zod schema for the `POST /v1/earnKit/claimRewards` API response.
|
|
30324
|
+
*
|
|
30325
|
+
* The Earn Service API wraps the claim rewards payload in a `data` envelope.
|
|
30326
|
+
*
|
|
30327
|
+
* @internal
|
|
30328
|
+
*/
|
|
30329
|
+
const claimRewardsResponseSchema = zod.z.object({
|
|
30330
|
+
data: claimRewardsPayloadSchema,
|
|
30331
|
+
});
|
|
30332
|
+
// ---------------------------------------------------------------------------
|
|
30333
|
+
// Deposit quote response schema
|
|
30334
|
+
// ---------------------------------------------------------------------------
|
|
30335
|
+
/**
|
|
30336
|
+
* Zod schema for the inner deposit quote payload.
|
|
30337
|
+
*
|
|
30338
|
+
* @internal
|
|
30339
|
+
*/
|
|
30340
|
+
const depositQuotePayloadSchema = zod.z.object({
|
|
30341
|
+
vaultAddress: zod.z.string(),
|
|
30342
|
+
vaultName: zod.z.string(),
|
|
30343
|
+
asset: zod.z.string(),
|
|
30344
|
+
depositAmount: amountJsonSchema,
|
|
30345
|
+
expectedShares: amountJsonSchema,
|
|
30346
|
+
sharePrice: zod.z.string(),
|
|
30347
|
+
currentApy: zod.z.number(),
|
|
30348
|
+
});
|
|
30349
|
+
/**
|
|
30350
|
+
* Zod schema for the `POST /v1/earnKit/deposit/quote` API response.
|
|
30351
|
+
*
|
|
30352
|
+
* The Zenith API wraps the payload in a `data` envelope.
|
|
30353
|
+
*
|
|
30354
|
+
* @internal
|
|
30355
|
+
*/
|
|
30356
|
+
const depositQuoteResponseSchema = zod.z.object({
|
|
30357
|
+
data: depositQuotePayloadSchema,
|
|
30358
|
+
});
|
|
30359
|
+
// ---------------------------------------------------------------------------
|
|
30360
|
+
// Withdrawal quote response schema
|
|
30361
|
+
// ---------------------------------------------------------------------------
|
|
30362
|
+
/**
|
|
30363
|
+
* Zod schema for a withdrawal quote fee in the API response.
|
|
30364
|
+
*
|
|
30365
|
+
* @internal
|
|
30366
|
+
*/
|
|
30367
|
+
const withdrawalQuoteFeeSchema = zod.z.object({
|
|
30368
|
+
token: zod.z.string(),
|
|
30369
|
+
amount: amountJsonSchema,
|
|
30370
|
+
});
|
|
30371
|
+
/**
|
|
30372
|
+
* Zod schema for the inner withdrawal quote payload.
|
|
30373
|
+
*
|
|
30374
|
+
* @internal
|
|
30375
|
+
*/
|
|
30376
|
+
const withdrawalQuotePayloadSchema = zod.z.object({
|
|
30377
|
+
vaultAddress: zod.z.string(),
|
|
30378
|
+
vaultName: zod.z.string(),
|
|
30379
|
+
asset: zod.z.string(),
|
|
30380
|
+
withdrawAmount: amountJsonSchema,
|
|
30381
|
+
sharesToRedeem: amountJsonSchema,
|
|
30382
|
+
sharePrice: zod.z.string(),
|
|
30383
|
+
maxWithdrawable: amountJsonSchema,
|
|
30384
|
+
fees: zod.z.array(withdrawalQuoteFeeSchema),
|
|
30385
|
+
warnings: zod.z.array(zod.z.string()).optional(),
|
|
30386
|
+
});
|
|
30387
|
+
/**
|
|
30388
|
+
* Zod schema for the `POST /v1/earnKit/withdrawal/quote` API response.
|
|
30389
|
+
*
|
|
30390
|
+
* The Zenith API wraps the payload in a `data` envelope.
|
|
30391
|
+
*
|
|
30392
|
+
* @internal
|
|
30393
|
+
*/
|
|
30394
|
+
const withdrawalQuoteResponseSchema = zod.z.object({
|
|
30395
|
+
data: withdrawalQuotePayloadSchema,
|
|
30396
|
+
});
|
|
30397
|
+
// ---------------------------------------------------------------------------
|
|
30398
|
+
// Claim rewards quote response schema
|
|
30399
|
+
// ---------------------------------------------------------------------------
|
|
30400
|
+
/**
|
|
30401
|
+
* Zod schema for a reward in the claim rewards quote response.
|
|
30402
|
+
*
|
|
30403
|
+
* @internal
|
|
30404
|
+
*/
|
|
30405
|
+
const claimRewardsQuoteRewardSchema = zod.z.object({
|
|
30406
|
+
token: zod.z.string(),
|
|
30407
|
+
symbol: zod.z.string(),
|
|
30408
|
+
amount: amountJsonSchema,
|
|
30409
|
+
});
|
|
30410
|
+
/**
|
|
30411
|
+
* Zod schema for the inner claim rewards quote payload.
|
|
30412
|
+
*
|
|
30413
|
+
* @internal
|
|
30414
|
+
*/
|
|
30415
|
+
const claimRewardsQuotePayloadSchema = zod.z.object({
|
|
30416
|
+
rewards: zod.z.array(claimRewardsQuoteRewardSchema),
|
|
30417
|
+
});
|
|
30418
|
+
/**
|
|
30419
|
+
* Zod schema for the `POST /v1/earnKit/claimRewards/quote` API response.
|
|
30420
|
+
*
|
|
30421
|
+
* The Zenith API wraps the payload in a `data` envelope.
|
|
30422
|
+
*
|
|
30423
|
+
* @internal
|
|
30424
|
+
*/
|
|
30425
|
+
const claimRewardsQuoteResponseSchema = zod.z.object({
|
|
30426
|
+
data: claimRewardsQuotePayloadSchema,
|
|
30427
|
+
});
|
|
30428
|
+
// ---------------------------------------------------------------------------
|
|
30429
|
+
// Batch vault response schema
|
|
30430
|
+
// ---------------------------------------------------------------------------
|
|
30431
|
+
/**
|
|
30432
|
+
* Zod schema for a per-vault error in the batch vault API response.
|
|
30433
|
+
*
|
|
30434
|
+
* @internal
|
|
30435
|
+
*/
|
|
30436
|
+
const vaultErrorSchema = zod.z.object({
|
|
30437
|
+
chain: zod.z.string(),
|
|
30438
|
+
vaultAddress: zod.z.string(),
|
|
30439
|
+
code: zod.z.number(),
|
|
30440
|
+
message: zod.z.string(),
|
|
30441
|
+
});
|
|
30442
|
+
/**
|
|
30443
|
+
* Zod schema for the inner batch vault payload.
|
|
30444
|
+
*
|
|
30445
|
+
* @internal
|
|
30446
|
+
*/
|
|
30447
|
+
const getVaultsPayloadSchema = zod.z.object({
|
|
30448
|
+
vaults: zod.z.array(vaultInfoResponseSchema),
|
|
30449
|
+
errors: zod.z.array(vaultErrorSchema),
|
|
30450
|
+
});
|
|
30451
|
+
/**
|
|
30452
|
+
* Zod schema for the `GET /v1/earnKit/vaults` batch API response.
|
|
30453
|
+
*
|
|
30454
|
+
* The Earn Service API wraps the vault payload in a `data` envelope.
|
|
30455
|
+
*
|
|
30456
|
+
* @internal
|
|
30457
|
+
*/
|
|
30458
|
+
const getVaultsResponseSchema = zod.z.object({
|
|
30459
|
+
data: getVaultsPayloadSchema,
|
|
30460
|
+
});
|
|
30461
|
+
|
|
30462
|
+
/**
|
|
30463
|
+
* Type guard for the batch vault lookup API response.
|
|
30464
|
+
*
|
|
30465
|
+
* @param value - Unknown response value to validate
|
|
30466
|
+
* @returns True when the value matches the batch vault response shape
|
|
30467
|
+
*
|
|
30468
|
+
* @internal
|
|
30469
|
+
*/
|
|
30470
|
+
function isGetVaultsResponse(value) {
|
|
30471
|
+
return getVaultsResponseSchema.safeParse(value).success;
|
|
30472
|
+
}
|
|
30473
|
+
/**
|
|
30474
|
+
* Type guard for the position API response.
|
|
30475
|
+
*
|
|
30476
|
+
* @param value - Unknown response value to validate
|
|
30477
|
+
* @returns True when the value matches the position response shape
|
|
30478
|
+
*
|
|
30479
|
+
* @internal
|
|
30480
|
+
*/
|
|
30481
|
+
function isPositionResponse(value) {
|
|
30482
|
+
return positionResponseSchema.safeParse(value).success;
|
|
30483
|
+
}
|
|
30484
|
+
/**
|
|
30485
|
+
* Type guard for the deposit API response.
|
|
30486
|
+
*
|
|
30487
|
+
* @param value - Unknown response value to validate
|
|
30488
|
+
* @returns True when the value matches the deposit response shape
|
|
30489
|
+
*
|
|
30490
|
+
* @internal
|
|
30491
|
+
*/
|
|
30492
|
+
function isDepositResponse(value) {
|
|
30493
|
+
return depositResponseSchema.safeParse(value).success;
|
|
30494
|
+
}
|
|
30495
|
+
/**
|
|
30496
|
+
* Type guard for the withdraw API response.
|
|
30497
|
+
*
|
|
30498
|
+
* @param value - Unknown response value to validate
|
|
30499
|
+
* @returns True when the value matches the withdraw response shape
|
|
30500
|
+
*
|
|
30501
|
+
* @internal
|
|
30502
|
+
*/
|
|
30503
|
+
function isWithdrawResponse(value) {
|
|
30504
|
+
return withdrawResponseSchema.safeParse(value).success;
|
|
30505
|
+
}
|
|
30506
|
+
/**
|
|
30507
|
+
* Type guard for the claim rewards API response.
|
|
30508
|
+
*
|
|
30509
|
+
* @param value - Unknown response value to validate
|
|
30510
|
+
* @returns True when the value matches the claim rewards response shape
|
|
30511
|
+
*
|
|
30512
|
+
* @internal
|
|
30513
|
+
*/
|
|
30514
|
+
function isClaimRewardsResponse(value) {
|
|
30515
|
+
return claimRewardsResponseSchema.safeParse(value).success;
|
|
30516
|
+
}
|
|
30517
|
+
/**
|
|
30518
|
+
* Type guard for the deposit quote API response.
|
|
30519
|
+
*
|
|
30520
|
+
* @param value - Unknown response value to validate
|
|
30521
|
+
* @returns True when the value matches the deposit quote response shape
|
|
30522
|
+
*
|
|
30523
|
+
* @internal
|
|
30524
|
+
*/
|
|
30525
|
+
function isDepositQuoteResponse(value) {
|
|
30526
|
+
return depositQuoteResponseSchema.safeParse(value).success;
|
|
30527
|
+
}
|
|
30528
|
+
/**
|
|
30529
|
+
* Type guard for the withdrawal quote API response.
|
|
30530
|
+
*
|
|
30531
|
+
* @param value - Unknown response value to validate
|
|
30532
|
+
* @returns True when the value matches the withdrawal quote response shape
|
|
30533
|
+
*
|
|
30534
|
+
* @internal
|
|
30535
|
+
*/
|
|
30536
|
+
function isWithdrawalQuoteResponse(value) {
|
|
30537
|
+
return withdrawalQuoteResponseSchema.safeParse(value).success;
|
|
30538
|
+
}
|
|
30539
|
+
/**
|
|
30540
|
+
* Type guard for the claim rewards quote API response.
|
|
30541
|
+
*
|
|
30542
|
+
* @param value - Unknown response value to validate
|
|
30543
|
+
* @returns True when the value matches the claim rewards quote response shape
|
|
30544
|
+
*
|
|
30545
|
+
* @internal
|
|
30546
|
+
*/
|
|
30547
|
+
function isClaimRewardsQuoteResponse(value) {
|
|
30548
|
+
return claimRewardsQuoteResponseSchema.safeParse(value).success;
|
|
30549
|
+
}
|
|
30550
|
+
|
|
30551
|
+
/**
|
|
30552
|
+
* Build an API polling config with optional authorization header,
|
|
30553
|
+
* and resolve the base URL (configurable for testing).
|
|
30554
|
+
*
|
|
30555
|
+
* @param serviceConfig - Optional earn service configuration
|
|
30556
|
+
* @returns Resolved polling config and base URL
|
|
30557
|
+
*
|
|
30558
|
+
* @internal
|
|
30559
|
+
*/
|
|
30560
|
+
function buildConfig(serviceConfig) {
|
|
30561
|
+
const baseUrl = serviceConfig?.baseUrl ?? EARN_SERVICE_BASE_URL;
|
|
30562
|
+
if (serviceConfig?.kitKey === undefined) {
|
|
30563
|
+
return { pollingConfig: DEFAULT_CONFIG, baseUrl };
|
|
30564
|
+
}
|
|
30565
|
+
if (!isValidApiKey(serviceConfig.kitKey)) {
|
|
30566
|
+
throw new KitError({
|
|
30567
|
+
...InputError.VALIDATION_FAILED,
|
|
30568
|
+
recoverability: 'FATAL',
|
|
30569
|
+
message: 'Invalid kitKey format. Expected KIT_KEY:<keyId>:<keySecret>.',
|
|
30570
|
+
});
|
|
30571
|
+
}
|
|
30572
|
+
return {
|
|
30573
|
+
pollingConfig: {
|
|
30574
|
+
...DEFAULT_CONFIG,
|
|
30575
|
+
headers: {
|
|
30576
|
+
...DEFAULT_CONFIG.headers,
|
|
30577
|
+
Authorization: `Bearer ${serviceConfig.kitKey}`,
|
|
30578
|
+
},
|
|
30579
|
+
},
|
|
30580
|
+
baseUrl,
|
|
30581
|
+
};
|
|
30582
|
+
}
|
|
30583
|
+
|
|
30584
|
+
function toVaultInfo(data) {
|
|
30585
|
+
const { totalDeposits, liquidity, ...vault } = data;
|
|
30586
|
+
const chain = toSdkChain(vault.chain);
|
|
30587
|
+
if (chain === undefined) {
|
|
30588
|
+
throw createInvalidChainError(vault.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
30589
|
+
}
|
|
30590
|
+
return {
|
|
30591
|
+
...vault,
|
|
30592
|
+
chain,
|
|
30593
|
+
totalDeposits: Amount.fromJSON(totalDeposits),
|
|
30594
|
+
liquidity: Amount.fromJSON(liquidity),
|
|
30595
|
+
};
|
|
30596
|
+
}
|
|
30597
|
+
function toVaultError(error) {
|
|
30598
|
+
const chain = toSdkChain(error.chain);
|
|
30599
|
+
if (chain === undefined) {
|
|
30600
|
+
throw createInvalidChainError(error.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
30601
|
+
}
|
|
30602
|
+
return { ...error, chain };
|
|
30603
|
+
}
|
|
30604
|
+
function getVaultQueryChainLabel(chain) {
|
|
30605
|
+
return typeof chain === 'string' ? chain : 'unknown';
|
|
30606
|
+
}
|
|
30607
|
+
function resolveVaultQueryChain(chain) {
|
|
30608
|
+
try {
|
|
30609
|
+
return resolveChainIdentifier(chain);
|
|
30610
|
+
}
|
|
30611
|
+
catch {
|
|
30612
|
+
throw createInvalidChainError(getVaultQueryChainLabel(chain), 'Chain is not supported by the Earn Service provider');
|
|
30613
|
+
}
|
|
30614
|
+
}
|
|
30615
|
+
/**
|
|
30616
|
+
* Fetch vault information from the Earn Service API.
|
|
30617
|
+
*
|
|
30618
|
+
* Call `GET /v1/earnKit/vaults` with repeated chain and vaultAddress
|
|
30619
|
+
* query parameters for batch vault lookup.
|
|
30620
|
+
*
|
|
30621
|
+
* @param params - Vault query parameters
|
|
30622
|
+
* @returns Batch result with vaults and per-vault errors
|
|
30623
|
+
* @throws {@link KitError} When the API call fails
|
|
30624
|
+
*
|
|
30625
|
+
* @internal
|
|
30626
|
+
*/
|
|
30627
|
+
async function fetchVaults(params) {
|
|
30628
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30629
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/vaults`, baseUrl);
|
|
30630
|
+
// The API pairs chain[i] with vaultAddress[i] by insertion order.
|
|
30631
|
+
for (const vault of params.vaults) {
|
|
30632
|
+
const chainDefinition = resolveVaultQueryChain(vault.chain);
|
|
30633
|
+
const apiChain = toApiChain(chainDefinition.chain);
|
|
30634
|
+
if (apiChain === undefined) {
|
|
30635
|
+
throw createInvalidChainError(chainDefinition.chain, 'Chain is not supported by the Earn Service provider');
|
|
30636
|
+
}
|
|
30637
|
+
url.searchParams.append('chain', apiChain);
|
|
30638
|
+
url.searchParams.append('vaultAddress', vault.vaultAddress);
|
|
30639
|
+
}
|
|
30640
|
+
try {
|
|
30641
|
+
const response = await pollApiGet(url.toString(), isGetVaultsResponse, pollingConfig);
|
|
30642
|
+
return {
|
|
30643
|
+
vaults: response.data.vaults.map(toVaultInfo),
|
|
30644
|
+
errors: response.data.errors.map(toVaultError),
|
|
30645
|
+
};
|
|
30646
|
+
}
|
|
30647
|
+
catch (error) {
|
|
30648
|
+
throw parseEarnApiError(error, { operation: 'getVaults' });
|
|
30649
|
+
}
|
|
30650
|
+
}
|
|
30651
|
+
|
|
30652
|
+
function toAccruedReward(reward) {
|
|
30653
|
+
return {
|
|
30654
|
+
tokenAddress: reward.token,
|
|
30655
|
+
symbol: reward.symbol,
|
|
30656
|
+
amount: Amount.fromJSON(reward.amount),
|
|
30657
|
+
};
|
|
30658
|
+
}
|
|
30659
|
+
function assertNever(value) {
|
|
30660
|
+
throw new KitError({
|
|
30661
|
+
...EarnError.INTERNAL_ERROR,
|
|
30662
|
+
recoverability: 'FATAL',
|
|
30663
|
+
message: `Unhandled PnL status: ${JSON.stringify(value)}`,
|
|
30664
|
+
cause: {
|
|
30665
|
+
trace: value,
|
|
30666
|
+
},
|
|
30667
|
+
});
|
|
30668
|
+
}
|
|
30669
|
+
function toPositionPnL(data) {
|
|
30670
|
+
switch (data.status) {
|
|
30671
|
+
case 'available':
|
|
30672
|
+
return {
|
|
30673
|
+
status: 'available',
|
|
30674
|
+
principalDeposited: Amount.fromJSON(data.principalDeposited),
|
|
30675
|
+
totalYieldEarned: Amount.fromJSON(data.totalYieldEarned),
|
|
30676
|
+
};
|
|
30677
|
+
case 'pending':
|
|
30678
|
+
return { status: 'pending' };
|
|
30679
|
+
case 'unavailable':
|
|
30680
|
+
return { status: 'unavailable', reason: data.reason };
|
|
30681
|
+
default:
|
|
30682
|
+
return assertNever(data);
|
|
30683
|
+
}
|
|
30684
|
+
}
|
|
30685
|
+
function toPositionInfo(data) {
|
|
30686
|
+
const { currentBalance, shares, pnl, accruedRewards = [], ...position } = data;
|
|
30687
|
+
const chain = toSdkChain(position.chain);
|
|
30688
|
+
if (chain === undefined) {
|
|
30689
|
+
throw new KitError({
|
|
30690
|
+
...EarnError.INTERNAL_ERROR,
|
|
30691
|
+
recoverability: 'FATAL',
|
|
30692
|
+
message: `Unsupported Earn Service chain: ${position.chain}`,
|
|
30693
|
+
cause: {
|
|
30694
|
+
trace: {
|
|
30695
|
+
chain: position.chain,
|
|
30696
|
+
},
|
|
30697
|
+
},
|
|
30698
|
+
});
|
|
30699
|
+
}
|
|
30700
|
+
return {
|
|
30701
|
+
...position,
|
|
30702
|
+
chain,
|
|
30703
|
+
currentBalance: Amount.fromJSON(currentBalance),
|
|
30704
|
+
shares: Amount.fromJSON(shares),
|
|
30705
|
+
pnl: toPositionPnL(pnl),
|
|
30706
|
+
accruedRewards: accruedRewards.map(toAccruedReward),
|
|
30707
|
+
};
|
|
30708
|
+
}
|
|
30709
|
+
/**
|
|
30710
|
+
* Fetch a user's vault position from the Earn Service API.
|
|
30711
|
+
*
|
|
30712
|
+
* Call `GET /v1/earnKit/position/{address}` with the provided chain
|
|
30713
|
+
* and vault address as query parameters.
|
|
30714
|
+
*
|
|
30715
|
+
* @param params - Position query parameters
|
|
30716
|
+
* @returns The user's position information
|
|
30717
|
+
* @throws {@link KitError} When the API call fails
|
|
30718
|
+
*
|
|
30719
|
+
* @internal
|
|
30720
|
+
*/
|
|
30721
|
+
async function fetchPosition(params) {
|
|
30722
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30723
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/position/${encodeURIComponent(params.address)}`, baseUrl);
|
|
30724
|
+
url.searchParams.set('chain', params.chain);
|
|
30725
|
+
url.searchParams.set('vaultAddress', params.vaultAddress);
|
|
30726
|
+
try {
|
|
30727
|
+
const response = await pollApiGet(url.toString(), isPositionResponse, pollingConfig);
|
|
30728
|
+
return toPositionInfo(response.data);
|
|
30729
|
+
}
|
|
30730
|
+
catch (error) {
|
|
30731
|
+
throw parseEarnApiError(error, { operation: 'getPosition' });
|
|
30732
|
+
}
|
|
30733
|
+
}
|
|
30734
|
+
|
|
30735
|
+
/**
|
|
30736
|
+
* Build signed deposit instructions via the Earn Service API.
|
|
30737
|
+
*
|
|
30738
|
+
* Call `POST /v1/earnKit/deposit` with the vault address, amount,
|
|
30739
|
+
* wallet address, and chain. Return EIP-712 signed execution
|
|
30740
|
+
* parameters for on-chain submission.
|
|
30741
|
+
*
|
|
30742
|
+
* @param params - Deposit parameters
|
|
30743
|
+
* @returns Signed execution parameters for the deposit
|
|
30744
|
+
* @throws {@link KitError} When the API call fails
|
|
30745
|
+
*
|
|
30746
|
+
* @internal
|
|
30747
|
+
*/
|
|
30748
|
+
async function fetchDeposit(params) {
|
|
30749
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30750
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/deposit`, baseUrl);
|
|
30751
|
+
const requestBody = {
|
|
30752
|
+
vaultAddress: params.vaultAddress,
|
|
30753
|
+
amount: params.amount,
|
|
30754
|
+
address: params.address,
|
|
30755
|
+
chain: params.chain,
|
|
30756
|
+
};
|
|
30757
|
+
try {
|
|
30758
|
+
const response = await pollApiPost(url.toString(), requestBody, isDepositResponse, pollingConfig);
|
|
30759
|
+
return response.data;
|
|
30760
|
+
}
|
|
30761
|
+
catch (error) {
|
|
30762
|
+
throw parseEarnApiError(error, { operation: 'deposit' });
|
|
30763
|
+
}
|
|
30764
|
+
}
|
|
30765
|
+
|
|
30766
|
+
/**
|
|
30767
|
+
* Build signed withdrawal instructions via the Earn Service API.
|
|
30768
|
+
*
|
|
30769
|
+
* Call `POST /v1/earnKit/withdraw` with the vault address, amount,
|
|
30770
|
+
* wallet address, and chain. Return EIP-712 signed execution
|
|
30771
|
+
* parameters for on-chain submission.
|
|
30772
|
+
*
|
|
30773
|
+
* @param params - Withdrawal parameters
|
|
30774
|
+
* @returns Signed execution parameters for the withdrawal
|
|
30775
|
+
* @throws {@link KitError} When the API call fails
|
|
30776
|
+
*
|
|
30777
|
+
* @internal
|
|
30778
|
+
*/
|
|
30779
|
+
async function fetchWithdraw(params) {
|
|
30780
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30781
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/withdraw`, baseUrl);
|
|
30782
|
+
const requestBody = {
|
|
30783
|
+
vaultAddress: params.vaultAddress,
|
|
30784
|
+
amount: params.amount,
|
|
30785
|
+
address: params.address,
|
|
30786
|
+
chain: params.chain,
|
|
30787
|
+
};
|
|
30788
|
+
try {
|
|
30789
|
+
const response = await pollApiPost(url.toString(), requestBody, isWithdrawResponse, pollingConfig);
|
|
30790
|
+
return response.data;
|
|
30791
|
+
}
|
|
30792
|
+
catch (error) {
|
|
30793
|
+
throw parseEarnApiError(error, { operation: 'withdraw' });
|
|
30794
|
+
}
|
|
30795
|
+
}
|
|
30796
|
+
|
|
30797
|
+
function toClaimedAmount(reward) {
|
|
30798
|
+
return {
|
|
30799
|
+
address: reward.token,
|
|
30800
|
+
symbol: reward.symbol,
|
|
30801
|
+
amount: Amount.fromJSON(reward.amount),
|
|
30802
|
+
};
|
|
30803
|
+
}
|
|
30804
|
+
/**
|
|
30805
|
+
* Build signed claim rewards instructions via the Earn Service API.
|
|
30806
|
+
*
|
|
30807
|
+
* Call `POST /v1/earnKit/claimRewards` with the wallet address, chain, and
|
|
30808
|
+
* vault address. Return EIP-712 signed execution parameters for on-chain
|
|
30809
|
+
* submission. When no rewards are claimable, return an empty rewards array
|
|
30810
|
+
* without execution parameters.
|
|
30811
|
+
*
|
|
30812
|
+
* @param params - Claim rewards parameters
|
|
30813
|
+
* @returns Signed execution parameters and reward details
|
|
30814
|
+
* @throws {@link KitError} When the API call fails
|
|
30815
|
+
*
|
|
30816
|
+
* @internal
|
|
30817
|
+
*/
|
|
30818
|
+
async function fetchClaimRewards(params) {
|
|
30819
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30820
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/claimRewards`, baseUrl);
|
|
30821
|
+
const requestBody = {
|
|
30822
|
+
address: params.address,
|
|
30823
|
+
chain: params.chain,
|
|
30824
|
+
vaultAddress: params.vaultAddress,
|
|
30825
|
+
};
|
|
30826
|
+
try {
|
|
30827
|
+
const response = await pollApiPost(url.toString(), requestBody, isClaimRewardsResponse, pollingConfig);
|
|
30828
|
+
const { rewards, executionParams, signature } = response.data;
|
|
30829
|
+
return {
|
|
30830
|
+
rewards: rewards.map(toClaimedAmount),
|
|
30831
|
+
...(executionParams === undefined ? {} : { executionParams }),
|
|
30832
|
+
...(signature === undefined ? {} : { signature }),
|
|
30833
|
+
};
|
|
30834
|
+
}
|
|
30835
|
+
catch (error) {
|
|
30836
|
+
throw parseEarnApiError(error, { operation: 'claimRewards' });
|
|
30837
|
+
}
|
|
30838
|
+
}
|
|
30839
|
+
|
|
30840
|
+
function toDepositQuoteInfo(data) {
|
|
30841
|
+
return {
|
|
30842
|
+
vaultAddress: data.vaultAddress,
|
|
30843
|
+
vaultName: data.vaultName,
|
|
30844
|
+
deposit: {
|
|
30845
|
+
symbol: data.asset,
|
|
30846
|
+
amount: Amount.fromJSON(data.depositAmount),
|
|
30847
|
+
},
|
|
30848
|
+
expectedShares: {
|
|
30849
|
+
symbol: VAULT_SHARE_SYMBOL,
|
|
30850
|
+
address: data.vaultAddress,
|
|
30851
|
+
amount: Amount.fromJSON(data.expectedShares),
|
|
30852
|
+
},
|
|
30853
|
+
sharePrice: data.sharePrice,
|
|
30854
|
+
currentApy: data.currentApy,
|
|
30855
|
+
fees: [],
|
|
30856
|
+
};
|
|
30857
|
+
}
|
|
30858
|
+
/**
|
|
30859
|
+
* Fetch a deposit quote from the Earn Service API.
|
|
30860
|
+
*
|
|
30861
|
+
* Call `POST /v1/earnKit/deposit/quote` with the vault address, amount,
|
|
30862
|
+
* wallet address, and chain. Return informational quote data including
|
|
30863
|
+
* expected shares, share price, and APY.
|
|
30864
|
+
*
|
|
30865
|
+
* @param params - Deposit quote parameters
|
|
30866
|
+
* @returns Deposit quote information
|
|
30867
|
+
* @throws {@link KitError} When the API call fails
|
|
30868
|
+
*
|
|
30869
|
+
* @internal
|
|
30870
|
+
*/
|
|
30871
|
+
async function fetchDepositQuote(params) {
|
|
30872
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30873
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/deposit/quote`, baseUrl);
|
|
30874
|
+
const requestBody = {
|
|
30875
|
+
vaultAddress: params.vaultAddress,
|
|
30876
|
+
amount: params.amount,
|
|
30877
|
+
address: params.address,
|
|
30878
|
+
chain: params.chain,
|
|
30879
|
+
};
|
|
30880
|
+
try {
|
|
30881
|
+
const response = await pollApiPost(url.toString(), requestBody, isDepositQuoteResponse, pollingConfig);
|
|
30882
|
+
return toDepositQuoteInfo(response.data);
|
|
30883
|
+
}
|
|
30884
|
+
catch (error) {
|
|
30885
|
+
throw parseEarnApiError(error, { operation: 'getDepositQuote' });
|
|
30886
|
+
}
|
|
30887
|
+
}
|
|
30888
|
+
|
|
30889
|
+
function toWithdrawalQuoteInfo(data) {
|
|
30890
|
+
return {
|
|
30891
|
+
vaultAddress: data.vaultAddress,
|
|
30892
|
+
vaultName: data.vaultName,
|
|
30893
|
+
withdrawal: {
|
|
30894
|
+
symbol: data.asset,
|
|
30895
|
+
amount: Amount.fromJSON(data.withdrawAmount),
|
|
30896
|
+
},
|
|
30897
|
+
sharesToRedeem: {
|
|
30898
|
+
symbol: VAULT_SHARE_SYMBOL,
|
|
30899
|
+
address: data.vaultAddress,
|
|
30900
|
+
amount: Amount.fromJSON(data.sharesToRedeem),
|
|
30901
|
+
},
|
|
30902
|
+
sharePrice: data.sharePrice,
|
|
30903
|
+
maxWithdrawable: {
|
|
30904
|
+
symbol: data.asset,
|
|
30905
|
+
amount: Amount.fromJSON(data.maxWithdrawable),
|
|
30906
|
+
},
|
|
30907
|
+
fees: data.fees.map((fee) => ({
|
|
30908
|
+
symbol: fee.token,
|
|
30909
|
+
amount: Amount.fromJSON(fee.amount),
|
|
30910
|
+
})),
|
|
30911
|
+
// Wire format uses `warnings`, but the SDK surface uses
|
|
30912
|
+
// `earnKitWarnings` to match the precedent set by `VaultInfo` —
|
|
30913
|
+
// `warnings` is reserved for the structured `VaultWarning` shape.
|
|
30914
|
+
...(data.warnings !== undefined && { earnKitWarnings: data.warnings }),
|
|
30915
|
+
};
|
|
30916
|
+
}
|
|
30917
|
+
/**
|
|
30918
|
+
* Fetch a withdrawal quote from the Earn Service API.
|
|
30919
|
+
*
|
|
30920
|
+
* Call `POST /v1/earnKit/withdrawal/quote` with the vault address, amount,
|
|
30921
|
+
* wallet address, and chain. Return informational quote data including
|
|
30922
|
+
* shares to redeem, max withdrawable, and fees.
|
|
30923
|
+
*
|
|
30924
|
+
* @param params - Withdrawal quote parameters
|
|
30925
|
+
* @returns Withdrawal quote information
|
|
30926
|
+
* @throws {@link KitError} When the API call fails
|
|
30927
|
+
*
|
|
30928
|
+
* @internal
|
|
30929
|
+
*/
|
|
30930
|
+
async function fetchWithdrawalQuote(params) {
|
|
30931
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30932
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/withdrawal/quote`, baseUrl);
|
|
30933
|
+
const requestBody = {
|
|
30934
|
+
vaultAddress: params.vaultAddress,
|
|
30935
|
+
amount: params.amount,
|
|
30936
|
+
address: params.address,
|
|
30937
|
+
chain: params.chain,
|
|
30938
|
+
};
|
|
30939
|
+
try {
|
|
30940
|
+
const response = await pollApiPost(url.toString(), requestBody, isWithdrawalQuoteResponse, pollingConfig);
|
|
30941
|
+
return toWithdrawalQuoteInfo(response.data);
|
|
30942
|
+
}
|
|
30943
|
+
catch (error) {
|
|
30944
|
+
throw parseEarnApiError(error, { operation: 'getWithdrawalQuote' });
|
|
30945
|
+
}
|
|
30946
|
+
}
|
|
30947
|
+
|
|
30948
|
+
/**
|
|
30949
|
+
* Fetch a claim rewards quote from the Earn Service API.
|
|
30950
|
+
*
|
|
30951
|
+
* Call `POST /v1/earnKit/claimRewards/quote` with the wallet address,
|
|
30952
|
+
* chain, and vault address. Return informational quote data including
|
|
30953
|
+
* claimable reward details.
|
|
30954
|
+
*
|
|
30955
|
+
* @param params - Claim rewards quote parameters
|
|
30956
|
+
* @returns Claim rewards quote information
|
|
30957
|
+
* @throws {@link KitError} When the API call fails
|
|
30958
|
+
*
|
|
30959
|
+
* @internal
|
|
30960
|
+
*/
|
|
30961
|
+
async function fetchClaimRewardsQuote(params) {
|
|
30962
|
+
const { pollingConfig, baseUrl } = buildConfig(params.config);
|
|
30963
|
+
const url = new URL(`${EARN_KIT_API_PREFIX}/claimRewards/quote`, baseUrl);
|
|
30964
|
+
const requestBody = {
|
|
30965
|
+
vaultAddress: params.vaultAddress,
|
|
30966
|
+
address: params.address,
|
|
30967
|
+
chain: params.chain,
|
|
30968
|
+
};
|
|
30969
|
+
try {
|
|
30970
|
+
const response = await pollApiPost(url.toString(), requestBody, isClaimRewardsQuoteResponse, pollingConfig);
|
|
30971
|
+
return {
|
|
30972
|
+
rewards: response.data.rewards.map((r) => ({
|
|
30973
|
+
symbol: r.symbol,
|
|
30974
|
+
amount: Amount.fromJSON(r.amount),
|
|
30975
|
+
address: r.token,
|
|
30976
|
+
})),
|
|
30977
|
+
};
|
|
30978
|
+
}
|
|
30979
|
+
catch (error) {
|
|
30980
|
+
throw parseEarnApiError(error, { operation: 'getClaimRewardsQuote' });
|
|
30981
|
+
}
|
|
30982
|
+
}
|
|
30983
|
+
|
|
30984
|
+
/**
|
|
30985
|
+
* Earn Service provider for the Circle earn service API.
|
|
30986
|
+
*
|
|
30987
|
+
* Implement the {@link EarningProvider} interface for yield-bearing vault
|
|
30988
|
+
* operations including vault discovery, position queries, deposits,
|
|
30989
|
+
* withdrawals, and reward claiming.
|
|
30990
|
+
*
|
|
30991
|
+
* @example
|
|
30992
|
+
* ```typescript
|
|
30993
|
+
* import { EarnServiceProvider } from '@circle-fin/provider-earn-service'
|
|
30994
|
+
*
|
|
30995
|
+
* // Permissionless mode
|
|
30996
|
+
* const provider = new EarnServiceProvider()
|
|
30997
|
+
*
|
|
30998
|
+
* // Permissioned mode with Kit Key
|
|
30999
|
+
* const provider = new EarnServiceProvider({
|
|
31000
|
+
* kitKey: 'KIT_KEY:keyId:keySecret',
|
|
31001
|
+
* })
|
|
31002
|
+
*
|
|
31003
|
+
* // Custom base URL for testing
|
|
31004
|
+
* const provider = new EarnServiceProvider({
|
|
31005
|
+
* baseUrl: 'https://api-staging.circle.com',
|
|
31006
|
+
* })
|
|
31007
|
+
*
|
|
31008
|
+
* const result = await provider.getVaults({
|
|
31009
|
+
* vaults: [
|
|
31010
|
+
* { chain: 'Arc_Testnet', vaultAddress: '0x8eB67...' },
|
|
31011
|
+
* ],
|
|
31012
|
+
* })
|
|
31013
|
+
* ```
|
|
31014
|
+
*/
|
|
31015
|
+
class EarnServiceProvider {
|
|
31016
|
+
/** {@inheritdoc} */
|
|
31017
|
+
name = 'EarnService';
|
|
31018
|
+
/** {@inheritdoc} */
|
|
31019
|
+
supportedChains = Object.keys(CHAIN_TO_API).map((chain) => resolveChainIdentifier(chain));
|
|
31020
|
+
defaultConfig;
|
|
31021
|
+
/**
|
|
31022
|
+
* Create a new EarnServiceProvider.
|
|
31023
|
+
*
|
|
31024
|
+
* @param config - Optional default configuration applied to all operations.
|
|
31025
|
+
* Per-operation config takes precedence when provided.
|
|
31026
|
+
*/
|
|
31027
|
+
constructor(config) {
|
|
31028
|
+
this.defaultConfig = config;
|
|
31029
|
+
}
|
|
31030
|
+
resolveConfig(config) {
|
|
31031
|
+
const resolvedConfig = this.defaultConfig === undefined
|
|
31032
|
+
? config
|
|
31033
|
+
: { ...this.defaultConfig, ...config };
|
|
31034
|
+
return resolvedConfig;
|
|
31035
|
+
}
|
|
31036
|
+
/** {@inheritdoc} */
|
|
31037
|
+
async getVaults(params) {
|
|
31038
|
+
const config = this.resolveConfig(params.config);
|
|
31039
|
+
return fetchVaults({
|
|
31040
|
+
vaults: params.vaults,
|
|
31041
|
+
config,
|
|
31042
|
+
});
|
|
31043
|
+
}
|
|
31044
|
+
/** {@inheritdoc} */
|
|
31045
|
+
async getPosition(params) {
|
|
31046
|
+
const config = this.resolveConfig(params.config);
|
|
31047
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
31048
|
+
return fetchPosition({
|
|
31049
|
+
address,
|
|
31050
|
+
chain,
|
|
31051
|
+
vaultAddress: params.vaultAddress,
|
|
31052
|
+
config,
|
|
31053
|
+
});
|
|
31054
|
+
}
|
|
31055
|
+
/** {@inheritdoc} */
|
|
31056
|
+
async deposit(params) {
|
|
31057
|
+
const config = this.resolveConfig(params.config);
|
|
31058
|
+
const { address, chain: apiChain, chainDefinition: chain, } = await resolveAdapterContext(params.from);
|
|
31059
|
+
const adapterContractAddress = requireAdapterContract(chain);
|
|
31060
|
+
const rawUsdcAddress = chain.usdcAddress;
|
|
31061
|
+
if (rawUsdcAddress === null) {
|
|
31062
|
+
throw createUnsupportedTokenError('USDC', chain.name);
|
|
31063
|
+
}
|
|
31064
|
+
const usdcAddress = assertHexAddress('chain.usdcAddress', rawUsdcAddress, `USDC address for chain ${chain.name} must be a 0x-prefixed 20-byte hex address.`);
|
|
31065
|
+
const { executionParams, signature } = await fetchDeposit({
|
|
31066
|
+
vaultAddress: params.vaultAddress,
|
|
31067
|
+
amount: params.amount,
|
|
31068
|
+
address,
|
|
31069
|
+
chain: apiChain,
|
|
31070
|
+
config,
|
|
31071
|
+
});
|
|
31072
|
+
validateExecutionDeadline(executionParams);
|
|
31073
|
+
const { adapter } = params.from;
|
|
31074
|
+
const tokenInputs = buildEarnTokenInputs(executionParams, usdcAddress);
|
|
31075
|
+
const approvalToken = tokenInputs[0]?.token;
|
|
31076
|
+
if (approvalToken !== undefined) {
|
|
31077
|
+
await approveMaxIfNeeded({
|
|
31078
|
+
adapter,
|
|
31079
|
+
chain,
|
|
31080
|
+
tokenAddress: approvalToken,
|
|
31081
|
+
delegate: adapterContractAddress,
|
|
31082
|
+
address,
|
|
31083
|
+
revertMessage: 'USDC approval reverted on-chain',
|
|
31084
|
+
});
|
|
31085
|
+
}
|
|
31086
|
+
const { txHash, explorerUrl } = await executeEarnAction({
|
|
31087
|
+
adapter,
|
|
31088
|
+
chain,
|
|
31089
|
+
address,
|
|
31090
|
+
actionKey: 'earn.deposit',
|
|
31091
|
+
actionParams: {
|
|
31092
|
+
executeParams: executionParams,
|
|
31093
|
+
tokenInputs,
|
|
31094
|
+
signature,
|
|
31095
|
+
},
|
|
31096
|
+
revertMessage: 'Earn deposit reverted on-chain',
|
|
31097
|
+
});
|
|
31098
|
+
return {
|
|
31099
|
+
txHash,
|
|
31100
|
+
explorerUrl,
|
|
31101
|
+
vaultAddress: params.vaultAddress,
|
|
31102
|
+
amount: params.amount,
|
|
31103
|
+
};
|
|
31104
|
+
}
|
|
31105
|
+
/** {@inheritdoc} */
|
|
31106
|
+
async withdraw(params) {
|
|
31107
|
+
const config = this.resolveConfig(params.config);
|
|
31108
|
+
const { address, chain: apiChain, chainDefinition: chain, } = await resolveAdapterContext(params.from);
|
|
31109
|
+
const adapterContractAddress = requireAdapterContract(chain);
|
|
31110
|
+
const vaultAddress = assertHexAddress('vaultAddress', params.vaultAddress, 'Vault address must be a 0x-prefixed 20-byte hex address.');
|
|
31111
|
+
const { executionParams, signature } = await fetchWithdraw({
|
|
31112
|
+
vaultAddress,
|
|
31113
|
+
amount: params.amount,
|
|
31114
|
+
address,
|
|
31115
|
+
chain: apiChain,
|
|
31116
|
+
config,
|
|
31117
|
+
});
|
|
31118
|
+
validateExecutionDeadline(executionParams);
|
|
31119
|
+
const { adapter } = params.from;
|
|
31120
|
+
const tokenInputs = buildEarnTokenInputs(executionParams, vaultAddress);
|
|
31121
|
+
const approvalToken = tokenInputs[0]?.token;
|
|
31122
|
+
if (approvalToken !== undefined) {
|
|
31123
|
+
await approveMaxIfNeeded({
|
|
31124
|
+
adapter,
|
|
31125
|
+
chain,
|
|
31126
|
+
tokenAddress: approvalToken,
|
|
31127
|
+
delegate: adapterContractAddress,
|
|
31128
|
+
address,
|
|
31129
|
+
revertMessage: 'Vault share token approval reverted on-chain',
|
|
31130
|
+
});
|
|
31131
|
+
}
|
|
31132
|
+
const { txHash, explorerUrl } = await executeEarnAction({
|
|
31133
|
+
adapter,
|
|
31134
|
+
chain,
|
|
31135
|
+
address,
|
|
31136
|
+
actionKey: 'earn.withdraw',
|
|
31137
|
+
actionParams: {
|
|
31138
|
+
executeParams: executionParams,
|
|
31139
|
+
tokenInputs,
|
|
31140
|
+
signature,
|
|
31141
|
+
},
|
|
31142
|
+
revertMessage: 'Earn withdraw reverted on-chain',
|
|
31143
|
+
});
|
|
31144
|
+
return {
|
|
31145
|
+
txHash,
|
|
31146
|
+
explorerUrl,
|
|
31147
|
+
vaultAddress,
|
|
31148
|
+
amount: params.amount,
|
|
31149
|
+
};
|
|
31150
|
+
}
|
|
31151
|
+
/** {@inheritdoc} */
|
|
31152
|
+
async claimRewards(params) {
|
|
31153
|
+
const config = this.resolveConfig(params.config);
|
|
31154
|
+
const { address, chain: apiChain, chainDefinition: chain, } = await resolveAdapterContext(params.from);
|
|
31155
|
+
// Claim rewards has no approval step, but still requires adapter support.
|
|
31156
|
+
requireAdapterContract(chain);
|
|
31157
|
+
const { rewards, executionParams, signature } = await fetchClaimRewards({
|
|
31158
|
+
address,
|
|
31159
|
+
chain: apiChain,
|
|
31160
|
+
vaultAddress: params.vaultAddress,
|
|
31161
|
+
config,
|
|
31162
|
+
});
|
|
31163
|
+
const nothingToClaim = rewards.length === 0;
|
|
31164
|
+
if (nothingToClaim) {
|
|
31165
|
+
return { status: 'no_rewards', rewards: [] };
|
|
31166
|
+
}
|
|
31167
|
+
const missingExecutionParams = executionParams === undefined;
|
|
31168
|
+
const missingSignature = signature === undefined;
|
|
31169
|
+
if (missingExecutionParams || missingSignature) {
|
|
31170
|
+
throw new KitError({
|
|
31171
|
+
...EarnError.INTERNAL_ERROR,
|
|
31172
|
+
recoverability: 'RETRYABLE',
|
|
31173
|
+
message: 'Claim rewards response must include executionParams and signature when rewards are claimable',
|
|
31174
|
+
cause: {
|
|
31175
|
+
trace: {
|
|
31176
|
+
rewardsCount: rewards.length,
|
|
31177
|
+
missingExecutionParams,
|
|
31178
|
+
missingSignature,
|
|
31179
|
+
},
|
|
31180
|
+
},
|
|
31181
|
+
});
|
|
31182
|
+
}
|
|
31183
|
+
validateExecutionDeadline(executionParams);
|
|
31184
|
+
const { txHash, explorerUrl } = await executeEarnAction({
|
|
31185
|
+
adapter: params.from.adapter,
|
|
31186
|
+
chain,
|
|
31187
|
+
address,
|
|
31188
|
+
actionKey: 'earn.claimRewards',
|
|
31189
|
+
actionParams: {
|
|
31190
|
+
executeParams: executionParams,
|
|
31191
|
+
tokenInputs: [],
|
|
31192
|
+
signature,
|
|
31193
|
+
},
|
|
31194
|
+
revertMessage: 'Earn claim rewards reverted on-chain',
|
|
31195
|
+
});
|
|
31196
|
+
return { status: 'claimed', rewards, txHash, explorerUrl };
|
|
31197
|
+
}
|
|
31198
|
+
/** {@inheritdoc} */
|
|
31199
|
+
async getDepositQuote(params) {
|
|
31200
|
+
const config = this.resolveConfig(params.config);
|
|
31201
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
31202
|
+
return fetchDepositQuote({
|
|
31203
|
+
vaultAddress: params.vaultAddress,
|
|
31204
|
+
amount: params.amount,
|
|
31205
|
+
address,
|
|
31206
|
+
chain,
|
|
31207
|
+
config,
|
|
31208
|
+
});
|
|
31209
|
+
}
|
|
31210
|
+
/** {@inheritdoc} */
|
|
31211
|
+
async getWithdrawalQuote(params) {
|
|
31212
|
+
const config = this.resolveConfig(params.config);
|
|
31213
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
31214
|
+
return fetchWithdrawalQuote({
|
|
31215
|
+
vaultAddress: params.vaultAddress,
|
|
31216
|
+
amount: params.amount,
|
|
31217
|
+
address,
|
|
31218
|
+
chain,
|
|
31219
|
+
config,
|
|
31220
|
+
});
|
|
31221
|
+
}
|
|
31222
|
+
/** {@inheritdoc} */
|
|
31223
|
+
async getClaimRewardsQuote(params) {
|
|
31224
|
+
const config = this.resolveConfig(params.config);
|
|
31225
|
+
const { address, chain } = await resolveAdapterContext(params.from);
|
|
31226
|
+
return fetchClaimRewardsQuote({
|
|
31227
|
+
vaultAddress: params.vaultAddress,
|
|
31228
|
+
address,
|
|
31229
|
+
chain,
|
|
31230
|
+
config,
|
|
31231
|
+
});
|
|
31232
|
+
}
|
|
31233
|
+
}
|
|
31234
|
+
|
|
31235
|
+
/**
|
|
31236
|
+
* The default providers used when no custom providers are specified.
|
|
31237
|
+
*
|
|
31238
|
+
* @returns An array containing the default EarnServiceProvider
|
|
31239
|
+
* @internal
|
|
31240
|
+
*/
|
|
31241
|
+
const getDefaultProviders$1 = () => [new EarnServiceProvider()];
|
|
31242
|
+
/**
|
|
31243
|
+
* Create an EarnKit context with validated configuration.
|
|
31244
|
+
*
|
|
31245
|
+
* Initialize an EarnKitContext with default providers and optional
|
|
31246
|
+
* custom configuration. Custom and default providers are merged,
|
|
31247
|
+
* preserving their exact types for type safety.
|
|
31248
|
+
*
|
|
31249
|
+
* @typeParam TExtraProviders - Array type of additional earn providers
|
|
31250
|
+
* @param config - Optional configuration for the EarnKit context
|
|
31251
|
+
* @returns A fully initialized EarnKitContext ready for earn operations
|
|
31252
|
+
*
|
|
31253
|
+
* @example
|
|
31254
|
+
* ```typescript
|
|
31255
|
+
* import { createEarnKitContext } from '@circle-fin/earn-kit'
|
|
31256
|
+
*
|
|
31257
|
+
* // Create context with defaults
|
|
31258
|
+
* const context = createEarnKitContext()
|
|
31259
|
+
* ```
|
|
31260
|
+
*
|
|
31261
|
+
* @example
|
|
31262
|
+
* ```typescript
|
|
31263
|
+
* import { createEarnKitContext } from '@circle-fin/earn-kit'
|
|
31264
|
+
*
|
|
31265
|
+
* // Create context with custom providers
|
|
31266
|
+
* const context = createEarnKitContext({
|
|
31267
|
+
* providers: [myCustomEarnProvider],
|
|
31268
|
+
* })
|
|
31269
|
+
* ```
|
|
31270
|
+
*/
|
|
31271
|
+
function createEarnKitContext(config = {}) {
|
|
31272
|
+
const defaultProviders = getDefaultProviders$1();
|
|
31273
|
+
const providers = [...(config.providers ?? []), ...defaultProviders];
|
|
31274
|
+
const context = {
|
|
31275
|
+
providers,
|
|
31276
|
+
};
|
|
31277
|
+
return context;
|
|
31278
|
+
}
|
|
31279
|
+
|
|
31280
|
+
/**
|
|
31281
|
+
* Symbol used to track that assertEarnParams has validated an object.
|
|
31282
|
+
* @internal
|
|
31283
|
+
*/
|
|
31284
|
+
const ASSERT_EARN_PARAMS_SYMBOL = Symbol('assertEarnParams');
|
|
31285
|
+
/**
|
|
31286
|
+
* Assert that the provided value conforms to the given earn params schema.
|
|
31287
|
+
*
|
|
31288
|
+
* Validate earn parameters using the provided Zod schema and track
|
|
31289
|
+
* validation state to avoid duplicate checks. Throw a structured
|
|
31290
|
+
* error with detailed validation messages if any parameter is invalid.
|
|
31291
|
+
*
|
|
31292
|
+
* @typeParam T - The expected type after validation
|
|
31293
|
+
* @param params - The earn parameters to validate
|
|
31294
|
+
* @param schema - The Zod schema to validate against
|
|
31295
|
+
* @throws {@link KitError} If the parameters fail validation
|
|
31296
|
+
*
|
|
31297
|
+
* @example
|
|
31298
|
+
* ```typescript
|
|
31299
|
+
* import { assertEarnParams, depositParamsSchema } from '@circle-fin/earn-kit'
|
|
31300
|
+
*
|
|
31301
|
+
* assertEarnParams(params, depositParamsSchema)
|
|
31302
|
+
* ```
|
|
31303
|
+
*/
|
|
31304
|
+
function assertEarnParams(params, schema) {
|
|
31305
|
+
validateWithStateTracking(params, schema, 'earn parameters', ASSERT_EARN_PARAMS_SYMBOL);
|
|
31306
|
+
}
|
|
31307
|
+
|
|
31308
|
+
function findProvider(context, chain, operation = 'earn') {
|
|
31309
|
+
let fallback;
|
|
31310
|
+
for (const provider of context.providers) {
|
|
31311
|
+
fallback ??= provider;
|
|
31312
|
+
if (provider.supportedChains.length === 0)
|
|
31313
|
+
continue;
|
|
31314
|
+
if (chain === undefined ||
|
|
31315
|
+
provider.supportedChains.some((c) => c.chain === chain.chain)) {
|
|
31316
|
+
return provider;
|
|
31317
|
+
}
|
|
31318
|
+
}
|
|
31319
|
+
if (fallback === undefined) {
|
|
31320
|
+
throw createValidationFailedError$1('context.providers', [], 'No earn providers configured');
|
|
31321
|
+
}
|
|
31322
|
+
if (chain !== undefined) {
|
|
31323
|
+
throw createUnsupportedEarnRouteError(operation, chain.name);
|
|
31324
|
+
}
|
|
31325
|
+
return fallback;
|
|
31326
|
+
}
|
|
31327
|
+
|
|
31328
|
+
/**
|
|
31329
|
+
* Format a provider amount object as a human-readable decimal string.
|
|
31330
|
+
*
|
|
31331
|
+
* The kit result surface intentionally exposes only the decimal string value,
|
|
31332
|
+
* so nested provider amount metadata is not retained at this boundary.
|
|
31333
|
+
*
|
|
31334
|
+
* @param amount - Provider amount object to format
|
|
31335
|
+
* @returns Human-readable decimal amount string
|
|
31336
|
+
*/
|
|
31337
|
+
function formatAmount$1(amount) {
|
|
31338
|
+
return formatUnits(amount.raw.toString(), amount.decimals);
|
|
31339
|
+
}
|
|
31340
|
+
function formatAssetAmount(assetAmount) {
|
|
31341
|
+
const { amount, ...rest } = assetAmount;
|
|
31342
|
+
return {
|
|
31343
|
+
...rest,
|
|
31344
|
+
amount: formatAmount$1(amount),
|
|
31345
|
+
};
|
|
31346
|
+
}
|
|
31347
|
+
function formatClaimedAmount(claimedAmount) {
|
|
31348
|
+
const { amount, ...rest } = claimedAmount;
|
|
31349
|
+
return {
|
|
31350
|
+
...rest,
|
|
31351
|
+
amount: formatAmount$1(amount),
|
|
31352
|
+
};
|
|
31353
|
+
}
|
|
31354
|
+
function formatAccruedReward(reward) {
|
|
31355
|
+
const { amount, ...rest } = reward;
|
|
31356
|
+
return {
|
|
31357
|
+
...rest,
|
|
31358
|
+
amount: formatAmount$1(amount),
|
|
31359
|
+
};
|
|
31360
|
+
}
|
|
31361
|
+
function formatPositionPnL(pnl) {
|
|
31362
|
+
if (pnl.status !== 'available') {
|
|
31363
|
+
return pnl;
|
|
31364
|
+
}
|
|
31365
|
+
return {
|
|
31366
|
+
...pnl,
|
|
31367
|
+
principalDeposited: formatAmount$1(pnl.principalDeposited),
|
|
31368
|
+
totalYieldEarned: formatAmount$1(pnl.totalYieldEarned),
|
|
31369
|
+
};
|
|
31370
|
+
}
|
|
31371
|
+
/**
|
|
31372
|
+
* Convert provider vault info into an EarnKit vault result.
|
|
31373
|
+
*
|
|
31374
|
+
* @param vault - Provider vault info with raw amount objects
|
|
31375
|
+
* @returns Vault info with total deposits and liquidity formatted as strings
|
|
31376
|
+
*/
|
|
31377
|
+
function formatVaultInfo(vault) {
|
|
31378
|
+
const { totalDeposits, liquidity, ...rest } = vault;
|
|
31379
|
+
return {
|
|
31380
|
+
...rest,
|
|
31381
|
+
totalDeposits: formatAmount$1(totalDeposits),
|
|
31382
|
+
liquidity: formatAmount$1(liquidity),
|
|
31383
|
+
};
|
|
31384
|
+
}
|
|
31385
|
+
/**
|
|
31386
|
+
* Convert a provider vault lookup result into an EarnKit result.
|
|
31387
|
+
*
|
|
31388
|
+
* @param result - Provider vault lookup result
|
|
31389
|
+
* @returns Vault lookup result with each vault amount formatted as strings
|
|
31390
|
+
*/
|
|
31391
|
+
function formatGetVaultsResult(result) {
|
|
31392
|
+
return {
|
|
31393
|
+
...result,
|
|
31394
|
+
vaults: result.vaults.map(formatVaultInfo),
|
|
31395
|
+
};
|
|
31396
|
+
}
|
|
31397
|
+
/**
|
|
31398
|
+
* Convert provider position info into an EarnKit position result.
|
|
31399
|
+
*
|
|
31400
|
+
* @param position - Provider position info with raw amount objects
|
|
31401
|
+
* @returns Position info with balances, shares, PnL, and rewards formatted as strings
|
|
31402
|
+
*/
|
|
31403
|
+
function formatPositionInfo(position) {
|
|
31404
|
+
const { currentBalance, shares, pnl, accruedRewards, ...rest } = position;
|
|
31405
|
+
return {
|
|
31406
|
+
...rest,
|
|
31407
|
+
currentBalance: formatAmount$1(currentBalance),
|
|
31408
|
+
shares: formatAmount$1(shares),
|
|
31409
|
+
pnl: formatPositionPnL(pnl),
|
|
31410
|
+
accruedRewards: accruedRewards.map(formatAccruedReward),
|
|
31411
|
+
};
|
|
31412
|
+
}
|
|
31413
|
+
/**
|
|
31414
|
+
* Convert a provider deposit quote into an EarnKit deposit quote result.
|
|
31415
|
+
*
|
|
31416
|
+
* @param quote - Provider deposit quote with raw amount objects
|
|
31417
|
+
* @returns Deposit quote with deposit, shares, and fees formatted as strings
|
|
31418
|
+
*/
|
|
31419
|
+
function formatDepositQuoteInfo(quote) {
|
|
31420
|
+
return {
|
|
31421
|
+
...quote,
|
|
31422
|
+
deposit: formatAssetAmount(quote.deposit),
|
|
31423
|
+
expectedShares: formatAssetAmount(quote.expectedShares),
|
|
31424
|
+
fees: quote.fees.map(formatAssetAmount),
|
|
31425
|
+
};
|
|
31426
|
+
}
|
|
31427
|
+
/**
|
|
31428
|
+
* Convert a provider withdrawal quote into an EarnKit withdrawal quote result.
|
|
31429
|
+
*
|
|
31430
|
+
* @param quote - Provider withdrawal quote with raw amount objects
|
|
31431
|
+
* @returns Withdrawal quote with withdrawal, shares, max, and fees formatted as strings
|
|
31432
|
+
*/
|
|
31433
|
+
function formatWithdrawalQuoteInfo(quote) {
|
|
31434
|
+
return {
|
|
31435
|
+
...quote,
|
|
31436
|
+
withdrawal: formatAssetAmount(quote.withdrawal),
|
|
31437
|
+
sharesToRedeem: formatAssetAmount(quote.sharesToRedeem),
|
|
31438
|
+
maxWithdrawable: formatAssetAmount(quote.maxWithdrawable),
|
|
31439
|
+
fees: quote.fees.map(formatAssetAmount),
|
|
31440
|
+
};
|
|
31441
|
+
}
|
|
31442
|
+
/**
|
|
31443
|
+
* Convert a provider claim-rewards quote into an EarnKit quote result.
|
|
31444
|
+
*
|
|
31445
|
+
* @param quote - Provider claim-rewards quote with raw reward amount objects
|
|
31446
|
+
* @returns Claim-rewards quote with rewards formatted as strings
|
|
31447
|
+
*/
|
|
31448
|
+
function formatClaimRewardsQuoteInfo(quote) {
|
|
31449
|
+
return {
|
|
31450
|
+
...quote,
|
|
31451
|
+
rewards: quote.rewards.map(formatAssetAmount),
|
|
31452
|
+
};
|
|
31453
|
+
}
|
|
31454
|
+
/**
|
|
31455
|
+
* Convert a provider claim-rewards result into an EarnKit result.
|
|
31456
|
+
*
|
|
31457
|
+
* @param result - Provider claim-rewards result
|
|
31458
|
+
* @returns Claim-rewards result with claimed reward amounts formatted as strings
|
|
31459
|
+
*/
|
|
31460
|
+
function formatClaimRewardsResult(result) {
|
|
31461
|
+
if (result.status === 'no_rewards') {
|
|
31462
|
+
return result;
|
|
31463
|
+
}
|
|
31464
|
+
return {
|
|
31465
|
+
...result,
|
|
31466
|
+
rewards: result.rewards.map(formatClaimedAmount),
|
|
31467
|
+
};
|
|
31468
|
+
}
|
|
31469
|
+
|
|
31470
|
+
/**
|
|
31471
|
+
* Schema for the adapter context within earn operations.
|
|
31472
|
+
*
|
|
31473
|
+
* Validate that a properly-shaped adapter instance and a valid chain
|
|
31474
|
+
* identifier are provided. The address field is optional (resolved from
|
|
31475
|
+
* the adapter at runtime).
|
|
31476
|
+
*
|
|
31477
|
+
* @internal
|
|
31478
|
+
*/
|
|
31479
|
+
const adapterContextSchema$4 = zod.z.object({
|
|
31480
|
+
adapter: adapterSchema$1,
|
|
31481
|
+
// AdapterContext accepts a wider chain field, but runtime validation must
|
|
31482
|
+
// stay constrained to EarnChain identifiers.
|
|
31483
|
+
chain: earnChainIdentifierSchema,
|
|
31484
|
+
address: zod.z.string().optional(),
|
|
31485
|
+
});
|
|
31486
|
+
/**
|
|
31487
|
+
* Schema for the EarnConfig options.
|
|
31488
|
+
*
|
|
31489
|
+
* Validate the optional Kit Key field using the standard `apiKeySchema`
|
|
31490
|
+
* format (`KIT_KEY:<keyId>:<keySecret>`). When omitted, the SDK
|
|
31491
|
+
* operates in permissionless mode.
|
|
31492
|
+
*
|
|
31493
|
+
* @internal
|
|
31494
|
+
*/
|
|
31495
|
+
const earnConfigSchema = zod.z.object({
|
|
31496
|
+
kitKey: apiKeySchema.optional(),
|
|
31497
|
+
});
|
|
31498
|
+
/**
|
|
31499
|
+
* Schema for validating human-readable decimal amount strings.
|
|
31500
|
+
*
|
|
31501
|
+
* Accept positive decimal strings like '100', '100.50', '0.001'.
|
|
31502
|
+
* Reject zero, negative, and non-numeric strings. Support up to 18
|
|
31503
|
+
* decimal places for maximum token compatibility.
|
|
31504
|
+
*
|
|
31505
|
+
* @internal
|
|
31506
|
+
*/
|
|
31507
|
+
const amountSchema$1 = zod.z
|
|
31508
|
+
.string({ required_error: 'amount is required' })
|
|
31509
|
+
.min(1, 'amount is required')
|
|
31510
|
+
.pipe(createDecimalStringValidator({
|
|
31511
|
+
allowZero: false,
|
|
31512
|
+
regexMessage: AMOUNT_FORMAT_ERROR_MESSAGE,
|
|
31513
|
+
attributeName: 'amount',
|
|
31514
|
+
maxDecimals: 18,
|
|
31515
|
+
})(zod.z.string()));
|
|
31516
|
+
/**
|
|
31517
|
+
* Schema for vault address validation.
|
|
31518
|
+
*
|
|
31519
|
+
* Validate that the vault address is a valid EVM address (0x + 40 hex
|
|
31520
|
+
* chars). EarnKit currently supports EVM vault addresses on Arc Testnet.
|
|
31521
|
+
*
|
|
31522
|
+
* @internal
|
|
31523
|
+
*/
|
|
31524
|
+
const vaultAddressSchema = evmAddressSchema;
|
|
31525
|
+
/**
|
|
31526
|
+
* Validation schema for VaultQuery.
|
|
31527
|
+
*
|
|
31528
|
+
* @example
|
|
31529
|
+
* ```typescript
|
|
31530
|
+
* import { vaultQuerySchema } from '@circle-fin/earn-kit'
|
|
31531
|
+
*
|
|
31532
|
+
* const result = vaultQuerySchema.safeParse({
|
|
31533
|
+
* chain: 'Arc_Testnet',
|
|
31534
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31535
|
+
* })
|
|
31536
|
+
* ```
|
|
31537
|
+
*/
|
|
31538
|
+
const vaultQuerySchema = zod.z.object({
|
|
31539
|
+
chain: earnChainIdentifierSchema,
|
|
31540
|
+
vaultAddress: vaultAddressSchema,
|
|
31541
|
+
});
|
|
31542
|
+
/**
|
|
31543
|
+
* Validation schema for GetVaultsParams.
|
|
31544
|
+
*
|
|
31545
|
+
* @example
|
|
31546
|
+
* ```typescript
|
|
31547
|
+
* import { getVaultsParamsSchema } from '@circle-fin/earn-kit'
|
|
31548
|
+
*
|
|
31549
|
+
* const result = getVaultsParamsSchema.safeParse({
|
|
31550
|
+
* vaults: [
|
|
31551
|
+
* {
|
|
31552
|
+
* chain: 'Arc_Testnet',
|
|
31553
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31554
|
+
* },
|
|
31555
|
+
* ],
|
|
31556
|
+
* })
|
|
31557
|
+
* ```
|
|
31558
|
+
*/
|
|
31559
|
+
const getVaultsParamsSchema = zod.z.object({
|
|
31560
|
+
vaults: zod.z
|
|
31561
|
+
.array(vaultQuerySchema)
|
|
31562
|
+
.min(1, 'at least one vault query is required')
|
|
31563
|
+
.max(20, 'maximum 20 vault queries per request'),
|
|
31564
|
+
config: earnConfigSchema.optional(),
|
|
31565
|
+
});
|
|
31566
|
+
/**
|
|
31567
|
+
* Validation schema for GetPositionParams.
|
|
31568
|
+
*
|
|
31569
|
+
* @example
|
|
31570
|
+
* ```typescript
|
|
31571
|
+
* import { getPositionParamsSchema } from '@circle-fin/earn-kit'
|
|
31572
|
+
*
|
|
31573
|
+
* const result = getPositionParamsSchema.safeParse({
|
|
31574
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31575
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31576
|
+
* })
|
|
31577
|
+
* ```
|
|
31578
|
+
*/
|
|
31579
|
+
const getPositionParamsSchema = zod.z.object({
|
|
31580
|
+
from: adapterContextSchema$4,
|
|
31581
|
+
vaultAddress: vaultAddressSchema,
|
|
31582
|
+
config: earnConfigSchema.optional(),
|
|
31583
|
+
});
|
|
31584
|
+
/**
|
|
31585
|
+
* Validation schema for DepositParams.
|
|
31586
|
+
*
|
|
31587
|
+
* @example
|
|
31588
|
+
* ```typescript
|
|
31589
|
+
* import { depositParamsSchema } from '@circle-fin/earn-kit'
|
|
31590
|
+
*
|
|
31591
|
+
* const result = depositParamsSchema.safeParse({
|
|
31592
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31593
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31594
|
+
* amount: '100.50',
|
|
31595
|
+
* })
|
|
31596
|
+
* ```
|
|
31597
|
+
*/
|
|
31598
|
+
const depositParamsSchema$1 = zod.z.object({
|
|
31599
|
+
from: adapterContextSchema$4,
|
|
31600
|
+
vaultAddress: vaultAddressSchema,
|
|
31601
|
+
amount: amountSchema$1,
|
|
31602
|
+
config: earnConfigSchema.optional(),
|
|
31603
|
+
});
|
|
31604
|
+
/**
|
|
31605
|
+
* Validation schema for WithdrawParams.
|
|
31606
|
+
*
|
|
31607
|
+
* @example
|
|
31608
|
+
* ```typescript
|
|
31609
|
+
* import { withdrawParamsSchema } from '@circle-fin/earn-kit'
|
|
31610
|
+
*
|
|
31611
|
+
* const result = withdrawParamsSchema.safeParse({
|
|
31612
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31613
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31614
|
+
* amount: '50.00',
|
|
31615
|
+
* })
|
|
31616
|
+
* ```
|
|
31617
|
+
*/
|
|
31618
|
+
const withdrawParamsSchema = zod.z.object({
|
|
31619
|
+
from: adapterContextSchema$4,
|
|
31620
|
+
vaultAddress: vaultAddressSchema,
|
|
31621
|
+
amount: amountSchema$1,
|
|
31622
|
+
config: earnConfigSchema.optional(),
|
|
31623
|
+
});
|
|
31624
|
+
/**
|
|
31625
|
+
* Validation schema for ClaimRewardsParams.
|
|
31626
|
+
*
|
|
31627
|
+
* @example
|
|
31628
|
+
* ```typescript
|
|
31629
|
+
* import { claimRewardsParamsSchema } from '@circle-fin/earn-kit'
|
|
31630
|
+
*
|
|
31631
|
+
* const result = claimRewardsParamsSchema.safeParse({
|
|
31632
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31633
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31634
|
+
* })
|
|
31635
|
+
* ```
|
|
31636
|
+
*/
|
|
31637
|
+
const claimRewardsParamsSchema = zod.z.object({
|
|
31638
|
+
from: adapterContextSchema$4,
|
|
31639
|
+
vaultAddress: vaultAddressSchema,
|
|
31640
|
+
config: earnConfigSchema.optional(),
|
|
31641
|
+
});
|
|
31642
|
+
/**
|
|
31643
|
+
* Validation schema for GetDepositQuoteParams.
|
|
31644
|
+
*
|
|
31645
|
+
* @example
|
|
31646
|
+
* ```typescript
|
|
31647
|
+
* import { getDepositQuoteParamsSchema } from '@circle-fin/earn-kit'
|
|
31648
|
+
*
|
|
31649
|
+
* const result = getDepositQuoteParamsSchema.safeParse({
|
|
31650
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31651
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31652
|
+
* amount: '100.50',
|
|
31653
|
+
* })
|
|
31654
|
+
* ```
|
|
31655
|
+
*/
|
|
31656
|
+
const getDepositQuoteParamsSchema = zod.z.object({
|
|
31657
|
+
from: adapterContextSchema$4,
|
|
31658
|
+
vaultAddress: vaultAddressSchema,
|
|
31659
|
+
amount: amountSchema$1,
|
|
31660
|
+
config: earnConfigSchema.optional(),
|
|
31661
|
+
});
|
|
31662
|
+
/**
|
|
31663
|
+
* Validation schema for GetWithdrawalQuoteParams.
|
|
31664
|
+
*
|
|
31665
|
+
* @example
|
|
31666
|
+
* ```typescript
|
|
31667
|
+
* import { getWithdrawalQuoteParamsSchema } from '@circle-fin/earn-kit'
|
|
31668
|
+
*
|
|
31669
|
+
* const result = getWithdrawalQuoteParamsSchema.safeParse({
|
|
31670
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31671
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31672
|
+
* amount: '50.00',
|
|
31673
|
+
* })
|
|
31674
|
+
* ```
|
|
31675
|
+
*/
|
|
31676
|
+
const getWithdrawalQuoteParamsSchema = zod.z.object({
|
|
31677
|
+
from: adapterContextSchema$4,
|
|
31678
|
+
vaultAddress: vaultAddressSchema,
|
|
31679
|
+
amount: amountSchema$1,
|
|
31680
|
+
config: earnConfigSchema.optional(),
|
|
31681
|
+
});
|
|
31682
|
+
/**
|
|
31683
|
+
* Validation schema for GetClaimRewardsQuoteParams.
|
|
31684
|
+
*
|
|
31685
|
+
* @example
|
|
31686
|
+
* ```typescript
|
|
31687
|
+
* import { getClaimRewardsQuoteParamsSchema } from '@circle-fin/earn-kit'
|
|
31688
|
+
*
|
|
31689
|
+
* const result = getClaimRewardsQuoteParamsSchema.safeParse({
|
|
31690
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
31691
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31692
|
+
* })
|
|
31693
|
+
* ```
|
|
31694
|
+
*/
|
|
31695
|
+
const getClaimRewardsQuoteParamsSchema = zod.z.object({
|
|
31696
|
+
from: adapterContextSchema$4,
|
|
31697
|
+
vaultAddress: vaultAddressSchema,
|
|
31698
|
+
config: earnConfigSchema.optional(),
|
|
31699
|
+
});
|
|
31700
|
+
|
|
31701
|
+
/**
|
|
31702
|
+
* Fetch vault information from the earn service.
|
|
31703
|
+
*
|
|
31704
|
+
* Query the configured earn providers to get information about one
|
|
31705
|
+
* or more DeFi lending vaults. Accept batch queries as chain +
|
|
31706
|
+
* vaultAddress pairs.
|
|
31707
|
+
*
|
|
31708
|
+
* @param context - The EarnKit context containing providers
|
|
31709
|
+
* @param params - Vault query parameters
|
|
31710
|
+
* @returns A promise resolving to the vault lookup results
|
|
31711
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31712
|
+
*
|
|
31713
|
+
* @example
|
|
31714
|
+
* ```typescript
|
|
31715
|
+
* import { createEarnKitContext, getVaults } from '@circle-fin/earn-kit'
|
|
31716
|
+
*
|
|
31717
|
+
* const context = createEarnKitContext()
|
|
31718
|
+
* const result = await getVaults(context, {
|
|
31719
|
+
* vaults: [{ chain: 'Arc_Testnet', vaultAddress: '0x...' }],
|
|
31720
|
+
* })
|
|
31721
|
+
* console.log(`Found ${result.vaults.length} vaults`)
|
|
31722
|
+
* ```
|
|
31723
|
+
*/
|
|
31724
|
+
async function getVaults$1(context, params) {
|
|
31725
|
+
assertEarnParams(params, getVaultsParamsSchema);
|
|
31726
|
+
const provider = findProvider(context);
|
|
31727
|
+
const result = await provider.getVaults({
|
|
31728
|
+
vaults: params.vaults,
|
|
31729
|
+
...(params.config !== undefined && { config: params.config }),
|
|
31730
|
+
});
|
|
31731
|
+
return formatGetVaultsResult(result);
|
|
31732
|
+
}
|
|
31733
|
+
|
|
31734
|
+
/**
|
|
31735
|
+
* Resolve the wallet address to use for on-chain operations.
|
|
31736
|
+
*
|
|
31737
|
+
* For developer-controlled adapters, callers pass `address` explicitly and we
|
|
31738
|
+
* return it unchanged. For user-controlled adapters, we fall back to
|
|
31739
|
+
* `adapter.getAddress(chain)`.
|
|
31740
|
+
*
|
|
31741
|
+
* @param from - Adapter context containing the adapter and optional explicit address.
|
|
31742
|
+
* @param chain - Resolved chain definition.
|
|
31743
|
+
* @returns The wallet address.
|
|
31744
|
+
* @throws Propagates errors from `adapter.getAddress(chain)` when
|
|
31745
|
+
* `from.address` is not supplied.
|
|
31746
|
+
*
|
|
31747
|
+
* @example
|
|
31748
|
+
* ```typescript
|
|
31749
|
+
* const address = await resolveAdapterAddress(params.from, chain)
|
|
31750
|
+
* ```
|
|
31751
|
+
*
|
|
31752
|
+
* @internal
|
|
31753
|
+
*/
|
|
31754
|
+
async function resolveAdapterAddress(from, chain) {
|
|
31755
|
+
if (from.address !== undefined && from.address !== '') {
|
|
31756
|
+
return from.address;
|
|
31757
|
+
}
|
|
31758
|
+
return from.adapter.getAddress(chain);
|
|
31759
|
+
}
|
|
31760
|
+
|
|
31761
|
+
/**
|
|
31762
|
+
* Fetch P&L position data for a wallet.
|
|
31763
|
+
*
|
|
31764
|
+
* Query the configured earn providers to get balance, principal,
|
|
31765
|
+
* earnings, and shares data for the wallet specified in the adapter context.
|
|
31766
|
+
*
|
|
31767
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
31768
|
+
* @param context - The EarnKit context containing providers
|
|
31769
|
+
* @param params - Position query parameters with adapter context
|
|
31770
|
+
* @returns A promise resolving to the wallet's position info
|
|
31771
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31772
|
+
*
|
|
31773
|
+
* @example
|
|
31774
|
+
* ```typescript
|
|
31775
|
+
* import {
|
|
31776
|
+
* createEarnKitContext,
|
|
31777
|
+
* getPosition,
|
|
31778
|
+
* EarnChain,
|
|
31779
|
+
* } from '@circle-fin/earn-kit'
|
|
31780
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
31781
|
+
*
|
|
31782
|
+
* const context = createEarnKitContext()
|
|
31783
|
+
* const adapter = createViemAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
31784
|
+
*
|
|
31785
|
+
* const position = await getPosition(context, {
|
|
31786
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
31787
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31788
|
+
* })
|
|
31789
|
+
* console.log(`Balance: ${position.currentBalance}`)
|
|
31790
|
+
* ```
|
|
31791
|
+
*/
|
|
31792
|
+
async function getPosition$1(context, params) {
|
|
31793
|
+
assertEarnParams(params, getPositionParamsSchema);
|
|
31794
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
31795
|
+
params.from.adapter.validateChainSupport(chain);
|
|
31796
|
+
const provider = findProvider(context, chain, 'getPosition');
|
|
31797
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
31798
|
+
const result = await provider.getPosition({
|
|
31799
|
+
from: { ...params.from, chain, address },
|
|
31800
|
+
vaultAddress: params.vaultAddress,
|
|
31801
|
+
...(params.config !== undefined && { config: params.config }),
|
|
31802
|
+
});
|
|
31803
|
+
return formatPositionInfo(result);
|
|
31804
|
+
}
|
|
31805
|
+
|
|
31806
|
+
/**
|
|
31807
|
+
* Execute a deposit into a DeFi lending vault.
|
|
31808
|
+
*
|
|
31809
|
+
* Validate user params, resolve the chain and wallet address, then delegate
|
|
31810
|
+
* the full on-chain flow (fetch signed instructions, issue a max USDC ERC-20
|
|
31811
|
+
* approval when needed, submit the deposit, wait for confirmation) to the
|
|
31812
|
+
* selected earn provider.
|
|
31813
|
+
*
|
|
31814
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
31815
|
+
* @param context - The EarnKit context containing providers
|
|
31816
|
+
* @param params - Deposit parameters including vault address, amount, and adapter
|
|
31817
|
+
* @returns A promise resolving to the deposit result with transaction details
|
|
31818
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31819
|
+
* @throws {@link KitError} If the chain has no adapter contract configured
|
|
31820
|
+
* @throws {@link KitError} If the chain does not support USDC
|
|
31821
|
+
* @throws {@link KitError} If the USDC approval transaction reverts on-chain
|
|
31822
|
+
* @throws {@link KitError} If the deposit transaction reverts on-chain
|
|
31823
|
+
*
|
|
31824
|
+
* @example
|
|
31825
|
+
* ```typescript
|
|
31826
|
+
* import {
|
|
31827
|
+
* createEarnKitContext,
|
|
31828
|
+
* deposit,
|
|
31829
|
+
* EarnChain,
|
|
31830
|
+
* } from '@circle-fin/earn-kit'
|
|
31831
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
31832
|
+
*
|
|
31833
|
+
* const context = createEarnKitContext()
|
|
31834
|
+
* const adapter = createViemAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
31835
|
+
*
|
|
31836
|
+
* const result = await deposit(context, {
|
|
31837
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
31838
|
+
* vaultAddress: '0x...',
|
|
31839
|
+
* amount: '100.50',
|
|
31840
|
+
* })
|
|
31841
|
+
* console.log(`Deposited ${result.amount} into ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
31842
|
+
* ```
|
|
31843
|
+
*/
|
|
31844
|
+
async function deposit$3(context, params) {
|
|
31845
|
+
assertEarnParams(params, depositParamsSchema$1);
|
|
31846
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
31847
|
+
params.from.adapter.validateChainSupport(chain);
|
|
31848
|
+
const provider = findProvider(context, chain, 'deposit');
|
|
31849
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
31850
|
+
return provider.deposit({
|
|
31851
|
+
from: { ...params.from, chain, address },
|
|
31852
|
+
vaultAddress: params.vaultAddress,
|
|
31853
|
+
amount: params.amount,
|
|
31854
|
+
...(params.config !== undefined && { config: params.config }),
|
|
31855
|
+
});
|
|
31856
|
+
}
|
|
31857
|
+
|
|
31858
|
+
/**
|
|
31859
|
+
* Execute a withdrawal from a DeFi lending vault.
|
|
31860
|
+
*
|
|
31861
|
+
* Validate user params, resolve the chain and wallet address, then delegate
|
|
31862
|
+
* the full on-chain flow (fetch signed instructions, issue a max vault-share
|
|
31863
|
+
* ERC-20 approval when needed, submit the withdrawal, wait for confirmation)
|
|
31864
|
+
* to the selected earn provider.
|
|
31865
|
+
*
|
|
31866
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
31867
|
+
* @param context - The EarnKit context containing providers
|
|
31868
|
+
* @param params - Withdrawal parameters including vault address, amount, and adapter
|
|
31869
|
+
* @returns A promise resolving to the withdrawal result with transaction details
|
|
31870
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31871
|
+
* @throws {@link KitError} If the chain has no adapter contract configured
|
|
31872
|
+
* @throws {@link KitError} If the vault share token approval transaction reverts on-chain
|
|
31873
|
+
* @throws {@link KitError} If the withdrawal transaction reverts on-chain
|
|
31874
|
+
*
|
|
31875
|
+
* @example
|
|
31876
|
+
* ```typescript
|
|
31877
|
+
* import {
|
|
31878
|
+
* createEarnKitContext,
|
|
31879
|
+
* withdraw,
|
|
31880
|
+
* EarnChain,
|
|
31881
|
+
* } from '@circle-fin/earn-kit'
|
|
31882
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
31883
|
+
*
|
|
31884
|
+
* const context = createEarnKitContext()
|
|
31885
|
+
* const adapter = createViemAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
31886
|
+
*
|
|
31887
|
+
* const result = await withdraw(context, {
|
|
31888
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
31889
|
+
* vaultAddress: '0x...',
|
|
31890
|
+
* amount: '50.00',
|
|
31891
|
+
* })
|
|
31892
|
+
* console.log(`Withdrew ${result.amount} from ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
31893
|
+
* ```
|
|
31894
|
+
*/
|
|
31895
|
+
async function withdraw$1(context, params) {
|
|
31896
|
+
assertEarnParams(params, withdrawParamsSchema);
|
|
31897
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
31898
|
+
params.from.adapter.validateChainSupport(chain);
|
|
31899
|
+
const provider = findProvider(context, chain, 'withdraw');
|
|
31900
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
31901
|
+
return provider.withdraw({
|
|
31902
|
+
from: { ...params.from, chain, address },
|
|
31903
|
+
vaultAddress: params.vaultAddress,
|
|
31904
|
+
amount: params.amount,
|
|
31905
|
+
...(params.config !== undefined && { config: params.config }),
|
|
31906
|
+
});
|
|
31907
|
+
}
|
|
31908
|
+
|
|
31909
|
+
/**
|
|
31910
|
+
* Claim rewards from earn vaults.
|
|
31911
|
+
*
|
|
31912
|
+
* Validate user params, resolve the chain and wallet address, then delegate
|
|
31913
|
+
* the full on-chain flow (fetch signed instructions, submit the claim, wait
|
|
31914
|
+
* for confirmation) to the selected earn provider. When no rewards are
|
|
31915
|
+
* claimable, the provider returns rewards without submitting a transaction.
|
|
31916
|
+
*
|
|
31917
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
31918
|
+
* @param context - The EarnKit context containing providers
|
|
31919
|
+
* @param params - Claim parameters including adapter context and vault address
|
|
31920
|
+
* @returns A promise resolving to the claim result with reward details
|
|
31921
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31922
|
+
* @throws {@link KitError} If the chain has no adapter contract configured
|
|
31923
|
+
* @throws {@link KitError} If the earn service API request or response fails
|
|
31924
|
+
* @throws {@link KitError} If the claim transaction reverts on-chain
|
|
31925
|
+
*
|
|
31926
|
+
* @example
|
|
31927
|
+
* ```typescript
|
|
31928
|
+
* import {
|
|
31929
|
+
* createEarnKitContext,
|
|
31930
|
+
* claimRewards,
|
|
31931
|
+
* EarnChain,
|
|
31932
|
+
* } from '@circle-fin/earn-kit'
|
|
31933
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
31934
|
+
*
|
|
31935
|
+
* const context = createEarnKitContext()
|
|
31936
|
+
* const adapter = createViemAdapterFromPrivateKey({ privateKey: '0x...' })
|
|
31937
|
+
*
|
|
31938
|
+
* const result = await claimRewards(context, {
|
|
31939
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
31940
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
31941
|
+
* })
|
|
31942
|
+
* if (result.status === 'no_rewards') {
|
|
31943
|
+
* console.log('No rewards to claim')
|
|
31944
|
+
* } else {
|
|
31945
|
+
* console.log(`Claimed ${result.rewards.length} reward(s), tx: ${result.txHash}`)
|
|
31946
|
+
* }
|
|
31947
|
+
* ```
|
|
31948
|
+
*/
|
|
31949
|
+
async function claimRewards$1(context, params) {
|
|
31950
|
+
assertEarnParams(params, claimRewardsParamsSchema);
|
|
31951
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
31952
|
+
params.from.adapter.validateChainSupport(chain);
|
|
31953
|
+
const provider = findProvider(context, chain, 'claimRewards');
|
|
31954
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
31955
|
+
const result = await provider.claimRewards({
|
|
31956
|
+
from: { ...params.from, chain, address },
|
|
31957
|
+
vaultAddress: params.vaultAddress,
|
|
31958
|
+
...(params.config === undefined ? {} : { config: params.config }),
|
|
31959
|
+
});
|
|
31960
|
+
return formatClaimRewardsResult(result);
|
|
31961
|
+
}
|
|
31962
|
+
|
|
31963
|
+
/**
|
|
31964
|
+
* Get an informational quote for a deposit into a vault.
|
|
31965
|
+
*
|
|
31966
|
+
* Query expected shares, share price, and APY for the specified
|
|
31967
|
+
* deposit amount without executing any transaction.
|
|
31968
|
+
*
|
|
31969
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
31970
|
+
* @param context - The EarnKit context containing providers
|
|
31971
|
+
* @param params - Deposit quote parameters including vault address and amount
|
|
31972
|
+
* @returns A promise resolving to the deposit quote information
|
|
31973
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
31974
|
+
*
|
|
31975
|
+
* @example
|
|
31976
|
+
* ```typescript
|
|
31977
|
+
* import {
|
|
31978
|
+
* createEarnKitContext,
|
|
31979
|
+
* getDepositQuote,
|
|
31980
|
+
* EarnChain,
|
|
31981
|
+
* } from '@circle-fin/earn-kit'
|
|
31982
|
+
*
|
|
31983
|
+
* const context = createEarnKitContext()
|
|
31984
|
+
* const quote = await getDepositQuote(context, {
|
|
31985
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
31986
|
+
* vaultAddress: '0x...',
|
|
31987
|
+
* amount: '100.50',
|
|
31988
|
+
* })
|
|
31989
|
+
* console.log(`Expected shares: ${quote.expectedShares.amount}`)
|
|
31990
|
+
* ```
|
|
31991
|
+
*/
|
|
31992
|
+
async function getDepositQuote$1(context, params) {
|
|
31993
|
+
assertEarnParams(params, getDepositQuoteParamsSchema);
|
|
31994
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
31995
|
+
params.from.adapter.validateChainSupport(chain);
|
|
31996
|
+
const provider = findProvider(context, chain, 'getDepositQuote');
|
|
31997
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
31998
|
+
const result = await provider.getDepositQuote({
|
|
31999
|
+
from: { ...params.from, chain, address },
|
|
32000
|
+
vaultAddress: params.vaultAddress,
|
|
32001
|
+
amount: params.amount,
|
|
32002
|
+
...(params.config !== undefined && { config: params.config }),
|
|
32003
|
+
});
|
|
32004
|
+
return formatDepositQuoteInfo(result);
|
|
32005
|
+
}
|
|
32006
|
+
|
|
32007
|
+
/**
|
|
32008
|
+
* Get an informational quote for a withdrawal from a vault.
|
|
32009
|
+
*
|
|
32010
|
+
* Query shares to redeem, max withdrawable, and fees for the specified
|
|
32011
|
+
* withdrawal amount without executing any transaction.
|
|
32012
|
+
*
|
|
32013
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
32014
|
+
* @param context - The EarnKit context containing providers
|
|
32015
|
+
* @param params - Withdrawal quote parameters including vault address and amount
|
|
32016
|
+
* @returns A promise resolving to the withdrawal quote information
|
|
32017
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32018
|
+
*
|
|
32019
|
+
* @example
|
|
32020
|
+
* ```typescript
|
|
32021
|
+
* import {
|
|
32022
|
+
* createEarnKitContext,
|
|
32023
|
+
* getWithdrawalQuote,
|
|
32024
|
+
* EarnChain,
|
|
32025
|
+
* } from '@circle-fin/earn-kit'
|
|
32026
|
+
*
|
|
32027
|
+
* const context = createEarnKitContext()
|
|
32028
|
+
* const quote = await getWithdrawalQuote(context, {
|
|
32029
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
32030
|
+
* vaultAddress: '0x...',
|
|
32031
|
+
* amount: '50.00',
|
|
32032
|
+
* })
|
|
32033
|
+
* console.log(`Shares to redeem: ${quote.sharesToRedeem.amount}`)
|
|
32034
|
+
* ```
|
|
32035
|
+
*/
|
|
32036
|
+
async function getWithdrawalQuote$1(context, params) {
|
|
32037
|
+
assertEarnParams(params, getWithdrawalQuoteParamsSchema);
|
|
32038
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
32039
|
+
params.from.adapter.validateChainSupport(chain);
|
|
32040
|
+
const provider = findProvider(context, chain, 'getWithdrawalQuote');
|
|
32041
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
32042
|
+
const result = await provider.getWithdrawalQuote({
|
|
32043
|
+
from: { ...params.from, chain, address },
|
|
32044
|
+
vaultAddress: params.vaultAddress,
|
|
32045
|
+
amount: params.amount,
|
|
32046
|
+
...(params.config !== undefined && { config: params.config }),
|
|
32047
|
+
});
|
|
32048
|
+
return formatWithdrawalQuoteInfo(result);
|
|
32049
|
+
}
|
|
32050
|
+
|
|
32051
|
+
/**
|
|
32052
|
+
* Return all chains supported by configured earn providers.
|
|
32053
|
+
*
|
|
32054
|
+
* @param context - The EarnKit context containing providers
|
|
32055
|
+
* @returns Deduplicated supported chain definitions
|
|
32056
|
+
*
|
|
32057
|
+
* @example
|
|
32058
|
+
* ```typescript
|
|
32059
|
+
* import { createEarnKitContext, getSupportedChains } from '@circle-fin/earn-kit'
|
|
32060
|
+
*
|
|
32061
|
+
* const context = createEarnKitContext()
|
|
32062
|
+
* const chains = getSupportedChains(context)
|
|
32063
|
+
* ```
|
|
32064
|
+
*/
|
|
32065
|
+
function getSupportedChains$3(context) {
|
|
32066
|
+
const earnChains = new Set(Object.values(exports.EarnChain));
|
|
32067
|
+
const chainsById = new Map();
|
|
32068
|
+
for (const provider of context.providers) {
|
|
32069
|
+
for (const chain of provider.supportedChains) {
|
|
32070
|
+
if (earnChains.has(chain.chain)) {
|
|
32071
|
+
chainsById.set(chain.chain, chain);
|
|
32072
|
+
}
|
|
32073
|
+
}
|
|
32074
|
+
}
|
|
32075
|
+
return [...chainsById.values()];
|
|
32076
|
+
}
|
|
32077
|
+
|
|
32078
|
+
/**
|
|
32079
|
+
* Get an informational quote for claiming rewards.
|
|
32080
|
+
*
|
|
32081
|
+
* Query claimable reward details without executing any transaction.
|
|
32082
|
+
*
|
|
32083
|
+
* @typeParam TFromAdapterCapabilities - The adapter capabilities type
|
|
32084
|
+
* @param context - The EarnKit context containing providers
|
|
32085
|
+
* @param params - Claim rewards quote parameters including vault address
|
|
32086
|
+
* @returns A promise resolving to the claim rewards quote information
|
|
32087
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32088
|
+
*
|
|
32089
|
+
* @example
|
|
32090
|
+
* ```typescript
|
|
32091
|
+
* import {
|
|
32092
|
+
* createEarnKitContext,
|
|
32093
|
+
* getClaimRewardsQuote,
|
|
32094
|
+
* EarnChain,
|
|
32095
|
+
* } from '@circle-fin/earn-kit'
|
|
32096
|
+
*
|
|
32097
|
+
* const context = createEarnKitContext()
|
|
32098
|
+
* const quote = await getClaimRewardsQuote(context, {
|
|
32099
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
32100
|
+
* vaultAddress: '0x...',
|
|
32101
|
+
* })
|
|
32102
|
+
* console.log(`Claimable rewards: ${quote.rewards.length}`)
|
|
32103
|
+
* ```
|
|
32104
|
+
*/
|
|
32105
|
+
async function getClaimRewardsQuote$1(context, params) {
|
|
32106
|
+
assertEarnParams(params, getClaimRewardsQuoteParamsSchema);
|
|
32107
|
+
const chain = resolveChainIdentifier(params.from.chain);
|
|
32108
|
+
params.from.adapter.validateChainSupport(chain);
|
|
32109
|
+
const provider = findProvider(context, chain, 'getClaimRewardsQuote');
|
|
32110
|
+
const address = await resolveAdapterAddress(params.from, chain);
|
|
32111
|
+
const result = await provider.getClaimRewardsQuote({
|
|
32112
|
+
from: { ...params.from, chain, address },
|
|
32113
|
+
vaultAddress: params.vaultAddress,
|
|
32114
|
+
...(params.config !== undefined && { config: params.config }),
|
|
32115
|
+
});
|
|
32116
|
+
return formatClaimRewardsQuoteInfo(result);
|
|
32117
|
+
}
|
|
32118
|
+
|
|
32119
|
+
/**
|
|
32120
|
+
* A high-level class-based interface for DeFi lending vault operations.
|
|
32121
|
+
*
|
|
32122
|
+
* EarnKit provides a familiar class-based API for developers who prefer
|
|
32123
|
+
* traditional object-oriented patterns. The class maintains an internal
|
|
32124
|
+
* context and provides methods for depositing, withdrawing, claiming
|
|
32125
|
+
* rewards, and querying vault and position data.
|
|
32126
|
+
*
|
|
32127
|
+
* Key features:
|
|
32128
|
+
* - Strongly typed parameters with comprehensive Zod validation
|
|
32129
|
+
* - Supported earn vault deposits and withdrawals
|
|
32130
|
+
* - Deposit quote queries (expected shares, share price, APY without executing a transaction)
|
|
32131
|
+
* - Withdrawal quote queries (shares to redeem, max withdrawable, fees without executing a transaction)
|
|
32132
|
+
* - Claim rewards quote queries (claimable reward details without executing a transaction)
|
|
32133
|
+
* - Reward claiming
|
|
32134
|
+
* - P&L position tracking
|
|
32135
|
+
* - Dual-mode authentication (permissioned and permissionless)
|
|
32136
|
+
* - Full TypeScript support with IntelliSense
|
|
32137
|
+
*
|
|
32138
|
+
* @example
|
|
32139
|
+
* ```typescript
|
|
32140
|
+
* import { EarnChain, EarnKit } from '@circle-fin/earn-kit'
|
|
32141
|
+
* import { createViemAdapterFromPrivateKey } from '@circle-fin/adapter-viem-v2'
|
|
32142
|
+
*
|
|
32143
|
+
* const kit = new EarnKit()
|
|
32144
|
+
* const adapter = createViemAdapterFromPrivateKey({
|
|
32145
|
+
* privateKey: process.env.PRIVATE_KEY,
|
|
32146
|
+
* })
|
|
32147
|
+
*
|
|
32148
|
+
* // Fetch vault info
|
|
32149
|
+
* const { vaults } = await kit.getVaults({
|
|
32150
|
+
* vaults: [{ chain: EarnChain.Arc_Testnet, vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458' }],
|
|
32151
|
+
* })
|
|
32152
|
+
* const [vault] = vaults
|
|
32153
|
+
* if (vault === undefined) {
|
|
32154
|
+
* throw new Error('No earn vaults available')
|
|
32155
|
+
* }
|
|
32156
|
+
*
|
|
32157
|
+
* // Deposit into a vault
|
|
32158
|
+
* const result = await kit.deposit({
|
|
32159
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
32160
|
+
* vaultAddress: vault.vaultAddress,
|
|
32161
|
+
* amount: '100.50',
|
|
32162
|
+
* })
|
|
32163
|
+
* console.log(`Deposited ${result.amount} into ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
32164
|
+
* ```
|
|
32165
|
+
*
|
|
32166
|
+
* @remarks
|
|
32167
|
+
* For functional usage, import and use the operations directly:
|
|
32168
|
+
* ```typescript
|
|
32169
|
+
* import { createEarnKitContext, deposit } from '@circle-fin/earn-kit'
|
|
32170
|
+
* const context = createEarnKitContext()
|
|
32171
|
+
* await deposit(context, params)
|
|
32172
|
+
* ```
|
|
32173
|
+
*/
|
|
32174
|
+
class EarnKit {
|
|
32175
|
+
context;
|
|
32176
|
+
/**
|
|
32177
|
+
* Create a new EarnKit instance.
|
|
32178
|
+
*
|
|
32179
|
+
* Accept an optional configuration object to customize the kit's
|
|
32180
|
+
* behavior. If no configuration is provided, the kit is initialized
|
|
32181
|
+
* with default settings using the built-in EarnServiceProvider.
|
|
32182
|
+
*
|
|
32183
|
+
* @param config - Optional configuration for the EarnKit instance
|
|
32184
|
+
*
|
|
32185
|
+
* @example
|
|
32186
|
+
* ```typescript
|
|
32187
|
+
* import { EarnKit } from '@circle-fin/earn-kit'
|
|
32188
|
+
*
|
|
32189
|
+
* // Create with default configuration
|
|
32190
|
+
* const kit = new EarnKit()
|
|
32191
|
+
* ```
|
|
32192
|
+
*/
|
|
32193
|
+
constructor(config = {}) {
|
|
32194
|
+
this.context = createEarnKitContext(config);
|
|
32195
|
+
}
|
|
32196
|
+
/**
|
|
32197
|
+
* Return the chains supported by configured earn providers.
|
|
32198
|
+
*
|
|
32199
|
+
* @returns Deduplicated supported chain definitions
|
|
32200
|
+
*
|
|
32201
|
+
* @example
|
|
32202
|
+
* ```typescript
|
|
32203
|
+
* const kit = new EarnKit()
|
|
32204
|
+
* const chains = kit.getSupportedChains()
|
|
32205
|
+
* ```
|
|
32206
|
+
*/
|
|
32207
|
+
getSupportedChains() {
|
|
32208
|
+
return getSupportedChains$3(this.context);
|
|
32209
|
+
}
|
|
32210
|
+
/**
|
|
32211
|
+
* Fetch available vault information.
|
|
32212
|
+
*
|
|
32213
|
+
* Query the configured earn providers to get a list of available
|
|
32214
|
+
* DeFi lending vaults with APY, TVL, and reward information.
|
|
32215
|
+
*
|
|
32216
|
+
* @param params - Query parameters with vault address and optional chain filter
|
|
32217
|
+
* @returns A promise resolving to the list of available vaults
|
|
32218
|
+
* @throws {@link KitError} If no provider is configured
|
|
32219
|
+
*
|
|
32220
|
+
* @example
|
|
32221
|
+
* ```typescript
|
|
32222
|
+
* const kit = new EarnKit()
|
|
32223
|
+
* const result = await kit.getVaults({
|
|
32224
|
+
* vaults: [{ chain: 'Arc_Testnet', vaultAddress: '0x8eB67...' }],
|
|
32225
|
+
* })
|
|
32226
|
+
* result.vaults.forEach(v => console.log(`${v.name}: ${(v.currentApy * 100).toFixed(2)}% APY`))
|
|
32227
|
+
* ```
|
|
32228
|
+
*/
|
|
32229
|
+
async getVaults(params) {
|
|
32230
|
+
return getVaults$1(this.context, params);
|
|
32231
|
+
}
|
|
32232
|
+
/**
|
|
32233
|
+
* Fetch P&L position data for the connected wallet.
|
|
32234
|
+
*
|
|
32235
|
+
* Query balance, principal, earnings, and shares data for the wallet
|
|
32236
|
+
* specified in the adapter context.
|
|
32237
|
+
*
|
|
32238
|
+
* @param params - Position query parameters with adapter context
|
|
32239
|
+
* @returns A promise resolving to the wallet's position info
|
|
32240
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32241
|
+
*
|
|
32242
|
+
* @example
|
|
32243
|
+
* ```typescript
|
|
32244
|
+
* const position = await kit.getPosition({
|
|
32245
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32246
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
32247
|
+
* })
|
|
32248
|
+
* if (position.pnl.status === 'available') {
|
|
32249
|
+
* console.log(`Yield: ${position.pnl.totalYieldEarned}`)
|
|
32250
|
+
* }
|
|
32251
|
+
* ```
|
|
32252
|
+
*/
|
|
32253
|
+
async getPosition(params) {
|
|
32254
|
+
return getPosition$1(this.context, params);
|
|
32255
|
+
}
|
|
32256
|
+
/**
|
|
32257
|
+
* Execute a deposit into a DeFi lending vault.
|
|
32258
|
+
*
|
|
32259
|
+
* Build signed deposit instructions via the earn service, issue a max USDC
|
|
32260
|
+
* ERC-20 approval for the adapter contract when the current allowance is
|
|
32261
|
+
* below the SDK threshold, then submit the deposit on-chain. Return the
|
|
32262
|
+
* confirmed transaction hash together with the deposited amount and target
|
|
32263
|
+
* vault.
|
|
32264
|
+
*
|
|
32265
|
+
* @param params - Deposit parameters including vault address and amount
|
|
32266
|
+
* @returns A promise resolving to the deposit result with transaction details
|
|
32267
|
+
* @throws {@link KitError} If validation fails, no provider is configured, the
|
|
32268
|
+
* chain has no adapter contract configured, the approval transaction
|
|
32269
|
+
* reverts on-chain, or the deposit transaction reverts on-chain
|
|
32270
|
+
*
|
|
32271
|
+
* @example
|
|
32272
|
+
* ```typescript
|
|
32273
|
+
* const result = await kit.deposit({
|
|
32274
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32275
|
+
* vaultAddress: '0x...',
|
|
32276
|
+
* amount: '100.50',
|
|
32277
|
+
* })
|
|
32278
|
+
* console.log(`Deposited ${result.amount} into ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
32279
|
+
* ```
|
|
32280
|
+
*/
|
|
32281
|
+
async deposit(params) {
|
|
32282
|
+
return deposit$3(this.context, params);
|
|
32283
|
+
}
|
|
32284
|
+
/**
|
|
32285
|
+
* Execute a withdrawal from a DeFi lending vault.
|
|
32286
|
+
*
|
|
32287
|
+
* Build signed withdrawal instructions via the earn service, approve the
|
|
32288
|
+
* adapter contract to spend vault share tokens if needed, then submit the
|
|
32289
|
+
* withdrawal on-chain. Return the withdrawal result including the on-chain
|
|
32290
|
+
* transaction hash, withdrawn amount, and target vault.
|
|
32291
|
+
*
|
|
32292
|
+
* @param params - Withdrawal parameters including vault address and amount
|
|
32293
|
+
* @returns A promise resolving to the withdrawal result with transaction details
|
|
32294
|
+
* @throws {@link KitError} If validation fails, no provider is configured,
|
|
32295
|
+
* the chain has no adapter contract configured, the share-token approval
|
|
32296
|
+
* reverts on-chain, or the withdrawal transaction reverts on-chain.
|
|
32297
|
+
*
|
|
32298
|
+
* @example
|
|
32299
|
+
* ```typescript
|
|
32300
|
+
* const result = await kit.withdraw({
|
|
32301
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32302
|
+
* vaultAddress: '0x...',
|
|
32303
|
+
* amount: '50.00',
|
|
32304
|
+
* })
|
|
32305
|
+
* console.log(`Withdrew ${result.amount} from ${result.vaultAddress}, tx: ${result.txHash}`)
|
|
32306
|
+
* ```
|
|
32307
|
+
*/
|
|
32308
|
+
async withdraw(params) {
|
|
32309
|
+
return withdraw$1(this.context, params);
|
|
32310
|
+
}
|
|
32311
|
+
/**
|
|
32312
|
+
* Claim rewards from earn vaults.
|
|
32313
|
+
*
|
|
32314
|
+
* Build signed claim rewards instructions via the earn service, submit
|
|
32315
|
+
* them on-chain through the adapter, and return the confirmed transaction
|
|
32316
|
+
* hash. When no rewards are claimable, no transaction is submitted.
|
|
32317
|
+
*
|
|
32318
|
+
* @param params - Claim parameters including adapter context
|
|
32319
|
+
* @returns A promise resolving to the claim result with reward details
|
|
32320
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32321
|
+
*
|
|
32322
|
+
* @example
|
|
32323
|
+
* ```typescript
|
|
32324
|
+
* const result = await kit.claimRewards({
|
|
32325
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32326
|
+
* vaultAddress: '0x8eB67A509616cd6A7c1B3c8C21D48FF57df3d458',
|
|
32327
|
+
* })
|
|
32328
|
+
*
|
|
32329
|
+
* if (result.status === 'claimed') {
|
|
32330
|
+
* console.log(`Claimed ${result.rewards.length} reward token(s), tx: ${result.txHash}`)
|
|
32331
|
+
* }
|
|
32332
|
+
* ```
|
|
32333
|
+
*/
|
|
32334
|
+
async claimRewards(params) {
|
|
32335
|
+
return claimRewards$1(this.context, params);
|
|
32336
|
+
}
|
|
32337
|
+
/**
|
|
32338
|
+
* Get an informational quote for a deposit into a vault.
|
|
32339
|
+
*
|
|
32340
|
+
* Query expected shares, share price, and APY for the specified
|
|
32341
|
+
* deposit amount without executing any transaction.
|
|
32342
|
+
*
|
|
32343
|
+
* @param params - Deposit quote parameters including vault address and amount
|
|
32344
|
+
* @returns A promise resolving to the deposit quote information
|
|
32345
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32346
|
+
*
|
|
32347
|
+
* @example
|
|
32348
|
+
* ```typescript
|
|
32349
|
+
* const quote = await kit.getDepositQuote({
|
|
32350
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32351
|
+
* vaultAddress: '0x...',
|
|
32352
|
+
* amount: '100.50',
|
|
32353
|
+
* })
|
|
32354
|
+
* console.log(`Expected shares: ${quote.expectedShares.amount}`)
|
|
32355
|
+
* ```
|
|
32356
|
+
*/
|
|
32357
|
+
async getDepositQuote(params) {
|
|
32358
|
+
return getDepositQuote$1(this.context, params);
|
|
32359
|
+
}
|
|
32360
|
+
/**
|
|
32361
|
+
* Get an informational quote for a withdrawal from a vault.
|
|
32362
|
+
*
|
|
32363
|
+
* Query shares to redeem, max withdrawable, and fees for the specified
|
|
32364
|
+
* withdrawal amount without executing any transaction.
|
|
32365
|
+
*
|
|
32366
|
+
* @param params - Withdrawal quote parameters including vault address and amount
|
|
32367
|
+
* @returns A promise resolving to the withdrawal quote information
|
|
32368
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32369
|
+
*
|
|
32370
|
+
* @example
|
|
32371
|
+
* ```typescript
|
|
32372
|
+
* const quote = await kit.getWithdrawalQuote({
|
|
32373
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32374
|
+
* vaultAddress: '0x...',
|
|
32375
|
+
* amount: '50.00',
|
|
32376
|
+
* })
|
|
32377
|
+
* console.log(`Shares to redeem: ${quote.sharesToRedeem.amount}`)
|
|
32378
|
+
* ```
|
|
32379
|
+
*/
|
|
32380
|
+
async getWithdrawalQuote(params) {
|
|
32381
|
+
return getWithdrawalQuote$1(this.context, params);
|
|
32382
|
+
}
|
|
32383
|
+
/**
|
|
32384
|
+
* Get an informational quote for claiming rewards.
|
|
32385
|
+
*
|
|
32386
|
+
* Query claimable reward details without executing any transaction.
|
|
32387
|
+
*
|
|
32388
|
+
* @param params - Claim rewards quote parameters including vault address
|
|
32389
|
+
* @returns A promise resolving to the claim rewards quote information
|
|
32390
|
+
* @throws {@link KitError} If validation fails or no provider is configured
|
|
32391
|
+
*
|
|
32392
|
+
* @example
|
|
32393
|
+
* ```typescript
|
|
32394
|
+
* const quote = await kit.getClaimRewardsQuote({
|
|
32395
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
32396
|
+
* vaultAddress: '0x...',
|
|
32397
|
+
* })
|
|
32398
|
+
* console.log(`Claimable rewards: ${quote.rewards.length}`)
|
|
32399
|
+
* ```
|
|
32400
|
+
*/
|
|
32401
|
+
async getClaimRewardsQuote(params) {
|
|
32402
|
+
return getClaimRewardsQuote$1(this.context, params);
|
|
32403
|
+
}
|
|
32404
|
+
}
|
|
32405
|
+
|
|
32406
|
+
/**
|
|
32407
|
+
*
|
|
32408
|
+
* Earn Kit
|
|
32409
|
+
*
|
|
32410
|
+
* A strongly-typed SDK for DeFi lending vault deposits, withdrawals, and rewards
|
|
32411
|
+
* @packageDocumentation
|
|
32412
|
+
*/
|
|
32413
|
+
// Auto-register this kit for user agent tracking
|
|
32414
|
+
registerKit(`${pkg$1.name}/${pkg$1.version}`);
|
|
32415
|
+
|
|
32416
|
+
/**
|
|
32417
|
+
* Create an EarnKit instance for AppKit earn operations.
|
|
32418
|
+
*
|
|
32419
|
+
* @remarks The context parameter is reserved for future EarnKit wiring.
|
|
32420
|
+
* EarnKit does not currently support AppKit developer fee hooks, so the
|
|
32421
|
+
* factory does not read fee callbacks from the context. Earn custom fees remain
|
|
32422
|
+
* reserved until EarnKit fee support ships.
|
|
32423
|
+
*
|
|
32424
|
+
* When EarnKit supports developer fee hooks, this factory can wire AppKit context through.
|
|
32425
|
+
*
|
|
32426
|
+
* @param context - AppKit context reserved for future EarnKit wiring
|
|
32427
|
+
* @returns A new EarnKit instance
|
|
32428
|
+
*
|
|
32429
|
+
* @example
|
|
32430
|
+
* ```typescript
|
|
32431
|
+
* const earnKit = createEarnKit(context)
|
|
32432
|
+
* ```
|
|
32433
|
+
*/
|
|
32434
|
+
const createEarnKit = () => new EarnKit();
|
|
32435
|
+
|
|
32436
|
+
/**
|
|
32437
|
+
* Register event handlers from a context actions map to a kit instance.
|
|
32438
|
+
*
|
|
32439
|
+
* This utility function registers event handlers stored in a context actions map
|
|
32440
|
+
* with a kit instance that supports event handling via an `on` method. It handles
|
|
32441
|
+
* wildcard handlers ('*') and prefixed action handlers, stripping the prefix
|
|
32442
|
+
* before registration.
|
|
32443
|
+
*
|
|
32444
|
+
* The function is designed to be reusable across different operation types
|
|
32445
|
+
* (bridge, swap, stake, etc.) by accepting a configurable prefix parameter.
|
|
32446
|
+
*
|
|
32447
|
+
* @param kit - The kit instance to register handlers with (must have an `on` method)
|
|
32448
|
+
* @param handlers - Map of action names to arrays of handler functions
|
|
32449
|
+
* @param prefix - Optional prefix to strip from action names (e.g., 'bridge.')
|
|
32450
|
+
*
|
|
32451
|
+
* @example
|
|
32452
|
+
* ```typescript
|
|
32453
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
32454
|
+
* import { BridgeKit } from '@circle-fin/bridge-kit'
|
|
32455
|
+
*
|
|
32456
|
+
* const kit = new BridgeKit()
|
|
32457
|
+
* const handlers = {
|
|
32458
|
+
* '*': [(payload) => console.log('All actions:', payload)],
|
|
32459
|
+
* 'bridge.approve': [(payload) => console.log('Approved:', payload)],
|
|
32460
|
+
* 'bridge.burn': [(payload) => console.log('Burned:', payload)],
|
|
32461
|
+
* }
|
|
32462
|
+
*
|
|
32463
|
+
* registerActionHandlers(kit, handlers, 'bridge.')
|
|
32464
|
+
* ```
|
|
32465
|
+
*
|
|
32466
|
+
* @example
|
|
32467
|
+
* ```typescript
|
|
32468
|
+
* import { registerActionHandlers } from '@circle-fin/app-kit/utils'
|
|
32469
|
+
* import { SwapKit } from '@circle-fin/swap-kit'
|
|
32470
|
+
*
|
|
32471
|
+
* const kit = new SwapKit()
|
|
32472
|
+
* const handlers = {
|
|
32473
|
+
* 'swap.initiate': [(payload) => console.log('Swap initiated:', payload)],
|
|
32474
|
+
* }
|
|
32475
|
+
*
|
|
32476
|
+
* registerActionHandlers(kit, handlers, 'swap.')
|
|
32477
|
+
* ```
|
|
32478
|
+
*/
|
|
32479
|
+
const registerActionHandlers = (kit, handlers, prefix = '') => {
|
|
32480
|
+
for (const [action, handlerArray] of Object.entries(handlers)) {
|
|
32481
|
+
// Register all handlers for this action
|
|
32482
|
+
for (const handler of handlerArray) {
|
|
32483
|
+
if (action === '*') {
|
|
32484
|
+
// Wildcard handlers are registered as-is
|
|
32485
|
+
kit.on('*', handler);
|
|
32486
|
+
}
|
|
32487
|
+
else if (prefix && action.startsWith(prefix)) {
|
|
32488
|
+
// Remove prefix to get the actual kit action name
|
|
32489
|
+
const kitAction = action.split('.').at(1);
|
|
32490
|
+
if (kitAction) {
|
|
32491
|
+
kit.on(kitAction, handler);
|
|
32492
|
+
}
|
|
32493
|
+
}
|
|
32494
|
+
else if (!prefix) {
|
|
32495
|
+
// No prefix configured, register action as-is
|
|
32496
|
+
kit.on(action, handler);
|
|
32497
|
+
}
|
|
32498
|
+
// Actions that don't match the prefix are silently ignored
|
|
32499
|
+
}
|
|
32500
|
+
}
|
|
32501
|
+
};
|
|
32502
|
+
|
|
32503
|
+
/**
|
|
32504
|
+
* List of all supported token aliases for App Kit send operations.
|
|
32505
|
+
*
|
|
32506
|
+
* This array is used for runtime validation to check if a token string
|
|
32507
|
+
* is a known alias rather than a custom address.
|
|
32508
|
+
*
|
|
32509
|
+
* @remarks
|
|
32510
|
+
* The type annotation `readonly TokenAlias[]` ensures this array stays in sync
|
|
32511
|
+
* with the TokenAlias type definition - TypeScript will enforce any changes.
|
|
32512
|
+
*
|
|
32513
|
+
* For swap operations, additional tokens (EURC, DAI, USDE, PYUSD) are supported
|
|
32514
|
+
* via SwapKit's SupportedToken type.
|
|
32515
|
+
*/
|
|
32516
|
+
const TOKEN_ALIASES = ['USDC', 'USDT', 'NATIVE'];
|
|
32517
|
+
/**
|
|
32518
|
+
* Check if a token string is a known alias.
|
|
32519
|
+
*
|
|
32520
|
+
* This function performs case-sensitive matching against the list of known
|
|
32521
|
+
* token aliases. Known aliases take precedence over custom addresses in the
|
|
32522
|
+
* send operation logic.
|
|
32523
|
+
*
|
|
32524
|
+
* @param token - The token identifier to check
|
|
32525
|
+
* @returns True if the token is a known alias, false otherwise
|
|
32526
|
+
*
|
|
32527
|
+
* @example
|
|
32528
|
+
* ```typescript
|
|
32529
|
+
* import { isTokenAlias } from '@circle-fin/app-kit'
|
|
32530
|
+
*
|
|
32531
|
+
* console.log(isTokenAlias('USDC')) // true
|
|
32532
|
+
* console.log(isTokenAlias('NATIVE')) // true
|
|
32533
|
+
* console.log(isTokenAlias('0x6B175474E89094C44Da98b954EedeAC495271d0F')) // false
|
|
32534
|
+
* ```
|
|
32535
|
+
*/
|
|
32536
|
+
function isTokenAlias(token) {
|
|
32537
|
+
return TOKEN_ALIASES.includes(token);
|
|
32538
|
+
}
|
|
32539
|
+
/**
|
|
32540
|
+
* Type guard to check if a string is a valid token address for a chain.
|
|
32541
|
+
*
|
|
32542
|
+
* This function verifies that a token string is:
|
|
32543
|
+
* 1. Not a known alias ('USDC', 'USDT', 'NATIVE')
|
|
32544
|
+
* 2. A valid address format for the specified chain
|
|
32545
|
+
*
|
|
32546
|
+
* Use this to narrow the type to `TokenAddress` in TypeScript.
|
|
32547
|
+
*
|
|
32548
|
+
* @param token - The token string to validate
|
|
32549
|
+
* @param chain - The chain definition for address validation
|
|
32550
|
+
* @returns True if the token is a valid address (not an alias)
|
|
32551
|
+
*
|
|
32552
|
+
* @example
|
|
32553
|
+
* ```typescript
|
|
32554
|
+
* import { isTokenAddress } from '@circle-fin/app-kit'
|
|
32555
|
+
* import { Ethereum } from '@core/chains'
|
|
32556
|
+
*
|
|
32557
|
+
* const daiAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F'
|
|
32558
|
+
* if (isTokenAddress(daiAddress, Ethereum)) {
|
|
32559
|
+
* // TypeScript knows daiAddress is TokenAddress here
|
|
32560
|
+
* console.log('Valid token address:', daiAddress)
|
|
32561
|
+
* }
|
|
32562
|
+
*
|
|
32563
|
+
* console.log(isTokenAddress('USDC', Ethereum)) // false - it's an alias
|
|
32564
|
+
* console.log(isTokenAddress('invalid', Ethereum)) // false - invalid format
|
|
32565
|
+
* ```
|
|
32566
|
+
*/
|
|
32567
|
+
function isTokenAddress(token, chain) {
|
|
32568
|
+
return !isTokenAlias(token) && isValidAddressForChain(token, chain);
|
|
32569
|
+
}
|
|
32570
|
+
/**
|
|
32571
|
+
* Validate and classify a token identifier.
|
|
32572
|
+
*
|
|
32573
|
+
* This function determines whether a token string is:
|
|
32574
|
+
* 1. A known alias ('USDC', 'USDT', or 'NATIVE')
|
|
32575
|
+
* 2. A valid token address for the given chain
|
|
32576
|
+
* 3. An invalid/unrecognized token identifier
|
|
32577
|
+
*
|
|
32578
|
+
* Known aliases always take precedence. If the token is not an alias,
|
|
32579
|
+
* it's validated as an address for the given chain.
|
|
32580
|
+
*
|
|
32581
|
+
* @param token - The token identifier to validate
|
|
32582
|
+
* @param chain - The chain definition for address validation
|
|
32583
|
+
* @returns An object containing validation results
|
|
32584
|
+
*
|
|
32585
|
+
* @example
|
|
32586
|
+
* ```typescript
|
|
32587
|
+
* import { validateToken } from '@circle-fin/app-kit'
|
|
32588
|
+
* import { Ethereum } from '@core/chains'
|
|
32589
|
+
*
|
|
32590
|
+
* // Known alias
|
|
32591
|
+
* const usdc = validateToken('USDC', Ethereum)
|
|
32592
|
+
* console.log(usdc) // { isAlias: true, isAddress: false, isValid: true }
|
|
32593
|
+
*
|
|
32594
|
+
* // Custom token address
|
|
32595
|
+
* const dai = validateToken('0x6B175474E89094C44Da98b954EedeAC495271d0F', Ethereum)
|
|
32596
|
+
* console.log(dai) // { isAlias: false, isAddress: true, isValid: true }
|
|
32597
|
+
*
|
|
32598
|
+
* // Invalid token
|
|
32599
|
+
* const invalid = validateToken('invalid', Ethereum)
|
|
32600
|
+
* console.log(invalid) // { isAlias: false, isAddress: false, isValid: false }
|
|
32601
|
+
* ```
|
|
32602
|
+
*/
|
|
32603
|
+
function validateToken(token, chain) {
|
|
32604
|
+
// Check if it's a known alias first (aliases take precedence)
|
|
32605
|
+
const alias = isTokenAlias(token);
|
|
32606
|
+
if (alias) {
|
|
32607
|
+
return {
|
|
32608
|
+
isAlias: true,
|
|
32609
|
+
isAddress: false,
|
|
32610
|
+
isValid: true,
|
|
32611
|
+
};
|
|
32612
|
+
}
|
|
32613
|
+
// Not an alias - check if it's a valid address for the chain
|
|
32614
|
+
const address = isTokenAddress(token, chain);
|
|
32615
|
+
return {
|
|
32616
|
+
isAlias: false,
|
|
32617
|
+
isAddress: address,
|
|
32618
|
+
isValid: address,
|
|
32619
|
+
};
|
|
32620
|
+
}
|
|
32621
|
+
|
|
32622
|
+
/**
|
|
32623
|
+
* Estimate the costs and details of a cross-chain bridge transfer using the AppKit context.
|
|
32624
|
+
*
|
|
32625
|
+
* This function provides cost estimation for bridge operations within the AppKit
|
|
32626
|
+
* ecosystem. It delegates to the underlying BridgeKit infrastructure while maintaining
|
|
32627
|
+
* consistency with the AppKit patterns and context-based architecture.
|
|
32628
|
+
*
|
|
32629
|
+
* The function validates parameters, applies context-specific configurations,
|
|
32630
|
+
* and returns comprehensive estimation details including fees, gas costs, and
|
|
32631
|
+
* transaction parameters without executing the actual transfer.
|
|
32632
|
+
*
|
|
32633
|
+
* @param context - AppKit context containing fee calculation and configuration hooks
|
|
32634
|
+
* @param params - Bridge parameters containing source, destination, amount, and token
|
|
32635
|
+
* @returns Promise resolving to the estimate result with comprehensive fee and cost information
|
|
32636
|
+
* @throws If bridge parameters are invalid
|
|
32637
|
+
* @throws If the bridge route is not supported
|
|
32638
|
+
* @throws If estimation fails due to network or configuration issues
|
|
32639
|
+
*
|
|
32640
|
+
* @example
|
|
32641
|
+
* ```typescript
|
|
32642
|
+
* import { estimateBridge } from '@circle-fin/app-kit/bridge'
|
|
32643
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
32644
|
+
*
|
|
32645
|
+
* const context = createContext({
|
|
32646
|
+
* getFee: async (type, params) => '1000000', // 1 USDC fee
|
|
32647
|
+
* getFeeRecipient: async (type, info) => '0xfee-recipient-address'
|
|
32648
|
+
* })
|
|
32649
|
+
*
|
|
32650
|
+
* const estimate = await estimateBridge(context, {
|
|
32651
|
+
* from: sourceAdapter,
|
|
32652
|
+
* to: { adapter: destAdapter, chain: 'Polygon' },
|
|
32653
|
+
* amount: '100.50',
|
|
32654
|
+
* token: 'USDC'
|
|
32655
|
+
* })
|
|
32656
|
+
*
|
|
32657
|
+
* console.log('Estimated total fee:', estimate.fee)
|
|
32658
|
+
* console.log('Estimated gas cost:', estimate.gasEstimate)
|
|
32659
|
+
* ```
|
|
32660
|
+
*/
|
|
32661
|
+
const estimateBridge = async (context, params) => {
|
|
32662
|
+
const kit = createBridgeKit(context);
|
|
32663
|
+
// Delegate to the BridgeKit for actual estimation
|
|
32664
|
+
return kit.estimate(params);
|
|
32665
|
+
};
|
|
32666
|
+
|
|
32667
|
+
const assertSendParamsSymbol = Symbol('assertSendParams');
|
|
32668
|
+
/**
|
|
32669
|
+
* Matches numeric amount strings with optional thousands separators and decimal part.
|
|
32670
|
+
*
|
|
32671
|
+
* Accepts both US (e.g. "1,234.56") and EU (e.g. "1.234,56") styles by allowing
|
|
32672
|
+
* either "," or "." as the grouping and decimal separators. Also matches integers
|
|
32673
|
+
* like "10" and simple decimals like "10.5" or "10,5".
|
|
32674
|
+
*/
|
|
32675
|
+
const amountNumericStringWithSeparatorsRegex = /^\d+(?:[.,]\d{3})*(?:[.,]\d+)?$/;
|
|
32676
|
+
/**
|
|
32677
|
+
* Schema describing the minimal adapter surface required by the kit.
|
|
32678
|
+
*
|
|
32679
|
+
* The adapter must implement two functions:
|
|
32680
|
+
* - `prepare` — build the transaction or instruction payload.
|
|
32681
|
+
* - `waitForTransaction` — await finality/confirmation for a submitted transaction.
|
|
32682
|
+
*
|
|
32683
|
+
* @returns Zod schema validating an object with `prepare` and `waitForTransaction` functions.
|
|
32684
|
+
*
|
|
32685
|
+
* @example
|
|
32686
|
+
* ```typescript
|
|
32687
|
+
* import { adapterSchema } from '@circle-fin/app-kit'
|
|
32688
|
+
*
|
|
32689
|
+
* console.log(adapterSchema.safeParse(ethereumAdapter).success) // true
|
|
32690
|
+
* ```
|
|
32691
|
+
*/
|
|
32692
|
+
const adapterSchema = zod.z.object({
|
|
32693
|
+
prepare: zod.z.function().returns(zod.z.any()),
|
|
32694
|
+
waitForTransaction: zod.z.function().returns(zod.z.any()),
|
|
32695
|
+
});
|
|
32696
|
+
/**
|
|
32697
|
+
* Schema for validating adapter contexts.
|
|
32698
|
+
* Ensure required fields are present and properly typed. An adapter context must include:
|
|
32699
|
+
* - A valid adapter with `prepare` and `waitForTransaction` methods.
|
|
32700
|
+
* - A valid chain identifier (string literal or chain object recognized by the kit).
|
|
32701
|
+
*
|
|
32702
|
+
* @returns Zod schema validating an adapter context object.
|
|
32703
|
+
* @throws ZodError If validation fails, with details about which properties failed.
|
|
32704
|
+
*
|
|
32705
|
+
* @example
|
|
32706
|
+
* ```typescript
|
|
32707
|
+
* import { adapterContextSchema } from '@circle-fin/app-kit'
|
|
32708
|
+
*
|
|
32709
|
+
* const result = adapterContextSchema.safeParse(context)
|
|
32710
|
+
* console.log(result.success) // true
|
|
32711
|
+
* ```
|
|
32712
|
+
*/
|
|
32713
|
+
const adapterContextSchema$3 = zod.z.object({
|
|
32714
|
+
adapter: adapterSchema,
|
|
32715
|
+
/**
|
|
32716
|
+
* Note: We cast chainIdentifierSchema to 'never' here to work around a TypeScript
|
|
32717
|
+
* limitation (TS2589: Type instantiation is excessively deep and possibly infinite)
|
|
29535
32718
|
* that can occur with complex Zod unions (e.g., string literals + enums).
|
|
29536
32719
|
* This cast is safe in this context because runtime validation is correct,
|
|
29537
32720
|
* and the type is enforced at the API boundary.
|
|
@@ -30058,14 +33241,15 @@ const estimateSwap = async (context, params) => {
|
|
|
30058
33241
|
* Get chains supported by AppKit operations.
|
|
30059
33242
|
*
|
|
30060
33243
|
* This helper returns the set of chains that can be used for a given
|
|
30061
|
-
* operation type (bridge, swap, or
|
|
30062
|
-
* it returns all chains known to support any
|
|
33244
|
+
* operation type (bridge, swap, earn, unified balance, or all). When no
|
|
33245
|
+
* operation type is specified, it returns all chains known to support any
|
|
33246
|
+
* AppKit operation.
|
|
30063
33247
|
*
|
|
30064
33248
|
* The result list contains unique chains and is safe to pass directly into
|
|
30065
33249
|
* higher-level flows such as chain pickers or routing logic.
|
|
30066
33250
|
*
|
|
30067
33251
|
* @param context - AppKit context containing fee configuration.
|
|
30068
|
-
* @param operationType - Optional operation type to filter chains ('bridge' | 'swap' | 'unifiedBalance').
|
|
33252
|
+
* @param operationType - Optional operation type to filter chains ('bridge' | 'swap' | 'earn' | 'unifiedBalance').
|
|
30069
33253
|
* @param unifiedBalance - Persistent AppKitUnifiedBalance namespace instance.
|
|
30070
33254
|
* @returns Array of unique chain definitions supporting the specified operation(s)
|
|
30071
33255
|
*
|
|
@@ -30091,6 +33275,12 @@ const estimateSwap = async (context, params) => {
|
|
|
30091
33275
|
* console.log('Chains supporting swap:', swapChains.map(c => c.name))
|
|
30092
33276
|
* ```
|
|
30093
33277
|
*
|
|
33278
|
+
* @example Get earn-specific chains
|
|
33279
|
+
* ```typescript
|
|
33280
|
+
* const earnChains = kit.getSupportedChains('earn')
|
|
33281
|
+
* console.log('Chains supporting earn:', earnChains.map(c => c.name))
|
|
33282
|
+
* ```
|
|
33283
|
+
*
|
|
30094
33284
|
* @example Check if specific chain supports an operation
|
|
30095
33285
|
* ```typescript
|
|
30096
33286
|
* import { Ethereum } from '@core/chains'
|
|
@@ -30105,11 +33295,12 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
|
|
|
30105
33295
|
if (operationType !== undefined &&
|
|
30106
33296
|
operationType !== 'bridge' &&
|
|
30107
33297
|
operationType !== 'swap' &&
|
|
33298
|
+
operationType !== 'earn' &&
|
|
30108
33299
|
operationType !== 'unifiedBalance') {
|
|
30109
33300
|
throw new KitError({
|
|
30110
33301
|
...InputError.VALIDATION_FAILED,
|
|
30111
33302
|
recoverability: 'FATAL',
|
|
30112
|
-
message: `Invalid operationType: "${String(operationType)}". Expected 'bridge', 'swap', or 'unifiedBalance'.`,
|
|
33303
|
+
message: `Invalid operationType: "${String(operationType)}". Expected 'bridge', 'swap', 'earn', or 'unifiedBalance'.`,
|
|
30113
33304
|
});
|
|
30114
33305
|
}
|
|
30115
33306
|
// Return bridge-specific chains
|
|
@@ -30122,23 +33313,228 @@ const getSupportedChains$2 = (context, operationType, unifiedBalance) => {
|
|
|
30122
33313
|
const swapKit = createSwapKit(context);
|
|
30123
33314
|
return swapKit.getSupportedChains();
|
|
30124
33315
|
}
|
|
33316
|
+
// Return earn-specific chains
|
|
33317
|
+
if (operationType === 'earn') {
|
|
33318
|
+
const earnKit = createEarnKit();
|
|
33319
|
+
return earnKit.getSupportedChains();
|
|
33320
|
+
}
|
|
30125
33321
|
// Return unified balance chains
|
|
30126
33322
|
if (operationType === 'unifiedBalance') {
|
|
30127
33323
|
return unifiedBalance.getSupportedChains();
|
|
30128
33324
|
}
|
|
30129
33325
|
// No operation type specified - return union of all chains
|
|
33326
|
+
// Reuse kit instances here if provider constructors become expensive or stateful.
|
|
30130
33327
|
const bridgeKit = createBridgeKit(context);
|
|
30131
33328
|
const swapKit = createSwapKit(context);
|
|
33329
|
+
const earnKit = createEarnKit();
|
|
30132
33330
|
const bridgeChains = bridgeKit.getSupportedChains();
|
|
30133
33331
|
const swapChains = swapKit.getSupportedChains();
|
|
33332
|
+
const earnChains = earnKit.getSupportedChains();
|
|
30134
33333
|
const ubChains = unifiedBalance.getSupportedChains();
|
|
30135
|
-
|
|
30136
|
-
|
|
30137
|
-
|
|
33334
|
+
// Combine chains from all operations
|
|
33335
|
+
const allChains = [...bridgeChains, ...swapChains, ...earnChains, ...ubChains];
|
|
33336
|
+
// Deduplicate by chain identifier. Later duplicates override earlier ones.
|
|
33337
|
+
return [...new Map(allChains.map((chain) => [chain.chain, chain])).values()];
|
|
30138
33338
|
};
|
|
30139
33339
|
|
|
33340
|
+
/**
|
|
33341
|
+
* Execute an earn deposit operation.
|
|
33342
|
+
*
|
|
33343
|
+
* @param context - AppKit context
|
|
33344
|
+
* @param params - Deposit parameters including source adapter, vault address, and amount
|
|
33345
|
+
* @returns Promise resolving to the earn deposit result
|
|
33346
|
+
* @throws If EarnKit validation fails, no provider is configured, or the deposit transaction fails
|
|
33347
|
+
*
|
|
33348
|
+
* @example
|
|
33349
|
+
* ```typescript
|
|
33350
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33351
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33352
|
+
* import { deposit } from '@circle-fin/app-kit/earn'
|
|
33353
|
+
*
|
|
33354
|
+
* const context = createContext()
|
|
33355
|
+
* const result = await deposit(context, {
|
|
33356
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33357
|
+
* vaultAddress: '0x...',
|
|
33358
|
+
* amount: '100.50',
|
|
33359
|
+
* })
|
|
33360
|
+
* ```
|
|
33361
|
+
*/
|
|
33362
|
+
async function deposit$2(context, params) {
|
|
33363
|
+
return createEarnKit().deposit(params);
|
|
33364
|
+
}
|
|
33365
|
+
/**
|
|
33366
|
+
* Execute an earn withdrawal operation.
|
|
33367
|
+
*
|
|
33368
|
+
* @param context - AppKit context
|
|
33369
|
+
* @param params - Withdrawal parameters including source adapter, vault address, and amount
|
|
33370
|
+
* @returns Promise resolving to the earn withdrawal result
|
|
33371
|
+
* @throws If EarnKit validation fails, no provider is configured, or the withdrawal transaction fails
|
|
33372
|
+
*
|
|
33373
|
+
* @example
|
|
33374
|
+
* ```typescript
|
|
33375
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33376
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33377
|
+
* import { withdraw } from '@circle-fin/app-kit/earn'
|
|
33378
|
+
*
|
|
33379
|
+
* const context = createContext()
|
|
33380
|
+
* const result = await withdraw(context, {
|
|
33381
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33382
|
+
* vaultAddress: '0x...',
|
|
33383
|
+
* amount: '50.00',
|
|
33384
|
+
* })
|
|
33385
|
+
* ```
|
|
33386
|
+
*/
|
|
33387
|
+
async function withdraw(context, params) {
|
|
33388
|
+
return createEarnKit().withdraw(params);
|
|
33389
|
+
}
|
|
33390
|
+
/**
|
|
33391
|
+
* Claim earn rewards.
|
|
33392
|
+
*
|
|
33393
|
+
* @param context - AppKit context
|
|
33394
|
+
* @param params - Claim rewards parameters including source adapter and vault address
|
|
33395
|
+
* @returns Promise resolving to the earn claim rewards result
|
|
33396
|
+
* @throws If EarnKit validation fails, no provider is configured, or the claim transaction fails
|
|
33397
|
+
*
|
|
33398
|
+
* @example
|
|
33399
|
+
* ```typescript
|
|
33400
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33401
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33402
|
+
* import { claimRewards } from '@circle-fin/app-kit/earn'
|
|
33403
|
+
*
|
|
33404
|
+
* const context = createContext()
|
|
33405
|
+
* const result = await claimRewards(context, {
|
|
33406
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33407
|
+
* vaultAddress: '0x...',
|
|
33408
|
+
* })
|
|
33409
|
+
* ```
|
|
33410
|
+
*/
|
|
33411
|
+
async function claimRewards(context, params) {
|
|
33412
|
+
return createEarnKit().claimRewards(params);
|
|
33413
|
+
}
|
|
33414
|
+
/**
|
|
33415
|
+
* Fetch vault information.
|
|
33416
|
+
*
|
|
33417
|
+
* @param context - AppKit context
|
|
33418
|
+
* @param params - Vault query parameters. `vaults` selects the chain and vault address pairs to query
|
|
33419
|
+
* @returns Promise resolving to vault data and per-vault errors
|
|
33420
|
+
* @throws If EarnKit validation fails or no provider is configured
|
|
33421
|
+
*
|
|
33422
|
+
* @example
|
|
33423
|
+
* ```typescript
|
|
33424
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33425
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33426
|
+
* import { getVaults } from '@circle-fin/app-kit/earn'
|
|
33427
|
+
*
|
|
33428
|
+
* const context = createContext()
|
|
33429
|
+
* const result = await getVaults(context, {
|
|
33430
|
+
* vaults: [{ chain: EarnChain.Arc_Testnet, vaultAddress: '0x...' }],
|
|
33431
|
+
* })
|
|
33432
|
+
* ```
|
|
33433
|
+
*/
|
|
33434
|
+
async function getVaults(context, params) {
|
|
33435
|
+
return createEarnKit().getVaults(params);
|
|
33436
|
+
}
|
|
33437
|
+
/**
|
|
33438
|
+
* Fetch a wallet position in a vault.
|
|
33439
|
+
*
|
|
33440
|
+
* @param context - AppKit context
|
|
33441
|
+
* @param params - Position parameters including source adapter and vault address
|
|
33442
|
+
* @returns Promise resolving to wallet position information
|
|
33443
|
+
* @throws If EarnKit validation fails or no provider is configured
|
|
33444
|
+
*
|
|
33445
|
+
* @example
|
|
33446
|
+
* ```typescript
|
|
33447
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33448
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33449
|
+
* import { getPosition } from '@circle-fin/app-kit/earn'
|
|
33450
|
+
*
|
|
33451
|
+
* const context = createContext()
|
|
33452
|
+
* const position = await getPosition(context, {
|
|
33453
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33454
|
+
* vaultAddress: '0x...',
|
|
33455
|
+
* })
|
|
33456
|
+
* ```
|
|
33457
|
+
*/
|
|
33458
|
+
async function getPosition(context, params) {
|
|
33459
|
+
return createEarnKit().getPosition(params);
|
|
33460
|
+
}
|
|
33461
|
+
/**
|
|
33462
|
+
* Fetch a deposit quote.
|
|
33463
|
+
*
|
|
33464
|
+
* @param context - AppKit context
|
|
33465
|
+
* @param params - Deposit quote parameters including source adapter, vault address, and amount
|
|
33466
|
+
* @returns Promise resolving to deposit quote information
|
|
33467
|
+
* @throws If EarnKit validation fails or no provider is configured
|
|
33468
|
+
*
|
|
33469
|
+
* @example
|
|
33470
|
+
* ```typescript
|
|
33471
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33472
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33473
|
+
* import { getDepositQuote } from '@circle-fin/app-kit/earn'
|
|
33474
|
+
*
|
|
33475
|
+
* const context = createContext()
|
|
33476
|
+
* const quote = await getDepositQuote(context, {
|
|
33477
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33478
|
+
* vaultAddress: '0x...',
|
|
33479
|
+
* amount: '100.50',
|
|
33480
|
+
* })
|
|
33481
|
+
* ```
|
|
33482
|
+
*/
|
|
33483
|
+
async function getDepositQuote(context, params) {
|
|
33484
|
+
return createEarnKit().getDepositQuote(params);
|
|
33485
|
+
}
|
|
33486
|
+
/**
|
|
33487
|
+
* Fetch a withdrawal quote.
|
|
33488
|
+
*
|
|
33489
|
+
* @param context - AppKit context
|
|
33490
|
+
* @param params - Withdrawal quote parameters including source adapter, vault address, and amount
|
|
33491
|
+
* @returns Promise resolving to withdrawal quote information
|
|
33492
|
+
* @throws If EarnKit validation fails or no provider is configured
|
|
33493
|
+
*
|
|
33494
|
+
* @example
|
|
33495
|
+
* ```typescript
|
|
33496
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33497
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33498
|
+
* import { getWithdrawalQuote } from '@circle-fin/app-kit/earn'
|
|
33499
|
+
*
|
|
33500
|
+
* const context = createContext()
|
|
33501
|
+
* const quote = await getWithdrawalQuote(context, {
|
|
33502
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33503
|
+
* vaultAddress: '0x...',
|
|
33504
|
+
* amount: '50.00',
|
|
33505
|
+
* })
|
|
33506
|
+
* ```
|
|
33507
|
+
*/
|
|
33508
|
+
async function getWithdrawalQuote(context, params) {
|
|
33509
|
+
return createEarnKit().getWithdrawalQuote(params);
|
|
33510
|
+
}
|
|
33511
|
+
/**
|
|
33512
|
+
* Fetch a claim rewards quote.
|
|
33513
|
+
*
|
|
33514
|
+
* @param context - AppKit context
|
|
33515
|
+
* @param params - Claim rewards quote parameters including source adapter and vault address
|
|
33516
|
+
* @returns Promise resolving to claim rewards quote information
|
|
33517
|
+
* @throws If EarnKit validation fails or no provider is configured
|
|
33518
|
+
*
|
|
33519
|
+
* @example
|
|
33520
|
+
* ```typescript
|
|
33521
|
+
* import { EarnChain } from '@circle-fin/app-kit'
|
|
33522
|
+
* import { createContext } from '@circle-fin/app-kit/context'
|
|
33523
|
+
* import { getClaimRewardsQuote } from '@circle-fin/app-kit/earn'
|
|
33524
|
+
*
|
|
33525
|
+
* const context = createContext()
|
|
33526
|
+
* const quote = await getClaimRewardsQuote(context, {
|
|
33527
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
33528
|
+
* vaultAddress: '0x...',
|
|
33529
|
+
* })
|
|
33530
|
+
* ```
|
|
33531
|
+
*/
|
|
33532
|
+
async function getClaimRewardsQuote(context, params) {
|
|
33533
|
+
return createEarnKit().getClaimRewardsQuote(params);
|
|
33534
|
+
}
|
|
33535
|
+
|
|
30140
33536
|
var name = "@circle-fin/unified-balance-kit";
|
|
30141
|
-
var version = "1.1.
|
|
33537
|
+
var version = "1.1.2";
|
|
30142
33538
|
var pkg = {
|
|
30143
33539
|
name: name,
|
|
30144
33540
|
version: version};
|
|
@@ -37057,7 +40453,7 @@ class AppKitUnifiedBalance {
|
|
|
37057
40453
|
}
|
|
37058
40454
|
|
|
37059
40455
|
/**
|
|
37060
|
-
* A high-level SDK for stablecoin operations, including bridging and
|
|
40456
|
+
* A high-level SDK for stablecoin operations, including bridging, swapping, and earn.
|
|
37061
40457
|
*
|
|
37062
40458
|
* The AppKit provides a unified interface for various stablecoin operations
|
|
37063
40459
|
* with strongly typed parameters and comprehensive fee estimation capabilities.
|
|
@@ -37068,6 +40464,7 @@ class AppKitUnifiedBalance {
|
|
|
37068
40464
|
* - Strongly typed fee estimation with operation-specific parameters
|
|
37069
40465
|
* - Cross-chain USDC bridging through CCTPv2
|
|
37070
40466
|
* - Same-chain token swapping between USDC, USDT, and native tokens
|
|
40467
|
+
* - Earn vault deposits, withdrawals, rewards, and quote queries
|
|
37071
40468
|
* - Token sending operations
|
|
37072
40469
|
* - Comprehensive error handling and validation
|
|
37073
40470
|
* - Full TypeScript support with IntelliSense
|
|
@@ -37100,6 +40497,13 @@ class AppKitUnifiedBalance {
|
|
|
37100
40497
|
* amountIn: '50.00'
|
|
37101
40498
|
* })
|
|
37102
40499
|
*
|
|
40500
|
+
* // Query an earn vault
|
|
40501
|
+
* const quote = await kit.earn.getDepositQuote({
|
|
40502
|
+
* from: { adapter, chain: 'Arc_Testnet' },
|
|
40503
|
+
* vaultAddress: '0x...',
|
|
40504
|
+
* amount: '100.50',
|
|
40505
|
+
* })
|
|
40506
|
+
*
|
|
37103
40507
|
* // Query unified balances across chains
|
|
37104
40508
|
* const balances = await kit.unifiedBalance.getBalances({
|
|
37105
40509
|
* token: 'USDC',
|
|
@@ -37114,6 +40518,25 @@ class AppKitUnifiedBalance {
|
|
|
37114
40518
|
*/
|
|
37115
40519
|
class AppKit {
|
|
37116
40520
|
context;
|
|
40521
|
+
/**
|
|
40522
|
+
* Earn operations exposed under `kit.earn`.
|
|
40523
|
+
*
|
|
40524
|
+
* @see {@link AppKitEarnOperations}
|
|
40525
|
+
*
|
|
40526
|
+
* @example
|
|
40527
|
+
* ```typescript
|
|
40528
|
+
* import { AppKit, EarnChain } from '@circle-fin/app-kit'
|
|
40529
|
+
*
|
|
40530
|
+
* const kit = new AppKit()
|
|
40531
|
+
*
|
|
40532
|
+
* const result = await kit.earn.deposit({
|
|
40533
|
+
* from: { adapter, chain: EarnChain.Arc_Testnet },
|
|
40534
|
+
* vaultAddress: '0x...',
|
|
40535
|
+
* amount: '100.50',
|
|
40536
|
+
* })
|
|
40537
|
+
* ```
|
|
40538
|
+
*/
|
|
40539
|
+
earn;
|
|
37117
40540
|
/**
|
|
37118
40541
|
* Namespace object for unified balance operations (deposit, spend,
|
|
37119
40542
|
* balance queries, delegation, fund removal).
|
|
@@ -37167,6 +40590,16 @@ class AppKit {
|
|
|
37167
40590
|
disableErrorReporting: config.disableErrorReporting,
|
|
37168
40591
|
}),
|
|
37169
40592
|
});
|
|
40593
|
+
this.earn = {
|
|
40594
|
+
deposit: async (params) => deposit$2(this.context, params),
|
|
40595
|
+
withdraw: async (params) => withdraw(this.context, params),
|
|
40596
|
+
claimRewards: async (params) => claimRewards(this.context, params),
|
|
40597
|
+
getVaults: async (params) => getVaults(this.context, params),
|
|
40598
|
+
getPosition: async (params) => getPosition(this.context, params),
|
|
40599
|
+
getDepositQuote: async (params) => getDepositQuote(this.context, params),
|
|
40600
|
+
getWithdrawalQuote: async (params) => getWithdrawalQuote(this.context, params),
|
|
40601
|
+
getClaimRewardsQuote: async (params) => getClaimRewardsQuote(this.context, params),
|
|
40602
|
+
};
|
|
37170
40603
|
}
|
|
37171
40604
|
/**
|
|
37172
40605
|
* Execute a cross-chain USDC bridge transfer.
|
|
@@ -37424,9 +40857,9 @@ class AppKit {
|
|
|
37424
40857
|
*
|
|
37425
40858
|
* Returns blockchain networks that support specific stablecoin operations.
|
|
37426
40859
|
* When no operation type is specified, returns all chains supporting any
|
|
37427
|
-
* operation (bridge, swap, or unified balance).
|
|
40860
|
+
* operation (bridge, swap, earn, or unified balance).
|
|
37428
40861
|
*
|
|
37429
|
-
* @param operationType - Optional operation type to filter chains ('bridge' | 'swap' | 'unifiedBalance')
|
|
40862
|
+
* @param operationType - Optional operation type to filter chains ('bridge' | 'swap' | 'earn' | 'unifiedBalance')
|
|
37430
40863
|
* @returns Array of unique chain definitions supporting the specified operation(s)
|
|
37431
40864
|
*
|
|
37432
40865
|
* @example Get all supported chains
|
|
@@ -37489,6 +40922,8 @@ class AppKit {
|
|
|
37489
40922
|
|
|
37490
40923
|
exports.AppKit = AppKit;
|
|
37491
40924
|
exports.BalanceError = BalanceError;
|
|
40925
|
+
exports.EarnError = EarnError;
|
|
40926
|
+
exports.EarnKit = EarnKit;
|
|
37492
40927
|
exports.InputError = InputError;
|
|
37493
40928
|
exports.KitError = KitError;
|
|
37494
40929
|
exports.NetworkError = NetworkError;
|
|
@@ -37497,9 +40932,26 @@ exports.RateLimitError = RateLimitError;
|
|
|
37497
40932
|
exports.RpcError = RpcError;
|
|
37498
40933
|
exports.ServiceError = ServiceError;
|
|
37499
40934
|
exports.TOKEN_ALIASES = TOKEN_ALIASES;
|
|
40935
|
+
exports.claimRewardsParamsSchema = claimRewardsParamsSchema;
|
|
40936
|
+
exports.createEarnKitContext = createEarnKitContext;
|
|
40937
|
+
exports.depositParamsSchema = depositParamsSchema$1;
|
|
40938
|
+
exports.earnClaimRewards = claimRewards$1;
|
|
40939
|
+
exports.earnDeposit = deposit$3;
|
|
40940
|
+
exports.earnGetClaimRewardsQuote = getClaimRewardsQuote$1;
|
|
40941
|
+
exports.earnGetDepositQuote = getDepositQuote$1;
|
|
40942
|
+
exports.earnGetPosition = getPosition$1;
|
|
40943
|
+
exports.earnGetSupportedChains = getSupportedChains$3;
|
|
40944
|
+
exports.earnGetVaults = getVaults$1;
|
|
40945
|
+
exports.earnGetWithdrawalQuote = getWithdrawalQuote$1;
|
|
40946
|
+
exports.earnWithdraw = withdraw$1;
|
|
40947
|
+
exports.getClaimRewardsQuoteParamsSchema = getClaimRewardsQuoteParamsSchema;
|
|
40948
|
+
exports.getDepositQuoteParamsSchema = getDepositQuoteParamsSchema;
|
|
37500
40949
|
exports.getErrorCode = getErrorCode;
|
|
37501
40950
|
exports.getErrorMessage = getErrorMessage;
|
|
40951
|
+
exports.getPositionParamsSchema = getPositionParamsSchema;
|
|
37502
40952
|
exports.getTokenDecimals = getTokenDecimals;
|
|
40953
|
+
exports.getVaultsParamsSchema = getVaultsParamsSchema;
|
|
40954
|
+
exports.getWithdrawalQuoteParamsSchema = getWithdrawalQuoteParamsSchema;
|
|
37503
40955
|
exports.isBalanceError = isBalanceError;
|
|
37504
40956
|
exports.isFatalError = isFatalError;
|
|
37505
40957
|
exports.isInputError = isInputError;
|
|
@@ -37515,4 +40967,5 @@ exports.isTokenAlias = isTokenAlias;
|
|
|
37515
40967
|
exports.isUserCancellationError = isUserCancellationError;
|
|
37516
40968
|
exports.setExternalPrefix = setExternalPrefix;
|
|
37517
40969
|
exports.validateToken = validateToken;
|
|
40970
|
+
exports.withdrawParamsSchema = withdrawParamsSchema;
|
|
37518
40971
|
//# sourceMappingURL=index.cjs.map
|