xls: TBD title: Attestations description: Unilateral, revocable on-ledger statements about arbitrary 32-byte subjects, signed by the attesting account. implementation: none yet author: Denis Angell (@dangell7) category: Amendment status: Draft proposal-from: TBD created: 2026-08-05 updated: 2026-08-05
An attestation is an on-ledger statement by one account about one 32-byte subject: this binary hash was built from this source commit, this audit report covers this code revision, this document hash is the one we signed. The attester creates it unilaterally, can revoke it at any time, and the ledger timestamps both actions. One new ledger entry and two transactions.
The ledger does not decide whether the statement is true. It proves who said it, when they said it, and whether they still stand behind it. Everything else is the verifier's trust decision about the attester, which is exactly how signing works everywhere else.
The concrete driver is source code validation: a validator operator wants to prove the binary they run was built from published source. The working answer is reproducible builds plus a signed statement linking binary hash to commit hash. Today that statement lives in a gist, a tweet, or a mailing list post, none of which offer revocation, a tamper-proof timestamp, or a stable place to look.
Once the statement is a ledger object, the same primitive covers cases we currently solve ad hoc:
- Build attestations:
binaryHashbuilt fromcommitHash(reproducible builds, the source-validation case). - Audit attestations: auditor attests their report hash covers a specific code revision, and revokes if the finding set changes.
- Document signing: attest the hash of an agreement, a spec revision, a policy.
- Operational statements: a publisher attests the hash of a UNL blob, an issuer attests a reserve report.
XLS-70 Credentials does not cover this. A credential's subject must be an account, and the subject must accept before the credential is valid. That bilateral, account-to-account shape is right for KYC and permissioned domains and wrong for statements about artifacts: a git commit cannot accept anything. Attestations are the unilateral half of the space: any 32-byte subject, no acceptance, no counterparty.
The key words MUST, MUST NOT, SHOULD, and MAY are to be interpreted as
described in RFC 2119. All behavior is gated on the featureAttestation
amendment.
Key Space: 0xXXXX (TBD)
ID = hash(keyspace, Attester, SubjectHash, AttestationType). One
attester, one subject, one type, one entry. Re-attesting the same triple
updates the existing entry.
| Field | Constant | Required | Internal Type | Description |
|---|---|---|---|---|
| LedgerEntryType | Yes | Yes | UINT16 | Attestation |
| Account | No | Yes | ACCOUNT | The attester. Owns the entry and its reserve |
| SubjectHash | No | Yes | HASH256 | The subject: a commit hash, binary digest, document hash, ledger object ID, or any 32-byte identifier |
| AttestationType | No | Yes | UINT32 | Application-defined type namespace (build, audit, document, ...). Types are conventions, not protocol semantics |
| Data | No | Optional | BLOB | Up to 256 bytes: a URI, a second hash, or a compact structured claim |
| Expiration | No | Optional | UINT32 | After this close time the attestation is expired and anyone MAY delete it |
| PreviousTxnID / PreviousTxnLgrSeq / OwnerNode | No | Yes | — | Standard |
Owned by Account, one owner reserve, listed in the attester's owner
directory only. Nothing about an attestation touches any other account's
state: the subject is a hash, not a party. Deleted by AttestationDelete;
an account with attestations cannot be deleted until they are removed, the
standard owner-directory rule.
Creates the entry, or updates Data and Expiration in place if the
(attester, subject, type) entry already exists. SubjectHash and
AttestationType are immutable; a different subject or type is a different
entry.
Failure conditions: amendment disabled (temDISABLED), Data over 256 bytes
(temMALFORMED), Expiration in the past (temBAD_EXPIRATION), insufficient
reserve on create (tecINSUFFICIENT_RESERVE).
The attester at any time (revocation), or anyone once Expiration has passed
(the keeper pattern, so expired statements do not linger). Deletion is the
revocation mechanism: an attestation on the ledger is a statement the attester
currently stands behind, and its PreviousTxnLgrSeq chain proves since when.
account_objects returns attestations under type attestation. ledger_entry
accepts {attestation: {account, subject_hash, attestation_type}}. A verifier
asks one question: does an unexpired attestation by this attester about this
subject exist right now.
Why not Credentials (XLS-70). Stated in Motivation: credential subjects are accounts and must accept. The one-sided, artifact-subject case is a different primitive, and bending Credentials to cover it (dummy subject accounts, auto-accept flags) would contaminate a shipped amendment for no gain.
Why on-ledger instead of a signed file. Three properties a gist cannot give: revocation with proof of when, a consensus timestamp, and key continuity (the attesting key is an account that can rotate via regular key and multisign, instead of a bare PGP key someone loses).
Why no truth machinery. An earlier framing of this idea, source code validation, tried to make the ledger verify the build. The ledger cannot run reproducible builds and should not pretend to. Attestations move the trust to where it actually lives, the attester's identity and track record, and keep the protocol surface to a signed, timestamped, revocable pointer. Verifiers that want multi-party assurance read N attestations from N independent attesters, which composes without any protocol support.
Composition. XLS-101 contracts can read attestations to gate logic (release only if two auditors attest this hash). The UNL publisher can attest each published blob. The doc pipeline can attest which commit its output covers. None of these need new protocol work beyond this spec.
None. New amendment, purely additive.
jtx suite: create/update/delete paths, immutability of subject and type, expiration boundary and third-party delete, reserve accounting, account deletion blocking, RPC lookups, amendment gating.
TBD. Sizing: one entry, two transactions, no asset movement, roughly 1.0 to 1.5 engineer-months to audit-ready. The smallest full amendment on the 2027 menu.
- Attestations move no value and touch no third-party state, so the griefing surface is the attester's own reserve.
- Nothing prevents attesting to garbage. That is by design: the object proves authorship and timing, and verifiers MUST evaluate the attester, not the existence of the entry.
- Revocation is deletion, so a verifier caching an attestation MUST re-check liveness at decision time, not at first sight.
- Type collision between applications is possible in the UINT32 namespace; applications SHOULD publish their type registries. The protocol does not arbitrate.