Skip to content

Commit

Permalink
Add did:bnb Typescript client library
Browse files Browse the repository at this point in the history
Provide client library @identity.com/did-bnb-client that conveniently exposes functions to interact with the on-chain EVM bases DIDRegistry contract. It comes with a thorough README and integration test that are exectuted in CI

PR: #15

Signed-off-by: Martin Riedel <[email protected]>
Reviewed-by: Robert Leonard <[email protected]>
  • Loading branch information
rado0x54 committed Sep 26, 2023
1 parent 636fed8 commit 30802cd
Show file tree
Hide file tree
Showing 29 changed files with 1,731 additions and 2,020 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ts-client-integration-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ jobs:

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1

- name: Set Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x

- name: Install Dev Dependencies
working-directory: ./ts-client
run: npm install
run: yarn install --frozen-lockfile

- name: Run Anvil Node
run: anvil &

- name: Run tests
working-directory: ./ts-client
run: npm run integration-test
run: yarn run test:integration
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ node_modules/
/broadcast/**/dry-run/

# ts-client files
ts-client/node_modules
ts-client/types
ts-client/dist/
ts-client/node_modules/
ts-client/src/contracts/typechain-types/
ts-client/yarn.lock
# Dotenv file
.env
Expand Down
169 changes: 166 additions & 3 deletions ts-client/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,172 @@
# DID bnb typescript client
# `did:bnb` Client

A typescript client library for registering, manipulating, and resolving DIDs
using the `did:bnb` method.

## Features
The `@identity.com/did-bnb-client` library provides the following features:

1. A W3C [DID core spec (v1.0)](https://www.w3.org/TR/did-core/) compliant DID method and resolver operating on the Binance Smart Chain (BSC).
2. TS Client for creating, manipulating, and resolving `did:bnb`.
3. Generic Support for VerificationMethods of any Type and Key length.
4. Native on-chain support for `EcdsaSecp256k1RecoveryMethod2020`.
5. A web-service driver, compatible with [uniresolver.io](https://unresolver.io) and [uniregistrar.io](https://uniregistrar.io).
6. Introduced `OWNERSHIP_PROOF` to indicate that a Verification Method Key signature was verified on-chain.
7. Introduced `DID_DOC_HIDDEN` flag that enables hiding a Verification Method from the DID resolution.

## Client library
### Installation
In the command line of the project folder, type the following and then press **Enter**:
```shell
yarn add @identity.com/did-bnb-client #
```

or

```shell
npm install @identity.com/did-bnb-client
```

### Contract Addresses
The BNB DID Registry contract is deployed at the following address (via proxy):
- Testnet: [0x88a05b4370BbB90c9F3EEa72A65c77131a7bc18d](https://testnet.bscscan.com/address/0x88a05b4370BbB90c9F3EEa72A65c77131a7bc18d)
- Mainnet: TODO

### Usage - Setup and Resolution
Create a service for a `did:bnb` by using the following code snippet:

#### Via Provider (read-only)
```typescript
const address = "0x88a05b4370BbB90c9F3EEa72A65c77131a7bc18d";
const provider = getDefaultProvider(process.env.RPC_URL); // e.g. https://bsc-testnet.publicnode.com
const chainEnv: ChainEnviroment = 'tesnet';
const didRegistry = new DidRegistry(provider, address, {chainEnvironment: 'localnet'});
// ... use didRegistry client
const randomDid = DidIdentifier.create(
Wallet.createRandom().address,
didRegistry.getDid().chainEnviroment
);
didRegistry.resolve(randomDid)
.then((didDocument) => {
console.log(didDocument);
})
.catch((error) => {
console.log(error);
});
```

#### Via Wallet
```typescript
const address = "0x88a05b4370BbB90c9F3EEa72A65c77131a7bc18d";
const provider = getDefaultProvider(process.env.RPC_URL); // e.g. https://bsc-testnet.publicnode.com
const randomWallet = Wallet.createRandom().connect(provider);
const chainEnv: ChainEnviroment = 'tesnet';
const didRegistry = new DidRegistry(randomWallet, address, {chainEnvironment: 'localnet'});
// ... use didRegistry client
// not passing a DID will resolve the DID of the wallet address
didRegistry.resolve()
.then((didDocument) => {
console.log(didDocument);
})
.catch((error) => {
console.log(error);
});
```
### DID resolution information
`did:bnb` DIDs are resolved in the following way:
1. `Generative` DIDs are DIDs that have no persisted DID account. (e.g. every valid EOA address is in this state).
This will return a generative DID document where only the public key of the Account is a valid Verification Method.
2. `Persisted` DIDs are DIDs that have a persisted DID account. Here the DID document represents the state that is found
on-chain.

### Check generative state (read-only)
```typescript
// can optionally take a DIDIdentifier as a parameter
const isGenerative: boolean = await didRegistry.isGenerativeDidState();
```

### Init a DID on-chain

```typescript
const tx: ContractTransaction = await didRegistry.initializeDidState();
```

### Add a VerificationMethod
This operation adds a new Verification Method to the DID. The `keyData` can be a generically sized `UInt8Array`, but logically it must match the `methodType` specified.

```typescript
const verificationMethod = {
fragment: 'test',
flags: reduceVmFlagArray([
BitwiseVerificationMethodFlag.CapabilityInvocation,
]),
methodType: VerificationMethodType.EcdsaSecp256k1RecoveryMethod2020,
keyData: utils.arrayify(Wallet.createRandom().address),
};
const tx: ContractTransaction = await didRegistry.addVerificationMethod(verificationMethod);
```

### Remove a VerificationMethod
This code removes a Verification Method with the given `fragment` from the DID. It is important to keep at least one valid Verification Method with a Capability Invocation flag to prevent a lockout.

```typescript
const tx: ContractTransaction = await didRegistry.removeVerificationMethod('test');
```

### Add a Service
This operation sets a new service on a DID. `serviceType` are strings, not enums, and can therefore be freely defined.

```typescript
const service = {
fragment: 'test2',
service_type: 'testType',
service_endpoint: 'testEndpoint',
};
const tx: ContractTransaction = await didRegistry.addService(service);
```

### Remove a Service
This operation removes a service with the given `fragment` name from the DID.

```typescript
const tx: ContractTransaction = await didRegistry.removeService('test2');
```

### Set VerificationMethodFlags
This sets/updates the flag on an existing VerificationMethod. **Important** if the flag contains `VerificationMethodFlags.OwnershipProof`
this transaction MUST use the same authority as the Verification Method. (e.g. proving that the owner can sign with
that specific VM).

```typescript
const tx: ContractTransaction = await didRegistry
.setVerificationMethodFlags('test', [
BitwiseVerificationMethodFlag.Authentication,
]);
```

### Add Native Controller (did:bnb - DID)
```typescript
const randomWallet = Wallet.createRandom();
const nativeController = DidIdentifier.create(
randomWallet.address,
didRegistry.getDid().chainEnviroment
);
const tx: ContractTransaction = await didRegistry
.addNativeController(nativeController);
```

### Add External Controller (non-did:bnb DID)
```typescript
const externalController = `did:ethr:${Wallet.createRandom().address}`;

const tx: ContractTransaction = await didRegistry
.addExternalController(externalController);
```

## Local Integration Test Setup
This repository uses `jest` to run integration test. These test will run against whatever `RPC_URL` is provided in the `.env` file.
This repository uses `test:integration` to run integration test. These test will run against whatever `RPC_URL` is provided in the `.env` file.

To run the integration test navigate to the `ts-client` directory and run `yarn jest`
To run the integration test navigate to the `ts-client` directory and run `yarn run test:integration`.

### Testing with Foundry
Foundry has a built in testnet node called `anvil`. You can first download foundry by following the [steps here](https://book.getfoundry.sh/getting-started/installation).
Expand Down
14 changes: 0 additions & 14 deletions ts-client/jest.config.ts

This file was deleted.

89 changes: 65 additions & 24 deletions ts-client/package.json
Original file line number Diff line number Diff line change
@@ -1,26 +1,67 @@
{
"name": "did-bnb-ts-client",
"version": "1.0.0",
"main": "src/index.ts",
"license": "MIT",
"scripts": {
"generate-contract-types": "typechain --target=ethers-v6 ./abi/DIDRegistry.json",
"spawn-devnet": "tenderly devnet spawn-rpc --project project --template bnb-testnet",
"integration-test": "jest"
},
"dependencies": {
"dotenv": "^16.3.1",
"ethers": "^6.7.1"
},
"devDependencies": {
"@typechain/ethers-v6": "^0.5.0",
"@types/jest": "^29.5.4",
"@types/node": "^20.5.1",
"jest": "^29.6.3",
"tenderly": "^0.5.3",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typechain": "^8.3.1",
"typescript": "^5.1.6"
"name": "@identity.com/did-bnb-client",
"version": "1.0.0-beta.1",
"main": "dist/src/index.js",
"typings": "dist/src/index.d.ts",
"license": "MIT",
"author": "Martin Riedel <[email protected]>",
"repository": "https://github.com/identity-com/did-bnb",
"homepage": "https://github.com/identity-com/did-bnb",
"files": [
"/dist",
"/npm-shrinkwrap.json"
],
"scripts": {
"postinstall": "$npm_execpath run generate-contract-types",
"lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w",
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check",
"clean": "shx rm -rf ./dist",
"compile": "tsc",
"build": "yarn clean && yarn compile",
"prepack": "yarn build",
"generate-contract-types": "typechain --target=ethers-v5 --out-dir ./src/contracts/typechain-types ./src/contracts/abi/DIDRegistry.json",
"spawn-devnet": "tenderly devnet spawn-rpc --project project --template bnb-testnet",
"test:integration": "ts-mocha test/integration/**/*.test.ts"
},
"dependencies": {
"@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-signer": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"bignumber.js": "^9.1.2",
"did-resolver": "^4.1.0",
"dotenv": "^16.3.1",
"ethers": "^5.7.2",
"ramda": "^0.29.0"
},
"devDependencies": {
"@typechain/ethers-v5": "^11.1.1",
"@types/chai": "^4.3.6",
"@types/chai-as-promised": "^7.1.6",
"@types/mocha": "^10.0.1",
"@types/node": "^20.5.1",
"@types/ramda": "^0.29.4",
"chai": "^4.3.8",
"chai-as-promised": "^7.1.1",
"husky": "^8.0.3",
"mocha": "^10.0.0",
"nyc": "^15.1.0",
"prettier": "^3.0.3",
"shx": "^0.3.4",
"tenderly": "^0.5.3",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.1",
"typechain": "^8.3.1",
"typescript": "^5.1.6"
},
"husky": {
"hooks": {
"pre-commit": "yarn lint"
}
}
},
"prettier": {
"printWidth": 80,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
}
}
File renamed without changes.
2 changes: 2 additions & 0 deletions ts-client/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './service';
export * from './utils';
Loading

0 comments on commit 30802cd

Please sign in to comment.