Who I am and what I want to build
I'm Ethan Frey — founder of the CosmWasm smart-contract engine for Cosmos. As part of
that work we built CosmWasm/optimizer, the
deterministic Wasm build image most CosmWasm contract verification has run on for years.
I'm now putting together the Soroban equivalent, and I want to flag the integration with
the Registry early — and concretely, against your actual contract code — so it slots
into what you've built rather than around it.
I want to build a decentralized-consensus source verifier for Soroban: a network of
independent, staked operators that takes a (source code, build image) pair — exactly
the inputs SEP-58 standardizes (bldimg, bldopt, a source identity) — rebuilds the
contract, and reaches consensus on whether the resulting Wasm hash matches the bytes
deployed on-chain. The output is a single, economically-backed proof that a specific
source tree compiles to a specific deployed Wasm. No central verifier; operator
disagreement is surfaced, not hidden.
Two payoffs, the second being the one I most want to co-design with you:
- Source verification. A deployed contract's opaque bytes get a trustworthy link
back to reviewable source.
- Audits that actually map to deployed contracts. An audit is always performed
against a specific source revision. Today nothing asserts that the audited source
is the source that produced the deployed bytecode, so "audited by X" floats free of
what's on-chain. Once a verifier proves source ↔ deployed-Wasm, an auditor's
attestation against that source binds to the on-chain contract.
So this is not a competitor to the trusted-auditor model in your Item 4; it's the
foundation that makes auditor attestations bind to deployed contracts at all.
One terminology issue to settle up front
Registry already uses "verified" to mean manager-curated into the root registry
(website/docs/registry.md: the Verified (Root) Registry requires manager approval;
the Unverified Registry is open). That is a governance/curation signal.
What I'm describing is source verification: a cryptographic/economic proof that
this source produces these deployed bytes. It is orthogonal to manager-curation — a
contract in the unverified registry can be source-verified, and a manager-curated
("verified") contract may have no source proof. To avoid overloading the word, this
proposal calls it "source-verified" throughout and treats it as a per-Wasm-hash
record, not a third registry and not a redefinition of your existing "verified". A
strong source-verification record is exactly the kind of objective signal that can
later inform manager curation, but it doesn't replace it.
Context
In discussion #1923,
@chadoh outlined a verify_source method storing Option<bool> per contract, gated to
a trusted-auditor subregistry, and noted it "could also be designed in a way to allow
multiple verifiers to store independent reviews." This is the concrete shape for the
multi-verifier case, mapped onto the primitives already in contracts/registry.
How this maps onto the contract as it exists today
I read the contract so this is additive, not hand-wavy. The relevant existing
primitives:
- Manager-gated mutation + typed event + compact per-entry status is an established
pattern: flag_contract(... flagged: bool) is gated by require_owner_or_manager,
stores a compact flag on ContractEntry, and emits SecurityFlagContract for
indexers. A source-verification record is the same shape of thing — manager-gated
write, compact stored record, typed event the UI consumes.
manager is the gate. Managed registries require manager.require_auth() for
publish/claim/batch/owner changes. In the rgstry deployment that manager is the Tansu
Registry Security Council. "Gated by the Security Council review" therefore means
exactly "callable only with the registry manager's auth" — no new gating concept.
- Subregistries are child Registry instances, registered by a single crate-style
name in the root and resolved via resolve_subregistry (the constructor already
auto-deploys the unverified one; SubRegistry { name, contract_id } is emitted).
The user-facing subregistry/name convention (unverified/my-contract) is parsed
into (child registry, name) — it is not a slashed on-chain name. So auditor and
verifier would be sibling subregistries alongside unverified, and
verifier/avs-soroban-compiler is shorthand for "name avs-soroban-compiler in the
verifier subregistry", consistent with how unverified/... already works.
- Hashes are first-class keys.
Storage.hash: PersistentMap<BytesN<32>, ()> already
keys by Wasm hash via HashKey. Source verification is a property of a Wasm hash
(which may be deployed as many contracts), so records should key by BytesN<32>,
reusing that pattern.
- SEP-58 surfacing is already in-scope for Q2. Issue stellar-scaffold/temp#13 explicitly adds
stellar contract info meta (the SEP-58 fields) to Wasm/Contract detail pages. A
source-verified badge belongs next to those fields on the same page.
Identity model
A human auditor is a person/company; a decentralized verifier has no single signer —
the "signer" is an on-chain consensus aggregator contract. So:
- Add sibling subregistries
auditor and verifier next to the existing unverified
one (same resolve_subregistry path, same root registration, each with its own
manager). Names within them are crate-style single segments (≤64 chars, ascii
alnum/-/_), e.g. verifier/avs-soroban-compiler, auditor/certora.
- The registered principal for a
verifier/* entry is a contract Address (the
consensus aggregator), not a G-address. Admission of that entry goes through the same
Tansu/manager review that gates root publishes.
Data model (illustrative; keyed by Wasm hash, matching the existing hash map)
// New: PersistentMap<BytesN<32>, Vec<VerificationRecord>, VerifyKey>
// One Wasm hash -> independent records from multiple verifiers. No aggregation.
#[contracttype]
pub struct VerificationRecord {
pub verifier: Address, // registered consensus-aggregator (or auditor) contract/acct
pub verifier_name: String, // its name in the `verifier`/`auditor` subregistry
pub result: Option<bool>, // None = in-flight; Some(true)=match; Some(false)=mismatch
pub sep58: Sep58Inputs, // the (image, options) half of what was replayed
pub source: SourceRef, // the source half: what bytes were rebuilt
pub evidence: Evidence, // how the result was reached (provenance)
pub trust_signals: Option<Bytes>, // opaque; schema = upstream SEP-58 companion SEP
pub created_at: u64,
}
#[contracttype]
pub struct Sep58Inputs { pub bldimg: String, pub bldopt: Vec<String> }
#[contracttype]
pub enum SourceRef {
RepoRev { source_repo: String, source_rev: String },
Tarball { tarball_url: Option<String>, tarball_sha256: BytesN<32> }, // sha256-alone = IPFS path
}
#[contracttype]
pub enum Evidence {
Auditor { signer: Address }, // human/company auditor
Consensus { // decentralized verifier
aggregator: Address,
operators_total: u32,
operators_agreeing: u32, // N-of-M; disagreement stays visible
threshold: u32,
evidence_uri: Option<String>, // off-chain signed per-operator detail
},
}
result: None in-flight (UI can show "verifying…"); Some(true) rebuilt bytes match
the deployed Wasm under the recorded SEP-58 inputs; Some(false) mismatch (a positive
signal the claimed source/inputs are wrong). operators_agreeing < operators_total is
preserved so the UI renders "8/9 operators agree", never a bare ✅.
Methods + event (illustrative, mirroring existing patterns)
// Write — manager-gated, exactly like flag_contract / managed publish.
// require_owner_or_manager-style: only the registry manager (Tansu council) or the
// registered verifier principal may write, and only its own (hash, verifier) slot.
fn submit_verification(env: Env, wasm_hash: BytesN<32>, record: VerificationRecord);
fn get_verifications(env: Env, wasm_hash: BytesN<32>) -> Vec<VerificationRecord>; // no aggregation
fn get_verification(env: Env, wasm_hash: BytesN<32>, verifier: Address) -> Option<VerificationRecord>;
// New typed event so the rgstry UI / StellarExpert index it, same as SecurityFlagContract.
#[contractevent(topics = ["source_verified"])]
pub struct SourceVerified { pub wasm_hash: BytesN<32>, pub verifier: String, pub result: Option<bool> }
The Registry never decides "is this verified?" — it stores independent records with
provenance and emits an event; consumers apply their own trust policy. That matches your
stated intent and SEP-58's verifier-policy-agnostic stance.
How auditor and verifier records coexist
|
auditor/* (human) |
verifier/* (decentralized) |
| Asserts |
a judgement about the source |
a mechanical fact: source → deployed bytes |
| Principal |
G-address (person/company) |
contract (consensus aggregator) |
Evidence |
Auditor |
Consensus (N-of-M, disagreement visible) |
| Cadence |
manual, low volume |
automated, potentially every uploaded Wasm |
| Gate |
registry manager (Tansu council) |
registry manager (Tansu council) — same path |
Both keyed on the same wasm_hash, so a consumer can require "source-verified and
audited" — which only works because both records sit together with provenance intact.
No human coordination point sits in the automated path.
Security / abuse considerations
- Write authorization is the existing
manager/owner auth path, not a new
hardcoded list — admission still flows through the Tansu council review you run.
- Record isolation: a verifier can only write its own
(wasm_hash, verifier) slot.
- Compactness: the contract already optimizes per-entry storage (the
flagged
length-of-vec trick); large per-operator detail stays off-chain behind evidence_uri,
on-chain record stays small.
- Staleness:
created_at + optional re-verification; the Registry never adjudicates.
- No oracle risk for the Registry: it stores claims with provenance; it does not
itself verify. Trust is pushed to the consumer, exactly as with flagged.
What this is and isn't
- Is: a concrete realization of your Item 4, expressed in the contract's own
primitives (manager gate, BytesN<32> key, typed event, sibling subregistry), adding
the source ↔ deployed-Wasm binding that lets audits map onto on-chain contracts.
- Isn't: a competing registry, a new explorer, a redefinition of your "verified
registry" curation term, or a change to who governs the Registry. The verifier writes
here; rgstry and StellarExpert render it. MIT, co-designed in scaffold-stellar.
Open questions for the Registry team
- Storage home: verification records in the root, keyed by
BytesN<32>
(reusing the hash map pattern), or in a dedicated verifier subregistry
instance? I lean root-keyed-by-hash since a hash maps to many contracts and stellar-scaffold/temp#13
already surfaces per-Wasm meta — but it's your architecture call.
- Contract principal: the consensus aggregator is a contract
Address, not an
author G-address. Does the manager/auth path (and the named-address work in stellar-scaffold/temp#27 /
SorobanDomains) accommodate a contract as the registered, authorized writer?
- Terminology: OK to surface this as a distinct "source-verified" signal on the
stellar-scaffold/temp#13 Wasm-detail page, kept separate from the existing "verified registry" curation
wording, so users aren't confused by two meanings of "verified"?
- Should an
auditor/* record optionally reference the verifier/* record that
proved source↔Wasm (making "audited ⇒ of the deployed bytes" explicit on-chain), or
is composing the two left to consumers reading both? I lean consumer-composed.
submit_verification overwrite-own-record (re-verification) vs append + versioning?
- Timing: stellar-scaffold/temp#13 (meta surfacing) is Q2; Item 4 ~Q3. Co-design this interface in Q2
so it's ready when Item 4 lands, or target a later checkpoint?
Who I am and what I want to build
I'm Ethan Frey — founder of the CosmWasm smart-contract engine for Cosmos. As part of
that work we built CosmWasm/optimizer, the
deterministic Wasm build image most CosmWasm contract verification has run on for years.
I'm now putting together the Soroban equivalent, and I want to flag the integration with
the Registry early — and concretely, against your actual contract code — so it slots
into what you've built rather than around it.
I want to build a decentralized-consensus source verifier for Soroban: a network of
independent, staked operators that takes a
(source code, build image)pair — exactlythe inputs SEP-58 standardizes (
bldimg,bldopt, a source identity) — rebuilds thecontract, and reaches consensus on whether the resulting Wasm hash matches the bytes
deployed on-chain. The output is a single, economically-backed proof that a specific
source tree compiles to a specific deployed Wasm. No central verifier; operator
disagreement is surfaced, not hidden.
Two payoffs, the second being the one I most want to co-design with you:
back to reviewable source.
against a specific source revision. Today nothing asserts that the audited source
is the source that produced the deployed bytecode, so "audited by X" floats free of
what's on-chain. Once a verifier proves source ↔ deployed-Wasm, an auditor's
attestation against that source binds to the on-chain contract.
So this is not a competitor to the trusted-auditor model in your Item 4; it's the
foundation that makes auditor attestations bind to deployed contracts at all.
One terminology issue to settle up front
Registry already uses "verified" to mean manager-curated into the root registry
(
website/docs/registry.md: the Verified (Root) Registry requires manager approval;the Unverified Registry is open). That is a governance/curation signal.
What I'm describing is source verification: a cryptographic/economic proof that
this source produces these deployed bytes. It is orthogonal to manager-curation — a
contract in the
unverifiedregistry can be source-verified, and a manager-curated("verified") contract may have no source proof. To avoid overloading the word, this
proposal calls it "source-verified" throughout and treats it as a per-Wasm-hash
record, not a third registry and not a redefinition of your existing "verified". A
strong source-verification record is exactly the kind of objective signal that can
later inform manager curation, but it doesn't replace it.
Context
In discussion #1923,
@chadoh outlined a
verify_sourcemethod storingOption<bool>per contract, gated toa trusted-auditor subregistry, and noted it "could also be designed in a way to allow
multiple verifiers to store independent reviews." This is the concrete shape for the
multi-verifier case, mapped onto the primitives already in
contracts/registry.How this maps onto the contract as it exists today
I read the contract so this is additive, not hand-wavy. The relevant existing
primitives:
pattern:
flag_contract(... flagged: bool)is gated byrequire_owner_or_manager,stores a compact flag on
ContractEntry, and emitsSecurityFlagContractforindexers. A source-verification record is the same shape of thing — manager-gated
write, compact stored record, typed event the UI consumes.
manageris the gate. Managed registries requiremanager.require_auth()forpublish/claim/batch/owner changes. In the rgstry deployment that manager is the Tansu
Registry Security Council. "Gated by the Security Council review" therefore means
exactly "callable only with the registry
manager's auth" — no new gating concept.name in the root and resolved via
resolve_subregistry(the constructor alreadyauto-deploys the
unverifiedone;SubRegistry { name, contract_id }is emitted).The user-facing
subregistry/nameconvention (unverified/my-contract) is parsedinto (child registry, name) — it is not a slashed on-chain name. So
auditorandverifierwould be sibling subregistries alongsideunverified, andverifier/avs-soroban-compileris shorthand for "nameavs-soroban-compilerin theverifiersubregistry", consistent with howunverified/...already works.Storage.hash: PersistentMap<BytesN<32>, ()>alreadykeys by Wasm hash via
HashKey. Source verification is a property of a Wasm hash(which may be deployed as many contracts), so records should key by
BytesN<32>,reusing that pattern.
stellar contract info meta(the SEP-58 fields) to Wasm/Contract detail pages. Asource-verified badge belongs next to those fields on the same page.
Identity model
A human auditor is a person/company; a decentralized verifier has no single signer —
the "signer" is an on-chain consensus aggregator contract. So:
auditorandverifiernext to the existingunverifiedone (same
resolve_subregistrypath, same root registration, each with its ownmanager). Names within them are crate-style single segments (≤64 chars, asciialnum/
-/_), e.g.verifier/avs-soroban-compiler,auditor/certora.verifier/*entry is a contractAddress(theconsensus aggregator), not a G-address. Admission of that entry goes through the same
Tansu/
managerreview that gates root publishes.Data model (illustrative; keyed by Wasm hash, matching the existing
hashmap)result:Nonein-flight (UI can show "verifying…");Some(true)rebuilt bytes matchthe deployed Wasm under the recorded SEP-58 inputs;
Some(false)mismatch (a positivesignal the claimed source/inputs are wrong).
operators_agreeing < operators_totalispreserved so the UI renders "8/9 operators agree", never a bare ✅.
Methods + event (illustrative, mirroring existing patterns)
The Registry never decides "is this verified?" — it stores independent records with
provenance and emits an event; consumers apply their own trust policy. That matches your
stated intent and SEP-58's verifier-policy-agnostic stance.
How auditor and verifier records coexist
auditor/*(human)verifier/*(decentralized)EvidenceAuditorConsensus(N-of-M, disagreement visible)manager(Tansu council)manager(Tansu council) — same pathBoth keyed on the same
wasm_hash, so a consumer can require "source-verified andaudited" — which only works because both records sit together with provenance intact.
No human coordination point sits in the automated path.
Security / abuse considerations
manager/owner auth path, not a newhardcoded list — admission still flows through the Tansu council review you run.
(wasm_hash, verifier)slot.flaggedlength-of-vec trick); large per-operator detail stays off-chain behind
evidence_uri,on-chain record stays small.
created_at+ optional re-verification; the Registry never adjudicates.itself verify. Trust is pushed to the consumer, exactly as with
flagged.What this is and isn't
primitives (manager gate,
BytesN<32>key, typed event, sibling subregistry), addingthe source ↔ deployed-Wasm binding that lets audits map onto on-chain contracts.
registry" curation term, or a change to who governs the Registry. The verifier writes
here; rgstry and StellarExpert render it. MIT, co-designed in
scaffold-stellar.Open questions for the Registry team
BytesN<32>(reusing the
hashmap pattern), or in a dedicatedverifiersubregistryinstance? I lean root-keyed-by-hash since a hash maps to many contracts and stellar-scaffold/temp#13
already surfaces per-Wasm meta — but it's your architecture call.
Address, not anauthor G-address. Does the
manager/auth path (and the named-address work in stellar-scaffold/temp#27 /SorobanDomains) accommodate a contract as the registered, authorized writer?
stellar-scaffold/temp#13 Wasm-detail page, kept separate from the existing "verified registry" curation
wording, so users aren't confused by two meanings of "verified"?
auditor/*record optionally reference theverifier/*record thatproved source↔Wasm (making "audited ⇒ of the deployed bytes" explicit on-chain), or
is composing the two left to consumers reading both? I lean consumer-composed.
submit_verificationoverwrite-own-record (re-verification) vs append + versioning?so it's ready when Item 4 lands, or target a later checkpoint?