Skip to content

Commit

Permalink
Added demonstration for CL registry based on event based approach
Browse files Browse the repository at this point in the history
Signed-off-by: artem.ivanov <[email protected]>
  • Loading branch information
Artemkaaas committed Dec 5, 2023
1 parent dca3cdc commit b4e2f2c
Show file tree
Hide file tree
Showing 14 changed files with 196 additions and 40 deletions.
33 changes: 24 additions & 9 deletions indy-besu/network/config/besu/genesis.json

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions indy-besu/smart_contracts/contracts-ts/EthereumCLRegistry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Contract } from '../utils/contract'

export class EthereumCLRegistry extends Contract {
public static readonly defaultAddress = '0x0000000000000000000000000000000000111111'

constructor(sender?: any) {
super(EthereumCLRegistry.name, sender)
}

public async createResource(id: string, resource: string) {
const tx = await this.instance.createResource(id, resource)
return tx.wait()
}
}
6 changes: 6 additions & 0 deletions indy-besu/smart_contracts/contracts/cl/ClErrors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ error CredentialDefinitionNotFound(string id);
* @param owner DID owner account address.
*/
error SenderIsNotIssuerDidOwner(address sender, address owner);

/**
* @notice Error that occurs when trying to create an already existing resource (Schema or Crdential Definition).
* @param id resource ID.
*/
error ResourceAlreadyExist(string id);
33 changes: 33 additions & 0 deletions indy-besu/smart_contracts/contracts/cl/EthereumCLRegistry.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

import { ControlledUpgradeable } from "../upgrade/ControlledUpgradeable.sol";

import { EthereumCLRegistryInterface } from "./EthereumCLRegistryInterface.sol";
import { ResourceAlreadyExist } from "./ClErrors.sol";

contract EthereumCLRegistry is EthereumCLRegistryInterface, ControlledUpgradeable {
/**
* Mapping to track created created resources by their id.
*/
mapping(string id => bool exists) private _resources;

/**
* Checks the uniqueness of the resource ID
*/
modifier _uniqueResourceId(string memory id) {
if (_resources[id] == true) revert ResourceAlreadyExist(id);
_;
}

function initialize(address upgradeControlAddress) public reinitializer(1) {
_initializeUpgradeControl(upgradeControlAddress);
}

/// @inheritdoc EthereumCLRegistryInterface
function createResource(string calldata id, string calldata resource) public virtual _uniqueResourceId(id) {
bytes32 resourceIdHash = keccak256(abi.encodePacked(id));
_resources[id] = true;
emit EthereumCLResourceCreated(resourceIdHash, resource);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.20;

interface EthereumCLRegistryInterface {
/**
* @dev Event that is sent when a new CL resource created
*
* @param id Hash of resource identifier
* @param resource Created resource as JSON string
*/
event EthereumCLResourceCreated(bytes32 indexed id, string resource);

/**
* @dev Creates a new CL resource using event based approach.
*
* @param id Identifier of the resource.
* @param resource The new AnonCreds resource as JSON string.
*/
function createResource(string calldata id, string calldata resource) external;
}
52 changes: 52 additions & 0 deletions indy-besu/smart_contracts/demos/ethereum-cl-registry.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import Web3 from 'web3'
import environment, { host } from '../environment'
import { Actor } from './utils/actor'
import { ROLES } from '../contracts-ts'
import { createSchemaObject } from '../utils'
import { EthereumCLRegistry } from '../contracts-ts/EthereumCLRegistry'

async function demo() {
const web3 = new Web3(new Web3.providers.HttpProvider(host))

let receipt: any

const trustee = await new Actor(environment.accounts.account1).init()
const faber = await new Actor().init()

console.log('1. Trustee assign ENDORSER role to Faber')
receipt = await trustee.roleControl.assignRole(ROLES.ENDORSER, faber.address)
console.log(`Role ${ROLES.ENDORSER} assigned to account ${faber.address}. Receipt: ${JSON.stringify(receipt)}`)

console.log('2. Faber creates Test Schema')
const schema = createSchemaObject({ issuerId: faber.did })
receipt = await faber.ethereumCLRegistry.createResource(schema.id, JSON.stringify(schema))
console.log(`Schema created for id ${schema.id}. Receipt: ${JSON.stringify(receipt)}`)

console.log('3. Faber resolves Test Schema')
const eventsByType = await faber.ethereumCLRegistry.instance.queryFilter('EthereumCLResourceCreated')
console.log(`Resolve schema using events by type and Ethers ${JSON.stringify(eventsByType, null, 2)}`)

const filter = await faber.ethereumCLRegistry.instance.filters.EthereumCLResourceCreated(
web3.utils.keccak256(schema.id),
)
const eventsUsingEthers = await faber.ethereumCLRegistry.instance.queryFilter(filter)
console.log(`Resolve schema using events and Ethers: ${JSON.stringify(eventsUsingEthers, null, 2)}`)
const resolvedSchema = web3.utils.hexToAscii(eventsUsingEthers[0].data)
console.log(`Schema JSON: ${resolvedSchema}`)

let eventsUsingWeb3 = await web3.eth.getPastLogs({
address: EthereumCLRegistry.defaultAddress,
topics: [
null, // same as: web3.utils.sha3("SchemaStringCreated(uint,uint)"),
web3.utils.keccak256(schema.id),
],
})
console.log(`Resolve schema using events and Web3: ${JSON.stringify(eventsUsingWeb3, null, 2)}`)
console.log(eventsUsingWeb3)
}

if (require.main === module) {
demo()
}

module.exports = exports = demo
3 changes: 3 additions & 0 deletions indy-besu/smart_contracts/demos/utils/actor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
UpgradeControl,
} from '../../contracts-ts'
import { Account, AccountInfo } from '../../utils'
import { EthereumCLRegistry } from '../../contracts-ts/EthereumCLRegistry'

export class Actor {
public account: Account
Expand All @@ -16,6 +17,7 @@ export class Actor {
public schemaRegistry!: SchemaRegistry
public credentialDefinitionRegistry!: CredentialDefinitionRegistry
public upgradeControl!: UpgradeControl
public ethereumCLRegistry!: EthereumCLRegistry

constructor(accountInfo?: AccountInfo) {
this.account = accountInfo ? new Account(accountInfo) : new Account()
Expand All @@ -30,6 +32,7 @@ export class Actor {
CredentialDefinitionRegistry.defaultAddress,
)
this.upgradeControl = await new UpgradeControl(this.account).getInstance(UpgradeControl.defaultAddress)
this.ethereumCLRegistry = await new EthereumCLRegistry(this.account).getInstance(EthereumCLRegistry.defaultAddress)
return this
}

Expand Down
1 change: 1 addition & 0 deletions indy-besu/smart_contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"demo/flow": "yarn run-on-besu demos/flow.ts",
"demo/account": "yarn run-on-besu demos/account-control.ts",
"demo/upgrade": "yarn run-on-besu demos/upgrade-control.ts",
"demo/ethereum-cl-registry": "yarn run-on-besu demos/ethereum-cl-registry.ts",
"genesis/generate": "ts-node scripts/genesis/generate.ts",
"postinstall": "cd ../../ && husky install indy-besu/smart_contracts/.husky",
"solc-compile": "solc -o compiled-contracts --optimize --bin-runtime --evm-version=constantinople @dk1a=$(pwd)/node_modules/@dk1a @openzeppelin=$(pwd)/node_modules/@openzeppelin contracts/**/*.sol node_modules/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"
Expand Down
11 changes: 11 additions & 0 deletions indy-besu/smart_contracts/scripts/genesis/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
SchemasConfig,
ValidatorsConfig,
} from './contracts'
import { EthereumCLRegistryConfig } from './contracts/ethereumCLRegistry'
import { UpgradeControlConfig } from './contracts/upgradeControl'

export const compiledContractsFolder = 'compiled-contracts'
Expand All @@ -24,6 +25,7 @@ export interface Config {
schemaRegistry: SchemasConfig
upgradeControl: UpgradeControlConfig
validatorControl: ValidatorsConfig
ethereumCLRegistry: EthereumCLRegistryConfig
}

const contractsAddresses = {
Expand All @@ -36,6 +38,7 @@ const contractsAddresses = {
validators: '0x0000000000000000000000000000000000007777',
accountControl: '0x0000000000000000000000000000000000008888',
upgradeControl: '0x0000000000000000000000000000000000009999',
ethereumCLRegistry: '0x0000000000000000000000000000000000111111',
}

export const config: Config = {
Expand Down Expand Up @@ -160,4 +163,12 @@ export const config: Config = {
upgradeControlAddress: contractsAddresses.upgradeControl,
},
},
ethereumCLRegistry: {
name: 'EthereumCLRegistry',
address: contractsAddresses.ethereumCLRegistry,
description: 'Smart contract to manage ethereum CL registry',
data: {
upgradeControlAddress: contractsAddresses.upgradeControl,
},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { padLeft } from 'web3-utils'
import { config } from '../config'
import { ContractConfig } from '../contractConfig'
import { buildProxySection, slots } from '../helpers'

export interface EthereumCLRegistryConfig extends ContractConfig {
data: {
upgradeControlAddress: string
}
}

export function ethereumCLRegistry() {
const { name, address, description, data } = config.ethereumCLRegistry
const storage: any = {}

// address of upgrade control contact stored in slot 1
storage[slots['0']] = padLeft(data.upgradeControlAddress, 64)
return buildProxySection(name, address, description, storage)
}
2 changes: 2 additions & 0 deletions indy-besu/smart_contracts/scripts/genesis/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
upgradeControl,
validatorControl,
} from './contracts'
import { ethereumCLRegistry } from './contracts/ethereumCLRegistry'

function main() {
const contracts = {
Expand All @@ -23,6 +24,7 @@ function main() {
...didRegistry(),
...schemaRegistry(),
...credentialDefinitionRegistry(),
...ethereumCLRegistry(),
}
writeJson(contracts, outFile)
}
Expand Down
37 changes: 9 additions & 28 deletions indy-besu/smart_contracts/test/utils/contract-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { HardhatEthersSigner } from '@nomicfoundation/hardhat-ethers/signers'
import { ethers } from 'hardhat'
import {
CredentialDefinitionRegistry,
DidRegistry,
Expand All @@ -6,8 +8,8 @@ import {
UpgradeControl,
ValidatorControl,
} from '../../contracts-ts'
import { Contract, createBaseDidDocument, createSchemaObject } from '../../utils'
import { getTestAccounts, ZERO_ADDRESS } from './test-entities'
import { Contract } from '../../utils'
import { ZERO_ADDRESS } from './test-entities'

export class DidRegex extends testableContractMixin(Contract) {
constructor() {
Expand All @@ -34,49 +36,28 @@ export const TestableRoleControl = testableContractMixin(RoleControl)
export const TestableValidatorControl = testableContractMixin(ValidatorControl)
export const TestableUpgradeControl = testableContractMixin(UpgradeControl)

export async function deployRoleControl() {
const roleControl = await new RoleControl().deployProxy({ params: [ZERO_ADDRESS] })
const testAccounts = await getTestAccounts(roleControl)

return { roleControl, testAccounts }
}

export async function deployDidRegistry() {
const { testAccounts } = await deployRoleControl()

const didRegex = await new DidRegex().deploy()
const didValidator = await new DidValidator().deploy({ libraries: [didRegex] })
const didRegistry = await new TestableDidRegistry().deployProxy({ params: [ZERO_ADDRESS], libraries: [didValidator] })

return { didRegistry, didValidator, didRegex, testAccounts }
return { didRegistry, didValidator, didRegex }
}

export async function deploySchemaRegistry() {
const { didRegistry, testAccounts } = await deployDidRegistry()
const { didRegistry } = await deployDidRegistry()
const schemaRegistry = await new TestableSchemaRegistry().deployProxy({ params: [didRegistry.address, ZERO_ADDRESS] })

return { didRegistry, schemaRegistry, testAccounts }
return { didRegistry, schemaRegistry }
}

export async function deployCredentialDefinitionRegistry() {
const { didRegistry, schemaRegistry, testAccounts } = await deploySchemaRegistry()
const { didRegistry, schemaRegistry } = await deploySchemaRegistry()
const credentialDefinitionRegistry = await new TestableCredentialDefinitionRegistry().deployProxy({
params: [didRegistry.address, schemaRegistry.address, ZERO_ADDRESS],
})

return { credentialDefinitionRegistry, didRegistry, schemaRegistry, testAccounts }
}

export async function createDid(didRegistry: DidRegistry, did: string) {
const didDocument = createBaseDidDocument(did)
await didRegistry.createDid(didDocument)
return didDocument
}

export async function createSchema(schemaRegistry: SchemaRegistry, issuerId: string) {
const schema = createSchemaObject({ issuerId })
await schemaRegistry.createSchema(schema)
return schema
return { credentialDefinitionRegistry, didRegistry, schemaRegistry }
}

function testableContractMixin<T extends new (...args: any[]) => Contract>(Base: T) {
Expand Down
3 changes: 1 addition & 2 deletions indy-besu/smart_contracts/test/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export namespace ClErrors {
export const FieldRequired = 'FieldRequired'
export const IssuerNotFound = 'IssuerNotFound'
export const IssuerHasBeenDeactivated = 'IssuerHasBeenDeactivated'
export const SenderIsNotIssuerDidOwner = 'SenderIsNotIssuerDidOwner'

// Schema errors
export const InvalidSchemaId = 'InvalidSchemaId'
Expand All @@ -15,7 +14,7 @@ export namespace ClErrors {

// CredDef errors
export const InvalidCredentialDefinitionId = 'InvalidCredentialDefinitionId'
export const UnsupportedCredentialDefinitionType = 'UnsupportedCredentialDefinitionType'
export const UnsupportedCredentialDefintionType = 'UnsupportedCredentialDefintionType'
export const CredentialDefinitionAlreadyExist = 'CredentialDefinitionAlreadyExist'
export const CredentialDefinitionNotFound = 'CredentialDefinitionNotFound'
}
Expand Down
2 changes: 1 addition & 1 deletion indy-besu/smart_contracts/utils/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class Contract {

protected readonly name: string
protected readonly signer?: Signer
protected instance: any
public instance: any

constructor(name: string, sender?: any) {
this.name = name
Expand Down

0 comments on commit b4e2f2c

Please sign in to comment.