- Node22 or newer
- Keyan
oda_…key: free with a wallet sign-in (300 calls), or bought with tADA. It goes inAuthorization: Bearer. - Seed128 hex characters, a 64-byte seed. It is your attester identity: keep it, it never leaves your machine and needs no funds.
- Vaultthe shared sandbox vault
…takes anchors from every key on this network. Each record is keyed by your attester id: nobody else can take it over or retract it. Everything on it is public test data. - Costabout 10 calls per anchor: the chain reads for the build, the sponsored submit and the job status. Verify and
/zk-configare free.
First anchor on Midnight
Anchor a hash under your own identity. You build and prove the transaction on your machine, a sponsor pays the fee. You need Node, a key and a seed: no NIGHT, no DUST, no indexer, no proof server.
Before you start
shellnpm i @odatano/nightgate-tx @midnight-ntwrk/compact-runtime
# a fresh seed: 64 bytes, 128 hex characters
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
# your environment
ODATANO_KEY=oda_…
SEED_HEX=<128 hex>
VAULT=<64 hex vault address>
Five steps
- 1Build locally.
createTxBuilderwithapireads contract state through this gateway. The prover keys come from/zk-configon the first run and stay cached. - 2Prove locally.
buildSponsorableproves in-process, about one to two minutes on a laptop. Only about 5 KB leave the machine. - 3Hand it to the sponsor.
sponsorUnboundsubmits the job and waits for the chain. The sponsor pays the dust; the anchor carries your attester id. - 4Find it on chain.
waitLandedresolves the job's identifier to the block and the transaction hash explorers show. - 5Verify, keyless. Anyone checks the anchor against live contract state with a plain GET, no wallet and no key.
anchor.mjsimport { createHash } from 'node:crypto';
import { connect, createTxBuilder } from '@odatano/nightgate-tx';
import { waitLanded } from '@odatano/nightgate-tx/txbuilder';
import { prepareAttest } from '@odatano/nightgate-tx/calls';
import { Contract } from '@odatano/nightgate-tx/attestation-vault-32';
const BASE = 'https://api.preprod.odatano.dev';
const api = { baseUrl: BASE, token: process.env.ODATANO_KEY };
const builder = await createTxBuilder({
seedHex: process.env.SEED_HEX, networkId: 'preprod',
api, walletSync: false, // chain reads through the gateway
zkConfigBaseUrl: `${BASE}/zk-config/attestation-vault-32`,
contractClass: Contract, contractName: 'attestation-vault-32',
});
const sha = (s) => createHash('sha256').update(s).digest('hex');
const payloadHash = sha('my document'); // only the hash goes on chain
const call = prepareAttest({
payloadHash, metadataHash: sha('{}'),
attestationSecret: builder.attestationSecret,
});
const { unboundTxB64 } = await builder.buildSponsorable({
contractAddress: process.env.VAULT, call, bind: false,
});
const job = await connect(api).sponsorUnbound({
unboundTxB64, idempotencyKey: `anchor-${payloadHash}`,
});
const landed = await waitLanded(job.txHash, { api, timeoutMs: 120_000 });
console.log({
attesterId: builder.attesterId, payloadHash,
identifier: job.txHash, explorerHash: landed?.txHash,
});
await builder.close();
Verify and look it up
- Verify
/odata/v4/midnight-verifytakes no key and charges nothing. The same function under/odata/v4/midnightneeds a key. - Recorda record is keyed by attester id and payload hash. Check the attester id against attesters you trust.
- Identifierthe job's
txHashis the ledger identifier. It exists as soon as you build and stays the same when the sponsor adds its fee. Use it to track the job. - Explorer hashthe transaction hash explorers show exists only once the sponsor completed the transaction.
waitLandedreturns it astxHash,Transactions/byIdentifierasledgerTxHash.
http# keyless, no wallet
GET https://api.preprod.odatano.dev/odata/v4/midnight-verify/verifyAttestationState(
contractAddress='<vault>',attesterId='<attester id>',
payloadHash='<sha256>',compiledArtifactRef='attestation-vault-32')
→ 200 { "verified": true, "attested": true, … }
# the preprod explorer
https://preprod.midnightexplorer.com/transactions/0x<explorer hash>
Your own vault
- Whenfor production use, or for the document-id registry, which only the vault's registrar can run
- Granta key with a deploy grant may sponsor one vault deploy: ask in a NIGHTGATE issue with network, use case and expected volume. The landed address becomes sponsorable under that key.
- Registrarthe vault's registrar is your attester id, derived from your seed.
- Dry runbuild and prove the deploy without sending it first. A dry run leaves the grant's deploy unused.
- Scriptreferences/deploy-vault.mjs in the AGENT_MS repo, the same builder settings as above
shellgit clone https://github.com/maxalexweber1/AGENT_MS
cd AGENT_MS && npm ci
cp .env.example .env # NIGHTGATE_TOKEN, NIGHTGATE_SEED_HEX
node references/deploy-vault.mjs --dry-run # nothing is sent
node references/deploy-vault.mjs # prints the vault address
When something fails
| Message | What it means |
|---|---|
| seedHex must be 128 hex chars | the seed is 64 bytes, written as 128 hex characters |
| 401 a gateway key is required | the call needs a key. Verify works without one under /odata/v4/midnight-verify. |
| … blocks behind, allowed 60 | the server's contract states trail the chain right now. Retry in a minute. |
| not sponsorable | the sponsor does not accept this contract or circuit for your key. Use the sandbox vault, or deploy your own with a grant. |
| already attested | your attester id has anchored this payload hash before. A record is written once; retract it first to change its metadata. |
| 429 | rate limit or used-up calls. Your account shows the calls left. |
| 404 on /zk-config/<contract> | expected for the bare path. The keys live below it, the builder fetches them itself. |
A working example
- AGENT_MSan agent that anchors its daily report, its actions and commit/reveal predictions this way, with a queue, retries and a public proof ledger: github.com/maxalexweber1/AGENT_MS
- MCPfor an AI agent,
@odatano/nightgate-mcpwraps the same flow as tools: AI agents quickstart - SDK@odatano/nightgate-tx on npm, batches, swaps and the token factory included