Overview
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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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:
- The full protocol: the specification, read from the start, with the encoding contract and the state-machine tables alongside it.
- Building a client or a verifier: client-api.md, then chapters 6 and 15 of the specification.
- Running a node or the history services: architecture.md, operations.md, history-query.md, and chapter 17.
- Running an availability layer: availability-profile.md.
- Project status: the README (external site).