@augustdigital/sdk 9.8.0 → 9.9.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/README.md +57 -0
- package/lib/adapters/evm/index.d.ts +23 -5
- package/lib/adapters/evm/index.js +25 -4
- package/lib/core/analytics/method-taxonomy.js +2 -0
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/attribution.d.ts +37 -5
- package/lib/core/attribution.js +39 -3
- package/lib/core/base.class.d.ts +6 -0
- package/lib/core/constants/swap-router.d.ts +21 -4
- package/lib/core/constants/swap-router.js +22 -5
- package/lib/core/helpers/swap-router.d.ts +66 -5
- package/lib/core/helpers/swap-router.js +158 -7
- package/lib/main.d.ts +21 -3
- package/lib/main.js +20 -3
- package/lib/modules/vaults/getters.d.ts +287 -14
- package/lib/modules/vaults/getters.js +452 -45
- package/lib/modules/vaults/main.d.ts +18 -1
- package/lib/modules/vaults/main.js +23 -0
- package/lib/modules/vaults/write.actions.d.ts +119 -29
- package/lib/modules/vaults/write.actions.js +384 -77
- package/lib/sdk.d.ts +11674 -11107
- package/lib/services/layerzero/deposits.d.ts +6 -0
- package/lib/services/layerzero/deposits.js +8 -0
- package/lib/services/subgraph/schema.d.ts +5 -2
- package/lib/services/subgraph/schema.js +22 -10
- package/lib/services/subgraph/vaults.d.ts +23 -1
- package/lib/services/subgraph/vaults.js +65 -0
- package/lib/types/subgraph.d.ts +10 -0
- package/lib/types/vaults.d.ts +38 -6
- package/package.json +1 -1
|
@@ -6,10 +6,15 @@ exports.getSwapRouterName = getSwapRouterName;
|
|
|
6
6
|
exports.isSwapRouterEligible = isSwapRouterEligible;
|
|
7
7
|
exports.resolveOriginCode = resolveOriginCode;
|
|
8
8
|
exports.getSwapRouterDepositResult = getSwapRouterDepositResult;
|
|
9
|
+
exports.getOriginInfo = getOriginInfo;
|
|
10
|
+
exports.readOriginInfo = readOriginInfo;
|
|
11
|
+
exports.readSwapRouterVaultInfo = readSwapRouterVaultInfo;
|
|
12
|
+
exports.readSwapRouterTokenWhitelisted = readSwapRouterTokenWhitelisted;
|
|
9
13
|
exports.getSwapRouterWhitelistedTokens = getSwapRouterWhitelistedTokens;
|
|
10
14
|
exports.getSwapRouterEligibleVaults = getSwapRouterEligibleVaults;
|
|
11
15
|
const ethers_1 = require("ethers");
|
|
12
16
|
const swap_router_1 = require("../constants/swap-router");
|
|
17
|
+
const attribution_1 = require("../attribution");
|
|
13
18
|
const abis_1 = require("../../abis");
|
|
14
19
|
const errors_1 = require("../errors");
|
|
15
20
|
const cache_1 = require("../cache");
|
|
@@ -59,7 +64,7 @@ function getSwapRouterName(chainId) {
|
|
|
59
64
|
*
|
|
60
65
|
* This gates the (flag-controlled) swap-router deposit UI and can fail-fast a
|
|
61
66
|
* {@link swapRouterDeposit} call. It does **not** affect {@link vaultDeposit},
|
|
62
|
-
* which
|
|
67
|
+
* which never swaps (see `getDepositRoute` for when it uses the router).
|
|
63
68
|
*
|
|
64
69
|
* @param vaultAddress - August vault address.
|
|
65
70
|
* @returns `true` when the vault is in {@link SWAP_ROUTER_ELIGIBLE_VAULTS}.
|
|
@@ -84,21 +89,33 @@ exports.vaultUsesSwapRouter = isSwapRouterEligible;
|
|
|
84
89
|
/**
|
|
85
90
|
* Normalize an optional origin code to the value to send on-chain.
|
|
86
91
|
*
|
|
87
|
-
* Returns the caller-supplied code when present
|
|
88
|
-
*
|
|
92
|
+
* Returns the caller-supplied code when present (an explicit all-zero
|
|
93
|
+
* sentinel opts one call out), otherwise the SDK instance's
|
|
94
|
+
* `attribution.originCode` when `chainId` is in
|
|
95
|
+
* {@link ORIGIN_ATTRIBUTION_CHAINS} (Ethereum mainnet only), otherwise the
|
|
96
|
+
* default (all-zero) sentinel from {@link ORIGIN_CODES}. Validates that any
|
|
89
97
|
* supplied code is exactly 32 bytes (66 chars including the `0x` prefix);
|
|
90
98
|
* the on-chain SwapRouter reverts with `InvalidOrigin` otherwise, but
|
|
91
99
|
* surfacing the failure here as a typed SDK error gives partners a
|
|
92
100
|
* grepable Sentry event instead of a generic `execution reverted`.
|
|
93
101
|
*
|
|
94
102
|
* @param provided - Optional caller-supplied origin code.
|
|
103
|
+
* @param chainId - Chain the deposit is sent on. The instance code is never
|
|
104
|
+
* returned without it, or on a chain outside
|
|
105
|
+
* {@link ORIGIN_ATTRIBUTION_CHAINS}.
|
|
95
106
|
* @returns The 32-byte origin code to pass to the router.
|
|
96
107
|
* @throws {@link AugustValidationError} when `provided` is not a 32-byte hex string.
|
|
97
108
|
*/
|
|
98
|
-
function resolveOriginCode(provided) {
|
|
99
|
-
if (provided === undefined)
|
|
100
|
-
|
|
101
|
-
|
|
109
|
+
function resolveOriginCode(provided, chainId) {
|
|
110
|
+
if (provided === undefined) {
|
|
111
|
+
const instanceCode = (0, attribution_1.getOriginCode)();
|
|
112
|
+
return instanceCode &&
|
|
113
|
+
chainId !== undefined &&
|
|
114
|
+
swap_router_1.ORIGIN_ATTRIBUTION_CHAINS.includes(chainId)
|
|
115
|
+
? instanceCode
|
|
116
|
+
: swap_router_1.ORIGIN_CODES.default;
|
|
117
|
+
}
|
|
118
|
+
if (!swap_router_1.ORIGIN_CODE_PATTERN.test(provided)) {
|
|
102
119
|
throw new errors_1.AugustValidationError('INVALID_INPUT', `resolveOriginCode: originCode must be a 32-byte hex string (66 chars incl. 0x), got "${provided}" (${provided.length} chars)`, { context: { provided, expectedLength: 66 } });
|
|
103
120
|
}
|
|
104
121
|
return provided;
|
|
@@ -181,6 +198,140 @@ async function getSwapRouterDepositResult(signer, { txHash, vault }) {
|
|
|
181
198
|
}
|
|
182
199
|
return null;
|
|
183
200
|
}
|
|
201
|
+
/** Cache TTL for resolved origin-code, vault and token registrations (5 minutes). */
|
|
202
|
+
const SWAP_ROUTER_ORIGIN_INFO_TTL_MS = 5 * 60 * 1000;
|
|
203
|
+
/**
|
|
204
|
+
* Read how an origin code is registered on a chain's `SwapRouter`: whether it
|
|
205
|
+
* exists, its origin fee, and its fee collector.
|
|
206
|
+
*
|
|
207
|
+
* Check a partner code with this before configuring it as
|
|
208
|
+
* `attribution.originCode` — the router reverts every deposit carrying an
|
|
209
|
+
* unregistered code with `InvalidOrigin`. A code is registered when its
|
|
210
|
+
* collector is non-zero (`addOrigin` always sets one); a zero-fee code is
|
|
211
|
+
* still registered but never emits `OriginFeeApplied`. Cached per (chain,
|
|
212
|
+
* router, code) for 5 minutes.
|
|
213
|
+
*
|
|
214
|
+
* @param options - {@link IGetOriginInfoOptions}.
|
|
215
|
+
* @returns {@link IOriginInfo}; `registered: false` with a zero fee and
|
|
216
|
+
* collector, and no RPC, on a chain with no SwapRouter deployment.
|
|
217
|
+
* @throws {@link AugustValidationError} when `originCode` is not a 32-byte hex
|
|
218
|
+
* string.
|
|
219
|
+
* @throws {@link AugustSDKError} when the `origins(bytes32)` read fails.
|
|
220
|
+
* @worstCaseRpcCalls 1 — one `origins(bytes32)` call; none on a cache hit.
|
|
221
|
+
* @example
|
|
222
|
+
* ```ts
|
|
223
|
+
* const info = await getOriginInfo({ chainId: 1, originCode, rpcUrl });
|
|
224
|
+
* if (!info.registered) throw new Error('origin code is not registered');
|
|
225
|
+
* ```
|
|
226
|
+
*/
|
|
227
|
+
async function getOriginInfo({ chainId, originCode, rpcUrl, }) {
|
|
228
|
+
if (!swap_router_1.ORIGIN_CODE_PATTERN.test(originCode)) {
|
|
229
|
+
throw new errors_1.AugustValidationError('INVALID_INPUT', `getOriginInfo: originCode must be a 32-byte hex string (66 chars incl. 0x), got ${String(originCode).length} chars`, { context: { chainId, expectedLength: 66 } });
|
|
230
|
+
}
|
|
231
|
+
try {
|
|
232
|
+
return await readOriginInfo(chainId, originCode, () => (0, web3_1.createProvider)(rpcUrl, chainId));
|
|
233
|
+
}
|
|
234
|
+
catch (e) {
|
|
235
|
+
if (e instanceof errors_1.AugustSDKError)
|
|
236
|
+
throw e;
|
|
237
|
+
throw new errors_1.AugustSDKError('UNKNOWN', `getOriginInfo failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { chainId } });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* {@link getOriginInfo} without input validation, reading through a caller
|
|
242
|
+
* runner (created lazily, only on a cache miss). Shared with the deposit-route
|
|
243
|
+
* resolver so both hit the same cache entry.
|
|
244
|
+
* @internal
|
|
245
|
+
*/
|
|
246
|
+
async function readOriginInfo(chainId, originCode, runner) {
|
|
247
|
+
const unregistered = {
|
|
248
|
+
registered: false,
|
|
249
|
+
originFeeBps: 0,
|
|
250
|
+
collector: ethers_1.ethers.ZeroAddress,
|
|
251
|
+
};
|
|
252
|
+
const router = getSwapRouterAddress(chainId);
|
|
253
|
+
if (!router)
|
|
254
|
+
return unregistered;
|
|
255
|
+
const cacheKey = `swap-router-origin-${chainId}-${router.toLowerCase()}-${originCode.toLowerCase()}`;
|
|
256
|
+
const cached = await (0, cache_1.getSafeCache)(cacheKey);
|
|
257
|
+
if (cached)
|
|
258
|
+
return cached;
|
|
259
|
+
const contract = (0, web3_1.createContract)({
|
|
260
|
+
address: router,
|
|
261
|
+
provider: runner(),
|
|
262
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
263
|
+
});
|
|
264
|
+
if (!contract)
|
|
265
|
+
return unregistered;
|
|
266
|
+
const [originFee, originFeeCollector] = await contract.origins(originCode);
|
|
267
|
+
const info = {
|
|
268
|
+
registered: originFeeCollector !== ethers_1.ethers.ZeroAddress,
|
|
269
|
+
originFeeBps: Number(originFee),
|
|
270
|
+
collector: originFeeCollector,
|
|
271
|
+
};
|
|
272
|
+
cache_1.CACHE.set(cacheKey, info, { ttl: SWAP_ROUTER_ORIGIN_INFO_TTL_MS });
|
|
273
|
+
return info;
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Read a vault's `SwapRouter` registration (`vaultInfo`), cached for 5
|
|
277
|
+
* minutes like the other router reads.
|
|
278
|
+
*
|
|
279
|
+
* @returns The router's `referenceAsset` for the vault (the zero address when
|
|
280
|
+
* it is not registered) and its `vaultType`; `undefined` on a chain with no
|
|
281
|
+
* SwapRouter.
|
|
282
|
+
* @internal
|
|
283
|
+
*/
|
|
284
|
+
async function readSwapRouterVaultInfo(runner, chainId, vault) {
|
|
285
|
+
const router = getSwapRouterAddress(chainId);
|
|
286
|
+
if (!router)
|
|
287
|
+
return undefined;
|
|
288
|
+
const cacheKey = `swap-router-vault-info-${chainId}-${router.toLowerCase()}-${vault.toLowerCase()}`;
|
|
289
|
+
const cached = await (0, cache_1.getSafeCache)(cacheKey);
|
|
290
|
+
if (cached)
|
|
291
|
+
return cached;
|
|
292
|
+
const contract = (0, web3_1.createContract)({
|
|
293
|
+
address: router,
|
|
294
|
+
provider: runner,
|
|
295
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
296
|
+
});
|
|
297
|
+
if (!contract)
|
|
298
|
+
return undefined;
|
|
299
|
+
const [, vaultType, referenceAsset] = await contract.vaultInfo(vault);
|
|
300
|
+
const info = {
|
|
301
|
+
referenceAsset: referenceAsset,
|
|
302
|
+
vaultType: Number(vaultType),
|
|
303
|
+
};
|
|
304
|
+
cache_1.CACHE.set(cacheKey, info, { ttl: SWAP_ROUTER_ORIGIN_INFO_TTL_MS });
|
|
305
|
+
return info;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Read whether a chain's `SwapRouter` whitelists `token`
|
|
309
|
+
* (`whitelistedTokens`), cached for 5 minutes like the other router reads.
|
|
310
|
+
* `SwapRouter.deposit` reverts `InputTokenNotWhitelisted` for any token it
|
|
311
|
+
* does not whitelist, the vault's reference asset included.
|
|
312
|
+
*
|
|
313
|
+
* @returns `false` on a chain with no SwapRouter.
|
|
314
|
+
* @internal
|
|
315
|
+
*/
|
|
316
|
+
async function readSwapRouterTokenWhitelisted(runner, chainId, token) {
|
|
317
|
+
const router = getSwapRouterAddress(chainId);
|
|
318
|
+
if (!router)
|
|
319
|
+
return false;
|
|
320
|
+
const cacheKey = `swap-router-token-whitelisted-${chainId}-${router.toLowerCase()}-${token.toLowerCase()}`;
|
|
321
|
+
const cached = await (0, cache_1.getSafeCache)(cacheKey);
|
|
322
|
+
if (cached !== null)
|
|
323
|
+
return cached;
|
|
324
|
+
const contract = (0, web3_1.createContract)({
|
|
325
|
+
address: router,
|
|
326
|
+
provider: runner,
|
|
327
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
328
|
+
});
|
|
329
|
+
if (!contract)
|
|
330
|
+
return false;
|
|
331
|
+
const whitelisted = (await contract.whitelistedTokens(token)) === true;
|
|
332
|
+
cache_1.CACHE.set(cacheKey, whitelisted, { ttl: SWAP_ROUTER_ORIGIN_INFO_TTL_MS });
|
|
333
|
+
return whitelisted;
|
|
334
|
+
}
|
|
184
335
|
/** Cache TTL for a chain's resolved SwapRouter token allowlist (5 minutes). */
|
|
185
336
|
const SWAP_ROUTER_WHITELIST_TTL_MS = 5 * 60 * 1000;
|
|
186
337
|
/**
|
package/lib/main.d.ts
CHANGED
|
@@ -89,10 +89,12 @@ export declare class AugustSDK extends AugustBase {
|
|
|
89
89
|
}): Promise<number>;
|
|
90
90
|
/**
|
|
91
91
|
* Deposit into a vault with an explicit signer. When `depositAsset` differs
|
|
92
|
-
* from the vault's underlying asset the deposit
|
|
93
|
-
*
|
|
92
|
+
* from the vault's underlying asset the deposit goes through the vault's
|
|
93
|
+
* multi-asset `deposit`, permit path, or configured adapter. It never swaps
|
|
94
|
+
* (use `evm.swapRouterDeposit` for that); with `attribution.originCode` set,
|
|
95
|
+
* eligible deposits go through the SwapRouter (see `evm.getDepositRoute`).
|
|
94
96
|
* @param signer - ethers Signer or Wallet that sends the transaction
|
|
95
|
-
* @param options - Vault address (`target`), depositor `wallet`, `amount`, and optional `depositAsset`, `wait`, `
|
|
97
|
+
* @param options - Vault address (`target`), depositor `wallet`, `amount`, and optional `depositAsset`, `wait`, `isDepositWithPermit`
|
|
96
98
|
* @returns Deposit transaction hash
|
|
97
99
|
*/
|
|
98
100
|
vaultDeposit(signer: Signer | Wallet, options: IContractWriteOptions): Promise<string>;
|
|
@@ -350,6 +352,22 @@ export declare class AugustSDK extends AugustBase {
|
|
|
350
352
|
getSwapRouterEligibleVaults(chainId: number, options?: {
|
|
351
353
|
fromBlock?: number;
|
|
352
354
|
}): Promise<IAddress[]>;
|
|
355
|
+
/**
|
|
356
|
+
* Read a SwapRouter origin code's on-chain registration (registered, fee in
|
|
357
|
+
* bps, collector). Delegates to {@link AugustVaults.getOriginInfo}.
|
|
358
|
+
* @param options - `chainId` and the `bytes32` `originCode` to look up.
|
|
359
|
+
* @returns `{ registered, originFeeBps, collector }`.
|
|
360
|
+
* @throws AugustValidationError when no provider is configured for `chainId`
|
|
361
|
+
* or `originCode` is malformed.
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* const { registered } = await augustSdk.getOriginInfo({ chainId: 1, originCode });
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
getOriginInfo(options: {
|
|
368
|
+
chainId: number;
|
|
369
|
+
originCode: `0x${string}`;
|
|
370
|
+
}): Promise<import("./types").IOriginInfo>;
|
|
353
371
|
/**
|
|
354
372
|
* Get lifetime PnL for a user in a specific vault.
|
|
355
373
|
* Calculates realized and unrealized PnL based on deposit/withdrawal history and current position.
|
package/lib/main.js
CHANGED
|
@@ -220,10 +220,12 @@ class AugustSDK extends core_1.AugustBase {
|
|
|
220
220
|
}
|
|
221
221
|
/**
|
|
222
222
|
* Deposit into a vault with an explicit signer. When `depositAsset` differs
|
|
223
|
-
* from the vault's underlying asset the deposit
|
|
224
|
-
*
|
|
223
|
+
* from the vault's underlying asset the deposit goes through the vault's
|
|
224
|
+
* multi-asset `deposit`, permit path, or configured adapter. It never swaps
|
|
225
|
+
* (use `evm.swapRouterDeposit` for that); with `attribution.originCode` set,
|
|
226
|
+
* eligible deposits go through the SwapRouter (see `evm.getDepositRoute`).
|
|
225
227
|
* @param signer - ethers Signer or Wallet that sends the transaction
|
|
226
|
-
* @param options - Vault address (`target`), depositor `wallet`, `amount`, and optional `depositAsset`, `wait`, `
|
|
228
|
+
* @param options - Vault address (`target`), depositor `wallet`, `amount`, and optional `depositAsset`, `wait`, `isDepositWithPermit`
|
|
227
229
|
* @returns Deposit transaction hash
|
|
228
230
|
*/
|
|
229
231
|
async vaultDeposit(signer, options) {
|
|
@@ -425,6 +427,21 @@ class AugustSDK extends core_1.AugustBase {
|
|
|
425
427
|
async getSwapRouterEligibleVaults(chainId, options) {
|
|
426
428
|
return await this.vaults.getSwapRouterEligibleVaults(chainId, options);
|
|
427
429
|
}
|
|
430
|
+
/**
|
|
431
|
+
* Read a SwapRouter origin code's on-chain registration (registered, fee in
|
|
432
|
+
* bps, collector). Delegates to {@link AugustVaults.getOriginInfo}.
|
|
433
|
+
* @param options - `chainId` and the `bytes32` `originCode` to look up.
|
|
434
|
+
* @returns `{ registered, originFeeBps, collector }`.
|
|
435
|
+
* @throws AugustValidationError when no provider is configured for `chainId`
|
|
436
|
+
* or `originCode` is malformed.
|
|
437
|
+
* @example
|
|
438
|
+
* ```ts
|
|
439
|
+
* const { registered } = await augustSdk.getOriginInfo({ chainId: 1, originCode });
|
|
440
|
+
* ```
|
|
441
|
+
*/
|
|
442
|
+
async getOriginInfo(options) {
|
|
443
|
+
return await this.vaults.getOriginInfo(options);
|
|
444
|
+
}
|
|
428
445
|
/**
|
|
429
446
|
* Get lifetime PnL for a user in a specific vault.
|
|
430
447
|
* Calculates realized and unrealized PnL based on deposit/withdrawal history and current position.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IAddress, type IHistoricalTimeseriesPoint, type IHistoricalTimeseriesResponse, type INormalizedNumber, type ISubgraphTransfer, type ITokenizedVault, type ISubgraphWithdrawProccessed, type IVault, type IVaultAllocations, type IVaultAnnualizedApy, type IVaultAvailableRedemption, type IVaultLoan, type IVaultPosition, type IVaultRedemptionHistoryItem, type IVaultSummary, type IVaultWithdrawals, type IVaultPendingRedemptions, type IActiveStakingPosition, type IVaultHistoricalParams, type IVaultUserLifetimePnl, type IVaultBorrowerHealthFactor, type IVaultPnl, type VaultAddress } from '../../types';
|
|
1
|
+
import { type IAddress, type IHistoricalTimeseriesPoint, type IHistoricalTimeseriesResponse, type INormalizedNumber, type ISubgraphReserveDeposit, type ISubgraphTransfer, type ISubgraphUserHistoryItem, type ITokenizedVault, type ISubgraphWithdrawProccessed, type IVault, type IVaultAllocations, type IVaultAnnualizedApy, type IVaultAvailableRedemption, type IVaultLoan, type IVaultPosition, type IVaultRedemptionHistoryItem, type IVaultSummary, type IVaultWithdrawals, type IVaultPendingRedemptions, type IActiveStakingPosition, type IVaultHistoricalParams, type IVaultUserLifetimePnl, type IVaultBorrowerHealthFactor, type IVaultPnl, type VaultAddress } from '../../types';
|
|
2
2
|
import type { IVaultBaseOptions } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Vault Data Getters
|
|
@@ -444,12 +444,15 @@ export type PnlTransfer = Pick<ISubgraphTransfer, 'from' | 'to' | 'value' | 'tim
|
|
|
444
444
|
* another wallet. Mints (from the zero address), burns (to it) and transfers to
|
|
445
445
|
* or from the vault itself are dropped: those are the deposit and withdrawal
|
|
446
446
|
* legs the subgraph history already records, and counting them again would
|
|
447
|
-
* double the cost basis.
|
|
447
|
+
* double the cost basis. Transfers to or from `exclude` are dropped too.
|
|
448
448
|
*
|
|
449
449
|
* @param transfers - Receipt-token transfers touching `wallet`, as returned by
|
|
450
450
|
* the vault's transfer subgraph.
|
|
451
451
|
* @param wallet - The wallet whose position is being valued.
|
|
452
452
|
* @param vault - The vault contract address.
|
|
453
|
+
* @param exclude - Other counterparties whose transfers are not peer
|
|
454
|
+
* transfers, such as a LayerZero OVault's hub composer and share OFT
|
|
455
|
+
* (`hubComposer` / `hubShareOFT` in `LAYERZERO_VAULTS`). Defaults to none.
|
|
453
456
|
* @returns The peer-to-peer transfers, in input order. Addresses compare
|
|
454
457
|
* case-insensitively.
|
|
455
458
|
* @example
|
|
@@ -457,7 +460,7 @@ export type PnlTransfer = Pick<ISubgraphTransfer, 'from' | 'to' | 'value' | 'tim
|
|
|
457
460
|
* const peer = selectPeerTransfers(transfers, wallet, vault);
|
|
458
461
|
* ```
|
|
459
462
|
*/
|
|
460
|
-
export declare function selectPeerTransfers<T extends PnlTransfer>(transfers: T[], wallet: IAddress, vault: IAddress): T[];
|
|
463
|
+
export declare function selectPeerTransfers<T extends PnlTransfer>(transfers: T[], wallet: IAddress, vault: IAddress, exclude?: string[]): T[];
|
|
461
464
|
/** Inputs {@link transferCostBasis} prices. */
|
|
462
465
|
export interface TransferCostBasisParams {
|
|
463
466
|
/** Peer transfers touching `wallet` — see {@link selectPeerTransfers}. */
|
|
@@ -472,6 +475,13 @@ export interface TransferCostBasisParams {
|
|
|
472
475
|
* read.
|
|
473
476
|
*/
|
|
474
477
|
history: Record<string, Pick<IHistoricalTimeseriesPoint, 'asset_share_ratio'>>;
|
|
478
|
+
/**
|
|
479
|
+
* Report sent shares even when none were received. Defaults to `false`, which
|
|
480
|
+
* zeroes them so a zero-deposit wallet's history guard still decides; pass
|
|
481
|
+
* `true` when the caller applies that rule itself, as {@link pnlCostBasis}
|
|
482
|
+
* does.
|
|
483
|
+
*/
|
|
484
|
+
countSentWithoutReceipt?: boolean;
|
|
475
485
|
}
|
|
476
486
|
/** Asset amounts that peer transfers moved into and out of a position. */
|
|
477
487
|
export interface TransferCostBasis {
|
|
@@ -491,9 +501,11 @@ export interface TransferCostBasis {
|
|
|
491
501
|
* profit. A day with no usable ratio takes the latest earlier day's, and a
|
|
492
502
|
* transfer older than the history takes the earliest day's.
|
|
493
503
|
*
|
|
494
|
-
* Sent shares count only against a received basis. A wallet that
|
|
495
|
-
* but received none gets a zero basis, so the lifetime-PnL history
|
|
496
|
-
* decides for it instead of reporting the sent shares as profit.
|
|
504
|
+
* Sent shares count only against a received basis by default. A wallet that
|
|
505
|
+
* sent shares but received none gets a zero basis, so the lifetime-PnL history
|
|
506
|
+
* guard still decides for it instead of reporting the sent shares as profit.
|
|
507
|
+
* `countSentWithoutReceipt: true` reports them anyway, for a caller that knows
|
|
508
|
+
* the wallet also deposited.
|
|
497
509
|
*
|
|
498
510
|
* Pure and synchronous. Assumes, as the getter does, that shares and assets
|
|
499
511
|
* share the vault's decimals.
|
|
@@ -514,7 +526,242 @@ export interface TransferCostBasis {
|
|
|
514
526
|
* });
|
|
515
527
|
* ```
|
|
516
528
|
*/
|
|
517
|
-
export declare function transferCostBasis({ transfers, wallet, vault, history, }: TransferCostBasisParams): TransferCostBasis;
|
|
529
|
+
export declare function transferCostBasis({ transfers, wallet, vault, history, countSentWithoutReceipt, }: TransferCostBasisParams): TransferCostBasis;
|
|
530
|
+
/** Inputs {@link historyCoversMints} compares. */
|
|
531
|
+
export interface HistoryCoversMintsParams {
|
|
532
|
+
/** Every share-token transfer touching `wallet`, mints included. */
|
|
533
|
+
transfers: Pick<ISubgraphTransfer, 'from' | 'to' | 'transactionHash_'>[];
|
|
534
|
+
/** The wallet whose history is being checked. */
|
|
535
|
+
wallet: IAddress;
|
|
536
|
+
/** Transaction hashes of the wallet's indexed deposits. */
|
|
537
|
+
depositTransactionHashes: string[];
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Check that a wallet's indexed deposit history accounts for every share mint
|
|
541
|
+
* its share-token ledger shows.
|
|
542
|
+
*
|
|
543
|
+
* A deposit mints shares to the wallet in the same transaction, so a mint with
|
|
544
|
+
* no deposit of the same hash means the history is missing that deposit (an
|
|
545
|
+
* older deposit the subgraph never indexed, or one a third party made for the
|
|
546
|
+
* wallet). Folding peer transfers into such a history would credit the wallet
|
|
547
|
+
* for shares it sent while missing what it paid for them, so
|
|
548
|
+
* {@link getVaultUserLifetimePnl} only folds transfers for a depositor when
|
|
549
|
+
* this holds.
|
|
550
|
+
*
|
|
551
|
+
* Pure and synchronous. Hashes and addresses compare case-insensitively.
|
|
552
|
+
*
|
|
553
|
+
* @param params - See {@link HistoryCoversMintsParams}.
|
|
554
|
+
* @returns `true` when every mint to `wallet` has a matching deposit, including
|
|
555
|
+
* when there are no mints.
|
|
556
|
+
* @example
|
|
557
|
+
* ```ts
|
|
558
|
+
* const covered = historyCoversMints({
|
|
559
|
+
* transfers,
|
|
560
|
+
* wallet,
|
|
561
|
+
* depositTransactionHashes: history
|
|
562
|
+
* .filter((item) => item.type === 'deposit')
|
|
563
|
+
* .map((item) => item.transactionHash_),
|
|
564
|
+
* });
|
|
565
|
+
* ```
|
|
566
|
+
*/
|
|
567
|
+
export declare function historyCoversMints({ transfers, wallet, depositTransactionHashes, }: HistoryCoversMintsParams): boolean;
|
|
568
|
+
/** Inputs {@link selectReserveDeposits} matches. */
|
|
569
|
+
export interface SelectReserveDepositsParams {
|
|
570
|
+
/** The wallet's `ReserveDeposit` events (see `getSubgraphUserReserveDeposits`). */
|
|
571
|
+
reserveDeposits: ISubgraphReserveDeposit[];
|
|
572
|
+
/** Every share-token transfer touching `wallet`, mints included. */
|
|
573
|
+
transfers: Pick<ISubgraphTransfer, 'from' | 'to' | 'transactionHash_'>[];
|
|
574
|
+
/** The wallet whose history is being completed. */
|
|
575
|
+
wallet: IAddress;
|
|
576
|
+
/** Transaction hashes of the wallet's indexed deposits. */
|
|
577
|
+
depositTransactionHashes: string[];
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Keep the `ReserveDeposit` events that explain a share mint the indexed
|
|
581
|
+
* deposit history misses.
|
|
582
|
+
*
|
|
583
|
+
* High Growth ETH mints shares for deposits made through Kelp's gain adapter
|
|
584
|
+
* with a `ReserveDeposit` event instead of an ERC-4626 `Deposit`, so those
|
|
585
|
+
* deposits are absent from the user history and fail {@link historyCoversMints}.
|
|
586
|
+
* An event counts only when its transaction mints shares to `wallet` and holds
|
|
587
|
+
* no indexed deposit, so a deposit is never counted twice.
|
|
588
|
+
*
|
|
589
|
+
* Pure and synchronous. Hashes and addresses compare case-insensitively.
|
|
590
|
+
*
|
|
591
|
+
* @param params - See {@link SelectReserveDepositsParams}.
|
|
592
|
+
* @returns The matching events, in input order.
|
|
593
|
+
* @example
|
|
594
|
+
* ```ts
|
|
595
|
+
* const reserve = selectReserveDeposits({
|
|
596
|
+
* reserveDeposits: await getSubgraphUserReserveDeposits(wallet, provider, vault),
|
|
597
|
+
* transfers,
|
|
598
|
+
* wallet,
|
|
599
|
+
* depositTransactionHashes,
|
|
600
|
+
* });
|
|
601
|
+
* ```
|
|
602
|
+
*/
|
|
603
|
+
export declare function selectReserveDeposits({ reserveDeposits, transfers, wallet, depositTransactionHashes, }: SelectReserveDepositsParams): ISubgraphReserveDeposit[];
|
|
604
|
+
/** Inputs {@link countWithdrawalRequestsOnce} reads. */
|
|
605
|
+
export interface CountWithdrawalRequestsOnceParams {
|
|
606
|
+
/** The wallet's user history (see `getSubgraphUserHistory`). */
|
|
607
|
+
history: ISubgraphUserHistoryItem[];
|
|
608
|
+
/** Every share-token transfer touching `wallet`. */
|
|
609
|
+
transfers: Pick<ISubgraphTransfer, 'from' | 'to' | 'transactionHash_'>[];
|
|
610
|
+
/** The wallet whose history is being read. */
|
|
611
|
+
wallet: IAddress;
|
|
612
|
+
/** The vault contract address. */
|
|
613
|
+
vault: IAddress;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Drop withdrawal-request rows the vault logged more than once for a single
|
|
617
|
+
* request.
|
|
618
|
+
*
|
|
619
|
+
* A redemption requested through Kelp's gain adapter makes High Growth ETH emit
|
|
620
|
+
* `WithdrawalRequested` twice for one share transfer, and the subgraph indexes
|
|
621
|
+
* both. In a transaction where the share ledger shows the wallet sending shares
|
|
622
|
+
* to the vault `n` times, at most `n` request rows are kept. A transaction the
|
|
623
|
+
* ledger shows no such transfer for keeps every row, so a missing ledger leaves
|
|
624
|
+
* the history unchanged.
|
|
625
|
+
*
|
|
626
|
+
* Pure and synchronous. Hashes and addresses compare case-insensitively.
|
|
627
|
+
*
|
|
628
|
+
* @param params - See {@link CountWithdrawalRequestsOnceParams}.
|
|
629
|
+
* @returns The history without the surplus request rows, in input order.
|
|
630
|
+
* @example
|
|
631
|
+
* ```ts
|
|
632
|
+
* const history = countWithdrawalRequestsOnce({ history: userHistory, transfers, wallet, vault });
|
|
633
|
+
* ```
|
|
634
|
+
*/
|
|
635
|
+
export declare function countWithdrawalRequestsOnce({ history, transfers, wallet, vault, }: CountWithdrawalRequestsOnceParams): ISubgraphUserHistoryItem[];
|
|
636
|
+
/** Inputs {@link settleV2Redemptions} values. */
|
|
637
|
+
export interface SettleV2RedemptionsParams {
|
|
638
|
+
/** The wallet's user history (see `getSubgraphUserHistory`). */
|
|
639
|
+
history: ISubgraphUserHistoryItem[];
|
|
640
|
+
/** The vault's `lagDuration()`, in seconds. */
|
|
641
|
+
lagDuration: number;
|
|
642
|
+
/**
|
|
643
|
+
* The vault's daily history from `fetchVaultHistoricalTimeseries`, keyed by
|
|
644
|
+
* UTC date (`YYYY-MM-DD`). Only `asset_share_ratio` (assets per share) is
|
|
645
|
+
* read.
|
|
646
|
+
*/
|
|
647
|
+
ratios: Record<string, Pick<IHistoricalTimeseriesPoint, 'asset_share_ratio'>>;
|
|
648
|
+
/** The current time, in unix seconds. */
|
|
649
|
+
now: number;
|
|
650
|
+
}
|
|
651
|
+
/** What a wallet's Tokenized Vault V2 redemption requests are worth. */
|
|
652
|
+
export interface V2RedemptionValue {
|
|
653
|
+
/** Assets paid, or due, for requests past their claim date; raw at vault decimals. */
|
|
654
|
+
settledAssetsRaw: bigint;
|
|
655
|
+
/** Shares to value at the current share price, raw. */
|
|
656
|
+
pendingShares: bigint;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* Value a wallet's Tokenized Vault V2 redemption requests, which carry only
|
|
660
|
+
* shares.
|
|
661
|
+
*
|
|
662
|
+
* Every processed withdrawal (`WithdrawalProcessed.assetsAmount`) counts at the
|
|
663
|
+
* assets the vault paid. Its shares, estimated at the vault's
|
|
664
|
+
* `asset_share_ratio` on the day it was processed, retire the oldest requests
|
|
665
|
+
* first. Request shares left over count at the ratio on their claim date (see
|
|
666
|
+
* `computeClaimableDate`) once claimable: the subgraph lacks some processed rows
|
|
667
|
+
* (none for earnAUSD before 2026-02-01), and that ratio lands within about
|
|
668
|
+
* 0.05% of what the vault paid. Shares not yet claimable are left to the
|
|
669
|
+
* current share price. Matching by amount, not by claim date, keeps the result
|
|
670
|
+
* right when a vault processes a request before the date today's `lagDuration`
|
|
671
|
+
* implies. A leftover under 0.5% of a request that a later processed
|
|
672
|
+
* withdrawal followed is rounding from the daily ratio, so it is dropped.
|
|
673
|
+
*
|
|
674
|
+
* Pure and synchronous. Assumes, as the getter does, that shares and assets
|
|
675
|
+
* share the vault's decimals. A day with no usable ratio takes the latest
|
|
676
|
+
* earlier day's, and a date older than the history takes the earliest day's.
|
|
677
|
+
*
|
|
678
|
+
* @param params - See {@link SettleV2RedemptionsParams}.
|
|
679
|
+
* @returns The settled assets and the shares left to the current price; every
|
|
680
|
+
* requested share is pending when `ratios` holds no usable day.
|
|
681
|
+
* @example
|
|
682
|
+
* ```ts
|
|
683
|
+
* const { settledAssetsRaw, pendingShares } = settleV2Redemptions({
|
|
684
|
+
* history,
|
|
685
|
+
* lagDuration: 259_200,
|
|
686
|
+
* ratios: (await fetchVaultHistoricalTimeseries(vault, nDays)).data,
|
|
687
|
+
* now: Math.floor(Date.now() / 1000),
|
|
688
|
+
* });
|
|
689
|
+
* ```
|
|
690
|
+
*/
|
|
691
|
+
export declare function settleV2Redemptions({ history, lagDuration, ratios, now, }: SettleV2RedemptionsParams): V2RedemptionValue;
|
|
692
|
+
/** Inputs {@link pnlCostBasis} folds together. */
|
|
693
|
+
export interface PnlCostBasisParams {
|
|
694
|
+
/** Indexed deposits at face value, raw at the vault's decimals. */
|
|
695
|
+
depositedRaw: bigint;
|
|
696
|
+
/** Withdrawals already in asset terms, raw at the vault's decimals. */
|
|
697
|
+
withdrawnAssetsRaw: bigint;
|
|
698
|
+
/** Whether history indexed any deposit, LayerZero deposits included. */
|
|
699
|
+
hasDeposits: boolean;
|
|
700
|
+
/** Whether the history accounts for every share mint (see {@link historyCoversMints}). */
|
|
701
|
+
mintsMatchHistory: boolean;
|
|
702
|
+
/**
|
|
703
|
+
* Peer transfers priced by {@link transferCostBasis} with
|
|
704
|
+
* `countSentWithoutReceipt: true`.
|
|
705
|
+
*/
|
|
706
|
+
transfers: TransferCostBasis;
|
|
707
|
+
}
|
|
708
|
+
/** The cost basis {@link getVaultUserLifetimePnl} computes PnL against. */
|
|
709
|
+
export interface PnlCostBasis {
|
|
710
|
+
/** Indexed deposits plus shares received by transfer, raw at vault decimals. */
|
|
711
|
+
depositedRaw: bigint;
|
|
712
|
+
/** Asset-terms withdrawals plus shares sent by transfer, raw at vault decimals. */
|
|
713
|
+
withdrawnAssetsRaw: bigint;
|
|
714
|
+
/** The part of `depositedRaw` that came from shares received by transfer. */
|
|
715
|
+
receivedByTransferRaw: bigint;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Fold peer share transfers into a wallet's lifetime-PnL cost basis.
|
|
719
|
+
*
|
|
720
|
+
* Shares a wallet received from another holder (a migration airdrop, a DEX
|
|
721
|
+
* purchase, a transfer from another wallet) cost the wallet their value on
|
|
722
|
+
* arrival, so they add to the deposited amount; shares it sent away count as
|
|
723
|
+
* withdrawn. This applies whether or not the wallet also deposited, so a holder
|
|
724
|
+
* who received shares and then topped up is not credited with the received
|
|
725
|
+
* shares as profit, and a depositor who moved its shares elsewhere (a lending
|
|
726
|
+
* market, a DEX) is not shown as having lost them. A wallet with no deposit and
|
|
727
|
+
* no received shares keeps a zero basis, so the history guard still decides.
|
|
728
|
+
*
|
|
729
|
+
* A depositor whose history misses a mint ({@link historyCoversMints}) is the
|
|
730
|
+
* exception: its transfers do not count, so the result matches what the getter
|
|
731
|
+
* returned before transfers counted for depositors. On a LayerZero OVault the
|
|
732
|
+
* caller leaves the hub composer and share OFT out of the transfers (see
|
|
733
|
+
* {@link selectPeerTransfers}): the composer's deliveries are already counted
|
|
734
|
+
* as LayerZero deposits, and shares bridged to a spoke chain still count in the
|
|
735
|
+
* position.
|
|
736
|
+
*
|
|
737
|
+
* Pure and synchronous.
|
|
738
|
+
*
|
|
739
|
+
* @param params - See {@link PnlCostBasisParams}.
|
|
740
|
+
* @returns The deposited and withdrawn amounts to compute PnL from, and the
|
|
741
|
+
* transfer-priced part of the deposited amount (zero when transfers did not
|
|
742
|
+
* count).
|
|
743
|
+
* @example
|
|
744
|
+
* ```ts
|
|
745
|
+
* const basis = pnlCostBasis({
|
|
746
|
+
* depositedRaw,
|
|
747
|
+
* withdrawnAssetsRaw,
|
|
748
|
+
* hasDeposits: depositedRaw > BigInt(0),
|
|
749
|
+
* mintsMatchHistory: historyCoversMints({
|
|
750
|
+
* transfers,
|
|
751
|
+
* wallet,
|
|
752
|
+
* depositTransactionHashes,
|
|
753
|
+
* }),
|
|
754
|
+
* transfers: transferCostBasis({
|
|
755
|
+
* transfers,
|
|
756
|
+
* wallet,
|
|
757
|
+
* vault,
|
|
758
|
+
* history,
|
|
759
|
+
* countSentWithoutReceipt: true,
|
|
760
|
+
* }),
|
|
761
|
+
* });
|
|
762
|
+
* ```
|
|
763
|
+
*/
|
|
764
|
+
export declare function pnlCostBasis({ depositedRaw, withdrawnAssetsRaw, hasDeposits, mintsMatchHistory, transfers, }: PnlCostBasisParams): PnlCostBasis;
|
|
518
765
|
/**
|
|
519
766
|
* Calculate lifetime PnL for a user in a specific vault.
|
|
520
767
|
*
|
|
@@ -536,13 +783,39 @@ export declare function transferCostBasis({ transfers, wallet, vault, history, }
|
|
|
536
783
|
* from the price server. There is no stand-in price: when none resolves the
|
|
537
784
|
* getter throws rather than returning USD values it cannot know.
|
|
538
785
|
*
|
|
539
|
-
* Shares
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
*
|
|
545
|
-
*
|
|
786
|
+
* Shares moved by transfer: peer transfers of the share token (see
|
|
787
|
+
* {@link selectPeerTransfers}) are valued at the vault's daily share ratio
|
|
788
|
+
* ({@link transferCostBasis}) and folded in by {@link pnlCostBasis} — received
|
|
789
|
+
* shares add to `totalDeposited` (and are reported again as
|
|
790
|
+
* `receivedByTransfer`), sent shares add to `totalWithdrawn`. This holds
|
|
791
|
+
* alongside indexed deposits, so a wallet that received shares and also
|
|
792
|
+
* deposited is not credited with the received shares as profit. LayerZero
|
|
793
|
+
* OVaults count transfers only when history holds no deposit, because their
|
|
794
|
+
* composer delivers cross-chain deposits by transfer.
|
|
795
|
+
*
|
|
796
|
+
* Gaps in the indexed history: a share mint with no `Deposit` event counts as
|
|
797
|
+
* a deposit of the assets in its `ReserveDeposit` event
|
|
798
|
+
* ({@link selectReserveDeposits}; High Growth ETH emits it for Kelp gain-adapter
|
|
799
|
+
* deposits), and a withdrawal request the vault logged twice counts once
|
|
800
|
+
* ({@link countWithdrawalRequestsOnce}). Transfers fold in for a depositor only
|
|
801
|
+
* once every mint is explained.
|
|
802
|
+
*
|
|
803
|
+
* Tokenized Vault V2 redemptions carry only shares, so a settled one counts at
|
|
804
|
+
* the assets the vault paid, or at the share ratio on its claim date when the
|
|
805
|
+
* subgraph has no processed row for it ({@link settleV2Redemptions}). Only a
|
|
806
|
+
* request not yet claimable is valued at the current share price. When the lag
|
|
807
|
+
* or the ratio history cannot be read, every request is valued at the current
|
|
808
|
+
* share price instead.
|
|
809
|
+
*
|
|
810
|
+
* Request cost: one receipt-transfer subgraph query (and a `symbol()` RPC read)
|
|
811
|
+
* per call, plus one backend timeseries request when peer transfers exist and
|
|
812
|
+
* one `reserveDeposits` subgraph query when a mint has no indexed deposit, and
|
|
813
|
+
* for a Tokenized Vault V2 wallet with redemption requests, a `lagDuration()`
|
|
814
|
+
* read plus one backend timeseries request. A timeseries window with no usable
|
|
815
|
+
* ratio (a closed vault whose history stopped earlier) is read again in full,
|
|
816
|
+
* so the latest earlier day still prices it. For
|
|
817
|
+
* non-LayerZero vaults the transfer query runs in parallel with the history
|
|
818
|
+
* read; for LayerZero vaults it runs only when history holds no deposit.
|
|
546
819
|
*
|
|
547
820
|
* @param vault - Vault contract address
|
|
548
821
|
* @param wallet - User wallet address
|