diff --git a/README.md b/README.md index 86c7bb16..9e88b852 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

Token Registry

- TradeTrust Token Registry + TradeTrust Token Registry

@@ -14,36 +14,44 @@

-The Electronic Bill of Lading (eBL) is a digital document that can be used to prove the ownership of goods. It is a standardised document that is accepted by all major shipping lines and customs authorities. The [Token Registry](https://github.com/Open-Attestation/token-registry) repository contains both the smart contract -code for token registry (in `/contracts`) as well as the node package for using this library (in `/src`). +The Electronic Bill of Lading (eBL) is a digital document which you can use to prove the ownership of goods. It is a standardized document accepted by all major shipping lines and customs authorities. + +The [Token Registry](https://github.com/Open-Attestation/token-registry) repository contains the following: + +* The smart contract code for token registry in the `/contracts` folder +* The node package for using this library in the `/src` folder ## Table of Contents + + - [Installation](#installation) - [Usage](#usage) - [TradeTrustToken](#tradetrusttoken) - [Title Escrow](#title-escrow) - - [Title Escrow Signable (Experimental)](#title-escrow-signable-experimental) - - [Provider & Signer](#provider--signer) - - [Roles and Access](#roles-and-access) + - [Title Escrow signable (experimental)](#title-escrow-signable-experimental) + - [Provider & signer](#provider--signer) + - [Roles and access](#roles-and-access) - [Deployment](#deployment) - - [Quick Start](#quick-start) - - [Advanced Usage](#advanced-usage) - - [Token Contract](#token-contract) - - [Stand-alone Contract](#stand-alone-contract) - - [Using an existing Title Escrow Factory](#using-an-existing-title-escrow-factory) - - [Title Escrow Factory](#title-escrow-factory) - - [Deploy a new Title Escrow Factory](#deploy-a-new-title-escrow-factory) + - [Quick start](#quick-start) + - [Advanced usage](#advanced-usage) + - [Token contract](#token-contract) + - [Standalone contract](#standalone-contract) + - [Using an existing Title Escrow factory](#using-an-existing-title-escrow-factory) + - [Title Escrow factory](#title-escrow-factory) + - [Deploying a new Title Escrow factory](#deploying-a-new-title-escrow-factory) - [Verification](#verification) - - [Network Configuration](#network-configuration) + - [Network configuration](#network-configuration) - [Configuration](#configuration) - [Development](#development) - [Scripts](#scripts) - [Subgraph](#subgraph) -- [Notes](#notes) +- [Additional information](#additional-information) ## Installation +To install Token Registry on your machine, run the command below: + ```sh npm install --save @govtechsg/token-registry ``` @@ -52,18 +60,23 @@ npm install --save @govtechsg/token-registry ## Usage -To use the package, you will need to provide your own +Provide one of the following depending on your purpose: + +* To use the package, provide your own Web3 [provider](https://docs.ethers.io/v5/api/providers/api-providers/) -or [signer](https://docs.ethers.io/v5/api/signer/#Wallet) (if you are writing to the blockchain). -This package exposes the [Typechain (Ethers)](https://github.com/dethcrypto/TypeChain/tree/master/packages/target-ethers-v5) bindings for the contracts. + +* To write to the blockchain, provide the [signer](https://docs.ethers.io/v5/api/signer/#Wallet) that exposes the [Typechain (Ethers)](https://github.com/dethcrypto/TypeChain/tree/master/packages/target-ethers-v5) bindings for the contracts ### TradeTrustToken The `TradeTrustToken` is a Soulbound Token (SBT) tied to the Title Escrow. The SBT implementation is loosely based on OpenZeppelin's implementation of the [ERC721](http://erc721.org/) standard. -An SBT is used in this case because the token, while can be transferred to the registry, is largely restricted to its designated Title Escrow contracts. + +In this case, an SBT is used because the token is largely restricted to its designated Title Escrow contracts, while it can be transferred to the registry. + See issue [#108](https://github.com/Open-Attestation/token-registry/issues/108) for more details. -#### Connect to existing token registry +#### Connecting to an existing token registry +The following is a code example that connects to a token registry: ```ts import { TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; @@ -71,19 +84,25 @@ import { TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; const connectedRegistry = TradeTrustToken__factory.connect(tokenRegistryAddress, signer); ``` -#### Issuing a Document +#### Issuing a document + +The following is a code example that issues a document: ```ts await connectedRegistry.mint(beneficiaryAddress, holderAddress, tokenId); ``` -#### Restoring a Document +#### Restoring a document + +The following is a code example that restores a document: ```ts await connectedRegistry.restore(tokenId); ``` -#### Accept/Burn a Document +#### Accepting or burning a document + +The following is a code example that burns a document: ```ts await connectedRegistry.burn(tokenId); @@ -91,11 +110,11 @@ await connectedRegistry.burn(tokenId); ### Title Escrow -The Title Escrow contract is used to manage and represent the ownership of a token between a beneficiary and holder. -During minting, the Token Registry will create and assign a Title Escrow as the owner of that token. +Using the Title Escrow contract, you can manage and represent the ownership of a token between a beneficiary and holder. During minting, the Token Registry will create and assign a Title Escrow as the owner of that token. The actual owners will use the Title Escrow contract to perform their ownership operations. -#### Connect to Title Escrow +#### Connecting to a Title Escrow +The following is a code example that connects to a Title Escrow: ```ts import { TitleEscrow__factory } from "@govtechsg/token-registry/contracts"; @@ -103,9 +122,9 @@ import { TitleEscrow__factory } from "@govtechsg/token-registry/contracts"; const connectedEscrow = TitleEscrow__factory.connect(existingTitleEscrowAddress, signer); ``` -#### Transfer of Beneficiary/Holder +#### Transfer of the beneficiary or holder -Transferring of beneficiary and holder within the Title Escrow relies on the following methods: +To transfer the beneficiary and holder within the Title Escrow, use the following methods: ```solidity function transferBeneficiary(address beneficiaryNominee) external; @@ -118,29 +137,32 @@ function nominate(address beneficiaryNominee) external; ``` -The `transferBeneficiary` transfers only the beneficiary and `transferHolder` transfers only the holder. -To transfer both beneficiary and holder in a single transaction, use `transferOwners`. Transfer of beneficiary will require a nomination done through the `nominate` method. +* The `transferBeneficiary` transfers only the beneficiary and `transferHolder` transfers only the holder. -#### Surrendering/Burning a Document +* To transfer both the beneficiary and holder in a single transaction, use `transferOwners`. -Use the `surrender` method in the Title Escrow. +* Transfer of the beneficiary will require a nomination through the `nominate` method. + +#### Surrendering or burning a document + +To surrender or burn a document use the `surrender` method in the Title Escrow: ```solidity function surrender() external; ``` -Example: +The following shows a code example: ```ts await connectedEscrow.surrender(); ``` -#### Accessing the Current Owners +#### Accessing the current owners -The addresses of the current owners can be retrieved from the `beneficiary`, `holder` and `nominee` methods. +You can retrieve the addresses of the current owners from the `beneficiary`, `holder`, and `nominee` methods. -Example: +The following shows a code example: ```ts const currentBeneficiary = await connectedEscrow.beneficiary(); @@ -150,17 +172,19 @@ const currentHolder = await connectedEscrow.holder(); const nominatedBeneficiary = await connectedEscrow.nominee(); ``` -### Title Escrow Signable (Experimental) +### Title Escrow signable (experimental) -This is similar to the [Title Escrow](#title-escrow) with the additional support for off-chain nomination and endorsement of beneficiary nominees. The on-chain nominee will take precedence. -The current beneficiary will initiate the transfer transaction with the endorsement. +This is similar to the [Title Escrow](#title-escrow) with the additional support for off-chain nomination and the endorsement of beneficiary nominees: +* The on-chain nominee will take precedence. +* The current beneficiary will initiate the transfer transaction with the endorsement. -This feature could help to save on gas fees for cases where there are frequent nominations and endorsements between the owners. +With this feature, you can save on gas fees for cases where frequent nominations and endorsements occur between the owners. -Currently, this is not the default Title Escrow. To use this version of the Title Escrow, you will need to make some changes to the `TitleEscrowFactory.sol` file before deployment by following these steps: +Currently, this is not the default Title Escrow. To use this version of the Title Escrow, you need to make some changes to the `TitleEscrowFactory.sol` file before deployment by following these steps in the code example: ```solidity // Step 1. Import the TitleEscrowSignable contract + import "./TitleEscrowSignable.sol"; contract TitleEscrowFactory is ITitleEscrowFactory { @@ -168,8 +192,11 @@ contract TitleEscrowFactory is ITitleEscrowFactory { constructor() { // Step 2. Look for this line in the constructor + implementation = address(new TitleEscrow()); - // Step 3. Replace the line in Step #2 with the following line: + + // Step 3. Replace the line in Step 2 with the following line: + implementation = address(new TitleEscrowSignable()); } @@ -178,11 +205,11 @@ contract TitleEscrowFactory is ITitleEscrowFactory { ``` -Note that this is currently an experimental feature. Implementers will need to setup a "book-keeping" backend for the signed data. +>**Note:** This is currently an experimental feature. Implementers need to set up a "book-keeping" backend for the signed data. -### Provider & Signer +### Provider & signer -Different ways to get provider or signer: +The following code examples shows different ways to get the provider or the signer: ```ts import { Wallet, providers, getDefaultProvider } from "ethers"; @@ -199,9 +226,9 @@ const signerFromMnemonic = Wallet.fromMnemonic("MNEMONIC-HERE"); signerFromMnemonic.connect(provider); ``` -### Roles and Access +### Roles and access -Roles are useful for granting users to access certain functions only. Currently, here are the designated roles meant for the different key operations. +Using roles, you can grant the users to access only certain functions. Currently, here are the designated roles for the different key operations. | Role | Access | | -------------- | ----------------------------------- | @@ -210,10 +237,15 @@ Roles are useful for granting users to access certain functions only. Currently, | `AccepterRole` | Able to accept a surrendered token | | `RestorerRole` | Able to restore a surrendered token | -A trusted user can be granted multiple roles by the admin user to perform different operations. -The following functions can be called on the token contract by the admin user to grant and revoke roles to and from users. -#### Grant a role to a user +The admin user can grant a trusted user multiple roles to perform different operations. + +To grant roles to the users or revoke roles from them, the admin user can call the following functions: + +#### Granting a role to a user + +Only the default admin or the role admin will be able to call this function: + ```ts import { constants } from "@govtechsg/token-registry"; @@ -221,9 +253,9 @@ import { constants } from "@govtechsg/token-registry"; await tokenRegistry.grantRole(constants.roleHash.MinterRole, "0xbabe"); ``` -Can only be called by default admin or role admin. +#### Revoking a role from a user -#### Revoke a role from a user +Only the default admin or the role admin will be able to call this function: ```ts import { constants } from "@govtechsg/token-registry"; @@ -231,12 +263,13 @@ import { constants } from "@govtechsg/token-registry"; await tokenRegistry.revokeRole(constants.roleHash.AccepterRole, "0xbabe"); ``` -Can only be called by default admin or role admin. - #### Setting a role admin -The standard setup does not add the role-admin roles so that users don't deploy (and, hence, pay the gas for) more than what they need. -If you need a more complex setup, you can add the admin roles to the designated roles. +The standard setup does not change the user's role into a role admin, so that the user does not need to deploy or pay the gas more than what's needed. + +For a more complex setup, you can add the admin roles to the designated roles. + +Only the default admin will be able to call this function: ```ts import { constants } from "@govtechsg/token-registry"; @@ -247,40 +280,35 @@ await tokenRegistry.setRoleAdmin(roleHash.RestorerRole, roleHash.RestorerAdminRo await tokenRegistry.setRoleAdmin(roleHash.AccepterRole, roleHash.AccepterAdminRole); ``` -Can only be called by default admin. - # Deployment -Hardhat is used to manage the contract development environment and deployment. This repository provides a couple of -Hardhat tasks to simplify the deployment process. +With Hardhat, you can manage the contract development environment and deployment. This repository provides a couple of Hardhat tasks to simplify the deployment process. -Starting from v4, we have included an easy and cost-effective way to deploy the contracts while also keeping options available for advanced users to setup the contracts their preferred way. +Starting from V4, the token registry includes an easy and cost-effective way to deploy the contracts and meanwhile keep the options available for advanced users to set up the contracts in a preferable way. -> 💡 Please ensure that you have setup your configuration file before deployment. -> See [Configuration](#configuration) section for more details. The deployer (configured in your `.env` file) will be made the default admin. +>**Note:** Before deployment, ensure that you have set up your configuration file. See the [Configuration](#configuration) section for more details. The deployer (configured in your `.env` file) will be the default admin. -## Quick Start +## Quick start -For users who want to quickly deploy their contracts without too much hassle, you’ll only have to supply the name and symbol of your token to the command, and you’re ready to roll! +To quickly deploy contracts with ease, you need to supply your token name and symbol to the command: ``` npx hardhat deploy:token --network mumbai --name "The Great Shipping Co." --symbol GSC ``` -👆 This is the easiest and most cost-effective method to deploy. Currently, this is supported on Ethereum, Sepolia, Polygon and Polygon Mumbai. The deployed contract will inherit all the standard functionality from our on-chain contracts. This helps to save deployment costs and make the process more convenient for users and integrators. +The above is the easiest and most cost-effective method to deploy. Currently, this is supported on Ethereum, Sepolia, Polygon, and Polygon Mumbai. The deployed contract will inherit all the standard functionalities from the Token Registry's on-chain contracts. This saves deployment costs and makes the process more convenient for users and integrators. -> 💡 Remember to supply the`--network` argument with the name of the network you wish to deploy on. -> See [Network Configuration](#network-configuration) section for more info on the list of network names. +>**Note:** Remember to supply the`--network` argument with the name of the network on which you want to deploy. See the [Network configuration](#network-configuration) section for more information on the list of network names. -## Advanced Usage +## Advanced usage -For experienced users who would like to have more control over their setup (or have extra 💰 to spend 💸), we have provided a few other options and commands. -However, you should be aware that, depending on what you’re doing, the gas costs could be higher than the method described in [Quick Start](#quick-start). -You should already know what you are doing when using any of these options. +For experienced users who want more control over their setup (or have extra fund to spend), a few other options and commands are provided. -### Token Contract +>**Important:** Depending on your use case, the gas costs might be higher than the method described in [Quick start](#quick-start). -Deploys the token contract. +### Token contract + +The following command deploys the token contract. ``` Usage: hardhat [GLOBAL OPTIONS] deploy:token --factory --name [--standalone] --symbol [--verify] @@ -296,21 +324,21 @@ OPTIONS: deploy:token: Deploys the TradeTrust token ``` -> 💡 Tip: Note that the `--factory` argument is optional. When not provided, the task will use the default Title Escrow Factory. -> You can also reuse a Title Escrow factory that you have previously deployed by passing its address to the `--factory` argument. +>**Note:** +> * The `--factory` argument is optional. If not provided, the task will use the default Title Escrow Factory. +> * You can also reuse a previously deployed Title Escrow factory by passing its address to the `--factory` argument. -#### Stand-alone Contract +#### Standalone contract -If you would like to deploy your own modified version of the token contract or simply just deploy your own copy of the contract, you can use the `--standalone` flag. +To deploy your own modified version or your own copy of the token contract, use the `--standalone` flag: ``` npx hardhat deploy:token --network mumbai --name "The Great Shipping Co." --symbol GSC --verify --standalone ``` -👆 This will deploy a _full token contract_ with the name _The Great Shipping Co._ under the symbol _GSC_ on the Polygon _mumbai_ -network using the default Title Escrow factory. The contract will also be _verified_ on Etherscan. +The above command will deploy a _full token contract_ with the name _The Great Shipping Co._ under the symbol _GSC_ on the Polygon _mumbai_ network using the default Title Escrow factory. The contract will also be _verified_ on Etherscan. -#### Using an existing Title Escrow Factory +#### Using an existing Title Escrow factory To use an existing or your own version of Title Escrow factory, you can supply its address to the `—factory` argument. This option only works with the `--standalone` flag. @@ -318,12 +346,11 @@ To use an existing or your own version of Title Escrow factory, you can supply i npx hardhat deploy:token --network polygon --name "The Great Shipping Co." --symbol GSC --factory 0xfac70 ``` -👆 This will deploy a "cheap" token contract with the name _The Great Shipping Co._ under the symbol _GSC_ on the _Polygon Mainnet_ -network using an existing Title Escrow factory at `0xfac70`. +The above command will deploy a "cheap" token contract with the name _The Great Shipping Co._ under the symbol _GSC_ on the _Polygon Mainnet_ network using an existing Title Escrow factory at `0xfac70`. -### Title Escrow Factory +### Title Escrow factory -Deploys the Title Escrow factory. +The command below deploys the Title Escrow factory. ``` Usage: hardhat [GLOBAL OPTIONS] deploy:factory [--verify] @@ -335,42 +362,44 @@ OPTIONS: deploy:factory: Deploys a new Title Escrow factory ``` -#### Deploy a new Title Escrow Factory +#### Deploying a new Title Escrow factory -If you want to deploy your own modified version or simply want to have your own copy of the Title Escrow factory, you can use this command: +To deploy your own modified version or your own copy of the Title Escrow factory, use this command: ``` npx hardhat deploy:factory --network rinkeby ``` -👆 This will deploy a new Title Escrow factory on the _Rinkeby_ network without verifying the contract. +The above command will deploy a new Title Escrow factory on the _Rinkeby_ network without verifying the contract. To verify the contract, pass in the `--verify` flag. ## Verification -When verifying the contracts through either the Hardhat's verify plugin or passing the `--verify` flag to the deployment -tasks (which internally uses the same plugin), you will need to include your correct API key, depending on the network, in your `.env` configuration. See [Configuration](#configuration) section for more info. +When verifying the contracts through either the Hardhat's verify plugin or passing the `--verify` flag to the deployment tasks, which internally uses the same plugin, you need to include your correct API key. Depending on the network, add the key into your `.env` configuration. See the [Configuration](#configuration) section for more information. + +- For Ethereum, set `ETHERSCAN_API_KEY` +- For Polygon, set `POLYGONSCAN_API_KEY` -- For Ethereum, set `ETHERSCAN_API_KEY`. -- For Polygon, set `POLYGONSCAN_API_KEY`. +## Network configuration -## Network Configuration +The table below shows the network names that are currently pre-configured: -Here's a list of network names currently pre-configured: +| Network ID | Name | Network | Type | +| ---------- | ------------------------ | ------------ | ---------- | +| `1` | Ethereum Mainnet | `mainnet` | Production | +| `11155111` | Ethereum Testnet Sepolia | `sepolia` | Test | +| `137` | Polygon Mainnet | `polygon` | Production | +| `80001` | Polygon Testnet Mumbai | `mumbai` | Test | +| `50` | XDC Network | `xdc` | Production | +| `51` | XDC Apothem Network | `xdcapothem` | Test | -- `mainnet` (Ethereum) -- `sepolia` -- `polygon` (Polygon Mainnet) -- `mumbai` (Polygon Mumbai) -- `xdc` (XDC Network Mainnet) -- `xdcapothem` (XDC Apothem TestNet) -> 💡 You can configure existing and add other networks you wish to deploy to in the `hardhat.config.ts` file. +>**Note:** You can configure the existing networks and add others to which you want to deploy in the `hardhat.config.ts` file. ## Configuration -Create a `.env` file and add your own keys into it. You can rename from the sample file `.env.sample` or copy the -following into a new file: +Create a `.env` file and add your own keys into it. You can rename it from the sample file `.env.sample` or copy the +following code into a new file: ``` # Infura @@ -388,23 +417,29 @@ DEPLOYER_PK= MNEMONIC= ``` -Only either the `DEPLOYER_PK` or `MNEMONIC` is needed. +Only one of the following is needed: +* `DEPLOYER_PK` +* `MNEMONIC` # Development -This repository's development framework uses [HardHat](https://hardhat.org/getting-started/). +This repository's development framework uses [Hardhat](https://hardhat.org/getting-started/). -Tests are run using `npm run test`, more development tasks can be found in the package.json scripts. +You can run the tests using `npm run test` and find more development tasks in the `package.json` scripts. ### Scripts +You can install dependencies, test your project, check source code, and build your project with the commands below: + ```sh npm install npm test npm run lint npm run build +``` -# See Deployment section for more info +For more information on the commands below, see the [Deployment](#deployment) section: +```sh npx hardhat deploy:token npx hardhat deploy:factory npx hardhat deploy:token:impl @@ -412,9 +447,9 @@ npx hardhat deploy:token:impl ## Subgraph -Check out our [Token Registry Subgraph](https://github.com/Open-Attestation/token-registry-subgraph) Github repository +Check out the [Token Registry Subgraph GitHub repository](https://github.com/Open-Attestation/token-registry-subgraph) for more information on using and deploying your own subgraphs for the Token Registry contracts. -## Notes +## Additional information -- The contracts have not gone through formal audits yet. Please use them at your own discretion. +The contracts have not gone through formal audits. Use them at your own discretion.