Skip to content

Commit

Permalink
fix: small updates to cheqd module and demo (#1439)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed May 8, 2023
1 parent 4145957 commit 61daf0c
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 198 deletions.
22 changes: 18 additions & 4 deletions 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,20 @@ 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.

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

If you want to run tests without the cheqd ledger, you can use the following ignore pattern:

```sh
yarn test --testPathIgnorePatterns packages/cheqd
```

### Run all tests

You can run the tests using the following command.
Expand All @@ -91,13 +105,13 @@ GENESIS_TXN_PATH=network/genesis/local-genesis.txn TEST_AGENT_PUBLIC_DID_SEED=00
Locally, you might want to run the tests without postgres tests. You can do that by ignoring the tests:

```sh
yarn test --testPathIgnorePatterns ./packages/indy-sdk/tests/postgres.e2e.test.ts -u
yarn test --testPathIgnorePatterns postgres.e2e.test.ts
```

In case you run into trouble running the tests, e.g. complaining about snapshots not being up-to-date, you can try and remove the data stored for the indy-client. On a Unix system with default setup you achieve this by running:
In case you run into trouble running the tests, e.g. complaining about snapshots not being up-to-date, you can try and remove the data stored for the indy-client or AFJ. Note this removes all wallets and data, so make sure you're okay with all data being removed. On a Unix system with default setup you achieve this by running:

```sh
rm -rf ~/.indy-client
rm -rf ~/.indy-client ~/.afj
```

## Usage with Docker
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
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

0 comments on commit 61daf0c

Please sign in to comment.