@jccdex/did
v0.3.2
Published
DID for wodecards
Readme
DID
Simple Profile Did文档解析.
Install
yarn add @jccdex/did @jccdex/vc-vocabularies @jccdex/ipfs-rpc-clientVC 签发与验签(0.3.0+)
业务词汇表在 @jccdex/vc-vocabularies;@jccdex/did 只提供类型无关的 issueVC / verifyVC。
import { issueVC, verifyVC, EthrDidResolver } from "@jccdex/did";
import { buildNftOwnershipDescriptor } from "@jccdex/vc-vocabularies";
import { IpfsClient } from "@jccdex/ipfs-rpc-client";
// baseURL 为 ipfs-service 网关地址;请替换为实际部署地址
const client = new IpfsClient({ baseURL: "https://ipfs-service.example.com" });
const resolver = new EthrDidResolver(client);
const did = "did:ethr:0x...";
const descriptor = buildNftOwnershipDescriptor(
"ccdao",
{ id: did, chainId: 1, contractAddress: "0x...", tokenId: "1", owner: did, status: "Active", standard: "ERC-721" },
{ id: `${did}#vc-1`, expirationDate: "2099-01-01T00:00:00.000Z" }
);
const vcJSON = await issueVC(descriptor, {
sign: async (data) => window.ccdao.request({ method: "did_issueCredential", params: [data] }),
keyDoc: { address: "0x...", did, id: `${did}#key-1` }
});
const { verified } = await verifyVC(vcJSON, { resolver });Usage in DAPP(DID 文档)
import {
EthrDid,
EthrDidPublish,
EthrDidResolver,
EthrDidDocument,
SwtcDid,
SwtcDidPublish,
SwtcDidResolver,
SwtcDidDocument,
DidService,
issueVC,
verifyVC,
} from "@jccdex/did";
import { buildNftOwnershipDescriptor } from "@jccdex/vc-vocabularies";
import { IpfsClient } from "@jccdex/ipfs-rpc-client";
const ethereum = window.ethereum;
// CCDAOConnector授权以太坊地址
const account = "";
// CCDAOConnector授权swtc地址
const swtcAccount = "";
const client = new IpfsClient({
baseURL: "https://ipfs-service.example.com",
sign: async (data, address) => {
const sign = await ethereum.request({
method: 'ipfs_personalSign',
params: [data, address],
});
return sign;
},
getPublicKey: async (address) => {
const pub = await ethereum.request({
method: 'ipfs_getPublicKey',
params: [address]
});
return pub;
}
});
// 创建did
const did = EthrDid.fromIdentifier(account);
const id = `${did.toString()}#key-1`;
const vcJSON = await issueVC(
buildNftOwnershipDescriptor(
"ccdao",
{
id: did.toString(),
contractAddress: "0xED5AF388653567Af2F388E6224dC7C4b3241C544",
chainId: 1,
tokenId: "443",
owner: "0xAWalletAddress",
status: "Active",
standard: "ERC-721"
},
{
id: `${did.toString()}#nft-0xED5AF388653567Af2F388E6224dC7C4b3241C544-443-${did.toString()}`,
expirationDate: "2099-01-01T00:00:00.000Z"
}
),
{
sign: async (data) => ethereum.request({ method: "did_issueCredential", params: [data] }),
keyDoc: { address: account, did: did.toString(), id }
}
);
const resolver = new EthrDidResolver(client);
const { verified } = await verifyVC(vcJSON, { resolver });
// 创建simple profile DID文档
const didDoc = new EthrDidDocument(did.toString());
const profile = DidService.generateProfile({
id: did.toString() + "#profile",
nickname: "张三",
// preferredAvatar 为 NFTOwnership VC 的 VCID(头像凭证 id),不是图片 URL
preferredAvatar: vcJSON.id
});
// 现在ipfs service的ipns固定值
const ipns = "ipns://k2k4r8ntjlp1cmgped39eq1fi4yze6fsr8og1kcmjhamgs3ubwkfldei"
// 获取did文档cid, 如果是原始文件, 则不用获取, 为空字符串.
const { cid } = await resolver.stat(did.toString());
const ipfsStorage = DidService.generateIpfsStorage({
id: did.toString() + "#ipfs-storage",
ipns,
previousCid: cid
});
// 从插件获取base58公钥及加密类型
const { publicKeyBase58, type } = await ethereum.request({
method: 'did_getBase58PublicKey',
params: [account],
});
didDoc.setVersion("1.0.0")
.addAuthentication(id)
.addAssertionMethod(id)
.addVerificationMethod({
id,
type,
controller: did.toString(),
publicKeyBase58
})
.addService(profile)
.addService(ipfsStorage)
.addCredential(vcJSON);
.setUpdated();
// 将did doc上传到ipfs service
const didPublisher = new EthrDidPublish(client);
const res = await didPublisher.upload(did.toString(), didDoc.toJSON(), account);
console.log("did publish result: ", res);
// 创建swtc did
const swtcDid = SwtcDid.fromIdentifier(swtcAccount);
const swtcId = `${swtcDid.toString()}#key-1`;
const swtcVcJSON = await issueVC(
buildNftOwnershipDescriptor(
"jdid",
{
id: swtcDid.toString(),
chainId: 315,
tokenName: "Golden Sands",
tokenId: "2",
owner: "swtcWalletAddress",
status: "Active"
},
{
id: "did:swtc:jHdWAmh8AAjhjqG7zEDA5RBgAnQHyd2g5m#nft-CrossChainDAONFT-j9pmACHpAV72ngFoSTNshhVtfhgGdQrXpc-43726F737320436861696E2044414F2000000000000000000000000000000002-did:swtc:jHdWAmh8AAjhjqG7zEDA5RBgAnQHyd2g5m",
expirationDate: "2099-01-01T00:00:00.000Z"
}
),
{
sign: async (data) => ethereum.request({ method: "did_issueCredential", params: [data] }),
keyDoc: { address: swtcAccount, did: swtcDid.toString(), id: swtcId }
}
);
const swtcResolver = new SwtcDidResolver(client);
const swtcVerified = await verifyVC(swtcVcJSON, { resolver: swtcResolver });
// 创建swtc simple profile DID文档
const swtcDidDoc = new SwtcDidDocument(swtcDid.toString());
const swtcProfile = DidService.generateProfile({
id: swtcDid.toString() + "#profile",
nickname: "李四",
preferredAvatar: swtcVcJSON.id
});
// 获取swtc did文档cid, 如果是原始文件, 则不用获取, 为空字符串.
const { cid: swtcCid } = await swtcResolver.stat(swtcDid.toString());
const swtcIpfsStorage = DidService.generateIpfsStorage({
id: swtcDid.toString() + "#ipfs-storage",
ipns,
previousCid: swtcCid
});
// 从插件获取base58公钥及加密类型
const { publicKeyBase58, type } = await ethereum.request({
method: 'did_getBase58PublicKey',
params: [swtcAccount],
});
swtcDidDoc.setVersion("1.0.0")
.addAuthentication(swtcId)
.addAssertionMethod(swtcId)
.addVerificationMethod({
id: swtcId,
type,
controller: swtcDid.toString(),
publicKeyBase58
})
.addService(swtcProfile)
.addService(swtcIpfsStorage)
.addCredential(swtcVcJSON)
.setUpdated();
// 将swtc did doc上传到ipfs service
const swtcDidPublisher = new SwtcDidPublish(client);
const swtcRes = await swtcDidPublisher.upload(swtcDid.toString(), swtcDidDoc.toJSON(), swtcAccount);
console.log("swtc did publish result: ", swtcRes);
综合 README.md 和目录结构分析,frontend/did 这个 DAPP 主要实现了如下功能,并采用了相关 DID 生态开发包:
主要功能实现
多链 DID 支持
- 支持以太坊(EthrDid)和 SWTC(SwtcDid)两种 DID 标准,能为不同链的账户生成 DID 标识和文档。
DID 文档的创建、扩展与发布
- 可根据账户生成 DID 文档(DID Document),并支持添加 profile(昵称、头像)、ipfsStorage、service、credential 等扩展字段。
- 支持将 DID 文档通过 IPFS 客户端上传到后端 ipfs-service,实现去中心化存储。
可验证凭证(VC)管理
- 支持类型无关的 VC 签发/验签(
issueVC/verifyVC),业务词汇表由@jccdex/vc-vocabularies提供。 - VC 支持多链(以太坊、SWTC)和多类型扩展。
- 支持类型无关的 VC 签发/验签(
DID 文档与 VC 的解析和验证
- 通过 EthrDidResolver、SwtcDidResolver 结合 IPFS 客户端,支持 DID 文档和 VC 的解析、CID 查询、签名验证等。
与钱包/插件集成
- 通过 window.ethereum.request 与钱包或浏览器插件交互,实现链上签名、公钥获取、凭证签发等操作,支持 DApp 场景下的用户身份和凭证管理。
IPFS 存储与版本管理
- 支持通过 ipfs-rpc-client 与后端 ipfs-service 通信,实现 DID 文档和凭证的去中心化存储、读取、CID 查询、IPNS 版本管理等。
主要依赖的开发包
@jccdex/did
- 提供 DID 标识、文档、凭证、解析、发布、服务扩展等全套能力,支持多链和多类型扩展。
- 主要类和方法:EthrDid、SwtcDid、EthrDidPublish、SwtcDidPublish、EthrDidResolver、SwtcDidResolver、issueVC、verifyVC、DidService 等。
@jccdex/ipfs-rpc-client
- 提供与后端 ipfs-service 的 HTTP 通信能力,实现 IPFS 文件的上传、下载、CID 查询、IPNS 管理等。
代码结构与典型流程
- 代码分为 lib/(核心库)、src/(业务逻辑)、test/(测试)等目录,核心 DID 相关逻辑在 lib/ 和 src/ 下。
- 典型流程:
- 通过账户生成 DID → 构建 DID 文档 → 生成/签名 VC → 通过 IPFS 客户端上传 DID 文档 → 解析/验证 DID 文档和 VC → 支持 profile、service、ipfsStorage 等扩展 → 与钱包插件集成实现链上签名和公钥获取。
特色与优势
- 支持多链 DID 和 NFT VC,适合多链身份和资产场景。
- DID 文档和凭证均可去中心化存储,支持版本管理和扩展。
- 与钱包深度集成,适合 DApp 场景。
- 代码结构清晰,扩展性强,便于二次开发。
DID / VC 兼容性与职责边界
关于 @jccdex/did 协议层工作范围、应用端(did_DApp)如何应对 VC 类型与字段演进、以及 SDK 后续改造方向,见仓库根目录文档:DID / VC 兼容性说明。
