NSpark is a first-class .NET SDK for the Spark Lightning Network protocol. Send and receive Bitcoin over Lightning — BOLT11 invoices, FROST threshold signing, deposits, withdrawals, Spark-to-Spark transfers — from any modern .NET application with a clean, DI-friendly API.
dotnet add package NSpark- Real Lightning, not a wrapper. Talks directly to Spark Signing Operators over gRPC and to your SSP over GraphQL — no daemon to babysit, no node to operate.
- Modern .NET.
net8.0/net9.0/net10.0, nullable reference types, async-first,IHttpClientFactory,IOptions<T>,ILogger<T>,OpenTelemetry. Plays nicely with ASP.NET Core, the generic host, and minimal APIs. - Cryptographically sound. BIP-39/BIP-32 derivation via NBitcoin, FROST threshold signing via the audited
spark_frostRust library through UniFFI bindings, ECIES share encryption, tagged-hash domain separation, BOLT11 description-hash support for NIP-57 zaps. - Observability by default. Structured logging with documented
EventIds, anActivitySourcenamed"NSpark", and aMeterwith counters/histograms — all of it inactive unless you subscribe. - Resilient. Pluggable Polly v8 retry/backoff/breaker on transient gRPC failures, bounded auth token cache with TTL eviction.
- Open source. MIT-licensed, single-package distribution with reproducible builds and SBOM in every release.
using NSpark;
var options = Microsoft.Extensions.Options.Options.Create(new SparkOptions
{
Network = SparkNetwork.Mainnet,
});
using var http = new HttpClient();
await using var spark = new SparkConnection(options, http);
// Use a real mnemonic in production — derive once and store securely.
const string mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
var wallet = await spark.CreateWalletAsync(mnemonic);
// Receive
var invoice = await wallet.CreateLightningInvoiceAsync(amountSats: 21_000, memo: "hello world");
Console.WriteLine(invoice.PaymentRequest);
// Send
await wallet.PayLightningInvoiceAsync("lnbc...");
// Balance
var balance = await wallet.GetBalanceAsync();
Console.WriteLine($"Available: {balance.SatsBalance.Available} sats");
Console.WriteLine($"Owned: {balance.SatsBalance.Owned} sats (incl. locked in-flight)");
Console.WriteLine($"Incoming: {balance.SatsBalance.Incoming} sats (pending claim)");// Program.cs
builder.Services.AddSpark(options =>
{
options.Network = SparkNetwork.Mainnet;
});
// Optional: background lifecycle service for token refresh hooks
builder.Services.AddHostedService<NSpark.Hosting.SparkHostedService>();// In any controller / service
public class InvoicesController(SparkConnection spark) : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Create(long sats, string memo, CancellationToken ct)
{
var wallet = await spark.CreateWalletAsync(Environment.GetEnvironmentVariable("WALLET_MNEMONIC")!, ct: ct);
var invoice = await wallet.CreateLightningInvoiceAsync(sats, memo, ct: ct);
return Ok(invoice);
}
}NSpark ships a native FROST signing library (libspark_frost) for the following runtime identifiers:
| RID | Status |
|---|---|
osx-arm64 |
✅ supported |
osx-x64 |
✅ supported |
linux-x64 |
✅ supported |
linux-arm64 |
✅ supported |
win-x64 |
✅ supported |
win-arm64 |
✅ supported |
SHA-256 hashes for every shipped binary are published in each GitHub release and packed at runtimes/SHA256SUMS.txt inside the NuGet.
| Topic | Link |
|---|---|
| Getting started | docs/getting-started.md |
| Architecture & threading | docs/architecture.md |
| Receiving Lightning payments | docs/lightning/receiving-invoices.md |
| Sending Lightning payments | docs/lightning/paying-invoices.md |
| NIP-57 zaps (description hash) | docs/lightning/description-hash.md |
| Custom signers / HSM | docs/signer.md |
| Deposits & withdrawals | docs/deposits.md, docs/withdrawals.md |
| Recovery snapshots & leaf maintenance | docs/recovery.md |
| Configuration reference | docs/configuration.md |
| Logging events | docs/logging.md |
| OpenTelemetry / observability | docs/observability.md |
| Error handling & retry | docs/error-handling.md |
| Trust model | docs/trust-model.md |
| Native library build | docs/native-build.md |
| FAQ & glossary | docs/faq.md, docs/glossary.md |
Working examples live under samples/:
samples/QuickStart— console app: mnemonic → wallet → invoice → balancesamples/AspNetCore— minimal-API receiver wired with OpenTelemetry (see roadmap)samples/CustomSigner— implementingISparkSigneragainst an HSM (see roadmap)
NSpark targets a 1.0.0 release on NuGet. Until then, versions are published as pre-releases under the same package id. See CHANGELOG.md.
| Area | v1.0 |
|---|---|
| BOLT11 send / receive | ✅ |
| Description-hash (NIP-57 zaps) | ✅ |
| On-chain deposits / withdrawals | ✅ |
| Spark-to-Spark transfers | ✅ |
| Unilateral-exit recovery snapshots | ✅ |
| Leaf renewal & consolidation | ✅ |
| FROST signing via Rust UniFFI | ✅ |
| OpenTelemetry tracing + metrics | ✅ |
| Polly v8 resilience | ✅ |
| Multi-target net8/9/10 | ✅ |
| BOLT12 offers | ❌ not yet — open a discussion if you need it |
| Native AOT | 🚧 v1.1 |
This SDK handles Bitcoin keys. Read SECURITY.md before deploying in production, and review docs/trust-model.md for the threat model — including the default Signing Operators and SSP that NSpark trusts. To report a vulnerability privately, see the disclosure process in SECURITY.md.
Issues, discussions, and pull requests are welcome. See CONTRIBUTING.md for build setup, coding conventions, and the PR checklist. Please read CODE_OF_CONDUCT.md before participating.
NSpark is licensed under the MIT License. Third-party dependencies and their licenses are enumerated in THIRD_PARTY_NOTICES.md. © OrkLabs S.A.S. and NSpark contributors.