Skip to main content

Ledger API

@midnight/ledger v2.0.8 • Readme | API


Ledger TypeScript API

This document outlines the flow of transaction assembly and usage with the ledger TS API.

Network ID

Prior to any interaction, setNetworkId should be used to set the NetworkId to target the correct network.

Proof stages

Most transaction components will be in one of three stages: X, UnprovenX, or ProofErasedX. The UnprovenX stage is always the first one. It is possible to transition to the X stage by proving an UnprovenTransaction through the proof server. For testing, and where proofs aren't necessary, the ProofErasedX stage is used, which can be reached via eraseProof[s] from the other two stages.

Transaction structure

A Transaction runs in two phases: a guaranteed phase, handling fee payments and fast-to-verify operations, and a fallible phase, handling operations which may fail atomically, separately from the guaranteed phase. It therefore contains:

It also contains additional cryptographic glue that will be omitted in this document.

Zswap

A Zswap Offer consists of:

  • A set of Inputs, burning coins.
  • A set of Outputs, creating coins.
  • A set of Transients, indicating a coin that is created and burnt in the same transaction.
  • A mapping from TokenTypes to offer balance, positive when there are more inputs than outputs and vice versa.

Inputs can be created either from a QualifiedCoinInfo and a contract address, if the coin is contract-owned, or from a QualifiedCoinInfo and a ZswapLocalState, if it is user-owned. Similarly, Outputs can be created from a CoinInfo and a contract address for contract-owned coins, or from a CoinInfo and a user's public key(s), if it is user-owned. A Transient is created similarly to a Input, but directly converts an existing Output.

A QualifiedCoinInfo is a CoinInfo with an index into the Merkle tree of coin commitments that can be used to find the relevant coin to spend, while a CoinInfo consists of a coins TokenType, value, and a nonce.

Calls

A ContractDeploy consists of an initial contract state, and a nonce.

A ContractCall consists of a contract's address, the entry point used on this contract, a guaranteed and a fallible public oracle transcript, a communication commitment, and a proof. ContractCalls are constructed via ContractCallPrototypes, which consist of the following raw pieces of data:

  • The contract address
  • The contract's entry point
  • The contract operation expected (that is, the verifier key and transcript shape expected to be at this contract address and entry point)
  • The guaranteed transcript (as produced by the generated JS code)
  • The fallible transcript (as produced by the generated JS code)
  • The outputs of the private oracle calls (As a FAB AlignedValues)
  • The input(s) to the call, concatenated together (As a FAB AlignedValue)
  • The output(s) to the call, concatenated together (As a FAB AlignedValue)
  • The communications commitment randomness (As a hex-encoded field element string)
  • A unique identifier for the ZK circuit used (used by the proof server to index for the prover key)

NOTE: currently the JS code only generates a single transcript. We probably just want a canonical way to split this into guaranteed/fallible?

A ContractCalls object is assembed, and ContractCallPrototypes / ContractDeploys are added to this directly. This can then be inserted into an UnprovenTransaction.

State Structure

The LedgerState is the primary entry point for Midnight's ledger state, and it consists of a ZswapChainState, as well as a mapping from ContractAddresses to ContractStates. States are immutable, and applying transactions always produce new outputs states.