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

asset: Updates to have a VC of Asset #196

Merged
merged 7 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 31 additions & 0 deletions demo/res/asset_vc_schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$metadata": {
"version": "1.0.0",
"slug": "asset-demo-schema",
"discoverable": true
},
"title": "Asset Demo Schema v3",
"description": "Asset Demo Schema",
"properties": {
"assetType": {
"type": "string"
},
"assetDesc": {
"type": "string"
},
"assetQty": {
"type": "integer"
},
"assetValue": {
"type": "integer"
},
"assetTag": {
"type": "string"
},
"assetMeta": {
"type": "string"
}
},
"type": "object"
}
208 changes: 163 additions & 45 deletions demo/src/asset-vc-tx.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,61 @@
import * as Cord from "@cord.network/sdk";
import { addNetworkMember } from "./utils/createAuthorities.js";
import { createAccount } from "./utils/createAccount.js";
/*
import {
buildFromAssetProperties,
failproofSubmit,
buildFromAssetIssueProperties,
buildFromAssetTransferProperties,
} from "./utils/assets.js";

import { AssetTypeOf, IAssetProperties } from "./utils/asset-types.js";
*/

import * as vcExport from "@cord.network/vc-export";
import { createDid } from "./utils/generateDid";
import PalletAssetVcAssetEntry from '@polkadot/types/lookup';

const { NETWORK_ADDRESS, ANCHOR_URI } = process.env;

import { hashToUri, uriToIdentifier } from '@cord.network/identifier'
import {
ASSET_IDENT,
ASSET_PREFIX,
AssetUri,
IAssetEntry,
DidUri,
SpaceUri,
blake2AsHex,
AccountId,
H256,
} from '@cord.network/types'
import * as Did from '@cord.network/did'
import { HexString } from "@cord.network/types";

async function buildFromAssetVcProperties(entryDigest: HexString, issuerUri: DidUri , spaceUri: SpaceUri, api: Cord.ConfigService) {
const scaleEncodedAssetDigest = api
.createType<H256>("H256", entryDigest)
.toU8a();
const scaleEncodedIssuer = api
.createType<AccountId>('AccountId', Did.toChain(issuerUri))
.toU8a()
const scaleEncodedSpace = api
.createType<AccountId>('Bytes', uriToIdentifier(spaceUri))
.toU8a()

const assetIdDigest = blake2AsHex(
Uint8Array.from([...scaleEncodedAssetDigest, ...scaleEncodedSpace, ...scaleEncodedIssuer])
);

const assetIdentifier = hashToUri(
assetIdDigest,
ASSET_IDENT,
ASSET_PREFIX
) as AssetUri;

const transformedEntry: IAssetEntry = {
creator: issuerUri,
space: spaceUri,
digest: entryDigest,
uri: assetIdentifier,
};

return transformedEntry;
}

async function main() {
const networkAddress = NETWORK_ADDRESS ?? 'ws://127.0.0.1:9944';
const networkAddress = NETWORK_ADDRESS ?? 'ws://127.0.0.1:63214';
const anchorUri = ANCHOR_URI ?? '//Alice';

// Temporarily suppress console.log
Expand All @@ -41,7 +80,7 @@ async function main() {
await addNetworkMember(networkAuthorityIdentity, authorIdentity.address)

// const { account: issuerIdentity } = createAccount();
// Create issuer DID
// Create issuer DID
const { mnemonic: issuerMnemonic, document: issuerDid } = await createDid(
networkAuthorityIdentity
)
Expand Down Expand Up @@ -71,7 +110,7 @@ async function main() {
await addNetworkMember(networkAuthorityIdentity, apiIdentity.address);
console.log("✅ Identities created!");

// Step 3: Create a new Chain Space
// Step 2: Create a new Chain Space
console.log(`\n❄️ Chain Space Creation `)
const spaceProperties = await Cord.ChainSpace.buildFromProperties(
issuerDid.uri
Expand All @@ -81,15 +120,17 @@ async function main() {
colors: true,
})

let extSignCallback = async ({ data }) => ({
signature: issuerKeys.authentication.sign(data),
keyType: issuerKeys.authentication.type,
})

console.log(`\n❄️ Chain Space Properties `)
const space = await Cord.ChainSpace.dispatchToChain(
spaceProperties,
issuerDid.uri,
authorIdentity,
async ({ data }) => ({
signature: issuerKeys.authentication.sign(data),
keyType: issuerKeys.authentication.type,
})
extSignCallback,
)
console.dir(space, {
depth: null,
Expand All @@ -103,9 +144,34 @@ async function main() {
space.uri,
100
)
console.log(`✅ Chain Space Approved`)
console.log(`✅ Chain Space Approved`)

// Step 3: Dispatch creation of asset schema to chain.
let newSchemaContent = require('../res/asset_vc_schema.json');
let newSchemaName =
newSchemaContent.title + ':' + Cord.Utils.UUID.generate();
newSchemaContent.title = newSchemaName;

let schemaProperties = Cord.Schema.buildFromProperties(
newSchemaContent,
space.uri,
issuerDid.uri,
);

// Step 2: Create assets on-chain
const schemaUri = await Cord.Schema.dispatchToChain(
schemaProperties.schema,
issuerDid.uri,
authorIdentity,
space.authorization,
async ({ data }) => ({
signature: issuerKeys.authentication.sign(data),
keyType: issuerKeys.authentication.type,
}),
);

console.log(`✅ Schema - ${schemaUri} - added!`);

// Step 4: Create assets off-chain
let assetProperties: Cord.IAssetProperties = {
assetType: Cord.AssetTypeOf.art,
assetDesc: "Asset - " + Cord.Utils.UUID.generate(),
Expand All @@ -121,37 +187,71 @@ async function main() {
colors: true,
});

const assetEntry = await Cord.Asset.buildFromAssetProperties(
assetProperties,
issuerDid.uri,
space.uri,
);
// Step 5: Delegate(Asset Owner/Issuer) creates a new Verifiable Document
console.log(`\n❄️ VC Asset Creation `);

console.log(`\n❄️ Asset Transaction - Created by Issuer `);
console.dir(assetEntry, {
depth: null,
colors: true,
});
let newCredContent = await vcExport.buildVcFromContent(
schemaProperties.schema,
assetProperties,
issuerDid,
issuerDid.uri,
{
spaceUri: space.uri,
schemaUri: schemaUri,
},
);
/* TODO: Fix addProof dependency issue by implementing the methods requiring api locally */
// let vc = await vcExport.addProof(
// newCredContent,
// async (data) => ({
// signature: await issuerKeys.assertionMethod.sign(data),
// keyType: issuerKeys.assertionMethod.type,
// keyUri: `${issuerDid.uri}${
// issuerDid.assertionMethod![0].id
// }` as Cord.DidResourceUri,
// }),
// issuerDid,
// { spaceUri: space.uri, schemaUri, needSDR: false, needStatementProof: false },
// );
// console.dir(vc, {
// depth: null,
// colors: true,
// });

const assetVcEntry = await buildFromAssetVcProperties(newCredContent.credentialHash, issuerDid.uri, space.uri, api);
newCredContent.id = assetVcEntry.uri;
console.log("\n❄️ Asset(create) Verifiable Credential Document created \n", newCredContent);

const extrinsic = await Cord.Asset.dispatchCreateVcToChain(
assetProperties.assetQty,
assetEntry.digest,
assetEntry.creator,
newCredContent.credentialHash,
newCredContent.issuer,
networkAuthorityIdentity,
space.authorization,
assetEntry.uri,
async ({ data }) => ({
signature: issuerKeys.authentication.sign(data),
keyType: issuerKeys.authentication.type,
}),
assetVcEntry.uri,
extSignCallback,
)
console.log("\n✅ VC Asset created on-chain!");

console.log("✅ Asset created!");
// Update the assetProperties with number of quantity of asset issued.
let issuanceQty = 1;
assetProperties.assetQty = issuanceQty;

let newIssueCredContent = await vcExport.buildVcFromContent(
schemaProperties.schema,
assetProperties,
issuerDid,
holderDid.uri,
{
spaceUri: space.uri,
schemaUri: schemaUri,
},
);

// Step 3: Issue Asset to Holder
// Step 6: Issue Asset to Holder
console.log(`\n❄️ Issue Asset to Holder - Issuer Action `);
const assetIssuance = await Cord.Asset.buildFromIssueProperties(
assetEntry.uri,
assetVcEntry.uri,
holderDid.uri,
1,
issuerDid.uri,
Expand All @@ -163,18 +263,36 @@ async function main() {
colors: true,
});

// Asset Issue ID consists of both asset_id:instance_id
newIssueCredContent.id = assetIssuance.uri;
console.log("\n❄️ Asset(issue) Verifiable Credential Document created \n", newIssueCredContent);

const issueExtrinsic = await Cord.Asset.dispatchIssueVcToChain(
assetIssuance,
networkAuthorityIdentity,
space.authorization,
async ({ data }) => ({
signature: issuerKeys.authentication.sign(data),
keyType: issuerKeys.authentication.type,
}),
extSignCallback,
)

// Step 4: Transfer Asset to New Owner
// Step 7: Transfer Asset to New Owner
console.log(`\n❄️ Transfer Asset to New Owner (Holder2) - Holder Action `);

// Should we create new assetProperties, or just update the qutantity(being issued)
assetProperties.assetQty = issuanceQty;
let newTransferCredContent = await vcExport.buildVcFromContent(
schemaProperties.schema,
assetProperties,
holderDid,
holder2Did.uri,
{
spaceUri: space.uri,
schemaUri: schemaUri,
},
);

// Asset Issue ID consists of both asset_id:instance_id
newTransferCredContent.id = assetIssuance.uri;
console.log("\n❄️ Asset(transfer) Verifiable Credential Document created \n", newTransferCredContent);

const assetTransfer = await Cord.Asset.buildFromTransferProperties(
assetIssuance.uri,
Expand All @@ -196,7 +314,7 @@ async function main() {
}),
)

console.log("✅ Asset transferred!");
console.log("✅ Asset transferred!");
}
main()
.then(() => console.log("\nBye! 👋 👋 👋 "))
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"@babel/preset-env": "^7.23.9",
"@commitlint/cli": "^9.1.2",
"@commitlint/config-conventional": "^9.1.2",
"@cord.network/vc-export": "0.9.3-1rc12",
"@playwright/test": "^1.41.2",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.6",
Expand Down
Loading