Bound
Contracts

ChallengeManager

Proves a short reserve on-chain and settles it in a single transaction.

CANDUKOYQIMZDK4MUWHN6MKJI5ORY5R4BPBEQIOQQSINJYITMY47UNZH

This is where Bound stops being a registry and starts being an enforcement mechanism.

Functions

FunctionAuthNotes
initialize(registry, auditor_staking, reserve_vault, fee_escrow, token, arbiter, min_stake)once
challenge(challenger, cert_id, proof_type, victim, stake) -> challenge_idchallengerPosts a bond of at least min_stake
resolve(challenge_id)permissionlessThe trustless path — InsufficientReserve only
resolve_by_arbiter(challenge_id, fraud_proven)arbiter onlySubjective types (BoundExceeded, FakeSignature)

The trustless path

resolve for InsufficientReserve is two cross-contract reads and a comparison:

let claimed: i128 = Registry.get_cert_reserve(cert_id);   // what the cert claims
let actual:  i128 = ReserveVault.get_balance();           // what is really locked
let fraud = actual < claimed;                             // math, not opinion

No oracle, no vote, no privileged caller. Anyone can invoke it, and the answer does not depend on who did.

Settlement, in one transaction

On fraud == true:

Read the certificate's auditor and their live stake.
slash(auditor, victim, 80%) — the victim is compensated first.
slash(auditor, challenger, 20%)reward = stake / 5, paid for catching it.
release_to_victim(victim, balance) — drain whatever reserve remains.
Registry.invalidate(cert_id) — the certificate is dead.
Return the challenger's bond.

On fraud == false, the challenger forfeits their bond, which stays in the contract. That is the cost that keeps challenges honest.

The arbiter path, and why it is separate

BoundExceeded and FakeSignature cannot be settled by arithmetic — they require judging what happened off-chain. Those route to resolve_by_arbiter, a named party.

That is a real trust assumption and it is deliberately not disguised as a trustless one. See Trust model.

On this page