Building on Midnight
VIA connects Midnight to its cross-chain network. VIA is not a bridge — it is a cross-chain messaging network. Token transfers, and bridges themselves, are applications you build on top of it. Midnight is not a single-route chain — a client authorizes peers per chain, and any VIA-connected chain can be one.
VIA is live on Midnight mainnet (VIA chain ID 64364449) and Midnight Preview (64364450). The examples and addresses on this page use Midnight Preview and Cardano Preprod; Networks and Contract Identity below lists what differs on mainnet.
The live reference integration is USDM, deployed and running cross-chain native transfers in both directions between Midnight and Cardano — see the Transfer USDM guide. This page covers how a Midnight client works.
How a Midnight Client Is Shaped
Midnight contracts are written in Compact. A VIA client on Midnight is one Compact contract. The examples below use the shape of the deployed USDM token client.
The constructor takes the chain ID and seeds a unique transaction-ID base from it. Two circuits are required to send a cross-chain message:
bridge— starts an outbound transfer. It checks that the system is enabled and the destination endpoint is authorized. It collects the configured fee, burns the token amount from the caller, assigns a unique tx ID, and stores the outbound message. It returns the tx ID.process— completes an inbound transfer. Only an allowlisted relayer can call it. It checks replay protection, the source endpoint, and that this contract and chain are the intended destination. Then it marks the message processed and mints to the recipient.
Admin circuits configure the contract — endpoints, relayers, fees, and pause.
Every circuit call needs a zero-knowledge proof. A proof server generates it — local by default (http://localhost:6300), or remote.
The Compact client source is proprietary to VIA Labs LLC (© 2026, all rights reserved). You receive it when we build your integration together. The usdm-bridge npm package is separate — it is public and MIT.
Endpoints: Any Chain Can Be a Peer
The client's endpoint registry is keyed by chain ID. It is not specific to any one chain:
export ledger endpoints: Map<Uint<64>, Map<Bytes<32>, Boolean>>;
export circuit setEndpoint(_chainId: Uint<64>, _address: Bytes<32>, _enabled: Boolean): []
A message passes only if its source pair — chain ID plus 32-byte contract identity — is enabled in this map. The owner configures it, one call per peer.
Example — an EVM peer. VIA chain IDs on EVM chains equal the EVM chain IDs. To accept messages from a contract on Sepolia, the owner enables it:
setEndpoint(11155111, <contract address, left-padded to 32 bytes>, true)
The EVM side is a standard VIA integration — the same contracts as Hello World and Burn & Mint Token. On EVM, non-EVM identities travel as bytes32, so the Midnight client appears there as its 32-byte contract address.
Example — the Cardano peer. The same call with VIA's Cardano chain ID (2273266 Preprod, 2273265 Mainnet) authorizes a Cardano contract. The deployed USDM client runs exactly this route today, on both network pairs — see the Transfer USDM guide.
Networks and Contract Identity
Midnight has no contract-to-contract calls, so on mainnet the USDM gateway and the token are one contract, deployed once for all routes — which is why mainnet runs a single VIA chain ID (64364449). Testnet predates that consolidation: it registered one ID per transfer direction, and 64364450 is the Cardano-route contract the examples use.
| Preview | Mainnet | |
|---|---|---|
| VIA chain ID | 64364450 (per-route) | 64364449 (single) |
| USDM contract | 471dfe55c866fdbc… | 65023744190a4fc7… |
| USDM token color | 003bacd9a361ba0d… | 8c2c22bc0c37fa99… |
Two identity facts to internalize:
- Tokens are identified by color. An unshielded Midnight token's identity is its 32-byte token color, minted into existence by its contract. The color is what wallets match balances on, and it is what a cross-chain transfer's
destination_tokenfield must carry when Midnight is the destination — not the contract address. - ZK artifacts belong to a deployment. A deployed contract carries its verifier keys on-chain; proofs are checked against them. Prover keys from one deployment do not prove against another — the Preview contract and the mainnet contract each have their own artifact set, and a client must load the set matching the network it targets.
Fees: DUST
Every Midnight transaction pays fees in DUST — including the bridge circuit call that starts a Midnight → anywhere transfer. DUST is not a token you acquire; it cannot be bought or transferred:
- On testnet, tDUST comes from the faucet.
- On mainnet, DUST accrues to a wallet's dust key from NIGHT held on Cardano that has been registered for generation. The registration is a Cardano-side action, signed by the NIGHT-holding wallet's stake key, and it names a Midnight dust address (
mn_dust1...) as the beneficiary. Capacity fills over hours, proportional to the registered NIGHT.
The dust key is derived from the wallet seed separately from the receive address (mn_addr1...) — a registration pointed at another wallet's dust key generates DUST your wallet can never spend, so verify the dust address in the registration is the one your wallet derives. Generation status for a Cardano stake address is queryable from the public indexer (dustGenerationStatus).
Version Compatibility
The USDM client compiles under Compact language_version >= 0.21.0. These @midnight-ntwrk package versions are the tested set:
| Package | Version |
|---|---|
@midnight-ntwrk/compact-runtime | 0.15.0 |
@midnight-ntwrk/ledger-v8 | 8.0.3 |
@midnight-ntwrk/midnight-js-contracts | 4.0.4 |
@midnight-ntwrk/midnight-js-http-client-proof-provider | 4.0.4 |
@midnight-ntwrk/midnight-js-indexer-public-data-provider | 4.0.4 |
@midnight-ntwrk/midnight-js-level-private-state-provider | 4.0.4 |
@midnight-ntwrk/midnight-js-network-id | 4.0.4 |
@midnight-ntwrk/midnight-js-node-zk-config-provider | 4.0.4 |
@midnight-ntwrk/midnight-js-types | 4.0.4 |
@midnight-ntwrk/midnight-js-utils | 4.0.4 |
@midnight-ntwrk/onchain-runtime-v2 | 2.0.1 |
@midnight-ntwrk/wallet-sdk-abstractions | 2.0.0 |
@midnight-ntwrk/wallet-sdk-address-format | 3.1.0 |
@midnight-ntwrk/wallet-sdk-dust-wallet | 3.0.0 |
@midnight-ntwrk/wallet-sdk-facade | 3.0.0 |
@midnight-ntwrk/wallet-sdk-hd | 3.0.1 |
@midnight-ntwrk/wallet-sdk-shielded | 2.1.0 |
@midnight-ntwrk/wallet-sdk-unshielded-wallet | 2.1.0 |
The pins matter. The Midnight SDK packages version independently, and this combination is the one the working USDM client ships with. Start from these exact versions.
Integration Reality
Two things to know before you plan a Midnight integration.
Launching your own integration is a guided process. You build it together with VIA — the same model as Cardano. Transferring USDM through the deployed contracts is permissionless; deploying a new client is not.
Relayers on Midnight run from an allowlist. The contract checks the caller against relayers the owner has enabled — there is no on-chain signature verification on Midnight yet.
Next Steps
- Transfer USDM guide — transfer USDM end to end, mainnet or testnet
- Building on Cardano — the other half of the Cardano route
- Audits — what has been audited and by whom