Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Project setup

Wire endpoints, keys, and the async runtime for a real application.

Endpoints

Pick one HTTP endpoint and (optionally) a paired WebSocket endpoint:

NetworkHTTPWebSocket
Mainnethttps://api-mainnet.dango.zonewss://api-mainnet.dango.zone/graphql
Local nodehttp://localhost:8080ws://localhost:8080/graphql

HttpClient::new accepts the bare HTTP origin; it appends /graphql and the REST paths internally. WsClient::from_http_url accepts an HTTP origin and rewrites the scheme — see WsClient.

Configuration via environment

Read endpoint and key material from the environment. Keep secrets out of source files.

use {
    anyhow::{Context, Result},
    dango_sdk::{HttpClient, Secp256k1, Secret, SingleSigner, WsClient},
    grug::Addr,
    std::{env, str::FromStr},
};
 
#[derive(Debug)]
struct Config {
    http_url:    String,
    ws_url:      String,
    chain_id:    String,
    address:     Addr,
    private_key: [u8; 32],
}
 
fn load() -> Result<Config> {
    Ok(Config {
        http_url:    env::var("DANGO_HTTP_URL").context("DANGO_HTTP_URL not set")?,
        ws_url:      env::var("DANGO_WS_URL").context("DANGO_WS_URL not set")?,
        chain_id:    env::var("DANGO_CHAIN_ID").unwrap_or_else(|_| "dango-1".into()),
        address:     Addr::from_str(&env::var("DANGO_ADDRESS")?)?,
        private_key: hex::decode(env::var("DANGO_PRIVATE_KEY")?)?
            .try_into()
            .map_err(|_| anyhow::anyhow!("DANGO_PRIVATE_KEY must be 32 bytes hex"))?,
    })
}
 
#[tokio::main]
async fn main() -> Result<()> {
    let cfg = load()?;
 
    let http   = HttpClient::new(&cfg.http_url)?;
    let ws     = WsClient::new(&cfg.ws_url)?;
    let secret = Secp256k1::from_bytes(cfg.private_key)?;
 
    let signer = SingleSigner::new(cfg.address, secret)
        .with_query_user_index(&http).await?
        .with_query_nonce(&http).await?;
 
    println!("ready: {}", signer.address);
    let _ = ws;
    Ok(())
}

Loading keys from an encrypted file

For local CLIs, persist a 32-byte private key in an AES-256-GCM keystore file. See Keystore for the format.

use {
    anyhow::Result,
    dango_sdk::{Keystore, Secp256k1, Secret},
};
 
fn load_secret(path: &str, password: &str) -> Result<Secp256k1> {
    let bytes = Keystore::from_file(path, password)?;
    Secp256k1::from_bytes(bytes)
}

Wrap the raw bytes in Secp256k1 or Eip712 depending on the account's signing scheme.

Runtime

Every network call is async. Use the multi-threaded runtime in real apps:

#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() -> anyhow::Result<()> { /* ... */ Ok(()) }

For libraries that own their runtime, expose async fn entry points and let the caller pick.

Logging

Enable the tracing feature when the host app uses tracing:

dango-sdk = { git = "...", features = ["tracing"] }

This emits debug! events on every GraphQL request, response, and subscription handshake. No public symbols change.

Next