# did:ethst method — implementation draft 0.1.0 Status: implementation draft with a deployed, frozen production network binding; hosted account/bot onboarding remains disabled. This document is not a verified canonical chain pin. Method name: `ethst`. Maintainer: Ethereum Streets / Silicon Soulaan Labs. Date: 2026-10-21. ## Identifiers and creation Production syntax is `did:ethst:0x` followed by exactly 40 lowercase hexadecimal characters. Test syntax is `did:ethst:test:0x` followed by the same address form. The zero address is forbidden. Addresses identify enduring subjects, not their current wallets. Names, subject types and Zodiac affiliations are private application records or credentials, not DID path segments. Earlier conceptual `user:`, `agent:` and `house:` examples are not v1 identifiers. An address has an implicit DID from the registry deployment block, without a registration transaction. Initial control belongs to that address. Enrollment requires separate proof of control and account authorization. Distinct bot individuals receive distinct identity addresses; sessions, restarts, recovery and migrations retain their individual's DID. The Species Registry, not this resolver, assigns Birthline. A DID or successful resolution does not prove an authorized canonical commitment. ## Network binding and trust Production chain ID is 369369369. The observed genesis hash is `0x946068cb75e6b56594d0f5273741c36100ab1855a90572c7bb669cb17fed0607`, verified through the chain server on 2026-10-21. The final binding MUST publish registry address, deployment block and hash, runtime bytecode hash, source/compiler provenance and confirmation count in `/method.json`. Production configuration MUST set `frozen: true` before issuance. Moving the API cannot change this binding. A reset of chain history requires a new method/network design; reusing a chain ID cannot silently replace identities. The permissioned Clique chain and RPC history are trust dependencies. Confirmation depth reduces ordinary reorganization risk; it is not cryptographic finality and does not eliminate collusion or censorship. An independent implementation with access to the same chain history can reconstruct identical documents. RPC availability and faithful historical log delivery are required; no cryptographic log completeness proof is implemented. The deployed contract uses unchanged `ethr-did-registry@2.0.0` source, MIT license. Compile with solc 0.8.30, optimizer 200 runs, EVM **Berlin**, because Streets is pre-London. The generated artifact records the exact source hash and compiler settings. Contract deployment and SDK transactions use legacy gas pricing on Streets. ## Updates and recovery ERC-1056 `changeOwner`, `addDelegate`, `revokeDelegate`, `setAttribute`, and `revokeAttribute` authorize updates using the current registry owner. Direct transactions carry Ethereum nonce and chain replay protection. The v1 SDK accepts a caller-owned signer; it does not hold identity, spending, or recovery secrets. A controller transfer changes the `#controller` verification method without changing the DID. A separate recovery controller can authorize delegates for everyday bot signing. If all authorized recovery control is lost, this method provides no administrative override. Supported delegates are `sigAuth` (authentication and assertion) and `veriKey` (assertion only). Verification methods use `EcdsaSecp256k1RecoveryMethod2020` and checksummed `eip155::
` blockchainAccountId. Delegate IDs are `#delegate--`. Delegates expire when `validTo <= selectedBlock.timestamp`. Consumers authenticating now MUST additionally enforce wall-clock expiry and current revocation policy; a historical DID document alone cannot authorize a current login. Smart account/EIP-1271 support is not provided. Supported public attributes are UTF-8 HTTPS service endpoints named `did/svc/` (type: a letter followed by up to 22 letters, digits, underscores or hyphens). Maximum endpoint length is 2048 characters. Attribute identity is the `(name,value)` pair, so changing a URL does not revoke its prior value; explicitly revoke the old endpoint. Service ID is `#service--`. Invalid or unsupported attributes and delegate types are ignored. Other key attribute formats are outside this version's profile. Email addresses, private mappings and permission policy MUST NOT be put on-chain. ## Permanent deactivation Deactivation is the first authorized `DIDOwnerChanged(identity, zeroAddress, previousChange)` event. It is an irreversible **method-level tombstone**. All subsequent events for that identity MUST be ignored forever. This distinction is essential: ERC-1056 itself treats a zero owner as a reset to the identity address and can accept later writes. Those writes never reactivate a `did:ethst` identity. Resolvers MUST replay history rather than consulting only `identityOwner`. A deactivated resolution has `didDocument: null` and `didDocumentMetadata.deactivated: true`. Historical versions before the tombstone remain resolvable. ## Resolution algorithm 1. Reject malformed identifiers and unconfigured network prefixes. Verify chain ID, genesis, deployment block hash and deployed runtime code hash against the binding. Never silently discover or substitute a registry. 2. Choose block `head - confirmations + 1`, or the explicitly supplied `versionId` decimal block number. Reject blocks before deployment or beyond the confirmed head. `versionTime` is explicitly unsupported in v1. The block timestamp governs delegate and attribute expiry. 3. Fetch all three ERC-1056 event types for the identity from deployment through that block, inclusive. Sort by block number, transaction index, then log index. Start with the identity address as owner. Apply owner changes until the first zero-owner tombstone. Reduce delegates by `(delegateType,address)` and attributes by `(name,value)`, keeping the last event of each pair. 4. Construct controller verification method first, then live supported delegates in lexical order of their event keys, then live services in lexical order of their event keys. All verification-method controllers refer to the subject DID; the controller key represents the current owner. Authentication/assertion references use the constructed IDs. Never rewrite arbitrary string values or service endpoints. 5. Return `didDocument`, `didDocumentMetadata` (including snapshot `versionId` and `ethstBlockHash`) and `didResolutionMetadata`. Recheck the selected block hash before responding; fail on a detected reorganization. Independent resolvers at the same block and configuration MUST return the same document. No resolver cache is needed to recover history. The default representation is `application/did+ld+json`; `application/did+json` omits `@context`. `versionId` identifies the complete snapshot block, not only the last identity event: this is needed to reproduce expiry between updates. Errors include `invalidDid`, `unsupportedNetwork`, `invalidOptions`, `representationNotSupported`, and `internalError` for RPC failure, missing history, or binding mismatch. An RPC outage MUST NOT produce `notFound`. ## HTTP service and release boundaries `GET /1.0/identifiers/{did}?versionId=` returns the DID resolution envelope, HTTP 400 for invalid input, or 503 when resolution is unavailable. `GET /method.json` publishes the binding without RPC credentials. `GET /docs` serves this document. `/healthz` checks the process; `/readyz` reports configuration readiness. Public requests are rate limited. The resolver has no private signing keys. This release does not implement hosted enrollment, challenge login, a transaction worker, tenant account mappings, Veramo key custody, WordPress provisioning, or automated Birthline assignment. Management routes reject requests instead of implying these features exist. Before enabling them, require PostgreSQL-backed one-use challenges, exact domain/audience binding, expiry, current authorization, durable idempotency, tenant ownership checks and a transactional worker/outbox. The remaining production acceptance gates are tracked in README.md. ## References - DID Core: https://www.w3.org/TR/did-core/ - ERC-1056 registry: https://github.com/uport-project/ethr-did-registry - Upstream Ethereum method semantics: https://github.com/decentralized-identity/ethr-did-resolver/blob/master/doc/did-method-spec.md - Resolver interface: https://github.com/decentralized-identity/did-resolver This is an independently implementable custom method draft; compatibility with a third-party wallet or universal resolver is not automatic.