@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
|
@@ -50,10 +50,10 @@ function buildSelfOperationArgs(amount, userAddress) {
|
|
|
50
50
|
* @returns Base64-encoded XDR of the unsigned transaction, ready for wallet signing.
|
|
51
51
|
*/
|
|
52
52
|
async function handleStellarDeposit(params) {
|
|
53
|
-
const { contractId, amount, senderAddress, network } = params;
|
|
53
|
+
const { contractId, amount, senderAddress, network, sorobanRpcUrl } = params;
|
|
54
54
|
validateContractAddress(contractId);
|
|
55
55
|
validateAccountAddress(senderAddress, 'sender');
|
|
56
|
-
const config = (0, soroban_1.resolveNetworkConfig)(network);
|
|
56
|
+
const config = (0, soroban_1.resolveNetworkConfig)(network, sorobanRpcUrl);
|
|
57
57
|
const args = buildSelfOperationArgs((0, soroban_1.toBigIntAmount)(amount, 'deposit amount'), senderAddress);
|
|
58
58
|
return (0, soroban_1.buildSorobanTx)(config, senderAddress, contractId, 'deposit', args);
|
|
59
59
|
}
|
|
@@ -67,10 +67,10 @@ async function handleStellarDeposit(params) {
|
|
|
67
67
|
* XDR to {@link submitStellarTransaction}.
|
|
68
68
|
*/
|
|
69
69
|
async function handleStellarRedeem(params) {
|
|
70
|
-
const { contractId, shares, receiverAddress, network } = params;
|
|
70
|
+
const { contractId, shares, receiverAddress, network, sorobanRpcUrl } = params;
|
|
71
71
|
validateContractAddress(contractId);
|
|
72
72
|
validateAccountAddress(receiverAddress, 'receiver');
|
|
73
|
-
const config = (0, soroban_1.resolveNetworkConfig)(network);
|
|
73
|
+
const config = (0, soroban_1.resolveNetworkConfig)(network, sorobanRpcUrl);
|
|
74
74
|
const args = buildSelfOperationArgs((0, soroban_1.toBigIntAmount)(shares, 'redeem shares'), receiverAddress);
|
|
75
75
|
return (0, soroban_1.buildSorobanTx)(config, receiverAddress, contractId, 'redeem', args);
|
|
76
76
|
}
|
|
@@ -16,7 +16,7 @@ import type { IStellarNetwork, IStellarUserPosition } from './types';
|
|
|
16
16
|
* Falls back to backend `latest_reported_tvl` for total assets, or zero
|
|
17
17
|
* for total supply, when on-chain queries fail.
|
|
18
18
|
*/
|
|
19
|
-
export declare const getStellarVault: (tokenizedVault: ITokenizedVault,
|
|
19
|
+
export declare const getStellarVault: (tokenizedVault: ITokenizedVault, options: IVaultBaseOptions) => Promise<IVault>;
|
|
20
20
|
/**
|
|
21
21
|
* Get user position for a Stellar vault.
|
|
22
22
|
* Queries the vault contract's balance(address) and decimals() functions via Soroban RPC.
|
|
@@ -37,6 +37,9 @@ export declare const getStellarVault: (tokenizedVault: ITokenizedVault, _options
|
|
|
37
37
|
* @param vaultAddress - Stellar vault contract ID (C… address)
|
|
38
38
|
* @param walletAddress - User's Stellar account (G… address); validated upfront
|
|
39
39
|
* @param network - 'mainnet' | 'testnet' (defaults to 'mainnet')
|
|
40
|
+
* @param sorobanRpcUrl - Optional override Soroban RPC endpoint (e.g. a keyed
|
|
41
|
+
* Alchemy URL); becomes the primary with the SDK's public endpoints kept as
|
|
42
|
+
* failover. Omit to use the public endpoints.
|
|
40
43
|
* @returns The position, or `null` if the balance read failed or was unparseable.
|
|
41
44
|
* @throws AugustValidationError on an invalid `walletAddress`.
|
|
42
45
|
* @example
|
|
@@ -49,7 +52,7 @@ export declare const getStellarVault: (tokenizedVault: ITokenizedVault, _options
|
|
|
49
52
|
* const human = Number(pos.shares) / 10 ** pos.decimals;
|
|
50
53
|
* ```
|
|
51
54
|
*/
|
|
52
|
-
export declare const getStellarUserPosition: (vaultAddress: string, walletAddress: string, network?: IStellarNetwork) => Promise<IStellarUserPosition | null>;
|
|
55
|
+
export declare const getStellarUserPosition: (vaultAddress: string, walletAddress: string, network?: IStellarNetwork, sorobanRpcUrl?: string) => Promise<IStellarUserPosition | null>;
|
|
53
56
|
/**
|
|
54
57
|
* Query the vault's `convert_to_shares` to preview how many shares a deposit
|
|
55
58
|
* amount would yield. Returns the raw share amount as a string, or null on
|
|
@@ -58,5 +61,8 @@ export declare const getStellarUserPosition: (vaultAddress: string, walletAddres
|
|
|
58
61
|
* @param vaultAddress Stellar contract ID (C… address)
|
|
59
62
|
* @param rawAmount Deposit amount in the deposit token's smallest unit
|
|
60
63
|
* @param network 'mainnet' | 'testnet'
|
|
64
|
+
* @param sorobanRpcUrl - Optional override Soroban RPC endpoint (e.g. a keyed
|
|
65
|
+
* Alchemy URL); becomes the primary with the SDK's public endpoints kept as
|
|
66
|
+
* failover. Omit to use the public endpoints.
|
|
61
67
|
*/
|
|
62
|
-
export declare const convertToShares: (vaultAddress: string, rawAmount: string, network?: IStellarNetwork) => Promise<string | null>;
|
|
68
|
+
export declare const convertToShares: (vaultAddress: string, rawAmount: string, network?: IStellarNetwork, sorobanRpcUrl?: string) => Promise<string | null>;
|
|
@@ -78,7 +78,7 @@ function resolveNetwork(tokenizedVault) {
|
|
|
78
78
|
* Falls back to backend `latest_reported_tvl` for total assets, or zero
|
|
79
79
|
* for total supply, when on-chain queries fail.
|
|
80
80
|
*/
|
|
81
|
-
const getStellarVault = async (tokenizedVault,
|
|
81
|
+
const getStellarVault = async (tokenizedVault, options) => {
|
|
82
82
|
const stellarMetadata = tokenizedVault.stellar_vault_metadata;
|
|
83
83
|
const depositDecimals = stellarMetadata?.deposit_token_decimals ?? constants_1.STELLAR_FALLBACK_DECIMALS;
|
|
84
84
|
if (stellarMetadata?.deposit_token_decimals == null) {
|
|
@@ -90,7 +90,13 @@ const getStellarVault = async (tokenizedVault, _options) => {
|
|
|
90
90
|
}
|
|
91
91
|
// Attempt on-chain queries for total assets, total supply, and share decimals
|
|
92
92
|
const network = resolveNetwork(tokenizedVault);
|
|
93
|
-
|
|
93
|
+
// Only apply the configured RPC override when it matches this vault's network
|
|
94
|
+
// (a testnet override must not be used for a mainnet read). `options` may be
|
|
95
|
+
// omitted by JS callers, so guard it.
|
|
96
|
+
const overrideRpcUrl = options?.stellarRpc?.network === network
|
|
97
|
+
? options.stellarRpc.rpcUrl
|
|
98
|
+
: undefined;
|
|
99
|
+
const config = (0, soroban_1.resolveNetworkConfig)(network, overrideRpcUrl);
|
|
94
100
|
const [assetsResult, supplyResult, decimalsResult] = await Promise.all([
|
|
95
101
|
(0, soroban_1.queryContract)(config, tokenizedVault.address, 'total_assets'),
|
|
96
102
|
(0, soroban_1.queryContract)(config, tokenizedVault.address, 'total_supply'),
|
|
@@ -171,6 +177,9 @@ exports.getStellarVault = getStellarVault;
|
|
|
171
177
|
* @param vaultAddress - Stellar vault contract ID (C… address)
|
|
172
178
|
* @param walletAddress - User's Stellar account (G… address); validated upfront
|
|
173
179
|
* @param network - 'mainnet' | 'testnet' (defaults to 'mainnet')
|
|
180
|
+
* @param sorobanRpcUrl - Optional override Soroban RPC endpoint (e.g. a keyed
|
|
181
|
+
* Alchemy URL); becomes the primary with the SDK's public endpoints kept as
|
|
182
|
+
* failover. Omit to use the public endpoints.
|
|
174
183
|
* @returns The position, or `null` if the balance read failed or was unparseable.
|
|
175
184
|
* @throws AugustValidationError on an invalid `walletAddress`.
|
|
176
185
|
* @example
|
|
@@ -183,8 +192,8 @@ exports.getStellarVault = getStellarVault;
|
|
|
183
192
|
* const human = Number(pos.shares) / 10 ** pos.decimals;
|
|
184
193
|
* ```
|
|
185
194
|
*/
|
|
186
|
-
const getStellarUserPosition = async (vaultAddress, walletAddress, network = 'mainnet') => {
|
|
187
|
-
const config = (0, soroban_1.resolveNetworkConfig)(network);
|
|
195
|
+
const getStellarUserPosition = async (vaultAddress, walletAddress, network = 'mainnet', sorobanRpcUrl) => {
|
|
196
|
+
const config = (0, soroban_1.resolveNetworkConfig)(network, sorobanRpcUrl);
|
|
188
197
|
// Validate address upfront — invalid input is a caller bug, not an RPC issue
|
|
189
198
|
let userAddress;
|
|
190
199
|
try {
|
|
@@ -243,8 +252,11 @@ exports.getStellarUserPosition = getStellarUserPosition;
|
|
|
243
252
|
* @param vaultAddress Stellar contract ID (C… address)
|
|
244
253
|
* @param rawAmount Deposit amount in the deposit token's smallest unit
|
|
245
254
|
* @param network 'mainnet' | 'testnet'
|
|
255
|
+
* @param sorobanRpcUrl - Optional override Soroban RPC endpoint (e.g. a keyed
|
|
256
|
+
* Alchemy URL); becomes the primary with the SDK's public endpoints kept as
|
|
257
|
+
* failover. Omit to use the public endpoints.
|
|
246
258
|
*/
|
|
247
|
-
const convertToShares = async (vaultAddress, rawAmount, network = 'mainnet') => {
|
|
259
|
+
const convertToShares = async (vaultAddress, rawAmount, network = 'mainnet', sorobanRpcUrl) => {
|
|
248
260
|
// Validate address upfront — invalid input is a caller bug, not an RPC issue
|
|
249
261
|
try {
|
|
250
262
|
new stellar_sdk_1.Address(vaultAddress);
|
|
@@ -252,7 +264,7 @@ const convertToShares = async (vaultAddress, rawAmount, network = 'mainnet') =>
|
|
|
252
264
|
catch (addrErr) {
|
|
253
265
|
throw new core_1.AugustValidationError('INVALID_ADDRESS', `convertToShares: invalid vaultAddress "${vaultAddress}": ${String(addrErr)}`, { cause: addrErr });
|
|
254
266
|
}
|
|
255
|
-
const config = (0, soroban_1.resolveNetworkConfig)(network);
|
|
267
|
+
const config = (0, soroban_1.resolveNetworkConfig)(network, sorobanRpcUrl);
|
|
256
268
|
const amountBigInt = (0, soroban_1.toBigIntAmount)(rawAmount, 'rawAmount');
|
|
257
269
|
const amountScVal = (0, stellar_sdk_1.nativeToScVal)(amountBigInt, { type: 'i128' });
|
|
258
270
|
const result = await (0, soroban_1.queryContract)(config, vaultAddress, 'convert_to_shares', [amountScVal]);
|
|
@@ -36,9 +36,24 @@ export declare const Stellar: {
|
|
|
36
36
|
* // Sign xdr with wallet (e.g. Freighter), then submit via adapter.submitTransaction()
|
|
37
37
|
* ```
|
|
38
38
|
*/
|
|
39
|
-
declare class StellarAdapter {
|
|
39
|
+
export declare class StellarAdapter {
|
|
40
40
|
private _network;
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Optional consumer-supplied Soroban RPC endpoint (e.g. a keyed Alchemy URL).
|
|
43
|
+
* When set it is the primary, with the SDK's public endpoints as failover.
|
|
44
|
+
*/
|
|
45
|
+
private _sorobanRpcUrl?;
|
|
46
|
+
/**
|
|
47
|
+
* @param network - Stellar network to operate on; defaults to `'mainnet'`.
|
|
48
|
+
* @param options - Optional adapter configuration. Its `sorobanRpcUrl` field
|
|
49
|
+
* overrides the Soroban RPC endpoint (e.g. a keyed Alchemy URL): it becomes
|
|
50
|
+
* the primary with the SDK's built-in public endpoints kept behind it as
|
|
51
|
+
* failover, and a per-call `sorobanRpcUrl` (on the deposit/redeem params)
|
|
52
|
+
* takes precedence over this adapter-level one.
|
|
53
|
+
*/
|
|
54
|
+
constructor(network?: IStellarNetwork, options?: {
|
|
55
|
+
sorobanRpcUrl?: string;
|
|
56
|
+
});
|
|
42
57
|
get network(): IStellarNetwork;
|
|
43
58
|
isStellarAddress(address: string): boolean;
|
|
44
59
|
getExplorerLink(id: string, type?: 'contract' | 'account' | 'tx'): string;
|
|
@@ -41,7 +41,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
41
41
|
};
|
|
42
42
|
})();
|
|
43
43
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.Stellar = void 0;
|
|
44
|
+
exports.StellarAdapter = exports.Stellar = void 0;
|
|
45
45
|
const StellarConstants = __importStar(require("./constants"));
|
|
46
46
|
const StellarGetters = __importStar(require("./getters"));
|
|
47
47
|
const StellarActions = __importStar(require("./actions"));
|
|
@@ -70,8 +70,22 @@ exports.Stellar = {
|
|
|
70
70
|
*/
|
|
71
71
|
class StellarAdapter {
|
|
72
72
|
_network;
|
|
73
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Optional consumer-supplied Soroban RPC endpoint (e.g. a keyed Alchemy URL).
|
|
75
|
+
* When set it is the primary, with the SDK's public endpoints as failover.
|
|
76
|
+
*/
|
|
77
|
+
_sorobanRpcUrl;
|
|
78
|
+
/**
|
|
79
|
+
* @param network - Stellar network to operate on; defaults to `'mainnet'`.
|
|
80
|
+
* @param options - Optional adapter configuration. Its `sorobanRpcUrl` field
|
|
81
|
+
* overrides the Soroban RPC endpoint (e.g. a keyed Alchemy URL): it becomes
|
|
82
|
+
* the primary with the SDK's built-in public endpoints kept behind it as
|
|
83
|
+
* failover, and a per-call `sorobanRpcUrl` (on the deposit/redeem params)
|
|
84
|
+
* takes precedence over this adapter-level one.
|
|
85
|
+
*/
|
|
86
|
+
constructor(network = 'mainnet', options) {
|
|
74
87
|
this._network = network;
|
|
88
|
+
this._sorobanRpcUrl = options?.sorobanRpcUrl;
|
|
75
89
|
}
|
|
76
90
|
get network() {
|
|
77
91
|
return this._network;
|
|
@@ -90,6 +104,8 @@ class StellarAdapter {
|
|
|
90
104
|
return StellarActions.handleStellarDeposit({
|
|
91
105
|
...params,
|
|
92
106
|
network: this._network,
|
|
107
|
+
// A per-call override (params.sorobanRpcUrl) wins over the adapter-level one.
|
|
108
|
+
sorobanRpcUrl: params.sorobanRpcUrl ?? this._sorobanRpcUrl,
|
|
93
109
|
});
|
|
94
110
|
}
|
|
95
111
|
/**
|
|
@@ -100,6 +116,8 @@ class StellarAdapter {
|
|
|
100
116
|
return StellarActions.handleStellarRedeem({
|
|
101
117
|
...params,
|
|
102
118
|
network: this._network,
|
|
119
|
+
// A per-call override (params.sorobanRpcUrl) wins over the adapter-level one.
|
|
120
|
+
sorobanRpcUrl: params.sorobanRpcUrl ?? this._sorobanRpcUrl,
|
|
103
121
|
});
|
|
104
122
|
}
|
|
105
123
|
/**
|
|
@@ -129,7 +147,7 @@ class StellarAdapter {
|
|
|
129
147
|
* ```
|
|
130
148
|
*/
|
|
131
149
|
async submitTransaction(signedXdr) {
|
|
132
|
-
return StellarSubmit.submitStellarTransaction(signedXdr, this._network);
|
|
150
|
+
return StellarSubmit.submitStellarTransaction(signedXdr, this._network, this._sorobanRpcUrl);
|
|
133
151
|
}
|
|
134
152
|
/**
|
|
135
153
|
* Get user's vault share balance.
|
|
@@ -140,7 +158,7 @@ class StellarAdapter {
|
|
|
140
158
|
* a redeem MUST refuse rather than trust it (see AUGUST-6381).
|
|
141
159
|
*/
|
|
142
160
|
async getUserPosition(vaultAddress, walletAddress) {
|
|
143
|
-
return StellarGetters.getStellarUserPosition(vaultAddress, walletAddress, this._network);
|
|
161
|
+
return StellarGetters.getStellarUserPosition(vaultAddress, walletAddress, this._network, this._sorobanRpcUrl);
|
|
144
162
|
}
|
|
145
163
|
/**
|
|
146
164
|
* Preview how many vault shares a deposit amount would yield.
|
|
@@ -149,8 +167,9 @@ class StellarAdapter {
|
|
|
149
167
|
* @returns Raw share amount as a string, or null if query fails.
|
|
150
168
|
*/
|
|
151
169
|
async convertToShares(vaultAddress, rawAmount) {
|
|
152
|
-
return StellarGetters.convertToShares(vaultAddress, rawAmount, this._network);
|
|
170
|
+
return StellarGetters.convertToShares(vaultAddress, rawAmount, this._network, this._sorobanRpcUrl);
|
|
153
171
|
}
|
|
154
172
|
}
|
|
173
|
+
exports.StellarAdapter = StellarAdapter;
|
|
155
174
|
exports.default = StellarAdapter;
|
|
156
175
|
//# sourceMappingURL=index.js.map
|
|
@@ -8,14 +8,101 @@ import { type xdr, rpc } from '@stellar/stellar-sdk';
|
|
|
8
8
|
import type { IStellarNetwork } from './types';
|
|
9
9
|
/** Resolved network configuration for Soroban RPC calls. */
|
|
10
10
|
export interface ISorobanNetworkConfig {
|
|
11
|
+
/** Primary endpoint — the first of {@link rpcUrls}; kept for convenience. */
|
|
11
12
|
rpcUrl: string;
|
|
13
|
+
/** Ordered endpoints for health-gated failover: primary first, fallbacks after. */
|
|
14
|
+
rpcUrls: readonly string[];
|
|
12
15
|
passphrase: string;
|
|
13
16
|
}
|
|
14
17
|
export declare function createServer(rpcUrl: string): rpc.Server;
|
|
15
18
|
/**
|
|
16
|
-
* Resolve RPC
|
|
19
|
+
* Resolve the ordered RPC endpoints and network passphrase for a Stellar network.
|
|
20
|
+
*
|
|
21
|
+
* When `overrideRpcUrl` is supplied (e.g. a consumer's keyed Alchemy endpoint),
|
|
22
|
+
* it becomes the primary with the built-in public endpoints kept behind it as
|
|
23
|
+
* failover — so opting into a premium provider still degrades to the public
|
|
24
|
+
* network rather than becoming a new single point of failure. The endpoint is
|
|
25
|
+
* injected rather than hardcoded, so the adapter depends on configuration, not a
|
|
26
|
+
* constant.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolveNetworkConfig(network: IStellarNetwork, overrideRpcUrl?: string): ISorobanNetworkConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Clear the health-check cache and any in-flight probes. Test-only seam.
|
|
31
|
+
* @internal
|
|
32
|
+
*/
|
|
33
|
+
export declare function resetHealthyServerCache(): void;
|
|
34
|
+
/**
|
|
35
|
+
* Host-only view of an RPC URL, safe for logs. Keyed provider endpoints put the
|
|
36
|
+
* API key in the path (e.g. Alchemy `/v2/<key>`), so logging the raw URL would
|
|
37
|
+
* leak the secret into SDK logs / crash reporters. Returns just protocol+host.
|
|
38
|
+
* @internal
|
|
39
|
+
*/
|
|
40
|
+
export declare function redactRpcUrl(url: string): string;
|
|
41
|
+
/**
|
|
42
|
+
* Return a Soroban RPC server backed by a healthy endpoint for `config`. Thin
|
|
43
|
+
* wrapper over {@link resolveHealthyServer} for callers (e.g. submission) that
|
|
44
|
+
* only need the server, not the URL it resolved to.
|
|
45
|
+
*
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
export declare function getHealthyServer(config: ISorobanNetworkConfig): Promise<rpc.Server>;
|
|
49
|
+
/**
|
|
50
|
+
* A thrown RPC error is retryable on another endpoint UNLESS it is one of our
|
|
51
|
+
* typed domain errors. Those mark a *deterministic* outcome — a contract revert,
|
|
52
|
+
* an unfunded account, archived state needing restore, a bad input, or a local
|
|
53
|
+
* assembly failure — which reproduces identically on every node, so retrying
|
|
54
|
+
* elsewhere only wastes calls. Any other throw (a transport hang/reset, or a
|
|
55
|
+
* method-specific node error from an endpoint that still answered `getHealth()`)
|
|
56
|
+
* is worth the next endpoint.
|
|
57
|
+
*
|
|
58
|
+
* Exported so an operation with different semantics (e.g. an idempotency-aware
|
|
59
|
+
* submission path) can compose or replace this policy via
|
|
60
|
+
* {@link FailoverOptions.isRetryable} — extension without editing the core.
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
export declare function isRetryableRpcError(err: unknown): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Whether a simulation *error* string is a node/infrastructure failure (which
|
|
66
|
+
* clears on another endpoint) rather than a genuine contract revert (which
|
|
67
|
+
* reproduces on every node). `isSimulationError` alone can't tell these apart —
|
|
68
|
+
* both arrive as a populated `error` field — so callers use this to decide
|
|
69
|
+
* whether to fail over or treat the error as terminal.
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export declare function isRetryableSimulationError(errorText: string): boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Tunables for {@link withEndpointFailover}, injected with sensible defaults so
|
|
75
|
+
* a new operation can vary retry policy or latency budget without editing the
|
|
76
|
+
* failover core (Open/Closed at the call site).
|
|
77
|
+
*/
|
|
78
|
+
export interface FailoverOptions {
|
|
79
|
+
/** Which thrown errors get the next endpoint. Defaults to {@link isRetryableRpcError}. */
|
|
80
|
+
isRetryable?: (err: unknown) => boolean;
|
|
81
|
+
/** Per-attempt timeout in ms. Defaults to {@link RPC_OPERATION_TIMEOUT_MS}. */
|
|
82
|
+
timeoutMs?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Run an idempotent, side-effect-free `operation` (a read or a tx build) against
|
|
86
|
+
* a Soroban endpoint, failing over to the remaining endpoints on a retryable
|
|
87
|
+
* failure.
|
|
88
|
+
*
|
|
89
|
+
* {@link getHealthyServer} only proves an endpoint answered `getHealth()`, and
|
|
90
|
+
* caches that choice for {@link HEALTHY_SERVER_TTL_MS} — but the node can still
|
|
91
|
+
* hang or return a method-specific error on the *real* call. So we run the op on
|
|
92
|
+
* the health-gated server first (the fast, cached path) and, on a retryable
|
|
93
|
+
* failure, drop that cached choice and retry the op against every endpoint in
|
|
94
|
+
* priority order. Deterministic contract/domain errors short-circuit (see
|
|
95
|
+
* {@link isRetryableRpcError}); each attempt is time-boxed so a hung node can't
|
|
96
|
+
* stall the loop.
|
|
97
|
+
*
|
|
98
|
+
* The `operation` is a strategy (dependency-injected), so new read/build calls
|
|
99
|
+
* reuse this failover without changing it; `options` keeps retry policy and
|
|
100
|
+
* timeout open for extension. Submission is deliberately NOT routed through here
|
|
101
|
+
* — re-sending a signed transaction across endpoints risks a double-submit, so
|
|
102
|
+
* it needs sequence/DUPLICATE-based idempotency rather than blind retry.
|
|
103
|
+
* @internal
|
|
17
104
|
*/
|
|
18
|
-
export declare function
|
|
105
|
+
export declare function withEndpointFailover<T>(config: ISorobanNetworkConfig, method: string, operation: (server: rpc.Server) => Promise<T>, options?: FailoverOptions): Promise<T>;
|
|
19
106
|
/**
|
|
20
107
|
* Validate and convert a string amount to a non-negative BigInt.
|
|
21
108
|
* Throws a descriptive error if the value is not a valid non-negative integer string.
|