@augustdigital/sdk 8.19.0 → 8.20.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/adapters/sui/constants.d.ts +1 -1
- package/lib/adapters/sui/constants.js +6 -1
- package/lib/core/analytics/sentry.d.ts +7 -0
- package/lib/core/analytics/sentry.js +182 -1
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/constants/core.js +42 -15
- package/lib/core/constants/web3.d.ts +17 -0
- package/lib/core/constants/web3.js +22 -1
- package/lib/core/helpers/chain-support.d.ts +80 -0
- package/lib/core/helpers/chain-support.js +115 -0
- package/lib/core/helpers/web3.d.ts +20 -1
- package/lib/core/helpers/web3.js +51 -5
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.js +1 -0
- package/lib/modules/vaults/getters.js +109 -21
- package/lib/modules/vaults/main.d.ts +24 -3
- package/lib/modules/vaults/main.js +32 -31
- package/lib/sdk.d.ts +11299 -11155
- package/package.json +1 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ALLOWED_SUI_VAULT_ADDRESSES = exports.EMBER_DEFAULTS = exports.EMBER_ENDPOINTS = exports.EMBER_API_BASE_URL = exports.SUI_CHAIN_ID = void 0;
|
|
4
|
-
|
|
4
|
+
// Canonical definition lives in `core/constants/web3.ts` so `core/` can
|
|
5
|
+
// recognise the Sui chain ID without importing the adapter layer. Re-exported
|
|
6
|
+
// here to keep `adapters/sui/constants` import sites (and the published API)
|
|
7
|
+
// unchanged.
|
|
8
|
+
var web3_1 = require("../../core/constants/web3");
|
|
9
|
+
Object.defineProperty(exports, "SUI_CHAIN_ID", { enumerable: true, get: function () { return web3_1.SUI_CHAIN_ID; } });
|
|
5
10
|
exports.EMBER_API_BASE_URL = 'https://vaults.api.sui-prod.bluefin.io/api/v1/vaults';
|
|
6
11
|
exports.EMBER_ENDPOINTS = {
|
|
7
12
|
VAULTS: '/',
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import type * as Sentry from '@sentry/browser';
|
|
2
2
|
import type { IEnv } from '../../types';
|
|
3
3
|
import type { IAnalyticsConfig } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Clear the error dedupe bookkeeping. Test-only — the rate limiter is process
|
|
6
|
+
* lifetime state and would otherwise leak between test cases.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare function resetErrorDedupe(): void;
|
|
4
11
|
/**
|
|
5
12
|
* Initialize Sentry with SDK-specific configuration. Idempotent: re-calls
|
|
6
13
|
* only refresh user identity and the cached API-key hash.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resetErrorDedupe = resetErrorDedupe;
|
|
3
4
|
exports.initializeSentry = initializeSentry;
|
|
4
5
|
exports.updateUser = updateUser;
|
|
5
6
|
exports.clearUser = clearUser;
|
|
@@ -78,6 +79,164 @@ function safeSetUser(user) {
|
|
|
78
79
|
// Silently fail - analytics should never break SDK
|
|
79
80
|
}
|
|
80
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Chains whose errors are dropped before reaching Sentry.
|
|
84
|
+
*
|
|
85
|
+
* Mezo is muted by request: its public dRPC endpoint is unreliable enough that
|
|
86
|
+
* its failures dominated the error stream without ever describing an SDK
|
|
87
|
+
* defect. This is a deliberate blind spot — Mezo bugs (bad vault data, reverts,
|
|
88
|
+
* decode failures) are silenced along with the transport noise. Remove the
|
|
89
|
+
* entry to restore reporting; nothing else needs to change.
|
|
90
|
+
*
|
|
91
|
+
* Keyed by both the `chainIdToTagValue` slug and the numeric chain ID, because
|
|
92
|
+
* the two arrive on different events.
|
|
93
|
+
*/
|
|
94
|
+
const MUTED_CHAIN_SLUGS = new Set(['mezo']);
|
|
95
|
+
/** Numeric chain IDs matching {@link MUTED_CHAIN_SLUGS}. */
|
|
96
|
+
const MUTED_CHAIN_IDS = new Set(['31612']);
|
|
97
|
+
/**
|
|
98
|
+
* Substrings that identify an event as Mezo-related regardless of tags.
|
|
99
|
+
*
|
|
100
|
+
* Tag-based matching alone is not enough: `sdk.chain` / `sdk.last_chainId`
|
|
101
|
+
* record the last *instrumented method's* chain, not the chain of the RPC that
|
|
102
|
+
* actually failed — the production Mezo batch-rejection events are tagged
|
|
103
|
+
* `sdk.chain: ethereum` while carrying `"requestUrl": "https://mezo.drpc.org"`
|
|
104
|
+
* in the message. Matching the message body catches those.
|
|
105
|
+
*/
|
|
106
|
+
const MUTED_CHAIN_MESSAGE_PATTERNS = [/mezo/i];
|
|
107
|
+
/**
|
|
108
|
+
* Whether an event belongs to a muted chain and must not be sent.
|
|
109
|
+
*
|
|
110
|
+
* Checks, in order: the chain tags, then the event message and every exception
|
|
111
|
+
* value/type in the chain (an RPC failure's identifying detail often lives in a
|
|
112
|
+
* wrapped inner error rather than the top-level message).
|
|
113
|
+
*
|
|
114
|
+
* @param event - The Sentry event about to be sent.
|
|
115
|
+
* @returns `true` when the event should be dropped.
|
|
116
|
+
*/
|
|
117
|
+
function isMutedChainEvent(event) {
|
|
118
|
+
const chainTag = event.tags?.['sdk.chain'];
|
|
119
|
+
if (typeof chainTag === 'string' && MUTED_CHAIN_SLUGS.has(chainTag)) {
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
122
|
+
const chainIdTag = event.tags?.['sdk.last_chainId'];
|
|
123
|
+
if (typeof chainIdTag === 'string' && MUTED_CHAIN_IDS.has(chainIdTag)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
const haystacks = [];
|
|
127
|
+
if (typeof event.message === 'string')
|
|
128
|
+
haystacks.push(event.message);
|
|
129
|
+
for (const exception of event.exception?.values ?? []) {
|
|
130
|
+
if (typeof exception.value === 'string')
|
|
131
|
+
haystacks.push(exception.value);
|
|
132
|
+
if (typeof exception.type === 'string')
|
|
133
|
+
haystacks.push(exception.type);
|
|
134
|
+
}
|
|
135
|
+
return haystacks.some((text) => MUTED_CHAIN_MESSAGE_PATTERNS.some((pattern) => pattern.test(text)));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Rolling window, in milliseconds, over which identical errors are counted.
|
|
139
|
+
*/
|
|
140
|
+
const ERROR_DEDUPE_WINDOW_MS = 60_000;
|
|
141
|
+
/**
|
|
142
|
+
* Maximum captures of one error signature per {@link ERROR_DEDUPE_WINDOW_MS}.
|
|
143
|
+
* Chosen so a genuine, ongoing failure is still visible (and its rate
|
|
144
|
+
* observable via `sdk.suppressed_since_last`) while a hot loop hammering a
|
|
145
|
+
* broken RPC or a 404-per-borrower fan-out cannot bill thousands of identical
|
|
146
|
+
* events. Beyond this, further captures in the window are dropped.
|
|
147
|
+
*/
|
|
148
|
+
const ERROR_DEDUPE_MAX_PER_WINDOW = 3;
|
|
149
|
+
/** Hard cap on tracked signatures, so the map cannot grow without bound. */
|
|
150
|
+
const ERROR_DEDUPE_MAX_KEYS = 500;
|
|
151
|
+
/**
|
|
152
|
+
* Per-signature capture bookkeeping for the dedupe window.
|
|
153
|
+
*
|
|
154
|
+
* Deliberately process-global, matching the Sentry client it feeds: the client
|
|
155
|
+
* is a singleton, so every `AugustSDK` instance in the process shares one
|
|
156
|
+
* event stream and one quota. The signature intentionally omits partner/app
|
|
157
|
+
* identity — a host serving several partners reports an identical upstream
|
|
158
|
+
* failure ≤{@link ERROR_DEDUPE_MAX_PER_WINDOW} times per window in aggregate,
|
|
159
|
+
* not per partner, because the failure is one event regardless of how many
|
|
160
|
+
* tenants observed it. Per-tenant attribution comes from the `partner.id` tag
|
|
161
|
+
* on the events that are sent, and `sdk.suppressed_since_last` preserves the
|
|
162
|
+
* true rate. `resetAnalytics()` clears this map for the whole process.
|
|
163
|
+
*/
|
|
164
|
+
const errorDedupeState = new Map();
|
|
165
|
+
/**
|
|
166
|
+
* Build a low-cardinality signature for an error.
|
|
167
|
+
*
|
|
168
|
+
* Message tails carry the variable parts (addresses, block ranges, response
|
|
169
|
+
* bodies), so only the leading 120 characters participate — enough to separate
|
|
170
|
+
* distinct failure modes without splitting one failure mode into thousands of
|
|
171
|
+
* unique keys.
|
|
172
|
+
*
|
|
173
|
+
* @param error - The normalized error being captured.
|
|
174
|
+
* @param origin - The `sdk.origin` call-site tag, when present.
|
|
175
|
+
* @returns A stable key identifying this class of failure.
|
|
176
|
+
*/
|
|
177
|
+
function errorSignature(error, origin) {
|
|
178
|
+
const tag = typeof origin === 'string' ? origin : '';
|
|
179
|
+
return `${tag}|${error.name}|${(error.message || '').slice(0, 120)}`;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Decide whether an error should be sent to Sentry, applying a per-signature
|
|
183
|
+
* rolling rate limit.
|
|
184
|
+
*
|
|
185
|
+
* Why this exists: the SDK is called from server-rendered pages that fan out
|
|
186
|
+
* per vault and per borrower, so a single upstream condition (a 502 from the
|
|
187
|
+
* backend, an RPC rejecting a batch) reproduces on every iteration of every
|
|
188
|
+
* request. Those are the same event, and paying Sentry per copy buys no extra
|
|
189
|
+
* signal.
|
|
190
|
+
*
|
|
191
|
+
* Side effect: mutates {@link errorDedupeState}.
|
|
192
|
+
*
|
|
193
|
+
* @param error - The normalized error about to be captured.
|
|
194
|
+
* @param origin - The `sdk.origin` call-site tag, when present.
|
|
195
|
+
* @returns `send: false` to drop the event. When `send: true`, `suppressed` is
|
|
196
|
+
* the number of copies dropped since the last event that was sent, and is
|
|
197
|
+
* attached to the outgoing event so the true rate stays recoverable.
|
|
198
|
+
*/
|
|
199
|
+
function admitError(error, origin) {
|
|
200
|
+
const key = errorSignature(error, origin);
|
|
201
|
+
const now = Date.now();
|
|
202
|
+
const entry = errorDedupeState.get(key);
|
|
203
|
+
// Touch the key on every access so iteration order is true
|
|
204
|
+
// least-recently-used, not first-inserted: a Map's `set` on an existing key
|
|
205
|
+
// does NOT reorder it, so without the delete a signature that keeps
|
|
206
|
+
// recurring would hold its original position and be evicted ahead of a stale
|
|
207
|
+
// one-shot signature registered after it — silently handing the hot
|
|
208
|
+
// signature a fresh allowance every time it churned out of the map.
|
|
209
|
+
errorDedupeState.delete(key);
|
|
210
|
+
if (!entry || now - entry.windowStart >= ERROR_DEDUPE_WINDOW_MS) {
|
|
211
|
+
// Bound the map: drop the least-recently-used signature before inserting.
|
|
212
|
+
if (errorDedupeState.size >= ERROR_DEDUPE_MAX_KEYS) {
|
|
213
|
+
const oldest = errorDedupeState.keys().next();
|
|
214
|
+
if (!oldest.done)
|
|
215
|
+
errorDedupeState.delete(oldest.value);
|
|
216
|
+
}
|
|
217
|
+
const suppressed = entry?.suppressed ?? 0;
|
|
218
|
+
errorDedupeState.set(key, { windowStart: now, captured: 1, suppressed: 0 });
|
|
219
|
+
return { send: true, suppressed };
|
|
220
|
+
}
|
|
221
|
+
errorDedupeState.set(key, entry);
|
|
222
|
+
if (entry.captured < ERROR_DEDUPE_MAX_PER_WINDOW) {
|
|
223
|
+
// `suppressed` can only be non-zero once the allowance is exhausted, so
|
|
224
|
+
// inside the allowance there is never a carried count to report.
|
|
225
|
+
entry.captured += 1;
|
|
226
|
+
return { send: true, suppressed: 0 };
|
|
227
|
+
}
|
|
228
|
+
entry.suppressed += 1;
|
|
229
|
+
return { send: false, suppressed: entry.suppressed };
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Clear the error dedupe bookkeeping. Test-only — the rate limiter is process
|
|
233
|
+
* lifetime state and would otherwise leak between test cases.
|
|
234
|
+
*
|
|
235
|
+
* @internal
|
|
236
|
+
*/
|
|
237
|
+
function resetErrorDedupe() {
|
|
238
|
+
errorDedupeState.clear();
|
|
239
|
+
}
|
|
81
240
|
/**
|
|
82
241
|
* Build the SDK's internal Sentry sink — the bridge that forwards
|
|
83
242
|
* `Logger.log.*` output to the resolved Sentry SDK. Errors are captured as
|
|
@@ -95,6 +254,12 @@ function createSentrySink() {
|
|
|
95
254
|
const sdk = (0, sentry_runtime_1.getSentrySDK)();
|
|
96
255
|
if (!sdk)
|
|
97
256
|
return;
|
|
257
|
+
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
258
|
+
// Rate-limit identical failures before touching Sentry at all — the
|
|
259
|
+
// scope work and the event payload are both wasted if it is dropped.
|
|
260
|
+
const admission = admitError(normalized, context?.tag);
|
|
261
|
+
if (!admission.send)
|
|
262
|
+
return;
|
|
98
263
|
sdk.withScope((scope) => {
|
|
99
264
|
// `beforeSend` drops any event not tagged as ours; the tag is global
|
|
100
265
|
// already, but set it on the scope defensively in case a future
|
|
@@ -115,7 +280,10 @@ function createSentrySink() {
|
|
|
115
280
|
}
|
|
116
281
|
}
|
|
117
282
|
}
|
|
118
|
-
|
|
283
|
+
// Preserve the true failure rate even though copies were dropped.
|
|
284
|
+
if (admission.suppressed > 0) {
|
|
285
|
+
scope.setExtra('sdk.suppressed_since_last', admission.suppressed);
|
|
286
|
+
}
|
|
119
287
|
sdk.captureException(normalized);
|
|
120
288
|
});
|
|
121
289
|
}
|
|
@@ -243,12 +411,22 @@ function initializeSentry(config, environment, walletAddress, apiKey, appName) {
|
|
|
243
411
|
// Local dev/test node leaking into a prod DSN: :8545 is the canonical
|
|
244
412
|
// Anvil/Hardhat port and is never a production RPC endpoint.
|
|
245
413
|
/ECONNREFUSED .*:8545/,
|
|
414
|
+
// AugustHistoryUnavailableError is a designed, documented outcome:
|
|
415
|
+
// the getter refuses to return a fabricated number when the indexer
|
|
416
|
+
// has no deposit/withdrawal history. It is thrown to the caller, who
|
|
417
|
+
// renders "temporarily unavailable" — the SDK is behaving correctly,
|
|
418
|
+
// so it is not an SDK issue. Indexer health is monitored separately.
|
|
419
|
+
/transaction history unavailable/i,
|
|
246
420
|
],
|
|
247
421
|
beforeSend(event) {
|
|
248
422
|
// Only send events tagged as SDK-related
|
|
249
423
|
if (event.tags?.sdk !== 'august-digital') {
|
|
250
424
|
return null;
|
|
251
425
|
}
|
|
426
|
+
// Muted chains (see MUTED_CHAIN_SLUGS) are dropped wholesale.
|
|
427
|
+
if (isMutedChainEvent(event)) {
|
|
428
|
+
return null;
|
|
429
|
+
}
|
|
252
430
|
return event;
|
|
253
431
|
},
|
|
254
432
|
beforeSendTransaction(transaction) {
|
|
@@ -383,6 +561,9 @@ function resetAnalytics() {
|
|
|
383
561
|
cachedApiKey = undefined;
|
|
384
562
|
logger_1.Logger.setSentrySink(null);
|
|
385
563
|
(0, sentry_runtime_1.resetSentryRuntime)();
|
|
564
|
+
// The error rate limiter is process-lifetime state; a reset analytics layer
|
|
565
|
+
// must not inherit a half-full dedupe window from the previous one.
|
|
566
|
+
resetErrorDedupe();
|
|
386
567
|
}
|
|
387
568
|
/**
|
|
388
569
|
* Capture an exception into Sentry with SDK-specific context. Use from
|
|
@@ -5,6 +5,33 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.DEFAULT_FETCH_OPTIONS = exports.WEBSERVER_ENDPOINTS = exports.WEBSERVER_URL = exports.PRICE_SERVER_URL = exports.REQUEST_TIMEOUT_MS = void 0;
|
|
7
7
|
const ethers_1 = require("ethers");
|
|
8
|
+
/**
|
|
9
|
+
* Build the path segment for a subaccount identifier.
|
|
10
|
+
*
|
|
11
|
+
* Why this exists: subaccounts are not EVM-only. Vault operators and loan
|
|
12
|
+
* borrowers can be Solana base58 keys or Stellar `G…`/`C…` addresses, and the
|
|
13
|
+
* backend keys those records by their native string form. Calling ethers'
|
|
14
|
+
* `getAddress()` on them throws `INVALID_ARGUMENT` before the request is ever
|
|
15
|
+
* made — which is how a Solana borrower turned every
|
|
16
|
+
* `getVaultAllocations` call for a mixed-chain vault into a
|
|
17
|
+
* `TypeError: invalid address` (see `getVaultAllocations:cefi` /
|
|
18
|
+
* `:otc` in Sentry).
|
|
19
|
+
*
|
|
20
|
+
* EVM addresses are still checksummed, because the backend expects the
|
|
21
|
+
* checksummed form for those and case-normalising avoids cache misses.
|
|
22
|
+
* Everything else is passed through URL-encoded so a malformed value can never
|
|
23
|
+
* inject extra path segments.
|
|
24
|
+
*
|
|
25
|
+
* @param subaccount - Subaccount identifier: EVM hex address, Solana base58
|
|
26
|
+
* public key, or Stellar strkey. Not validated beyond the EVM branch — the
|
|
27
|
+
* backend is the authority on whether a non-EVM identifier exists.
|
|
28
|
+
* @returns A single URL path segment safe to interpolate into an endpoint.
|
|
29
|
+
*/
|
|
30
|
+
function subaccountSegment(subaccount) {
|
|
31
|
+
return (0, ethers_1.isAddress)(subaccount)
|
|
32
|
+
? (0, ethers_1.getAddress)(subaccount)
|
|
33
|
+
: encodeURIComponent(subaccount);
|
|
34
|
+
}
|
|
8
35
|
/**
|
|
9
36
|
* Request timeout in milliseconds.
|
|
10
37
|
* Set to 90 seconds to accommodate slow API responses.
|
|
@@ -34,22 +61,22 @@ exports.WEBSERVER_ENDPOINTS = {
|
|
|
34
61
|
},
|
|
35
62
|
subaccount: {
|
|
36
63
|
list: (offset = 0, limit = 100) => `/subaccount?offset=${offset}&limit=${limit}`,
|
|
37
|
-
rewards: (subaccount) => `/subaccount/${(
|
|
38
|
-
tokens: (subaccount) => `/subaccount/${(
|
|
64
|
+
rewards: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/rewards`,
|
|
65
|
+
tokens: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/tokens`,
|
|
39
66
|
twap: {
|
|
40
|
-
create: (subaccount) => `/subaccount/${(
|
|
41
|
-
stop: (subaccount, id) => `/subaccount/${(
|
|
42
|
-
fills: (subaccount, id) => `/subaccount/${(
|
|
67
|
+
create: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/twap`,
|
|
68
|
+
stop: (subaccount, id) => `/subaccount/${subaccountSegment(subaccount)}/twap/${id}/stop`,
|
|
69
|
+
fills: (subaccount, id) => `/subaccount/${subaccountSegment(subaccount)}/twap/${id}/fills`,
|
|
43
70
|
},
|
|
44
|
-
debank: (subaccount) => `/subaccount/${(
|
|
45
|
-
health_factor: (subaccount) => `/subaccount/${(
|
|
46
|
-
summary: (subaccount) => `/subaccount/${(
|
|
47
|
-
batch: (subaccount) => `/subaccount/${(
|
|
48
|
-
loans: (subaccount, side = 'BOTH', active = true) => `/subaccount/${(
|
|
49
|
-
cefi: (subaccount) => `/subaccount/${(
|
|
50
|
-
otc_positions: (subaccount) => `/subaccount/${(
|
|
71
|
+
debank: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/debank`,
|
|
72
|
+
health_factor: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/health_factor`,
|
|
73
|
+
summary: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/summary`,
|
|
74
|
+
batch: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/tx_batcher_integrations`,
|
|
75
|
+
loans: (subaccount, side = 'BOTH', active = true) => `/subaccount/${subaccountSegment(subaccount)}/loans?side=${side}&active=${active}`,
|
|
76
|
+
cefi: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/cefi_position`,
|
|
77
|
+
otc_positions: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}/otc_positions`,
|
|
51
78
|
loanByAddress: (loanAddress, chainId) => `/subaccount/loans/${encodeURIComponent(loanAddress)}?chain_id=${chainId}`,
|
|
52
|
-
_: (subaccount) => `/subaccount/${(
|
|
79
|
+
_: (subaccount) => `/subaccount/${subaccountSegment(subaccount)}`,
|
|
53
80
|
},
|
|
54
81
|
transactions: {
|
|
55
82
|
v2: (subaccount, startTime, endTime) => {
|
|
@@ -108,7 +135,7 @@ exports.WEBSERVER_ENDPOINTS = {
|
|
|
108
135
|
},
|
|
109
136
|
prices: (symbol) => `/prices/${symbol}`,
|
|
110
137
|
metrics: {
|
|
111
|
-
pnl: (subaccount, startTime, endTime) => `/metrics/pnl?subaccount_address=${(
|
|
138
|
+
pnl: (subaccount, startTime, endTime) => `/metrics/pnl?subaccount_address=${subaccountSegment(subaccount)}${startTime && endTime ? `&start=${startTime}&end=${endTime}` : ''}`,
|
|
112
139
|
vaultPerformanceFees: (params) => {
|
|
113
140
|
const q = new URLSearchParams({
|
|
114
141
|
vault_address: params.vaultAddress,
|
|
@@ -126,7 +153,7 @@ exports.WEBSERVER_ENDPOINTS = {
|
|
|
126
153
|
public: {
|
|
127
154
|
integrations: {
|
|
128
155
|
morpho: {
|
|
129
|
-
apy: (subaccount, vaultAddress) => `/integrations/morpho/apy?subaccount_address=${(
|
|
156
|
+
apy: (subaccount, vaultAddress) => `/integrations/morpho/apy?subaccount_address=${subaccountSegment(subaccount)}&vault_address=${(0, ethers_1.getAddress)(vaultAddress)}`,
|
|
130
157
|
},
|
|
131
158
|
},
|
|
132
159
|
tokenizedVault: {
|
|
@@ -11,6 +11,23 @@ export declare const SPECIAL_CHAINS: {
|
|
|
11
11
|
explorer: string;
|
|
12
12
|
};
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Chain ID used to address Sui vaults.
|
|
16
|
+
*
|
|
17
|
+
* Unlike Solana (`-1`) and Stellar (`-3`), Sui does not use a synthetic
|
|
18
|
+
* negative ID — `101` is the SLIP-44-derived value the Sui adapter has always
|
|
19
|
+
* used. It lives here rather than in `adapters/sui/constants.ts` so that
|
|
20
|
+
* `core/` can recognise it without importing the adapter layer (which would
|
|
21
|
+
* create a `core → adapters` back-edge); the adapter re-exports it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const SUI_CHAIN_ID = 101;
|
|
24
|
+
/**
|
|
25
|
+
* Chain IDs the SDK understands that are **not** served by an EVM JSON-RPC
|
|
26
|
+
* provider. Callers may legitimately pass these to vault methods without a
|
|
27
|
+
* matching entry in the `providers` map — the request routes through the
|
|
28
|
+
* Solana / Stellar / Sui adapter instead.
|
|
29
|
+
*/
|
|
30
|
+
export declare const NON_EVM_CHAIN_IDS: ReadonlySet<number>;
|
|
14
31
|
export declare const NATIVE_ADDRESS = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
15
32
|
/**
|
|
16
33
|
* Decimal precision of the native gas token on every EVM chain this SDK
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FALLBACK_RPC_URLS = exports.FALLBACK_CHAINID = exports.FALLBACK_DECIMALS = exports.MULTICALL3_VERIFIED_CHAINS = exports.MULTICALL3_ADDRESS = exports.AVAILABLE_CHAINS = exports.NETWORKS = exports.ORACLE_CONTRACTS = exports.MIN_ABIS = exports.EVM_NATIVE_DECIMALS = exports.NATIVE_ADDRESS = exports.SPECIAL_CHAINS = void 0;
|
|
3
|
+
exports.FALLBACK_RPC_URLS = exports.FALLBACK_CHAINID = exports.FALLBACK_DECIMALS = exports.MULTICALL3_VERIFIED_CHAINS = exports.MULTICALL3_ADDRESS = exports.AVAILABLE_CHAINS = exports.NETWORKS = exports.ORACLE_CONTRACTS = exports.MIN_ABIS = exports.EVM_NATIVE_DECIMALS = exports.NATIVE_ADDRESS = exports.NON_EVM_CHAIN_IDS = exports.SUI_CHAIN_ID = exports.SPECIAL_CHAINS = void 0;
|
|
4
4
|
// Special Chains
|
|
5
5
|
exports.SPECIAL_CHAINS = {
|
|
6
6
|
solana: {
|
|
@@ -14,6 +14,27 @@ exports.SPECIAL_CHAINS = {
|
|
|
14
14
|
explorer: 'https://stellar.expert',
|
|
15
15
|
},
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Chain ID used to address Sui vaults.
|
|
19
|
+
*
|
|
20
|
+
* Unlike Solana (`-1`) and Stellar (`-3`), Sui does not use a synthetic
|
|
21
|
+
* negative ID — `101` is the SLIP-44-derived value the Sui adapter has always
|
|
22
|
+
* used. It lives here rather than in `adapters/sui/constants.ts` so that
|
|
23
|
+
* `core/` can recognise it without importing the adapter layer (which would
|
|
24
|
+
* create a `core → adapters` back-edge); the adapter re-exports it.
|
|
25
|
+
*/
|
|
26
|
+
exports.SUI_CHAIN_ID = 101;
|
|
27
|
+
/**
|
|
28
|
+
* Chain IDs the SDK understands that are **not** served by an EVM JSON-RPC
|
|
29
|
+
* provider. Callers may legitimately pass these to vault methods without a
|
|
30
|
+
* matching entry in the `providers` map — the request routes through the
|
|
31
|
+
* Solana / Stellar / Sui adapter instead.
|
|
32
|
+
*/
|
|
33
|
+
exports.NON_EVM_CHAIN_IDS = new Set([
|
|
34
|
+
exports.SPECIAL_CHAINS.solana.chainId,
|
|
35
|
+
exports.SPECIAL_CHAINS.stellar.chainId,
|
|
36
|
+
exports.SUI_CHAIN_ID,
|
|
37
|
+
]);
|
|
17
38
|
// General
|
|
18
39
|
exports.NATIVE_ADDRESS = '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE';
|
|
19
40
|
/**
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chain-ID validation for public SDK entry points.
|
|
3
|
+
*
|
|
4
|
+
* Two distinct failure modes are covered here, and they are deliberately kept
|
|
5
|
+
* separate because they have different remediations:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Unknown chain ID** — the caller passed an ID the SDK has no concept of
|
|
8
|
+
* (a typo, a stale constant, an off-by-one on a non-EVM synthetic ID). No
|
|
9
|
+
* configuration can make this work; the call site is wrong.
|
|
10
|
+
* 2. **Known EVM chain, no RPC configured** — the ID is valid but the SDK was
|
|
11
|
+
* constructed without a provider for it. Remediated by passing an RPC URL.
|
|
12
|
+
*
|
|
13
|
+
* Both used to be logged-and-ignored, letting execution continue with an
|
|
14
|
+
* `undefined` RPC URL. That produced a cascade of misleading downstream
|
|
15
|
+
* failures (`connect ECONNREFUSED 127.0.0.1:8545` from ethers' localhost
|
|
16
|
+
* default, `missing revert data` from `decimals()` reads issued against the
|
|
17
|
+
* wrong chain, and `TypeError: Cannot read properties of undefined`). Failing
|
|
18
|
+
* fast at the boundary replaces that cascade with one actionable error.
|
|
19
|
+
*
|
|
20
|
+
* @module core/helpers/chain-support
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* Whether `chainId` is an EVM chain the SDK knows about (i.e. has an entry in
|
|
24
|
+
* {@link NETWORKS}).
|
|
25
|
+
*
|
|
26
|
+
* @param chainId - Numeric chain ID to test.
|
|
27
|
+
* @returns `true` for supported EVM chains, `false` for non-EVM synthetic IDs
|
|
28
|
+
* (Solana, Stellar, Sui) and for anything unrecognised.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isEvmChainId(chainId: number): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Whether `chainId` is recognised by the SDK at all — either a supported EVM
|
|
33
|
+
* chain or one of the non-EVM chain IDs in {@link NON_EVM_CHAIN_IDS}.
|
|
34
|
+
*
|
|
35
|
+
* @param chainId - Numeric chain ID to test.
|
|
36
|
+
* @returns `true` when the ID maps to a chain the SDK can route to.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isKnownChainId(chainId: number): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Throw when `chainId` is not a chain the SDK recognises.
|
|
41
|
+
*
|
|
42
|
+
* Called at public vault entry points so an unroutable ID surfaces as one
|
|
43
|
+
* typed error instead of an opaque downstream RPC failure.
|
|
44
|
+
*
|
|
45
|
+
* @param chainId - Chain ID supplied by the caller. `undefined` is a no-op —
|
|
46
|
+
* omitting the chain is valid and falls back to the SDK's active network.
|
|
47
|
+
* @param providers - The SDK's configured `chainId → RPC URL` map. A chain
|
|
48
|
+
* with a caller-configured provider is routable even if it is missing from
|
|
49
|
+
* {@link NETWORKS} (the SDK ships fallback RPCs/oracles for some EVM chains
|
|
50
|
+
* ahead of adding them to `NETWORKS`), so it is accepted here too.
|
|
51
|
+
* @param method - Public method name, used to make the message actionable.
|
|
52
|
+
* @throws {@link AugustValidationError} with code `INVALID_CHAIN` when the ID
|
|
53
|
+
* is not in {@link NETWORKS} or {@link NON_EVM_CHAIN_IDS}, and has no
|
|
54
|
+
* caller-configured provider.
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* assertKnownChainId(-2, undefined, 'getVault');
|
|
58
|
+
* // AugustValidationError: getVault: unknown chainId -2.
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function assertKnownChainId(chainId: number | undefined, providers: Partial<Record<number, string>> | undefined, method: string): void;
|
|
62
|
+
/**
|
|
63
|
+
* Throw when a known EVM `chainId` has no RPC URL configured on the SDK.
|
|
64
|
+
*
|
|
65
|
+
* Non-EVM chain IDs are exempt: Solana, Stellar and Sui vaults route through
|
|
66
|
+
* their adapters and never read from the `providers` map, so a missing entry
|
|
67
|
+
* is expected rather than a misconfiguration.
|
|
68
|
+
*
|
|
69
|
+
* @param chainId - Chain ID supplied by the caller. `undefined` is a no-op.
|
|
70
|
+
* @param providers - The SDK's configured `chainId → RPC URL` map.
|
|
71
|
+
* @param method - Public method name, used to make the message actionable.
|
|
72
|
+
* @throws {@link AugustValidationError} with code `INVALID_CHAIN` when
|
|
73
|
+
* `chainId` is an EVM chain with no configured provider.
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* assertEvmProviderConfigured(143, {}, 'getVault');
|
|
77
|
+
* // AugustValidationError: getVault: no RPC URL configured for chainId 143 (Monad).
|
|
78
|
+
* ```
|
|
79
|
+
*/
|
|
80
|
+
export declare function assertEvmProviderConfigured(chainId: number | undefined, providers: Partial<Record<number, string>> | undefined, method: string): void;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Chain-ID validation for public SDK entry points.
|
|
4
|
+
*
|
|
5
|
+
* Two distinct failure modes are covered here, and they are deliberately kept
|
|
6
|
+
* separate because they have different remediations:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Unknown chain ID** — the caller passed an ID the SDK has no concept of
|
|
9
|
+
* (a typo, a stale constant, an off-by-one on a non-EVM synthetic ID). No
|
|
10
|
+
* configuration can make this work; the call site is wrong.
|
|
11
|
+
* 2. **Known EVM chain, no RPC configured** — the ID is valid but the SDK was
|
|
12
|
+
* constructed without a provider for it. Remediated by passing an RPC URL.
|
|
13
|
+
*
|
|
14
|
+
* Both used to be logged-and-ignored, letting execution continue with an
|
|
15
|
+
* `undefined` RPC URL. That produced a cascade of misleading downstream
|
|
16
|
+
* failures (`connect ECONNREFUSED 127.0.0.1:8545` from ethers' localhost
|
|
17
|
+
* default, `missing revert data` from `decimals()` reads issued against the
|
|
18
|
+
* wrong chain, and `TypeError: Cannot read properties of undefined`). Failing
|
|
19
|
+
* fast at the boundary replaces that cascade with one actionable error.
|
|
20
|
+
*
|
|
21
|
+
* @module core/helpers/chain-support
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.isEvmChainId = isEvmChainId;
|
|
25
|
+
exports.isKnownChainId = isKnownChainId;
|
|
26
|
+
exports.assertKnownChainId = assertKnownChainId;
|
|
27
|
+
exports.assertEvmProviderConfigured = assertEvmProviderConfigured;
|
|
28
|
+
const web3_1 = require("../constants/web3");
|
|
29
|
+
const errors_1 = require("../errors");
|
|
30
|
+
/**
|
|
31
|
+
* Whether `chainId` is an EVM chain the SDK knows about (i.e. has an entry in
|
|
32
|
+
* {@link NETWORKS}).
|
|
33
|
+
*
|
|
34
|
+
* @param chainId - Numeric chain ID to test.
|
|
35
|
+
* @returns `true` for supported EVM chains, `false` for non-EVM synthetic IDs
|
|
36
|
+
* (Solana, Stellar, Sui) and for anything unrecognised.
|
|
37
|
+
*/
|
|
38
|
+
function isEvmChainId(chainId) {
|
|
39
|
+
return Object.hasOwn(web3_1.NETWORKS, chainId);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether `chainId` is recognised by the SDK at all — either a supported EVM
|
|
43
|
+
* chain or one of the non-EVM chain IDs in {@link NON_EVM_CHAIN_IDS}.
|
|
44
|
+
*
|
|
45
|
+
* @param chainId - Numeric chain ID to test.
|
|
46
|
+
* @returns `true` when the ID maps to a chain the SDK can route to.
|
|
47
|
+
*/
|
|
48
|
+
function isKnownChainId(chainId) {
|
|
49
|
+
return isEvmChainId(chainId) || web3_1.NON_EVM_CHAIN_IDS.has(chainId);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Throw when `chainId` is not a chain the SDK recognises.
|
|
53
|
+
*
|
|
54
|
+
* Called at public vault entry points so an unroutable ID surfaces as one
|
|
55
|
+
* typed error instead of an opaque downstream RPC failure.
|
|
56
|
+
*
|
|
57
|
+
* @param chainId - Chain ID supplied by the caller. `undefined` is a no-op —
|
|
58
|
+
* omitting the chain is valid and falls back to the SDK's active network.
|
|
59
|
+
* @param providers - The SDK's configured `chainId → RPC URL` map. A chain
|
|
60
|
+
* with a caller-configured provider is routable even if it is missing from
|
|
61
|
+
* {@link NETWORKS} (the SDK ships fallback RPCs/oracles for some EVM chains
|
|
62
|
+
* ahead of adding them to `NETWORKS`), so it is accepted here too.
|
|
63
|
+
* @param method - Public method name, used to make the message actionable.
|
|
64
|
+
* @throws {@link AugustValidationError} with code `INVALID_CHAIN` when the ID
|
|
65
|
+
* is not in {@link NETWORKS} or {@link NON_EVM_CHAIN_IDS}, and has no
|
|
66
|
+
* caller-configured provider.
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* assertKnownChainId(-2, undefined, 'getVault');
|
|
70
|
+
* // AugustValidationError: getVault: unknown chainId -2.
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
function assertKnownChainId(chainId, providers, method) {
|
|
74
|
+
if (typeof chainId === 'undefined')
|
|
75
|
+
return;
|
|
76
|
+
if (isKnownChainId(chainId))
|
|
77
|
+
return;
|
|
78
|
+
if (providers?.[chainId])
|
|
79
|
+
return;
|
|
80
|
+
throw new errors_1.AugustValidationError('INVALID_CHAIN', `${method}: unknown chainId ${chainId}. ` +
|
|
81
|
+
'Pass a supported EVM chain ID (see NETWORKS) or a non-EVM chain ID ' +
|
|
82
|
+
'(-1 Solana, -3 Stellar, 101 Sui).', { context: { method, chainId } });
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Throw when a known EVM `chainId` has no RPC URL configured on the SDK.
|
|
86
|
+
*
|
|
87
|
+
* Non-EVM chain IDs are exempt: Solana, Stellar and Sui vaults route through
|
|
88
|
+
* their adapters and never read from the `providers` map, so a missing entry
|
|
89
|
+
* is expected rather than a misconfiguration.
|
|
90
|
+
*
|
|
91
|
+
* @param chainId - Chain ID supplied by the caller. `undefined` is a no-op.
|
|
92
|
+
* @param providers - The SDK's configured `chainId → RPC URL` map.
|
|
93
|
+
* @param method - Public method name, used to make the message actionable.
|
|
94
|
+
* @throws {@link AugustValidationError} with code `INVALID_CHAIN` when
|
|
95
|
+
* `chainId` is an EVM chain with no configured provider.
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* assertEvmProviderConfigured(143, {}, 'getVault');
|
|
99
|
+
* // AugustValidationError: getVault: no RPC URL configured for chainId 143 (Monad).
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
function assertEvmProviderConfigured(chainId, providers, method) {
|
|
103
|
+
if (typeof chainId === 'undefined')
|
|
104
|
+
return;
|
|
105
|
+
if (!isEvmChainId(chainId))
|
|
106
|
+
return;
|
|
107
|
+
if (providers?.[chainId])
|
|
108
|
+
return;
|
|
109
|
+
const name = web3_1.NETWORKS[chainId]?.name;
|
|
110
|
+
throw new errors_1.AugustValidationError('INVALID_CHAIN', `${method}: no RPC URL configured for chainId ${chainId}` +
|
|
111
|
+
`${name ? ` (${name})` : ''}. ` +
|
|
112
|
+
'Pass one when constructing AugustSDK: ' +
|
|
113
|
+
`new AugustSDK({ providers: { ${chainId}: '<rpc-url>' } }).`, { context: { method, chainId } });
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=chain-support.js.map
|
|
@@ -33,7 +33,26 @@ export declare const determineSecondsPerBlock: (chain: number) => number;
|
|
|
33
33
|
* @param chain Chain ID
|
|
34
34
|
* @returns Block interval for pagination
|
|
35
35
|
*/
|
|
36
|
-
export declare const determineBlockSkipInternal: (chain: number) => 1000 | 8000 |
|
|
36
|
+
export declare const determineBlockSkipInternal: (chain: number) => 1000 | 8000 | 10000;
|
|
37
|
+
/**
|
|
38
|
+
* Maximum JSON-RPC calls ethers may coalesce into a single batched HTTP
|
|
39
|
+
* request for a given endpoint.
|
|
40
|
+
*
|
|
41
|
+
* Providers advertise wildly different batch limits and reject the whole batch
|
|
42
|
+
* — not the excess — when exceeded, so one oversized batch fails every call
|
|
43
|
+
* inside it. dRPC's free tier caps batches at 3, which made every Mezo read
|
|
44
|
+
* fail with `server response 500 … "Batch of more than 3 requests are not
|
|
45
|
+
* allowed"` (the single highest-volume SDK error in production).
|
|
46
|
+
*
|
|
47
|
+
* Detection is host-based rather than chain-based because the limit is a
|
|
48
|
+
* property of the endpoint, not the chain: the same chain served by a
|
|
49
|
+
* self-hosted node has no such cap.
|
|
50
|
+
*
|
|
51
|
+
* @param rpcUrl - The RPC endpoint URL. Unparseable values fall back to the
|
|
52
|
+
* conservative default rather than throwing.
|
|
53
|
+
* @returns Batch size cap to pass to ethers as `batchMaxCount`.
|
|
54
|
+
*/
|
|
55
|
+
export declare const determineRpcBatchMaxCount: (rpcUrl: string) => number;
|
|
37
56
|
/**
|
|
38
57
|
* Retrieve chain ID from web3 provider.
|
|
39
58
|
* Handles both initialized and uninitialized provider states.
|