Skip to main content
HOW-TO
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", "developer@example.com")
.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​