Bound

Trust model

What Bound proves without trusting anyone, what it does not, and where the edges are.

A protocol that is vague about its assumptions is asking to be trusted about trust. This page is the opposite: it lists what holds unconditionally, what depends on someone, and what is simply not built yet.

What is trustless

Three of the four proofs. Each is arithmetic over state the contracts already hold, so the contract rules on it itself. No oracle, no arbiter, no vote.

  • InsufficientReserve — the certificate's claimed reserve against the vault's live balance for that certificate.
  • BoundExceeded — the PaymentRouter's cumulative routed spend for the certificate against its certified bound.
  • ExpiredCertificate — the router's record of payments that settled after expiry.

Filing opens a 72-hour claim window rather than settling on the spot, so claimants who arrive later are paid on the same terms as the first. Anyone may close a lapsed window; the call is permissionless.

Read what these actually pay out before relying on them: BoundExceeded and ExpiredCertificate settle in hygiene mode — the certificate is killed and the challenger paid a flat bounty, and the auditor is not slashed. Routed spend is gross flow, not loss, and both predicates are manufacturable by the operator for the price of gas.

The locks. release_to_operator() reverts before unlock_at. release(auditor) reverts before locked_until. Those are contract conditions, not policies.

The reads. verify, get_balance and get_stake are public views that anyone can simulate for free. You never have to accept a reported number.

What requires trust

FakeSignature, and any assessment of harm. A forged attestation leaves no on-chain trace to read, so it is the one proof type that still needs a named arbiter, set at initialization. The arbiter also supplies the harm figure that sizes a victim payout, because no predicate can name who was hurt or for how much. That is a trusted party, and it is now scoped to exactly this. In v1 it also covered BoundExceeded; the router closed that gap.

Naming the victim. Even on the trustless path, the challenger names who was harmed. The contract proves the reserve was short; it does not prove who suffered from it.

The auditor's diligence. The protocol guarantees the auditor loses their stake for a false vouch. It does not guarantee they checked carefully — it makes not checking expensive.

Known limits of the current deployment

  • Reserves are per certificate. Each certificate's reserve is held and locked under its own id, and only that certificate's operator can fund or reclaim it.
  • Testnet only. No mainnet deployment exists. Amounts are testnet USDC.
  • Stake sizing is a policy question. The protocol enforces that a stake exists and is slashable, not that it is large enough relative to the bound. That is the reader's call — both numbers are on the certificate.
  • Expiry is not revocation. An expired certificate stops being valid; it does not become invalid. Invalid means a challenge succeeded.
  • Pre-production. Contracts are tested but not audited. Treat this as a working system to evaluate, not one to secure real value with.

Defects in the deployed contracts

These are bugs — behaviour the contracts were not meant to have, found by reading the deployed source. They are listed here rather than after they are fixed, because a reader deciding whether to trust this deployment should be deciding with them in hand.

Five were disclosed against the v1 deployment. Three of them are closed in the v2 contracts now on testnet, and they are kept here, marked, rather than deleted: a disclosure that quietly loses entries is not a disclosure.

Still live

initialize is unauthenticated. It is guarded against being called twice and nothing more, so between deployment and initialization any account could have claimed a contract by wiring it to addresses of their choosing. The current deployment is initialized and correctly wired — every address is committed in the deployment record and independently checkable on-chain — but the deploy sequence relied on winning that race rather than on the contract refusing to lose it.

The fee escrow can pay out only once. Its state is a single global slot: a second deposit overwrites the first, and release_to_auditor sets a released flag that is never cleared. This no longer sits on any path that matters — auditors are paid by the PremiumVault, which is per-certificate and was built as a separate contract precisely so it would not inherit this shape. The escrow is still deployed and still broken; nothing calls it.

Closed in v2

The reserve check read one shared balance. The challenge manager asked the vault for its balance with no certificate argument, and the vault kept one balance for everything. This was the most serious of the five, because it undercut the single trustless proof the protocol offers. The vault now keys every balance, lock and unlock stamp by certificate id, and the challenge manager passes the id through. Reserve accounting was reworked rather than the check patched, which is why v2 is a redeploy.

Anyone could stop an agent's certificate from resolving. publish authorized the operator but took the agent address as an ordinary parameter, overwriting that agent's mapping unconditionally. publish now requires the agent's authorization as well as the operator's, so nobody can be bonded without consenting to it. One consequence is visible in the app: a browser wallet holds one key, so the only certificate it can publish unaided is one naming itself.

Storage had no time-to-live management. No contract extended the lifetime of any storage entry, so entries would archive and reaching one aborts the transaction. All seven contracts now extend the TTL of the entries they own. Archival is still a property of Soroban rather than something a contract can switch off — an entry untouched for long enough will still lapse — so treat long-idle certificates with care.

The line the design draws

The honest edge is narrow and worth stating plainly: a short reserve is provable on-chain with zero trusted parties. Who was harmed, and how much an agent really spent, are not.

That is the design's claim, and the deployed contracts now honour it: the proof is sound and the accounting it reads is per-certificate. That was not true of v1, and the gap between the two is the reason v2 exists. Bound keeps the two apart and marks which is which, instead of extending the trustless label over the part it cannot back.

If that distinction matters to your use case, read proof_type before you read anything else.

On this page