NArk.Storage.EfCore
1.0.141-beta
dotnet add package NArk.Storage.EfCore --version 1.0.141-beta
NuGet\Install-Package NArk.Storage.EfCore -Version 1.0.141-beta
<PackageReference Include="NArk.Storage.EfCore" Version="1.0.141-beta" />
<PackageVersion Include="NArk.Storage.EfCore" Version="1.0.141-beta" />
<PackageReference Include="NArk.Storage.EfCore" />
paket add NArk.Storage.EfCore --version 1.0.141-beta
#r "nuget: NArk.Storage.EfCore, 1.0.141-beta"
#:package NArk.Storage.EfCore@1.0.141-beta
#addin nuget:?package=NArk.Storage.EfCore&version=1.0.141-beta&prerelease
#tool nuget:?package=NArk.Storage.EfCore&version=1.0.141-beta&prerelease
NArk .NET SDK
A .NET SDK for building applications on Arkade — a Bitcoin virtual execution layer that enables instant, low-cost, programmable off-chain transactions using virtual UTXOs (VTXOs).
Packages
| Package | Description |
|---|---|
| NArk.Abstractions | Interfaces and domain types (IVtxoStorage, IContractStorage, IWalletProvider, ArkCoin, ArkVtxo, etc.) |
| NArk.Core | Core services: spending, batch management, VTXO sync, sweeping, wallet infrastructure, gRPC transport |
| NArk.Swaps | Boltz swap integration for BTC-to-Ark and Ark-to-BTC chain/submarine swaps |
| NArk.Storage.EfCore | Entity Framework Core storage implementations (provider-agnostic — works with PostgreSQL, SQLite, etc.) |
| NArk | Meta-package that pulls in NArk.Core + NArk.Swaps |
Quick Start
Install
dotnet add package NArk # Core + Swaps
dotnet add package NArk.Storage.EfCore # EF Core persistence
Minimal Setup with Generic Host
using NArk.Hosting;
using NArk.Core.Wallet;
using NArk.Storage.EfCore;
using NArk.Storage.EfCore.Hosting;
var builder = Host.CreateDefaultBuilder(args)
.AddArk()
.WithVtxoStorage<EfCoreVtxoStorage>()
.WithContractStorage<EfCoreContractStorage>()
.WithIntentStorage<EfCoreIntentStorage>()
.WithWalletProvider<DefaultWalletProvider>()
.WithSafetyService<YourSafetyService>()
.WithTimeProvider<YourChainTimeProvider>()
.OnMainnet()
.EnableSwaps();
// Register your DbContext and EF Core storage
builder.ConfigureServices((_, services) =>
{
services.AddDbContextFactory<YourDbContext>(opts =>
opts.UseNpgsql(connectionString));
services.AddArkEfCoreStorage<YourDbContext>();
});
var app = builder.Build();
await app.RunAsync();
Setup with IServiceCollection (plugin/non-host scenarios)
using NArk.Hosting;
using NArk.Core.Wallet;
using NArk.Storage.EfCore.Hosting;
services.AddArkCoreServices();
services.AddArkNetwork(ArkNetworkConfig.Mainnet);
services.AddArkSwapServices();
services.AddDbContextFactory<YourDbContext>(opts =>
opts.UseNpgsql(connectionString));
services.AddArkEfCoreStorage<YourDbContext>();
// Register remaining required services
services.AddSingleton<IWalletProvider, DefaultWalletProvider>();
services.AddSingleton<ISafetyService, YourSafetyService>();
services.AddSingleton<IChainTimeProvider, YourChainTimeProvider>();
Architecture
NArk (meta-package)
├── NArk.Core
│ ├── Services (spending, batches, VTXO sync, sweeping, intents)
│ ├── Wallet (WalletFactory, signers, address providers)
│ ├── Hosting (DI extensions, ArkApplicationBuilder)
│ └── Transport (gRPC client for Ark server communication)
│
├── NArk.Swaps
│ ├── Boltz client (submarine & chain swaps)
│ └── Swap management service
│
└── NArk.Abstractions
├── Domain types (ArkCoin, ArkVtxo, ArkContract, ArkAddress, etc.)
├── Storage interfaces (IVtxoStorage, IContractStorage, IIntentStorage)
└── Wallet interfaces (IWalletProvider, IArkadeWalletSigner)
NArk.Storage.EfCore (optional, provider-agnostic persistence)
├── EF Core entity mappings
├── Storage implementations
└── DI extension: AddArkEfCoreStorage<TDbContext>()
Wallet Management
The SDK supports two wallet types:
HD Wallets — BIP-39 mnemonic with BIP-86 taproot derivation (m/86'/cointype'/0'):
var serverInfo = await transport.GetServerInfoAsync();
var wallet = await WalletFactory.CreateWallet(
"abandon abandon abandon ... about", // BIP-39 mnemonic
destination: null,
serverInfo);
// wallet.WalletType == WalletType.HD
Single-Key Wallets — nostr nsec format (Bech32-encoded secp256k1 key):
var wallet = await WalletFactory.CreateWallet(
"nsec1...",
destination: null,
serverInfo);
// wallet.WalletType == WalletType.SingleKey
Save and load wallets through IWalletStorage:
await walletStorage.SaveWallet(wallet);
var loaded = await walletStorage.LoadWallet(wallet.Id);
var all = await walletStorage.LoadAllWallets();
Spending
Use ISpendingService to send Ark transactions:
// Automatic coin selection
var txId = await spendingService.Spend(
walletId,
outputs: [new ArkTxOut(recipientAddress, Money.Satoshis(10_000))]);
// Manual coin selection
var coins = await spendingService.GetAvailableCoins(walletId);
var txId = await spendingService.Spend(
walletId,
inputs: coins.Take(2).ToArray(),
outputs: [new ArkTxOut(recipientAddress, Money.Satoshis(5_000))]);
Assets
The SDK supports issuing, transferring, and burning assets on Ark. Assets are encoded as AssetGroup entries inside an OP_RETURN output (an "asset packet") attached to each Ark transaction. The asset ID is derived from {txid, groupIndex} after submission.
Issuance
Use IAssetManager to create new assets:
var result = await assetManager.IssueAsync(walletId,
new IssuanceParams(Amount: 1000));
// result.AssetId — the unique asset identifier
// result.ArkTxId — the Ark transaction that created it
Issue with metadata:
var result = await assetManager.IssueAsync(walletId,
new IssuanceParams(
Amount: 1000,
Metadata: new Dictionary<string, string>
{
{ "name", "My Token" },
{ "ticker", "MTK" },
{ "decimals", "8" }
}));
Controlled Issuance & Reissuance
A control asset acts as a minting key — only the holder can issue more supply:
// Issue a control asset (amount=1, acts as the minting authority)
var control = await assetManager.IssueAsync(walletId,
new IssuanceParams(Amount: 1));
// Issue a token controlled by that asset
var token = await assetManager.IssueAsync(walletId,
new IssuanceParams(Amount: 1000, ControlAssetId: control.AssetId));
// Reissue more supply later (requires holding the control asset)
await assetManager.ReissueAsync(walletId,
new ReissuanceParams(control.AssetId, Amount: 500));
Transfer
Asset transfers use the standard SpendingService.Spend() with ArkTxOut.Assets:
await spendingService.Spend(walletId,
[
new ArkTxOut(ArkTxOutType.Vtxo, serverInfo.Dust, recipientAddress)
{
Assets = [new ArkTxOutAsset(assetId, 400)]
}
]);
// Automatic coin selection handles BTC fees and asset change.
// Sender retains remaining units (e.g. 600 of 1000) as asset change.
Burn
Reduce the circulating supply of an asset:
await assetManager.BurnAsync(walletId,
new BurnParams(assetId, Amount: 400));
// Remaining 600 units are returned as change
Querying Assets
Check asset balances from local VTXO storage:
var coins = await spendingService.GetAvailableCoins(walletId);
foreach (var coin in coins.Where(c => c.Assets is { Count: > 0 }))
{
foreach (var asset in coin.Assets!)
Console.WriteLine($"Asset {asset.AssetId}: {asset.Amount} units");
}
Query asset details from the Ark server:
var details = await transport.GetAssetDetailsAsync(assetId);
// details.Supply — total circulating supply
// details.AssetId — the asset identifier
// details.Metadata — key-value metadata (if set during issuance)
Collaborative Exits (On-chain)
Move funds from Ark back to the Bitcoin base layer:
var btcTxId = await onchainService.InitiateCollaborativeExit(
walletId,
new ArkTxOut(bitcoinAddress, Money.Satoshis(50_000)));
Contracts
Derive receiving addresses and manage contracts:
// Derive a new receive contract (generates a new Ark address)
var contract = await contractService.DeriveContract(
walletId,
NextContractPurpose.Receive);
// The contract's script can be converted to an ArkAddress for display
EF Core Storage
NArk.Storage.EfCore provides ready-made storage implementations. It is provider-agnostic — no dependency on Npgsql or any specific database driver.
DbContext Setup
In your DbContext.OnModelCreating, call ConfigureArkEntities:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ConfigureArkEntities(opts =>
{
opts.Schema = "ark"; // default
// opts.WalletsTable = "Wallets"; // all table names configurable
});
}
}
Storage Options
ArkStorageOptions controls schema, table names, and provider-specific behavior:
services.AddArkEfCoreStorage<MyDbContext>(opts =>
{
opts.Schema = "my_schema";
// PostgreSQL-specific text search on contract metadata
opts.ContractSearchProvider = (query, searchText) =>
query.Where(c => EF.Functions.ILike(c.Metadata, $"%{searchText}%"));
});
Entities
| Entity | Table | Primary Key |
|---|---|---|
ArkWalletEntity |
Wallets |
Id |
ArkWalletContractEntity |
WalletContracts |
(Script, WalletId) |
VtxoEntity |
Vtxos |
(TransactionId, TransactionOutputIndex) |
ArkIntentEntity |
Intents |
IntentTxId |
ArkIntentVtxoEntity |
IntentVtxos |
(IntentTxId, VtxoTransactionId, VtxoTransactionOutputIndex) |
ArkSwapEntity |
Swaps |
(SwapId, WalletId) |
Networks
Pre-configured network environments:
// Fluent builder
builder.AddArk().OnMainnet();
builder.AddArk().OnMutinynet();
builder.AddArk().OnRegtest();
builder.AddArk().OnCustomGrpcArk("http://my-ark-server:7070");
// IServiceCollection
services.AddArkNetwork(ArkNetworkConfig.Mainnet);
services.AddArkNetwork(new ArkNetworkConfig(
ArkUri: "http://my-ark-server:7070",
BoltzUri: "http://my-boltz:9069/"));
Swaps (Boltz Integration)
Enable Bitcoin ↔ Ark swaps through Boltz:
// Fluent builder
builder.AddArk()
.EnableSwaps()
// or with custom Boltz URL:
.OnCustomBoltz("https://api.boltz.exchange", websocketUrl: null);
// IServiceCollection
services.AddArkSwapServices();
services.AddHttpClient<BoltzClient>();
The SwapsManagementService handles swap lifecycle automatically — monitoring status, cooperative claim signing, and VHTLC management.
Extensibility Points
The SDK uses a pluggable architecture. Register your implementations for:
| Interface | Purpose | Default |
|---|---|---|
IVtxoStorage |
VTXO persistence | EfCoreVtxoStorage |
IContractStorage |
Contract persistence | EfCoreContractStorage |
IIntentStorage |
Intent persistence | EfCoreIntentStorage |
ISwapStorage |
Swap persistence | EfCoreSwapStorage |
IWalletStorage |
Wallet persistence | EfCoreWalletStorage |
IWalletProvider |
Wallet signer/address resolution | DefaultWalletProvider |
ISafetyService |
Distributed locking | Must implement |
IChainTimeProvider |
Current blockchain height/time | Must implement |
IFeeEstimator |
Transaction fee estimation | DefaultFeeEstimator |
ICoinSelector |
UTXO selection strategy | DefaultCoinSelector |
ISweepPolicy |
VTXO consolidation rules | Register zero or more |
IContractTransformer |
Custom contract → coin transforms | Register zero or more |
IEventHandler<T> |
React to batch/sweep/spend events | Register zero or more |
Local Development
The SDK uses .NET Aspire for local orchestration with Docker containers (arkd, Bitcoin Core, Boltz, etc.):
cd NArk.AppHost
dotnet run
Running Tests
# Unit tests
dotnet test NArk.Tests
# End-to-end tests (requires Docker)
dotnet test NArk.Tests.End2End
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.EntityFrameworkCore (>= 8.0.16)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.16)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
- NArk.Core (>= 1.0.141-beta)
- NArk.Swaps (>= 1.0.141-beta)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.141-beta | 0 | 2/27/2026 |
| 1.0.140-beta | 0 | 2/27/2026 |
| 1.0.139-beta | 0 | 2/27/2026 |
| 1.0.83-beta | 34 | 2/24/2026 |
| 1.0.82-beta | 38 | 2/19/2026 |
| 1.0.80-beta | 54 | 2/18/2026 |