Encoding and types
What this teaches: which crates own which user-facing types, how numeric units are represented, and the shape of GraphQL response data.
Where types live
dango-sdk is thin: most user-facing types are re-exported by the SDK, dango_types, and indexer_graphql_types.
| Type | Crate | Notes |
|---|---|---|
Addr, Hash256, Binary, ByteArray<N> | Core | Strongly-typed wrappers over fixed-size byte arrays. |
Message, Tx, UnsignedTx, Block, BlockOutcome, TxOutcome | Core | Core chain types. |
Coins, Denom, Coin, Uint128, Uint256 | Core | Bank balances and unsigned integers. |
NonEmpty<T>, Defined<T>, Undefined<T>, MaybeDefined<T> | Core | Typestate helpers. |
Key, Signature, SignDoc, Nonce, UserIndex | dango_types::auth / dango_types::account_factory | Account-factory primitives. |
PageInfo, <query>::Variables, <query>::ResponseData, generated *Nodes/*Edges | indexer_graphql_types | GraphQL codegen surface, re-exported at the dango_sdk crate root. |
SubscribeBlock, …, SubscribeQueryStatus (×14) | indexer_graphql_types | One marker struct per subscription. Each has a snake-case module of Variables/ResponseData. |
WsError | dango_sdk | The only public typed error in the crate. |
Base units, not human units
Amounts on the wire are integers in base units (the contract's smallest denomination). Coins::one("bridge/usdc", 100_000_000_u128) is 100 USDC, not 100 micro-USDC.
the SDK exposes Uint128/Uint256 for amounts. Convert to display units at the edge — there is no SDK-side Decimal.
Addresses
Addr is a 20-byte fixed array, hex-encoded with the 0x prefix in display form.
use {grug::Addr, std::str::FromStr};
let addr = Addr::from_str("0x0000000000000000000000000000000000000000")?;
println!("{addr}"); // 0x0000...
let bytes: [u8; 20] = addr.into_inner();
// Ok::<(), anyhow::Error>(())Hashes
Hash256 is a 32-byte hash, hex-encoded. Used for transaction hashes, key hashes, and content hashes.
use {grug::Hash256, std::str::FromStr};
let hash = Hash256::from_str("0x0000000000000000000000000000000000000000000000000000000000000000")?;
// Ok::<(), anyhow::Error>(())GraphQL response types
Every query and subscription generates three pieces of code:
- A marker struct, e.g.
SubscribeTrades. Use as the generic argument:session.subscribe::<SubscribeTrades>(...). - A snake-case module —
subscribe_trades— exposingVariables,ResponseData, and nested*Nodesrecords. - An
impl Variables for subscribe_trades::Variables { type Query = SubscribeTrades; }linking the two.
use dango_sdk::{SubscribeTrades, subscribe_trades};
let variables = subscribe_trades::Variables {
base_denom: "dango".into(),
quote_denom: "bridge/usdc".into(),
};All generated types derive Debug + Clone + PartialEq + Eq. Variables types derive Default so partial construction with ..Default::default() is idiomatic.
Connection nodes
Indexer queries return Relay-style connections: { nodes, page_info: PageInfo }. The paginate helpers extract nodes and follow cursors. Each query has its own node type (accounts::AccountsAccountsNodes, transfers::TransfersTransfersNodes, …) — see the SubscriptionVariables index for the subscription set.
Serializing dynamic payloads
Smart-contract calls and queries are JSON-encoded. the SDK provides JsonSerExt / JsonDeExt for typed encode/decode of any Serialize/Deserialize value:
use grug::JsonSerExt;
let json = my_struct.to_json_value()?;
// Ok::<(), anyhow::Error>(())Message::execute and Message::transfer accept typed payloads directly; you rarely need raw JSON.
Next
- Error handling —
anyhow::ErrorvsWsError. - Subscriptions — how
Variables/ResponseDataplug into streams.