Live on Ethereum Sepolia, Tron Nile & BNB Smart Chain testnets
A payment rail
AI agents can be trusted with.
Software agents are starting to spend money. Varnir is the ledger underneath them — a chain in its
own right, settling across the chains they already use. One agent proposes a payment, other
agents verify it, and nothing moves until they have.
Testnet. The ledger, wallets, exchange, invoicing and SDK are built and running on public
test networks, with no real funds. Two-key approval is built; the wider multi-verifier layer is where this
is going, not something you can use today. This page says which is which.
01 — The problem
An agent that can pay is an agent that can be wrong expensively.
Give a model a key and it can move money. That is the whole security review. Nothing sits between the
inference and the irreversible transaction: no second opinion, no policy check the model cannot talk its
way past, no record of why the payment was thought correct.
i
One model, one signature, no recourse
One agent holding one private key is a single point of failure. Prompt injection, a hallucinated
invoice, a poisoned tool response — each ends the same way: a valid signature over a payment nobody
sanctioned.
ii
Custody is the actual risk
The usual fix is to hand the key to a platform. Now the platform can move your funds, and its breach is
your breach. Swapping one unaccountable signer for another is not a control.
iii
Nothing to audit afterwards
"The agent decided to" is not an audit trail. Without a record of what was proposed, what checked it
and why it passed, nobody can reason about an automated treasury — and nobody accountable will sign
off on one.
02 — The approach
Put agents on both sides of the transaction.
An agent proposes a payment. It does not execute one. Independent verifying agents check the proposal
against treasury policy, and only an approved proposal settles. The proposer never holds unilateral
authority, because authority is the thing being split.
The rail — your policy plugs in
Varnir enforces the split — who may propose, who may confirm, and that no key confirms its own proposal.
What each verifier checks is your policy to write, not ours to prescribe. Every decision —
approval or refusal — is a record you can go back and read.
That is the shape it is heading for. The first rung is built and running on public testnet today:
two keys on one identity, and a payment that cannot happen until the second one says so.
Built — on testnet today
The split is enforced by key authority at consensus — not by a permission check an API could get wrong,
and not by the agent behaving itself. The ledger refuses a compromised agent's payment. Nor can the
approver rewrite what it approves: amount, destination and network are read back out of the stored
proposal before anything executes. A stake-80 key has dual status — it can raise a transfer as
well as confirm one — and the one thing it cannot do is confirm the transfer it raised: the proposal
records which key created it, and that key's confirmation is refused. So two agents can check each other
with nobody privileged above them, and one compromised key is not enough — even though that key can do
both jobs. How it works, in code →
Built
Your key never reaches our servers
Not a policy — a property of the code, everywhere in the stack. Keys are generated in your process and
stay there. Transactions are signed locally and posted straight to a chain node, not relayed
through an API that could have signed for you.
The one thing our API is asked during wallet setup is which wallet id to claim — a public,
unauthenticated read. It hands out ids. It cannot assign one to you; that takes a transaction signed
with your own key.
Built
Signed requests, not bearer tokens
An API credential is a secp256k1 keypair you generate; we store only the public half. Each request
carries a signature over the route, a timestamp and the exact body — so there is no secret in a header
to leak through a log or a proxy, and a signature cannot be replayed against a different endpoint.
Built
Real infrastructure, not a diagram
Four ledger nodes, with onboarding, wallet assignment, transfer and swap written as on-ledger
contracts. A public scanner over it. Wallets, an exchange, invoicing and deposit webhooks across two L1
testnets. You can use it now.
Built
Approval as a first-class record
A proposal is not an allow or a deny that vanishes once acted on. It is a durable, on-ledger record of
exactly what was proposed and which authority confirmed it, readable on the public scanner afterwards.
That is what lets someone accountable sign off on an automated treasury: they can read what it did,
and on whose say-so.
Built
No bridge to hack
Varnir runs its own ledger with an L2 balance layer over it — and no cross-chain bridge. Nothing is
locked in a contract on one chain so a wrapped copy can be minted on another. USDT stays on Tron, ether
stays on Ethereum; Varnir mirrors what arrives and settles it internally.
Bridges are the largest single exploit class in crypto: value pooled behind one contract and one trust
assumption. Not having one does not make Varnir unhackable. It does mean the bridge-hack surface — the
one that comes with wrapped assets — is not there.
Built
Its own chain — and a layer over others
Varnir runs its own ledger with its own consensus: four nodes, its own state. By the usual test that
makes it a layer-1, not a contract deployed on someone else's chain. It just doesn't try to be the chain
your assets live on.
Value stays where it was deposited — USDT on Tron, ether on Ethereum. Varnir mirrors the deposit onto
its own ledger, settles transfers and trades between identities internally, and withdraws back to the
origin chain on the way out. So it is both: a sovereign ledger used as settlement tissue between the
chains that already hold the value, with no token or gas economy of its own. Balances stay denominated
in whatever you deposited.
03 — Live today
Testnet, and actually running.
Everything below is deployed on public test networks and reachable from this page. None of it handles real
funds, and we would rather say so plainly than let a landing page imply otherwise.
Named, referenced invoices across one or more wallets. Payment is detected from observed deposits; an
HMAC-signed callback fires at pending and again at confirmed.
USDT and native, both networks
Token registry
Which tokens the network credits is on-ledger state, not a list compiled into the code. Balances are
keyed by the token’s L1 contract address, not its ticker — two tokens can share a symbol
and never be confused for each other, and adding one is a ledger transaction, not a software release.
read it with listTokens()
Settlement layer
A custom Activeledger fork running as a four-node network, with onboarding, wallet assignment,
transfer and swap implemented as on-ledger contracts.
Ethereum Sepolia, Tron Nile & BNB Smart Chain
SDK
@varnir/chain-client and @varnir/signing — everything the web wallet does,
from your own code, signed on your side of the wire.
A native wallet on the same SDK — onboard, send, receive, trade, raise invoices and manage signing keys
from the phone. It also signs for the web scanner: pair by QR, and every action that needs a
signature is approved on the phone, where the key stays. Works on-device today; not in the app stores
yet.
On-device keys · QR remote signing
04 — Quantum-safe by design
The first quantum-safe order book.
The first we know of, anyway. Nobody can say when a computer running Shor's algorithm at scale arrives;
when it does, it can derive a private key from any secp256k1 public key it can see, and most of crypto's
public keys are already in view. Varnir is in an unusual position: it runs its own ledger, so it gets to
choose its own signature scheme — and it settles on chains whose scheme it cannot choose. What follows
is what that split lets us do, and where it stops.
Built — on testnet today
Post-quantum identities, on by default
A Varnir identity is a key on our own ledger, so we decide what kind of key it is. A new identity
signs with Falcon-512 by default, with ML-DSA-65 selectable — both NIST
post-quantum schemes — and its 12-word recovery phrase derives that same post-quantum key.
No classical key hides in the backup. A post-quantum key can sit beside a classical one on the same
identity while everything around it catches up.
Everything that key authorises on the L2 — transfers, withdrawal authorisation, and every make,
take and cancel on the exchange — is signed post-quantum. That is what the order-book claim rests
on. It is the identity key and its recovery, not the whole account: the settlement gateway's
custody-signing key is still classical secp256k1, and so are identities made before the release.
The recovery phrase is Varnir-internal — there is no cross-wallet standard
for post-quantum keys yet.
Coming — in design
QER: Quantum Exposure Reduction on L1
Ethereum, Tron and BSC sign with secp256k1, and no layer above them changes that. What Varnir can
change is how much value sits behind any key that does get exposed. QER is our own settlement pattern
for withdrawals: a fresh wallet for each one, no address used twice, and the change swept to a
brand-new wallet in the same act. A key is exposed once, and by then it guards next to nothing.
On Ethereum the signed withdrawal will go out through a private relay rather than the public mempool,
closing the window in which a transaction is visible but not yet included — the same route that
protects against front-running. That piece is Ethereum-only; on Tron and BSC, QER is the fresh-wallet
discipline alone.
Three things this is not. It is not your whole account: the identity key and its recovery are
post-quantum; the gateway's custody key is not yet, and neither are identities made before the release.
It is not L1 becoming quantum-proof:
nothing Varnir does changes what Ethereum accepts as a signature, and QER — still a design, not a
code path — lowers the value at exposure rather than removing it. And it is not mainnet: this is the
public testnet, with no real funds. Each row gets marked built here when it is, and not before.
What is covered, and what isn't →
05 — Where this is going
The convenience of an exchange, without the custody.
What makes a centralised venue pleasant is that a trade is a bookkeeping entry between two accounts on one
system — instant, no gas, no waiting for a block. What makes it dangerous is separate: it holds the assets,
so it can lose them, freeze them or spend them. The two come apart, and this rail is already on the right
side of both.
Built
Balances already settle internally
A deposit credits an L2 balance on your own identity, written on-ledger as it confirms. Reading your
balance is reading your own stream — not asking us what we think you have.
Built
And nobody here holds the keys
The keys that could move those funds on L1 are never whole at Varnir — split across independent node
operators, or generated so the key is never assembled anywhere at all. There is no operator override
to ask for, and none to steal.
Built
Gas-free transfer between identities
The settlement half of trading is written and reachable: one transaction debits an identity's
L2 balance and credits another's, touching no L1 chain and paying no gas. It is an SDK call —
transferOnLedger — and the swap contract built on the same move settles both legs of a
trade in one transaction, or neither. That is what the exchange above runs on.
The swap primitive, in code →
Not built
Treasury-grade trading, and fees
A treasury identity can't trade under propose-and-verify yet — an order from one fails closed rather
than settling unchecked. And there is no fee in v1: that model is undecided, so nothing is charged.
Agents come first here on purpose. An agent trading against a bounded, approvable balance is a smaller
promise than a person's savings, and it exercises the settlement layer for real while the amounts stay
proportionate to a testnet. People's own funds are a higher bar, and the bars should be cleared in that
order.
The full roadmap, including what is missing →
06 — Build on it
Five steps from nothing to a live invoice.
Generate a key, onboard it, claim a wallet, register a scoped signing key, raise an invoice. Every
signature happens in your process.
wallet-and-invoice-flow.ts
// 1. A key you generate, and keep. It never leaves this process.const phrase = generateRecoveryPhrase();
const { privateKeyHex } = derivePrivateKeyFromPhrase(phrase);
// 2. Onboard it. Signed here, posted straight to a chain node.const client = await VarnirClient.onboard({ privateKeyHex });
// 3. Claim a wallet, then prove ownership on-chain.const wallet = await client.getWallet('niles');
// 4. Attach a scoped key — a real authority on your ledger identity.const scoped = VarnirClient.generateKey();
await client.addKey({
publicKeyHex: scoped.publicKeyHex,
role: 'offledger',
scopes: ['invoices:create'],
});
// 5. Raise an invoice — signed request, no bearer token.const invoice = await client.createInvoice({
wallets: [wallet.id],
amount: '10',
currency: 'native',
name: 'Order 4021',
});
# 1. A key you generated and kept. It never leaves this process.
private_key = '0x59c6995e…'# 2. Onboard it. Signed here, posted straight to a chain node.
client = VarnirClient.onboard(private_key)
# 3. Claim a wallet, then prove ownership on-chain.
wallet = client.get_wallet('niles')
# 4. Attach a scoped key — a real authority on your ledger identity.
client.add_key(AddKeyOptions(
public_key=scoped_public_key, # yours, generated and kept
role=KeyRole.OFFLEDGER,
scopes=['invoices:create'],
))
# 5. Raise an invoice — signed request, no bearer token.
invoice = client.create_invoice(
wallet_ids=[wallet.id],
amount='10',
currency='native',
name='Order 4021',
)
// 1. A key you generated and kept. It never leaves this process.var privateKey = "0x59c6995e…";
// 2. Onboard it. Signed here, posted straight to a chain node.using var client = VarnirClient.ForPrivateKey(privateKey);
await client.OnboardAsync();
// 3. Claim a wallet, then prove ownership on-chain.var wallet = await client.GetWalletAsync("niles");
// 4. Attach a scoped key — a real authority on your ledger identity.await client.AddKeyAsync(newAddKeyOptions {
PublicKey = scopedPublicKey, // yours, generated and kept
Role = KeyRole.OffLedger,
Scopes = new[] { "invoices:create" },
});
// 5. Raise an invoice — signed request, no bearer token.var invoice = await client.CreateInvoiceAsync(
walletIds: new[] { wallet.Id },
amount: "10",
currency: "native",
name: "Order 4021");
// 1. A key you generated and kept. It never leaves this process.val privateKey = "0x59c6995e…"// 2. Onboard it. Signed here, posted straight to a chain node.val client = VarnirClient.forPrivateKey(privateKey)
client.onboard()
// 3. Claim a wallet, then prove ownership on-chain.val wallet = client.getWallet("niles")
// 4. Attach a scoped key — a real authority on your ledger identity.
client.addKey(AddKeyOptions(
publicKey = scopedPublicKey, // yours, generated and kept
role = KeyRole.OFFLEDGER,
scopes = listOf("invoices:create"),
))
// 5. Raise an invoice — signed request, no bearer token.val invoice = client.createInvoice(
walletIds = listOf(wallet.id),
amount = "10",
currency = "native",
name = "Order 4021",
)
Varnir is a working testnet with a clear thesis, not a finished product. If AI agents paying on their own
behalf is a problem you are thinking about — something to build on, integrate, or argue with — the code is
the honest version of the pitch.