@circle-fin/app-kit 1.15.1 → 1.15.3
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 +12 -0
- package/bridge.cjs +61 -18
- package/bridge.d.cts +71 -0
- package/bridge.d.mts +71 -0
- package/bridge.d.ts +71 -0
- package/bridge.mjs +61 -18
- package/context.d.cts +71 -0
- package/context.d.mts +71 -0
- package/context.d.ts +71 -0
- package/earn.cjs +383 -43
- package/earn.d.cts +19 -26
- package/earn.d.mts +19 -26
- package/earn.d.ts +19 -26
- package/earn.mjs +383 -43
- package/estimateBridge.cjs +61 -18
- package/estimateBridge.d.cts +71 -0
- package/estimateBridge.d.mts +71 -0
- package/estimateBridge.d.ts +71 -0
- package/estimateBridge.mjs +61 -18
- package/estimateSwap.cjs +59 -16
- package/estimateSwap.d.cts +71 -0
- package/estimateSwap.d.mts +71 -0
- package/estimateSwap.d.ts +71 -0
- package/estimateSwap.mjs +59 -16
- package/index.cjs +291 -63
- package/index.d.cts +184 -91
- package/index.d.mts +184 -91
- package/index.d.ts +184 -91
- package/index.mjs +291 -63
- package/package.json +4 -4
- package/server.cjs +13 -17
- package/server.d.cts +10 -9
- package/server.d.mts +10 -9
- package/server.d.ts +10 -9
- package/server.mjs +13 -17
- package/swap.cjs +59 -16
- package/swap.d.cts +71 -0
- package/swap.d.mts +71 -0
- package/swap.d.ts +71 -0
- package/swap.mjs +59 -16
package/index.mjs
CHANGED
|
@@ -13600,7 +13600,7 @@ function resolveOptions(options) {
|
|
|
13600
13600
|
}
|
|
13601
13601
|
|
|
13602
13602
|
var name$4 = "@circle-fin/bridge-kit";
|
|
13603
|
-
var version$5 = "1.15.
|
|
13603
|
+
var version$5 = "1.15.1";
|
|
13604
13604
|
var pkg$5 = {
|
|
13605
13605
|
name: name$4,
|
|
13606
13606
|
version: version$5};
|
|
@@ -14792,7 +14792,7 @@ function createBridgeParamsSchema(tokenSchema, config) {
|
|
|
14792
14792
|
/**
|
|
14793
14793
|
* `POST` — returns a server-signed fee quote for a CCTPx transfer of the
|
|
14794
14794
|
* given `tokenId` between the named source and destination domains.
|
|
14795
|
-
*/ const CCTPX_FEE_QUOTE_PATH = '/
|
|
14795
|
+
*/ const CCTPX_FEE_QUOTE_PATH = '/v2/quote/cctpx/{tokenId}/{sourceDomain}/{destinationDomain}';
|
|
14796
14796
|
/**
|
|
14797
14797
|
* `GET` — returns the remaining fast-burn allowance for the given
|
|
14798
14798
|
* `tokenIds` (a comma-separated query param of bytes32 token ids). Backs
|
|
@@ -16323,7 +16323,7 @@ function createNoopLogger() {
|
|
|
16323
16323
|
})
|
|
16324
16324
|
]);
|
|
16325
16325
|
/**
|
|
16326
|
-
* Schema for `POST /
|
|
16326
|
+
* Schema for `POST /v2/quote/cctpx/{tokenId}/{src}/{dst}`.
|
|
16327
16327
|
*
|
|
16328
16328
|
* Use {@link parseOrThrow} from `@core/utils` to validate payloads
|
|
16329
16329
|
* against this schema.
|
|
@@ -44514,7 +44514,7 @@ registerKit(`${pkg$3.name}/${pkg$3.version}`);
|
|
|
44514
44514
|
};
|
|
44515
44515
|
|
|
44516
44516
|
var name$2 = "@circle-fin/earn-kit";
|
|
44517
|
-
var version$2 = "1.
|
|
44517
|
+
var version$2 = "1.8.0";
|
|
44518
44518
|
var pkg$2 = {
|
|
44519
44519
|
name: name$2,
|
|
44520
44520
|
version: version$2};
|
|
@@ -45053,6 +45053,142 @@ const GAS_SAFETY_MULTIPLIER_DENOMINATOR = 10n;
|
|
|
45053
45053
|
};
|
|
45054
45054
|
}
|
|
45055
45055
|
|
|
45056
|
+
/**
|
|
45057
|
+
* Fallback gas reserve expressed in ERC-20 deposit token base units when no
|
|
45058
|
+
* quote gas fees are available. 50_000 = 0.05 USDC at the 6-decimal ERC-20
|
|
45059
|
+
* USDC scale used on Arc (and the scale of `balance` / `depositAmountRaw`).
|
|
45060
|
+
*
|
|
45061
|
+
* @internal
|
|
45062
|
+
*/ const DEFAULT_GAS_RESERVE = 50_000n;
|
|
45063
|
+
/**
|
|
45064
|
+
* Standard ERC-20 decimal precision for USDC and EURC. Both tokens use 6
|
|
45065
|
+
* decimals on all EVM chains, regardless of how many decimals the native
|
|
45066
|
+
* gas-token representation uses.
|
|
45067
|
+
*
|
|
45068
|
+
* @internal
|
|
45069
|
+
*/ const STABLECOIN_ERC20_DECIMALS = 6;
|
|
45070
|
+
/**
|
|
45071
|
+
* Compute the gas reserve in ERC-20 deposit token base units.
|
|
45072
|
+
*
|
|
45073
|
+
* `EstimatedGas.fee` is denominated in the chain's native currency base units
|
|
45074
|
+
* (e.g. 18-decimal USDC on Arc). The deposit token balance and
|
|
45075
|
+
* `depositAmountRaw` are in ERC-20 token base units (e.g. 6-decimal USDC).
|
|
45076
|
+
* This function converts the native fee total to the same scale so both sides
|
|
45077
|
+
* of the `balance < required` comparison are commensurable.
|
|
45078
|
+
*
|
|
45079
|
+
* Conversion: `fee_token_units = fee_native_units / 10^(nativeDecimals - tokenDecimals)`
|
|
45080
|
+
*
|
|
45081
|
+
* Falls back to {@link DEFAULT_GAS_RESERVE} when:
|
|
45082
|
+
* - `gasFees` is absent or empty
|
|
45083
|
+
* - all fee entries have `fees: null` (estimation failed)
|
|
45084
|
+
* - the converted total rounds to zero (native fee smaller than 1 token unit)
|
|
45085
|
+
*
|
|
45086
|
+
* @internal
|
|
45087
|
+
*/ function computeGasReserve(gasFees, nativeDecimals, tokenDecimals) {
|
|
45088
|
+
if (gasFees === undefined || gasFees.length === 0) {
|
|
45089
|
+
return DEFAULT_GAS_RESERVE;
|
|
45090
|
+
}
|
|
45091
|
+
let totalNative = 0n;
|
|
45092
|
+
let hasNullEntry = false;
|
|
45093
|
+
for (const entry of gasFees){
|
|
45094
|
+
if (entry.fees === null) {
|
|
45095
|
+
hasNullEntry = true;
|
|
45096
|
+
} else {
|
|
45097
|
+
totalNative += BigInt(entry.fees.fee);
|
|
45098
|
+
}
|
|
45099
|
+
}
|
|
45100
|
+
const decimalDiff = nativeDecimals - tokenDecimals;
|
|
45101
|
+
// Use ceiling division when reducing precision so we never under-estimate.
|
|
45102
|
+
const scale = decimalDiff > 0 ? 10n ** BigInt(decimalDiff) : 1n;
|
|
45103
|
+
let knownToken;
|
|
45104
|
+
if (totalNative === 0n) {
|
|
45105
|
+
knownToken = 0n;
|
|
45106
|
+
} else if (decimalDiff > 0) {
|
|
45107
|
+
knownToken = (totalNative + scale - 1n) / scale;
|
|
45108
|
+
} else {
|
|
45109
|
+
knownToken = totalNative * 10n ** BigInt(-decimalDiff);
|
|
45110
|
+
}
|
|
45111
|
+
// When any estimate is missing the true total is unknown, so reserve at
|
|
45112
|
+
// least DEFAULT_GAS_RESERVE on top of whatever was already known.
|
|
45113
|
+
// BigInt is not supported by Math.max, so we use an explicit comparison.
|
|
45114
|
+
if (hasNullEntry) {
|
|
45115
|
+
return knownToken > DEFAULT_GAS_RESERVE ? knownToken : DEFAULT_GAS_RESERVE // NOSONAR
|
|
45116
|
+
;
|
|
45117
|
+
}
|
|
45118
|
+
return knownToken > 0n ? knownToken : DEFAULT_GAS_RESERVE;
|
|
45119
|
+
}
|
|
45120
|
+
/**
|
|
45121
|
+
* Build a symbol → ERC-20 address map from the chain's known token addresses.
|
|
45122
|
+
* Used to resolve whether the native gas token corresponds to the deposit
|
|
45123
|
+
* token's address.
|
|
45124
|
+
*
|
|
45125
|
+
* @internal
|
|
45126
|
+
*/ function buildSymbolAddressMap(chain) {
|
|
45127
|
+
const map = new Map();
|
|
45128
|
+
if (chain.usdcAddress != null) {
|
|
45129
|
+
map.set('USDC', chain.usdcAddress.toLowerCase());
|
|
45130
|
+
}
|
|
45131
|
+
if (chain.eurcAddress != null) {
|
|
45132
|
+
map.set('EURC', chain.eurcAddress.toLowerCase());
|
|
45133
|
+
}
|
|
45134
|
+
return map;
|
|
45135
|
+
}
|
|
45136
|
+
/**
|
|
45137
|
+
* Pre-broadcast balance check for EOA wallets on chains where the native gas
|
|
45138
|
+
* token and the deposit token are the same asset (e.g. Arc: USDC gas + USDC
|
|
45139
|
+
* deposit).
|
|
45140
|
+
*
|
|
45141
|
+
* When the deposit would consume the entire balance, the adapter locks gas
|
|
45142
|
+
* before `transferFrom`, causing an `ERC20: transfer amount exceeds balance`
|
|
45143
|
+
* revert on-chain. This function reads the wallet balance before broadcast and
|
|
45144
|
+
* throws {@link BalanceError.INSUFFICIENT_TOKEN} (code 9001) when
|
|
45145
|
+
* `balance < depositAmount + gasReserve`, giving callers a clean pre-broadcast
|
|
45146
|
+
* error instead of an opaque chain revert.
|
|
45147
|
+
*
|
|
45148
|
+
* The check is skipped when the chain's native gas currency symbol does not
|
|
45149
|
+
* match the deposit token symbol (derived by address lookup). Examples of
|
|
45150
|
+
* chains where the check is skipped: EURC deposit on Arc, any ETH-gas chain.
|
|
45151
|
+
*
|
|
45152
|
+
* Gas fees from the quote (`gasFees`) are in native-currency base units
|
|
45153
|
+
* (18-decimal on Arc) and are scaled down to ERC-20 token units (6-decimal)
|
|
45154
|
+
* before being added to `depositAmountRaw`.
|
|
45155
|
+
*
|
|
45156
|
+
* @param params - Adapter context, chain, deposit token, amount, and optional
|
|
45157
|
+
* quote gas fees.
|
|
45158
|
+
* @throws {@link KitError} (code 9001) when the balance is insufficient to
|
|
45159
|
+
* cover both the deposit and the gas reserve.
|
|
45160
|
+
*
|
|
45161
|
+
* @internal
|
|
45162
|
+
*/ async function checkGasReserveForDeposit(params) {
|
|
45163
|
+
const { adapter, chain, address, depositTokenAddress, depositAmountRaw, gasFees } = params;
|
|
45164
|
+
const nativeSymbol = chain.nativeCurrency.symbol.toUpperCase();
|
|
45165
|
+
const symbolAddressMap = buildSymbolAddressMap(chain);
|
|
45166
|
+
const nativeTokenAddress = symbolAddressMap.get(nativeSymbol);
|
|
45167
|
+
// Only applies when native gas currency and deposit token are the same asset.
|
|
45168
|
+
if (nativeTokenAddress === undefined || depositTokenAddress.toLowerCase() !== nativeTokenAddress) {
|
|
45169
|
+
return;
|
|
45170
|
+
}
|
|
45171
|
+
const rawBalance = await executeAdapterReadAction(adapter, 'token.balanceOf', {
|
|
45172
|
+
tokenAddress: depositTokenAddress,
|
|
45173
|
+
walletAddress: address
|
|
45174
|
+
}, {
|
|
45175
|
+
chain,
|
|
45176
|
+
address
|
|
45177
|
+
});
|
|
45178
|
+
const balance = BigInt(String(rawBalance));
|
|
45179
|
+
// Both USDC and EURC use 6 ERC-20 decimals; the check only reaches here when
|
|
45180
|
+
// the deposit token is the chain's native gas asset (USDC or EURC).
|
|
45181
|
+
const gasReserve = computeGasReserve(gasFees, chain.nativeCurrency.decimals, STABLECOIN_ERC20_DECIMALS);
|
|
45182
|
+
const required = depositAmountRaw + gasReserve;
|
|
45183
|
+
if (balance < required) {
|
|
45184
|
+
throw new KitError({
|
|
45185
|
+
...BalanceError.INSUFFICIENT_TOKEN,
|
|
45186
|
+
recoverability: 'FATAL',
|
|
45187
|
+
message: `Insufficient ${chain.nativeCurrency.symbol} balance to cover deposit and gas. Balance: ${balance.toString()}, required: ${required.toString()} (deposit: ${depositAmountRaw.toString()} + gas reserve: ${gasReserve.toString()})`
|
|
45188
|
+
});
|
|
45189
|
+
}
|
|
45190
|
+
}
|
|
45191
|
+
|
|
45056
45192
|
/** @internal */ function isSameAddress(actual, expected) {
|
|
45057
45193
|
return actual.toLowerCase() === expected.toLowerCase();
|
|
45058
45194
|
}
|
|
@@ -46442,12 +46578,19 @@ const EARN_OPERATIONS = new Set([
|
|
|
46442
46578
|
writable: true,
|
|
46443
46579
|
configurable: true
|
|
46444
46580
|
});
|
|
46581
|
+
// Surface the tx hash in the message so callers can look it up without
|
|
46582
|
+
// digging into cause.trace. Only applies to on-chain reverts — other errors
|
|
46583
|
+
// either have no tx hash or already embed it in their message.
|
|
46584
|
+
let message = base.message;
|
|
46585
|
+
if (base.name === 'ONCHAIN_TRANSACTION_REVERTED' && typeof existingTrace['txHash'] === 'string' && existingTrace['txHash'] !== '') {
|
|
46586
|
+
message = `${message} (txHash: ${existingTrace['txHash']})`;
|
|
46587
|
+
}
|
|
46445
46588
|
return new KitError({
|
|
46446
46589
|
code: base.code,
|
|
46447
46590
|
name: base.name,
|
|
46448
46591
|
type: base.type,
|
|
46449
46592
|
recoverability,
|
|
46450
|
-
message
|
|
46593
|
+
message,
|
|
46451
46594
|
cause: {
|
|
46452
46595
|
trace
|
|
46453
46596
|
}
|
|
@@ -46563,10 +46706,8 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
46563
46706
|
assetAddress: z.string(),
|
|
46564
46707
|
lltv: z.number(),
|
|
46565
46708
|
supplyUsd: z.number(),
|
|
46566
|
-
//
|
|
46567
|
-
|
|
46568
|
-
// schema; `null` when the product exposes no per-market allocation (V2).
|
|
46569
|
-
allocationPct: z.number().nullable().optional()
|
|
46709
|
+
// `null` when the product exposes no per-market allocation (V2).
|
|
46710
|
+
allocationPct: z.number().nullable()
|
|
46570
46711
|
});
|
|
46571
46712
|
/**
|
|
46572
46713
|
* Zod schema for a Morpho vault warning in the API response.
|
|
@@ -46673,19 +46814,20 @@ const bridgeFeeTokenSchema = hexAddressSchema;
|
|
|
46673
46814
|
earnKitWarnings: z.array(z.string()).optional()
|
|
46674
46815
|
});
|
|
46675
46816
|
/**
|
|
46676
|
-
* Shared base schema: existing flat fields (kept
|
|
46677
|
-
* facets
|
|
46678
|
-
*
|
|
46817
|
+
* Shared base schema: existing flat fields (kept as deprecated aliases) plus
|
|
46818
|
+
* the nested facets. Zenith emits all facets on every response; required here
|
|
46819
|
+
* so a partial emission is caught at parse time rather than surfacing as a
|
|
46820
|
+
* runtime `undefined` access.
|
|
46679
46821
|
*
|
|
46680
46822
|
* @internal
|
|
46681
46823
|
*/ const earnBaseSchema = vaultInfoResponseSchema.extend({
|
|
46682
|
-
address: z.string()
|
|
46683
|
-
asOf: z.string()
|
|
46684
|
-
manager: managerSchema.nullable()
|
|
46685
|
-
apyProfile: apyProfileSchema
|
|
46686
|
-
fee: feeInfoSchema
|
|
46687
|
-
liquidityProfile: liquidityProfileSchema
|
|
46688
|
-
riskSignals: riskSignalsSchema
|
|
46824
|
+
address: z.string(),
|
|
46825
|
+
asOf: z.string(),
|
|
46826
|
+
manager: managerSchema.nullable(),
|
|
46827
|
+
apyProfile: apyProfileSchema,
|
|
46828
|
+
fee: feeInfoSchema,
|
|
46829
|
+
liquidityProfile: liquidityProfileSchema,
|
|
46830
|
+
riskSignals: riskSignalsSchema
|
|
46689
46831
|
});
|
|
46690
46832
|
/**
|
|
46691
46833
|
* Zod schema for the `vault` opportunity variant.
|
|
@@ -47473,7 +47615,7 @@ const bridgeDepositPrepareReviewSchema = z.object({
|
|
|
47473
47615
|
}
|
|
47474
47616
|
|
|
47475
47617
|
var name$1 = "@circle-fin/provider-earn-service";
|
|
47476
|
-
var version$1 = "1.
|
|
47618
|
+
var version$1 = "1.7.0";
|
|
47477
47619
|
var pkg$1 = {
|
|
47478
47620
|
name: name$1,
|
|
47479
47621
|
version: version$1};
|
|
@@ -47621,23 +47763,16 @@ var pkg$1 = {
|
|
|
47621
47763
|
if (chain === undefined) {
|
|
47622
47764
|
throw createInvalidChainError(vault.chain, 'Chain returned by the Earn Service is not supported by the SDK');
|
|
47623
47765
|
}
|
|
47624
|
-
// The nested facets are `.optional()` in the schema (a backend that predates
|
|
47625
|
-
// them omits them) and are typed optional on `EarnOpportunity` to match.
|
|
47626
|
-
// Convert the nested liquidity amounts when present and pass the remaining
|
|
47627
|
-
// facets straight through; each absent facet stays absent rather than being
|
|
47628
|
-
// asserted present by a cast.
|
|
47629
47766
|
return {
|
|
47630
47767
|
...vault,
|
|
47631
47768
|
chain,
|
|
47632
47769
|
totalDeposits: Amount.fromJSON(totalDeposits),
|
|
47633
47770
|
liquidity: Amount.fromJSON(liquidity),
|
|
47634
|
-
|
|
47635
|
-
liquidityProfile
|
|
47636
|
-
|
|
47637
|
-
|
|
47638
|
-
|
|
47639
|
-
totalSupply: Amount.fromJSON(liquidityProfile.totalSupply)
|
|
47640
|
-
}
|
|
47771
|
+
liquidityProfile: {
|
|
47772
|
+
...liquidityProfile,
|
|
47773
|
+
totalDeposits: Amount.fromJSON(liquidityProfile.totalDeposits),
|
|
47774
|
+
available: Amount.fromJSON(liquidityProfile.available),
|
|
47775
|
+
totalSupply: Amount.fromJSON(liquidityProfile.totalSupply)
|
|
47641
47776
|
}
|
|
47642
47777
|
};
|
|
47643
47778
|
}
|
|
@@ -49153,6 +49288,24 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
49153
49288
|
amount: params.amount
|
|
49154
49289
|
};
|
|
49155
49290
|
}
|
|
49291
|
+
// Only EOA wallets pay native gas from their own balance — SCAs have
|
|
49292
|
+
// their gas sponsored externally. Detect EOA by checking that the
|
|
49293
|
+
// adapter supports readBytecode and the wallet address has no on-chain
|
|
49294
|
+
// bytecode (empty code ⟹ EOA; non-empty ⟹ smart-contract account).
|
|
49295
|
+
// EIP-7702-delegated addresses are treated as EOA by isContractSigner.
|
|
49296
|
+
// If the adapter does not expose readBytecode (non-EVM adapter) the
|
|
49297
|
+
// check is skipped conservatively.
|
|
49298
|
+
if (approvalToken !== undefined && requiredAllowance > 0n && chain.type === 'evm' && isEvmAdapterLike(adapter) && !await isContractSigner(adapter, address, chain)) {
|
|
49299
|
+
const sameChainParams = params;
|
|
49300
|
+
await checkGasReserveForDeposit({
|
|
49301
|
+
adapter,
|
|
49302
|
+
chain,
|
|
49303
|
+
address,
|
|
49304
|
+
depositTokenAddress: approvalToken,
|
|
49305
|
+
depositAmountRaw: requiredAllowance,
|
|
49306
|
+
gasFees: sameChainParams.gasFees
|
|
49307
|
+
});
|
|
49308
|
+
}
|
|
49156
49309
|
if (!options.skipApprove && approvalToken !== undefined && requiredAllowance > 0n) {
|
|
49157
49310
|
await this.runPhase(ctx, 'approve', 'approve', async ()=>{
|
|
49158
49311
|
try {
|
|
@@ -49559,7 +49712,7 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
49559
49712
|
// Gas is estimated server-side by the Earn Service and returned on the quote, so the
|
|
49560
49713
|
// SDK no longer simulates it locally. `chainDefinition` lets the fetch fill
|
|
49561
49714
|
// the native token symbol / blockchain on each gas entry.
|
|
49562
|
-
|
|
49715
|
+
const quote = await fetchDepositQuote({
|
|
49563
49716
|
vaultAddress: params.vaultAddress,
|
|
49564
49717
|
amount: params.amount,
|
|
49565
49718
|
address,
|
|
@@ -49567,6 +49720,34 @@ function finishElapsedWait(lastStatus, lastError) {
|
|
|
49567
49720
|
config,
|
|
49568
49721
|
chainDefinition
|
|
49569
49722
|
});
|
|
49723
|
+
// Run the same pre-broadcast gas reserve check here so callers get an early
|
|
49724
|
+
// warning at quote time — before they call deposit() and hit the real check.
|
|
49725
|
+
// Only applies on stablecoin-gas chains (e.g. Arc) where the deposit token
|
|
49726
|
+
// is also the native gas token, and only for EOA wallets that pay native gas
|
|
49727
|
+
// from their own balance. Skips silently on all other chains and wallet types.
|
|
49728
|
+
if (chainDefinition?.type === 'evm' && isEvmAdapterLike(params.from.adapter) && !await isContractSigner(params.from.adapter, address, chainDefinition)) {
|
|
49729
|
+
const symbol = quote.deposit.symbol.toUpperCase();
|
|
49730
|
+
let depositTokenAddress = null;
|
|
49731
|
+
if (symbol === 'USDC') {
|
|
49732
|
+
depositTokenAddress = chainDefinition.usdcAddress;
|
|
49733
|
+
} else if (symbol === 'EURC') {
|
|
49734
|
+
depositTokenAddress = chainDefinition.eurcAddress;
|
|
49735
|
+
}
|
|
49736
|
+
if (depositTokenAddress != null) {
|
|
49737
|
+
const amountObj = Amount.parse(params.amount, {
|
|
49738
|
+
decimals: 6
|
|
49739
|
+
});
|
|
49740
|
+
await checkGasReserveForDeposit({
|
|
49741
|
+
adapter: params.from.adapter,
|
|
49742
|
+
chain: chainDefinition,
|
|
49743
|
+
address,
|
|
49744
|
+
depositTokenAddress,
|
|
49745
|
+
depositAmountRaw: amountObj.raw,
|
|
49746
|
+
gasFees: quote.gasFees
|
|
49747
|
+
});
|
|
49748
|
+
}
|
|
49749
|
+
}
|
|
49750
|
+
return quote;
|
|
49570
49751
|
}
|
|
49571
49752
|
/** {@inheritdoc} */ async getWithdrawalQuote(params) {
|
|
49572
49753
|
const config = this.resolveConfig(params.config);
|
|
@@ -49866,21 +50047,15 @@ function formatPositionPnL(pnl) {
|
|
|
49866
50047
|
// consumers keep receiving them until Contract.
|
|
49867
50048
|
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
49868
50049
|
const { totalDeposits, liquidity, liquidityProfile, ...rest } = vault;
|
|
49869
|
-
// `liquidityProfile` is `.optional()` in the response schema during the
|
|
49870
|
-
// expand/contract window (an old backend that predates the nested facets
|
|
49871
|
-
// omits it), so only format and re-attach it when present — matching the
|
|
49872
|
-
// provider-side `toVaultInfo` mapper.
|
|
49873
50050
|
return {
|
|
49874
50051
|
...rest,
|
|
49875
50052
|
totalDeposits: formatAmount$1(totalDeposits),
|
|
49876
50053
|
liquidity: formatAmount$1(liquidity),
|
|
49877
|
-
|
|
49878
|
-
liquidityProfile
|
|
49879
|
-
|
|
49880
|
-
|
|
49881
|
-
|
|
49882
|
-
totalSupply: formatAmount$1(liquidityProfile.totalSupply)
|
|
49883
|
-
}
|
|
50054
|
+
liquidityProfile: {
|
|
50055
|
+
...liquidityProfile,
|
|
50056
|
+
totalDeposits: formatAmount$1(liquidityProfile.totalDeposits),
|
|
50057
|
+
available: formatAmount$1(liquidityProfile.available),
|
|
50058
|
+
totalSupply: formatAmount$1(liquidityProfile.totalSupply)
|
|
49884
50059
|
}
|
|
49885
50060
|
};
|
|
49886
50061
|
}
|
|
@@ -50366,6 +50541,49 @@ const sourceAdapterContextSchema = z.object({
|
|
|
50366
50541
|
vaultAddress: vaultAddressSchema,
|
|
50367
50542
|
config: earnConfigSchema.optional()
|
|
50368
50543
|
});
|
|
50544
|
+
/**
|
|
50545
|
+
* Schema for a successful gas fee entry (fees is non-null).
|
|
50546
|
+
*
|
|
50547
|
+
* Validates the kit shape — {@link EarnEstimatedGas} uses decimal strings for
|
|
50548
|
+
* `gas`, `gasPrice`, and `fee`. Only digits are accepted so that the deposit
|
|
50549
|
+
* operation can safely convert them to `bigint` before passing them to the
|
|
50550
|
+
* provider's `computeGasReserve`.
|
|
50551
|
+
*
|
|
50552
|
+
* @internal
|
|
50553
|
+
*/ const earnGasFeeEstimateSuccessSchema = z.object({
|
|
50554
|
+
name: z.string(),
|
|
50555
|
+
token: z.string(),
|
|
50556
|
+
blockchain: z.string(),
|
|
50557
|
+
fees: z.object({
|
|
50558
|
+
gas: z.string().regex(/^\d+$/, 'gas must be a non-negative integer string'),
|
|
50559
|
+
gasPrice: z.string().regex(/^\d+$/, 'gasPrice must be a non-negative integer string'),
|
|
50560
|
+
fee: z.string().regex(/^\d+$/, 'fee must be a non-negative integer string')
|
|
50561
|
+
}),
|
|
50562
|
+
error: z.undefined().optional()
|
|
50563
|
+
}).strict();
|
|
50564
|
+
/**
|
|
50565
|
+
* Schema for a failed gas fee entry (fees is null, error is a string).
|
|
50566
|
+
*
|
|
50567
|
+
* @internal
|
|
50568
|
+
*/ const earnGasFeeEstimateFailureSchema = z.object({
|
|
50569
|
+
name: z.string(),
|
|
50570
|
+
token: z.string(),
|
|
50571
|
+
blockchain: z.string(),
|
|
50572
|
+
fees: z.null(),
|
|
50573
|
+
error: z.string()
|
|
50574
|
+
}).strict();
|
|
50575
|
+
/**
|
|
50576
|
+
* Schema for a single kit-level gas fee estimate entry.
|
|
50577
|
+
*
|
|
50578
|
+
* Rejects arbitrary inputs (null, numbers, empty objects, non-numeric fee
|
|
50579
|
+
* strings) so callers receive a descriptive validation error instead of a
|
|
50580
|
+
* raw `BigInt` conversion error inside `computeGasReserve`.
|
|
50581
|
+
*
|
|
50582
|
+
* @internal
|
|
50583
|
+
*/ const earnGasFeeEstimateSchema = z.union([
|
|
50584
|
+
earnGasFeeEstimateSuccessSchema,
|
|
50585
|
+
earnGasFeeEstimateFailureSchema
|
|
50586
|
+
]);
|
|
50369
50587
|
/**
|
|
50370
50588
|
* Validation schema for the same-chain variant of DepositParams.
|
|
50371
50589
|
*
|
|
@@ -50378,6 +50596,7 @@ const sourceAdapterContextSchema = z.object({
|
|
|
50378
50596
|
to: z.undefined().optional(),
|
|
50379
50597
|
vaultAddress: vaultAddressSchema,
|
|
50380
50598
|
amount: amountSchema$1,
|
|
50599
|
+
gasFees: z.array(earnGasFeeEstimateSchema).optional(),
|
|
50381
50600
|
config: earnConfigSchema.optional()
|
|
50382
50601
|
}).strict();
|
|
50383
50602
|
const crossChainDepositDestinationSchema = z.object({
|
|
@@ -50998,6 +51217,9 @@ async function deposit$3(context, params) {
|
|
|
50998
51217
|
},
|
|
50999
51218
|
vaultAddress: params.vaultAddress,
|
|
51000
51219
|
amount: params.amount,
|
|
51220
|
+
...!hasExplicitDestination && params.gasFees !== undefined && {
|
|
51221
|
+
gasFees: toProviderGasFees(params.gasFees)
|
|
51222
|
+
},
|
|
51001
51223
|
...params.config !== undefined && {
|
|
51002
51224
|
config: params.config
|
|
51003
51225
|
}
|
|
@@ -51020,6 +51242,21 @@ async function deposit$3(context, params) {
|
|
|
51020
51242
|
}
|
|
51021
51243
|
return provider.deposit(baseParams);
|
|
51022
51244
|
}
|
|
51245
|
+
function toProviderGasFees(gasFees) {
|
|
51246
|
+
return gasFees.map((entry)=>{
|
|
51247
|
+
if (entry.fees === null) {
|
|
51248
|
+
return entry; // NOSONAR
|
|
51249
|
+
}
|
|
51250
|
+
return {
|
|
51251
|
+
...entry,
|
|
51252
|
+
fees: {
|
|
51253
|
+
...entry.fees,
|
|
51254
|
+
gas: BigInt(entry.fees.gas),
|
|
51255
|
+
gasPrice: BigInt(entry.fees.gasPrice)
|
|
51256
|
+
}
|
|
51257
|
+
};
|
|
51258
|
+
});
|
|
51259
|
+
}
|
|
51023
51260
|
function hasCrossChainDestination(params) {
|
|
51024
51261
|
// Runs before schema validation, so guard against non-object params from
|
|
51025
51262
|
// untyped callers; assertEarnParams reports those with a structured error.
|
|
@@ -52495,10 +52732,10 @@ function readUserAgent(hostWindow) {
|
|
|
52495
52732
|
* @param widgetPath - Path appended to `widgetBaseUrl`. Leading `/`
|
|
52496
52733
|
* is required by the URL semantics below — see remarks.
|
|
52497
52734
|
* @param params - Additional query parameters to set on the launch URL
|
|
52498
|
-
* (e.g. `
|
|
52499
|
-
* `undefined` or empty are skipped.
|
|
52500
|
-
*
|
|
52501
|
-
*
|
|
52735
|
+
* (e.g. the asset-scoping `chains` / `tokens` / `pairs`). Entries whose
|
|
52736
|
+
* value is `undefined` or empty are skipped. Launch URLs end up in
|
|
52737
|
+
* browser history and access logs, so never pass user identifiers
|
|
52738
|
+
* such as wallet addresses here.
|
|
52502
52739
|
* @returns A fully-qualified launch URL.
|
|
52503
52740
|
*
|
|
52504
52741
|
* @remarks
|
|
@@ -52522,9 +52759,9 @@ function readUserAgent(hostWindow) {
|
|
|
52522
52759
|
* @example
|
|
52523
52760
|
* ```ts
|
|
52524
52761
|
* composeWidgetUrl('https://onramp.arc.io', 'tok-1', '', {
|
|
52525
|
-
*
|
|
52762
|
+
* tokens: 'USDC',
|
|
52526
52763
|
* })
|
|
52527
|
-
* // → 'https://onramp.arc.io/?sessionToken=tok-1&
|
|
52764
|
+
* // → 'https://onramp.arc.io/?sessionToken=tok-1&tokens=USDC'
|
|
52528
52765
|
* ```
|
|
52529
52766
|
*
|
|
52530
52767
|
* @internal Implementation detail shared by the server kit
|
|
@@ -52533,13 +52770,6 @@ function readUserAgent(hostWindow) {
|
|
|
52533
52770
|
*/ function composeWidgetUrl(widgetBaseUrl, sessionToken, widgetPath, params) {
|
|
52534
52771
|
const url = new URL(widgetPath, widgetBaseUrl);
|
|
52535
52772
|
url.searchParams.set('sessionToken', sessionToken);
|
|
52536
|
-
if (params !== undefined) {
|
|
52537
|
-
for (const [key, value] of Object.entries(params)){
|
|
52538
|
-
if (typeof value === 'string' && value.length > 0) {
|
|
52539
|
-
url.searchParams.set(key, value);
|
|
52540
|
-
}
|
|
52541
|
-
}
|
|
52542
|
-
}
|
|
52543
52773
|
return url.toString();
|
|
52544
52774
|
}
|
|
52545
52775
|
|
|
@@ -52749,12 +52979,10 @@ function readUserAgent(hostWindow) {
|
|
|
52749
52979
|
assertSafeWidgetUrl(session.widgetUrl, expectedOrigin);
|
|
52750
52980
|
return session.widgetUrl;
|
|
52751
52981
|
}
|
|
52752
|
-
// Fallback path: compose from a bare session token. The widget reads
|
|
52753
|
-
//
|
|
52754
|
-
//
|
|
52755
|
-
return composeWidgetUrl(widgetBaseUrl, session.sessionToken, ONRAMP_WIDGET_PATH
|
|
52756
|
-
destinationWallet: typeof session.destinationWallet === 'string' ? session.destinationWallet : undefined
|
|
52757
|
-
});
|
|
52982
|
+
// Fallback path: compose from a bare session token. The widget reads the
|
|
52983
|
+
// destination wallet from the token's `walletAddress` claim, so
|
|
52984
|
+
// `session.destinationWallet` must not be added to the URL.
|
|
52985
|
+
return composeWidgetUrl(widgetBaseUrl, session.sessionToken, ONRAMP_WIDGET_PATH);
|
|
52758
52986
|
}
|
|
52759
52987
|
|
|
52760
52988
|
const ALLOWED_TRANSITIONS = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@circle-fin/app-kit",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.3",
|
|
4
4
|
"description": "A one-stop Circle SDK solution for building stablecoin (e.g. USDC) applications, with bridging, swapping, and more on-chain operations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"circle",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"module": "./index.mjs",
|
|
37
37
|
"types": "./index.d.cts",
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@circle-fin/onramp-kit": "1.0.
|
|
39
|
+
"@circle-fin/onramp-kit": "1.0.2",
|
|
40
40
|
"@circle-fin/unified-balance-kit": "1.7.0",
|
|
41
41
|
"@circle-fin/provider-gateway-v1": "1.5.0",
|
|
42
|
-
"@circle-fin/earn-kit": "1.
|
|
43
|
-
"@circle-fin/bridge-kit": "1.15.
|
|
42
|
+
"@circle-fin/earn-kit": "1.8.0",
|
|
43
|
+
"@circle-fin/bridge-kit": "1.15.1",
|
|
44
44
|
"@circle-fin/swap-kit": "1.7.0",
|
|
45
45
|
"@coral-xyz/anchor": "^0.31.1",
|
|
46
46
|
"@noble/curves": "1.4.2",
|
package/server.cjs
CHANGED
|
@@ -8650,7 +8650,7 @@ const swapTokenEnumSchema = zod.z.enum([
|
|
|
8650
8650
|
return kit;
|
|
8651
8651
|
}
|
|
8652
8652
|
|
|
8653
|
-
var version = "1.0.
|
|
8653
|
+
var version = "1.0.2";
|
|
8654
8654
|
var pkg = {
|
|
8655
8655
|
version: version};
|
|
8656
8656
|
|
|
@@ -9166,10 +9166,10 @@ function isAbortLikeError(err) {
|
|
|
9166
9166
|
* @param widgetPath - Path appended to `widgetBaseUrl`. Leading `/`
|
|
9167
9167
|
* is required by the URL semantics below — see remarks.
|
|
9168
9168
|
* @param params - Additional query parameters to set on the launch URL
|
|
9169
|
-
* (e.g. `
|
|
9170
|
-
* `undefined` or empty are skipped.
|
|
9171
|
-
*
|
|
9172
|
-
*
|
|
9169
|
+
* (e.g. the asset-scoping `chains` / `tokens` / `pairs`). Entries whose
|
|
9170
|
+
* value is `undefined` or empty are skipped. Launch URLs end up in
|
|
9171
|
+
* browser history and access logs, so never pass user identifiers
|
|
9172
|
+
* such as wallet addresses here.
|
|
9173
9173
|
* @returns A fully-qualified launch URL.
|
|
9174
9174
|
*
|
|
9175
9175
|
* @remarks
|
|
@@ -9193,9 +9193,9 @@ function isAbortLikeError(err) {
|
|
|
9193
9193
|
* @example
|
|
9194
9194
|
* ```ts
|
|
9195
9195
|
* composeWidgetUrl('https://onramp.arc.io', 'tok-1', '', {
|
|
9196
|
-
*
|
|
9196
|
+
* tokens: 'USDC',
|
|
9197
9197
|
* })
|
|
9198
|
-
* // → 'https://onramp.arc.io/?sessionToken=tok-1&
|
|
9198
|
+
* // → 'https://onramp.arc.io/?sessionToken=tok-1&tokens=USDC'
|
|
9199
9199
|
* ```
|
|
9200
9200
|
*
|
|
9201
9201
|
* @internal Implementation detail shared by the server kit
|
|
@@ -9434,17 +9434,13 @@ function isAbortLikeError(err) {
|
|
|
9434
9434
|
const session = unwrapped !== null && typeof unwrapped === 'object' ? unwrapped : {};
|
|
9435
9435
|
const sessionToken = typeof session['sessionToken'] === 'string' ? session['sessionToken'] : undefined;
|
|
9436
9436
|
const existingWidgetUrl = typeof session['widgetUrl'] === 'string' && session['widgetUrl'].length > 0 ? session['widgetUrl'] : undefined;
|
|
9437
|
-
// The
|
|
9438
|
-
// (`
|
|
9439
|
-
// the
|
|
9440
|
-
//
|
|
9441
|
-
//
|
|
9442
|
-
// (`assets`) rides the same launch URL as `chains`/`tokens`/`pairs`.
|
|
9437
|
+
// The launch URL carries only the session token and host-app asset
|
|
9438
|
+
// scoping (`chains`/`tokens`/`pairs`). The destination wallet must
|
|
9439
|
+
// stay out of it: the widget reads the wallet from the signed session
|
|
9440
|
+
// token's `walletAddress` claim, and a query param would only leak
|
|
9441
|
+
// the address into browser history and access logs.
|
|
9443
9442
|
const assetParams = serializeAssetSelection(params.assets);
|
|
9444
|
-
const composedWidgetUrl = sessionToken === undefined ? undefined : composeWidgetUrl(widgetBaseUrl, sessionToken, ONRAMP_WIDGET_PATH,
|
|
9445
|
-
destinationWallet: params.destinationAddress,
|
|
9446
|
-
...assetParams
|
|
9447
|
-
});
|
|
9443
|
+
const composedWidgetUrl = sessionToken === undefined ? undefined : composeWidgetUrl(widgetBaseUrl, sessionToken, ONRAMP_WIDGET_PATH, assetParams);
|
|
9448
9444
|
// When wallets-api returns a `widgetUrl`, asset scoping must still be
|
|
9449
9445
|
// applied — `assets` is a display-only widget concern and is never
|
|
9450
9446
|
// forwarded upstream, so we merge the params directly into the returned
|
package/server.d.cts
CHANGED
|
@@ -1785,17 +1785,17 @@ interface KitEventSubscription<M extends EventMap = KitEventMap> {
|
|
|
1785
1785
|
* embeds. Never sent back by the client; it is redeemed inside the
|
|
1786
1786
|
* widget origin only.
|
|
1787
1787
|
* - `widgetUrl` — fully composed launch URL (origin + path + token +
|
|
1788
|
-
*
|
|
1788
|
+
* asset-scoping params). The server kit prefers to compose this itself
|
|
1789
1789
|
* so the client kit has no exposure to the widget origin. The client
|
|
1790
1790
|
* still accepts a bare `sessionToken` and composes a URL locally as a
|
|
1791
1791
|
* fallback. `getOnrampUrl` is the single place that enforces the
|
|
1792
1792
|
* https-scheme / origin-pin safety checks before the URL reaches the
|
|
1793
1793
|
* DOM — that is a security boundary, not response validation.
|
|
1794
1794
|
* - `destinationWallet` — the wallet that receives funds. The widget
|
|
1795
|
-
*
|
|
1796
|
-
*
|
|
1797
|
-
* `
|
|
1798
|
-
*
|
|
1795
|
+
* reads it from the signed session token, not the launch URL, so the
|
|
1796
|
+
* kit never adds it there. The server kit still echoes the
|
|
1797
|
+
* `destinationAddress` it was minted with here for the host's
|
|
1798
|
+
* convenience.
|
|
1799
1799
|
* - `expiresAt` — RFC 3339 timestamp. The client refuses to launch an
|
|
1800
1800
|
* expired session and throws an `INPUT` `KitError` so the host can
|
|
1801
1801
|
* re-mint.
|
|
@@ -1819,8 +1819,8 @@ interface OnrampSession {
|
|
|
1819
1819
|
*/
|
|
1820
1820
|
readonly sessionToken: string;
|
|
1821
1821
|
/**
|
|
1822
|
-
* Fully composed launch URL (origin + path + token +
|
|
1823
|
-
*
|
|
1822
|
+
* Fully composed launch URL (origin + path + token + optional
|
|
1823
|
+
* asset-scoping params).
|
|
1824
1824
|
*
|
|
1825
1825
|
* @remarks
|
|
1826
1826
|
* The server kit prefers to compose this itself; the client falls
|
|
@@ -1833,8 +1833,9 @@ interface OnrampSession {
|
|
|
1833
1833
|
*
|
|
1834
1834
|
* @remarks
|
|
1835
1835
|
* Echoed verbatim from the `destinationAddress` the server kit
|
|
1836
|
-
* minted with
|
|
1837
|
-
*
|
|
1836
|
+
* minted with, for the host's convenience (e.g. to display it). Never
|
|
1837
|
+
* added to the launch URL: the widget reads the destination wallet
|
|
1838
|
+
* from the signed session token.
|
|
1838
1839
|
*/
|
|
1839
1840
|
readonly destinationWallet?: string;
|
|
1840
1841
|
/**
|