Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: small updates to cheqd module and demo #1439

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion DEVREADME.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ docker pull postgres
docker run --name postgres -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres
```

### Setup Ledger
### Setup Indy Ledger

For testing we've added a setup to this repo that allows you to quickly setup an indy ledger.

Expand All @@ -74,6 +74,14 @@ docker exec indy-pool add-did-from-seed 000000000000000000000000Trustee9 TRUSTEE
# docker exec indy-pool add-did "NkGXDEPgpFGjQKMYmz6SyF" "CrSA1WbYYWLJoHm16Xw1VEeWxFvXtWjtsfEzMsjB5vDT"
```

### Setup Cheqd Ledger

In addition, there's also a docker command to run a cheqd test network.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to also have an advice about skipping cheqd tests like we did for postgres


```sh
docker run --rm -d -p 26657:26657 ghcr.io/cheqd/cheqd-testnet:latest
```

### Run all tests

You can run the tests using the following command.
Expand Down
5 changes: 5 additions & 0 deletions demo/src/Alice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export class Alice extends BaseAgent {
}

public async acceptCredentialOffer(credentialRecord: CredentialExchangeRecord) {
const linkSecretIds = await this.agent.modules.anoncreds.getLinkSecretIds()
if (linkSecretIds.length === 0) {
await this.agent.modules.anoncreds.createLinkSecret()
}

await this.agent.credentials.acceptOffer({
credentialRecordId: credentialRecord.id,
})
Expand Down
16 changes: 9 additions & 7 deletions demo/src/BaseAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import type { IndySdkPoolConfig } from '@aries-framework/indy-sdk'
import type { IndyVdrPoolConfig } from '@aries-framework/indy-vdr'

import {
AnonCredsCredentialFormatService,
AnonCredsModule,
AnonCredsProofFormatService,
LegacyIndyCredentialFormatService,
LegacyIndyProofFormatService,
V1CredentialProtocol,
Expand Down Expand Up @@ -31,7 +33,7 @@ import {
HttpOutboundTransport,
} from '@aries-framework/core'
import { IndySdkAnonCredsRegistry, IndySdkModule, IndySdkSovDidResolver } from '@aries-framework/indy-sdk'
import { IndyVdrAnonCredsRegistry, IndyVdrModule, IndyVdrSovDidResolver } from '@aries-framework/indy-vdr'
import { IndyVdrIndyDidResolver, IndyVdrAnonCredsRegistry, IndyVdrModule } from '@aries-framework/indy-vdr'
import { agentDependencies, HttpInboundTransport } from '@aries-framework/node'
import { anoncreds } from '@hyperledger/anoncreds-nodejs'
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'
Expand All @@ -46,7 +48,7 @@ const bcovrin = `{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node1","blsk
{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node3","blskey":"3WFpdbg7C5cnLYZwFZevJqhubkFALBfCBBok15GdrKMUhUjGsk3jV6QKj6MZgEubF7oqCafxNdkm7eswgA4sdKTRc82tLGzZBd6vNqU8dupzup6uYUf32KTHTPQbuUM8Yk4QFXjEf2Usu2TJcNkdgpyeUSX42u5LqdDDpNSWUK5deC5","blskey_pop":"QwDeb2CkNSx6r8QC8vGQK3GRv7Yndn84TGNijX8YXHPiagXajyfTjoR87rXUu4G4QLk2cF8NNyqWiYMus1623dELWwx57rLCFqGh7N4ZRbGDRP4fnVcaKg1BcUxQ866Ven4gw8y4N56S5HzxXNBZtLYmhGHvDtk6PFkFwCvxYrNYjh","client_ip":"138.197.138.255","client_port":9706,"node_ip":"138.197.138.255","node_port":9705,"services":["VALIDATOR"]},"dest":"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya"},"metadata":{"from":"4cU41vWW82ArfxJxHkzXPG"},"type":"0"},"txnMetadata":{"seqNo":3,"txnId":"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4"},"ver":"1"}
{"reqSignature":{},"txn":{"data":{"data":{"alias":"Node4","blskey":"2zN3bHM1m4rLz54MJHYSwvqzPchYp8jkHswveCLAEJVcX6Mm1wHQD1SkPYMzUDTZvWvhuE6VNAkK3KxVeEmsanSmvjVkReDeBEMxeDaayjcZjFGPydyey1qxBHmTvAnBKoPydvuTAqx5f7YNNRAdeLmUi99gERUU7TD8KfAa6MpQ9bw","blskey_pop":"RPLagxaR5xdimFzwmzYnz4ZhWtYQEj8iR5ZU53T2gitPCyCHQneUn2Huc4oeLd2B2HzkGnjAff4hWTJT6C7qHYB1Mv2wU5iHHGFWkhnTX9WsEAbunJCV2qcaXScKj4tTfvdDKfLiVuU2av6hbsMztirRze7LvYBkRHV3tGwyCptsrP","client_ip":"138.197.138.255","client_port":9708,"node_ip":"138.197.138.255","node_port":9707,"services":["VALIDATOR"]},"dest":"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA"},"metadata":{"from":"TWwCRQRZ2ZHMJFn9TzLp7W"},"type":"0"},"txnMetadata":{"seqNo":4,"txnId":"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008"},"ver":"1"}`

const indyNetworkConfig = {
export const indyNetworkConfig = {
// Need unique network id as we will have multiple agent processes in the agent
id: randomUUID(),
genesisTransactions: bcovrin,
Expand All @@ -55,7 +57,7 @@ const indyNetworkConfig = {
connectOnStartup: true,
} satisfies IndySdkPoolConfig | IndyVdrPoolConfig

type DemoAgent = Agent<ReturnType<typeof getLegacyIndySdkModules> | ReturnType<typeof getAskarAnonCredsIndyModules>>
type DemoAgent = Agent<ReturnType<typeof getAskarAnonCredsIndyModules>>

export class BaseAgent {
public port: number
Expand Down Expand Up @@ -92,7 +94,7 @@ export class BaseAgent {
this.agent = new Agent({
config,
dependencies: agentDependencies,
modules: useLegacyIndySdk ? getLegacyIndySdkModules() : getAskarAnonCredsIndyModules(),
modules: getAskarAnonCredsIndyModules(),
})
this.agent.registerInboundTransport(new HttpInboundTransport({ port }))
this.agent.registerOutboundTransport(new HttpOutboundTransport())
Expand Down Expand Up @@ -120,7 +122,7 @@ function getAskarAnonCredsIndyModules() {
indyCredentialFormat: legacyIndyCredentialFormatService,
}),
new V2CredentialProtocol({
credentialFormats: [legacyIndyCredentialFormatService],
credentialFormats: [legacyIndyCredentialFormatService, new AnonCredsCredentialFormatService()],
}),
],
}),
Expand All @@ -131,7 +133,7 @@ function getAskarAnonCredsIndyModules() {
indyProofFormat: legacyIndyProofFormatService,
}),
new V2ProofProtocol({
proofFormats: [legacyIndyProofFormatService],
proofFormats: [legacyIndyProofFormatService, new AnonCredsProofFormatService()],
}),
],
}),
Expand All @@ -157,7 +159,7 @@ function getAskarAnonCredsIndyModules() {
})
),
dids: new DidsModule({
resolvers: [new IndyVdrSovDidResolver(), new CheqdDidResolver()],
resolvers: [new IndyVdrIndyDidResolver(), new CheqdDidResolver()],
registrars: [new CheqdDidRegistrar()],
}),
askar: new AskarModule({
Expand Down
55 changes: 23 additions & 32 deletions demo/src/Faber.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type BottomBar from 'inquirer/lib/ui/bottom-bar'
import { KeyType, TypedArrayEncoder, utils, ConnectionEventTypes } from '@aries-framework/core'
import { ui } from 'inquirer'

import { BaseAgent } from './BaseAgent'
import { BaseAgent, indyNetworkConfig } from './BaseAgent'
import { Color, greenText, Output, purpleText, redText } from './OutputClass'

export enum RegistryOptions {
Expand Down Expand Up @@ -33,28 +33,23 @@ export class Faber extends BaseAgent {
public async importDid(registry: string) {
// NOTE: we assume the did is already registered on the ledger, we just store the private key in the wallet
// and store the existing did in the wallet
const privateKey = TypedArrayEncoder.fromString('afjdemoverysercure00000000000000')
const key = await this.agent.wallet.createKey({
keyType: KeyType.Ed25519,
privateKey,
// indy did is based on private key (seed)
const unqualifiedIndyDid = '2jEvRuKmfBJTRa7QowDpNN'
const cheqdDid = 'did:cheqd:testnet:d37eba59-513d-42d3-8f9f-d1df0548b675'
const indyDid = `did:indy:${indyNetworkConfig.indyNamespace}:${unqualifiedIndyDid}`

const did = registry === RegistryOptions.indy ? indyDid : cheqdDid
await this.agent.dids.import({
did,
overwrite: true,
privateKeys: [
{
keyType: KeyType.Ed25519,
privateKey: TypedArrayEncoder.fromString('afjdemoverysercure00000000000000'),
},
],
})
// did is first 16 bytes of public key encoded as base58
const unqualifiedIndyDid = TypedArrayEncoder.toBase58(key.publicKey.slice(0, 16))
const cheqdDid = 'did:cheqd:testnet:2d6841a0-8614-44c0-95c5-d54c61e420f2'
switch (registry) {
case RegistryOptions.indy:
await this.agent.dids.import({
did: `did:sov:${unqualifiedIndyDid}`,
})
this.anonCredsIssuerId = unqualifiedIndyDid
break
case RegistryOptions.cheqd:
await this.agent.dids.import({
did: cheqdDid,
})
this.anonCredsIssuerId = cheqdDid
break
}
this.anonCredsIssuerId = did
}

private async getConnectionRecord() {
Expand Down Expand Up @@ -149,9 +144,7 @@ export class Faber extends BaseAgent {

const { schemaState } = await this.agent.modules.anoncreds.registerSchema({
schema: schemaTemplate,
options: {
didIndyNamespace: 'bcovrin:test',
},
options: {},
})

if (schemaState.state !== 'finished') {
Expand All @@ -175,9 +168,7 @@ export class Faber extends BaseAgent {
issuerId: this.anonCredsIssuerId,
tag: 'latest',
},
options: {
didIndyNamespace: 'bcovrin:test',
},
options: {},
})

if (credentialDefinitionState.state !== 'finished') {
Expand All @@ -202,9 +193,9 @@ export class Faber extends BaseAgent {

await this.agent.credentials.offerCredential({
connectionId: connectionRecord.id,
protocolVersion: 'v1',
protocolVersion: 'v2',
credentialFormats: {
indy: {
anoncreds: {
attributes: [
{
name: 'name',
Expand Down Expand Up @@ -255,10 +246,10 @@ export class Faber extends BaseAgent {
await this.printProofFlow(greenText('\nRequesting proof...\n', false))

await this.agent.proofs.requestProof({
protocolVersion: 'v1',
protocolVersion: 'v2',
connectionId: connectionRecord.id,
proofFormats: {
indy: {
anoncreds: {
name: 'proof-request',
version: '1.0',
requested_attributes: proofAttribute,
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@
"ws": "^8.13.0"
},
"resolutions": {
"@types/node": "^16.11.7"
"@types/node": "^16.11.7",
"ref-napi": "npm:@2060.io/ref-napi"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the ref-napi trick must still be left to the CI script, right?

},
"engines": {
"node": "^16 || ^18"
}
}
}
2 changes: 1 addition & 1 deletion packages/askar/src/wallet/AskarWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,7 @@ export class AskarWallet implements Wallet {
if (!isError(error)) {
throw new AriesFrameworkError('Attempted to throw error, but it was not of type Error', { cause: error })
}
throw new WalletError(`Error signing data with verkey ${key.publicKeyBase58}`, { cause: error })
throw new WalletError(`Error signing data with verkey ${key.publicKeyBase58}. ${error.message}`, { cause: error })
}
}

Expand Down
28 changes: 22 additions & 6 deletions packages/cheqd/src/dids/CheqdDidRegistrar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import type {
DidCreateResult,
DidDeactivateResult,
DidUpdateResult,
DidDocument,
VerificationMethod,
} from '@aries-framework/core'
import type { CheqdNetwork, DIDDocument, DidStdFee, TVerificationKey, VerificationMethods } from '@cheqd/sdk'
import type { SignInfo } from '@cheqd/ts-proto/cheqd/did/v2'

import {
DidDocument,
DidDocumentRole,
DidRecord,
DidRepository,
Expand All @@ -21,6 +21,7 @@ import {
utils,
TypedArrayEncoder,
getKeyFromVerificationMethod,
JsonTransformer,
} from '@aries-framework/core'
import { MethodSpecificIdAlgo, createDidVerificationMethod } from '@cheqd/sdk'
import { MsgCreateResourcePayload } from '@cheqd/ts-proto/cheqd/resource/v2'
Expand Down Expand Up @@ -65,28 +66,43 @@ export class CheqdDidRegistrar implements DidRegistrar {
keyType: KeyType.Ed25519,
privateKey: privateKey,
})

didDocument = generateDidDoc({
verificationMethod: verificationMethod.type as VerificationMethods,
verificationMethodId: verificationMethod.id || 'key-1',
methodSpecificIdAlgo: (methodSpecificIdAlgo as MethodSpecificIdAlgo) || MethodSpecificIdAlgo.Uuid,
network: network as CheqdNetwork,
publicKey: TypedArrayEncoder.toHex(key.publicKey),
}) satisfies DidDocument
})

const contextMapping = {
Ed25519VerificationKey2018: 'https://w3id.org/security/suites/ed25519-2018/v1',
Ed25519VerificationKey2020: 'https://w3id.org/security/suites/ed25519-2020/v1',
JsonWebKey2020: 'https://w3id.org/security/suites/jws-2020/v1',
}
const contextUrl = contextMapping[verificationMethod.type]

// Add the context to the did document
// NOTE: cheqd sdk uses https://www.w3.org/ns/did/v1 while AFJ did doc uses https://w3id.org/did/v1
// We should align these at some point. For now we just return a consistent value.
didDocument.context = ['https://www.w3.org/ns/did/v1', contextUrl]
} else {
return {
didDocumentMetadata: {},
didRegistrationMetadata: {},
didState: {
state: 'failed',
reason: 'Provide a didDocument or atleast one verificationMethod with seed in secret',
reason: 'Provide a didDocument or at least one verificationMethod with seed in secret',
},
}
}

const payloadToSign = await createMsgCreateDidDocPayloadToSign(didDocument as DIDDocument, versionId)
const didDocumentJson = didDocument.toJSON() as DIDDocument

const payloadToSign = await createMsgCreateDidDocPayloadToSign(didDocumentJson, versionId)
const signInputs = await this.signPayload(agentContext, payloadToSign, didDocument.verificationMethod)

const response = await cheqdLedgerService.create(didDocument as DIDDocument, signInputs, versionId)
const response = await cheqdLedgerService.create(didDocumentJson, signInputs, versionId)
if (response.code !== 0) {
throw new Error(`${response.rawLog}`)
}
Expand Down Expand Up @@ -263,7 +279,7 @@ export class CheqdDidRegistrar implements DidRegistrar {
didState: {
state: 'finished',
did: didDocument.id,
didDocument: didDocument as DidDocument,
didDocument: JsonTransformer.fromJSON(didDocument, DidDocument),
secret: options.secret,
},
}
Expand Down
12 changes: 6 additions & 6 deletions packages/cheqd/src/dids/CheqdDidResolver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ParsedCheqdDid } from '../anoncreds/utils/identifiers'
import type { AgentContext, DidDocument, DidResolutionResult, DidResolver, ParsedDid } from '@aries-framework/core'
import type { AgentContext, DidResolutionResult, DidResolver, ParsedDid } from '@aries-framework/core'
import type { Metadata } from '@cheqd/ts-proto/cheqd/resource/v2'

import { AriesFrameworkError, utils } from '@aries-framework/core'
import { DidDocument, AriesFrameworkError, utils, JsonTransformer } from '@aries-framework/core'

import {
cheqdDidMetadataRegex,
Expand Down Expand Up @@ -132,7 +132,7 @@ export class CheqdDidResolver implements DidResolver {

const { didDocumentVersionsMetadata } = await cheqdLedgerService.resolveMetadata(did)
return {
didDocument: { id: did } as DidDocument,
didDocument: new DidDocument({ id: did }),
didDocumentMetadata: didDocumentVersionsMetadata,
didResolutionMetadata: {},
}
Expand All @@ -144,7 +144,7 @@ export class CheqdDidResolver implements DidResolver {

const metadata = await cheqdLedgerService.resolveCollectionResources(did, id)
return {
didDocument: { id: did } as DidDocument,
didDocument: new DidDocument({ id: did }),
didDocumentMetadata: {
linkedResourceMetadata: metadata,
},
Expand All @@ -168,7 +168,7 @@ export class CheqdDidResolver implements DidResolver {

const metadata = await cheqdLedgerService.resolveResourceMetadata(did, id, resourceId)
return {
didDocument: { id: did } as DidDocument,
didDocument: new DidDocument({ id: did }),
didDocumentMetadata: {
linkedResourceMetadata: metadata,
},
Expand All @@ -184,7 +184,7 @@ export class CheqdDidResolver implements DidResolver {
didDocumentMetadata.linkedResourceMetadata = resources

return {
didDocument: didDocument as DidDocument,
didDocument: JsonTransformer.fromJSON(didDocument, DidDocument),
didDocumentMetadata,
didResolutionMetadata: {},
}
Expand Down
13 changes: 9 additions & 4 deletions packages/cheqd/src/dids/didCheqdUtil.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import type { DidDocument } from '@aries-framework/core'
import type { CheqdNetwork, DIDDocument, MethodSpecificIdAlgo, TVerificationKey } from '@cheqd/sdk'
import type { Metadata } from '@cheqd/ts-proto/cheqd/resource/v2'

import { AriesFrameworkError, JsonEncoder, TypedArrayEncoder } from '@aries-framework/core'
import {
DidDocument,
AriesFrameworkError,
JsonEncoder,
TypedArrayEncoder,
JsonTransformer,
} from '@aries-framework/core'
import {
createDidPayload,
createDidVerificationMethod,
Expand Down Expand Up @@ -102,8 +107,8 @@ export function generateDidDoc(options: IDidDocOptions) {
throw new Error('Invalid DID options')
}
const verificationMethods = createDidVerificationMethod([verificationMethod], [verificationKeys])

return createDidPayload(verificationMethods, [verificationKeys]) as DidDocument
const didPayload = createDidPayload(verificationMethods, [verificationKeys])
return JsonTransformer.fromJSON(didPayload, DidDocument)
}

export interface IDidDocOptions {
Expand Down
Loading