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: implemented linked-resource methods #18

Merged
merged 6 commits into from
Jan 9, 2024
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
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"clean": "rm -rf build",
"clean:deps": "pnpm clean && rm -rf node_modules",
"build": "pnpm clean && tsc",
"test": "node --require ts-node/register --test ./tests/*.test.ts",
"test": "node --require ts-node/register --test ./tests/polygon.test.ts",
"prettier": "prettier --ignore-path .prettierignore .",
"check-format": "pnpm prettier --list-different",
"check-types": "pnpm build --noEmit",
Expand All @@ -19,15 +19,17 @@
],
"license": "MIT",
"dependencies": {
"@ayanworks/polygon-did-registry-contract": "2.0.1-alpha.2",
"@ayanworks/polygon-did-registry-contract": "2.0.1-alpha.3",
"@ethersproject/basex": "^5.7.0",
"@ethersproject/signing-key": "^5.7.0",
"@ethersproject/transactions": "^5.7.0",
"@ethersproject/wallet": "^5.7.0",
"ethers": "^6.9.0"
"ethers": "^6.9.0",
"uuid": "^9.0.1"
},
"devDependencies": {
"@types/node": "^18.17.0",
"@types/uuid": "^9.0.7",
"prettier": "^3.0.2",
"release-it": "^16.1.5",
"ts-node": "^10.9.1",
Expand Down
23 changes: 19 additions & 4 deletions pnpm-lock.yaml

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

174 changes: 151 additions & 23 deletions src/registrar.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { Contract, JsonRpcProvider, Wallet, computeAddress } from 'ethers'
import { wrapDidDocument } from './polygon-did-registrar'
import { parseDid, validateDid } from './utils/did'
import { validateResourcePayload } from './utils/linkedResource'
import DidRegistryContract from '@ayanworks/polygon-did-registry-contract'
import { Base58 } from '@ethersproject/basex'
import { computePublicKey } from '@ethersproject/signing-key'
import { v4 as uuidv4 } from 'uuid'

export type PolygonDidInitOptions = {
contractAddress: string
Expand All @@ -17,6 +19,19 @@ export type PolygonDidRegisterOptions = {
serviceEndpoint?: string
}

export type ResourcePayload = {
resourceURI: string
resourceCollectionId: string
resourceId: string
resourceName: string
resourceType: string
mediaType: string
created: string
checksum: string
previousVersionId: string | null
nextVersionId: string | null
}

export class PolygonDID {
private registry: Contract

Expand All @@ -35,6 +50,7 @@ export class PolygonDID {
}

static createKeyPair(network: string) {
let did: string = ''
const wallet = Wallet.createRandom()
const privateKey = wallet.privateKey
const address = computeAddress(privateKey)
Expand All @@ -44,12 +60,14 @@ export class PolygonDID {
const bufferPublicKey = Buffer.from(publicKey)
const publicKeyBase58 = Base58.encode(bufferPublicKey)

if (network !== ('testnet' || 'mainnet')) {
if (network !== 'testnet' && network !== 'mainnet') {
throw new Error('Invalid network provided')
}

const did = `did:polygon:${network}:${address}`

if (network === 'mainnet') {
did = `did:polygon:${address}`
} else {
did = `did:polygon:${network}:${address}`
}
return { address, privateKey, publicKeyBase58, did }
}

Expand All @@ -68,7 +86,7 @@ export class PolygonDID {

const resolveDidDoc = await this.registry.getDIDDoc(parsedDid.didAddress)

if (resolveDidDoc) {
if (resolveDidDoc[0]) {
throw new Error('The DID document already registered!')
}

Expand All @@ -92,51 +110,151 @@ export class PolygonDID {
didDoc,
}
} catch (error) {
console.log(`Error occurred in registerDID function ${error}`)
console.log(`Error occurred in registerDID function ${error} `)
throw error
}
}

public async update(did: string, didDoc: string) {
public async update(did: string, didDoc: object) {
try {
const isValidDid = validateDid(did)
if (!isValidDid) {
throw new Error('invalid did provided')
throw new Error('Invalid did provided')
}

const parsedDid = parseDid(did)

if (!didDoc && !JSON.parse(didDoc)) {
throw new Error('Invalid DID has been entered!')
}
const didDocJson = JSON.parse(didDoc)

if (
!didDocJson['@context'] ||
!didDocJson['id'] ||
!didDocJson['verificationMethod']
) {
throw new Error('Invalid DID doc')
}

// Calling smart contract with update DID document on matic chain
const txnHash = await this.registry.updateDIDDoc(
parsedDid.didAddress,
JSON.stringify(didDoc),
)
return {
did,
didDoc,
txnHash,
}
} catch (error) {
console.log(`Error occurred in update ${error} `)
throw error
}
}

public async addResource(did: string, resourcePayload: ResourcePayload) {
try {
const isValidDid = validateDid(did)
if (!isValidDid) {
throw new Error('Invalid did provided')
}

const parsedDid = parseDid(did)

validateResourcePayload(resourcePayload)

const resolveDidDoc = await this.registry.getDIDDoc(parsedDid.didAddress)

if (!resolveDidDoc[0]) {
throw new Error(`The DID document for the given DID was not found!`)
}

const stringDidDoc = JSON.stringify(resourcePayload)
const resourceId = uuidv4()

const txnHash = await this.registry.addResource(
parsedDid.didAddress,
resourceId,
stringDidDoc,
)

return {
did,
didDoc,
resourceId,
txnHash,
}
} catch (error) {
console.log(`Error occurred in addResource function ${error} `)
throw error
}
}

public async updateResource(
did: string,
resourceId: string,
resourcePayload: ResourcePayload,
) {
try {
const isValidDid = validateDid(did)
if (!isValidDid && resourceId) {
throw new Error('Invalid DID or resourceId provided!')
}

const parsedDid = parseDid(did)

validateResourcePayload(resourcePayload)

const resolveDidDoc = await this.registry.getDIDDoc(parsedDid.didAddress)

if (!resolveDidDoc[0]) {
throw new Error(`The DID document for the given DID was not found!`)
}

const stringDidDoc = JSON.stringify(resourcePayload)

const txnHash = await this.registry.addResource(
parsedDid.didAddress,
resourceId,
stringDidDoc,
)

return {
did,
resourceId,
txnHash,
}
} catch (error) {
console.log(`Error occurred in update ${error}`)
console.log(`Error occurred in addResource function ${error} `)
throw error
}
}

public async deactivate(did: string) {
public async getResourceByDidAndResourceId(did: string, resourceId: string) {
try {
const isValidDid = validateDid(did)

if (!isValidDid) {
throw new Error('Invalid did provided')
}

const parsedDid = parseDid(did)

const resolveDidDoc = await this.registry.getDIDDoc(parsedDid.didAddress)

if (!resolveDidDoc[0]) {
throw new Error(`The DID document for the given DID was not found!`)
}

const linkedResource = await this.registry.getResource(
parsedDid.didAddress,
resourceId,
)

return {
did,
linkedResource: JSON.parse(linkedResource),
}
} catch (error) {
console.log(
`Error occurred in getResourcesByDidAndResourceId function ${error} `,
)
throw error
}
}

public async getResourcesByDid(did: string) {
try {
const isValidDid = validateDid(did)
if (!isValidDid) {
Expand All @@ -145,14 +263,24 @@ export class PolygonDID {

const parsedDid = parseDid(did)

const txnHash = await this.registry.deleteDIDDoc(parsedDid.didAddress)
const resolveDidDoc = await this.registry.getDIDDoc(parsedDid.didAddress)

if (!resolveDidDoc[0]) {
throw new Error(`The DID document for the given DID was not found!`)
}

const listLinkedResource = await this.registry.getAllResources(
parsedDid.didAddress,
)

return {
did,
txnHash,
linkedResources: listLinkedResource.map((element: string) => {
return JSON.parse(element) as ResourcePayload
}),
}
} catch (error) {
console.log(`Error occurred in deactivate ${error}`)
console.log(`Error occurred in getResourcesByDid function ${error} `)
throw error
}
}
Expand Down
Loading
Loading