Skip to main content
EID

Working with DIDs

Elastos DIDs are W3C-compliant Decentralized Identifiers anchored on the EID chain. They follow the format did:elastos:i<base58-encoded-id>. The JavaScript SDK implements the W3C DID Core profile used on EID: create and publish documents, issue credentials, and resolve others’ DIDs on-chain.

DID Architecture

┌──────────────────────────────────────────────────────┐
│ DID Document │
│ │
│ DID: did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN │
│ │
│ ┌─────────────────────────────┐ │
│ │ Public Keys │ │
│ │ - authentication key │ │
│ │ - assertion key │ │
│ └─────────────────────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ Services │ │
│ │ - Hive vault endpoint │ │
│ │ - Carrier address │ │
│ └─────────────────────────────┘ │
│ │
│ ┌─────────────────────────────┐ │
│ │ Verifiable Credentials │ │
│ │ - Self-proclaimed │ │
│ │ - Third-party issued │ │
│ └─────────────────────────────┘ │
└──────────────────────────────────────────────────────┘

│ IDChainRequest transaction

┌──────────────────┐
│ EID Chain │
│ (Chain ID: 22) │
│ │
│ Precompiled │
│ contracts: │
│ - 0x16 (22) │ ← operationDID (create/update/deactivate)
│ - 0x17 (23) │ ← resolveDID (resolve DID documents)
│ - 0x7D7 (2007) │ ← KYC operations
└──────────────────┘

SDK Installation

npm install @elastosfoundation/did-js-sdk

Configure the resolver (DIDBackend)

Point the SDK at mainnet or testnet before any DID operation:

import { DIDBackend, DefaultDIDAdapter } from "@elastosfoundation/did-js-sdk";

// Mainnet
DIDBackend.initialize(new DefaultDIDAdapter("https://api.elastos.io/eid"));

// Testnet
DIDBackend.initialize(new DefaultDIDAdapter("https://api-testnet.elastos.io/eid"));
Single global resolver

Call DIDBackend.initialize() once at application startup. Calling it again replaces the global resolver and can cause confusing resolution behavior.

Key Classes

ClassPurpose
DIDStorePersistent storage for DID documents and private keys
RootIdentityRoot identity derived from HD mnemonic
DIDA decentralized identifier reference
DIDDocumentThe full document associated with a DID
DIDURLURL format for referencing DID resources
VerifiableCredentialA signed credential (claim about a subject)
VerifiablePresentationA package of credentials presented to a verifier
IssuerEntity that creates and signs credentials

DIDStore operations

OperationMethodDescription
Open / create storeDIDStore.open(path)Opens an existing store or creates one at the given path
Load a DIDstore.loadDid(did)Loads a DID document from local storage
List DIDsstore.listDids()Lists DIDs in the store
Delete a DIDstore.deleteDid(did)Removes a DID and its keys from local storage
Exportstore.exportDid(did, password, storepass)Exports a DID (with keys) as encrypted JSON
Importstore.importDid(exportedJson, password, storepass)Imports a previously exported DID
Syncstore.synchronize(identity, storepass)Pulls the latest DID documents from the chain into the store

Creating a DID Identity

import {
DIDStore,
RootIdentity,
DID,
DIDDocument,
Mnemonic,
DIDBackend,
DefaultDIDAdapter,
} from "@elastosfoundation/did-js-sdk";

// Initialize the DID backend resolver
const resolver = new DefaultDIDAdapter("https://api.elastos.io/eid");
DIDBackend.initialize(resolver);

// Create or open a DID store
const store = await DIDStore.open("/path/to/did-store");

// Generate a new mnemonic or use existing one
const mnemonic = Mnemonic.generate("english");

// Create root identity from mnemonic
// Derives keys at m/44'/0'/0'/0/<index> using P-256 curve
const rootIdentity = RootIdentity.createFromMnemonic(
mnemonic,
"", // passphrase (empty for default)
store,
"storepass" // store encryption password
);

// Create the first DID document (index 0)
const doc = await rootIdentity.newDid("storepass");
const did = doc.getSubject();
console.log("Created DID:", did.toString());
// Output: did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN
Back up the mnemonic

The mnemonic is the master secret for every DID derived from this RootIdentity. Store it offline; losing it means losing access to those DIDs permanently.

Publishing a DID Document

Publishing anchors the DID document on the EID chain via an IDChainRequest transaction:

// Publish the DID document to the EID chain
await doc.publish("storepass");

// The SDK handles:
// 1. Serializing the DID document to JSON
// 2. Creating an IDChainRequest transaction
// 3. Signing with the DID's private key
// 4. Submitting to the EID chain

// Wait for confirmation (usually 10-20 seconds on EID)
// Then resolve to verify
const resolvedDoc = await DID.resolve(did);
console.log("Resolved:", resolvedDoc !== null);
info

DID publication requires at least one EID block confirmation. EID block time is approximately 5-10 seconds, but network conditions can vary. See Common Pitfalls for retry strategies.

Resolving a DID with the SDK

After a DID is published, you can resolve its document from the chain using a DID instance (this uses the same DIDBackend you initialized earlier):

import { DID } from "@elastosfoundation/did-js-sdk";

const did = new DID("did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN");
const doc = await did.resolve();

if (doc) {
console.log("Public keys:", doc.getPublicKeyCount());
console.log("Services:", doc.getServiceCount());
console.log("Expires:", doc.getExpires()?.toISOString());
} else {
console.log("DID not found on chain");
}
Resolution delay

A DID that was just published may take roughly 10–20 seconds to become resolvable while EID confirms blocks.

Issuing Verifiable Credentials

import { Issuer, VerifiableCredential, DIDURL } from "@elastosfoundation/did-js-sdk";

async function issueCredential(
issuerDoc: DIDDocument,
subjectDID: DID,
storepass: string
): Promise<VerifiableCredential> {
const issuer = new Issuer(issuerDoc);

const credentialId = DIDURL.from("#emailCredential", subjectDID);

const vc = await issuer.issueFor(subjectDID)
.id(credentialId)
.type("EmailCredential", "BasicProfileCredential")
.property("email", "[email protected]")
.property("name", "Jane Developer")
.property("timestamp", new Date().toISOString())
.expirationDate(new Date(Date.now() + 365 * 24 * 60 * 60 * 1000)) // 1 year
.seal(storepass);

console.log("Credential ID:", vc.getId().toString());
console.log("Issuer:", vc.getIssuer().toString());
console.log("Subject:", vc.getSubject().getId().toString());

return vc;
}

Creating Verifiable Presentations

import { VerifiablePresentation } from "@elastosfoundation/did-js-sdk";

async function createPresentation(
holderDoc: DIDDocument,
credentials: VerifiableCredential[],
nonce: string,
realm: string,
storepass: string
): Promise<VerifiablePresentation> {
const vp = await VerifiablePresentation.createFor(
holderDoc.getSubject(),
credentials,
nonce,
realm,
storepass,
holderDoc.getStore()!
);

console.log("Presentation holder:", vp.getHolder().toString());
console.log("Credentials count:", vp.getCredentialCount());
return vp;
}

Verifying Credentials and Presentations

async function verifyCredential(vc: VerifiableCredential): Promise<boolean> {
// Checks:
// 1. Signature is valid (signed by issuer's key)
// 2. Credential is not expired
// 3. Issuer DID is resolvable and not deactivated
// 4. Credential has not been revoked
const isValid = await vc.isValid();

if (!isValid) {
// Check specific failure reasons
const isExpired = vc.isExpired();
const isGenuine = await vc.isGenuine();
console.log("Expired:", isExpired);
console.log("Genuine signature:", isGenuine);
}

return isValid;
}

async function verifyPresentation(vp: VerifiablePresentation): Promise<boolean> {
const isValid = await vp.isValid();

if (isValid) {
const holder = vp.getHolder();
const credentials = vp.getCredentials();
for (const cred of credentials) {
console.log(`Credential ${cred.getId()}: subject=${cred.getSubject().getId()}`);
}
}

return isValid;
}

Resolving DIDs On-Chain

DIDs are resolved by calling the precompiled contract at address 22 (0x16) on the EID chain:

import { ethers } from "ethers";

async function resolveDIDOnChain(didString: string): Promise<object | null> {
const provider = new ethers.JsonRpcProvider("https://api.elastos.io/eid");

const result = await provider.call({
to: "0x0000000000000000000000000000000017", // resolveDID (address 23)
data: ethers.hexlify(ethers.toUtf8Bytes(didString)),
});

if (result === "0x") return null;

const docJson = ethers.toUtf8String(result);
return JSON.parse(docJson);
}

// Usage
const doc = await resolveDIDOnChain("did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN");
if (doc) {
console.log("DID Document:", JSON.stringify(doc, null, 2));
}
tip

For more details on EID precompiled contracts, see ESC Precompiled Contracts.

DID Document Structure

A resolved DID document looks like this:

{
"@context": "https://www.w3.org/ns/did/v1",
"id": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN",
"publicKey": [
{
"id": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN#primary",
"type": "ECDSAsecp256r1",
"controller": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN",
"publicKeyBase58": "27bqfhMew5hEFLYp2kFnhCrJrij7Z6xPSQq6dBgKmyJBw"
}
],
"authentication": [
"did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN#primary"
],
"verifiableCredential": [
{
"id": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN#name",
"type": ["SelfProclaimedCredential"],
"issuer": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN",
"issuanceDate": "2024-01-15T10:00:00Z",
"credentialSubject": {
"id": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN",
"name": "Jane Developer"
}
}
],
"service": [
{
"id": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN#hivevault",
"type": "HiveVault",
"serviceEndpoint": "https://your-hive-node.example.com"
}
],
"expires": "2029-01-15T10:00:00Z",
"proof": {
"type": "ECDSAsecp256r1",
"verificationMethod": "did:elastos:icJ4z2DULrHEzYSvjKNJpKyhqFDxvYV7pN#primary",
"signature": "..."
}
}

SDKs in other languages

LanguageRepository
JavaElastos.DID.Java.SDK
SwiftElastos.DID.Swift.SDK
C/C++Elastos.DID.Native.SDK

Future: Runtime DID Bridge

Planned Feature

The ElastOS Runtime currently uses did:key (Ed25519, locally generated) for device identity and message signing. A bridge from the runtime's did:key to on-chain did:elastos DID is planned but not yet available. When implemented, this will allow runtime identities to anchor to the EID chain, connecting local device identity with globally verifiable on-chain identity. See the Runtime Roadmap for status.

Resources