Unbridged Protocol

Every bridge is a proof system wearing a costume.

A bridge answers “does this holder have the asset?” with a signature. Unbridged answers it by reading the state. No wrapping, no custody, no reporter — and nothing that has to be believed.

$UBR · 1,000,000,000 fixed Uniswap v4 · flags 0x2080 Ethereum mainnet Fee 1.00% → 0.40%

01The costume

Why every bridge fails the same way

Every bridge failure in history is the same sentence: the custody was real, the claim was not. You hand an asset to a contract on one chain, it mints a receipt on another, and the receipt is worth exactly what the guard of the original is worth.

The cryptography is almost never what breaks. What breaks is the reporter — some address, committee, multisig or relayer trusted to say what the other side looks like. Wrapping and custody are not features of bridging; they are the attack surface.

The inversion

Unbridged never asks you to move anything. You declare yourself present, and the protocol reads your balance where it already is. Nothing is wrapped, nothing is locked, and no contract in this system can hold, move, freeze or mint a single UBR.


02Attestation vs verification

The whole argument, in one control

Both models below answer the same question. One is told the answer by a reporter; the other checks. Corrupt the reporter and watch which one notices.

Statement — “holder controls 100,000 UBR”

Bridge

Attested

State on Ethereum100,000
Reporter signshonest
Claim on target100,000
Accepted — because it was signed.

Unbridged

Verified

State on Ethereum100,000
No reporter exists
isPresent() reads it100,000
Accepted — because it was checked.

There is no honest-reporter setting on the right-hand side, because there is no reporter. That is not a stronger assumption — it is one assumption fewer.


03The proof system

Stated in the vocabulary it belongs to

Zero-knowledge storage proofs exist to delete the reporter: they let a verifier check a state slot it cannot read, instead of being told about it. Unbridged is that thesis carried through the whole system — verification everywhere, attestation nowhere. Reduced to its floor, Presence is a proof system, and it is worth writing out as one:

Statement
This address holds at least FLOOR of UBR.
Witness
The holder’s own balance slot, in Ethereum state.
Verifier
Presence.isPresent(address) — two SLOADs.
Setup
None. No ceremony, no proving key, no toxic waste.

On the chain where the state lives you can simply read it, so the proof collapses into the check itself. The prover is the chain. Same guarantee, same trust model, none of the circuit — and one SLOAD instead of a pairing.

Soundness

No false statement can be accepted. isPresent() cannot be made to return true for an address below the floor, by anyone, at any price. It re-reads the balance at the instant it is asked: no cache, no snapshot, no admin override. There is no stale-proof window because there is no stored proof.

Completeness

No true statement can be censored. Anyone above the floor may call declare() — permissionless and unpriced — and no address can be removed, blocked or expired by anyone, including the deployer. No merkle root to be included in, no signature to obtain from a server.


04Presence

The register — declared by the holder, never assigned

declare() is callable once per address, ever. It costs gas and nothing else: no approval, no transfer, no stake, no deposit. The register writes down the block you declared at and increments two counters.

function declare() external {
    if (declaredAt[msg.sender] != 0) revert AlreadyDeclared();
    uint256 held = token.balanceOf(msg.sender);
    if (held < FLOOR) revert BelowFloor(held, FLOOR);

    declaredAt[msg.sender] = uint64(block.timestamp);
    unchecked { reach += 1; }
    bool sovereign = msg.sender.code.length == 0;
    if (sovereign) { unchecked { sovereignReach += 1; } }
}

sovereign records whether the declaring account carried no code at that moment — a plain key, not a contract. It is published as a statistic and deliberately settles no value.

There is no undeclare

Not an oversight. There is nothing to give back, and nothing to revoke — the verifier already stops answering true the moment the balance drops. A function to undo it would be decoration.


05The live witness

A declaration is about the past; presence is about now

Because the witness is read fresh on every call, a declaration that is no longer backed stops verifying the instant the tokens leave — with no keeper, no expiry job and nothing to prune. Drag the balance below the floor and watch the verifier answer.

Wallet balance 240,000 UBR
0FLOOR — 100,000400,000
isPresent()
true
Fee charged
0.40%
Declaration
intact

The declaration never changes — it is intact in every state above. Sell back above the floor and you are present again, on the same declaration. State cannot lie about itself.

Why sybils prove nothing

The economics are per-address, not global. A valid proof lowers the fee on your swaps and nobody else’s, so splitting a balance across a hundred wallets buys a hundred proofs of a hundred smaller positions and costs a hundred floors to carry. It gains nothing, and reach settles no value, so inflating it purchases a larger number on a picture and not one wei.


06The hook

Verification at the point of execution

What proofs buy is the right to act on state you did not write. A Uniswap v4 hook is where that becomes useful: it runs inside the swap, so a proof checked there decides execution itself rather than being posted somewhere afterwards and hoped about.

function beforeSwap(...) external view returns (bytes4, BeforeSwapDelta, uint24) {
    if (!_isOurPool(key)) return (selector, ZERO_DELTA, 0);
    uint24 fee = presence.isPresent(tx.origin) ? PRESENT_FEE : BASE_FEE;
    return (selector, ZERO_DELTA, fee | OVERRIDE_FEE_FLAG);
}

Both figures are ordinary Uniswap LP fees paid to liquidity providers. The hook takes no share and holds no balance, and has no withdrawal function because it has nothing to withdraw. Both fees are immutable and hashed into the hook’s mined address — the fee you read today is the fee forever.

Dynamic-fee pool — required

The pool must be initialised with key.fee == 0x800000 (8388608) and tickSpacing == 200. beforeInitialize rejects anything else, so the pool cannot be created with the wrong parameters — by you or by anyone.


07The commitment chain

Sealed by anyone, attested by nobody

A proof system needs something to prove about. Ledger keeps a growing chain of sealed readings: one immutable entry per four-hour epoch, each a commitment to what the register held, permanent the moment it is written.

seal() takes zero arguments

It accepts no claims, no submitted proofs and no signatures. It reads Presence and the token directly, at the block it is called, and writes down what it found. There is nothing to forge and nothing to dispute. Two callers in the same epoch get the same answer, and the second reverts.

struct Entry {
    uint64  sealedAt;   // when it was written
    uint32  reach;      // declarations ever made
    uint32  sovereign;  // of those, from accounts with no code
    uint128 burned;     // UBR destroyed, ever, at that moment
}

Sealing is permissionless and unrewarded on purpose. There is nothing to win by sealing early, late or often, so there is nothing to game — an epoch nobody seals simply has no entry, and the gap is visible in the chain forever.


08Emissaries

A commitment made portable

An emissary is the oldest answer to the cross-chain problem, and the one every proof system is trying to replace: you cannot send the state, so you send someone who saw it. This is that, made literal — and made harmless.

claim() mints an ERC-721 that freezes the latest sealed entry and never changes it. It carries no authority: it cannot move value, settle anything, or be presented anywhere to unlock a balance. Its art is drawn fully on chain — a bright origin node with sight lines out to satellites, and the spokes carry nothing, because they are sight lines and not bridges.

Why forging one gains nothing

A bridge receipt is a claim you are expected to honour. An emissary is a copy of something already public and already immutable — anyone can check it against the Ledger without asking the holder anything at all.


09Parameters

Every number, and whether it can move

ParameterValueMutable
Total supply1,000,000,000 UBRNo — no mint exists
Presence floor100,000 UBR (0.01%)No — immutable
Base fee10000 pips — 1.00%No — mined into the address
Present fee4000 pips — 0.40%No — mined into the address
Epoch4 hoursNo — immutable
Pool fee8388608 (dynamic flag)Fixed at initialise
Tick spacing200Fixed at initialise
Hook flags0x2080No — it is the address

Contracts

ContractSizeRole
UnbridgedToken3,005 BUBR. The witness. No tax, no mint, no owner after launch
Presence1,876 BThe verifier
UnbridgedHook3,900 BVerification inside the swap
Ledger2,832 BThe commitment chain
Emissary5,287 BERC-721 carrying a sealed commitment
EmissaryRenderer3,472 BOn-chain constellation

10Contract API

Everything an interface needs

Presence

declare()                    // once per address, ever
isPresent(address) → bool    // the verifier; live, never cached
statusOf(address)
    → (declared, present, since, held, floor)
stats() → (reach, sovereign, floor)
declaredAt(address) → uint64
FLOOR() → uint256

UnbridgedHook

quoteFee(address) → (uint24 fee, bool present)
BASE_FEE() → uint24        // 10000 = 1.00%
PRESENT_FEE() → uint24     // 4000  = 0.40%
HARD_CEIL() → uint24       // 100000, a construction bound

Ledger

seal()                       // no arguments, permissionless, unrewarded
entries(uint64) → Entry
latestEpoch() → uint64
sealedCount() → uint64
EPOCH() → uint64            // 14400 seconds
GENESIS() → uint64

Emissary · Token

claim() → uint256           // mint an emissary of the latest sealed epoch
tokenURI(uint256) → string  // on-chain JSON + SVG

burn(uint256)               // destroy your own UBR
openTrading()               // once; deletes the launcher role

11Reverts

What refuses, and why

ErrorRaised byMeaning
AlreadyDeclared()PresenceOne declaration per address, forever
BelowFloor(held, floor)PresenceYou cannot declare what you do not hold
PoolNotDynamicFee(exp, got)HookPool not initialised with 0x800000
WrongTickSpacing(exp, got)HookSpacing is not 200
NotOurPool()HookWrong currency pair
AlreadySealed(epoch)LedgerThat epoch is already committed

12Verify it yourself

Do not take any of the above on faith

Everything on this page is a claim about state you can read. The point of the protocol is that you never have to believe a reporter — including this website.

# am I present, right now?
cast call $PRESENCE "isPresent(address)(bool)" $YOU

# everything about one address, in one call
cast call $PRESENCE "statusOf(address)(bool,bool,uint64,uint256,uint256)" $YOU

# what would I pay on the next swap?
cast call $HOOK "quoteFee(address)(uint24,bool)" $YOU

# the fees are immutable — read them, then read them again in a year
cast call $HOOK "BASE_FEE()(uint24)"
cast call $HOOK "PRESENT_FEE()(uint24)"

# the commitment chain
cast call $LEDGER "latestEpoch()(uint64)"
cast call $LEDGER "entries(uint64)(uint64,uint32,uint32,uint128)" $EPOCH

The hook’s permissions are not a claim either — they are its address. The low 14 bits of 0x…2080 are beforeInitialize | beforeSwap, which is why the address had to be mined and why it cannot silently gain a permission later.


13Fork results

Mainnet fork, every check passing

PASS
A static-fee pool is rejected
PASS
The wrong tick spacing is rejected
PASS
An undeclared wallet pays 10000 pips (1.00%)
PASS
A declared wallet pays 4000 pips (0.40%)
PASS
Declaring below the floor reverts
PASS
Declaring twice reverts
PASS
Selling below the floor ends presence — with no keeper
PASS
Buying back restores it on the original declaration
PASS
A stranger sealed an epoch
PASS
The sealed entry matched a direct read
PASS
Sealing the same epoch twice reverts
PASS
The emissary froze the sealed number, not a live one
PASS
The art contains no quote or backslash — it cannot break out of the JSON

Buy gas measured at 102k–118k, normal for a v4 swap; the hook adds roughly 5k, which is two SLOADs and a call.


14What it cannot do

The list that matters more than the feature list

  • No custody. No contract in this system ever holds UBR.
  • No mint. Supply is written once in the constructor; the function does not exist.
  • No owner. After openTrading() there is no privileged address anywhere.
  • No fee setter. Both fees are immutable and mined into the hook’s address.
  • No transfer tax. Sending UBR wallet-to-wallet costs what any ERC-20 costs.
  • No pause, no blacklist, no upgrade. There is no proxy and no admin.
  • Your LP is yours. The hook owns no liquidity; you add and remove it on Uniswap normally.

15Succinct proofs

Where a circuit is actually required — stated plainly

On the chain where the state lives, a storage proof collapses into the check itself: you can read the slot, so the canonical state is the witness. That is what ships today, and it is why verification costs one SLOAD instead of a pairing.

Extending the identical statement to a slot on another chain is exactly where a succinct proof becomes necessary — and it is the direction this design is built to take. The commitment chain exists so that a future prover has a stable, append-only sequence to prove against.

Read the source, not the roadmap

What is deployed today verifies state directly on Ethereum, with no reporter, no committee and no light-client assumption. Cross-chain proving is a stated direction, not a deployed claim — and every contract is verified, so you never have to take that distinction on trust either.


16FAQ

Short answers

Does declaring lock my tokens?

No. Nothing is deposited, transferred or escrowed. declare() costs gas and writes a timestamp. Your tokens never leave your wallet — that is the entire point.

What happens if I sell?

The moment your balance drops below the floor you stop being present, silently and instantly. No keeper runs, nothing is revoked. Buy back above the floor and you are present again on the same declaration.

Can I declare twice, or undeclare?

Neither. declare() reverts with AlreadyDeclared() after the first call, and there is no undeclare because there is nothing to give back.

Why can’t I create the pool on the Uniswap app?

It is a dynamic-fee pool — the fee is decided by the hook per swap, so it has no standard fee tier. The pool must be initialised with fee = 8388608 and tickSpacing = 200, which the app does not offer.

Who can change the fees?

Nobody. Both are immutable and hashed into the hook’s mined address. Changing either would require a different address, which would be a different hook and a different pool.

Is sealing profitable?

No, deliberately. It is permissionless and unrewarded, so there is nothing to win by sealing early, late or often — and therefore nothing to game.