Overview

Draft protocolSource at 169cbd2 ↗Source SHA-256 7850441…aaa

Makechain is a public ledger for the provenance of published content. It records who published what, to which project, under whose authority, and in what order, whether the publisher is a person or an agent acting on a person's behalf. Anyone can verify that record against a finalized block, in a browser or from a smart contract on another chain, without trusting the server that returned it. The chain holds identity, authority, and order, while the content itself stays in stores that each team runs or chooses. There is no native token. Usage is paid for in credits at fixed prices, and credits enter through a verified deposit on an external EVM chain, with Tempo as the first on-ramp.

Why it exists

People publish code, documents, and whole applications, and a growing share of that work is published by agents acting for them. Anyone who relies on the work needs to know who stands behind it: whether a person signed it or an agent did so under authority the person granted, whether that authority was still valid at the time, and what came before it. Today the platform hosting the work answers those questions, and its answer has to be taken on trust. Two platforms can disagree, and neither can prove its answer.

A transparency log would not fix this on its own: it can prove that an entry exists, but not which key may write to a project today, or whether a key was revoked before or after a given publication. Settling that takes an ordered, agreed history of state changes that independent parties validate, even when some of them misbehave. Makechain is that history, kept on a shared ledger that no platform controls and verifiable by anyone.

Because no single platform owns the record, every application built on Makechain can share it. A person keeps one account across all of them, along with any agents they have authorized, so their identity and publishing history are not tied to a single app. Each application serves its content from its own stores, never from the chain itself, to everyone or only to the accounts it chooses. Whoever receives the content can check it against its hash, and a publication receipt from Makechain proves which account published that hash, to which project, and at what point in the chain. Applications can also build on one another: any of them can read the publications of the others from the shared record, and fetch the underlying content wherever its store grants access.

Goals and boundaries

Makechain is built to:

  • keep one final, agreed order of everything that happens to accounts and projects;
  • let anyone verify a publication without trusting the server that returned it;
  • leave control of identity and authority with the keys that hold each account, never with a platform;
  • work with more than one content-addressing scheme, git included, with new schemes added by release;
  • evolve through scheduled, signed releases.

It also leaves some things out on purpose:

  • It stores no content. The chain records a hash that identifies each object and never holds or serves the bytes.
  • It runs no user programs. There is a fixed set of seventeen commands and no general-purpose execution.
  • It has no token. Usage is paid for in credits at fixed prices, with no fee market.
  • It carries no social features. Links, reactions, reviews, and profiles are signed messages that live outside the chain.

Core concepts

Identity and delegation

An account is the identity of a person or a team. It is a 20-byte address controlled by keys its holder keeps: a wallet key, a key in a device's secure enclave, or a passkey. An account can answer to one key or to a weighted quorum of several, so the loss of a single key need not mean the loss of the account. Addresses are derived the same way Tempo derives its accounts, which lets one identity exist on both chains.

The holder can sign with a key of their own, and can issue delegated keys to agents and automation, each limited to what it needs. An agent's key might only publish to a single project, while another key might only sign social messages. Every delegated key expires, and all of them can be revoked at once. Each publication records both the account and the key that signed it, so the record names the person and, when one acted on their behalf, the agent.

Commands

An account acts on the chain through commands. A command is one instruction, such as creating a project, authorizing a key, or publishing, that a block executes as a unit. Every change an account or governance makes to the chain's state happens through a command, and the set is closed at seventeen, so the chain runs nothing else. Account commands are signed by a key with the authority to issue them and charged from a fixed price table. System commands are authorized differently: a credit import by its deposit proof, and releases and validator changes by the governance multisig. Reads are not commands, since services around the chain answer them. Neither are social messages such as reactions and reviews, which are signed with the same keys but never enter the chain.

Projects and publication

A project is where publications go, comparable to a repository. The account that controls it can grant other accounts the right to publish and can transfer it to someone else, and a project is never deleted. Publishing means signing a push, the command that adds one or more objects to the project's permanent record and moves its named pointers, such as branches. On the chain, a published object is a commitment: its content hash, tagged with the scheme that produced it. A named pointer is a ref. The first workload is versioned code and interactive experiences, built by people and by agents on their behalf and published from the Uno app through mkit (external site). Nothing in the protocol is specific to code, and any content-addressed object can be published under a registered scheme.

Where content lives

Most of the design follows from one decision: the chain holds identity, authority, and the order of publications, and the content lives elsewhere. It is kept in availability layers, stores that a team runs or chooses, one or more per project. Because the chain holds only hashes, it stays small, and privacy becomes a property of the store: a project can publish private work with a public hash and private bytes. Each layer sets its own access policy and billing, and can disclose content to everyone, to selected parties, or to no one. That policy belongs to the layer, not the protocol, but it can rely on verified facts from the chain. A layer can, for example, grant access by Makechain account and widen it over time, disclosing a project's content progressively. What the chain itself records, meaning the hashes, pointer names, accounts, and timing, is public.

Verification

A set of validators agrees on each block and finalizes it. Anyone can then check any part of the record against a finalized block, including in a web browser, without trusting whoever returned the answer. The same check works from other blockchains, because every block is finalized under one public key that stays the same for the life of the chain. A smart contract on Tempo or any other EVM chain can hold that key and confirm for itself that a block is final, that a publication is in it, and that an object belongs to a project. A proof establishes that an object was published. It says nothing about what the object contains, or whether its bytes can still be downloaded.

Paying for usage

Usage is paid for in credits. An account obtains them by depositing a dollar stablecoin on Tempo, and a proof of that deposit credits the account at one credit per millionth of a dollar. Prices come from a fixed, published table, so there is no fee market to bid in. Credits cannot be transferred or cashed out, and that is what keeps them from becoming a token: they buy usage on Makechain and nothing else.

How the system fits together

Makechain is a small consensus core surrounded by services that hold no authority. The core orders and finalizes commands. The services around it admit commands, keep history, answer queries, and hold content, and none of them can change what the core decided. Every answer a client receives can either be checked against something the validators certified, or is labeled as one service's claim. Among the parts of the system, only the validators have to be trusted, and only as a group: the chain stays safe while fewer than a third of them misbehave. Governance and Tempo are trusted separately, as the last section explains.

  • Validators order commands into blocks, execute them, and finalize each block by vote. They serve no reads to clients.
  • The exporter executes the same blocks without voting, and publishes every block to two long-term copies of history, the store and the mirror. It also serves current-state proofs.
  • The proof service answers proofs about older history from the store.
  • The indexer answers queries, streams events, and assembles publication receipts.
  • The gateway is the front door. It accepts signed commands from clients and passes reads and proofs back to them.
  • The relayer turns deposits on Tempo into credit imports.
  • Availability layers hold the content.
flowchart TB
  EVM["Contract on an EVM chain"]
  C["Clients: apps, agents, CLI, browser"]
  AV["Availability layers"]
  GW["Gateway"]
  RL["Relayer"]
  TP["Tempo"]
  V["Validators<br/><i>consensus core</i>"]
  EX["Exporter"]
  ST["Store and mirror"]
  PS["Proof service"]
  IX["Indexer"]
  C -. "proofs" .-> EVM
  C -- "content" --> AV
  C <-- "commands and answers" --> GW
  TP -- "deposits" --> RL
  RL -- "credit imports" --> GW
  GW -- "commands" --> V
  V -- "finalized blocks" --> EX
  EX -- "every block" --> ST
  ST --> PS
  ST --> IX
  EX -. "current-state proofs" .-> GW
  PS -. "proofs" .-> GW
  IX -. "queries, receipts" .-> GW

The life of a publication

Suppose a person wants an agent to publish changes to one of their projects. Before the agent can do anything, the person authorizes a key for it: a delegated key that may only push to that project and that expires after a set time. Authorizing the key is itself a command, finalized like any other. From then on every validator knows exactly what the key may do, and the person can revoke it at any moment. This happens once for the life of the key. After that, each publication has two halves, the content and the command, and is complete only when both are done. The steps below follow one publication from upload to a verified receipt.

  1. Store the content. The agent uploads the new objects to one of the project's availability layers. A layer that follows the availability profile checks the chain first and accepts the upload only if the agent's key, and the account it acts for, may currently write to the project.
  2. Sign the push. The agent builds a push that names the new objects and the branch moves, and signs it with the key it was given. The push records both the person's account and the agent's key. The signature covers everything that decides what the command does, including the rules and prices in force and the most the agent is willing to pay, so the command cannot be replayed or run under conditions it was not signed for. Proofs that each branch target was published travel beside the signature, so a gateway can refresh them.
  3. Submit. A gateway runs quick checks on the signature, replay protection, and rate limits, then forwards the command to the validators. Acceptance at this stage is not a promise, since only execution inside a block decides whether the command is valid.
  4. Finalize. A leader proposes a block containing the command. The other validators re-execute it and vote, and when enough of them agree, the block is final and carries a finalization certificate, one signature under the chain's public key.
  5. Publish to history. Validators keep only recent blocks, so the exporter, which executes the same blocks, queues the finalized block and its certificate and publishes them to the store and the mirror.
  6. Get a receipt. The event stream reports that the command was finalized. The agent then asks the indexer for a publication receipt: a portable proof that this account published this object into this project, at this position in the chain, signed by the agent's key.
  7. Verify. The agent, or anyone else holding the receipt, checks it with their own verifier against the chain's public key, trusting nothing in between. A contract on an EVM chain can check the same inclusion.
sequenceDiagram
  participant P as Person
  participant A as Agent
  participant L as Availability layer
  participant G as Gateway
  participant V as Validators
  participant X as Exporter
  participant S as Store and mirror
  participant I as Indexer
  P->>G: authorize a key for the agent, limited to one project
  Note over P,G: once per key, before any publication
  A->>L: upload objects (layer checks write rights on chain)
  A->>G: signed push
  G->>V: quick checks, then forward
  V->>V: propose, re-execute, vote, finalize
  V->>X: finalized block and certificate
  X->>X: queue block and certificate before pruning
  X->>S: upload to store and mirror
  I->>S: read the stored block
  I-->>A: event, then a publication receipt
  A->>A: verify the receipt against the chain's key

In the spec: ch. 2, System overview · ch. 12, Execution and block validity · ch. 15, Proofs, light clients, and publication receipts · client-api.md

Accounts and keys

An account's address never changes. A single-key account is the Ethereum-style address of one secp256k1 key, as on Tempo. A configured account has several weighted owners and a signing threshold, and its address is derived from its first owner configuration exactly as Tempo derives its configurable accounts under TIP-1107 (external site), so one configuration is one identity on both chains. That derivation needs a factory address that a future release will set. Until then, accounts start single-key and can upgrade in place with ROOT_CONFIGURE, keeping their address.

The owners hold the account's root authority. An owner is a secp256k1, P256, or WebAuthn key, never another account, and the threshold lets the remaining owners recover from one lost key. Tempo is the model for accounts, not a dependency: validators never read Tempo to check authority, and once an account is set up, its configurations on the two chains evolve independently. An account's first credit import creates its ledger, and INIT_ACCOUNT then sets up its authority.

Delegated keys do the day-to-day signing. The account's owners issue each one with KEY_AUTHORIZE, under root authority. Each key has a capability class, from broadest to narrowest ACCOUNT, PROJECT, WRITE, and SOCIAL, and each class includes the ones below it. A key also has an expiry, and a WRITE key can be confined to one project. A SOCIAL key authorizes no command and signs only off-chain messages. Ed25519 keys sign through SSH signatures, so ssh-agent works as a signer, while P256 and WebAuthn keys cover secure enclaves and passkeys. Keys have no spending limit, so a leaked key can spend within its class until it is revoked.

Each key records the account's delegation epoch when it is issued. KEY_REVOKE(All) advances the epoch, which invalidates every earlier key in one step. Signatures also bind the authority context they were made under, so re-granting a key or a role never revives an old signature. Separately from its keys, an account can lease a username at a flat annual price.

In the spec: ch. 7, Accounts and authorization · client-api.md

Projects, pushes, and refs

The set of commands stays small on purpose: the chain orders only what benefits from having every validator order it, forever. The seventeen commands fall into six families:

Family Commands
Account INIT_ACCOUNT, ROOT_CONFIGURE, KEY_AUTHORIZE, KEY_REVOKE
Project PROJECT_CREATE, PROJECT_SET_METADATA, PROJECT_SET_STATUS, ROLE_SET, TRANSFER_OFFER, TRANSFER_ACCEPT
Publication PUSH
Cleanup RECLAIM
Usernames USERNAME_CLAIM, USERNAME_RELEASE
System IMPORT_CREDITS, SCHEDULE_RELEASE, VALIDATOR_SET_SCHEDULE

A project is either active or frozen, and a frozen project accepts no pushes. Its controller grants maintainer and writer roles, maintainers can also grant writer roles, and roles decide who may publish, never who may read, because everything in a block is public. A push needs two separate permissions: the account must control the project or hold a role in it, and the signing key's class and scope must allow the push. A delegated key can narrow what its account may do, never widen it. Ownership moves by an offer and an acceptance, and the transfer voids every role granted before it. A fork is a new project that names the commitment it started from, as the creator's claim, which the chain does not verify.

PUSH works as one unit. It appends its commitments to the project's membership log, the permanent list of everything ever published to the project, and then applies its ref operations, each of which creates, moves, or deletes a ref. An operation succeeds only if the ref still holds the value the signer expected, so two writers racing on one branch cannot both win. If any step fails, the whole push fails, because a ref pointing at an unpublished object is the one inconsistency the chain could never repair later.

The chain does not check ancestry between a ref's old and new targets, so any authorized writer can force-update a ref. What it does check is that every new target was published. Each ref update carries a witness showing that its target is in the project's membership log, and the validator checks it against a root it computed itself. This keeps every ref pointing at a published object without an index of every published object.

A scheme registry gives commitments their meaning. mkit-blake3 is the primary scheme, and git-sha1 and git-sha256 serve native git projects. Validators never read the objects, and commit metadata such as the author or message never goes on chain. Links, reactions, reviews, and profiles are off-chain messages signed with the same keys, and the one on-chain step of a merge is an ordinary push.

In the spec: ch. 8, Commands · state-machine.md · off-chain-signed-messages.md

State and its growth

Every block header commits the roots of three authenticated databases, built on QMDB, Commonware's authenticated store. Each one holds data with a different lifetime:

  • Validity state holds every record execution reads or writes: accounts, keys, projects, refs, roles, usernames, credit balances, and schedules. Every node keeps it whole.
  • The membership log holds one permanent entry per published commitment. Its root covers the whole log forever, but validators keep only a recent window of entries.
  • The block-history accumulator holds one entry per block, linking it to its parent. With it, a single later certificate proves that any earlier block is final.

Blocks and certificates follow the same pattern as the membership log. Validators keep a recent window, and the store and the mirror keep everything. Validity state is therefore the part of the chain that grows, and its growth is priced and rate-limited, never capped. Every record an account creates pays a creation fee, and for a permanent record that fee helps fund long-term history storage. Records that can be deleted, such as refs, roles, and keys, also lock a deposit, which comes back as credits when the record is deleted.

No block sweeps away expired records. Instead, RECLAIM lets any account delete a stale record, such as an expired key, and returns the deposit to whoever paid it. A per-block limit on new records bounds how fast state can grow.

In the spec: ch. 9, State and record lifecycle · ch. 10, Resources and pricing · architecture.md §10

Consensus and validators

Consensus is Simplex, from the Commonware (external site) library the node is built on. A randomly chosen leader proposes each block, votes are BLS12-381 threshold signatures, and the chain tolerates up to ⌊(n − 1)/3⌋ faulty validators. Every validator re-executes each proposed block and rejects it if anything it derives differs from what the proposer claimed. A block header commits the link to its parent, the release in force, the three database roots, and the root of a Merkle tree over the block's commands, and a finalization certificate signs the Keccak256 hash of that header.

The chain is defined by a genesis chainspec, and its hash is the chain id. Every signature binds the chain id, so a signature made for one chain means nothing on another. The chainspec also fixes the consensus profile. Production networks use DynamicReshareV1, and a second profile, FixedEpochZeroV1, runs a fixed committee of seven and exists only for disposable development networks.

Under the production profile, the chain's key comes from a one-time trustless key generation, so no single party ever knows the group secret. The committee starts at seven validators, and a governance multisig changes membership with VALIDATOR_SET_SCHEDULE, adding at most one member and removing at most one per change. Each epoch the validators reshare the key to the next epoch's committee, and the public key never changes. One trust anchor therefore serves a light client for the chain's whole life, and a new key means a new chain.

In the spec: ch. 5, Chain identity and chainspec · ch. 11, Blocks and headers · ch. 13, Consensus and validator membership

Proofs and their limits

Makechain uses two hash functions. Everything a verifier hashes on the way from a certificate to a proven fact uses Keccak256, because EVM contracts compute it cheaply. Almost everything else uses BLAKE3, which is faster and is mkit's own object hash. The exceptions are Tempo's account formulas, which keep Tempo's Keccak256 format, and the hashes inside each signature scheme.

A verifier starts from a trust anchor it already holds: the chain id plus the genesis block, or a release checkpoint it has verified. It never takes the anchor from a response. From there, proofs can establish:

  • finality: a block is final, by its own certificate or by a later block's certificate plus an ancestry proof;
  • command inclusion: these exact signed bytes are in that block;
  • membership: an object is in a project's membership log;
  • release lineage: which rules a given height ran under;
  • current state: the live value of a record, served by the exporter at its latest height.

No proof establishes what content says, whether it is available, who authored it, or that a list is complete and up to date. "Not found" is always a service's claim, never a proven absence. Proofs of a record's past value are not offered at launch, so a client that will later need to show where a ref pointed should keep the current-state proof it read at the time.

A contract on an EVM chain can check finality, inclusion, membership, and ancestry with Keccak256 alone. It cannot read current state, because state keys are BLAKE3 hashes, and release lineage is current state. A contract therefore cannot check a full publication receipt on its own.

In the spec: ch. 6, Encoding and digests · ch. 15, Proofs, light clients, and publication receipts · client-api.md §5

History, queries, and availability

No node keeps all of history. Instead, the exporter has a duty to publish it. The exporter executes and prunes every block just as a validator does, but before pruning it puts the block, its certificate, and its history rows into a durable local queue. A background drain uploads each entry to both the store and the mirror, and drops it from the queue only once both have it. Consensus never waits on this, so an outage only makes the queue longer. If the queue fills up, the exporter pauses its own following until the drain frees space. Validators keep going.

The store serves reads. It runs exoware (external site), Commonware's data layer, inside a private network. The mirror is the durability copy, one object per block in a storage bucket under retention lock. Either copy can rebuild the other. A checker compares the store against certified headers and stops the drain on any mismatch, and a standby exporter queues every block too. History is lost only if both exporters fall further behind than the validators' retention window, or if the queues, the store, and the mirror all lose the same range.

flowchart TB
  subgraph val["Validator"]
    v1["live state"]
    v2["recent log entries, blocks, and certificates"]
  end
  subgraph exp["Exporter"]
    e1["the same as a validator"]
    e2["a durable publication queue"]
  end
  subgraph sto["Store and mirror"]
    s1["every block and certificate, forever"]
    s2["the full logs and history tables"]
  end
  val -- "finalized blocks" --> exp
  exp -- "publish before pruning" --> sto

Validators and gateways do not answer lists or searches. Queries go to exoware's SQL engine, over history tables the exporter writes with each block. Every query is pinned to the latest published height, so an answer built from several reads is one consistent snapshot. Query results and events are services' claims, so a decision that depends on authority, such as a layer checking upload rights or a client about to sign, should rest on a proof from the exporter.

Availability layers sit entirely outside consensus. None of them can spend a user's credits, and the chain records no location for content: a project's layers announce themselves in off-chain messages signed with the project's keys.

In the spec: ch. 14, Finalized events · ch. 17, Node roles and the database set · history-query.md · availability-profile.md

Credits and settlement

A credit is one microdollar, and every price and balance is a whole number of credits. Credits exist only because a deposit on an external EVM chain was proven, and at launch that chain is Tempo (external site). An immutable contract on Tempo accepts a dollar stablecoin and keeps a lifetime total for each beneficiary that only ever goes up.

A relayer submits IMPORT_CREDITS with a storage proof of that total, under a Tempo block header certified by Tempo's own threshold key, which Makechain keeps in its state. The beneficiary and the amount come from the proof, so a relayer cannot redirect credits. An import counts only if it raises the total already credited, so no deposit is counted twice. Genesis allocates no credits, and there is no faucet.

Tempo is an on-ramp, never an oracle. Makechain changes the Tempo key it trusts only through a release, and its trust in Tempo's latest certified header expires unless a newer header refreshes it. Governance can pause imports without undoing any that have finalized.

Fixed prices take the place of a fee market. Before any signature is checked, each command reserves its worst-case cost in three separate dimensions: bytes, work, and new records. The dimensions never convert into one another, so an abundance of a cheap resource cannot pay for an expensive one.

In the spec: ch. 10, Resources and pricing · ch. 16, Settlement · settlement-interface.md

Upgrades

A release names a ruleset, a class, and an activation height, and the governance multisig schedules it with SCHEDULE_RELEASE. Every release other than a pure parameter change is a hardfork, and every hardfork is a flag day: at the activation height, each node either runs the new rules or stops. A release that changes how a root is computed, an encoding, or the chain's public key is a reset, which starts a new chain with no inherited state.

Signed commands bind the ruleset and price schedule they expect. A command signed under rules that have since been replaced becomes invalid, and the client signs it again. Every ruleset that has ever been active stays in the node binary, so history always replays under the rules it was finalized under.

Releases that change consensus itself activate only at the start of an epoch, when every validator rebuilds its consensus engine together. There is no rollback. A problem is fixed by a successor release, through a faster emergency path that never applies to consensus changes. Pause switches for credit imports, username claims, and reclaims allow a response in the meantime without new code.

In the spec: ch. 18, Releases and hardforks · release-process.md

Trust and accepted risks

Role Consensus Serves
Validator votes consensus peers only (other validators and the exporter), no client reads
Exporter non-voting peer publication to history, current-state proofs, proofs within the recent window
Proof service none proofs about older history, from the store
Gateway none command admission and forwarding, pass-through of answers
Indexer none queries, events, inclusion proofs, publication receipts
Relayer none Tempo evidence and credit imports
Availability layer none content storage and retrieval, under its own policy

Among the roles in the table, safety rests on the validators alone and holds while fewer than a third of them are Byzantine. Every other role is untrusted, and the store and the mirror are storage rather than roles. The protocol names the risks it accepts:

  • Old key shares stay dangerous. Verifiers check the chain's key, not the current committee, so a quorum of key shares from any past epoch could sign under that key forever. Mandatory erasure of old shares limits this, and the only complete remedy is a new chain.
  • Credits are only as sound as Tempo. Issuance depends on Tempo's safety and on the value of the deposited stablecoin. Since credits never leave the ledger, a forged import buys usage, not money.
  • Governance is trusted. The multisig schedules releases and changes the validator set.
  • History can be lost under the two conditions described in History, queries, and availability.
  • Availability is outside consensus. The chain proves that an object was published, not that anyone still serves it.
  • Everything in a block is public.

In the spec: ch. 4, Assumptions and threat model · ch. 17, Node roles and the database set

Further reading

This overview is not normative. The specification is, and where the two differ, the specification governs. The documents below go deeper, grouped by purpose: