/** * Shared Soroban RPC utilities * * Common transaction building and read-only query helpers used by * actions, submit, and getters modules. */ import { type xdr, rpc } from '@stellar/stellar-sdk'; import type { IStellarNetwork } from './types'; /** Resolved network configuration for Soroban RPC calls. */ export interface ISorobanNetworkConfig { /** Primary endpoint — the first of {@link rpcUrls}; kept for convenience. */ rpcUrl: string; /** Ordered endpoints for health-gated failover: primary first, fallbacks after. */ rpcUrls: readonly string[]; passphrase: string; } export declare function createServer(rpcUrl: string): rpc.Server; /** * Resolve the ordered RPC endpoints and network passphrase for a Stellar network. * * When `overrideRpcUrl` is supplied (e.g. a consumer's keyed Alchemy endpoint), * it becomes the primary with the built-in public endpoints kept behind it as * failover — so opting into a premium provider still degrades to the public * network rather than becoming a new single point of failure. The endpoint is * injected rather than hardcoded, so the adapter depends on configuration, not a * constant. */ export declare function resolveNetworkConfig(network: IStellarNetwork, overrideRpcUrl?: string): ISorobanNetworkConfig; /** * Clear the health-check cache and any in-flight probes. Test-only seam. * @internal */ export declare function resetHealthyServerCache(): void; /** * Host-only view of an RPC URL, safe for logs. Keyed provider endpoints put the * API key in the path (e.g. Alchemy `/v2/`), so logging the raw URL would * leak the secret into SDK logs / crash reporters. Returns just protocol+host. * @internal */ export declare function redactRpcUrl(url: string): string; /** * Return a Soroban RPC server backed by a healthy endpoint for `config`. Thin * wrapper over {@link resolveHealthyServer} for callers (e.g. submission) that * only need the server, not the URL it resolved to. * * @internal */ export declare function getHealthyServer(config: ISorobanNetworkConfig): Promise; /** * A thrown RPC error is retryable on another endpoint UNLESS it is one of our * typed domain errors. Those mark a *deterministic* outcome — a contract revert, * an unfunded account, archived state needing restore, a bad input, or a local * assembly failure — which reproduces identically on every node, so retrying * elsewhere only wastes calls. Any other throw (a transport hang/reset, or a * method-specific node error from an endpoint that still answered `getHealth()`) * is worth the next endpoint. * * Exported so an operation with different semantics (e.g. an idempotency-aware * submission path) can compose or replace this policy via * {@link FailoverOptions.isRetryable} — extension without editing the core. * * Named distinctly from `core/helpers/chain-error`'s `isRetryableRpcError` * (the EVM transport classifier, deliberately public) — the internal-dts * leak check matches `@internal` tags by name across the whole `src.ts` tree, * so a same-named pair would make it flag the public EVM one as a leak. * @internal */ export declare function isRetryableSorobanRpcError(err: unknown): boolean; /** * Whether a simulation *error* string is a node/infrastructure failure (which * clears on another endpoint) rather than a genuine contract revert (which * reproduces on every node). `isSimulationError` alone can't tell these apart — * both arrive as a populated `error` field — so callers use this to decide * whether to fail over or treat the error as terminal. * @internal */ export declare function isRetryableSimulationError(errorText: string): boolean; /** * Tunables for {@link withEndpointFailover}, injected with sensible defaults so * a new operation can vary retry policy or latency budget without editing the * failover core (Open/Closed at the call site). */ export interface FailoverOptions { /** Which thrown errors get the next endpoint. Defaults to {@link isRetryableSorobanRpcError}. */ isRetryable?: (err: unknown) => boolean; /** Per-attempt timeout in ms. Defaults to {@link RPC_OPERATION_TIMEOUT_MS}. */ timeoutMs?: number; } /** * Run an idempotent, side-effect-free `operation` (a read or a tx build) against * a Soroban endpoint, failing over to the remaining endpoints on a retryable * failure. * * {@link getHealthyServer} only proves an endpoint answered `getHealth()`, and * caches that choice for {@link HEALTHY_SERVER_TTL_MS} — but the node can still * hang or return a method-specific error on the *real* call. So we run the op on * the health-gated server first (the fast, cached path) and, on a retryable * failure, drop that cached choice and retry the op against every endpoint in * priority order. Deterministic contract/domain errors short-circuit (see * {@link isRetryableSorobanRpcError}); each attempt is time-boxed so a hung node can't * stall the loop. * * The `operation` is a strategy (dependency-injected), so new read/build calls * reuse this failover without changing it; `options` keeps retry policy and * timeout open for extension. Submission is deliberately NOT routed through here * — re-sending a signed transaction across endpoints risks a double-submit, so * it needs sequence/DUPLICATE-based idempotency rather than blind retry. * @internal */ export declare function withEndpointFailover(config: ISorobanNetworkConfig, method: string, operation: (server: rpc.Server) => Promise, options?: FailoverOptions): Promise; /** * Validate and convert a string amount to a non-negative BigInt. * Throws a descriptive error if the value is not a valid non-negative integer string. */ export declare function toBigIntAmount(value: string, label: string): bigint; export declare function queryContract(config: ISorobanNetworkConfig, contractId: string, method: string, args?: xdr.ScVal[]): Promise; /** * Build an unsigned Soroban contract invocation transaction. * Fetches the real source account from the network (the account must exist and be funded). * Simulates via Soroban RPC to attach resource footprint and auth entries, * using MAX_FEE_STROOPS as the fee ceiling and incorporating the simulated resource fee. * * Thrown errors carry `context.stage` naming where the build broke: * `'simulation'` (the contract itself rejected the call), `'restore-required'`, * `'assembly'`, or `'rpc-failover'` (no endpoint answered). Callers use it to * separate a vault-level rejection from a transport problem — see the curator * alerting in `handleStellarRedeem`. Validation errors (e.g. * `ACCOUNT_NOT_FUNDED`) carry no stage, so treat a missing one as "not a * vault-level failure" rather than assuming the field is always present. */ export declare function buildSorobanTx(config: ISorobanNetworkConfig, sourceAddress: string, contractId: string, method: string, args: xdr.ScVal[]): Promise;