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

feat!: On track with v1 on-ledger release #115

Merged
merged 2 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 10 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"homepage": "https://github.com/cheqd/sdk#readme",
"dependencies": {
"@cheqd/ts-proto": "^1.0.16-develop.3",
"@cheqd/ts-proto": "^2.0.0-develop.1",
"@cosmjs/amino": "^0.29.4",
"@cosmjs/encoding": "^0.29.4",
"@cosmjs/math": "^0.29.4",
Expand All @@ -37,6 +37,7 @@
"@stablelib/ed25519": "^1.0.3",
"cosmjs-types": "^0.5.2",
"did-jwt": "^6.9.0",
"did-resolver": "^4.0.1",
"multiformats": "^9.9.0",
"uuid": "^9.0.0"
},
Expand Down
7 changes: 5 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { createDefaultCheqdRegistry } from './registry'
import { CheqdSigningStargateClient } from './signer'
import { CheqdNetwork, IContext, IModuleMethodMap } from './types'
import { createSignInputsFromImportableEd25519Key } from './utils'
import { GasPrice } from '@cosmjs/stargate'

export interface ICheqdSDKOptions {
modules: AbstractCheqdSDKModule[]
authorizedMethods?: string[]
network?: CheqdNetwork
rpcUrl: string
network?: CheqdNetwork
gasPrice?: GasPrice
authorizedMethods?: string[]
readonly wallet: OfflineSigner
}

Expand Down Expand Up @@ -78,6 +80,7 @@ export class CheqdSDK {
this.options.wallet,
{
registry,
gasPrice: this.options?.gasPrice,
}
)

Expand Down
205 changes: 189 additions & 16 deletions src/modules/did.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,41 @@ import { createProtobufRpcClient, DeliverTxResponse, QueryClient } from "@cosmjs
/* import { QueryClientImpl } from '@cheqd/ts-proto/cheqd/did/v1/query' */
import { CheqdExtension, AbstractCheqdSDKModule, MinimalImportableCheqdSDKModule } from "./_"
import { CheqdSigningStargateClient } from "../signer"
import { DidStdFee, IContext, ISignInputs, MsgCreateDidPayload, MsgDeactivateDidPayload, MsgUpdateDidPayload, VerificationMethodPayload } from "../types"
import { DIDDocument, DidStdFee, IContext, ISignInputs, SpecValidationResult, VerificationMethods } from '../types';
import {
MsgCreateDidDoc,
MsgCreateDidDocPayload,
MsgCreateDidDocResponse,
MsgDeactivateDidDoc,
MsgDeactivateDidDocPayload,
MsgDeactivateDidDocResponse,
MsgUpdateDidDoc,
MsgUpdateDidDocPayload,
MsgUpdateDidDocResponse,
protobufPackage,
SignInfo
Service,
SignInfo,
VerificationMethod
} from "@cheqd/ts-proto/cheqd/did/v2"
import { EncodeObject, GeneratedType } from "@cosmjs/proto-signing"

export const typeUrlMsgCreateDidDoc = `/${protobufPackage}.MsgCreateDidDoc`
export const typeUrlMsgCreateDidDocResponse = `/${protobufPackage}.MsgCreateDidDocResponse`
export const typeUrlMsgUpdateDidDoc = `/${protobufPackage}.MsgUpdateDidDoc`
export const typeUrlMsgUpdateDidDocResponse = `/${protobufPackage}.MsgUpdateDidDocResponse`
export const typeUrlMsgDeactivateDidDoc = `/${protobufPackage}.MsgDeactivateDidDoc`
export const typeUrlMsgDeactivateDidDocResponse = `/${protobufPackage}.MsgDeactivateDidDocResponse`
import { v4 } from "uuid"
import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin";
import { Int53 } from "@cosmjs/math";

export const protobufLiterals = {
MsgCreateDidDoc: "MsgCreateDidDoc",
MsgCreateDidDocResponse: "MsgCreateDidDocResponse",
MsgUpdateDidDoc: "MsgUpdateDidDoc",
MsgUpdateDidDocResponse: "MsgUpdateDidDocResponse",
MsgDeactivateDidDoc: "MsgDeactivateDidDoc",
MsgDeactivateDidDocResponse: "MsgDeactivateDidDocResponse",
} as const
export const typeUrlMsgCreateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgCreateDidDoc}`
export const typeUrlMsgCreateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgCreateDidDocResponse}`
export const typeUrlMsgUpdateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgUpdateDidDoc}`
export const typeUrlMsgUpdateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgUpdateDidDocResponse}`
export const typeUrlMsgDeactivateDidDoc = `/${protobufPackage}.${protobufLiterals.MsgDeactivateDidDoc}`
export const typeUrlMsgDeactivateDidDocResponse = `/${protobufPackage}.${protobufLiterals.MsgDeactivateDidDocResponse}`

export interface MsgCreateDidDocEncodeObject extends EncodeObject {
readonly typeUrl: typeof typeUrlMsgCreateDidDoc,
Expand Down Expand Up @@ -87,6 +102,14 @@ export class DIDModule extends AbstractCheqdSDKModule {
[typeUrlMsgDeactivateDidDocResponse, MsgDeactivateDidDocResponse],
]

static readonly baseMinimalDenom = 'ncheq' as const

static readonly fees = {
DefaultCreateDidFee: { amount: '50000000000', denom: DIDModule.baseMinimalDenom } as const,
DefaultUpdateDidFee: { amount: '25000000000', denom: DIDModule.baseMinimalDenom } as const,
DefaultDeactivateDidFee: { amount: '10000000000', denom: DIDModule.baseMinimalDenom } as const,
} as const

constructor(signer: CheqdSigningStargateClient) {
super(signer)
this.methods = {
Expand All @@ -100,12 +123,36 @@ export class DIDModule extends AbstractCheqdSDKModule {
return DIDModule.registryTypes
}

async createDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: Partial<MsgCreateDidPayload>, address: string, fee: DidStdFee | 'auto' | number, memo?: string, context?: IContext): Promise<DeliverTxResponse> {
async createDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: DIDDocument, address: string, fee: DidStdFee | 'auto' | number, memo?: string, versionId?: string, context?: IContext): Promise<DeliverTxResponse> {
if (!this._signer) {
this._signer = context!.sdk!.signer
}

const payload = MsgCreateDidPayload.transformPayload(didPayload)
if (!versionId || versionId === '') {
versionId = v4()
}

const { valid, error, protobufVerificationMethod, protobufService } = await DIDModule.validateSpecCompliantPayload(didPayload)

if (!valid) {
throw new Error(`DID payload is not spec compliant: ${error}`)
}

const payload = MsgCreateDidDocPayload.fromPartial({
context: <string[]>didPayload?.['@context'],
id: didPayload.id,
controller: <string[]>didPayload.controller,
verificationMethod: protobufVerificationMethod,
authentication: <string[]>didPayload.authentication,
assertionMethod: <string[]>didPayload.assertionMethod,
capabilityInvocation: <string[]>didPayload.capabilityInvocation,
capabilityDelegation: <string[]>didPayload.capabilityDelegation,
keyAgreement: <string[]>didPayload.keyAgreement,
service: protobufService,
alsoKnownAs: <string[]>didPayload.alsoKnownAs,
versionId: versionId
})

let signatures: SignInfo[]
if(ISignInputs.isSignInput(signInputs)) {
signatures = await this._signer.signCreateDidTx(signInputs, payload)
Expand All @@ -131,12 +178,35 @@ export class DIDModule extends AbstractCheqdSDKModule {
)
}

async updateDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: Partial<MsgUpdateDidPayload>, address: string, fee: DidStdFee | 'auto' | number, memo?: string, context?: IContext): Promise<DeliverTxResponse> {
async updateDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: DIDDocument, address: string, fee: DidStdFee | 'auto' | number, memo?: string, versionId?: string, context?: IContext): Promise<DeliverTxResponse> {
if (!this._signer) {
this._signer = context!.sdk!.signer
}

const payload = MsgCreateDidPayload.transformPayload(didPayload)
if (!versionId || versionId === '') {
versionId = v4()
}

const { valid, error, protobufVerificationMethod, protobufService } = await DIDModule.validateSpecCompliantPayload(didPayload)

if (!valid) {
throw new Error(`DID payload is not spec compliant: ${error}`)
}

const payload = MsgUpdateDidDocPayload.fromPartial({
context: <string[]>didPayload?.['@context'],
id: didPayload.id,
controller: <string[]>didPayload.controller,
verificationMethod: protobufVerificationMethod,
authentication: <string[]>didPayload.authentication,
assertionMethod: <string[]>didPayload.assertionMethod,
capabilityInvocation: <string[]>didPayload.capabilityInvocation,
capabilityDelegation: <string[]>didPayload.capabilityDelegation,
keyAgreement: <string[]>didPayload.keyAgreement,
service: protobufService,
alsoKnownAs: <string[]>didPayload.alsoKnownAs,
versionId: versionId
})
let signatures: SignInfo[]
if(ISignInputs.isSignInput(signInputs)) {
signatures = await this._signer.signUpdateDidTx(signInputs, payload)
Expand All @@ -162,15 +232,29 @@ export class DIDModule extends AbstractCheqdSDKModule {
)
}

async deactivateDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: MsgDeactivateDidPayload, address: string, fee: DidStdFee | 'auto' | number, memo?: string, context?: IContext): Promise<DeliverTxResponse> {
async deactivateDidTx(signInputs: ISignInputs[] | SignInfo[], didPayload: DIDDocument, address: string, fee: DidStdFee | 'auto' | number, memo?: string, versionId?: string, context?: IContext): Promise<DeliverTxResponse> {
if (!this._signer) {
this._signer = context!.sdk!.signer
}

const payload = MsgDeactivateDidDocPayload.fromPartial({id: didPayload.id, versionId: didPayload.versionId})
if (!versionId || versionId === '') {
versionId = v4()
}

const { valid, error, protobufVerificationMethod } = await DIDModule.validateSpecCompliantPayload(didPayload)

if (!valid) {
throw new Error(`DID payload is not spec compliant: ${error}`)
}

const payload = MsgDeactivateDidDocPayload.fromPartial({
id: didPayload.id,
versionId: versionId
})

let signatures: SignInfo[]
if(ISignInputs.isSignInput(signInputs)) {
signatures = await this._signer.signDeactivateDidTx(signInputs, payload, didPayload.verificationMethod.map((e)=>VerificationMethodPayload.transformPayload(e)))
signatures = await this._signer.signDeactivateDidTx(signInputs, payload, protobufVerificationMethod!)
} else {
signatures = signInputs
}
Expand All @@ -192,6 +276,95 @@ export class DIDModule extends AbstractCheqdSDKModule {
memo
)
}

static async validateSpecCompliantPayload(didDocument: DIDDocument): Promise<SpecValidationResult> {
// id is required, validated on both compile and runtime
if (!didDocument?.id) return { valid: false, error: 'id is required' }

// verificationMethod is required
if (!didDocument?.verificationMethod) return { valid: false, error: 'verificationMethod is required' }

// verificationMethod must be an array
if (!Array.isArray(didDocument?.verificationMethod)) return { valid: false, error: 'verificationMethod must be an array' }

// verificationMethod types must be supported
const protoVerificationMethod = didDocument.verificationMethod.map((vm) => {
switch (vm?.type) {
case VerificationMethods.Ed255192020:
if (!vm?.publicKeyMultibase) throw new Error('publicKeyMultibase is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.Ed255192020,
verificationMaterial: vm.publicKeyMultibase,
})
case VerificationMethods.JWK:
if (!vm?.publicKeyJwk) throw new Error('publicKeyJwk is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.JWK,
verificationMaterial: JSON.stringify(vm.publicKeyJwk),
})
case VerificationMethods.Ed255192018:
if (!vm?.publicKeyBase58) throw new Error('publicKeyBase58 is required')

return VerificationMethod.fromPartial({
id: vm.id,
controller: vm.controller,
verificationMethodType: VerificationMethods.Ed255192018,
verificationMaterial: vm.publicKeyBase58,
})
default:
throw new Error('Unsupported verificationMethod type')
}
})

const protoService = didDocument?.service?.map((s) => {
return Service.fromPartial({
id: s?.id,
serviceType: s?.type,
serviceEndpoint: <string[]>s?.serviceEndpoint,
})
})

return { valid: true, protobufVerificationMethod: protoVerificationMethod, protobufService: protoService } as SpecValidationResult
}

static async generateCreateDidDocFees(feePayer: string, granter?: string): Promise<DidStdFee> {
return {
amount: [
DIDModule.fees.DefaultCreateDidFee
],
gas: '360000',
payer: feePayer,
granter: granter
} as DidStdFee
}

static async generateUpdateDidDocFees(feePayer: string, granter?: string): Promise<DidStdFee> {
return {
amount: [
DIDModule.fees.DefaultUpdateDidFee
],
gas: '360000',
payer: feePayer,
granter: granter
} as DidStdFee
}

static async generateDeactivateDidDocFees(feePayer: string, granter?: string): Promise<DidStdFee> {
return {
amount: [
DIDModule.fees.DefaultDeactivateDidFee
],
gas: '360000',
payer: feePayer,
granter: granter
} as DidStdFee
}
}

export type MinimalImportableDIDModule = MinimalImportableCheqdSDKModule<DIDModule>
Expand Down
Loading