@augustdigital/sdk 8.9.0 → 8.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/lib/adapters/stellar/actions.js +4 -4
- package/lib/adapters/stellar/getters.d.ts +9 -3
- package/lib/adapters/stellar/getters.js +18 -6
- package/lib/adapters/stellar/index.d.ts +17 -2
- package/lib/adapters/stellar/index.js +24 -5
- package/lib/adapters/stellar/soroban.d.ts +89 -2
- package/lib/adapters/stellar/soroban.js +487 -64
- package/lib/adapters/stellar/submit.d.ts +4 -1
- package/lib/adapters/stellar/submit.js +7 -3
- package/lib/adapters/stellar/types.d.ts +12 -0
- package/lib/core/analytics/sanitize.js +19 -3
- package/lib/core/analytics/version.d.ts +1 -1
- package/lib/core/analytics/version.js +1 -1
- package/lib/core/base.class.d.ts +2 -1
- package/lib/core/helpers/chain-error.d.ts +1 -0
- package/lib/core/helpers/chain-error.js +96 -0
- package/lib/main.js +6 -1
- package/lib/modules/vaults/getters.js +5 -1
- package/lib/modules/vaults/main.d.ts +6 -0
- package/lib/modules/vaults/main.js +35 -0
- package/lib/modules/vaults/types.d.ts +11 -1
- package/lib/modules/vaults/write.actions.js +76 -6
- package/lib/sdk.d.ts +87 -6
- package/lib/types/vaults.d.ts +10 -0
- package/lib/types/web3.d.ts +15 -0
- package/package.json +1 -1
|
@@ -25,6 +25,11 @@ const SENSITIVE_KEYS = [
|
|
|
25
25
|
'privateKey',
|
|
26
26
|
'mnemonic',
|
|
27
27
|
'seed',
|
|
28
|
+
// RPC endpoints can carry the API key in the path (e.g. Alchemy `/v2/<key>`),
|
|
29
|
+
// so a `sorobanRpcUrl` / `rpcUrl` argument must never reach telemetry. Matched
|
|
30
|
+
// as a substring, so it also covers `sorobanRpcUrls` and snake_case variants.
|
|
31
|
+
'rpcurl',
|
|
32
|
+
'rpc_url',
|
|
28
33
|
];
|
|
29
34
|
/** Regex patterns applied in order to scrub secrets from free-form strings. */
|
|
30
35
|
const STRING_REDACTION_PATTERNS = [
|
|
@@ -34,6 +39,9 @@ const STRING_REDACTION_PATTERNS = [
|
|
|
34
39
|
'$1[REDACTED]',
|
|
35
40
|
],
|
|
36
41
|
[/(gateway\.thegraph\.com\/api\/)[A-Za-z0-9]{20,}(\/)/g, '$1[REDACTED]$2'],
|
|
42
|
+
// Provider path-embedded API keys (e.g. Alchemy `…/v2/<key>`, Infura `…/v3/<key>`):
|
|
43
|
+
// a 16+ char token right after a `/vN/` segment is a key, not a resource path.
|
|
44
|
+
[/(\/v\d+\/)[A-Za-z0-9_-]{16,}/g, '$1[REDACTED]'],
|
|
37
45
|
[/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '[REDACTED_JWT]'],
|
|
38
46
|
[/\bnpm_[A-Za-z0-9]{30,}\b/g, '[REDACTED_NPM_TOKEN]'],
|
|
39
47
|
// Stop value match at & # so adjacent query params aren't swallowed.
|
|
@@ -172,8 +180,10 @@ function sanitizeArgs(args) {
|
|
|
172
180
|
return;
|
|
173
181
|
}
|
|
174
182
|
if (typeof arg === 'string') {
|
|
175
|
-
//
|
|
176
|
-
|
|
183
|
+
// Scrub embedded secrets, then truncate long strings.
|
|
184
|
+
const scrubbed = sanitizeString(arg);
|
|
185
|
+
sanitized[key] =
|
|
186
|
+
scrubbed.length > 100 ? `${scrubbed.substring(0, 100)}...` : scrubbed;
|
|
177
187
|
return;
|
|
178
188
|
}
|
|
179
189
|
if (typeof arg === 'number' || typeof arg === 'boolean') {
|
|
@@ -214,8 +224,14 @@ function sanitizeObject(obj, depth = 0) {
|
|
|
214
224
|
sanitized[key] = '[REDACTED_HEX]';
|
|
215
225
|
continue;
|
|
216
226
|
}
|
|
227
|
+
// Scrub embedded secrets (API keys in URL paths/queries, bearer tokens,
|
|
228
|
+
// JWTs, …) from free-form values before truncating — key-name matching
|
|
229
|
+
// alone misses a secret carried inside a value under a benign key.
|
|
230
|
+
const scrubbedValue = sanitizeString(value);
|
|
217
231
|
sanitized[key] =
|
|
218
|
-
|
|
232
|
+
scrubbedValue.length > 100
|
|
233
|
+
? `${scrubbedValue.substring(0, 100)}...`
|
|
234
|
+
: scrubbedValue;
|
|
219
235
|
continue;
|
|
220
236
|
}
|
|
221
237
|
if (typeof value === 'number' || typeof value === 'boolean') {
|
package/lib/core/base.class.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ISolanaConfig, IAddress, IChainId, IEnv, IProvidersConfig, IWSMonitorHeaders } from '../types';
|
|
1
|
+
import type { ISolanaConfig, IStellarConfig, IAddress, IChainId, IEnv, IProvidersConfig, IWSMonitorHeaders } from '../types';
|
|
2
2
|
import { type IAnalyticsConfig } from './analytics';
|
|
3
3
|
import { type IVersionCheckConfig } from './version-check';
|
|
4
4
|
interface IKeys {
|
|
@@ -38,6 +38,7 @@ export interface IAugustBase {
|
|
|
38
38
|
appName: string;
|
|
39
39
|
providers?: IProvidersConfig;
|
|
40
40
|
solana?: ISolanaConfig;
|
|
41
|
+
stellar?: IStellarConfig;
|
|
41
42
|
keys: IKeys;
|
|
42
43
|
monitoring?: IMonitoring;
|
|
43
44
|
/** Analytics configuration. Enabled by default (opt-out model). */
|
|
@@ -45,6 +45,7 @@ export declare function isUserRejectionError(error: unknown): boolean;
|
|
|
45
45
|
* ```
|
|
46
46
|
*/
|
|
47
47
|
export declare function isExpectedRevertError(error: unknown): boolean;
|
|
48
|
+
export declare function isInsufficientFundsError(error: unknown): boolean;
|
|
48
49
|
/**
|
|
49
50
|
* Log a caught chain error at the severity its category warrants, without
|
|
50
51
|
* swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isUserRejectionError = isUserRejectionError;
|
|
4
4
|
exports.isExpectedRevertError = isExpectedRevertError;
|
|
5
|
+
exports.isInsufficientFundsError = isInsufficientFundsError;
|
|
5
6
|
exports.logChainError = logChainError;
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
8
|
/**
|
|
@@ -21,6 +22,9 @@ const logger_1 = require("../logger");
|
|
|
21
22
|
* 2. **Expected on-chain read reverts** — reading a function a vault doesn't
|
|
22
23
|
* implement, or an address with no/incompatible bytecode, reverts. This is a
|
|
23
24
|
* routine outcome of probing heterogeneous vaults, not a defect.
|
|
25
|
+
* 3. **Underfunded sender accounts** — the node rejects the transaction because
|
|
26
|
+
* the sender can't cover gas (or, on rollups such as Citrea, the extra L1
|
|
27
|
+
* data-availability fee). This is a "top up your wallet" prompt, not a bug.
|
|
24
28
|
*
|
|
25
29
|
* These predicates let call sites demote exactly those cases to `warn` while
|
|
26
30
|
* leaving genuine failures at `error`. They are intentionally dependency-free
|
|
@@ -77,6 +81,39 @@ function errorCodes(error) {
|
|
|
77
81
|
}
|
|
78
82
|
return codes;
|
|
79
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Collect every human-readable message string an error-like value carries,
|
|
86
|
+
* across the nested locations providers stash them in.
|
|
87
|
+
*
|
|
88
|
+
* Why this is separate from {@link errorText}: ethers v6 flattens a rejected
|
|
89
|
+
* `eth_estimateGas`/`eth_call` to a generic *top-level* `message` (e.g.
|
|
90
|
+
* `"missing revert data"`) while preserving the node's original JSON-RPC error
|
|
91
|
+
* one level down at `info.error.message`. The real reason (an insufficient-funds
|
|
92
|
+
* report, say) is therefore invisible to a top-level `.message` read. We scan
|
|
93
|
+
* the top-level message plus `error.message`, `info.error.message`,
|
|
94
|
+
* `cause.message`, and `cause.info.error.message` so a caller catches the reason
|
|
95
|
+
* whether it holds the raw provider error or an SDK error that wrapped it as
|
|
96
|
+
* `cause`.
|
|
97
|
+
*
|
|
98
|
+
* @param error - The caught value, of unknown type.
|
|
99
|
+
* @returns Every non-empty message string found (possibly empty array).
|
|
100
|
+
*/
|
|
101
|
+
function nestedMessages(error) {
|
|
102
|
+
const out = [];
|
|
103
|
+
const push = (value) => {
|
|
104
|
+
if (typeof value === 'string' && value.length > 0)
|
|
105
|
+
out.push(value);
|
|
106
|
+
};
|
|
107
|
+
push(errorText(error));
|
|
108
|
+
if (error && typeof error === 'object') {
|
|
109
|
+
const e = error;
|
|
110
|
+
push(e.error?.message);
|
|
111
|
+
push(e.info?.error?.message);
|
|
112
|
+
push(e.cause?.message);
|
|
113
|
+
push(e.cause?.info?.error?.message);
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
80
117
|
/**
|
|
81
118
|
* Is this error a wallet/user rejection of a transaction or signature request?
|
|
82
119
|
*
|
|
@@ -143,6 +180,65 @@ function isExpectedRevertError(error) {
|
|
|
143
180
|
msg.includes('call revert exception') ||
|
|
144
181
|
msg.includes('reverted'));
|
|
145
182
|
}
|
|
183
|
+
/**
|
|
184
|
+
* Is this error the chain node reporting that the sender can't afford the
|
|
185
|
+
* transaction's gas/fee — i.e. the account needs topping up, not a defect?
|
|
186
|
+
*
|
|
187
|
+
* This is distinct from a contract revert, and easy to misclassify. When the
|
|
188
|
+
* node rejects `eth_estimateGas` for an underfunded account, ethers v6 discards
|
|
189
|
+
* the node's reason and surfaces a generic `CALL_EXCEPTION` / `"missing revert
|
|
190
|
+
* data"` at the top level — which {@link isExpectedRevertError} matches. The
|
|
191
|
+
* real reason survives only in the nested JSON-RPC error, so this predicate
|
|
192
|
+
* scans there (via `nestedMessages`). On a write path, check this **before**
|
|
193
|
+
* {@link isExpectedRevertError}, or a genuine funds shortfall reads as a benign
|
|
194
|
+
* revert.
|
|
195
|
+
*
|
|
196
|
+
* Matching is anchored to the node's pre-execution funds-check phrasings (see
|
|
197
|
+
* `INSUFFICIENT_FUNDS_PHRASES`), each of which carries a `for <purpose>`
|
|
198
|
+
* qualifier — `insufficient funds for gas`, `insufficient funds for transfer`,
|
|
199
|
+
* `not enough funds for L1 fee` (Citrea's data-availability fee), etc. This is
|
|
200
|
+
* deliberately narrower than a bare `"insufficient funds"` substring: a
|
|
201
|
+
* *contract revert reason* that merely contains the word "funds" (e.g.
|
|
202
|
+
* `execution reverted: insufficient funds in pool`) must stay a genuine failure,
|
|
203
|
+
* not be demoted to an ACCOUNT_NOT_FUNDED "top up gas" prompt.
|
|
204
|
+
*
|
|
205
|
+
* @param error - The caught value, of unknown type.
|
|
206
|
+
* @returns `true` when the failure is an unfunded/underfunded sender account.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* try { await vault.requestRedeem(...); }
|
|
211
|
+
* catch (e) {
|
|
212
|
+
* if (isInsufficientFundsError(e))
|
|
213
|
+
* throw new AugustValidationError(
|
|
214
|
+
* 'ACCOUNT_NOT_FUNDED',
|
|
215
|
+
* 'Add gas to continue',
|
|
216
|
+
* { cause: e },
|
|
217
|
+
* );
|
|
218
|
+
* throw e;
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
/**
|
|
223
|
+
* The node pre-execution funds-check phrasings {@link isInsufficientFundsError}
|
|
224
|
+
* recognises, lower-cased. Each keeps the `for <purpose>` qualifier so the match
|
|
225
|
+
* is anchored to a funding rejection and can't be tripped by a contract revert
|
|
226
|
+
* reason that merely mentions "funds". `insufficient funds for gas` covers the
|
|
227
|
+
* geth/reth `"... for gas * price + value"` message; `not enough funds for l1
|
|
228
|
+
* fee` is the rollup (Citrea) data-availability-fee shortfall.
|
|
229
|
+
*/
|
|
230
|
+
const INSUFFICIENT_FUNDS_PHRASES = [
|
|
231
|
+
'insufficient funds for gas',
|
|
232
|
+
'insufficient funds for transfer',
|
|
233
|
+
'insufficient funds for intrinsic transaction cost',
|
|
234
|
+
'not enough funds for l1 fee',
|
|
235
|
+
];
|
|
236
|
+
function isInsufficientFundsError(error) {
|
|
237
|
+
return nestedMessages(error).some((raw) => {
|
|
238
|
+
const msg = raw.toLowerCase();
|
|
239
|
+
return INSUFFICIENT_FUNDS_PHRASES.some((phrase) => msg.includes(phrase));
|
|
240
|
+
});
|
|
241
|
+
}
|
|
146
242
|
/**
|
|
147
243
|
* Log a caught chain error at the severity its category warrants, without
|
|
148
244
|
* swallowing it. When `isBenign` is `true` the failure is recorded as a `warn`
|
package/lib/main.js
CHANGED
|
@@ -108,7 +108,12 @@ class AugustSDK extends core_1.AugustBase {
|
|
|
108
108
|
(0, analytics_1.instrumentClass)(this.solana, () => core_1.SPECIAL_CHAINS.solana.chainId);
|
|
109
109
|
}
|
|
110
110
|
this.sui = new sui_1.default();
|
|
111
|
-
|
|
111
|
+
// @stellar: mirror the Solana injection — the consumer may supply a keyed
|
|
112
|
+
// Soroban RPC (e.g. Alchemy) via `baseConfig.stellar`; otherwise the adapter
|
|
113
|
+
// uses its built-in public endpoints. Endpoint is injected, not hardcoded.
|
|
114
|
+
this.stellar = new stellar_1.default(baseConfig.stellar?.network, {
|
|
115
|
+
sorobanRpcUrl: baseConfig.stellar?.rpcUrl,
|
|
116
|
+
});
|
|
112
117
|
this.vaults = new vaults_1.AugustVaults(baseConfig, this.solana, this.sui);
|
|
113
118
|
this.subaccounts = new sub_accounts_1.AugustSubAccounts(baseConfig);
|
|
114
119
|
this.api = new api_1.AugustApi(baseConfig);
|
|
@@ -1058,7 +1058,11 @@ async function getVaultPositions({ vault, wallet, solanaWallet, stellarWallet, o
|
|
|
1058
1058
|
let balance = (0, core_1.toNormalizedBn)(0);
|
|
1059
1059
|
if (stellarWallet && (0, utils_3.isStellarAddress)(stellarWallet)) {
|
|
1060
1060
|
const stellarNetwork = v.stellar_vault_metadata?.network_name ?? 'mainnet';
|
|
1061
|
-
|
|
1061
|
+
// Only use the configured RPC override for its own network.
|
|
1062
|
+
const stellarOverrideRpcUrl = options.stellarRpc?.network === stellarNetwork
|
|
1063
|
+
? options.stellarRpc.rpcUrl
|
|
1064
|
+
: undefined;
|
|
1065
|
+
const position = await StellarGetters.getStellarUserPosition(v.address, stellarWallet, stellarNetwork, stellarOverrideRpcUrl);
|
|
1062
1066
|
if (position && !position.decimalsFromFallback) {
|
|
1063
1067
|
balance = (0, core_1.toNormalizedBn)(BigInt(position.shares), position.decimals);
|
|
1064
1068
|
}
|
|
@@ -23,6 +23,12 @@ export declare class AugustVaults extends AugustBase {
|
|
|
23
23
|
private solanaService;
|
|
24
24
|
private suiService;
|
|
25
25
|
private headers;
|
|
26
|
+
/**
|
|
27
|
+
* Consumer-supplied Soroban RPC override for Stellar vault reads, with the
|
|
28
|
+
* network it was configured for so it's only applied to matching-network
|
|
29
|
+
* vaults (see `IVaultBaseOptions.stellarRpc`).
|
|
30
|
+
*/
|
|
31
|
+
private _stellarRpc?;
|
|
26
32
|
constructor(baseConfig: IAugustBase, solana: SolanaAdapter, sui: SuiAdapter);
|
|
27
33
|
/**
|
|
28
34
|
* @description deposit underlying token into the specified pool with adapter support. This is for when we cannot pass in a signer in sdk and need to do so as an arg
|
|
@@ -74,10 +74,23 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
74
74
|
solanaService;
|
|
75
75
|
suiService;
|
|
76
76
|
headers = null;
|
|
77
|
+
/**
|
|
78
|
+
* Consumer-supplied Soroban RPC override for Stellar vault reads, with the
|
|
79
|
+
* network it was configured for so it's only applied to matching-network
|
|
80
|
+
* vaults (see `IVaultBaseOptions.stellarRpc`).
|
|
81
|
+
*/
|
|
82
|
+
_stellarRpc;
|
|
77
83
|
constructor(baseConfig, solana, sui) {
|
|
78
84
|
super(baseConfig);
|
|
79
85
|
this.solanaService = solana;
|
|
80
86
|
this.suiService = sui || new sui_1.default();
|
|
87
|
+
// Network defaults to mainnet, matching the StellarAdapter constructor.
|
|
88
|
+
this._stellarRpc = baseConfig.stellar?.rpcUrl
|
|
89
|
+
? {
|
|
90
|
+
rpcUrl: baseConfig.stellar.rpcUrl,
|
|
91
|
+
network: baseConfig.stellar.network ?? 'mainnet',
|
|
92
|
+
}
|
|
93
|
+
: undefined;
|
|
81
94
|
this.headers = {
|
|
82
95
|
'x-environment': this.monitoring?.['x-environment'],
|
|
83
96
|
'x-user-id': this.monitoring?.['x-user-id'],
|
|
@@ -166,6 +179,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
166
179
|
options: {
|
|
167
180
|
rpcUrl,
|
|
168
181
|
solanaService: this.solanaService,
|
|
182
|
+
stellarRpc: this._stellarRpc,
|
|
169
183
|
env: this.monitoring?.env,
|
|
170
184
|
augustKey: this.keys?.august,
|
|
171
185
|
subgraphKey: this.keys?.graph,
|
|
@@ -243,6 +257,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
243
257
|
options: {
|
|
244
258
|
rpcUrl: this.providers?.[v.chain],
|
|
245
259
|
solanaService: this.solanaService,
|
|
260
|
+
stellarRpc: this._stellarRpc,
|
|
246
261
|
env: this.monitoring?.env,
|
|
247
262
|
augustKey: this.keys?.august,
|
|
248
263
|
subgraphKey: this.keys?.graph,
|
|
@@ -316,6 +331,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
316
331
|
? this.providers?.[chainId]
|
|
317
332
|
: this.activeNetwork?.rpcUrl,
|
|
318
333
|
solanaService: this.solanaService,
|
|
334
|
+
stellarRpc: this._stellarRpc,
|
|
319
335
|
env: this.monitoring?.env,
|
|
320
336
|
augustKey: this.keys?.august,
|
|
321
337
|
subgraphKey: this.keys?.graph,
|
|
@@ -340,6 +356,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
340
356
|
? this.providers?.[chainId]
|
|
341
357
|
: this.activeNetwork?.rpcUrl,
|
|
342
358
|
solanaService: this.solanaService,
|
|
359
|
+
stellarRpc: this._stellarRpc,
|
|
343
360
|
env: this.monitoring?.env,
|
|
344
361
|
augustKey: this.keys?.august,
|
|
345
362
|
subgraphKey: this.keys?.graph,
|
|
@@ -385,6 +402,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
385
402
|
subgraphKey: this.keys?.graph,
|
|
386
403
|
chainId: chainId,
|
|
387
404
|
solanaService: this.solanaService,
|
|
405
|
+
stellarRpc: this._stellarRpc,
|
|
388
406
|
headers: this.headers,
|
|
389
407
|
});
|
|
390
408
|
return vaultResponse;
|
|
@@ -416,6 +434,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
416
434
|
subgraphKey: this.keys?.graph,
|
|
417
435
|
chainId: chainId,
|
|
418
436
|
solanaService: this.solanaService,
|
|
437
|
+
stellarRpc: this._stellarRpc,
|
|
419
438
|
headers: this.headers,
|
|
420
439
|
});
|
|
421
440
|
return vaultResponse;
|
|
@@ -447,6 +466,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
447
466
|
? this.providers?.[chainId]
|
|
448
467
|
: this.activeNetwork?.rpcUrl,
|
|
449
468
|
solanaService: this.solanaService,
|
|
469
|
+
stellarRpc: this._stellarRpc,
|
|
450
470
|
env: this.monitoring?.env,
|
|
451
471
|
augustKey: this.keys?.august,
|
|
452
472
|
subgraphKey: this.keys?.graph,
|
|
@@ -527,6 +547,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
527
547
|
? this.providers?.[chainId]
|
|
528
548
|
: this.activeNetwork?.rpcUrl,
|
|
529
549
|
solanaService: this.solanaService,
|
|
550
|
+
stellarRpc: this._stellarRpc,
|
|
530
551
|
env: this.monitoring?.env,
|
|
531
552
|
augustKey: this.keys?.august,
|
|
532
553
|
subgraphKey: this.keys?.graph,
|
|
@@ -611,6 +632,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
611
632
|
? this.providers?.[chainId]
|
|
612
633
|
: this.activeNetwork?.rpcUrl,
|
|
613
634
|
solanaService: this.solanaService,
|
|
635
|
+
stellarRpc: this._stellarRpc,
|
|
614
636
|
env: this.monitoring?.env,
|
|
615
637
|
augustKey: this.keys?.august,
|
|
616
638
|
subgraphKey: this.keys?.graph,
|
|
@@ -632,6 +654,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
632
654
|
options: {
|
|
633
655
|
rpcUrl: this.providers?.[v.chain],
|
|
634
656
|
solanaService: this.solanaService,
|
|
657
|
+
stellarRpc: this._stellarRpc,
|
|
635
658
|
env: this.monitoring?.env,
|
|
636
659
|
augustKey: this.keys?.august,
|
|
637
660
|
subgraphKey: this.keys?.graph,
|
|
@@ -667,6 +690,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
667
690
|
options: {
|
|
668
691
|
rpcUrl: this.providers?.[v.chain],
|
|
669
692
|
solanaService: this.solanaService,
|
|
693
|
+
stellarRpc: this._stellarRpc,
|
|
670
694
|
env: this.monitoring?.env,
|
|
671
695
|
augustKey: this.keys?.august,
|
|
672
696
|
subgraphKey: this.keys?.graph,
|
|
@@ -706,6 +730,10 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
706
730
|
chainId: _chainId,
|
|
707
731
|
type: h.type,
|
|
708
732
|
transactionHash: h.transactionHash_,
|
|
733
|
+
// Deposit rows on multi-asset (pre-deposit) vaults carry the actual
|
|
734
|
+
// deposited token address; propagate it so consumers render the right
|
|
735
|
+
// asset symbol instead of guessing the vault's first deposit asset.
|
|
736
|
+
assetIn: h.assetIn,
|
|
709
737
|
}));
|
|
710
738
|
}
|
|
711
739
|
// Helper function to fetch history for a vault
|
|
@@ -826,6 +854,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
826
854
|
? this.providers?.[chainId]
|
|
827
855
|
: this.requireActiveNetwork().rpcUrl,
|
|
828
856
|
solanaService: this.solanaService,
|
|
857
|
+
stellarRpc: this._stellarRpc,
|
|
829
858
|
env: this.monitoring?.env,
|
|
830
859
|
augustKey: this.keys?.august,
|
|
831
860
|
subgraphKey: this.keys?.graph,
|
|
@@ -851,6 +880,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
851
880
|
? this.providers?.[chainId]
|
|
852
881
|
: this.requireActiveNetwork().rpcUrl,
|
|
853
882
|
solanaService: this.solanaService,
|
|
883
|
+
stellarRpc: this._stellarRpc,
|
|
854
884
|
env: this.monitoring?.env,
|
|
855
885
|
augustKey: this.keys?.august,
|
|
856
886
|
subgraphKey: this.keys?.graph,
|
|
@@ -1033,6 +1063,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
1033
1063
|
rpcUrl: rpcUrl,
|
|
1034
1064
|
chainId: resolvedChainId,
|
|
1035
1065
|
solanaService: this.solanaService,
|
|
1066
|
+
stellarRpc: this._stellarRpc,
|
|
1036
1067
|
env: this.monitoring?.env,
|
|
1037
1068
|
augustKey: this.keys?.august,
|
|
1038
1069
|
subgraphKey: this.keys?.graph,
|
|
@@ -1056,6 +1087,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
1056
1087
|
options: {
|
|
1057
1088
|
rpcUrl: rpcUrl,
|
|
1058
1089
|
solanaService: this.solanaService,
|
|
1090
|
+
stellarRpc: this._stellarRpc,
|
|
1059
1091
|
env: this.monitoring?.env,
|
|
1060
1092
|
augustKey: this.keys?.august,
|
|
1061
1093
|
subgraphKey: this.keys?.graph,
|
|
@@ -1103,6 +1135,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
1103
1135
|
? this.providers?.[chainId]
|
|
1104
1136
|
: rpcUrl || this.requireActiveNetwork().rpcUrl,
|
|
1105
1137
|
solanaService: this.solanaService,
|
|
1138
|
+
stellarRpc: this._stellarRpc,
|
|
1106
1139
|
env: this.monitoring?.env,
|
|
1107
1140
|
augustKey: this.keys?.august,
|
|
1108
1141
|
subgraphKey: this.keys?.graph,
|
|
@@ -1376,6 +1409,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
1376
1409
|
options: {
|
|
1377
1410
|
rpcUrl: chainId ? this.providers?.[chainId] : this.activeNetwork.rpcUrl,
|
|
1378
1411
|
solanaService: this.solanaService,
|
|
1412
|
+
stellarRpc: this._stellarRpc,
|
|
1379
1413
|
env: this.monitoring?.env,
|
|
1380
1414
|
augustKey: this.keys?.august,
|
|
1381
1415
|
subgraphKey: this.keys?.graph,
|
|
@@ -1428,6 +1462,7 @@ class AugustVaults extends core_1.AugustBase {
|
|
|
1428
1462
|
options: {
|
|
1429
1463
|
rpcUrl,
|
|
1430
1464
|
solanaService: this.solanaService,
|
|
1465
|
+
stellarRpc: this._stellarRpc,
|
|
1431
1466
|
env: this.monitoring?.env,
|
|
1432
1467
|
augustKey: this.keys?.august,
|
|
1433
1468
|
subgraphKey: this.keys?.graph,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Connection } from '@solana/web3.js';
|
|
2
|
-
import type { IAddress, IEnv, IWSMonitorHeaders } from '../../types';
|
|
2
|
+
import type { IAddress, IEnv, IStellarNetwork, IWSMonitorHeaders } from '../../types';
|
|
3
3
|
/**
|
|
4
4
|
* Structural interface for the Solana adapter surface used by vault operations.
|
|
5
5
|
* Avoids importing the concrete SolanaAdapter class to prevent circular dependencies.
|
|
@@ -40,6 +40,16 @@ export interface IVaultBaseOptions {
|
|
|
40
40
|
subgraphKey?: string;
|
|
41
41
|
chainId?: number;
|
|
42
42
|
solanaService?: ISolanaService;
|
|
43
|
+
/**
|
|
44
|
+
* Optional Soroban RPC override (e.g. a keyed Alchemy URL) for Stellar vault
|
|
45
|
+
* reads, threaded from the SDK's `stellar` config. Carries the network it was
|
|
46
|
+
* configured for so it is only applied to matching-network vaults — a testnet
|
|
47
|
+
* override must not be used for a mainnet read. Unset → built-in endpoints.
|
|
48
|
+
*/
|
|
49
|
+
stellarRpc?: {
|
|
50
|
+
rpcUrl: string;
|
|
51
|
+
network: IStellarNetwork;
|
|
52
|
+
};
|
|
43
53
|
headers?: IWSMonitorHeaders;
|
|
44
54
|
/**
|
|
45
55
|
* Portfolio mode: when true, the per-vault EVM getter does NOT null out a
|
|
@@ -185,6 +185,39 @@ async function tryRecoverTxHash(error, signer, wait) {
|
|
|
185
185
|
}
|
|
186
186
|
return txHash;
|
|
187
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* Rethrow a caught write-path error as a typed {@link AugustValidationError}
|
|
190
|
+
* when it is the chain node reporting the sender can't afford the transaction's
|
|
191
|
+
* gas/fee (see {@link isInsufficientFundsError}).
|
|
192
|
+
*
|
|
193
|
+
* Why: for an underfunded account ethers surfaces an opaque `CALL_EXCEPTION` /
|
|
194
|
+
* "missing revert data" that gives the caller no stable way to tell "user needs
|
|
195
|
+
* gas" apart from a genuine on-chain failure. Converting it to the
|
|
196
|
+
* `ACCOUNT_NOT_FUNDED` code lets a consuming UI branch on `err.code` (e.g. show
|
|
197
|
+
* a "top up to cover network fees" prompt) instead of string-matching. Every
|
|
198
|
+
* write path shares this so the classification is identical across
|
|
199
|
+
* deposit/redeem/approve rather than drifting per call site.
|
|
200
|
+
*
|
|
201
|
+
* A no-op when `isInsufficient` is `false`, so callers fall through to their
|
|
202
|
+
* existing handling unchanged. The caller passes the already-computed
|
|
203
|
+
* classification (it also feeds the telemetry-demotion decision) so
|
|
204
|
+
* {@link isInsufficientFundsError} runs once per catch, not twice.
|
|
205
|
+
*
|
|
206
|
+
* @param isInsufficient - Result of {@link isInsufficientFundsError} for
|
|
207
|
+
* `error`, computed once by the caller and shared with the benign-log flag.
|
|
208
|
+
* @param operation - Human-readable label for the attempted write (e.g.
|
|
209
|
+
* `'Request redeem'`), used verbatim in the thrown error's message.
|
|
210
|
+
* @param error - The caught value, of unknown type, preserved as the thrown
|
|
211
|
+
* error's `cause`.
|
|
212
|
+
* @param context - Structured context attached to the thrown error for logging.
|
|
213
|
+
* @throws {AugustValidationError} with code `ACCOUNT_NOT_FUNDED` when
|
|
214
|
+
* `isInsufficient` is `true`.
|
|
215
|
+
*/
|
|
216
|
+
function throwIfInsufficientFunds(isInsufficient, operation, error, context) {
|
|
217
|
+
if (!isInsufficient)
|
|
218
|
+
return;
|
|
219
|
+
throw new core_1.AugustValidationError('ACCOUNT_NOT_FUNDED', `${operation} failed: insufficient native balance to cover gas/network fees`, { cause: error, context });
|
|
220
|
+
}
|
|
188
221
|
async function approveCore(signer, options) {
|
|
189
222
|
const { wallet, target, wait, amount, depositAsset } = options;
|
|
190
223
|
const [goodWallet, goodPool] = [
|
|
@@ -293,7 +326,12 @@ async function approveCore(signer, options) {
|
|
|
293
326
|
throw e;
|
|
294
327
|
// A user declining the approval in their wallet is product behaviour, not
|
|
295
328
|
// an SDK fault — demote it to a breadcrumb so it doesn't bill as an issue.
|
|
296
|
-
|
|
329
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
330
|
+
(0, core_1.logChainError)('vaultApprove', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
331
|
+
target,
|
|
332
|
+
amount,
|
|
333
|
+
});
|
|
334
|
+
throwIfInsufficientFunds(insufficientFunds, 'Approval', e, {
|
|
297
335
|
target,
|
|
298
336
|
amount,
|
|
299
337
|
});
|
|
@@ -601,7 +639,13 @@ async function vaultDeposit(signer, options) {
|
|
|
601
639
|
if (e instanceof core_1.AugustSDKError)
|
|
602
640
|
throw e;
|
|
603
641
|
// User-cancelled deposits are normal; only genuine failures stay at error.
|
|
604
|
-
|
|
642
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
643
|
+
(0, core_1.logChainError)('deposit', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
644
|
+
target,
|
|
645
|
+
amount,
|
|
646
|
+
depositAsset,
|
|
647
|
+
});
|
|
648
|
+
throwIfInsufficientFunds(insufficientFunds, 'Deposit', e, {
|
|
605
649
|
target,
|
|
606
650
|
amount,
|
|
607
651
|
depositAsset,
|
|
@@ -754,7 +798,12 @@ async function vaultRequestRedeem(signer, options) {
|
|
|
754
798
|
if (e instanceof core_1.AugustSDKError)
|
|
755
799
|
throw e;
|
|
756
800
|
// User-cancelled redeem requests are normal; only genuine failures stay at error.
|
|
757
|
-
|
|
801
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
802
|
+
(0, core_1.logChainError)('requestRedeem', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
803
|
+
target,
|
|
804
|
+
amount,
|
|
805
|
+
});
|
|
806
|
+
throwIfInsufficientFunds(insufficientFunds, 'Request redeem', e, {
|
|
758
807
|
target,
|
|
759
808
|
amount,
|
|
760
809
|
});
|
|
@@ -801,7 +850,15 @@ async function vaultRedeem(signer, options) {
|
|
|
801
850
|
if (e instanceof core_1.AugustSDKError)
|
|
802
851
|
throw e;
|
|
803
852
|
// User-cancelled redeems are normal; only genuine failures stay at error.
|
|
804
|
-
|
|
853
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
854
|
+
(0, core_1.logChainError)('redeem', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
855
|
+
target,
|
|
856
|
+
year,
|
|
857
|
+
month,
|
|
858
|
+
day,
|
|
859
|
+
receiverIndex,
|
|
860
|
+
});
|
|
861
|
+
throwIfInsufficientFunds(insufficientFunds, 'Redeem', e, {
|
|
805
862
|
target,
|
|
806
863
|
year,
|
|
807
864
|
month,
|
|
@@ -899,7 +956,13 @@ async function depositNative(signer, options) {
|
|
|
899
956
|
if (e instanceof core_1.AugustSDKError)
|
|
900
957
|
throw e;
|
|
901
958
|
// User-cancelled native deposits are normal; only genuine failures stay at error.
|
|
902
|
-
|
|
959
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
960
|
+
(0, core_1.logChainError)('depositNative', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
961
|
+
wrapperAddress,
|
|
962
|
+
receiver,
|
|
963
|
+
amount,
|
|
964
|
+
});
|
|
965
|
+
throwIfInsufficientFunds(insufficientFunds, 'Deposit native', e, {
|
|
903
966
|
wrapperAddress,
|
|
904
967
|
receiver,
|
|
905
968
|
amount,
|
|
@@ -978,7 +1041,14 @@ async function rwaRedeemAsset(signer, options) {
|
|
|
978
1041
|
if (e instanceof core_1.AugustSDKError)
|
|
979
1042
|
throw e;
|
|
980
1043
|
// User-cancelled RWA redeems are normal; only genuine failures stay at error.
|
|
981
|
-
|
|
1044
|
+
const insufficientFunds = (0, core_1.isInsufficientFundsError)(e);
|
|
1045
|
+
(0, core_1.logChainError)('rwaRedeemAsset', e, (0, core_1.isUserRejectionError)(e) || insufficientFunds, {
|
|
1046
|
+
target,
|
|
1047
|
+
asset,
|
|
1048
|
+
amount,
|
|
1049
|
+
minOut,
|
|
1050
|
+
});
|
|
1051
|
+
throwIfInsufficientFunds(insufficientFunds, 'RWA redeem', e, {
|
|
982
1052
|
target,
|
|
983
1053
|
asset,
|
|
984
1054
|
amount,
|