@augustdigital/sdk 9.5.0 → 9.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/lib/adapters/evm/index.d.ts +1 -1
- package/lib/adapters/evm/index.js +29 -29
- package/lib/core/analytics/app-name.js +1 -1
- package/lib/core/analytics/constants.d.ts +10 -0
- package/lib/core/analytics/constants.js +17 -1
- package/lib/core/analytics/index.d.ts +7 -4
- package/lib/core/analytics/index.js +8 -4
- package/lib/core/analytics/instrumentation.js +8 -4
- package/lib/core/analytics/method-taxonomy.js +13 -0
- package/lib/core/analytics/metrics.d.ts +25 -10
- package/lib/core/analytics/metrics.js +41 -15
- package/lib/core/analytics/sentry.d.ts +24 -3
- package/lib/core/analytics/sentry.js +49 -18
- package/lib/core/analytics/types.d.ts +11 -4
- package/lib/core/analytics/user-identity.d.ts +19 -5
- package/lib/core/analytics/user-identity.js +35 -21
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/auth/verify.js +5 -1
- package/lib/core/base.class.js +3 -0
- package/lib/core/constants/core.d.ts +3 -0
- package/lib/core/constants/core.js +3 -0
- package/lib/core/constants/swap-router.d.ts +16 -0
- package/lib/core/constants/swap-router.js +16 -0
- package/lib/core/errors/index.d.ts +36 -1
- package/lib/core/errors/index.js +40 -1
- package/lib/core/fetcher.d.ts +13 -0
- package/lib/core/fetcher.js +33 -0
- package/lib/main.d.ts +5 -0
- package/lib/main.js +5 -0
- package/lib/modules/vaults/getters.d.ts +55 -0
- package/lib/modules/vaults/getters.js +58 -14
- package/lib/modules/vaults/main.d.ts +4 -0
- package/lib/modules/vaults/main.js +4 -0
- package/lib/modules/vaults/write.actions.d.ts +57 -1
- package/lib/modules/vaults/write.actions.js +86 -2
- package/lib/sdk.d.ts +13032 -12801
- package/package.json +2 -2
package/lib/main.js
CHANGED
|
@@ -430,6 +430,11 @@ class AugustSDK extends core_1.AugustBase {
|
|
|
430
430
|
* Calculates realized and unrealized PnL based on deposit/withdrawal history and current position.
|
|
431
431
|
* @param props - Vault address, wallet address, and optional chain ID
|
|
432
432
|
* @returns Lifetime PnL data including realized and unrealized PnL in both native token and USD
|
|
433
|
+
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
434
|
+
* live position has no indexed deposits or withdrawals.
|
|
435
|
+
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
436
|
+
* vault's underlying asset has no USD price — the USD fields are never
|
|
437
|
+
* computed from a stand-in price.
|
|
433
438
|
*/
|
|
434
439
|
async getVaultUserLifetimePnl(props) {
|
|
435
440
|
return await this.vaults.getVaultUserLifetimePnl(props);
|
|
@@ -366,6 +366,53 @@ export interface PnlHistoryConsistencyParams {
|
|
|
366
366
|
* ```
|
|
367
367
|
*/
|
|
368
368
|
export declare function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, totalWithdrawnRaw, currentPositionRaw, }: PnlHistoryConsistencyParams): void;
|
|
369
|
+
/** Inputs the lifetime-PnL price guard inspects. */
|
|
370
|
+
export interface PnlTokenPriceParams {
|
|
371
|
+
/** Vault contract address, used for the error message and context. */
|
|
372
|
+
vault: IAddress;
|
|
373
|
+
/** User wallet address, used for the error message and context. */
|
|
374
|
+
wallet: IAddress;
|
|
375
|
+
/**
|
|
376
|
+
* The vault's underlying asset (`asset()`) that was priced, or `undefined`
|
|
377
|
+
* when `asset()` could not be read and no price lookup was possible.
|
|
378
|
+
*/
|
|
379
|
+
asset: IAddress | undefined;
|
|
380
|
+
/**
|
|
381
|
+
* USD price of `asset` as resolved by the price server. `0` means the lookup
|
|
382
|
+
* failed or the token is unknown to it (`fetchTokenPriceByAddress` never
|
|
383
|
+
* throws).
|
|
384
|
+
*/
|
|
385
|
+
tokenPriceUsd: number;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Guard against converting lifetime PnL to USD with a fabricated price.
|
|
389
|
+
*
|
|
390
|
+
* Every USD field `getVaultUserLifetimePnl` returns is a native amount times
|
|
391
|
+
* the underlying asset's USD price. When the price server has no price, the
|
|
392
|
+
* only honest outcome is "no USD value" — substituting a stand-in (the getter
|
|
393
|
+
* previously used `1`) reports a non-dollar vault's position at $1 per asset,
|
|
394
|
+
* a plausible-looking but wrong number that callers cannot detect.
|
|
395
|
+
*
|
|
396
|
+
* Pure and synchronous — no RPC, no I/O.
|
|
397
|
+
*
|
|
398
|
+
* @param params - See {@link PnlTokenPriceParams}.
|
|
399
|
+
* @returns `tokenPriceUsd`, unchanged, when it is a finite number above zero.
|
|
400
|
+
* @throws {@link AugustPriceUnavailableError} with code `PRICE_UNAVAILABLE`
|
|
401
|
+
* and `context: { vault, wallet, asset }` when the price is zero, negative,
|
|
402
|
+
* or not finite. The message carries the
|
|
403
|
+
* `#getVaultUserLifetimePnl::<vault>::<wallet>` prefix so it groups with the
|
|
404
|
+
* other errors leaving the getter.
|
|
405
|
+
* @example
|
|
406
|
+
* ```ts
|
|
407
|
+
* const price = assertPnlTokenPrice({
|
|
408
|
+
* vault,
|
|
409
|
+
* wallet,
|
|
410
|
+
* asset: underlyingAssetAddress,
|
|
411
|
+
* tokenPriceUsd: await pricePromise,
|
|
412
|
+
* });
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
export declare function assertPnlTokenPrice({ vault, wallet, asset, tokenPriceUsd, }: PnlTokenPriceParams): number;
|
|
369
416
|
/**
|
|
370
417
|
* Sum a wallet's per-asset deposits into the vault's own decimals, at face
|
|
371
418
|
* value — 1 unit of any deposited asset is treated as 1 unit of the vault's
|
|
@@ -408,10 +455,18 @@ export declare function sumDepositsAtFaceValue(depositsByAsset: Map<string, bigi
|
|
|
408
455
|
* non-pegged deposit asset would need deposit-time price conversion, which
|
|
409
456
|
* this function does not perform.
|
|
410
457
|
*
|
|
458
|
+
* Every USD field is the native amount times the underlying asset's USD price
|
|
459
|
+
* from the price server. There is no stand-in price: when none resolves the
|
|
460
|
+
* getter throws rather than returning USD values it cannot know.
|
|
461
|
+
*
|
|
411
462
|
* @param vault - Vault contract address
|
|
412
463
|
* @param wallet - User wallet address
|
|
413
464
|
* @param options - RPC configuration and service options
|
|
414
465
|
* @returns Lifetime PnL data in both native token and USD
|
|
466
|
+
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
467
|
+
* live position has no indexed deposits or withdrawals.
|
|
468
|
+
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
469
|
+
* underlying asset has no USD price, or `asset()` cannot be read.
|
|
415
470
|
*/
|
|
416
471
|
export declare function getVaultUserLifetimePnl({ vault, wallet, options, }: {
|
|
417
472
|
vault: IAddress;
|
|
@@ -54,6 +54,7 @@ exports.registerUserForPoints = registerUserForPoints;
|
|
|
54
54
|
exports.fetchPointsLeaderboard = fetchPointsLeaderboard;
|
|
55
55
|
exports.getYieldLastRealizedOn = getYieldLastRealizedOn;
|
|
56
56
|
exports.assertPnlHistoryConsistent = assertPnlHistoryConsistent;
|
|
57
|
+
exports.assertPnlTokenPrice = assertPnlTokenPrice;
|
|
57
58
|
exports.sumDepositsAtFaceValue = sumDepositsAtFaceValue;
|
|
58
59
|
exports.getVaultUserLifetimePnl = getVaultUserLifetimePnl;
|
|
59
60
|
exports.getVaultPnl = getVaultPnl;
|
|
@@ -2295,6 +2296,39 @@ function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, totalWithdrawn
|
|
|
2295
2296
|
throw new errors_1.AugustHistoryUnavailableError(`#getVaultUserLifetimePnl::${vault}::${wallet}:transaction history unavailable — a live position exists but no deposits or withdrawals were indexed, so lifetime PnL cannot be computed without over-reporting the entire position as profit`, { context: { vault, wallet } });
|
|
2296
2297
|
}
|
|
2297
2298
|
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Guard against converting lifetime PnL to USD with a fabricated price.
|
|
2301
|
+
*
|
|
2302
|
+
* Every USD field `getVaultUserLifetimePnl` returns is a native amount times
|
|
2303
|
+
* the underlying asset's USD price. When the price server has no price, the
|
|
2304
|
+
* only honest outcome is "no USD value" — substituting a stand-in (the getter
|
|
2305
|
+
* previously used `1`) reports a non-dollar vault's position at $1 per asset,
|
|
2306
|
+
* a plausible-looking but wrong number that callers cannot detect.
|
|
2307
|
+
*
|
|
2308
|
+
* Pure and synchronous — no RPC, no I/O.
|
|
2309
|
+
*
|
|
2310
|
+
* @param params - See {@link PnlTokenPriceParams}.
|
|
2311
|
+
* @returns `tokenPriceUsd`, unchanged, when it is a finite number above zero.
|
|
2312
|
+
* @throws {@link AugustPriceUnavailableError} with code `PRICE_UNAVAILABLE`
|
|
2313
|
+
* and `context: { vault, wallet, asset }` when the price is zero, negative,
|
|
2314
|
+
* or not finite. The message carries the
|
|
2315
|
+
* `#getVaultUserLifetimePnl::<vault>::<wallet>` prefix so it groups with the
|
|
2316
|
+
* other errors leaving the getter.
|
|
2317
|
+
* @example
|
|
2318
|
+
* ```ts
|
|
2319
|
+
* const price = assertPnlTokenPrice({
|
|
2320
|
+
* vault,
|
|
2321
|
+
* wallet,
|
|
2322
|
+
* asset: underlyingAssetAddress,
|
|
2323
|
+
* tokenPriceUsd: await pricePromise,
|
|
2324
|
+
* });
|
|
2325
|
+
* ```
|
|
2326
|
+
*/
|
|
2327
|
+
function assertPnlTokenPrice({ vault, wallet, asset, tokenPriceUsd, }) {
|
|
2328
|
+
if (Number.isFinite(tokenPriceUsd) && tokenPriceUsd > 0)
|
|
2329
|
+
return tokenPriceUsd;
|
|
2330
|
+
throw new errors_1.AugustPriceUnavailableError(`#getVaultUserLifetimePnl::${vault}::${wallet}:underlying token price unavailable for ${asset ?? 'an unreadable asset()'} — USD values cannot be computed without fabricating a price`, { context: { vault, wallet, asset: asset ?? null } });
|
|
2331
|
+
}
|
|
2298
2332
|
/**
|
|
2299
2333
|
* Sum a wallet's per-asset deposits into the vault's own decimals, at face
|
|
2300
2334
|
* value — 1 unit of any deposited asset is treated as 1 unit of the vault's
|
|
@@ -2352,10 +2386,18 @@ function sumDepositsAtFaceValue(depositsByAsset, assetDecimals, vaultDecimals) {
|
|
|
2352
2386
|
* non-pegged deposit asset would need deposit-time price conversion, which
|
|
2353
2387
|
* this function does not perform.
|
|
2354
2388
|
*
|
|
2389
|
+
* Every USD field is the native amount times the underlying asset's USD price
|
|
2390
|
+
* from the price server. There is no stand-in price: when none resolves the
|
|
2391
|
+
* getter throws rather than returning USD values it cannot know.
|
|
2392
|
+
*
|
|
2355
2393
|
* @param vault - Vault contract address
|
|
2356
2394
|
* @param wallet - User wallet address
|
|
2357
2395
|
* @param options - RPC configuration and service options
|
|
2358
2396
|
* @returns Lifetime PnL data in both native token and USD
|
|
2397
|
+
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
2398
|
+
* live position has no indexed deposits or withdrawals.
|
|
2399
|
+
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
2400
|
+
* underlying asset has no USD price, or `asset()` cannot be read.
|
|
2359
2401
|
*/
|
|
2360
2402
|
async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
|
|
2361
2403
|
try {
|
|
@@ -2663,25 +2705,25 @@ async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
|
|
|
2663
2705
|
totalWithdrawnRaw,
|
|
2664
2706
|
currentPositionRaw: BigInt(currentPositionValue.raw),
|
|
2665
2707
|
});
|
|
2666
|
-
const tokenPriceUsd =
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
}
|
|
2708
|
+
const tokenPriceUsd = assertPnlTokenPrice({
|
|
2709
|
+
vault,
|
|
2710
|
+
wallet,
|
|
2711
|
+
asset: underlyingAssetAddress,
|
|
2712
|
+
tokenPriceUsd: await pricePromise,
|
|
2713
|
+
});
|
|
2672
2714
|
// totalDeposited is already in the vault's own decimals (face value,
|
|
2673
2715
|
// computed above) — convert to USD with the same underlying price used
|
|
2674
2716
|
// for the other two legs below, so all three legs share one conversion
|
|
2675
2717
|
// factor instead of drifting independently against each other.
|
|
2676
2718
|
const totalDeposited = (0, core_1.toNormalizedBn)(totalDepositedNativeRaw, decimals);
|
|
2677
|
-
const totalDepositedUsd = Number(totalDeposited.normalized) *
|
|
2678
|
-
const totalWithdrawnUsd = Number(totalWithdrawn.normalized) *
|
|
2679
|
-
const currentPositionValueUsd = Number(currentPositionValue.normalized) *
|
|
2719
|
+
const totalDepositedUsd = Number(totalDeposited.normalized) * tokenPriceUsd;
|
|
2720
|
+
const totalWithdrawnUsd = Number(totalWithdrawn.normalized) * tokenPriceUsd;
|
|
2721
|
+
const currentPositionValueUsd = Number(currentPositionValue.normalized) * tokenPriceUsd;
|
|
2680
2722
|
// Calculate lifetimePnl in USD first (since deposits may be in different tokens with different prices)
|
|
2681
2723
|
const lifetimePnlUsd = currentPositionValueUsd + totalWithdrawnUsd - totalDepositedUsd;
|
|
2682
2724
|
// Use BigInt-scaled arithmetic to minimize precision loss when converting USD to native
|
|
2683
2725
|
const scaleFactor = BigInt(10 ** 18); // High precision scale
|
|
2684
|
-
const tokenPriceScaled = BigInt(Math.round(
|
|
2726
|
+
const tokenPriceScaled = BigInt(Math.round(tokenPriceUsd * Number(scaleFactor)));
|
|
2685
2727
|
// Convert lifetimePnlUsd to native units
|
|
2686
2728
|
const lifetimePnlUsdScaled = BigInt(Math.round(lifetimePnlUsd * Number(scaleFactor)));
|
|
2687
2729
|
const lifetimePnlRaw = tokenPriceScaled > BigInt(0)
|
|
@@ -2706,10 +2748,12 @@ async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
|
|
|
2706
2748
|
}
|
|
2707
2749
|
catch (e) {
|
|
2708
2750
|
core_1.Logger.log.error('getVaultUserLifetimePnl', e, { vault, wallet });
|
|
2709
|
-
// Preserve the typed history
|
|
2710
|
-
// unavailable-history failure from a generic getter
|
|
2711
|
-
// already
|
|
2712
|
-
|
|
2751
|
+
// Preserve the typed history and price guards so callers can distinguish
|
|
2752
|
+
// an unavailable-history or unavailable-price failure from a generic getter
|
|
2753
|
+
// error. Their messages already carry the
|
|
2754
|
+
// `#getVaultUserLifetimePnl::vault::wallet` prefix.
|
|
2755
|
+
if (e instanceof errors_1.AugustHistoryUnavailableError ||
|
|
2756
|
+
e instanceof errors_1.AugustPriceUnavailableError)
|
|
2713
2757
|
throw e;
|
|
2714
2758
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
2715
2759
|
throw new Error(`#getVaultUserLifetimePnl::${vault}::${wallet}:${errorMessage}`);
|
|
@@ -244,6 +244,10 @@ export declare class AugustVaults extends AugustBase {
|
|
|
244
244
|
* Get lifetime PnL for a user in a specific vault.
|
|
245
245
|
* @param props Vault address, wallet address, and optional chain ID
|
|
246
246
|
* @returns Lifetime PnL data including realized and unrealized PnL
|
|
247
|
+
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
248
|
+
* live position has no indexed deposits or withdrawals.
|
|
249
|
+
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
250
|
+
* vault's underlying asset has no USD price.
|
|
247
251
|
*/
|
|
248
252
|
getVaultUserLifetimePnl({ vault, wallet, chainId, }: {
|
|
249
253
|
vault: IAddress;
|
|
@@ -933,6 +933,10 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
933
933
|
* Get lifetime PnL for a user in a specific vault.
|
|
934
934
|
* @param props Vault address, wallet address, and optional chain ID
|
|
935
935
|
* @returns Lifetime PnL data including realized and unrealized PnL
|
|
936
|
+
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
937
|
+
* live position has no indexed deposits or withdrawals.
|
|
938
|
+
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
939
|
+
* vault's underlying asset has no USD price.
|
|
936
940
|
*/
|
|
937
941
|
async getVaultUserLifetimePnl({ vault, wallet, chainId, }) {
|
|
938
942
|
if (!(0, ethers_1.isAddress)(wallet))
|
|
@@ -535,6 +535,14 @@ export declare function depositViaSwapRouter(signer: Signer | Wallet, options: I
|
|
|
535
535
|
* before depositing — only valid when the vault's reference asset equals
|
|
536
536
|
* the wrapped-native token.
|
|
537
537
|
*
|
|
538
|
+
* **Wrap-only limitation**: the on-chain SwapRouter has no ETH→other-asset
|
|
539
|
+
* swap leg, so this only ever reaches a WETH-accepting vault (see
|
|
540
|
+
* {@link SWAP_ROUTER_WRAPPED_NATIVE}). There is no atomic native-ETH deposit
|
|
541
|
+
* into a non-WETH-reference vault (e.g. a USDC vault) — deposit the wrapped
|
|
542
|
+
* native token instead (already whitelisted, routes through the swap leg for
|
|
543
|
+
* a non-reference-asset vault). Use {@link isNativeSwapRouterDepositSupported}
|
|
544
|
+
* to check eligibility before offering this path in a UI.
|
|
545
|
+
*
|
|
538
546
|
* No ERC-20 approval is needed; `amount` travels as `msg.value`.
|
|
539
547
|
*
|
|
540
548
|
* @param signer - ethers `Signer` or `Wallet`.
|
|
@@ -545,6 +553,51 @@ export declare function depositViaSwapRouter(signer: Signer | Wallet, options: I
|
|
|
545
553
|
* addresses, or zero amount.
|
|
546
554
|
*/
|
|
547
555
|
export declare function depositNativeViaSwapRouter(signer: Signer | Wallet, options: ISwapRouterNativeDepositOptions): Promise<string>;
|
|
556
|
+
/**
|
|
557
|
+
* Whether a vault can take a native-ETH (chain-native token) SwapRouter
|
|
558
|
+
* deposit — the pre-flight check for {@link depositNativeViaSwapRouter} and
|
|
559
|
+
* {@link swapRouterDeposit} with a zero-address `depositAsset`.
|
|
560
|
+
*
|
|
561
|
+
* The on-chain SwapRouter only wraps native ETH to the chain's wrapped-native
|
|
562
|
+
* token and deposits that — it has no ETH→other-asset swap leg (see
|
|
563
|
+
* {@link SWAP_ROUTER_WRAPPED_NATIVE}). So a native deposit needs all three: a
|
|
564
|
+
* SwapRouter deployed on `chainId`, the vault registered on that router with
|
|
565
|
+
* the wrapped-native token as its `vaultInfo(vault).referenceAsset` (a
|
|
566
|
+
* deposit into an unregistered vault reverts with `InvalidVault`), and the
|
|
567
|
+
* vault's own on-chain `asset()` equal to that same token. Use this to gate a
|
|
568
|
+
* "deposit ETH" UI option before the user picks it, instead of discovering
|
|
569
|
+
* the answer via a thrown {@link AugustValidationError} or an on-chain revert.
|
|
570
|
+
*
|
|
571
|
+
* It checks configuration only — a deposit that passes this check can still
|
|
572
|
+
* fail on balance, gas, a paused vault, or a deposit cap.
|
|
573
|
+
*
|
|
574
|
+
* Read-only and provider-agnostic (no signer required) — safe to call before
|
|
575
|
+
* a wallet is connected. Makes no backend call.
|
|
576
|
+
*
|
|
577
|
+
* @param chainId - EVM chain ID the vault is deployed on.
|
|
578
|
+
* @param vault - August vault address to check.
|
|
579
|
+
* @param options - `rpcUrl` for `chainId`, passed to `createProvider`.
|
|
580
|
+
* @returns `true` iff a SwapRouter exists on `chainId`, the vault is
|
|
581
|
+
* registered on it with the wrapped-native reference asset, and the vault's
|
|
582
|
+
* `asset()` is that token. `false` — never throws — for a chain with no
|
|
583
|
+
* SwapRouter deployment, a missing/invalid `rpcUrl`, an unreadable vault or
|
|
584
|
+
* router, an unregistered vault, or a vault whose reference asset isn't the
|
|
585
|
+
* wrapped-native token.
|
|
586
|
+
* @worstCaseRpcCalls 2 — the vault's `asset()` and the router's
|
|
587
|
+
* `vaultInfo(vault)`, read in parallel. None on a chain with no SwapRouter.
|
|
588
|
+
* @example
|
|
589
|
+
* ```ts
|
|
590
|
+
* const canDepositEth = await isNativeSwapRouterDepositSupported(
|
|
591
|
+
* 1,
|
|
592
|
+
* '0x1234000000000000000000000000000000005678',
|
|
593
|
+
* { rpcUrl: 'https://eth-mainnet.example/v2/KEY' },
|
|
594
|
+
* );
|
|
595
|
+
* // true only if that vault is a router-registered WETH vault on mainnet
|
|
596
|
+
* ```
|
|
597
|
+
*/
|
|
598
|
+
export declare function isNativeSwapRouterDepositSupported(chainId: number, vault: IAddress, options: {
|
|
599
|
+
rpcUrl: string;
|
|
600
|
+
}): Promise<boolean>;
|
|
548
601
|
/**
|
|
549
602
|
* Deposit into an August vault through the on-chain `SwapRouter`, selecting the
|
|
550
603
|
* correct router path from the deposit asset. This is the high-level, explicit
|
|
@@ -564,7 +617,10 @@ export declare function depositNativeViaSwapRouter(signer: Signer | Wallet, opti
|
|
|
564
617
|
* - equals the reference asset → direct router deposit, no swap
|
|
565
618
|
* ({@link depositViaSwapRouter});
|
|
566
619
|
* - the zero address → native-token deposit ({@link depositNativeViaSwapRouter}),
|
|
567
|
-
* valid only when the reference asset is the chain's wrapped-native token
|
|
620
|
+
* valid only when the reference asset is the chain's wrapped-native token —
|
|
621
|
+
* the router only wraps ETH, it never swaps it, so this throws for any
|
|
622
|
+
* other reference asset (see {@link SWAP_ROUTER_WRAPPED_NATIVE} for why, and
|
|
623
|
+
* {@link isNativeSwapRouterDepositSupported} to check first);
|
|
568
624
|
* - any other ERC-20 → a swap to the reference asset (Paraswap quote pinned to
|
|
569
625
|
* the chain's whitelisted aggregator, fail-closed on router/selector drift)
|
|
570
626
|
* bundled into {@link swapAndDeposit}.
|
|
@@ -19,6 +19,7 @@ exports.rwaRedeemAsset = rwaRedeemAsset;
|
|
|
19
19
|
exports.swapAndDeposit = swapAndDeposit;
|
|
20
20
|
exports.depositViaSwapRouter = depositViaSwapRouter;
|
|
21
21
|
exports.depositNativeViaSwapRouter = depositNativeViaSwapRouter;
|
|
22
|
+
exports.isNativeSwapRouterDepositSupported = isNativeSwapRouterDepositSupported;
|
|
22
23
|
exports.swapRouterDeposit = swapRouterDeposit;
|
|
23
24
|
const ethers_1 = require("ethers");
|
|
24
25
|
const abis_1 = require("../../abis");
|
|
@@ -1407,7 +1408,7 @@ async function dispatchViaSwapRouter(args) {
|
|
|
1407
1408
|
const wrappedNative = core_1.SWAP_ROUTER_WRAPPED_NATIVE[args.chainId];
|
|
1408
1409
|
if (!wrappedNative ||
|
|
1409
1410
|
args.underlyingAsset.toLowerCase() !== wrappedNative.toLowerCase()) {
|
|
1410
|
-
throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit (SwapRouter): native deposit is only supported when the vault's reference asset is the chain's wrapped-native token. Vault ${args.target} underlying ${args.underlyingAsset} is not. Wrap to ${wrappedNative ?? 'WETH'} first and call again with depositAsset = the wrapped token.`, {
|
|
1411
|
+
throw new core_1.AugustValidationError('INVALID_INPUT', `vaultDeposit (SwapRouter): native deposit is only supported when the vault's reference asset is the chain's wrapped-native token. Vault ${args.target} underlying ${args.underlyingAsset} is not. Wrap to ${wrappedNative ?? 'WETH'} first and call again with depositAsset = the wrapped token. Check isNativeSwapRouterDepositSupported(chainId, vault, options) before offering this path to avoid hitting this error.`, {
|
|
1411
1412
|
context: {
|
|
1412
1413
|
vault: args.target,
|
|
1413
1414
|
underlying: args.underlyingAsset,
|
|
@@ -1694,6 +1695,14 @@ async function depositViaSwapRouter(signer, options) {
|
|
|
1694
1695
|
* before depositing — only valid when the vault's reference asset equals
|
|
1695
1696
|
* the wrapped-native token.
|
|
1696
1697
|
*
|
|
1698
|
+
* **Wrap-only limitation**: the on-chain SwapRouter has no ETH→other-asset
|
|
1699
|
+
* swap leg, so this only ever reaches a WETH-accepting vault (see
|
|
1700
|
+
* {@link SWAP_ROUTER_WRAPPED_NATIVE}). There is no atomic native-ETH deposit
|
|
1701
|
+
* into a non-WETH-reference vault (e.g. a USDC vault) — deposit the wrapped
|
|
1702
|
+
* native token instead (already whitelisted, routes through the swap leg for
|
|
1703
|
+
* a non-reference-asset vault). Use {@link isNativeSwapRouterDepositSupported}
|
|
1704
|
+
* to check eligibility before offering this path in a UI.
|
|
1705
|
+
*
|
|
1697
1706
|
* No ERC-20 approval is needed; `amount` travels as `msg.value`.
|
|
1698
1707
|
*
|
|
1699
1708
|
* @param signer - ethers `Signer` or `Wallet`.
|
|
@@ -1727,6 +1736,78 @@ async function depositNativeViaSwapRouter(signer, options) {
|
|
|
1727
1736
|
core_1.Logger.log.info('depositNativeViaSwapRouter:tx_hash', hash);
|
|
1728
1737
|
return hash;
|
|
1729
1738
|
}
|
|
1739
|
+
/**
|
|
1740
|
+
* Whether a vault can take a native-ETH (chain-native token) SwapRouter
|
|
1741
|
+
* deposit — the pre-flight check for {@link depositNativeViaSwapRouter} and
|
|
1742
|
+
* {@link swapRouterDeposit} with a zero-address `depositAsset`.
|
|
1743
|
+
*
|
|
1744
|
+
* The on-chain SwapRouter only wraps native ETH to the chain's wrapped-native
|
|
1745
|
+
* token and deposits that — it has no ETH→other-asset swap leg (see
|
|
1746
|
+
* {@link SWAP_ROUTER_WRAPPED_NATIVE}). So a native deposit needs all three: a
|
|
1747
|
+
* SwapRouter deployed on `chainId`, the vault registered on that router with
|
|
1748
|
+
* the wrapped-native token as its `vaultInfo(vault).referenceAsset` (a
|
|
1749
|
+
* deposit into an unregistered vault reverts with `InvalidVault`), and the
|
|
1750
|
+
* vault's own on-chain `asset()` equal to that same token. Use this to gate a
|
|
1751
|
+
* "deposit ETH" UI option before the user picks it, instead of discovering
|
|
1752
|
+
* the answer via a thrown {@link AugustValidationError} or an on-chain revert.
|
|
1753
|
+
*
|
|
1754
|
+
* It checks configuration only — a deposit that passes this check can still
|
|
1755
|
+
* fail on balance, gas, a paused vault, or a deposit cap.
|
|
1756
|
+
*
|
|
1757
|
+
* Read-only and provider-agnostic (no signer required) — safe to call before
|
|
1758
|
+
* a wallet is connected. Makes no backend call.
|
|
1759
|
+
*
|
|
1760
|
+
* @param chainId - EVM chain ID the vault is deployed on.
|
|
1761
|
+
* @param vault - August vault address to check.
|
|
1762
|
+
* @param options - `rpcUrl` for `chainId`, passed to `createProvider`.
|
|
1763
|
+
* @returns `true` iff a SwapRouter exists on `chainId`, the vault is
|
|
1764
|
+
* registered on it with the wrapped-native reference asset, and the vault's
|
|
1765
|
+
* `asset()` is that token. `false` — never throws — for a chain with no
|
|
1766
|
+
* SwapRouter deployment, a missing/invalid `rpcUrl`, an unreadable vault or
|
|
1767
|
+
* router, an unregistered vault, or a vault whose reference asset isn't the
|
|
1768
|
+
* wrapped-native token.
|
|
1769
|
+
* @worstCaseRpcCalls 2 — the vault's `asset()` and the router's
|
|
1770
|
+
* `vaultInfo(vault)`, read in parallel. None on a chain with no SwapRouter.
|
|
1771
|
+
* @example
|
|
1772
|
+
* ```ts
|
|
1773
|
+
* const canDepositEth = await isNativeSwapRouterDepositSupported(
|
|
1774
|
+
* 1,
|
|
1775
|
+
* '0x1234000000000000000000000000000000005678',
|
|
1776
|
+
* { rpcUrl: 'https://eth-mainnet.example/v2/KEY' },
|
|
1777
|
+
* );
|
|
1778
|
+
* // true only if that vault is a router-registered WETH vault on mainnet
|
|
1779
|
+
* ```
|
|
1780
|
+
*/
|
|
1781
|
+
async function isNativeSwapRouterDepositSupported(chainId, vault, options) {
|
|
1782
|
+
const wrappedNative = core_1.SWAP_ROUTER_WRAPPED_NATIVE[chainId];
|
|
1783
|
+
const routerAddress = (0, core_1.getSwapRouterAddress)(chainId);
|
|
1784
|
+
if (!wrappedNative || !routerAddress)
|
|
1785
|
+
return false;
|
|
1786
|
+
try {
|
|
1787
|
+
const provider = (0, core_1.createProvider)(options.rpcUrl, chainId);
|
|
1788
|
+
const vaultContract = (0, core_1.createContract)({
|
|
1789
|
+
address: vault,
|
|
1790
|
+
provider,
|
|
1791
|
+
abi: abis_1.ABI_TOKENIZED_VAULT_V2,
|
|
1792
|
+
});
|
|
1793
|
+
const routerContract = (0, core_1.createContract)({
|
|
1794
|
+
address: routerAddress,
|
|
1795
|
+
provider,
|
|
1796
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
1797
|
+
});
|
|
1798
|
+
const [asset, info] = await Promise.all([
|
|
1799
|
+
vaultContract.asset(),
|
|
1800
|
+
routerContract.vaultInfo(vault),
|
|
1801
|
+
]);
|
|
1802
|
+
const wrapped = wrappedNative.toLowerCase();
|
|
1803
|
+
return (asset.toLowerCase() === wrapped &&
|
|
1804
|
+
info?.referenceAsset?.toLowerCase() === wrapped);
|
|
1805
|
+
}
|
|
1806
|
+
catch (error) {
|
|
1807
|
+
core_1.Logger.log.warn('isNativeSwapRouterDepositSupported', 'vault or router read failed — treating as unsupported', { vault, chainId, error });
|
|
1808
|
+
return false;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1730
1811
|
/**
|
|
1731
1812
|
* Deposit into an August vault through the on-chain `SwapRouter`, selecting the
|
|
1732
1813
|
* correct router path from the deposit asset. This is the high-level, explicit
|
|
@@ -1746,7 +1827,10 @@ async function depositNativeViaSwapRouter(signer, options) {
|
|
|
1746
1827
|
* - equals the reference asset → direct router deposit, no swap
|
|
1747
1828
|
* ({@link depositViaSwapRouter});
|
|
1748
1829
|
* - the zero address → native-token deposit ({@link depositNativeViaSwapRouter}),
|
|
1749
|
-
* valid only when the reference asset is the chain's wrapped-native token
|
|
1830
|
+
* valid only when the reference asset is the chain's wrapped-native token —
|
|
1831
|
+
* the router only wraps ETH, it never swaps it, so this throws for any
|
|
1832
|
+
* other reference asset (see {@link SWAP_ROUTER_WRAPPED_NATIVE} for why, and
|
|
1833
|
+
* {@link isNativeSwapRouterDepositSupported} to check first);
|
|
1750
1834
|
* - any other ERC-20 → a swap to the reference asset (Paraswap quote pinned to
|
|
1751
1835
|
* the chain's whitelisted aggregator, fail-closed on router/selector drift)
|
|
1752
1836
|
* bundled into {@link swapAndDeposit}.
|