Method ​
TypeScript implementation of did:btcr2 DID Method.
Documentation ​
Visit btcr2.dev to learn more about how to use @did-btcr2/method.
Test Vector Generator ​
An incremental CLI tool for generating did:btcr2 test vectors through a stepped workflow: create → update (offline) → fund → announce → resolve. It produces JSON files under lib/data/.
The first positional argument is the action. create runs offline. All subsequent actions only need --hash — the type and network are derived from the DID itself.
Quick Start ​
# From packages/method/
# 1. Create a new DID (only action that takes --type and --network)
pnpm generate:vector create
pnpm generate:vector create --type external --network mutinynet
# 2. Construct and sign an update offline (use the hash printed by step 1)
pnpm generate:vector update --hash <hash> --offline
# 3. Fund the beacon address(es)
source .env
pnpm generate:vector fund --hash <hash>
# 4. Announce the signed update on-chain
pnpm generate:vector announce --hash <hash>
# 5. Resolve the DID against a live Bitcoin node
pnpm generate:vector resolve --hash <hash>
# List existing vectors
pnpm generate:vector list
pnpm generate:vector list --network regtest --type keyCLI Reference ​
pnpm generate:vector <action> [options]Actions ​
| Action | Description |
|---|---|
create | Create a new DID and initial test vector files |
update | Construct and sign an update (optionally announce) |
fund | Fund beacon address(es) via RPC sendtoaddress + mine a block |
announce | Announce a previously signed update on-chain |
resolve | Resolve a DID against a live Bitcoin node |
list | Show existing test vectors |
Options ​
| Flag | Values | Default | Applies to | Description |
|---|---|---|---|---|
--type | key, external | key | create, list | DID identifier type |
--network | regtest, bitcoin, mutinynet, etc. | regtest | create, list | Bitcoin network |
--genesis | hex string | prompt / auto-generate | create | Genesis bytes hex (see below) |
--hash | 8-char short hash | — | update, fund, announce, resolve | Vector identifier (required) |
--interactive | flag (no value) | off | update | Enable interactive patch builder |
--amount | BTC amount | 0.001 | fund | BTC amount to send to each beacon address |
--offline | flag (no value) | off | update, resolve | Skip on-chain announcement or live resolution |
After
create, the hash uniquely identifies the vector. The script finds the directory automatically and derives the type and network from the stored DID.
Actions ​
create ​
Creates a DID and writes the initial vector files. The --genesis flag behavior depends on the --type:
- k1:
--genesisis a compressed public key hex. If omitted, prompts for one. If blank, auto-generates a keypair. - x1:
--genesisis a SHA-256 hash hex of a genesis document. If omitted, prompts for a JSON genesis document or hex hash. If blank, auto-generates a keypair and default genesis document.
# Auto-generate everything
pnpm generate:vector create
pnpm generate:vector create --type external --network regtest
# Bring your own genesis bytes
pnpm generate:vector create --type key --genesis 02abc...def
pnpm generate:vector create --type external --network regtest --genesis 82830a78...f83a99Outputs:
lib/data/{network}/{type}/{hash}/
create/input.json # { idType, version, network, genesisBytes }
create/output.json # { did }
other.json # { genesisKeys: { secret, public }, genesisDocument? }The --hash for subsequent steps is printed to the console.
update ​
Reads back the create output, rebuilds the source document, constructs and signs an update.
Without --interactive: applies a default patch that rotates the first SingletonBeacon service endpoint (P2PKH key rotation).
With --interactive: prompts for JSON Patch operations with smart auto-generation (see below).
With --offline: builds and signs the update but skips the on-chain announcement. This is the typical workflow — use fund and announce as separate steps afterward.
Without --offline: also announces the update on-chain immediately (requires a funded beacon address and BITCOIN_NETWORK_CONFIG).
# Recommended: sign offline, then fund and announce separately
pnpm generate:vector update --hash <hash> --offline
pnpm generate:vector update --hash <hash> --offline --interactive
# Or sign and announce in one step (beacon must already be funded)
source .env
pnpm generate:vector update --hash <hash>Outputs:
lib/data/{network}/{type}/{hash}/
update/input.json # { sourceDocument, patches, sourceVersionId, ... }
update/output.json # { signedUpdate }
other.json # (updated with generated keys)fund ​
Funds all beacon service addresses in the DID document via RPC sendtoaddress, then mines blocks to confirm the funding transaction(s). Requires a live Bitcoin node with a loaded wallet.
source .env
pnpm generate:vector fund --hash <hash>
pnpm generate:vector fund --hash <hash> --amount 0.01Requires
BITCOIN_NETWORK_CONFIGto be set with connection info for the DID's network. Source your.envfile or export it directly.
announce ​
Announces a previously signed update on-chain via the beacon service. Reads the signed update and beacon metadata from the update step's persisted files. Useful for retrying a failed announcement without re-running the full update pipeline.
source .env
pnpm generate:vector announce --hash <hash>Requires
BITCOIN_NETWORK_CONFIGto be set with connection info for the DID's network. Source your.envfile or export it directly.
resolve ​
Resolves a DID against a live Bitcoin node. Assembles a sidecar from the signed update (if the update step has been run) and the genesis document (for x1 types).
With --offline: writes only the sidecar input file without connecting to Bitcoin.
# Resolve against a live Bitcoin node
source .env
pnpm generate:vector resolve --hash <hash>
# Offline — build sidecar input only
pnpm generate:vector resolve --hash <hash> --offlineOutputs:
lib/data/{network}/{type}/{hash}/
resolve/input.json # { did, resolutionOptions: { sidecar } }
resolve/output.json # { didDocument, didResolutionMetadata, didDocumentMetadata } (live only)Live resolution requires
BITCOIN_NETWORK_CONFIGto be set with connection info for the DID's network. Source your.envfile or export it directly.
list ​
Displays existing test vectors filtered by network and type. If --network or --type are not provided, prompts interactively.
pnpm generate:vector list
pnpm generate:vector list --network regtest --type keyInteractive Mode ​
Pass --interactive to the update step to build custom patches. The tool detects common patch targets and auto-generates values.
pnpm generate:vector update --hash <hash> --interactiveService patches (/service/<n>) ​
When add or replace targets a path like /service/0, the tool:
- Prompts for address type (
p2pkh,p2wpkh,p2tr) — defaults top2pkh - Prompts for pubkey hex — leave empty to auto-generate a new keypair
- Derives the Bitcoin address and builds the complete service object
--- Add a JSON Patch operation ---
op: add
path: /service/1
Detected service patch — auto-generating value.
address type (p2pkh | p2wpkh | p2tr) [p2pkh]: p2wpkh
pubkey hex (leave empty to auto-generate):
Auto-generated keypair (stored as "service-service-1")
Added: {"op":"add","path":"/service/1","value":{"id":"did:btcr2:...#service-1","type":"SingletonBeacon","serviceEndpoint":"bitcoin:bcrt1q..."}}Verification method patches (/verificationMethod/<n>) ​
When add or replace targets a path like /verificationMethod/1, the tool:
- Prompts for an id fragment (e.g.
someNewIdor#someNewId) — defaults tokey-1,key-2, etc. - Validates the id is unique against existing verification methods
- Prompts for pubkey hex — leave empty to auto-generate
- Builds the complete verification method object with
publicKeyMultibase
--- Add a JSON Patch operation ---
op: add
path: /verificationMethod/1
Detected verificationMethod patch — auto-generating value.
id fragment (e.g. "someNewId" or "#someNewId") [key-1]: recoveryKey
pubkey hex (leave empty to auto-generate):
Auto-generated keypair (stored as "verificationMethod-verificationMethod-1")
Added: {"op":"add","path":"/verificationMethod/1","value":{"id":"did:btcr2:...#recoveryKey","type":"Multikey","controller":"did:btcr2:...","publicKeyMultibase":"zQ3sh..."}}Other patches ​
For any path not matching the above patterns, or for operations like remove, move, copy, the tool falls back to manual JSON value input.
Key Storage ​
All generated and user-provided keys are persisted in other.json for later reuse:
- Auto-generated keys include both
secretandpublichex values - User-provided keys store the
publichex with an emptysecretfield for you to fill in if needed
{
"genesisKeys": { "secret": "...", "public": "..." },
"newBeaconKeys": { "secret": "...", "public": "..." },
"generatedKeys": {
"service-service-1": { "secret": "...", "public": "..." },
"verificationMethod-verificationMethod-1": { "secret": "", "public": "..." }
}
}Output Directory Structure ​
lib/data/{network}/{type}/{hash}/
create/
input.json
output.json
update/
input.json
output.json
resolve/
input.json
output.json # (live mode only)
other.jsonEnumerations ​
Classes ​
- AggregateBeaconCohort
- AggregateBeaconError
- AggregateBeaconMessage
- Appendix
- BaseMessage
- Beacon
- BeaconCohortAdvertMessage
- BeaconCohortAggregatedNonceMessage
- BeaconCohortAuthorizationRequestMessage
- BeaconCohortNonceContributionMessage
- BeaconCohortOptInAcceptMessage
- BeaconCohortOptInMessage
- BeaconCohortReadyMessage
- BeaconCohortRequestSignatureMessage
- BeaconCohortSignatureAuthorizationMessage
- BeaconCohortSigningSession
- BeaconCohortSubscribeMessage
- BeaconCoordinator
- BeaconCoordinatorError
- BeaconError
- BeaconFactory
- BeaconParticipant
- BeaconParticipantError
- BeaconSignalDiscovery
- BeaconUtils
- CASBeacon
- CASBeaconError
- CommunicationAdapterError
- CommunicationFactory
- CommunicationServiceError
- DidBtcr2
- DidCommAdapter
- DidCommAdapterConfig
- DidDocument
- DidDocumentBuilder
- DidVerificationMethod
- Document
- GenesisDocument
- Identifier
- NostrAdapter
- Resolver
- SingletonBeacon
- SingletonBeaconError
- SMTBeacon
- SMTBeaconError
- Update
Interfaces ​
- BeaconCohort
- BeaconProcessResult
- BeaconService
- BeaconSignal
- BlockMetadata
- Btcr2DidDocument
- Btcr2VerificationMethod
- CohortAdvertMessage
- CohortAggregatedNonceMessage
- CohortAuthorizationRequestMessage
- CohortNonceContributionMessage
- CohortOptInAcceptMessage
- CohortOptInMessage
- CohortReadyMessage
- CohortSubscribeMessage
- CommunicationService
- DidComponents
- DidCreateOptions
- DidResolutionResponse
- IdentifierComponents
- NeedBeaconSignals
- NeedCASAnnouncement
- NeedGenesisDocument
- NeedSignedUpdate
- NostrAdapterConfig
- ParsedBeaconService
- ResolutionOptions
- RootCapability
- Service
- ServiceAdapterConfig
- SigningSession
- SMTProof
Type Aliases ​
- AggregateBeaconMessageType
- AsyncMessageHandler
- Base
- BaseBody
- BeaconCoordinatorParams
- BeaconSidecarData
- CASAnnouncement
- CASBeaconSidecarData
- COHORT_STATUS_TYPE
- CohortRequestSignatureMessage
- CohortSignatureAuthorizationMessage
- CommunicationServiceType
- DataNeed
- DidDocumentLike
- ExternalData
- GenesisDocumentLike
- KeyGenMessageType
- MessageHandler
- Musig2CohortObject
- ResolverState
- ServiceAdapter
- ServiceAdapterConfigType
- ServiceAdapterIdentity
- Sidecar
- SidecarData
- SIGNING_SESSION_STATUS_TYPE
- SignMessageType
- SingletonBeaconSidecarData
- SMTBeaconSidecarData
- SyncMessageHandler
- VerificationRelationships
Variables ​
- BEACON_COHORT_ADVERT
- BEACON_COHORT_AGGREGATED_NONCE
- BEACON_COHORT_AUTHORIZATION_REQUEST
- BEACON_COHORT_MESSAGE_PREFIX
- BEACON_COHORT_NONCE_CONTRIBUTION
- BEACON_COHORT_OPT_IN
- BEACON_COHORT_OPT_IN_ACCEPT
- BEACON_COHORT_READY
- BEACON_COHORT_REQUEST_SIGNATURE
- BEACON_COHORT_SIGNATURE_AUTHORIZATION
- BECH32M_CHARS
- BTCR2_DID_DOCUMENT_CONTEXT
- DEFAULT_NOSTR_RELAYS
- DID_REGEX
- ID_PLACEHOLDER_VALUE
- MESSAGE_PREFIX