Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

SWORN

SWORN is the bonded dispute layer for GenLayer β€” contested real-world claims settled by validator consensus with skin in the game.

SWORN landing page β€” the bonded dispute layer for GenLayer, with the tagline "a sworn statement is true until consensus says otherwise" and a call to action into the live console

A sworn statement is true until consensus says otherwise.

Live App Demo Video Launch Thread Contract Chain

Live App Β· Demo Video Β· Launch Thread Β· Contract on Bradbury Β· Search / RPC Proxy Β· Chain: Bradbury 4221


SWORN in one minute

Real-world facts that money depends on β€” did the shipment arrive, did the metric cross the threshold, did the event happen β€” are today resolved by someone you have to trust. That is the captured-oracle problem, and SWORN exists to kill it. Nothing settles on the asserter's word alone, and nothing settles on an LLM's word alone.

1. Create an assertion β€” swear a statement.
                 ↓
2. Stake a bond β€” real GEN, custodied by the contract.
                 ↓
3. Anyone may challenge β€” by staking their own bond.
                 ↓
4. Only challenged assertions invoke AI consensus β€” exactly one round.
                 ↓
5. Deterministic settlement β€” loser slashed, integer math, no discretion.
                 ↓
6. Consumer contracts read read_truth() β€” and gate their own value on it.

Unchallenged assertions settle for free after the window β€” zero LLM calls. Consensus is invoked only when someone has money on a disagreement.

What settles deterministically: the assertion id, the challenge window and all timing, the bond/slash/fee arithmetic (integer basis points, no floats), the label→action mapping, and the payout ledger. The LLM only ever proposes a label. What read_truth(assertion_id) returns to any other contract is exactly:

{"found": bool, "status": str, "label": str, "resolved": bool, "true": bool}

resolved is True once the assertion has settled (RESOLVED_TRUE / RESOLVED_FALSE / RESOLVED_UNRESOLVABLE); true is only True for RESOLVED_TRUE. Checking both means you never treat an unresolved or disputed-but-unsettled claim as confirmed.

Watch it work

SWORN demo β€” swearing a statement under bond, bonding a challenge, one consensus round, and the resulting slash and settlement, live on Bradbury testnet

The clip runs the full path against the deployed contract on Bradbury testnet: swear β†’ challenge β†’ consensus β†’ settlement, ending on the settled label and the economic outcome the loser paid for.

How it settles

swear (bond)  β†’  optimistic window  β†’  bonded challenge  β†’  consensus on a label  β†’  slash the loser  β†’  read_truth()

The status machine is PENDING β†’ CHALLENGED β†’ RESOLVING β†’ RESOLVED_TRUE | RESOLVED_FALSE | RESOLVED_UNRESOLVABLE, plus the free path PENDING β†’ RESOLVED_TRUE via finalize_unchallenged() once the window elapses untouched. An unchallenged claim costs zero LLM calls; a challenged one costs exactly one consensus round, paid for by the loser's bond.

SWORN console dashboard showing the protocol's live aggregate state β€” bonds custodied, assertion counts by status, finalization, and accrued protocol fees

The console reads the protocol's live aggregate state: bonds actually custodied by the contract, assertions by status, finalization, and the protocol fees accrued from settled disputes.

Resolved assertion detail β€” the consensus timeline alongside the economic settlement panel naming the winner, the loser, the amount slashed, and the protocol fee

On a resolved assertion, the consensus timeline sits beside the economic settlement panel: who won, who lost, how much was slashed, what the protocol kept. That panel is the product. The label is only the input to it.

The swear form with a live preview of the statement as it will be sworn, and the bond-at-risk notice showing the stake the asserter is putting up

Swearing shows you the statement exactly as it will be stored and the bond you are putting at risk before you sign. The floor is _effective_min_bond(who) = min_bond * (1 + grief_strikes[who]) β€” it rises for anyone who keeps losing.

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CONSUMERS        consumer_escrow.py, any Intelligent Contract   β”‚
β”‚                  reads read_truth() β€” never reads evidence      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ VIEWS            read_truth Β· dispute_summary Β· get_assertion   β”‚
β”‚                  pure reads of settled state                    β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ DETERMINISTIC    swear Β· challenge Β· finalize_unchallenged Β·    β”‚
β”‚ PROTOCOL CORE    claim_asserter/challenger/protocol_fee β€”       β”‚
β”‚                  state machine + integer math,                  β”‚
β”‚                  no LLM, no network, no consensus               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ CONDITIONAL      resolve() β€” only for CHALLENGED assertions:    β”‚
β”‚ CONSENSUS        one leader/validator round over pinned         β”‚
β”‚                  evidence; LLM only for WEB_EVENT; mechanical   β”‚
β”‚                  eth_call comparator for ONCHAIN_METRIC         β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ EVIDENCE         proxy/app.py β€” per-round determinism cache     β”‚
β”‚ TRANSPORT        (search + pinned-block eth_call); availability β”‚
β”‚                  layer, never assigns truth                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Only one layer is non-deterministic. Everything above the consensus layer is deterministic and runs on every assertion. The consensus layer runs only when a bonded challenge exists β€” the LLM never touches an uncontested claim, and settlement math after the label is deterministic integer arithmetic.

Why consensus is conditional

  • Economics β€” an unchallenged claim costs zero LLM calls; a challenged one costs exactly one consensus round, paid for by the loser's bond.
  • Determinism β€” everything that can be deterministic is: guards, bonds, windows, dedup, settlement math, views. AI cannot replace these, because they must be bit-identical across validators and replayable. The LLM is confined to one judgment (TRUE | FALSE | UNRESOLVABLE on evidence) inside one agreement band.
  • Authority β€” consensus is the sole authority for semantic judgment. No off-chain component β€” proxy, relayer, console β€” can assign or alter a label.

The agreement band is identical-label agreement over {TRUE, FALSE, UNRESOLVABLE}. Nothing else is compared: not the reason text, not a confidence score, not the raw evidence. Failures finalize too β€” SWORN raises static, never-interpolated error classes ([EXPECTED], [EXTERNAL], [LLM_ERROR]) so validators agree on failures as well as successes and a transient outage never becomes a stuck dispute. ONCHAIN_METRIC runs the same leader/validator machinery with no LLM at all β€” a pinned-block eth_call through the proxy plus an integer comparator β€” so AI consensus is a strict subset of validator consensus.

An ONCHAIN_METRIC assertion resolved TRUE against real Ethereum mainnet state β€” the evidence panel shows the raw comparator output, onchain value=51047428496982125 >= threshold=1000000000000, block-pinned via the proxy with no LLM involved

A settled ONCHAIN_METRIC dispute: the evidence panel carries the literal comparator result (onchain value=51047428496982125 >= threshold=1000000000000 @proxy-latest) read from real USDC supply on Ethereum mainnet, block-pinned per round so every validator saw the same bytes. No model was asked anything.

Trust boundary

  • Trustless β€” verdicts, bond custody, settlement math, owed amounts, read_truth(). All on-chain, all deterministic or consensus-settled.
  • Trusted for availability, not truth β€” the evidence proxy. It guarantees every validator in a round sees identical evidence bytes; it cannot assign a label. For WEB_EVENT it is in the evidence supply chain (a compromised proxy could feed misleading search snippets to the judging LLM β€” the same trust class as any oracle's data source). Mitigations: asserter-supplied sources are fetched independently, evidence is capped and sanitized, and the band degrades to UNRESOLVABLE on thin evidence. For ONCHAIN_METRIC the proxy only relays pinned-block eth_call bytes.
  • Trusted for delivery, not verdicts β€” the payout relayer. Who is owed what is recorded trustlessly on-chain; only the cash movement is relayer-executed. A stalled relayer can delay payment, never change it.
  • Untrusted β€” the console and its read cache. Conveniences over public state, with a direct-RPC fallback and a "verify on chain" bypass built in.

Reads at scale β€” one cache, not one reader per visitor

The public Bradbury RPC is a shared resource across every developer on the testnet, and GenLayer's team flagged the architectural point directly after early rate-limit reports. proxy/app.py serves GET /state/summary and GET /state/assertion/<id>: a cached, single-upstream-reader tier with ETag / stale-while-revalidate semantics, so any number of browsers share one small flat read rate instead of each adding their own load. This is a performance layer over public chain state, not a truth layer β€” writes never touch it, frontend/sworn-client.js falls back to a direct gen_call if the cache is cold or down, and the assertion detail page has a one-click "verify on chain" action that re-reads straight from the chain. Current deployment note, stated plainly: the proxy is not yet returning an Access-Control-Allow-Origin header, so the browser presently takes the direct-gen_call fallback path rather than the cache. The console renders correct live data either way β€” this is a proxy header fix, not a design change, and it cannot affect a verdict because the cache is non-authoritative by construction. Full mechanics in proxy/README.md.

Depth: docs/CONSENSUS_DESIGN.md for the band, the determinism sandwich, timing and economic security; docs/SUBMISSION_SPEC.md Β§1 and Β§5 for the full audited architecture and trust-boundary diagrams.

Not Intelligent Oracle β€” adjudication, not resolution

GenLayer's own Intelligent Oracle resolves markets you define β€” you write the question, IO answers it. SWORN adjudicates stake-backed disagreements β€” it only ever runs consensus when someone has bonded a challenge, and the economics (whose money is at risk, who gets slashed, what the protocol keeps) are the product, not a detail. If nobody disputes a sworn statement, it settles for free; IO has no equivalent of "free unless contested." That's the distinction this repo is built around, not an afterthought.

The economics are real, proven live

  • Bonds are really custodied. swear / challenge collect native GEN into the contract β€” confirmed by reading the contract's own on-chain balance grow by exactly the bonds paid in.

  • Settlement is deterministic integer math. On TRUE the asserter takes the challenger's bond minus challenge_fee_bps (5% default) to the protocol; on FALSE, symmetric in the asserter's bond; the winner's own bond is simply returned, so slashing only ever touches the loser's stake. UNRESOLVABLE is loss-making for both sides β€” the asserter loses asserter_penalty_bps (10% default), the challenger loses challenge_fee_bps β€” so neither frivolous assertions nor frivolous challenges are free.

  • Griefing is priced. Every settled assertion bumps a strike against whichever side lost (both, on UNRESOLVABLE), raising that address's future effective minimum bond. Measured live: by the time one address had ~15 settled assertions against it, its effective floor had risen to roughly 0.16 GEN from a 0.01 GEN base.

  • Challenger bond β‰₯ asserter bond. A challenger cannot contest with a token amount and hope to win big off someone else's larger stake.

  • Settlement is per-recipient, idempotent, and releases real custody on-chain wherever the runner permits it. Each side calls its own claim β€” claim_asserter(), claim_challenger(), claim_protocol_fee() β€” independently, in any order, and exactly once. (claim_bond() remains as a thin compatibility router.) The verdict, the split and the ledger are entirely trustless and on-chain, and the conservation identity payout_asserter + payout_challenger + protocol_fee == bond + challenger_bond holds integer-exact on every settlement path.

  • Delivery is routed by verified recipient capability, because this runner will not deliver value to a wallet. Measured, not assumed (probe matrix with tx ids in docs/GENLAYER-FEEDBACK.md):

    recipient route what happens
    contract (proved it has code) ONCHAIN native transfer out of custody, inside the claim tx; marked *_claimed
    wallet RELAYER marked *_pending, custody untouched, delivered by scripts/relay_payouts.py, then attested on-chain via confirm_delivery()

    A claim is never marked complete before the money moves β€” on the ONCHAIN route that is enforced by the contract itself. On the RELAYER route the guarantee extends only as far as the relayer's honesty: the contract cannot verify an L1 hash from inside, so scripts/relay_payouts.py waits for the delivery receipt and refuses to attest without one. This repository preserves a live example of what a false attestation looks like, and why that check exists (docs/LIVE-PROOF.md). Capability is proved, not declared: register_onchain_recipient() only accepts a caller whose sender_address != origin_address, which only an internal (contract-originated) call can satisfy, so a wallet cannot route its own payout into a transfer that would silently swallow it.

  • The earlier "emit_transfer is a universal no-op" finding in this repo was wrong, and is corrected in docs/GENLAYER-FEEDBACK.md. The SDK signature is emit_transfer(*, value, on=…); the default on='finalized' merely defers delivery until the transaction finalizes β€” it does arrive, but slowly and with no observable pending state, so every earlier observation window was shorter than finalization. With on='accepted' the same call pays inside the transaction. The genuine remaining gap is contractβ†’EOA, which never pays under either setting even after finalization β€” not the primitive itself.

  • Delivery is proven by balance-delta, not by a clean ACCEPTED poll. Live on Bradbury, a contract recipient's claim released custody inside the claim transaction: recipient +0.005000 GEN, contract βˆ’0.005000 GEN, the recipient's __receive__ fired, and a second claim moved +0.000000 on both sides. Full transcript with tx ids: docs/LIVE-PROOF.md.

  • dispute_summary(assertion_id) reads the whole economic story in one call: asserter, challenger, winner, loser, slashed amount, protocol fee, label, claimed.

  • The relayer is an unreimbursed funding source, and the bond it covers stays locked. On the RELAYER route the relayer pays the recipient from its own balance and the corresponding bond remains in the contract permanently β€” _pay() cannot reach a wallet, so there is no on-chain reimbursement path and no way to release that balance once the claim is marked complete. This is a bounded consequence of the runner limitation above, not a design choice, and it disappears if the EOA-transfer gap is closed upstream. Two practical corollaries: don't run a relayer for a deployment you don't control, and don't read custodied_balance as a solvency figure β€” it includes bonds behind payouts already settled off-chain. Full statement in docs/CONSENSUS_DESIGN.md.

  • Composability proven three ways, not two. A real consumer contract (contracts/consumer_escrow.py) gates its own release on read_truth() and distinguishes release / refund / wait: RESOLVED_TRUE releases to the beneficiary, RESOLVED_FALSE and RESOLVED_UNRESOLVABLE refund the depositor, and a PENDING / CHALLENGED / RESOLVING assertion refuses to settle at all rather than treating "not true yet" as "false". Proven live on Bradbury: release() against pending truth left the escrow byte-for-byte unchanged and moved nothing (docs/LIVE-PROOF.md).

The finalization curve

scripts/finrate.py runs a 15-item graded-difficulty corpus (tests/direct/conftest.py::GRADED_CORPUS) live against a deployed contract, rather than asserting a number.

tier n finalization rate agreement with expected
decisive 8 1.00 1.00
medium 3 1.00 1.00
ambiguous 4 1.00 1.00

Every one of the 15 items finalized to the correct label: decisive TRUE and FALSE claims were correctly distinguished (not just defaulted to one side), medium claims requiring a read past the lead paragraph resolved correctly, and every subjective or predictive ambiguous claim correctly landed on UNRESOLVABLE rather than being forced to a side.

The honest caveat: that 100% is the eventual, independently-verified outcome β€” not a clean one-shot. Getting there required retrying past real Bradbury-testnet infra issues and surfaced two genuine bugs (a grief-strike bond floor rising past a fixed test bond; ACCEPTED not being proof of persistence under load). None of them were evidence-pipeline or prompt-correctness bugs β€” once a transaction durably landed, the label was always right. Full methodology, the per-item raw results, and the complete caveat: docs/FINALIZATION_RATE.md.

Build on SWORN

The read_truth() explorer in the console β€” query an assertion id and see the exact composability surface a consumer contract receives

You only need read_truth(assertion_id) -> dict. Declare it with @gl.contract_interface and call it as a view β€” no write, no gas, no LLM cost on your side:

@gl.contract_interface
class Sworn:
    class View:
        def read_truth(self, assertion_id: str) -> dict: ...

    class Write:
        pass


class YourContract(gl.Contract):
    sworn_addr: Address

    def __init__(self, sworn_addr: str) -> None:
        self.sworn_addr = Address(sworn_addr)

    @gl.public.write
    def your_gated_action(self, assertion_id: str) -> None:
        truth = Sworn(self.sworn_addr).view().read_truth(assertion_id)
        if truth["resolved"] and truth["true"]:
            ...  # release, mint, payout -- whatever your contract does
        else:
            ...  # refuse, refund, or wait (it may not be resolved yet)

Prediction markets, insurance payouts, escrow release, DAO clawback β€” these are not separate integrations. They are customers of one interface: each gates its own value on a sworn, dispute-tested fact instead of trusting an off-chain resolver. read_truth_by_ref(ref_hash) maps your own external reference key to the same shape. The worked escrow example and the one caveat that applies to any contract built this way are in docs/BUILD.md.

What's live today

Component State
Gate-zero probe (contracts/gatezero.py) Ready β€” run first, see GATEZERO_RUNBOOK.md
Phase 1 β€” deterministic core LIVE β€” swear / challenge / finalize_unchallenged / per-recipient claim_* / read_truth + guards, slash math, greybox hardening
Phase 2 β€” resolve() (WEB_EVENT) LIVE β€” text-rendered legible evidence + a deterministic independent-search proxy, both verified load-bearing
Phase 3 β€” real economics LIVE β€” per-recipient idempotent claims with capability-routed delivery (on-chain release balance-delta proven; wallets via relayer attestation), dispute_summary view, consumer_escrow composability including the wait state
Phase 3 β€” ONCHAIN_METRIC LIVE β€” TRUE and FALSE claims resolved against real Ethereum mainnet state via eth_call proxied through Render, per-round block pinning, API key server-side
Phase 4 β€” tests Band test passing; deterministic-core + finalization-rate measured live
Phase 5 β€” frontend LIVE β€” swornic.vercel.app: landing + an 11-route console (dashboard, assertions, detail, swear, read_truth() explorer, activity, validators, wallet, developers, docs, settings), zero-dependency gen_call reads with EIP-1193 writes, proxy-cached read tier with direct-RPC fallback and "verify on chain", four headless smokes gating CI

Repository navigation

Path What it is
contracts/sworn.py Core protocol: bonds, window, consensus, settlement, read_truth()
contracts/consumer_escrow.py Example consumer β€” gates escrow release on read_truth()
contracts/gatezero.py Runner-capability probe (run before resolve() was enabled)
proxy/app.py Evidence transport: per-round search + eth_call determinism, console read cache
frontend/SWORN Console.dc.html Protocol console
frontend/sworn-client.js The only browser↔chain integration surface
docs/CONSENSUS_DESIGN.md The agreement band, labels, determinism sandwich, economics
docs/SUBMISSION_SPEC.md Audited architecture, trust boundaries, diagrams, roadmap, Truth Receipt spec
docs/BUILD.md Build-on-SWORN: the read_truth() interface + escrow pattern
docs/GENLAYER-FEEDBACK.md Runner quirks + workarounds, honestly logged
docs/FINALIZATION_RATE.md Measured live finalization curve
docs/FRONTEND.md Frontend integration decisions record
scripts/sworn_smoke.py Live on-chain smoke: swear / challenge / resolve / claim / payout_proof
scripts/relay_payouts.py Off-chain payout relayer
tests/direct/ Band test + deterministic-core acceptance tests

Roadmap β€” SWORN v2

Everything in this section is future work. None of it is part of the v1 submission. The deployed v1 behavior is what the sections above describe. Full detail: docs/SUBMISSION_SPEC.md Β§6.

  • Mechanical Evidence Preparation Layer (the centerpiece) β€” formalize the evidence work that v1 does inline (markupβ†’text, trimming, sanitizing, caps, per-round caching) into an explicitly mechanical stage that may normalize, deduplicate, order, hash, chunk and package evidence β€” and must never assign truth, assign confidence, replace consensus, or make semantic judgments. The invariant is normative: removing the preparation layer must never change a protocol verdict. It may only affect latency, bandwidth and ergonomics. That is concretely testable β€” the finalization corpus becomes its regression suite.
  • Truth Receipt β€” specified, not yet built (docs/SUBMISSION_SPEC.md Β§7). A presentation-layer artifact derived deterministically from finalized on-chain state: one canonical card and versioned JSON object (sworn-receipt/1) answering what was claimed, what was decided, what moved, and how do I check it myself β€” carrying the exact read_truth() call that reproduces it. It introduces no protocol state and is never consumed by contracts or consensus. Receipts exist only after settlement.
  • Versioned truth and receipt indexing β€” receipts are deterministic derivations of finalized state, so an indexer could pre-generate them keyed by assertion id and serve them without touching trust, byte-comparable with client-built ones.
  • Protocol-surface conveniences β€” events for swear/challenge/resolve/claim, an effective_min_bond(addr) view, and native payout delivery retiring the relayer if the runner's emit_transfer is fixed upstream. All excluded from v1 because they would touch the frozen protocol surface.

Run it yourself

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env            # put a funded Bradbury key in ACCOUNT_PRIVATE_KEY

# GATE-ZERO (do this before building resolve()):
python deploy/deploy.py gatezero
python scripts/gatezero_run.py all
#   ...wait ~3 min...
python scripts/gatezero_run.py dt
python scripts/gatezero_run.py read
# fill in GATEZERO_RUNBOOK.md results; if green, proceed.

# Main contract:
python deploy/deploy.py sworn

Then drive it live β€” swear, challenge, resolve, claim, prove the payout, read the dispute:

python scripts/sworn_smoke.py params

Deploy target: Bradbury (chain 4221). Runner: py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6. Pinned SWORN address: 0x74Cd8e753E970D2D70Bfca46068e10CEEb6d9B99 (see deploy/sworn.deployment.json; rotates on redeploy β€” frontend/sworn-config.js is generated from it and CI hard-fails if the two drift).

Repository status

Builder Program submission β€” git tag submission-v1. That tag is the immutable snapshot submitted for review; reviewers should evaluate the repository at it.

Active development β€” branch v2. Ongoing work continues there and does not alter the submitted snapshot.

Links

Live app https://swornic.vercel.app/
Demo video https://youtu.be/iMwNheI6koc
Launch thread https://x.com/i/status/2075976433655075091
Contract (Bradbury 4221) 0x74Cd8e753E970D2D70Bfca46068e10CEEb6d9B99
Search / RPC proxy https://sworn.onrender.com
Docs index docs/ β€” consensus Β· build Β· finalization Β· runner feedback Β· architecture & roadmap Β· frontend

About

bonded dispute layer for genLayer.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages