MLXDocs
Transactions

Transactions

Markdown

Every change to the MLX ledger is a transaction signed by a wallet's Ed25519 key or by the sequencer, ordered into hash-linked, signed blocks.

What a transaction is

A transaction is a small JSON object. The wallet signs it, sends it to POST /api/tx, and the sequencer applies it to the ledger in a block. Nothing else changes a balance.

A signed transfer
{
  "chain": "mlx-1",
  "from": "luca.mlx",
  "nonce": 4,
  "ts": 1793116800000,
  "pk": "7812b1435b317df04f45731ac508ae7774d4731ee0445fd46ccdcc5019faa524",
  "body": { "type": "transfer", "to": "shop.mlx", "token": "USDC", "amount": "2500000" },
  "sig": "ce8c7621b38777895b06107168e08a542bf9d5fbaf2ac53bb1b9a1b1d3ade2635d5c00150a2f76990b49330365d964c2b55d3289bbc9cc3e380550a2715cb10f"
}
FieldTypeNotes
chainstringThe network's chain id. Production is mlx-1; GET /api/stats returns it as chain.
fromstringThe wallet that signs, for example luca.mlx. sequencer for system transactions.
nonceintegerThe wallet's next nonce: its current nonce plus one. create_account uses 0.
tsintegerWhen it was signed, in milliseconds since 1970. Must be close to the network's clock.
pkstringThe signer's Ed25519 public key, 64 lowercase hex characters.
bodyobjectWhat to do. body.type names the transaction type.
sigstringEd25519 signature, 128 hex characters, over the transaction's hash.

Amounts are strings of base units with 6 decimals: "2500000" is 2.5 USDC.

Hash and signature

The transaction's hash is SHA-256 of its canonical JSON (keys sorted, no whitespace) without sig. The signature is Ed25519 over those 32 hash bytes. The hash is also the transaction's id: GET /api/tx/<hash>. Signing the same fields twice gives the same hash, so sending a transaction again never applies it twice. Details and a worked example: Keys and signing.

Nonces

Each wallet has a nonce, starting at 0 when it is created. A transaction applies only with nonce = current nonce + 1, and a successful one moves the wallet's nonce up by one. A failed transaction does not use its nonce: sign the next one with the same number. The sequencer applies a wallet's transactions in nonce order, and one that arrives ahead of its predecessor waits for it briefly in the mempool. See Submitting.

Read a wallet's current nonce from GET /api/account/<name> (account.nonce).

Blocks

The sequencer takes transactions from the mempool, applies them in order and seals them into a block. A submit seals a block right away when it can; a scheduled job seals anything left. Each block carries:

  • prev: the hash of the block before it, so blocks form a chain from the genesis block (height 0);
  • txRoot: a Merkle root over the hashes of the transactions it holds;
  • producer and sig: the sequencer's public key and its Ed25519 signature over the block hash.

A transaction that fails is still recorded in its block, with status: "failed" and an error, and changes nothing. Every block then goes into the ledger's transparency log. Block endpoints: Blocks.

User and system transactions

User transactionsSystem transactions
Signed bythe wallet's own key (pk must be the key the wallet was created with)the sequencer's key (from: "sequencer", nonce: 0)
Examplescreate_account, transfer, swap, buy_node, withdraw, bind_devicedeposit, mint_node, compute_reward, withdraw_settle, issue, adjust, gift
Who sends themwallets, MLX Node's link sheet, your own codethe network itself: the payment watcher, the hourly reward run, withdrawal payouts, the operator's admin

System transactions are public like any other: they show on the explorer with their reason, and the hourly state commitment covers the balances they produce. A user cannot send one: a system type signed by a wallet fails.

Where to go next