Autonomi.Antd 0.2.0

dotnet add package Autonomi.Antd --version 0.2.0
                    
NuGet\Install-Package Autonomi.Antd -Version 0.2.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Autonomi.Antd" Version="0.2.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Autonomi.Antd" Version="0.2.0" />
                    
Directory.Packages.props
<PackageReference Include="Autonomi.Antd" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Autonomi.Antd --version 0.2.0
                    
#r "nuget: Autonomi.Antd, 0.2.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Autonomi.Antd@0.2.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Autonomi.Antd&version=0.2.0
                    
Install as a Cake Addin
#tool nuget:?package=Autonomi.Antd&version=0.2.0
                    
Install as a Cake Tool

antd-csharp — C# SDK for Autonomi

C# SDK for the antd daemon. Provides an async client with both REST and gRPC transports targeting .NET 8.

Installation

dotnet add package Autonomi.Antd

Compatibility

This package talks to a running antd daemon; it does not join the network itself. Targets .NET 8. Tested against antd 0.12.x. The gRPC transport uses Grpc.Net.Client, which is a package dependency, so both transports work out of the box. For a daemon-less client see Autonomi.Ffi.

Prerequisites

Building

cd antd-csharp

# Build all projects (SDK, examples, tests)
dotnet build Antd.sln

# Or build individual projects
dotnet build Antd.Sdk/Antd.Sdk.csproj

Quick Start

using System.Text;
using Antd.Sdk;

using var client = AntdClient.CreateRest();

// Health check
var status = await client.HealthAsync();
Console.WriteLine($"{status.Network} — healthy: {status.Ok}");

// Store and retrieve data
var result = await client.DataPutPublicAsync(
    Encoding.UTF8.GetBytes("Hello, Autonomi!")
);
Console.WriteLine($"Address: {result.Address}, chunks: {result.ChunksStored}");

var data = await client.DataGetPublicAsync(result.Address);
Console.WriteLine(Encoding.UTF8.GetString(data));

Client Creation

using Antd.Sdk;

// REST transport (default)
using var client = AntdClient.CreateRest(
    baseUrl: "http://localhost:8082",
    timeout: TimeSpan.FromSeconds(30)
);

// gRPC transport (wallet operations and payment_mode are REST-only)
using var grpcClient = AntdClient.CreateGrpc(
    target: "http://localhost:50051"
);

// Factory method (transport string)
using var auto = AntdClient.Create(transport: "rest");

API Reference

All methods are async and return Task<T>. The client implements IDisposable.

Health

Method Returns Description
HealthAsync() HealthStatus Check daemon health — also reports antd version, EVM network, uptime, build commit, and payment contract addresses (antd ≥ 0.4.0)

Data

Method Returns Description
DataPutPublicAsync(byte[] data, PaymentMode mode = Auto) DataPutPublicResult Store public data — DataMap stored on-network
DataGetPublicAsync(string address) byte[] Retrieve public data by address
DataPutAsync(byte[] data, PaymentMode mode = Auto) DataPutResult Store private (encrypted) data — DataMap returned to caller
DataGetAsync(string dataMap) byte[] Retrieve private data using a caller-held DataMap
DataCostAsync(byte[] data, PaymentMode mode = Auto) UploadCostEstimate Estimate storage cost — size, chunks, gas, payment mode

Chunks

Method Returns Description
ChunkPutAsync(byte[] data) PutResult Store a raw chunk
ChunkGetAsync(string address) byte[] Retrieve a chunk

Files

Method Returns Description
FilePutAsync(string path, PaymentMode mode = Auto) FilePutResult Upload a file privately — DataMap returned to caller
FileGetAsync(string dataMap, string destPath) — Download a private file using a caller-held DataMap
FilePutPublicAsync(string path, PaymentMode mode = Auto) FilePutPublicResult Upload a file publicly — DataMap stored on-network
FileGetPublicAsync(string address, string destPath) — Download a public file by address
FileCostAsync(string path, bool isPublic, PaymentMode mode = Auto) UploadCostEstimate Estimate cost — size, chunks, gas, payment mode

Models

All models are sealed records (immutable).

Model Fields Description
HealthStatus Ok, Network, Version, EvmNetwork, UptimeSeconds, BuildCommit, PaymentTokenAddress, PaymentVaultAddress Health check result (diagnostic fields require antd ≥ 0.4.0)
PutResult Cost, Address Result of ChunkPutAsync only
DataPutResult DataMap, ChunksStored, PaymentModeUsed Private data put — DataMap returned to caller
DataPutPublicResult Address, ChunksStored, PaymentModeUsed Public data put — DataMap stored on-network
FilePutResult DataMap, StorageCostAtto, GasCostWei, ChunksStored, PaymentModeUsed Private file put — DataMap returned to caller
FilePutPublicResult Address, StorageCostAtto, GasCostWei, ChunksStored, PaymentModeUsed Public file put — DataMap stored on-network
UploadCostEstimate Cost, FileSize, ChunkCount, EstimatedGasCostWei, PaymentMode Pre-upload cost breakdown

Error Handling

All errors inherit from AntdException:

using Antd.Sdk;

try
{
    var data = await client.DataGetPublicAsync("nonexistent");
}
catch (NotFoundException)
{
    Console.WriteLine("Data not found");
}
catch (PaymentException)
{
    Console.WriteLine("Insufficient funds");
}
catch (AntdException ex)
{
    Console.WriteLine($"Error ({ex.StatusCode}): {ex.Message}");
}
Exception HTTP gRPC Description
BadRequestException 400 INVALID_ARGUMENT Invalid parameters
PaymentException 402 FAILED_PRECONDITION Payment issue
NotFoundException 404 NOT_FOUND Not found
AlreadyExistsException 409 ALREADY_EXISTS Already exists
ForkException 409 ABORTED (non-partial-upload) Version conflict
TooLargeException 413 RESOURCE_EXHAUSTED Too large
InternalException 500 INTERNAL Server error
NetworkException 502 UNAVAILABLE Unreachable
PartialUploadException 502 (code: "PARTIAL_UPLOAD") ABORTED (detail starts with Partial upload:) Finalize stored some chunks, not all; extends NetworkException

Partial uploads

A finalize (FinalizeUploadAsync, FinalizeMerkleUploadAsync, FinalizeChunkUploadAsync) can fail after the wallet has paid: some chunks store, others miss quorum after the daemon's own retries. The SDK surfaces that as PartialUploadException with ChunksStored, ChunksFailed, TotalChunks, Retryable and RetentionKnown. The on-chain payment persists and the stored chunks stay on the network; the two flags say how to finish:

  • Retryable: the daemon kept the paid attempt (payment proofs plus the unstored chunks) under the same upload_id. Call the same finalize method again with the same arguments (same upload_id, same payment artefacts) to store the remainder against the same payment: no re-prepare, no second signature, no double payment. Bound the loop: a persistent failure throws on every call, so cap the attempts and treat a ChunksFailed that stops shrinking as stuck. The retained attempt expires with the daemon's pending-upload TTL.
  • RetentionKnown && !Retryable: the daemon confirmed it kept nothing (for example a merkle finalize that deliberately left sub-batches unpaid). Re-prepare the same content; already-stored chunks are skipped, so the retry pays only for the remainder.
  • !RetentionKnown: retention is unknown, because a daemon before antd 0.14.0 answered over REST (it never sends retryable) or the SDK could not fully read the error. The daemon may still hold the paid attempt, since it records the resume handle before it returns the error. Stop automatic recovery, keep the upload_id and the original payment artefacts, and reconcile before re-preparing or paying again. Never pay again on this signal alone.

Retryable implies RetentionKnown. PartialUploadException extends NetworkException because a partial upload has always arrived as a 502, so existing catch (NetworkException) blocks keep matching; catch the derived type first to branch on the counts. Over REST the counts come from the structured error body, and RetentionKnown is true only when retryable is a JSON boolean (missing, null, "true" or 1 read as unknown). Over gRPC an ABORTED status maps to PartialUploadException only when its status detail starts with the daemon's fixed Partial upload: prefix; any other ABORTED, including one that quotes Partial upload: further into its detail, keeps the ForkException mapping. The detail reads Partial upload: <stored>/<total> chunks stored, <failed> failed after retries: <reason> (<hint>). RetentionKnown is true only when the detail starts with those counts, all three parse, and it ends with one of the daemon's two hints: (paid attempt retained...) sets Retryable, and (stored chunks persist; re-prepare the same content...) means the daemon confirmed it kept nothing (daemons before antd 0.14.0 write only this one). If the counts do not match the daemon's layout or do not convert (an overflow, non-ASCII digits), all three read as zero and both flags are false, even with a hint. Readable counts with a missing, truncated or unrecognised hint, or text after it, keep the counts, but both flags stay false: retention is unknown (stop and reconcile), not "nothing retained".

Behaviour change over gRPC: a partial-upload ABORTED used to surface as ForkException; it is now PartialUploadException. The daemon emits ABORTED only for PARTIAL_UPLOAD, so a catch (ForkException) around a gRPC finalize should become catch (PartialUploadException).

var lastFailed = 0UL;
for (var attempt = 1; ; attempt++)
{
    try
    {
        return await client.FinalizeUploadAsync(uploadId, txHashes); // every chunk stored
    }
    catch (PartialUploadException ex) when (ex.Retryable)
    {
        var stalled = attempt > 1 && ex.ChunksFailed >= lastFailed;
        if (attempt >= 5 || stalled)
            throw; // still retained under uploadId until the daemon's TTL: finalize again later
        lastFailed = ex.ChunksFailed;
        await Task.Delay(TimeSpan.FromSeconds(attempt * 2), cancellationToken);
    }
    // RetentionKnown && !Retryable propagates: the daemon kept nothing, so re-prepare the same content.
    // !RetentionKnown propagates: retention unknown, so keep uploadId + txHashes and reconcile before paying again.
}

See Examples/FinalizeRetry.cs (FinalizeWithRetryAsync, used by example 7) and docs/external-signer-flow.md §6.

Examples

cd Examples

dotnet run -- 1     # Connect
dotnet run -- 2     # Public data
dotnet run -- 3     # Chunks
dotnet run -- 4     # Files
dotnet run -- 6     # Private data
dotnet run -- 7     # External signer (bounded partial-upload retry)
dotnet run -- all   # Run all

Or use the dev CLI:

ant dev example data -l csharp
ant dev example all -l csharp

Project Structure

antd-csharp/
├── Antd.sln                   # Solution file
├── Antd.Sdk/                  # SDK library
│   ├── Antd.Sdk.csproj
│   ├── IAntdClient.cs         # Client interface
│   ├── AntdClientFactory.cs   # Factory methods
│   ├── AntdRestClient.cs      # REST implementation
│   ├── AntdGrpcClient.cs      # gRPC implementation
│   ├── Models.cs              # Data models
│   └── Exceptions.cs          # Exception hierarchy
├── Examples/                  # Example programs
│   ├── Examples.csproj
│   └── Program.cs
└── Antd.Sdk.Tests/            # Tests
    ├── Antd.Sdk.Tests.csproj
    └── Program.cs
Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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
0.2.0 41 9/25/2026
0.1.0 76 9/15/2026