Skip to content

Commit

Permalink
Add score module to sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
adi-a11y committed Oct 9, 2023
1 parent 2153124 commit fcd469d
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 82 deletions.
203 changes: 137 additions & 66 deletions demo/src/demo-score.ts
Original file line number Diff line number Diff line change
@@ -1,93 +1,164 @@
import * as Cord from '@cord.network/sdk'
import { ScoreType } from '@cord.network/types'
import { UUID } from '@cord.network/utils'
import { UUID, Crypto } from '@cord.network/utils'
import { generateKeypairs } from './utils/generateKeypairs'
import { createDid } from './utils/generateDid'
import { addRegistryAdminDelegate } from './utils/generateRegistry'
import { randomUUID } from 'crypto'
import { addAuthority } from './utils/createAuthorities'
import { createAccount } from './utils/createAccount'
import { updateScore } from './utils/updateScore'
import { ScoreType, IJournalContent, EntryType } from '@cord.network/types'

async function main() {
await Cord.init({ address: 'ws://127.0.0.1:9944' })

// Step 1: Setup Org Identity
console.log(`\n❄️ Demo Identities (KeyRing)`)
//3x4DHc1rxVAEqKWSx1DAAA8wZxLB4VhiRbMV997niBckUwSi
const sellerIdentity = Cord.Identity.buildFromURI('//Entity', {
signingKeyPairType: 'sr25519',
})
console.log(
`🏛 Seller Entity (${sellerIdentity.signingKeyType}): ${sellerIdentity.address}`
const networkAddress = 'ws://127.0.0.1:63554'
Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK })
await Cord.connect(networkAddress)

const api = Cord.ConfigService.get('api')

console.log(`\n❄️ New Member`)
const authorityAuthorIdentity = Crypto.makeKeypairFromUri(
'//Alice',
'sr25519'
)
// Setup author authority account.
const { account: authorIdentity } = await createAccount()
console.log(`🏦 Member (${authorIdentity.type}): ${authorIdentity.address}`)
await addAuthority(authorityAuthorIdentity, authorIdentity.address)
console.log(`🔏 Member permissions updated`)
console.log('✅ Network Member added!')

// Step 2: Setup Identities
console.log(`\n❄️ Demo Identities (KeyRing)`)
const { mnemonic: issuerMnemonic, document: issuerDid } = await createDid(
authorIdentity
)
const deliveryIdentity = Cord.Identity.buildFromURI('//Delivery', {
signingKeyPairType: 'sr25519',
})
const issuerKeys = generateKeypairs(issuerMnemonic)
console.log(
`🏛 Delivery Entity (${deliveryIdentity.signingKeyType}): ${deliveryIdentity.address}`
`🏛 Issuer (${issuerDid?.assertionMethod![0].type}): ${issuerDid.uri}`
)
const collectorIdentity = Cord.Identity.buildFromURI('//BuyerApp', {
signingKeyPairType: 'ed25519',
})

// Create Delegate One DID
const { mnemonic: delegateOneMnemonic, document: delegateOneDid } =
await createDid(authorIdentity)

const delegateOneKeys = generateKeypairs(delegateOneMnemonic)

console.log(
`🧑🏻‍💼 Score Collector (${collectorIdentity.signingKeyType}): ${collectorIdentity.address}`
`🏛 Delegate (${delegateOneDid?.assertionMethod![0].type}): ${
delegateOneDid.uri
}`
)
const requestorIdentity = Cord.Identity.buildFromURI('//SellerApp', {
signingKeyPairType: 'ed25519',
})

console.log('✅ Identities created!')

// Entities
console.log(`\n❄️ Demo Entities`)
const sellerIdentity = Crypto.makeKeypairFromUri('//Entity', 'sr25519')
console.log(
`👩‍⚕️ Score Requestor (${requestorIdentity.signingKeyType}): ${requestorIdentity.address}`
`🏛 Seller Entity (${sellerIdentity.type}): ${sellerIdentity.address}`
)
await addAuthority(authorityAuthorIdentity, sellerIdentity.address)

const { mnemonic: sellerMnemonic, document: sellerDid } = await createDid(
sellerIdentity
)
const transactionAuthor = Cord.Identity.buildFromURI('//Bob', {
signingKeyPairType: 'sr25519',
})

const collectorIdentity = Crypto.makeKeypairFromUri('//BuyerApp', 'sr25519')
console.log(
`🏢 Transaction Author (${transactionAuthor.signingKeyType}): ${transactionAuthor.address}`
`🧑🏻‍💼 Score Collector (${collectorIdentity.type}): ${collectorIdentity.address}`
)
console.log('✅ Identities created!')
await addAuthority(authorityAuthorIdentity, collectorIdentity.address)

// Step 2: Create a jounal entry
console.log(`\n❄️ Journal Entry `)
let journalContent = {
entity: sellerIdentity.address,
uid: UUID.generate().toString(),
tid: UUID.generate().toString(),
collector: collectorIdentity.address,
requestor: requestorIdentity.address,
scoreType: ScoreType.overall,
score: 3.7,
const { mnemonic: collectorMnemonic, document: collectorDid } =
await createDid(collectorIdentity)

console.log('✅ Entities created!')

console.log(`\n❄️ Registry Creation `)

const registryTitle = `Registry v3.${randomUUID().substring(0, 4)}`
const registryDetails: Cord.IContents = {
title: registryTitle,
description: 'Registry for for scoring',
}
console.dir(journalContent, { depth: null, colors: true })

let newJournalEntry = Cord.Score.fromJournalProperties(
journalContent,
sellerIdentity
)
const registryType: Cord.IRegistryType = {
details: registryDetails,
creator: issuerDid.uri,
}

let journalCreationExtrinsic = await Cord.Score.entries(newJournalEntry)
console.log(`\n❄️ Transformed Journal Entry `)
console.dir(newJournalEntry, { depth: null, colors: true })
const txRegistry: Cord.IRegistry =
Cord.Registry.fromRegistryProperties(registryType)

let registry
try {
await Cord.Chain.signAndSubmitTx(
journalCreationExtrinsic,
transactionAuthor,
{
resolveOn: Cord.Chain.IS_IN_BLOCK,
rejectOn: Cord.Chain.IS_ERROR,
}
await Cord.Registry.verifyStored(txRegistry)
console.log('Registry already stored. Skipping creation')
} catch {
console.log('Regisrty not present. Creating it now...')
// Authorize the tx.
const tx = api.tx.registry.create(txRegistry.details, null)
const extrinsic = await Cord.Did.authorizeTx(
issuerDid.uri,
tx,
async ({ data }) => ({
signature: issuerKeys.assertionMethod.sign(data),
keyType: issuerKeys.assertionMethod.type,
}),
authorIdentity.address
)
console.log('✅ Journal Entry added!')
} catch (e: any) {
console.log(e.errorCode, '-', e.message)
console.log('\n', txRegistry)
// Write to chain then return the Schema.
await Cord.Chain.signAndSubmitTx(extrinsic, authorIdentity)
registry = txRegistry
}
console.log('\n✅ Registry created!')

console.log(`\n❄️ Query Chain Scores `)
const chainScore = await Cord.Score.query(
journalContent.entity,
journalContent.scoreType
// Step 4: Add Delelegate One as Registry Admin
console.log(`\n❄️ Registry Admin Delegate Authorization `)
const registryAuthority = await addRegistryAdminDelegate(
authorIdentity,
issuerDid.uri,
registry['identifier'],
delegateOneDid.uri,
async ({ data }) => ({
signature: issuerKeys.capabilityDelegation.sign(data),
keyType: issuerKeys.capabilityDelegation.type,
})
)
console.dir(chainScore, { depth: null, colors: true })
console.log(`\n✅ Registry Authorization - ${registryAuthority} - created!`)

const chainAvgScore = await Cord.Score.queryAverage(
journalContent.entity,
journalContent.scoreType
console.log(`\n❄️ Journal Entry `)
let journalContent: IJournalContent = {
entity: sellerDid.uri.replace('did:cord:', ''),
tid: UUID.generatev4().toString(),
collector: collectorDid.uri.replace('did:cord:', ''),
rating_type: ScoreType.overall,
rating: 12.116,
entry_type: EntryType.debit,
count: 5,
}
console.dir(journalContent, { depth: null, colors: true })
console.log('\n✅ Journal Entry created!')

console.log('\nAnchoring the score on the blockchain...')
const scoreIdentifier = await updateScore(
journalContent,
registryAuthority,
authorIdentity,
delegateOneDid.uri,
delegateOneKeys
)

console.log(
'\n✅ The score has been successfully anchored on the blockchain \nIdentifier:',
scoreIdentifier
)
console.dir(chainAvgScore, { depth: null, colors: true })
let x = await Cord.Scoring.fetchAverageScore(sellerDid.uri,'Overall')
console.log('x',x)
let y = await Cord.Scoring.fetchJournalFromChain('score:cord:Y8ARa4Djnve7csqRDMtNn2D3LjY4mbyiUyV7zKYEv99LPYgY9','Overall')
console.log(y)
}

main()
Expand Down
2 changes: 1 addition & 1 deletion demo/src/demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function getChallenge(): string {
}

async function main() {
const networkAddress = 'ws://127.0.0.1:9944'
const networkAddress = 'ws://127.0.0.1:63554'
Cord.ConfigService.set({ submitTxResolveOn: Cord.Chain.IS_IN_BLOCK })
await Cord.connect(networkAddress)

Expand Down
56 changes: 56 additions & 0 deletions demo/src/utils/updateScore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import * as Cord from '@cord.network/sdk'
import { IJournalContent, IRatingInput } from '@cord.network/types'

/**
* This function anchors the score on the blockchain
* @param journalContent - Score entry details
* @param registryAuthority - Registry authority
* @param authorIdentity - The account that will be used to sign and submit the extrinsic.
* @param authorDid - DID of the entity which anchors the transaction.
* @param authorKeys - Keys which are used to sign.
* @returns the hash of the score entry if the operation is executed successfully.
*/

export async function updateScore(
journalContent: IJournalContent,
registryAuthority: String,
authorIdentity: Cord.CordKeyringPair,
authorDid: Cord.DidUri,
authorKeys: Cord.CordKeyringPair
) {
const api = Cord.ConfigService.get('api')

journalContent.rating = await Cord.Scoring.adjustAndRoundRating(
journalContent.rating
)
const digest = await Cord.Scoring.generateDigestFromJournalContent(
journalContent
)
const authorization = registryAuthority.replace('auth:cord:', '')
const ratingInput: IRatingInput = {
entry: journalContent,
digest: digest,
creator: authorIdentity.address,
}
const journalCreationExtrinsic = await api.tx.score.addRating(
ratingInput,
authorization
)

const authorizedStreamTx = await Cord.Did.authorizeTx(
authorDid,
journalCreationExtrinsic,
async ({ data }) => ({
signature: authorKeys.assertionMethod.sign(data),
keyType: authorKeys.assertionMethod.type,
}),
authorIdentity.address
)

try {
await Cord.Chain.signAndSubmitTx(authorizedStreamTx, authorIdentity)
return Cord.Scoring.getUriForScore(journalContent)
} catch (error) {
return error.message
}
}
1 change: 1 addition & 0 deletions packages/did/src/DidDetails/FullDidDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const methodMapping: Record<string, VerificationKeyRelationship | undefined> = {
'did.submitDidCall': undefined,
didLookup: 'authentication',
didName: 'authentication',
score:'authentication',
}

function getKeyRelationshipForMethod(
Expand Down
1 change: 1 addition & 0 deletions packages/modules/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * as Registry from './registry/index.js'
export * as Content from './content/index.js'
export * as Stream from './stream/index.js'
export * as Document from './document/index.js'
export * as Scoring from './scoring/index.js'
export { connect, disconnect, init } from './cordconfig/index.js'
export { SDKErrors } from '@cord.network/utils'
// export { Identity, PublicIdentity } from './identity/index.js'
Expand Down
65 changes: 65 additions & 0 deletions packages/modules/src/scoring/Scoring.chain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {
ScoreType,
IScoreDetails,
SCORE_MODULUS,
IJournalContent,
} from '@cord.network/types'
import { ConfigService } from '@cord.network/config'
import { Identifier, SDKErrors } from '@cord.network/utils'
import * as Did from '@cord.network/did'

export async function fetchJournalFromChain(
scoreId: string,
scoreType: ScoreType
): Promise<IJournalContent | null> {
const api = ConfigService.get('api')
const cordScoreId = Identifier.uriToIdentifier(scoreId)
const encodedScoreEntry = await api.query.score.journal(
cordScoreId,
scoreType
)
const decodedScoreEntry = fromChain(encodedScoreEntry)
if (decodedScoreEntry === null) {
throw new SDKErrors.ScoreMissingError(
`There is not a Score of type ${scoreType} with the provided ID "${scoreId}" on chain.`
)
} else return decodedScoreEntry
}

export function fromChain(
encodedEntry: any
): IJournalContent | null {
if (encodedEntry.isSome) {
const unwrapped = encodedEntry.unwrap()
return {
entity: Did.fromChain(unwrapped.entry.entity),
tid: JSON.stringify(unwrapped.entry.tid.toHuman()),
collector: Did.fromChain(unwrapped.entry.collector),
rating_type: unwrapped.entry.ratingType.toString(),
rating: parseInt(unwrapped.entry.rating.toString()) / SCORE_MODULUS,
entry_type: unwrapped.entry.entryType.toString(),
count: parseInt(unwrapped.entry.count.toString()),
}
} else {
return null
}
}

export async function fetchScore(
entityUri: string,
scoreType: ScoreType
): Promise<IScoreDetails> {
const api = ConfigService.get('api')
const encoded = await api.query.score.scores(entityUri, scoreType)
if (encoded.isSome) {
const decoded = encoded.unwrap()
return {
rating: JSON.parse(decoded.rating.toString()),
count: JSON.parse(decoded.count.toString()),
}
} else
throw new SDKErrors.ScoreMissingError(
`There is not a Score of type ${scoreType} with the provided ID "${entityUri}" on chain.`
)
}

Loading

0 comments on commit fcd469d

Please sign in to comment.