@augustdigital/sdk 9.9.1 → 9.11.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 +8 -6
- package/lib/adapters/evm/index.d.ts +11 -3
- package/lib/adapters/evm/index.js +11 -3
- package/lib/adapters/solana/confirm.d.ts +88 -0
- package/lib/adapters/solana/confirm.js +291 -0
- package/lib/adapters/solana/index.d.ts +1 -1
- package/lib/adapters/solana/utils.d.ts +2 -1
- package/lib/adapters/solana/utils.js +3 -1
- package/lib/adapters/solana/vault.actions.d.ts +6 -0
- package/lib/adapters/solana/vault.actions.js +6 -0
- package/lib/adapters/stellar/soroban.js +3 -13
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/errors/index.d.ts +29 -1
- package/lib/core/errors/index.js +36 -1
- package/lib/core/helpers/concurrency.d.ts +14 -0
- package/lib/core/helpers/concurrency.js +21 -0
- package/lib/core/helpers/swap-router.d.ts +17 -0
- package/lib/core/helpers/swap-router.js +44 -0
- package/lib/modules/vaults/getters.d.ts +40 -17
- package/lib/modules/vaults/getters.js +42 -22
- package/lib/modules/vaults/write.actions.d.ts +27 -17
- package/lib/modules/vaults/write.actions.js +45 -16
- package/lib/sdk.d.ts +158 -43
- package/lib/types/sub-accounts.d.ts +13 -3
- package/package.json +1 -1
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
17
|
/** Stable error codes attached to SDK errors. */
|
|
18
|
-
export type AugustErrorCode = 'AUTH_MISSING_KEY' | 'AUTH_INVALID_KEY' | 'AUTH_FORBIDDEN' | 'AUTH_UNAUTHORIZED' | 'INVALID_URL' | 'INVALID_INPUT' | 'INVALID_CHAIN' | 'INVALID_ADDRESS' | 'ACCOUNT_NOT_FUNDED' | 'NETWORK_ERROR' | 'TIMEOUT' | 'RATE_LIMITED' | 'SERVER_ERROR' | 'HISTORY_UNAVAILABLE' | 'PRICE_UNAVAILABLE' | 'UNKNOWN';
|
|
18
|
+
export type AugustErrorCode = 'AUTH_MISSING_KEY' | 'AUTH_INVALID_KEY' | 'AUTH_FORBIDDEN' | 'AUTH_UNAUTHORIZED' | 'INVALID_URL' | 'INVALID_INPUT' | 'INVALID_CHAIN' | 'INVALID_ADDRESS' | 'ACCOUNT_NOT_FUNDED' | 'NETWORK_ERROR' | 'TIMEOUT' | 'RATE_LIMITED' | 'SERVER_ERROR' | 'TRANSACTION_UNCONFIRMED' | 'HISTORY_UNAVAILABLE' | 'PRICE_UNAVAILABLE' | 'UNKNOWN';
|
|
19
19
|
/** Options accepted by every SDK error constructor. */
|
|
20
20
|
export interface AugustErrorOptions {
|
|
21
21
|
/** Original error preserved for stack-trace chaining. */
|
|
@@ -145,5 +145,33 @@ export declare class AugustPriceUnavailableError extends AugustSDKError {
|
|
|
145
145
|
*/
|
|
146
146
|
constructor(message: string, options?: AugustErrorOptions);
|
|
147
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* A transaction was sent but its outcome could not be established
|
|
150
|
+
* (`TRANSACTION_UNCONFIRMED`). It may have landed: check {@link signature}
|
|
151
|
+
* before resubmitting, or a deposit or redeem can execute twice.
|
|
152
|
+
* `context.reason` says what was seen (e.g. `expired_not_found`: the blockhash
|
|
153
|
+
* expired and no lookup found it, so it very likely never landed).
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```ts
|
|
157
|
+
* try {
|
|
158
|
+
* await sdk.solana.vaultDeposit(programId, idl, wallet, amount, undefined, vault);
|
|
159
|
+
* } catch (err) {
|
|
160
|
+
* if (err instanceof AugustTransactionError) showPending(err.signature);
|
|
161
|
+
* else throw err;
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare class AugustTransactionError extends AugustSDKError {
|
|
166
|
+
/** Signature of the transaction that was sent. */
|
|
167
|
+
readonly signature: string;
|
|
168
|
+
/**
|
|
169
|
+
* @param message - Human-readable description, naming the signature.
|
|
170
|
+
* @param signature - Signature of the transaction that was sent.
|
|
171
|
+
* @param options - Standard SDK error options.
|
|
172
|
+
*/
|
|
173
|
+
constructor(message: string, signature: string, options?: AugustErrorOptions);
|
|
174
|
+
toJSON(): Record<string, unknown>;
|
|
175
|
+
}
|
|
148
176
|
/** Type guard. Works across realms (e.g. Web Worker / VM contexts). */
|
|
149
177
|
export declare function isAugustSDKError(err: unknown): err is AugustSDKError;
|
package/lib/core/errors/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.AugustPriceUnavailableError = exports.AugustHistoryUnavailableError = exports.AugustServerError = exports.AugustRateLimitError = exports.AugustValidationError = exports.AugustTimeoutError = exports.AugustNetworkError = exports.AugustAuthError = exports.AugustSDKError = void 0;
|
|
19
|
+
exports.AugustTransactionError = exports.AugustPriceUnavailableError = exports.AugustHistoryUnavailableError = exports.AugustServerError = exports.AugustRateLimitError = exports.AugustValidationError = exports.AugustTimeoutError = exports.AugustNetworkError = exports.AugustAuthError = exports.AugustSDKError = void 0;
|
|
20
20
|
exports.isAugustSDKError = isAugustSDKError;
|
|
21
21
|
/** Base class for all SDK errors. */
|
|
22
22
|
class AugustSDKError extends Error {
|
|
@@ -212,6 +212,41 @@ class AugustPriceUnavailableError extends AugustSDKError {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
exports.AugustPriceUnavailableError = AugustPriceUnavailableError;
|
|
215
|
+
/**
|
|
216
|
+
* A transaction was sent but its outcome could not be established
|
|
217
|
+
* (`TRANSACTION_UNCONFIRMED`). It may have landed: check {@link signature}
|
|
218
|
+
* before resubmitting, or a deposit or redeem can execute twice.
|
|
219
|
+
* `context.reason` says what was seen (e.g. `expired_not_found`: the blockhash
|
|
220
|
+
* expired and no lookup found it, so it very likely never landed).
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* try {
|
|
225
|
+
* await sdk.solana.vaultDeposit(programId, idl, wallet, amount, undefined, vault);
|
|
226
|
+
* } catch (err) {
|
|
227
|
+
* if (err instanceof AugustTransactionError) showPending(err.signature);
|
|
228
|
+
* else throw err;
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
class AugustTransactionError extends AugustSDKError {
|
|
233
|
+
/** Signature of the transaction that was sent. */
|
|
234
|
+
signature;
|
|
235
|
+
/**
|
|
236
|
+
* @param message - Human-readable description, naming the signature.
|
|
237
|
+
* @param signature - Signature of the transaction that was sent.
|
|
238
|
+
* @param options - Standard SDK error options.
|
|
239
|
+
*/
|
|
240
|
+
constructor(message, signature, options) {
|
|
241
|
+
super('TRANSACTION_UNCONFIRMED', message, options);
|
|
242
|
+
this.name = 'AugustTransactionError';
|
|
243
|
+
this.signature = signature;
|
|
244
|
+
}
|
|
245
|
+
toJSON() {
|
|
246
|
+
return { ...super.toJSON(), signature: this.signature };
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
exports.AugustTransactionError = AugustTransactionError;
|
|
215
250
|
/** Type guard. Works across realms (e.g. Web Worker / VM contexts). */
|
|
216
251
|
function isAugustSDKError(err) {
|
|
217
252
|
return (err instanceof AugustSDKError ||
|
|
@@ -35,3 +35,17 @@
|
|
|
35
35
|
* @internal
|
|
36
36
|
*/
|
|
37
37
|
export declare function mapWithConcurrency<TIn, TOut>(items: readonly TIn[], limit: number, task: (item: TIn, index: number) => Promise<TOut>): Promise<TOut[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Race a promise against a timeout so a hung call can't block indefinitely. The
|
|
40
|
+
* timer is always cleared, so a fast-resolving promise leaves nothing pending.
|
|
41
|
+
*
|
|
42
|
+
* @param promise - The call to bound. It keeps running after a timeout; only
|
|
43
|
+
* the wait is abandoned.
|
|
44
|
+
* @param ms - Timeout in milliseconds. Values below 0 are treated as 0.
|
|
45
|
+
* @param label - Names the call in the rejection message.
|
|
46
|
+
* @returns What `promise` resolves to.
|
|
47
|
+
* @throws `Error("<label> timed out after <ms>ms")` on timeout, or whatever
|
|
48
|
+
* `promise` rejects with.
|
|
49
|
+
* @internal
|
|
50
|
+
*/
|
|
51
|
+
export declare function withTimeout<T>(promise: Promise<T>, ms: number, label: string): Promise<T>;
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.mapWithConcurrency = mapWithConcurrency;
|
|
13
|
+
exports.withTimeout = withTimeout;
|
|
13
14
|
/**
|
|
14
15
|
* Map over `items` running at most `limit` tasks at a time.
|
|
15
16
|
*
|
|
@@ -55,4 +56,24 @@ async function mapWithConcurrency(items, limit, task) {
|
|
|
55
56
|
await Promise.all(Array.from({ length: width }, worker));
|
|
56
57
|
return results;
|
|
57
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Race a promise against a timeout so a hung call can't block indefinitely. The
|
|
61
|
+
* timer is always cleared, so a fast-resolving promise leaves nothing pending.
|
|
62
|
+
*
|
|
63
|
+
* @param promise - The call to bound. It keeps running after a timeout; only
|
|
64
|
+
* the wait is abandoned.
|
|
65
|
+
* @param ms - Timeout in milliseconds. Values below 0 are treated as 0.
|
|
66
|
+
* @param label - Names the call in the rejection message.
|
|
67
|
+
* @returns What `promise` resolves to.
|
|
68
|
+
* @throws `Error("<label> timed out after <ms>ms")` on timeout, or whatever
|
|
69
|
+
* `promise` rejects with.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
function withTimeout(promise, ms, label) {
|
|
73
|
+
let timer;
|
|
74
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
75
|
+
timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), Math.max(0, ms));
|
|
76
|
+
});
|
|
77
|
+
return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));
|
|
78
|
+
}
|
|
58
79
|
//# sourceMappingURL=concurrency.js.map
|
|
@@ -169,6 +169,23 @@ export declare function readSwapRouterVaultInfo(runner: IContractRunner, chainId
|
|
|
169
169
|
* @internal
|
|
170
170
|
*/
|
|
171
171
|
export declare function readSwapRouterTokenWhitelisted(runner: IContractRunner, chainId: number, token: IAddress): Promise<boolean>;
|
|
172
|
+
/**
|
|
173
|
+
* Read whether a chain's `SwapRouter` is paused (`isPaused()`), cached for 15
|
|
174
|
+
* seconds. Every router entry point (`deposit`, `swapAndDeposit`,
|
|
175
|
+
* `depositNativeToken`) reverts with `ContractIsPaused` while the router is
|
|
176
|
+
* paused, so callers check this before routing a deposit or sending an
|
|
177
|
+
* approval to the router.
|
|
178
|
+
*
|
|
179
|
+
* @param runner - Contract runner (provider or signer) used for the read.
|
|
180
|
+
* @param chainId - EVM chain ID.
|
|
181
|
+
* @returns `true` while the router is paused; `false` when it is not, or on a
|
|
182
|
+
* chain with no SwapRouter (no RPC).
|
|
183
|
+
* @throws When the `isPaused()` read fails. Callers wrap it in
|
|
184
|
+
* {@link AugustSDKError}.
|
|
185
|
+
* @worstCaseRpcCalls 1 — one `isPaused()` call; none on a cache hit.
|
|
186
|
+
* @internal
|
|
187
|
+
*/
|
|
188
|
+
export declare function readSwapRouterPaused(runner: IContractRunner, chainId: number): Promise<boolean>;
|
|
172
189
|
/**
|
|
173
190
|
* Resolve the ERC-20 tokens currently whitelisted for the `SwapRouter` on a
|
|
174
191
|
* chain — the any-token set a UI can offer as swap-and-deposit inputs.
|
|
@@ -10,6 +10,7 @@ exports.getOriginInfo = getOriginInfo;
|
|
|
10
10
|
exports.readOriginInfo = readOriginInfo;
|
|
11
11
|
exports.readSwapRouterVaultInfo = readSwapRouterVaultInfo;
|
|
12
12
|
exports.readSwapRouterTokenWhitelisted = readSwapRouterTokenWhitelisted;
|
|
13
|
+
exports.readSwapRouterPaused = readSwapRouterPaused;
|
|
13
14
|
exports.getSwapRouterWhitelistedTokens = getSwapRouterWhitelistedTokens;
|
|
14
15
|
exports.getSwapRouterEligibleVaults = getSwapRouterEligibleVaults;
|
|
15
16
|
const ethers_1 = require("ethers");
|
|
@@ -332,6 +333,49 @@ async function readSwapRouterTokenWhitelisted(runner, chainId, token) {
|
|
|
332
333
|
cache_1.CACHE.set(cacheKey, whitelisted, { ttl: SWAP_ROUTER_ORIGIN_INFO_TTL_MS });
|
|
333
334
|
return whitelisted;
|
|
334
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Cache TTL for a SwapRouter's pause state (15 seconds). Far shorter than the
|
|
338
|
+
* 5-minute TTL of the other router reads: the owner pauses the router to stop
|
|
339
|
+
* deposits during an incident, so a pause must reach the deposit-route
|
|
340
|
+
* resolver within seconds. Long enough that the resolver and the router write
|
|
341
|
+
* it hands off to share one `isPaused()` read.
|
|
342
|
+
*/
|
|
343
|
+
const SWAP_ROUTER_PAUSED_TTL_MS = 15 * 1000;
|
|
344
|
+
/**
|
|
345
|
+
* Read whether a chain's `SwapRouter` is paused (`isPaused()`), cached for 15
|
|
346
|
+
* seconds. Every router entry point (`deposit`, `swapAndDeposit`,
|
|
347
|
+
* `depositNativeToken`) reverts with `ContractIsPaused` while the router is
|
|
348
|
+
* paused, so callers check this before routing a deposit or sending an
|
|
349
|
+
* approval to the router.
|
|
350
|
+
*
|
|
351
|
+
* @param runner - Contract runner (provider or signer) used for the read.
|
|
352
|
+
* @param chainId - EVM chain ID.
|
|
353
|
+
* @returns `true` while the router is paused; `false` when it is not, or on a
|
|
354
|
+
* chain with no SwapRouter (no RPC).
|
|
355
|
+
* @throws When the `isPaused()` read fails. Callers wrap it in
|
|
356
|
+
* {@link AugustSDKError}.
|
|
357
|
+
* @worstCaseRpcCalls 1 — one `isPaused()` call; none on a cache hit.
|
|
358
|
+
* @internal
|
|
359
|
+
*/
|
|
360
|
+
async function readSwapRouterPaused(runner, chainId) {
|
|
361
|
+
const router = getSwapRouterAddress(chainId);
|
|
362
|
+
if (!router)
|
|
363
|
+
return false;
|
|
364
|
+
const cacheKey = `swap-router-paused-${chainId}-${router.toLowerCase()}`;
|
|
365
|
+
const cached = await (0, cache_1.getSafeCache)(cacheKey);
|
|
366
|
+
if (cached !== null)
|
|
367
|
+
return cached;
|
|
368
|
+
const contract = (0, web3_1.createContract)({
|
|
369
|
+
address: router,
|
|
370
|
+
provider: runner,
|
|
371
|
+
abi: abis_1.ABI_SWAP_ROUTER,
|
|
372
|
+
});
|
|
373
|
+
if (!contract)
|
|
374
|
+
return false;
|
|
375
|
+
const paused = (await contract.isPaused()) === true;
|
|
376
|
+
cache_1.CACHE.set(cacheKey, paused, { ttl: SWAP_ROUTER_PAUSED_TTL_MS });
|
|
377
|
+
return paused;
|
|
378
|
+
}
|
|
335
379
|
/** Cache TTL for a chain's resolved SwapRouter token allowlist (5 minutes). */
|
|
336
380
|
const SWAP_ROUTER_WHITELIST_TTL_MS = 5 * 60 * 1000;
|
|
337
381
|
/**
|
|
@@ -311,6 +311,16 @@ export interface PnlHistoryConsistencyParams {
|
|
|
311
311
|
* (subgraph deposits or LayerZero cross-chain deposits).
|
|
312
312
|
*/
|
|
313
313
|
hasDeposits: boolean;
|
|
314
|
+
/**
|
|
315
|
+
* Whether the indexed deposits explain every share mint to the wallet (see
|
|
316
|
+
* {@link historyCoversMints}). Defaults to `true`.
|
|
317
|
+
*/
|
|
318
|
+
mintsMatchHistory?: boolean;
|
|
319
|
+
/**
|
|
320
|
+
* Shares received by peer transfer, priced in raw base units (asset
|
|
321
|
+
* decimals) by {@link transferCostBasis}. Defaults to zero.
|
|
322
|
+
*/
|
|
323
|
+
receivedByTransferRaw?: bigint;
|
|
314
324
|
/** Total withdrawn, in raw base units (asset decimals). */
|
|
315
325
|
totalWithdrawnRaw: bigint;
|
|
316
326
|
/** Current on-chain position value, in raw base units (asset decimals). */
|
|
@@ -326,9 +336,14 @@ export interface PnlHistoryConsistencyParams {
|
|
|
326
336
|
* position as pure profit — a plausible-looking but wrong number.
|
|
327
337
|
*
|
|
328
338
|
* This guard rejects exactly that state: a non-zero position with no recorded
|
|
329
|
-
* deposits *and* no recorded withdrawals.
|
|
330
|
-
*
|
|
339
|
+
* deposits, no shares received by transfer *and* no recorded withdrawals. It
|
|
340
|
+
* also rejects a non-zero position with no recorded deposits when a share mint
|
|
341
|
+
* to the wallet has no matching deposit (`mintsMatchHistory: false`): the mint
|
|
342
|
+
* proves a deposit the history failed to return, so neither a peer transfer
|
|
343
|
+
* nor a withdrawal makes the cost basis complete. Otherwise, any of the
|
|
344
|
+
* following is treated as consistent and passes:
|
|
331
345
|
* - deposits are present (the normal, computable case);
|
|
346
|
+
* - shares were received by transfer and priced (see {@link transferCostBasis});
|
|
332
347
|
* - withdrawals are present (a fully-exited-then-re-entered position is still
|
|
333
348
|
* computable — the withdrawal records prove history loaded);
|
|
334
349
|
* - the current position is zero (the wallet never interacted or fully exited,
|
|
@@ -338,15 +353,17 @@ export interface PnlHistoryConsistencyParams {
|
|
|
338
353
|
* path with no added latency.
|
|
339
354
|
*
|
|
340
355
|
* Shares received by a direct token transfer (never deposited, never withdrew)
|
|
341
|
-
* reach this guard as
|
|
342
|
-
* with {@link transferCostBasis} first. The guard still throws for
|
|
343
|
-
* wallet when its transfers cannot be read or priced
|
|
356
|
+
* reach this guard as `receivedByTransferRaw`: {@link getVaultUserLifetimePnl}
|
|
357
|
+
* prices them with {@link transferCostBasis} first. The guard still throws for
|
|
358
|
+
* such a wallet when its transfers cannot be read or priced, or when a share
|
|
359
|
+
* mint to it has no indexed deposit.
|
|
344
360
|
*
|
|
345
361
|
* @param params - See {@link PnlHistoryConsistencyParams}.
|
|
346
362
|
* @returns `void` when the history is consistent.
|
|
347
363
|
* @throws {@link AugustHistoryUnavailableError} with code `HISTORY_UNAVAILABLE`
|
|
348
|
-
* and `context: { vault, wallet }` when a non-zero position has
|
|
349
|
-
*
|
|
364
|
+
* and `context: { vault, wallet }` when a non-zero position has no deposits
|
|
365
|
+
* recorded and either a share mint without a matching deposit or neither
|
|
366
|
+
* received shares nor withdrawals. The message carries the
|
|
350
367
|
* `#getVaultUserLifetimePnl::<vault>::<wallet>` prefix so it groups with the
|
|
351
368
|
* other errors leaving the getter.
|
|
352
369
|
* @example
|
|
@@ -355,12 +372,14 @@ export interface PnlHistoryConsistencyParams {
|
|
|
355
372
|
* vault,
|
|
356
373
|
* wallet,
|
|
357
374
|
* hasDeposits: depositsByAsset.size > 0,
|
|
375
|
+
* mintsMatchHistory,
|
|
376
|
+
* receivedByTransferRaw: costBasis.receivedByTransferRaw,
|
|
358
377
|
* totalWithdrawnRaw,
|
|
359
378
|
* currentPositionRaw: currentPositionValue.raw,
|
|
360
379
|
* });
|
|
361
380
|
* ```
|
|
362
381
|
*/
|
|
363
|
-
export declare function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, totalWithdrawnRaw, currentPositionRaw, }: PnlHistoryConsistencyParams): void;
|
|
382
|
+
export declare function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, mintsMatchHistory, receivedByTransferRaw, totalWithdrawnRaw, currentPositionRaw, }: PnlHistoryConsistencyParams): void;
|
|
364
383
|
/** Inputs the lifetime-PnL price guard inspects. */
|
|
365
384
|
export interface PnlTokenPriceParams {
|
|
366
385
|
/** Vault contract address, used for the error message and context. */
|
|
@@ -728,7 +747,9 @@ export interface PnlCostBasis {
|
|
|
728
747
|
*
|
|
729
748
|
* A depositor whose history misses a mint ({@link historyCoversMints}) is the
|
|
730
749
|
* exception: its transfers do not count, so the result matches what the getter
|
|
731
|
-
* returned before transfers counted for depositors.
|
|
750
|
+
* returned before transfers counted for depositors. A wallet with no deposit
|
|
751
|
+
* still gets a basis here when its history misses a mint, but
|
|
752
|
+
* {@link assertPnlHistoryConsistent} rejects it. On a LayerZero OVault the
|
|
732
753
|
* caller leaves the hub composer and share OFT out of the transfers (see
|
|
733
754
|
* {@link selectPeerTransfers}): the composer's deliveries are already counted
|
|
734
755
|
* as LayerZero deposits, and shares bridged to a spoke chain still count in the
|
|
@@ -789,16 +810,18 @@ export declare function pnlCostBasis({ depositedRaw, withdrawnAssetsRaw, hasDepo
|
|
|
789
810
|
* shares add to `totalDeposited` (and are reported again as
|
|
790
811
|
* `receivedByTransfer`), sent shares add to `totalWithdrawn`. This holds
|
|
791
812
|
* 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
|
|
794
|
-
* composer delivers cross-chain deposits by transfer
|
|
813
|
+
* deposited is not credited with the received shares as profit. On LayerZero
|
|
814
|
+
* OVaults, transfers from or to the hub composer and share OFT do not count,
|
|
815
|
+
* because the composer delivers cross-chain deposits by transfer and those
|
|
816
|
+
* are already counted as LayerZero deposits.
|
|
795
817
|
*
|
|
796
818
|
* Gaps in the indexed history: a share mint with no `Deposit` event counts as
|
|
797
819
|
* a deposit of the assets in its `ReserveDeposit` event
|
|
798
820
|
* ({@link selectReserveDeposits}; High Growth ETH emits it for Kelp gain-adapter
|
|
799
821
|
* deposits), and a withdrawal request the vault logged twice counts once
|
|
800
822
|
* ({@link countWithdrawalRequestsOnce}). Transfers fold in for a depositor only
|
|
801
|
-
* once every mint is explained.
|
|
823
|
+
* once every mint is explained. A wallet with no indexed deposit and a mint
|
|
824
|
+
* that no deposit explains throws `HISTORY_UNAVAILABLE`.
|
|
802
825
|
*
|
|
803
826
|
* Tokenized Vault V2 redemptions carry only shares, so a settled one counts at
|
|
804
827
|
* the assets the vault paid, or at the share ratio on its claim date when the
|
|
@@ -813,9 +836,8 @@ export declare function pnlCostBasis({ depositedRaw, withdrawnAssetsRaw, hasDepo
|
|
|
813
836
|
* for a Tokenized Vault V2 wallet with redemption requests, a `lagDuration()`
|
|
814
837
|
* read plus one backend timeseries request. A timeseries window with no usable
|
|
815
838
|
* ratio (a closed vault whose history stopped earlier) is read again in full,
|
|
816
|
-
* so the latest earlier day still prices it.
|
|
817
|
-
*
|
|
818
|
-
* read; for LayerZero vaults it runs only when history holds no deposit.
|
|
839
|
+
* so the latest earlier day still prices it. The transfer query runs for
|
|
840
|
+
* every vault, in parallel with the history read.
|
|
819
841
|
*
|
|
820
842
|
* @param vault - Vault contract address
|
|
821
843
|
* @param wallet - User wallet address
|
|
@@ -823,7 +845,8 @@ export declare function pnlCostBasis({ depositedRaw, withdrawnAssetsRaw, hasDepo
|
|
|
823
845
|
* @returns Lifetime PnL data in both native token and USD
|
|
824
846
|
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
825
847
|
* live position has no indexed deposits, withdrawals or priceable share
|
|
826
|
-
* transfers
|
|
848
|
+
* transfers, or has no indexed deposit while a share mint to the wallet has
|
|
849
|
+
* no matching deposit.
|
|
827
850
|
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
828
851
|
* underlying asset has no USD price, or `asset()` cannot be read.
|
|
829
852
|
*/
|
|
@@ -2273,9 +2273,14 @@ async function getYieldLastRealizedOn({ vault, options, }) {
|
|
|
2273
2273
|
* position as pure profit — a plausible-looking but wrong number.
|
|
2274
2274
|
*
|
|
2275
2275
|
* This guard rejects exactly that state: a non-zero position with no recorded
|
|
2276
|
-
* deposits *and* no recorded withdrawals.
|
|
2277
|
-
*
|
|
2276
|
+
* deposits, no shares received by transfer *and* no recorded withdrawals. It
|
|
2277
|
+
* also rejects a non-zero position with no recorded deposits when a share mint
|
|
2278
|
+
* to the wallet has no matching deposit (`mintsMatchHistory: false`): the mint
|
|
2279
|
+
* proves a deposit the history failed to return, so neither a peer transfer
|
|
2280
|
+
* nor a withdrawal makes the cost basis complete. Otherwise, any of the
|
|
2281
|
+
* following is treated as consistent and passes:
|
|
2278
2282
|
* - deposits are present (the normal, computable case);
|
|
2283
|
+
* - shares were received by transfer and priced (see {@link transferCostBasis});
|
|
2279
2284
|
* - withdrawals are present (a fully-exited-then-re-entered position is still
|
|
2280
2285
|
* computable — the withdrawal records prove history loaded);
|
|
2281
2286
|
* - the current position is zero (the wallet never interacted or fully exited,
|
|
@@ -2285,15 +2290,17 @@ async function getYieldLastRealizedOn({ vault, options, }) {
|
|
|
2285
2290
|
* path with no added latency.
|
|
2286
2291
|
*
|
|
2287
2292
|
* Shares received by a direct token transfer (never deposited, never withdrew)
|
|
2288
|
-
* reach this guard as
|
|
2289
|
-
* with {@link transferCostBasis} first. The guard still throws for
|
|
2290
|
-
* wallet when its transfers cannot be read or priced
|
|
2293
|
+
* reach this guard as `receivedByTransferRaw`: {@link getVaultUserLifetimePnl}
|
|
2294
|
+
* prices them with {@link transferCostBasis} first. The guard still throws for
|
|
2295
|
+
* such a wallet when its transfers cannot be read or priced, or when a share
|
|
2296
|
+
* mint to it has no indexed deposit.
|
|
2291
2297
|
*
|
|
2292
2298
|
* @param params - See {@link PnlHistoryConsistencyParams}.
|
|
2293
2299
|
* @returns `void` when the history is consistent.
|
|
2294
2300
|
* @throws {@link AugustHistoryUnavailableError} with code `HISTORY_UNAVAILABLE`
|
|
2295
|
-
* and `context: { vault, wallet }` when a non-zero position has
|
|
2296
|
-
*
|
|
2301
|
+
* and `context: { vault, wallet }` when a non-zero position has no deposits
|
|
2302
|
+
* recorded and either a share mint without a matching deposit or neither
|
|
2303
|
+
* received shares nor withdrawals. The message carries the
|
|
2297
2304
|
* `#getVaultUserLifetimePnl::<vault>::<wallet>` prefix so it groups with the
|
|
2298
2305
|
* other errors leaving the getter.
|
|
2299
2306
|
* @example
|
|
@@ -2302,16 +2309,23 @@ async function getYieldLastRealizedOn({ vault, options, }) {
|
|
|
2302
2309
|
* vault,
|
|
2303
2310
|
* wallet,
|
|
2304
2311
|
* hasDeposits: depositsByAsset.size > 0,
|
|
2312
|
+
* mintsMatchHistory,
|
|
2313
|
+
* receivedByTransferRaw: costBasis.receivedByTransferRaw,
|
|
2305
2314
|
* totalWithdrawnRaw,
|
|
2306
2315
|
* currentPositionRaw: currentPositionValue.raw,
|
|
2307
2316
|
* });
|
|
2308
2317
|
* ```
|
|
2309
2318
|
*/
|
|
2310
|
-
function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, totalWithdrawnRaw, currentPositionRaw, }) {
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2319
|
+
function assertPnlHistoryConsistent({ vault, wallet, hasDeposits, mintsMatchHistory = true, receivedByTransferRaw = BigInt(0), totalWithdrawnRaw, currentPositionRaw, }) {
|
|
2320
|
+
if (currentPositionRaw <= BigInt(0) || hasDeposits)
|
|
2321
|
+
return;
|
|
2322
|
+
const missingDeposit = !mintsMatchHistory;
|
|
2323
|
+
const noHistory = receivedByTransferRaw === BigInt(0) && totalWithdrawnRaw === BigInt(0);
|
|
2324
|
+
if (missingDeposit || noHistory) {
|
|
2325
|
+
const reason = missingDeposit
|
|
2326
|
+
? 'a share mint has no indexed deposit'
|
|
2327
|
+
: 'no deposits or withdrawals were indexed';
|
|
2328
|
+
throw new errors_1.AugustHistoryUnavailableError(`#getVaultUserLifetimePnl::${vault}::${wallet}:transaction history unavailable — a live position exists but ${reason}, so lifetime PnL cannot be computed without over-reporting the entire position as profit`, { context: { vault, wallet } });
|
|
2315
2329
|
}
|
|
2316
2330
|
}
|
|
2317
2331
|
/**
|
|
@@ -2713,7 +2727,9 @@ function settleV2Redemptions({ history, lagDuration, ratios, now, }) {
|
|
|
2713
2727
|
*
|
|
2714
2728
|
* A depositor whose history misses a mint ({@link historyCoversMints}) is the
|
|
2715
2729
|
* exception: its transfers do not count, so the result matches what the getter
|
|
2716
|
-
* returned before transfers counted for depositors.
|
|
2730
|
+
* returned before transfers counted for depositors. A wallet with no deposit
|
|
2731
|
+
* still gets a basis here when its history misses a mint, but
|
|
2732
|
+
* {@link assertPnlHistoryConsistent} rejects it. On a LayerZero OVault the
|
|
2717
2733
|
* caller leaves the hub composer and share OFT out of the transfers (see
|
|
2718
2734
|
* {@link selectPeerTransfers}): the composer's deliveries are already counted
|
|
2719
2735
|
* as LayerZero deposits, and shares bridged to a spoke chain still count in the
|
|
@@ -2855,16 +2871,18 @@ async function readV2Redemptions(provider, vault, history, headers) {
|
|
|
2855
2871
|
* shares add to `totalDeposited` (and are reported again as
|
|
2856
2872
|
* `receivedByTransfer`), sent shares add to `totalWithdrawn`. This holds
|
|
2857
2873
|
* alongside indexed deposits, so a wallet that received shares and also
|
|
2858
|
-
* deposited is not credited with the received shares as profit. LayerZero
|
|
2859
|
-
* OVaults
|
|
2860
|
-
* composer delivers cross-chain deposits by transfer
|
|
2874
|
+
* deposited is not credited with the received shares as profit. On LayerZero
|
|
2875
|
+
* OVaults, transfers from or to the hub composer and share OFT do not count,
|
|
2876
|
+
* because the composer delivers cross-chain deposits by transfer and those
|
|
2877
|
+
* are already counted as LayerZero deposits.
|
|
2861
2878
|
*
|
|
2862
2879
|
* Gaps in the indexed history: a share mint with no `Deposit` event counts as
|
|
2863
2880
|
* a deposit of the assets in its `ReserveDeposit` event
|
|
2864
2881
|
* ({@link selectReserveDeposits}; High Growth ETH emits it for Kelp gain-adapter
|
|
2865
2882
|
* deposits), and a withdrawal request the vault logged twice counts once
|
|
2866
2883
|
* ({@link countWithdrawalRequestsOnce}). Transfers fold in for a depositor only
|
|
2867
|
-
* once every mint is explained.
|
|
2884
|
+
* once every mint is explained. A wallet with no indexed deposit and a mint
|
|
2885
|
+
* that no deposit explains throws `HISTORY_UNAVAILABLE`.
|
|
2868
2886
|
*
|
|
2869
2887
|
* Tokenized Vault V2 redemptions carry only shares, so a settled one counts at
|
|
2870
2888
|
* the assets the vault paid, or at the share ratio on its claim date when the
|
|
@@ -2879,9 +2897,8 @@ async function readV2Redemptions(provider, vault, history, headers) {
|
|
|
2879
2897
|
* for a Tokenized Vault V2 wallet with redemption requests, a `lagDuration()`
|
|
2880
2898
|
* read plus one backend timeseries request. A timeseries window with no usable
|
|
2881
2899
|
* ratio (a closed vault whose history stopped earlier) is read again in full,
|
|
2882
|
-
* so the latest earlier day still prices it.
|
|
2883
|
-
*
|
|
2884
|
-
* read; for LayerZero vaults it runs only when history holds no deposit.
|
|
2900
|
+
* so the latest earlier day still prices it. The transfer query runs for
|
|
2901
|
+
* every vault, in parallel with the history read.
|
|
2885
2902
|
*
|
|
2886
2903
|
* @param vault - Vault contract address
|
|
2887
2904
|
* @param wallet - User wallet address
|
|
@@ -2889,7 +2906,8 @@ async function readV2Redemptions(provider, vault, history, headers) {
|
|
|
2889
2906
|
* @returns Lifetime PnL data in both native token and USD
|
|
2890
2907
|
* @throws {@link AugustHistoryUnavailableError} (`HISTORY_UNAVAILABLE`) when a
|
|
2891
2908
|
* live position has no indexed deposits, withdrawals or priceable share
|
|
2892
|
-
* transfers
|
|
2909
|
+
* transfers, or has no indexed deposit while a share mint to the wallet has
|
|
2910
|
+
* no matching deposit.
|
|
2893
2911
|
* @throws {@link AugustPriceUnavailableError} (`PRICE_UNAVAILABLE`) when the
|
|
2894
2912
|
* underlying asset has no USD price, or `asset()` cannot be read.
|
|
2895
2913
|
*/
|
|
@@ -3259,7 +3277,9 @@ async function getVaultUserLifetimePnl({ vault, wallet, options, }) {
|
|
|
3259
3277
|
assertPnlHistoryConsistent({
|
|
3260
3278
|
vault,
|
|
3261
3279
|
wallet,
|
|
3262
|
-
hasDeposits
|
|
3280
|
+
hasDeposits,
|
|
3281
|
+
mintsMatchHistory,
|
|
3282
|
+
receivedByTransferRaw: costBasis.receivedByTransferRaw,
|
|
3263
3283
|
totalWithdrawnRaw: costBasis.withdrawnAssetsRaw,
|
|
3264
3284
|
currentPositionRaw: BigInt(currentPositionValue.raw),
|
|
3265
3285
|
});
|
|
@@ -172,8 +172,11 @@ export type ApproveResult =
|
|
|
172
172
|
/**
|
|
173
173
|
* Why {@link getDepositRoute} kept a deposit on the vault's native path.
|
|
174
174
|
* `no-origin-code` is what every SDK without `attribution.originCode` gets.
|
|
175
|
+
* `router-paused` means the SwapRouter's owner paused it: the deposit goes
|
|
176
|
+
* straight to the vault, even under `attribution.strictOrigin`, until the
|
|
177
|
+
* router is unpaused.
|
|
175
178
|
*/
|
|
176
|
-
export type DepositRouteReason = 'no-origin-code' | 'no-router' | 'chain-not-supported' | 'permit' | 'native-token' | 'adapter' | 'vault-not-registered' | 'asset-not-accepted' | 'router-token-not-whitelisted' | 'origin-not-registered';
|
|
179
|
+
export type DepositRouteReason = 'no-origin-code' | 'no-router' | 'chain-not-supported' | 'permit' | 'native-token' | 'adapter' | 'vault-not-registered' | 'asset-not-accepted' | 'router-token-not-whitelisted' | 'router-paused' | 'origin-not-registered';
|
|
177
180
|
/** A deposit's route — the SwapRouter or the vault's native path — and the address to approve. */
|
|
178
181
|
export type IDepositRoute = {
|
|
179
182
|
/**
|
|
@@ -199,23 +202,25 @@ export type IGetDepositRouteOptions = Pick<IContractWriteOptions, 'target' | 'de
|
|
|
199
202
|
* Ethereum mainnet ({@link ORIGIN_ATTRIBUTION_CHAINS}) and has a SwapRouter,
|
|
200
203
|
* the vault is registered on it, the vault accepts the asset directly (its
|
|
201
204
|
* reference asset, or a Tokenized Vault V2 whitelisted asset — deposited
|
|
202
|
-
* as-is, never swapped), the router whitelists the asset, the
|
|
203
|
-
* permit, native-token or adapter deposit, and
|
|
204
|
-
* Otherwise it is `native` with a `reason`.
|
|
205
|
+
* as-is, never swapped), the router whitelists the asset, the router is not
|
|
206
|
+
* paused, the deposit is not a permit, native-token or adapter deposit, and
|
|
207
|
+
* the code is registered. Otherwise it is `native` with a `reason`. A paused
|
|
208
|
+
* router gives `router-paused` even under `attribution.strictOrigin`.
|
|
205
209
|
*
|
|
206
210
|
* @param signer - ethers `Signer` / `Wallet` used for the reads.
|
|
207
211
|
* @param options - {@link IGetDepositRouteOptions}; `depositAsset` defaults
|
|
208
212
|
* to the vault's underlying.
|
|
209
213
|
* @returns {@link IDepositRoute}.
|
|
210
214
|
* @throws AugustValidationError on an invalid `target`, or an unregistered
|
|
211
|
-
* code under `attribution.strictOrigin
|
|
215
|
+
* code under `attribution.strictOrigin` while the router is not paused.
|
|
212
216
|
* @throws AugustSDKError when a backend, vault or router read fails.
|
|
213
|
-
* @worstCaseRpcCalls
|
|
217
|
+
* @worstCaseRpcCalls 8 — the backend vault row, `asset()`, the router's
|
|
214
218
|
* `vaultInfo`, the vault's `assetsWhitelistAddress()` and
|
|
215
219
|
* `getWhitelistedAssets()` (Tokenized Vault V2 non-reference asset only),
|
|
216
|
-
* the router's `whitelistedTokens(asset)`, and
|
|
217
|
-
* router reads and `getWhitelistedAssets()` are cached for 5 minutes
|
|
218
|
-
* router read without a code or off Ethereum
|
|
220
|
+
* the router's `whitelistedTokens(asset)`, `isPaused()` and `origins`. The
|
|
221
|
+
* router reads and `getWhitelistedAssets()` are cached for 5 minutes, except
|
|
222
|
+
* `isPaused()` (15 seconds). No router read without a code or off Ethereum
|
|
223
|
+
* mainnet.
|
|
219
224
|
* @example
|
|
220
225
|
* ```ts
|
|
221
226
|
* const route = await augustSdk.evm.getDepositRoute({ target: vault, depositAsset: usdt });
|
|
@@ -555,7 +560,8 @@ export declare function rwaRedeemAsset(signer: Signer | Wallet, options: IRwaRed
|
|
|
555
560
|
* addresses, empty/oversized swap arrays, or an origin code not registered on
|
|
556
561
|
* the router (a per-call code, or the instance code under
|
|
557
562
|
* `attribution.strictOrigin`), before any approval.
|
|
558
|
-
* @throws {@link AugustSDKError}
|
|
563
|
+
* @throws {@link AugustSDKError} while the SwapRouter is paused (checked before
|
|
564
|
+
* any approval), or on unrecoverable contract or RPC failure.
|
|
559
565
|
*
|
|
560
566
|
* @example
|
|
561
567
|
* ```ts
|
|
@@ -598,7 +604,8 @@ export declare function swapAndDeposit(signer: Signer | Wallet, options: ISwapAn
|
|
|
598
604
|
* per-call code, or the instance code under `attribution.strictOrigin`),
|
|
599
605
|
* before any approval; with code `ACCOUNT_NOT_FUNDED` when the account cannot
|
|
600
606
|
* cover gas.
|
|
601
|
-
* @throws {@link AugustSDKError}
|
|
607
|
+
* @throws {@link AugustSDKError} while the SwapRouter is paused (checked before
|
|
608
|
+
* any approval), or on unrecoverable contract or RPC failure.
|
|
602
609
|
*/
|
|
603
610
|
export declare function depositViaSwapRouter(signer: Signer | Wallet, options: ISwapRouterDirectDepositOptions): Promise<string>;
|
|
604
611
|
/**
|
|
@@ -626,7 +633,8 @@ export declare function depositViaSwapRouter(signer: Signer | Wallet, options: I
|
|
|
626
633
|
* per-call code, or the instance code under `attribution.strictOrigin`),
|
|
627
634
|
* before any approval; with code `ACCOUNT_NOT_FUNDED` when the account cannot
|
|
628
635
|
* cover gas.
|
|
629
|
-
* @throws {@link AugustSDKError}
|
|
636
|
+
* @throws {@link AugustSDKError} while the SwapRouter is paused (checked before
|
|
637
|
+
* any approval), or on unrecoverable contract or RPC failure.
|
|
630
638
|
*/
|
|
631
639
|
export declare function depositNativeViaSwapRouter(signer: Signer | Wallet, options: ISwapRouterNativeDepositOptions): Promise<string>;
|
|
632
640
|
/**
|
|
@@ -724,14 +732,16 @@ export declare function isNativeSwapRouterDepositSupported(chainId: number, vaul
|
|
|
724
732
|
* not registered on the router (a per-call code, or the instance code under
|
|
725
733
|
* `attribution.strictOrigin`), before any approval; with code
|
|
726
734
|
* `ACCOUNT_NOT_FUNDED` when the account cannot cover gas.
|
|
727
|
-
* @throws {@link AugustSDKError}
|
|
728
|
-
*
|
|
735
|
+
* @throws {@link AugustSDKError} while the SwapRouter is paused (checked before
|
|
736
|
+
* any approval), or on unrecoverable contract or RPC failure.
|
|
737
|
+
* @worstCaseRpcCalls 11 on the swap path into a Tokenized Vault V2 —
|
|
729
738
|
* tokenized-vault metadata, reference asset + decimals, deposit-token
|
|
730
739
|
* decimals, the router's `vaultInfo` and `whitelistedTokens`, the vault's
|
|
731
740
|
* `assetsWhitelistAddress()` and `getWhitelistedAssets()`, the quote, the
|
|
732
|
-
* origin code's `origins` (none for the zero
|
|
733
|
-
* read. The router reads and
|
|
734
|
-
* minutes
|
|
741
|
+
* router's `isPaused()`, the origin code's `origins` (none for the zero
|
|
742
|
+
* sentinel), and the allowance read. The router reads and
|
|
743
|
+
* `getWhitelistedAssets()` are cached for 5 minutes, except `isPaused()`
|
|
744
|
+
* (15 seconds).
|
|
735
745
|
* @example
|
|
736
746
|
* ```ts
|
|
737
747
|
* // USDT deposited into a USDC-reference vault → swapped to USDC en route.
|