Skip to main content
Version: 0.7

Hedera

Hedera is a public network whose Consensus Service (HCS) stores did:hedera DID documents and AnonCreds objects. @credo-ts/hedera adds the did:hedera method and an AnonCreds registry, built on the Hiero DID SDK. Writes cost HBAR, paid by an operator account that you configure.

Use did:hedera when your ecosystem uses Hedera, for DIDs or as an AnonCreds registry.

Experimental

The Hedera module is experimental and may have breaking changes in any release. Pin exact versions of all @credo-ts/* packages when you use it.

Install​

npm install @credo-ts/hedera@^0.7.2

Configure​

Register HederaModule with the networks you use, and add the Hedera registrar and resolver to DidsModule:

agent.ts
import {
Agent,
DidDocumentService,
DidsModule,
JwkDidRegistrar,
JwkDidResolver,
KeyDidRegistrar,
KeyDidResolver,
PeerDidRegistrar,
PeerDidResolver,
WebDidResolver,
} from '@credo-ts/core'
import {
type HederaDidCreateOptions,
HederaDidRegistrar,
HederaDidResolver,
type HederaDidUpdateOptions,
HederaModule,
} from '@credo-ts/hedera'
import { agentDependencies } from '@credo-ts/node'

// The operator account pays the Hedera transaction fees
const operatorId = process.env.HEDERA_OPERATOR_ID
const operatorKey = process.env.HEDERA_OPERATOR_KEY
if (!operatorId || !operatorKey) throw new Error('HEDERA_OPERATOR_ID and HEDERA_OPERATOR_KEY must be set')

const hederaModules = {
hedera: new HederaModule({
networks: [{ network: 'testnet', operatorId, operatorKey }],
}),
dids: new DidsModule({
registrars: [new KeyDidRegistrar(), new PeerDidRegistrar(), new JwkDidRegistrar(), new HederaDidRegistrar()],
resolvers: [
new KeyDidResolver(),
new PeerDidResolver(),
new JwkDidResolver(),
new WebDidResolver(),
new HederaDidResolver(),
],
}),
}

Spread these modules into the modules of your agent. Each network takes:

OptionDescription
network'mainnet', 'testnet', 'previewnet', 'local-node', or a custom network { name, nodes, mirrorNodes }.
operatorIdAccount id of the operator account, such as 0.0.12345.
operatorKeyPrivate key of the operator account.

HederaModule doesn't register the DID registrar and resolver itself, so list them in DidsModule. Your lists replace the default registrars and resolvers, see Configure DID methods.

Create a did:hedera​

issuer.ts
const { didState } = await agent.dids.create<HederaDidCreateOptions>({
method: 'hedera',
options: { network: 'testnet' },
})

if (didState.state !== 'finished') {
throw new Error(`Creating the did failed: ${didState.state === 'failed' ? didState.reason : didState.state}`)
}
const did = didState.did

Credo creates an Ed25519 root key in the KMS and publishes a DID document with it as #did-root-key. The root key signs every later update. Pass secret.rootKeyId to use an Ed25519 key that's already in the KMS. With more than one network configured, options.network picks the network for the new DID.

To publish a full DID document right away, pass didDocument, and list the KMS keys of its verification methods in secret.keys as { kmsKeyId, didDocumentRelativeKeyId }.

Update a did:hedera​

issuer.ts
const updateResult = await agent.dids.update<HederaDidUpdateOptions>({
did,
didDocumentOperation: 'addToDidDocument',
didDocument: {
service: [
new DidDocumentService({
id: `${did}#website`,
type: 'LinkedDomains',
serviceEndpoint: 'https://issuer.example.com',
}),
],
},
})
if (updateResult.didState.state !== 'finished') throw new Error('Updating the did failed')

didDocumentOperation is required:

  • addToDidDocument adds the services and verification methods in didDocument.
  • removeFromDidDocument removes them.
  • setDidDocument replaces the document.

Credo finds the network from the DID and signs with the root key from the DidRecord. Every verification method in the update needs its KMS key: Credo uses the keys in the DidRecord, and you pass keys for new verification methods in secret.keys.

Deactivate a did:hedera​

issuer.ts
const deactivateResult = await agent.dids.deactivate({ did })

AnonCreds registry​

HederaAnonCredsRegistry registers and resolves AnonCreds schemas, credential definitions and revocation data on HCS. Import it from the @credo-ts/hedera/anoncreds subpath: the export from the @credo-ts/hedera root is deprecated, and removed in 0.8. The Hiero DID SDK needs a Zstandard library to store the objects, and a crypto library on React Native:

npm install zstd-napi

Set up AnonCreds as described in AnonCreds, with the Hedera registry:

agent.ts
import { AnonCredsModule } from '@credo-ts/anoncreds'
import { HederaAnonCredsRegistry } from '@credo-ts/hedera/anoncreds'
import { NativeAnoncreds } from '@hyperledger/anoncreds-nodejs'

// HederaModule must be registered as well, the registry uses its network configuration
const anoncreds = new AnonCredsModule({
anoncreds: NativeAnoncreds,
registries: [new HederaAnonCredsRegistry()],
})

The registry uses the network configuration of HederaModule, so register that module as well. The issuer needs a did:hedera.