@augustdigital/sdk 8.6.0 → 8.6.1
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/core/analytics/instrumentation.js +7 -11
- package/lib/core/analytics/sentry.d.ts +1 -1
- package/lib/core/analytics/sentry.js +31 -5
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/helpers/chain-error.d.ts +66 -0
- package/lib/core/helpers/chain-error.js +174 -0
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.js +1 -0
- package/lib/modules/vaults/read.actions.js +26 -12
- package/lib/modules/vaults/write.actions.js +38 -6
- package/lib/sdk.d.ts +70 -1
- package/lib/services/subgraph/vaults.js +10 -3
- package/package.json +1 -1
|
@@ -123,15 +123,11 @@ function trackMethodCall(methodName, metrics, args) {
|
|
|
123
123
|
// Counters: SUM(invocation) → total calls; SUM(error)/SUM(invocation) → error rate.
|
|
124
124
|
sdk.setMeasurement('sdk.method.invocation', 1, 'none');
|
|
125
125
|
sdk.setMeasurement('sdk.method.error', metrics.success ? 0 : 1, 'none');
|
|
126
|
-
//
|
|
126
|
+
// Only sticky-tag the last method name — useful for attributing errors that fire
|
|
127
|
+
// outside an active SDK span. sdk.category and sdk.chain are already recorded as
|
|
128
|
+
// span attributes on each call, so mutating the global scope with them here would
|
|
129
|
+
// just contaminate subsequent unrelated events with stale values.
|
|
127
130
|
sdk.setTag('sdk.last_method', methodName);
|
|
128
|
-
if (metrics.category) {
|
|
129
|
-
sdk.setTag('sdk.category', metrics.category);
|
|
130
|
-
}
|
|
131
|
-
if (metrics.chainId !== undefined) {
|
|
132
|
-
sdk.setTag('sdk.chain', (0, chain_name_1.chainIdToTagValue)(metrics.chainId));
|
|
133
|
-
sdk.setTag('sdk.last_chainId', metrics.chainId.toString());
|
|
134
|
-
}
|
|
135
131
|
}
|
|
136
132
|
catch {
|
|
137
133
|
// Silently fail - analytics should never break SDK
|
|
@@ -223,9 +219,9 @@ function trackSyncMethodCall(methodName, metrics, args) {
|
|
|
223
219
|
...args,
|
|
224
220
|
},
|
|
225
221
|
});
|
|
226
|
-
//
|
|
227
|
-
|
|
228
|
-
|
|
222
|
+
// Measurements omitted: sync methods have no span of their own, so setMeasurement
|
|
223
|
+
// would attach to whatever parent transaction happens to be active on the scope,
|
|
224
|
+
// overwriting its counters. The breadcrumb above already captures success/failure.
|
|
229
225
|
sdk.setTag('sdk.last_sync_method', methodName);
|
|
230
226
|
if (metrics.category) {
|
|
231
227
|
sdk.setTag('sdk.category', metrics.category);
|
|
@@ -6,7 +6,7 @@ import type { IAnalyticsConfig } from './types';
|
|
|
6
6
|
* only refresh user identity and the cached API-key hash.
|
|
7
7
|
*
|
|
8
8
|
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
9
|
-
* override the
|
|
9
|
+
* override the default of `0.1`.
|
|
10
10
|
* @param environment - Current environment (DEV or PROD).
|
|
11
11
|
* @param walletAddress - Optional wallet address for user identification.
|
|
12
12
|
* @param apiKey - Optional API key (hashed for identification).
|
|
@@ -138,7 +138,7 @@ function createSentrySink() {
|
|
|
138
138
|
* only refresh user identity and the cached API-key hash.
|
|
139
139
|
*
|
|
140
140
|
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
141
|
-
* override the
|
|
141
|
+
* override the default of `0.1`.
|
|
142
142
|
* @param environment - Current environment (DEV or PROD).
|
|
143
143
|
* @param walletAddress - Optional wallet address for user identification.
|
|
144
144
|
* @param apiKey - Optional API key (hashed for identification).
|
|
@@ -214,17 +214,36 @@ function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
|
214
214
|
const rawSampleRate = typeof config.tracesSampleRate === 'number' &&
|
|
215
215
|
Number.isFinite(config.tracesSampleRate)
|
|
216
216
|
? config.tracesSampleRate
|
|
217
|
-
: 1.0
|
|
217
|
+
: 0.1; // Phase 2 default — verified partners can opt into 1.0 explicitly
|
|
218
218
|
const tracesSampleRate = Math.max(0, Math.min(1, rawSampleRate));
|
|
219
219
|
sdk.init({
|
|
220
220
|
dsn: constants_1.SENTRY_DSN,
|
|
221
|
-
// TODO(post-verified-partner): ramp default down to ~0.1.
|
|
222
221
|
tracesSampleRate,
|
|
223
222
|
enableTracing: true,
|
|
224
223
|
environment: environment.toLowerCase(),
|
|
225
224
|
release: `august-sdk@${getSDKVersion()}`,
|
|
226
225
|
sendDefaultPii: true,
|
|
227
|
-
|
|
226
|
+
// SDK errors route through Logger.setSentrySink → captureException directly,
|
|
227
|
+
// so captureConsoleIntegration is redundant here. Omitting it also prevents
|
|
228
|
+
// consumer app console.error calls from being billed as SDK error events (the
|
|
229
|
+
// global sdk:'august-digital' tag would otherwise cause them to pass beforeSend).
|
|
230
|
+
integrations: [],
|
|
231
|
+
// Drop classes of event that are never SDK signal, as a backstop to the
|
|
232
|
+
// call-site demotions (see `logChainError` / `isUserRejectionError`).
|
|
233
|
+
// Scope is deliberately narrow: only categories that are noise in EVERY
|
|
234
|
+
// code path. Generic contract reverts (`CALL_EXCEPTION` / "missing revert
|
|
235
|
+
// data") are intentionally NOT listed — a reverted *write* tx is a real
|
|
236
|
+
// error we keep at `error` level, and only read-path reverts are demoted
|
|
237
|
+
// (surgically, at the call site).
|
|
238
|
+
ignoreErrors: [
|
|
239
|
+
// Wallet user-rejections are normal product behaviour, not an SDK fault.
|
|
240
|
+
/user rejected/i,
|
|
241
|
+
/user denied/i,
|
|
242
|
+
'ACTION_REJECTED',
|
|
243
|
+
// Local dev/test node leaking into a prod DSN: :8545 is the canonical
|
|
244
|
+
// Anvil/Hardhat port and is never a production RPC endpoint.
|
|
245
|
+
/ECONNREFUSED .*:8545/,
|
|
246
|
+
],
|
|
228
247
|
beforeSend(event) {
|
|
229
248
|
// Only send events tagged as SDK-related
|
|
230
249
|
if (event.tags?.sdk !== 'august-digital') {
|
|
@@ -233,7 +252,14 @@ function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
|
233
252
|
return event;
|
|
234
253
|
},
|
|
235
254
|
beforeSendTransaction(transaction) {
|
|
236
|
-
//
|
|
255
|
+
// Sub-sample the high-frequency network bookkeeping category (switchNetwork,
|
|
256
|
+
// updateWallet, clearWallet, setSigner) to 10% of whatever tracesSampleRate
|
|
257
|
+
// already passed — these fire on every wallet/chain update and are low signal
|
|
258
|
+
// for the partner-usage dashboard relative to read/write calls.
|
|
259
|
+
if (transaction.tags?.['sdk.category'] === 'network' &&
|
|
260
|
+
Math.random() > 0.1) {
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
237
263
|
return transaction;
|
|
238
264
|
},
|
|
239
265
|
});
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is this error a wallet/user rejection of a transaction or signature request?
|
|
3
|
+
*
|
|
4
|
+
* Detects ethers v6's `ACTION_REJECTED` code, the EIP-1193 `4001`
|
|
5
|
+
* ("User rejected the request") code (top-level or nested), and the common
|
|
6
|
+
* human-readable phrasings as a fallback for providers that omit a code.
|
|
7
|
+
*
|
|
8
|
+
* @param error - The caught value, of unknown type.
|
|
9
|
+
* @returns `true` when the failure was the user declining in their wallet.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* try { await vault.deposit(...); }
|
|
14
|
+
* catch (e) {
|
|
15
|
+
* if (isUserRejectionError(e)) return; // user cancelled — not an error
|
|
16
|
+
* throw e;
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function isUserRejectionError(error: unknown): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Is this error a routine on-chain read revert rather than a real failure?
|
|
23
|
+
*
|
|
24
|
+
* Reading a function a contract doesn't implement, or an address that holds no
|
|
25
|
+
* (or incompatible) bytecode, reverts — a normal outcome when the SDK probes
|
|
26
|
+
* heterogeneous vaults. Matches ethers' `CALL_EXCEPTION` code and the
|
|
27
|
+
* message variants emitted by ethers and viem (`missing revert data`,
|
|
28
|
+
* `execution reverted`, `call revert exception`, and the bare `reverted`
|
|
29
|
+
* phrasing such as `the contract function "totalAssets" reverted`).
|
|
30
|
+
*
|
|
31
|
+
* Scope note: callers apply this on **read** paths only. A reverted *write*
|
|
32
|
+
* (a tx that failed on-chain) is a genuine error and is intentionally not
|
|
33
|
+
* demoted by this predicate's use in `write.actions`.
|
|
34
|
+
*
|
|
35
|
+
* @param error - The caught value, of unknown type.
|
|
36
|
+
* @returns `true` when the failure is an expected/benign contract revert.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* try { return await vaultContract.maxDepositAmount(); }
|
|
41
|
+
* catch (e) {
|
|
42
|
+
* logChainError('maxDeposit', e, isExpectedRevertError(e));
|
|
43
|
+
* throw e;
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function isExpectedRevertError(error: unknown): boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Log a caught chain error at the severity its category warrants, without
|
|
50
|
+
* swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
|
|
51
|
+
* (a Sentry breadcrumb that rides along with the next real issue, not a billed
|
|
52
|
+
* standalone issue); otherwise it is logged at `error` (a Sentry issue). The
|
|
53
|
+
* caller is still responsible for re-throwing — this only routes telemetry.
|
|
54
|
+
*
|
|
55
|
+
* Pass the benign decision explicitly (via {@link isUserRejectionError} or
|
|
56
|
+
* {@link isExpectedRevertError}) so the call site documents *why* the demotion
|
|
57
|
+
* is safe and each path opts into only the category that applies to it.
|
|
58
|
+
*
|
|
59
|
+
* @param tag - Low-cardinality call-site label (e.g. `'deposit'`), used as the
|
|
60
|
+
* Sentry breadcrumb/issue grouping key.
|
|
61
|
+
* @param error - The caught value, of unknown type.
|
|
62
|
+
* @param isBenign - `true` to demote to `warn`; `false` to keep at `error`.
|
|
63
|
+
* @param context - Optional structured context attached to the log entry. It is
|
|
64
|
+
* sanitized by the logger before transport.
|
|
65
|
+
*/
|
|
66
|
+
export declare function logChainError(tag: string, error: unknown, isBenign: boolean, context?: Record<string, unknown>): void;
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isUserRejectionError = isUserRejectionError;
|
|
4
|
+
exports.isExpectedRevertError = isExpectedRevertError;
|
|
5
|
+
exports.logChainError = logChainError;
|
|
6
|
+
const logger_1 = require("../logger");
|
|
7
|
+
/**
|
|
8
|
+
* Classification of caught chain/RPC/wallet errors so the SDK can decide
|
|
9
|
+
* whether a failure is worth a standalone Sentry issue or is routine, expected
|
|
10
|
+
* noise that should ride along as a breadcrumb instead.
|
|
11
|
+
*
|
|
12
|
+
* Why this exists: most of the SDK's read/write paths `catch` and re-throw, and
|
|
13
|
+
* historically logged every caught error at `error` level — which the SDK's
|
|
14
|
+
* Sentry sink turns into a billed issue (see the severity policy on
|
|
15
|
+
* `SDKSentrySink` in `core/logger`). Two large, low-signal categories dominate
|
|
16
|
+
* that volume:
|
|
17
|
+
*
|
|
18
|
+
* 1. **User-rejected transactions** — the user clicked "reject" in their wallet.
|
|
19
|
+
* This is normal product behaviour, not an SDK fault, yet it fires on every
|
|
20
|
+
* cancelled deposit/redeem/approve.
|
|
21
|
+
* 2. **Expected on-chain read reverts** — reading a function a vault doesn't
|
|
22
|
+
* implement, or an address with no/incompatible bytecode, reverts. This is a
|
|
23
|
+
* routine outcome of probing heterogeneous vaults, not a defect.
|
|
24
|
+
*
|
|
25
|
+
* These predicates let call sites demote exactly those cases to `warn` while
|
|
26
|
+
* leaving genuine failures at `error`. They are intentionally dependency-free
|
|
27
|
+
* (no `ethers`/Sentry imports) so they stay cheap and safe in both browser and
|
|
28
|
+
* Node, and classify purely by inspecting the error's `code`/`message` shape.
|
|
29
|
+
*
|
|
30
|
+
* @module
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* Best-effort message extraction from an unknown thrown value. Reads
|
|
34
|
+
* `error.message` for `Error` and error-like objects, passes strings through,
|
|
35
|
+
* and falls back to `String(error)` for everything else. Never throws.
|
|
36
|
+
*
|
|
37
|
+
* @param error - The caught value, of unknown type.
|
|
38
|
+
* @returns The error's message text (never `undefined`).
|
|
39
|
+
*/
|
|
40
|
+
function errorText(error) {
|
|
41
|
+
if (typeof error === 'string')
|
|
42
|
+
return error;
|
|
43
|
+
if (error instanceof Error)
|
|
44
|
+
return error.message;
|
|
45
|
+
if (error && typeof error === 'object') {
|
|
46
|
+
const maybe = error.message;
|
|
47
|
+
if (typeof maybe === 'string')
|
|
48
|
+
return maybe;
|
|
49
|
+
}
|
|
50
|
+
return String(error);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Collect the `code` fields an error-like value may carry. Wallet/provider
|
|
54
|
+
* errors stash their machine-readable code in different places depending on the
|
|
55
|
+
* stack: ethers sets a top-level string `code` (e.g. `'ACTION_REJECTED'`),
|
|
56
|
+
* EIP-1193 providers use a numeric `code` (e.g. `4001`), and some wrap the
|
|
57
|
+
* original under `error`/`info.error`/`cause`. We scan the common locations so
|
|
58
|
+
* callers needn't know which library produced the error.
|
|
59
|
+
*
|
|
60
|
+
* @param error - The caught value, of unknown type.
|
|
61
|
+
* @returns Every string/number `code` found (possibly empty).
|
|
62
|
+
*/
|
|
63
|
+
function errorCodes(error) {
|
|
64
|
+
const codes = [];
|
|
65
|
+
if (error && typeof error === 'object') {
|
|
66
|
+
const e = error;
|
|
67
|
+
const candidates = [
|
|
68
|
+
e.code,
|
|
69
|
+
e.error?.code,
|
|
70
|
+
e.info?.error?.code,
|
|
71
|
+
e.cause?.code,
|
|
72
|
+
];
|
|
73
|
+
for (const c of candidates) {
|
|
74
|
+
if (typeof c === 'string' || typeof c === 'number')
|
|
75
|
+
codes.push(c);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return codes;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Is this error a wallet/user rejection of a transaction or signature request?
|
|
82
|
+
*
|
|
83
|
+
* Detects ethers v6's `ACTION_REJECTED` code, the EIP-1193 `4001`
|
|
84
|
+
* ("User rejected the request") code (top-level or nested), and the common
|
|
85
|
+
* human-readable phrasings as a fallback for providers that omit a code.
|
|
86
|
+
*
|
|
87
|
+
* @param error - The caught value, of unknown type.
|
|
88
|
+
* @returns `true` when the failure was the user declining in their wallet.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* try { await vault.deposit(...); }
|
|
93
|
+
* catch (e) {
|
|
94
|
+
* if (isUserRejectionError(e)) return; // user cancelled — not an error
|
|
95
|
+
* throw e;
|
|
96
|
+
* }
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
function isUserRejectionError(error) {
|
|
100
|
+
const codes = errorCodes(error);
|
|
101
|
+
if (codes.includes('ACTION_REJECTED') || codes.includes(4001))
|
|
102
|
+
return true;
|
|
103
|
+
const msg = errorText(error).toLowerCase();
|
|
104
|
+
return (msg.includes('user rejected') ||
|
|
105
|
+
msg.includes('user denied') ||
|
|
106
|
+
msg.includes('rejected the request') ||
|
|
107
|
+
msg.includes('request rejected'));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Is this error a routine on-chain read revert rather than a real failure?
|
|
111
|
+
*
|
|
112
|
+
* Reading a function a contract doesn't implement, or an address that holds no
|
|
113
|
+
* (or incompatible) bytecode, reverts — a normal outcome when the SDK probes
|
|
114
|
+
* heterogeneous vaults. Matches ethers' `CALL_EXCEPTION` code and the
|
|
115
|
+
* message variants emitted by ethers and viem (`missing revert data`,
|
|
116
|
+
* `execution reverted`, `call revert exception`, and the bare `reverted`
|
|
117
|
+
* phrasing such as `the contract function "totalAssets" reverted`).
|
|
118
|
+
*
|
|
119
|
+
* Scope note: callers apply this on **read** paths only. A reverted *write*
|
|
120
|
+
* (a tx that failed on-chain) is a genuine error and is intentionally not
|
|
121
|
+
* demoted by this predicate's use in `write.actions`.
|
|
122
|
+
*
|
|
123
|
+
* @param error - The caught value, of unknown type.
|
|
124
|
+
* @returns `true` when the failure is an expected/benign contract revert.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* try { return await vaultContract.maxDepositAmount(); }
|
|
129
|
+
* catch (e) {
|
|
130
|
+
* logChainError('maxDeposit', e, isExpectedRevertError(e));
|
|
131
|
+
* throw e;
|
|
132
|
+
* }
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
function isExpectedRevertError(error) {
|
|
136
|
+
const codes = errorCodes(error);
|
|
137
|
+
if (codes.includes('CALL_EXCEPTION'))
|
|
138
|
+
return true;
|
|
139
|
+
const msg = errorText(error).toLowerCase();
|
|
140
|
+
return (msg.includes('call_exception') ||
|
|
141
|
+
msg.includes('missing revert data') ||
|
|
142
|
+
msg.includes('execution reverted') ||
|
|
143
|
+
msg.includes('call revert exception') ||
|
|
144
|
+
msg.includes('reverted'));
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Log a caught chain error at the severity its category warrants, without
|
|
148
|
+
* swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
|
|
149
|
+
* (a Sentry breadcrumb that rides along with the next real issue, not a billed
|
|
150
|
+
* standalone issue); otherwise it is logged at `error` (a Sentry issue). The
|
|
151
|
+
* caller is still responsible for re-throwing — this only routes telemetry.
|
|
152
|
+
*
|
|
153
|
+
* Pass the benign decision explicitly (via {@link isUserRejectionError} or
|
|
154
|
+
* {@link isExpectedRevertError}) so the call site documents *why* the demotion
|
|
155
|
+
* is safe and each path opts into only the category that applies to it.
|
|
156
|
+
*
|
|
157
|
+
* @param tag - Low-cardinality call-site label (e.g. `'deposit'`), used as the
|
|
158
|
+
* Sentry breadcrumb/issue grouping key.
|
|
159
|
+
* @param error - The caught value, of unknown type.
|
|
160
|
+
* @param isBenign - `true` to demote to `warn`; `false` to keep at `error`.
|
|
161
|
+
* @param context - Optional structured context attached to the log entry. It is
|
|
162
|
+
* sanitized by the logger before transport.
|
|
163
|
+
*/
|
|
164
|
+
function logChainError(tag, error, isBenign, context) {
|
|
165
|
+
if (isBenign) {
|
|
166
|
+
// Demote to a breadcrumb: the SDK's Sentry sink forwards `warn` as a
|
|
167
|
+
// breadcrumb, so this no longer creates its own billed issue while still
|
|
168
|
+
// preserving the trail if a genuine error follows.
|
|
169
|
+
logger_1.Logger.log.warn(tag, { message: errorText(error), ...(context ?? {}) });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
logger_1.Logger.log.error(tag, error, context);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=chain-error.js.map
|
package/lib/core/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './constants/vaults';
|
|
|
12
12
|
export * from './constants/swap-router';
|
|
13
13
|
export * from './helpers/web3';
|
|
14
14
|
export * from './helpers/vaults';
|
|
15
|
+
export * from './helpers/chain-error';
|
|
15
16
|
export * from './helpers/core';
|
|
16
17
|
export * from './helpers/adapters';
|
|
17
18
|
export * from './helpers/signer';
|
package/lib/core/index.js
CHANGED
|
@@ -28,6 +28,7 @@ __exportStar(require("./constants/vaults"), exports);
|
|
|
28
28
|
__exportStar(require("./constants/swap-router"), exports);
|
|
29
29
|
__exportStar(require("./helpers/web3"), exports);
|
|
30
30
|
__exportStar(require("./helpers/vaults"), exports);
|
|
31
|
+
__exportStar(require("./helpers/chain-error"), exports);
|
|
31
32
|
__exportStar(require("./helpers/core"), exports);
|
|
32
33
|
__exportStar(require("./helpers/adapters"), exports);
|
|
33
34
|
__exportStar(require("./helpers/signer"), exports);
|
|
@@ -40,7 +40,7 @@ async function fetchInstantRedemptionFee(signer, options) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
catch (e) {
|
|
43
|
-
core_1.
|
|
43
|
+
(0, core_1.logChainError)('failed to fetch instant redeem fee', e, (0, core_1.isExpectedRevertError)(e));
|
|
44
44
|
throw new Error(`Failed to fetch instant redeem fee for ${target}: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -83,7 +83,7 @@ async function vaultAllowance(signer, options) {
|
|
|
83
83
|
return normalized;
|
|
84
84
|
}
|
|
85
85
|
catch (e) {
|
|
86
|
-
core_1.
|
|
86
|
+
(0, core_1.logChainError)('allowance', e, (0, core_1.isExpectedRevertError)(e));
|
|
87
87
|
throw new Error(`Failed to fetch allowance: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -109,7 +109,7 @@ async function sendersWhitelistAddress(signer, options) {
|
|
|
109
109
|
return whitelistAddress;
|
|
110
110
|
}
|
|
111
111
|
catch (e) {
|
|
112
|
-
core_1.
|
|
112
|
+
(0, core_1.logChainError)('sendersWhitelistAddress', e, (0, core_1.isExpectedRevertError)(e));
|
|
113
113
|
throw new Error(`Failed to fetch senders whitelist address: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -138,7 +138,7 @@ async function isWhitelisted(signer, options) {
|
|
|
138
138
|
return result;
|
|
139
139
|
}
|
|
140
140
|
catch (e) {
|
|
141
|
-
core_1.
|
|
141
|
+
(0, core_1.logChainError)('isWhitelisted', e, (0, core_1.isExpectedRevertError)(e));
|
|
142
142
|
throw new Error(`Failed to check whitelist status: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -183,7 +183,7 @@ async function getDeposited(signer, options) {
|
|
|
183
183
|
return normalized;
|
|
184
184
|
}
|
|
185
185
|
catch (e) {
|
|
186
|
-
core_1.
|
|
186
|
+
(0, core_1.logChainError)('getDeposited', e, (0, core_1.isExpectedRevertError)(e));
|
|
187
187
|
throw new Error(`Failed to fetch deposited amount: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
@@ -232,7 +232,7 @@ async function getRemainingAllocations(signer, options) {
|
|
|
232
232
|
return normalized;
|
|
233
233
|
}
|
|
234
234
|
catch (e) {
|
|
235
|
-
core_1.
|
|
235
|
+
(0, core_1.logChainError)('getRemainingAllocations', e, (0, core_1.isExpectedRevertError)(e));
|
|
236
236
|
throw new Error(`Failed to fetch remaining allocations: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
@@ -263,7 +263,11 @@ async function previewRwaRedemption(signer, options) {
|
|
|
263
263
|
return normalized;
|
|
264
264
|
}
|
|
265
265
|
catch (e) {
|
|
266
|
-
core_1.
|
|
266
|
+
(0, core_1.logChainError)('previewRwaRedemption', e, (0, core_1.isExpectedRevertError)(e), {
|
|
267
|
+
target,
|
|
268
|
+
asset,
|
|
269
|
+
amount,
|
|
270
|
+
});
|
|
267
271
|
throw new Error(`Preview RWA redemption failed: ${e instanceof Error ? e.message : 'Unknown error'}`);
|
|
268
272
|
}
|
|
269
273
|
}
|
|
@@ -354,7 +358,10 @@ async function previewDeposit(signer, options) {
|
|
|
354
358
|
if (e instanceof core_1.AugustValidationError || e instanceof core_1.AugustSDKError) {
|
|
355
359
|
throw e;
|
|
356
360
|
}
|
|
357
|
-
core_1.
|
|
361
|
+
(0, core_1.logChainError)('previewDeposit', e, (0, core_1.isExpectedRevertError)(e), {
|
|
362
|
+
vault,
|
|
363
|
+
amount: amount.toString(),
|
|
364
|
+
});
|
|
358
365
|
throw new core_1.AugustSDKError('UNKNOWN', `previewDeposit failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { vault, amount: amount.toString() } });
|
|
359
366
|
}
|
|
360
367
|
}
|
|
@@ -410,7 +417,7 @@ async function previewRedeem(signer, options) {
|
|
|
410
417
|
if (e instanceof core_1.AugustValidationError || e instanceof core_1.AugustSDKError) {
|
|
411
418
|
throw e;
|
|
412
419
|
}
|
|
413
|
-
core_1.
|
|
420
|
+
(0, core_1.logChainError)('previewRedeem', e, (0, core_1.isExpectedRevertError)(e), {
|
|
414
421
|
vault,
|
|
415
422
|
shares: shares.toString(),
|
|
416
423
|
});
|
|
@@ -480,7 +487,11 @@ async function allowance(signer, options) {
|
|
|
480
487
|
if (e instanceof core_1.AugustValidationError || e instanceof core_1.AugustSDKError) {
|
|
481
488
|
throw e;
|
|
482
489
|
}
|
|
483
|
-
core_1.
|
|
490
|
+
(0, core_1.logChainError)('allowance', e, (0, core_1.isExpectedRevertError)(e), {
|
|
491
|
+
vault,
|
|
492
|
+
owner,
|
|
493
|
+
asset,
|
|
494
|
+
});
|
|
484
495
|
throw new core_1.AugustSDKError('UNKNOWN', `allowance failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { vault, owner, asset } });
|
|
485
496
|
}
|
|
486
497
|
}
|
|
@@ -521,7 +532,7 @@ async function balanceOf(signer, options) {
|
|
|
521
532
|
if (e instanceof core_1.AugustValidationError || e instanceof core_1.AugustSDKError) {
|
|
522
533
|
throw e;
|
|
523
534
|
}
|
|
524
|
-
core_1.
|
|
535
|
+
(0, core_1.logChainError)('balanceOf', e, (0, core_1.isExpectedRevertError)(e), { asset, owner });
|
|
525
536
|
throw new core_1.AugustSDKError('UNKNOWN', `balanceOf failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { asset, owner } });
|
|
526
537
|
}
|
|
527
538
|
}
|
|
@@ -575,7 +586,10 @@ async function maxDeposit(signer, options) {
|
|
|
575
586
|
if (e instanceof core_1.AugustValidationError || e instanceof core_1.AugustSDKError) {
|
|
576
587
|
throw e;
|
|
577
588
|
}
|
|
578
|
-
core_1.
|
|
589
|
+
(0, core_1.logChainError)('maxDeposit', e, (0, core_1.isExpectedRevertError)(e), {
|
|
590
|
+
vault,
|
|
591
|
+
receiver,
|
|
592
|
+
});
|
|
579
593
|
throw new core_1.AugustSDKError('UNKNOWN', `maxDeposit failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { vault, receiver } });
|
|
580
594
|
}
|
|
581
595
|
}
|
|
@@ -297,7 +297,12 @@ async function approveCore(signer, options) {
|
|
|
297
297
|
catch (e) {
|
|
298
298
|
if (e instanceof core_1.AugustSDKError)
|
|
299
299
|
throw e;
|
|
300
|
-
|
|
300
|
+
// A user declining the approval in their wallet is product behaviour, not
|
|
301
|
+
// an SDK fault — demote it to a breadcrumb so it doesn't bill as an issue.
|
|
302
|
+
(0, core_1.logChainError)('vaultApprove', e, (0, core_1.isUserRejectionError)(e), {
|
|
303
|
+
target,
|
|
304
|
+
amount,
|
|
305
|
+
});
|
|
301
306
|
throw new core_1.AugustSDKError('UNKNOWN', `Approval failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, amount } });
|
|
302
307
|
}
|
|
303
308
|
}
|
|
@@ -632,7 +637,12 @@ async function vaultDeposit(signer, options) {
|
|
|
632
637
|
}
|
|
633
638
|
if (e instanceof core_1.AugustSDKError)
|
|
634
639
|
throw e;
|
|
635
|
-
|
|
640
|
+
// User-cancelled deposits are normal; only genuine failures stay at error.
|
|
641
|
+
(0, core_1.logChainError)('deposit', e, (0, core_1.isUserRejectionError)(e), {
|
|
642
|
+
target,
|
|
643
|
+
amount,
|
|
644
|
+
depositAsset,
|
|
645
|
+
});
|
|
636
646
|
throw new core_1.AugustSDKError('UNKNOWN', `Deposit failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, amount, depositAsset } });
|
|
637
647
|
}
|
|
638
648
|
}
|
|
@@ -780,7 +790,11 @@ async function vaultRequestRedeem(signer, options) {
|
|
|
780
790
|
}
|
|
781
791
|
if (e instanceof core_1.AugustSDKError)
|
|
782
792
|
throw e;
|
|
783
|
-
|
|
793
|
+
// User-cancelled redeem requests are normal; only genuine failures stay at error.
|
|
794
|
+
(0, core_1.logChainError)('requestRedeem', e, (0, core_1.isUserRejectionError)(e), {
|
|
795
|
+
target,
|
|
796
|
+
amount,
|
|
797
|
+
});
|
|
784
798
|
throw new core_1.AugustSDKError('UNKNOWN', `Request redeem failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, amount } });
|
|
785
799
|
}
|
|
786
800
|
}
|
|
@@ -823,7 +837,14 @@ async function vaultRedeem(signer, options) {
|
|
|
823
837
|
}
|
|
824
838
|
if (e instanceof core_1.AugustSDKError)
|
|
825
839
|
throw e;
|
|
826
|
-
|
|
840
|
+
// User-cancelled redeems are normal; only genuine failures stay at error.
|
|
841
|
+
(0, core_1.logChainError)('redeem', e, (0, core_1.isUserRejectionError)(e), {
|
|
842
|
+
target,
|
|
843
|
+
year,
|
|
844
|
+
month,
|
|
845
|
+
day,
|
|
846
|
+
receiverIndex,
|
|
847
|
+
});
|
|
827
848
|
throw new core_1.AugustSDKError('UNKNOWN', `Redeem failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, year, month, day, receiverIndex } });
|
|
828
849
|
}
|
|
829
850
|
}
|
|
@@ -914,7 +935,12 @@ async function depositNative(signer, options) {
|
|
|
914
935
|
}
|
|
915
936
|
if (e instanceof core_1.AugustSDKError)
|
|
916
937
|
throw e;
|
|
917
|
-
|
|
938
|
+
// User-cancelled native deposits are normal; only genuine failures stay at error.
|
|
939
|
+
(0, core_1.logChainError)('depositNative', e, (0, core_1.isUserRejectionError)(e), {
|
|
940
|
+
wrapperAddress,
|
|
941
|
+
receiver,
|
|
942
|
+
amount,
|
|
943
|
+
});
|
|
918
944
|
throw new core_1.AugustSDKError('UNKNOWN', `Deposit native failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { wrapperAddress, receiver, amount } });
|
|
919
945
|
}
|
|
920
946
|
}
|
|
@@ -988,7 +1014,13 @@ async function rwaRedeemAsset(signer, options) {
|
|
|
988
1014
|
}
|
|
989
1015
|
if (e instanceof core_1.AugustSDKError)
|
|
990
1016
|
throw e;
|
|
991
|
-
|
|
1017
|
+
// User-cancelled RWA redeems are normal; only genuine failures stay at error.
|
|
1018
|
+
(0, core_1.logChainError)('rwaRedeemAsset', e, (0, core_1.isUserRejectionError)(e), {
|
|
1019
|
+
target,
|
|
1020
|
+
asset,
|
|
1021
|
+
amount,
|
|
1022
|
+
minOut,
|
|
1023
|
+
});
|
|
992
1024
|
throw new core_1.AugustSDKError('UNKNOWN', `RWA redeem failed: ${e instanceof Error ? e.message : 'Unknown error'}`, { cause: e, context: { target, asset, amount, minOut } });
|
|
993
1025
|
}
|
|
994
1026
|
}
|
package/lib/sdk.d.ts
CHANGED
|
@@ -19011,7 +19011,7 @@ export declare function depositNative(signer: Signer | Wallet, options: INativeD
|
|
|
19011
19011
|
* only refresh user identity and the cached API-key hash.
|
|
19012
19012
|
*
|
|
19013
19013
|
* @param config - Analytics configuration. Pass `tracesSampleRate` to
|
|
19014
|
-
* override the
|
|
19014
|
+
* override the default of `0.1`.
|
|
19015
19015
|
* @param environment - Current environment (DEV or PROD).
|
|
19016
19016
|
* @param walletAddress - Optional wallet address for user identification.
|
|
19017
19017
|
* @param apiKey - Optional API key (hashed for identification).
|
|
@@ -19405,6 +19405,34 @@ export declare function depositNative(signer: Signer | Wallet, options: INativeD
|
|
|
19405
19405
|
|
|
19406
19406
|
export declare function isEarlierThanNow(startTime: Date): boolean;
|
|
19407
19407
|
|
|
19408
|
+
/**
|
|
19409
|
+
* Is this error a routine on-chain read revert rather than a real failure?
|
|
19410
|
+
*
|
|
19411
|
+
* Reading a function a contract doesn't implement, or an address that holds no
|
|
19412
|
+
* (or incompatible) bytecode, reverts — a normal outcome when the SDK probes
|
|
19413
|
+
* heterogeneous vaults. Matches ethers' `CALL_EXCEPTION` code and the
|
|
19414
|
+
* message variants emitted by ethers and viem (`missing revert data`,
|
|
19415
|
+
* `execution reverted`, `call revert exception`, and the bare `reverted`
|
|
19416
|
+
* phrasing such as `the contract function "totalAssets" reverted`).
|
|
19417
|
+
*
|
|
19418
|
+
* Scope note: callers apply this on **read** paths only. A reverted *write*
|
|
19419
|
+
* (a tx that failed on-chain) is a genuine error and is intentionally not
|
|
19420
|
+
* demoted by this predicate's use in `write.actions`.
|
|
19421
|
+
*
|
|
19422
|
+
* @param error - The caught value, of unknown type.
|
|
19423
|
+
* @returns `true` when the failure is an expected/benign contract revert.
|
|
19424
|
+
*
|
|
19425
|
+
* @example
|
|
19426
|
+
* ```ts
|
|
19427
|
+
* try { return await vaultContract.maxDepositAmount(); }
|
|
19428
|
+
* catch (e) {
|
|
19429
|
+
* logChainError('maxDeposit', e, isExpectedRevertError(e));
|
|
19430
|
+
* throw e;
|
|
19431
|
+
* }
|
|
19432
|
+
* ```
|
|
19433
|
+
*/
|
|
19434
|
+
export declare function isExpectedRevertError(error: unknown): boolean;
|
|
19435
|
+
|
|
19408
19436
|
/**
|
|
19409
19437
|
* Whether a vault's receipt token is hub-only (no cross-chain withdraw).
|
|
19410
19438
|
* The deposit UI must not offer a spoke share destination for these vaults.
|
|
@@ -19676,6 +19704,27 @@ export declare function depositNative(signer: Signer | Wallet, options: INativeD
|
|
|
19676
19704
|
ownerAddr: IAddress;
|
|
19677
19705
|
}
|
|
19678
19706
|
|
|
19707
|
+
/**
|
|
19708
|
+
* Is this error a wallet/user rejection of a transaction or signature request?
|
|
19709
|
+
*
|
|
19710
|
+
* Detects ethers v6's `ACTION_REJECTED` code, the EIP-1193 `4001`
|
|
19711
|
+
* ("User rejected the request") code (top-level or nested), and the common
|
|
19712
|
+
* human-readable phrasings as a fallback for providers that omit a code.
|
|
19713
|
+
*
|
|
19714
|
+
* @param error - The caught value, of unknown type.
|
|
19715
|
+
* @returns `true` when the failure was the user declining in their wallet.
|
|
19716
|
+
*
|
|
19717
|
+
* @example
|
|
19718
|
+
* ```ts
|
|
19719
|
+
* try { await vault.deposit(...); }
|
|
19720
|
+
* catch (e) {
|
|
19721
|
+
* if (isUserRejectionError(e)) return; // user cancelled — not an error
|
|
19722
|
+
* throw e;
|
|
19723
|
+
* }
|
|
19724
|
+
* ```
|
|
19725
|
+
*/
|
|
19726
|
+
export declare function isUserRejectionError(error: unknown): boolean;
|
|
19727
|
+
|
|
19679
19728
|
/**
|
|
19680
19729
|
* Signer Compatibility Helpers
|
|
19681
19730
|
*
|
|
@@ -21072,6 +21121,26 @@ export declare function depositNative(signer: Signer | Wallet, options: INativeD
|
|
|
21072
21121
|
|
|
21073
21122
|
export declare function loanStateToReadable(loanState: number | bigint): "PREAPPROVED" | "FUNDING_REQUIRED" | "FUNDED" | "ACTIVE" | "CANCELLED" | "MATURED" | "CLOSED";
|
|
21074
21123
|
|
|
21124
|
+
/**
|
|
21125
|
+
* Log a caught chain error at the severity its category warrants, without
|
|
21126
|
+
* swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
|
|
21127
|
+
* (a Sentry breadcrumb that rides along with the next real issue, not a billed
|
|
21128
|
+
* standalone issue); otherwise it is logged at `error` (a Sentry issue). The
|
|
21129
|
+
* caller is still responsible for re-throwing — this only routes telemetry.
|
|
21130
|
+
*
|
|
21131
|
+
* Pass the benign decision explicitly (via {@link isUserRejectionError} or
|
|
21132
|
+
* {@link isExpectedRevertError}) so the call site documents *why* the demotion
|
|
21133
|
+
* is safe and each path opts into only the category that applies to it.
|
|
21134
|
+
*
|
|
21135
|
+
* @param tag - Low-cardinality call-site label (e.g. `'deposit'`), used as the
|
|
21136
|
+
* Sentry breadcrumb/issue grouping key.
|
|
21137
|
+
* @param error - The caught value, of unknown type.
|
|
21138
|
+
* @param isBenign - `true` to demote to `warn`; `false` to keep at `error`.
|
|
21139
|
+
* @param context - Optional structured context attached to the log entry. It is
|
|
21140
|
+
* sanitized by the logger before transport.
|
|
21141
|
+
*/
|
|
21142
|
+
export declare function logChainError(tag: string, error: unknown, isBenign: boolean, context?: Record<string, unknown>): void;
|
|
21143
|
+
|
|
21075
21144
|
export declare const Logger: {
|
|
21076
21145
|
setLogger: typeof setLogger;
|
|
21077
21146
|
setStructuredLogger: typeof setStructuredLogger;
|
|
@@ -183,12 +183,19 @@ const NEW_DEPOSIT_QUERY_PROPS = `
|
|
|
183
183
|
senderAddr
|
|
184
184
|
receiverAddr
|
|
185
185
|
`;
|
|
186
|
+
// The `block_number: blockNumber` alias on these new-schema withdrawal prop
|
|
187
|
+
// sets is required, not cosmetic: getWithdrawalRequestsWithStatus prunes by
|
|
188
|
+
// `Number(req.block_number) >= blockCutoff` (per the ISubgraphBase contract).
|
|
189
|
+
// New-schema subgraphs expose the field as `blockNumber`, so without the alias
|
|
190
|
+
// it reads undefined → Number(undefined) is NaN → every request is pruned
|
|
191
|
+
// (AUGUST-6514). Only the REQUESTED set is read today; the processed/withdrawals
|
|
192
|
+
// aliases below are kept for the same type contract so the NaN prune can't recur.
|
|
186
193
|
const NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS = `
|
|
187
194
|
id
|
|
188
195
|
shares
|
|
189
196
|
receiverAddr
|
|
190
197
|
holderAddr
|
|
191
|
-
blockNumber
|
|
198
|
+
block_number: blockNumber
|
|
192
199
|
transactionHash_: transactionHash
|
|
193
200
|
timestamp_: blockTimestamp
|
|
194
201
|
`;
|
|
@@ -196,7 +203,7 @@ const NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS = `
|
|
|
196
203
|
id
|
|
197
204
|
receiverAddr
|
|
198
205
|
assetsAmount
|
|
199
|
-
blockNumber
|
|
206
|
+
block_number: blockNumber
|
|
200
207
|
transactionHash_: transactionHash
|
|
201
208
|
timestamp_: blockTimestamp
|
|
202
209
|
`;
|
|
@@ -204,7 +211,7 @@ const NEW_WITHDRAWALS_QUERY_PROPS = `
|
|
|
204
211
|
id
|
|
205
212
|
transactionHash_: transactionHash
|
|
206
213
|
timestamp_: blockTimestamp
|
|
207
|
-
blockNumber
|
|
214
|
+
block_number: blockNumber
|
|
208
215
|
assets
|
|
209
216
|
receiver
|
|
210
217
|
sender
|