By the end of this page you will have:
  1. Installed an SDK for your language.
  2. Generated an OAS DID and the Ed25519 key that controls it.
  3. Connected to the public testnet.
  4. Received 100 test SIGIL from the faucet.
  5. Sent a Transfer transaction.
  6. Read back the transaction receipt.
The whole flow takes about five minutes on a warm machine.
Use the public testnet (sigil-testnet-1) for everything in this guide. Mainnet (sigil-mainnet-1) settles in MINT, has no faucet, and rejects test keys.

1. Install

Sigil ships a first-party Rust SDK (sigil-sdk) and a TypeScript JSON-RPC client (@sigil/sigil-web). Go and Python developers call the JSON-RPC directly today — see SDK overview for the parity matrix.
# Rust toolchain (skip if you already have it)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup component add rustfmt clippy

# Bun (TypeScript)
curl -fsSL https://bun.sh/install | bash
[dependencies]
sigil-sdk = { git = "https://github.com/l1feai/sigil", package = "sigil-sdk" }
sigil-core = { git = "https://github.com/l1feai/sigil", package = "sigil-core" }
ed25519-dalek = "2"
rand = "0.8"
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }
Sigil’s transaction signing requires BLAKE3 + Ed25519, not BLAKE2. The Go and Python snippets below pull a BLAKE3 implementation.

2. Walk through the flow

1

Generate a DID and signing key

A Sigil DID is a string of the form did:oas:sigil:agent:<32-byte-blake3-of-pubkey-hex>. Anyone can mint one offline — there is no central registry.
use ed25519_dalek::SigningKey;
use rand::rngs::OsRng;

let signing_key = SigningKey::generate(&mut OsRng);
let verifying_key = signing_key.verifying_key();
let pubkey_hex = hex::encode(verifying_key.as_bytes());
let address = blake3::hash(verifying_key.as_bytes());
let did = format!("did:oas:sigil:agent:{}", address.to_hex());

println!("DID: {did}");
println!("Public key: {pubkey_hex}");
// Persist `signing_key.to_bytes()` somewhere safe.
The DID is derived deterministically from the public key. Losing the signing key means losing control of the DID — back it up before continuing.
2

Confirm the network is up

The public testnet RPC is https://testnet-rpc.sigil.ml/rpc. The first call you make against any Sigil network should be sigil_getNodeInfo — it tells you the chain id, protocol version, and node version in one round-trip.
curl -s https://testnet-rpc.sigil.ml/rpc \
  -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"sigil_getNodeInfo","params":{}}'
Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "version": "0.1.0",
    "chain_id": "sigil-testnet-1",
    "protocol_version": "0.1.0"
  }
}
Field shapes are set by handle_node_info in node/sigil-node/src/rpc_server.rs; version reflects the node binary version and may advance ahead of protocol_version.Expected result.chain_id: sigil-testnet-1. If the call fails, status.sigil.ml shows live availability.
3

Drip from the faucet

The testnet faucet drips 100 test SIGIL per DID per hour. It accepts the DID you generated in step 1.
curl -s https://faucet.sigil.ml/drip \
  -H 'content-type: application/json' \
  -d '{"did":"did:oas:sigil:agent:<your-did-suffix>"}'
Expected response:
{ "ok": true, "tx_hash": "0xabc...", "amount_base_units": 100000000 }
Sigil uses micro-MINT as the smallest divisible unit: one display unit equals one million micro-MINT. 100 test SIGIL = 100_000_000 micro-MINT. (The faucet response field is still named amount_base_units for wire-format stability; values are micro-MINT.)
4

Check your balance

Wait one block (~6 s), then query the chain.
curl -s https://testnet-rpc.sigil.ml/rpc \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc":"2.0","id":1,
    "method":"sigil_getBalance",
    "params":{"did":"did:oas:sigil:agent:<your-did-suffix>"}
  }'
Response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "did": "did:oas:sigil:agent:abc123...",
    "balance": 100000000,
    "nonce": 0
  }
}
balance is in micro-MINT (100 test SIGIL = 100_000_000). nonce is the next-expected transaction nonce for this DID. Shape is defined by handle_get_balance in node/sigil-node/src/rpc_server.rs.
5

Sign and submit a Transfer

A signed transaction is BLAKE3-hashed with the domain tag sigil/transaction/v1\n, then Ed25519-signed. The Rust SDK exposes a fluent builder; the TypeScript path constructs the canonical JSON directly.
use ed25519_dalek::SigningKey;
use sigil_core::transaction::{TransferData, TransactionType, SignedTransaction};
use sigil_core::Transaction;
use sigil_sdk::{sign_transaction, TransactionBuilder};
use chrono::Utc;

async fn send_transfer(
    signing_key: &SigningKey,
    sender_did: &str,
    recipient_did: &str,
    amount_base_units: u64,
    nonce: u64,
) -> anyhow::Result<String> {
    // Construct the Transfer transaction. The fluent builder covers
    // staking and governance; for Transfer use the core Transaction type.
    let tx = Transaction {
        chain_id: "sigil-testnet-1".to_string(),
        sender_did: sender_did.to_string(),
        nonce,
        gas_limit: 200_000,
        gas_price: 1,
        tx_type: TransactionType::Transfer(TransferData {
            recipient_did: recipient_did.to_string(),
            amount: amount_base_units,
            memo: Some("quickstart".to_string()),
        }),
        timestamp: Utc::now(),
    };

    let signed = sign_transaction(tx, signing_key)?;
    let body = serde_json::json!({
        "jsonrpc": "2.0",
        "id": 1,
        "method": "sigil_sendTransaction",
        "params": signed,
    });

    let res: serde_json::Value = reqwest::Client::new()
        .post("https://testnet-rpc.sigil.ml/rpc")
        .json(&body)
        .send()
        .await?
        .json()
        .await?;

    let tx_hash = res["result"]["tx_hash"]
        .as_str()
        .ok_or_else(|| anyhow::anyhow!("missing tx_hash: {res}"))?;
    Ok(tx_hash.to_string())
}
The chain returns a tx_hash. Inclusion typically lands one block (~6 s) later.
6

Read back the receipt

Poll sigil_getTransactionReceipt until status flips from pending to final. On testnet this is usually 1–2 polls.
curl -s https://testnet-rpc.sigil.ml/rpc \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc":"2.0","id":1,
    "method":"sigil_getTransactionReceipt",
    "params":{"tx_hash":"0xabc..."}
  }'
Expected receipt shape:
{
  "tx_hash": "0xabc...",
  "block_height": 184201,
  "status": "final",
  "gas_used": 21000,
  "error": null
}

You’re done

You have a funded testnet DID, you can sign transactions client-side, and you can read chain state. That is everything you need to build on Sigil.

Next steps

Concepts

How identity, consensus, and execution fit together.

SDK guide

Pick the language-specific reference for your stack.

Cookbook

Copy-paste recipes for tokens, NFTs, names, channels, and more.