Skip to content

About

Stellar API SDK for .NET 8

Resources

Code of conduct

Contributing

Security policy

Stars

10 stars

Watchers

2 watching

Forks

Latest commit

 

History

1,212 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

dotnet-stellar-sdk

Stellar API SDK for .NET

Report Bug · Request Feature · Report Security Vulnerability

About The Project

dotnet-stellar-sdk is a .NET library for communicating with a Stellar Horizon server or Stellar RPC server.

It is used for building Stellar apps.

This project originated as a full port of the official Java SDK API.

The SEP (Stellar Ecosystem Proposal) protocol implementations were ported from the Flutter SDK.

Features

  • Built-in HTTP resilience for Stellar - Opt-in retries for 408/429/5xx tuned for Horizon (ForHorizon()) and Stellar RPC / Soroban (ForSoroban()), with Retry-After honored (capped by MaxRetryAfterDelay, default 1 minute)
  • Configurable - Customize retry count, delays, jitter, status codes, and method filter
  • Full Stellar Support - Works with both Horizon API and Stellar RPC servers

Installation

The stellar-dotnet-sdk library is bundled in a NuGet package.

Visual Studio

JetBrains Rider

Other

Platform support

The stellar-dotnet-sdk and stellar-dotnet-sdk-xdr packages multi-target the following frameworks:

Target framework Typical platforms Crypto backend
net10.0 .NET 10 apps NSec
net8.0 .NET 8 apps NSec
netstandard2.1 Unity 6, Unity 2022.3 (see compiler note below), Tizen 5.5+, portable libraries Sodium.Core

NuGet resolves the best matching assembly for your project automatically.

.NET MAUI: validated on an Android emulator and four physical Android devices; iOS is not validated yet. See MAUI compatibility for results, required workarounds (including for the published 15.1.0 package on Android), trimming settings and known limitations.

TFM-specific API notes

  • SEP-0009 date fields (BirthDate, IdIssueDate, IdExpirationDate, RegistrationDate): DateOnly? on net8.0 / net10.0; string? (ISO yyyy-MM-dd) on netstandard2.1. JSON wire format is identical across TFMs.
  • Synchronous HttpClient.Send resilience: on net8.0 / net10.0, RetryingHttpMessageHandler overrides sync Send with the full retry pipeline. On the netstandard2.1 assembly (also what net5–net7 apps resolve), sync Send throws NotSupportedException instead of silently bypassing retries — use SendAsync.
  • Unity compiler note (required members): many SDK request/response models declare C# required members. Constructing them from your code needs a compiler that understands required: Unity 6 qualifies; Unity 2022.3's bundled compiler (Roslyn 4.1) does not — member initialization of those types fails to compile there unless you upgrade the compiler (e.g. UnityRoslynUpdater). Deserialization and APIs without required members are unaffected.

Examples

The SDK includes numerous example applications showcasing its features. Explore these standalone projects:

HTTP retry & resilience

The SDK ships with opt-in retry support tuned for Stellar's HTTP surfaces (Horizon and Stellar RPC). Pick the preset that matches the server you're calling:

// For Horizon — GET queries and SubmitTransaction()
var resilience = HttpResilienceOptionsPresets.ForHorizon();
var server = new Server("https://horizon-testnet.stellar.org", resilience, bearerToken: null);

// For Stellar RPC (Soroban)
var rpcResilience = HttpResilienceOptionsPresets.ForSoroban();
var rpcClient = new DefaultStellarSdkHttpClient(resilienceOptions: rpcResilience);
var rpcServer = new StellarRpcServer("https://soroban-testnet.stellar.org", rpcClient);

Both retry HTTP 408, 429, 500, 502, 503, 504 on the Stellar requests they're scoped to (see the matrix below) with exponential backoff, jitter, and Retry-After honored (capped by MaxRetryAfterDelay, default 1 minute). They differ in retry budget and delay range.

Which Stellar operations are retried?

HttpResilienceOptions.RetryHttpMethods is an explicit whitelist. By default it contains only the RFC-safe methods (GET, HEAD, OPTIONS). Each preset opts in to the additional methods it needs.

Stellar operation HTTP method Retried by ForHorizon() Retried by ForSoroban()
Horizon queries (Server.Accounts, Ledgers, Operations, Effects, Root, …) GET ✅ ✅
Server.SubmitTransaction() / SubmitTransactionAsync() POST ✅ n/a
Every StellarRpcServer method — read (getLatestLedger, simulateTransaction, getEvents, …) or write (sendTransaction) POST n/a ✅
SEP-6 PATCH /transactions/{id} PATCH ❌ ❌
SEP-38 POST /quote (QuoteService.PostQuoteAsync) POST ⚠️ yes — don't use (see below) ⚠️ yes — don't use (see below)

Retrying SubmitTransaction() is safe on Stellar even though it is HTTP POST: every envelope is uniquely keyed by transaction hash plus the source account's sequence number, so a resubmit either returns the cached server result or fails with tx_bad_seq — there is no double-spend window. If the original submission had already committed when the transient failure occurred, the retry surfaces tx_bad_seq and your code should look up the transaction by its hash to recover the original result.

⚠️ Do not wire ForHorizon() or ForSoroban() into SEP service clients (ClientWebAuth, InteractiveService, TransferServerService, KycService, UriScheme, QuoteService, StellarToml with a custom HttpClient). Specific SEP POST endpoints are non-idempotent by spec and silently retrying them creates real problems:

  • SEP-10 POST /auth — the spec says: "The Server should not provide more than one JWT for a specific challenge transaction." The challenge is one-shot. On transient failure, request a fresh challenge — don't resubmit the same body.
  • SEP-24 POST /transactions/{deposit,withdraw}/interactive — each call mints a fresh transaction_id. Retrying creates a duplicate transaction record and an orphaned interactive URL. The spec defines no idempotency-key mechanism.
  • SEP-6 PATCH /transactions/{id} — not in the SEP-6 master spec; anchor-vendor extension that mutates KYC state. Treat as non-idempotent.
  • SEP-7 callback POST (UriScheme.SubmitToCallbackAsync, SignAndSubmitTransactionAsync) — the spec says nothing about idempotency; the POST delivers a signed transaction to a URL the requester chose, and a retry delivers it again. Use NoRetry() (the default) for UriScheme: even transport retries replay it.
  • SEP-12 POST /customer/files — each call stores the upload under a fresh file_id. Retrying after the anchor already stored it leaves an orphaned duplicate file.
  • SEP-38 POST /quote — each call creates a new firm quote that the anchor holds in reserve until it expires. Both presets retry POST on a 408, 429, 500, 502, 503 or 504 answer, so one call can reserve two quotes.

For the other SEP HttpClients, use WithConnectionRetries() (transport retries only) or build a custom HttpResilienceOptions whose RetryHttpMethods contains only GET/HEAD/OPTIONS. Note that transport (connection-failure) retries apply to all HTTP methods: a POST whose response was lost may already have been processed server-side, so even WithConnectionRetries() carries a small replay window. If that window is unacceptable, use NoRetry() and recover at the application level (e.g. request a fresh SEP-10 challenge).

Presets

  • ForHorizon() — for the Stellar Horizon API. Retries the transient HTTP status codes on Horizon's GET queries and SubmitTransaction() POST. 3 retries, 200ms–5s exponential backoff with jitter, honors Retry-After. PATCH/PUT/DELETE are not retried.
  • ForSoroban() — for Stellar RPC (Soroban). Same status-code set as ForHorizon(); adds POST to the retry-method whitelist (every JSON-RPC call is POST). Higher retry budget (5) and longer delays (up to 15s) — tuned for long-running polling workflows like getTransaction(hash). For latency-sensitive one-off calls (e.g. simulateTransaction), override MaxRetryCount/MaxDelay.
  • WithConnectionRetries() — transport-level retries only (HttpRequestException and timeouts thrown inside the handler chain; an HttpClient.Timeout cancellation is never retried). No status-code retries, but transport retries apply to all HTTP methods — see the SEP warning above for the replay window this implies on one-shot endpoints.
  • LowLatency() — minimal retries and short delays (trading bots, latency-sensitive workloads).
  • NoRetry() — no retries at all.

The retry pipeline observes responses inside the HTTP handler chain, so it triggers before status codes are translated into typed exceptions like TooManyRequestsException and ServiceUnavailableException. Those exceptions also expose a RetryAfterDelay (TimeSpan?) accessor for direct inspection when needed.

A note on Retry-After for Stellar services. Horizon sends Retry-After only on HTTP 429 (always as an integer number of seconds); on HTTP 503 it relies on the client's configured backoff. Stellar RPC (Soroban) does not send Retry-After at all, so when it reports overload as HTTP 503/504 the retry pipeline falls back to exponential backoff. The parser still accepts the RFC 7231 HTTP-date form because upstream proxies and CDNs (Cloudflare, nginx, API gateways) may rewrite the header.

JSON-RPC errors are not retried. Stellar RPC reports request-scoped failures — an out-of-range startLedger, malformed parameters, a TTL ledger key queried directly — as a JSON-RPC error body delivered with HTTP status 200. The retry pipeline keys on the status code, and 200 is not a failure, so these never enter it: neither RetryHttpStatusCodes nor AdditionalRetriableExceptionTypes can reach them and no backoff applies. They surface as SorobanRpcException, carrying the server's own error code and message, and are meant to be handled at the call site.

Documentation

Documentation is available here.

Community & Support

Contributing

For information on how to contribute, please refer to our contribution guide.

License

dotnet-stellar-sdk is licensed under an Apache-2.0 license. See the LICENSE file for details.

About

Stellar API SDK for .NET 8

Resources

Code of conduct

Contributing

Security policy

Stars

10 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages