generated from cheqd/.github
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Resources support [DEV-1616] (#18)
- Loading branch information
Showing
9 changed files
with
263 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { AbstractCheqdSDKModule, MinimalImportableCheqdSDKModule } from "./_" | ||
import { CheqdSigningStargateClient } from "../signer" | ||
import { EncodeObject, GeneratedType } from "@cosmjs/proto-signing" | ||
import { DidStdFee, IContext, ISignInputs } from '../types'; | ||
import { MsgCreateResource, MsgCreateResourcePayload, MsgCreateResourceResponse, protobufPackage } from "@cheqd/ts-proto/resource/v1/tx" | ||
import { DeliverTxResponse } from "@cosmjs/stargate" | ||
import { Writer } from "protobufjs" | ||
|
||
export const typeUrlMsgCreateResource = `/${protobufPackage}.MsgCreateResource` | ||
export const typeUrlMsgCreateResourceResponse = `/${protobufPackage}.MsgCreateResourceResponse` | ||
|
||
export interface MsgCreateResourceEncodeObject extends EncodeObject { | ||
readonly typeUrl: typeof typeUrlMsgCreateResource, | ||
readonly value: Partial<MsgCreateResource> | ||
} | ||
|
||
export function isMsgCreateResourceEncodeObject(obj: EncodeObject): obj is MsgCreateResourceEncodeObject { | ||
return obj.typeUrl === typeUrlMsgCreateResource | ||
} | ||
|
||
export class ResourceModule extends AbstractCheqdSDKModule { | ||
static readonly registryTypes: Iterable<[string, GeneratedType]> = [ | ||
[typeUrlMsgCreateResource, MsgCreateResource], | ||
[typeUrlMsgCreateResourceResponse, MsgCreateResourceResponse] | ||
] | ||
|
||
constructor(signer: CheqdSigningStargateClient) { | ||
super(signer) | ||
this.methods = { | ||
createResourceTx: this.createResourceTx.bind(this) | ||
} | ||
} | ||
|
||
public getRegistryTypes(): Iterable<[string, GeneratedType]> { | ||
return [] | ||
} | ||
|
||
// We need this workagound because amino encoding is used in cheqd-node to derive sign bytes for identity messages. | ||
// In most cases it works the same way as protobuf encoding, but in the MsgCreateResourcePayload | ||
// we use non-default property indexes so we need this separate encoding function. | ||
// TODO: Remove this workaround when cheqd-node will use protobuf encoding. | ||
static getMsgCreateResourcePayloadAminoSignBytes(message: MsgCreateResourcePayload): Uint8Array { | ||
const writer = new Writer(); | ||
|
||
if (message.collectionId !== "") { | ||
writer.uint32(10).string(message.collectionId); | ||
} | ||
if (message.id !== "") { | ||
writer.uint32(18).string(message.id); | ||
} | ||
if (message.name !== "") { | ||
writer.uint32(26).string(message.name); | ||
} | ||
if (message.resourceType !== "") { | ||
writer.uint32(34).string(message.resourceType); | ||
} | ||
if (message.data.length !== 0) { | ||
// Animo coded assigns index 5 to this property. In proto definitions it's 6. | ||
// Since we use amino on node + non default property indexing, we need to encode it manually. | ||
writer.uint32(42).bytes(message.data); | ||
} | ||
|
||
return writer.finish(); | ||
} | ||
|
||
static async signPayload(payload: MsgCreateResourcePayload, signInputs: ISignInputs[]): Promise<MsgCreateResource> { | ||
const signBytes = ResourceModule.getMsgCreateResourcePayloadAminoSignBytes(payload) | ||
const signatures = await CheqdSigningStargateClient.signIdentityTx(signBytes, signInputs) | ||
|
||
return { | ||
payload, | ||
signatures | ||
} | ||
} | ||
|
||
async createResourceTx(signInputs: ISignInputs[], resourcePayload: Partial<MsgCreateResourcePayload>, address: string, fee: DidStdFee | 'auto' | number, memo?: string, context?: IContext): Promise<DeliverTxResponse> { | ||
if (!this._signer) { | ||
this._signer = context!.sdk!.signer | ||
} | ||
|
||
const payload = MsgCreateResourcePayload.fromPartial(resourcePayload) | ||
|
||
const msg = await ResourceModule.signPayload(payload, signInputs) | ||
|
||
const encObj: MsgCreateResourceEncodeObject = { | ||
typeUrl: typeUrlMsgCreateResource, | ||
value: msg | ||
} | ||
|
||
return this._signer.signAndBroadcast( | ||
address, | ||
[encObj], | ||
fee, | ||
memo | ||
) | ||
} | ||
} | ||
|
||
export type MinimalImportableResourcesModule = MinimalImportableCheqdSDKModule<ResourceModule> |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { DirectSecp256k1HdWallet, GeneratedType } from "@cosmjs/proto-signing" | ||
import { DeliverTxResponse } from "@cosmjs/stargate" | ||
import { sign } from "@stablelib/ed25519" | ||
import { fromString, toString } from 'uint8arrays' | ||
import { DIDModule, ResourceModule } from "../../src" | ||
import { createDefaultCheqdRegistry } from "../../src/registry" | ||
import { CheqdSigningStargateClient } from "../../src/signer" | ||
import { DidStdFee, ISignInputs, MethodSpecificIdAlgo, VerificationMethods } from '../../src/types'; | ||
import { createDidPayload, createDidVerificationMethod, createKeyPairBase64, createVerificationKeys, exampleCheqdNetwork, faucet } from "../testutils.test" | ||
import { MsgCreateResourcePayload } from '@cheqd/ts-proto/resource/v1/tx'; | ||
import { randomUUID } from "crypto" | ||
|
||
const defaultAsyncTxTimeout = 20000 | ||
|
||
describe('ResourceModule', () => { | ||
describe('constructor', () => { | ||
it('should instantiate standalone module', async () => { | ||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic) | ||
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet) | ||
const resourceModule = new ResourceModule(signer) | ||
expect(resourceModule).toBeInstanceOf(ResourceModule) | ||
}) | ||
}) | ||
|
||
describe('createResourceTx', () => { | ||
it('should create a new Resource', async () => { | ||
// Creating a DID | ||
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic, {prefix: faucet.prefix}) | ||
|
||
const registry = createDefaultCheqdRegistry(Array.from(DIDModule.registryTypes).concat(Array.from(ResourceModule.registryTypes))) | ||
|
||
const signer = await CheqdSigningStargateClient.connectWithSigner(exampleCheqdNetwork.rpcUrl, wallet, { registry }) | ||
|
||
const didModule = new DIDModule(signer) | ||
|
||
const keyPair = createKeyPairBase64() | ||
const verificationKeys = createVerificationKeys(keyPair, MethodSpecificIdAlgo.Base58, 'key-1', 16) | ||
const verificationMethods = createDidVerificationMethod([VerificationMethods.Base58], [verificationKeys]) | ||
const didPayload = createDidPayload(verificationMethods, [verificationKeys]) | ||
|
||
const signInputs: ISignInputs[] = [ | ||
{ | ||
verificationMethodId: didPayload.verificationMethod[0].id, | ||
privateKeyHex: toString(fromString(keyPair.privateKey, 'base64'), 'hex') | ||
} | ||
] | ||
|
||
const fee: DidStdFee = { | ||
amount: [ | ||
{ | ||
denom: 'ncheq', | ||
amount: '50000000' | ||
} | ||
], | ||
gas: '1000000', | ||
payer: (await wallet.getAccounts())[0].address | ||
} | ||
|
||
const didTx: DeliverTxResponse = await didModule.createDidTx( | ||
signInputs, | ||
didPayload, | ||
(await wallet.getAccounts())[0].address, | ||
fee | ||
) | ||
|
||
console.warn(`Using payload: ${JSON.stringify(didPayload)}`) | ||
console.warn(`DID Tx: ${JSON.stringify(didTx)}`) | ||
|
||
expect(didTx.code).toBe(0) | ||
|
||
// Creating a resource | ||
|
||
const resourceModule = new ResourceModule(signer) | ||
|
||
const resourcePayload: MsgCreateResourcePayload = { | ||
collectionId: didPayload.id.split(":").reverse()[0], | ||
id: randomUUID(), | ||
name: 'Test Resource', | ||
resourceType: 'test-resource-type', | ||
data: new TextEncoder().encode("{ \"message\": \"hello world\"}") | ||
} | ||
|
||
console.warn(`Using payload: ${JSON.stringify(resourcePayload)}`) | ||
|
||
const resourceSignInputs: ISignInputs[] = [ | ||
{ | ||
verificationMethodId: didPayload.verificationMethod[0].id, | ||
keyType: 'Ed25519', | ||
privateKeyHex: toString(fromString(keyPair.privateKey, 'base64'), 'hex') | ||
} | ||
] | ||
|
||
const resourceTx = await resourceModule.createResourceTx( | ||
resourceSignInputs, | ||
resourcePayload, | ||
(await wallet.getAccounts())[0].address, | ||
fee | ||
) | ||
|
||
console.warn(`DID Tx: ${JSON.stringify(resourceTx)}`) | ||
|
||
expect(resourceTx.code).toBe(0) | ||
}, defaultAsyncTxTimeout) | ||
}) | ||
}) |