From d4854115cb92e4e404d229e96096cee9ab553795 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Sep 2022 14:41:02 +0800 Subject: [PATCH 01/63] feat(token-registry)!: token registry v4 --- README.md | 21 +--- package-lock.json | 30 ++++- package.json | 2 +- src/commands/deploy/deploy.types.ts | 13 +-- src/commands/deploy/title-escrow-creator.ts | 32 ------ src/commands/deploy/title-escrow.ts | 62 ---------- src/commands/deploy/token-registry.ts | 6 + .../title-escrow/endorse-change-of-owner.ts | 2 +- .../title-escrow/endorse-transfer-of-owner.ts | 15 ++- .../title-escrow/nominate-change-of-owner.ts | 10 +- .../title-escrow/title-escrow-command.type.ts | 2 +- src/commands/token-registry/role.ts | 9 ++ .../token-registry/role/grant-role.ts | 55 +++++++++ src/commands/token-registry/role/helper.ts | 27 +++++ .../token-registry/role/revoke-role.ts | 55 +++++++++ src/commands/token-registry/role/set-role.ts | 58 ++++++++++ .../token-registry-command.type.ts | 14 +++ .../deploy/title-escrow-creator/index.ts | 1 - .../title-escrow-creator.test.ts | 86 -------------- .../title-escrow-creator.ts | 35 ------ .../deploy/title-escrow/index.ts | 1 - .../deploy/title-escrow/title-escrow.test.ts | 106 ------------------ .../deploy/title-escrow/title-escrow.ts | 65 ----------- .../token-registry/token-registry.test.ts | 13 ++- .../deploy/token-registry/token-registry.ts | 32 +++++- .../title-escrow/acceptSurrendered.test.ts | 30 ++--- .../title-escrow/acceptSurrendered.ts | 10 +- .../title-escrow/changeHolder.test.ts | 60 ++++------ .../title-escrow/changeHolder.ts | 9 +- ...ngeOfOwner.test.ts => changeOwner.test.ts} | 35 +++--- ...endorseChangeOfOwner.ts => changeOwner.ts} | 12 +- ...s => endorseNominatedBeneficiary.test..ts} | 47 ++++---- .../endorseNominatedBeneficiary.ts | 52 +++++++++ .../title-escrow/endorseTransferOfOwner.ts | 58 ---------- src/implementations/title-escrow/helpers.ts | 41 ++++--- ...er.test.ts => nominateBeneficiary.test.ts} | 66 ++++++----- ...hangeOfOwner.ts => nominateBeneficiary.ts} | 23 ++-- .../title-escrow/rejectSurrendered.test.ts | 53 ++++----- .../title-escrow/rejectSurrendered.ts | 45 ++------ .../title-escrow/surrenderDocument.test.ts | 32 +++--- .../title-escrow/surrenderDocument.ts | 47 ++++++-- .../token-registry/issue.test.ts | 67 +++++------ src/implementations/token-registry/issue.ts | 16 +-- .../token-registry/role/grant-role.test.ts | 74 ++++++++++++ .../token-registry/role/grant-role.ts | 41 +++++++ .../token-registry/role/revoke-role.test.ts | 74 ++++++++++++ .../token-registry/role/revoke-role.ts | 41 +++++++ .../token-registry/role/set-role.test.ts | 73 ++++++++++++ .../token-registry/role/set-role.ts | 41 +++++++ 49 files changed, 989 insertions(+), 810 deletions(-) delete mode 100644 src/commands/deploy/title-escrow-creator.ts delete mode 100644 src/commands/deploy/title-escrow.ts create mode 100644 src/commands/token-registry/role.ts create mode 100644 src/commands/token-registry/role/grant-role.ts create mode 100644 src/commands/token-registry/role/helper.ts create mode 100644 src/commands/token-registry/role/revoke-role.ts create mode 100644 src/commands/token-registry/role/set-role.ts delete mode 100644 src/implementations/deploy/title-escrow-creator/index.ts delete mode 100644 src/implementations/deploy/title-escrow-creator/title-escrow-creator.test.ts delete mode 100644 src/implementations/deploy/title-escrow-creator/title-escrow-creator.ts delete mode 100644 src/implementations/deploy/title-escrow/index.ts delete mode 100644 src/implementations/deploy/title-escrow/title-escrow.test.ts delete mode 100644 src/implementations/deploy/title-escrow/title-escrow.ts rename src/implementations/title-escrow/{endorseChangeOfOwner.test.ts => changeOwner.test.ts} (82%) rename src/implementations/title-escrow/{endorseChangeOfOwner.ts => changeOwner.ts} (78%) rename src/implementations/title-escrow/{endorseTransferOfOwner.test.ts => endorseNominatedBeneficiary.test..ts} (76%) create mode 100644 src/implementations/title-escrow/endorseNominatedBeneficiary.ts delete mode 100644 src/implementations/title-escrow/endorseTransferOfOwner.ts rename src/implementations/title-escrow/{nominateChangeOfOwner.test.ts => nominateBeneficiary.test.ts} (61%) rename src/implementations/title-escrow/{nominateChangeOfOwner.ts => nominateBeneficiary.ts} (55%) create mode 100644 src/implementations/token-registry/role/grant-role.test.ts create mode 100644 src/implementations/token-registry/role/grant-role.ts create mode 100644 src/implementations/token-registry/role/revoke-role.test.ts create mode 100644 src/implementations/token-registry/role/revoke-role.ts create mode 100644 src/implementations/token-registry/role/set-role.test.ts create mode 100644 src/implementations/token-registry/role/set-role.ts diff --git a/README.md b/README.md index dfde4cb7..7b59789f 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,6 @@ npx -p @govtechsg/open-attestation-cli open-attestation | ------------------------------------------ | ----------- | ------ | ------- | | Create config | ❎ | ✔️ | ❎ | | Deploy document store | ✔ | ✔ | ✔ | -| Deploy title escrow | ✔ | ✔ | ✔ | -| Deploy title escrow creator | ✔ | ✔ | ✔ | | Deploy token registry | ✔ | ✔ | ✔ | | Dns txt create | ❎ | ❎ | ❎ | | Dns txt get | ❎ | ❎ | ❎ | @@ -48,6 +46,9 @@ npx -p @govtechsg/open-attestation-cli open-attestation | Document store transfer ownership | ✔ | ✔ | ✔ | | Token registry issue | ✔ | ✔ | ✔ | | Token registry mint | ✔ | ✔ | ✔ | +| Token registry grant role | ✔ | ✔ | ✔ | +| Token registry revoke role | ✔ | ✔ | ✔ | +| Token registry set role | ✔ | ✔ | ✔ | | Transaction cancel | ✔ | ✔ | ✔ | | Wallet create | ❎ | ❎ | ❎ | | Wallet decrypt | ❎ | ❎ | ❎ | @@ -251,22 +252,6 @@ open-attestation deploy token-registry "My Sample Token" MST --network ropsten ✔ success Token registry deployed at 0x4B127b8d5e53872d403ce43414afeb1db67B1842 ``` -#### Deploy new title escrow - -Deploys a title escrow contract on the blockchain - -```bash -open-attestation deploy title-escrow --network --address --beneficiary --holder -``` - -Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). - -```bash -open-attestation deploy title-escrow --network ropsten --address 0x4B127b8d5e53872d403ce43414afeb1db67B1842 --beneficiary 0x6FFeD6E6591b808130a9b248fEA32101b5220eca --holder 0x6FFeD6E6591b808130a9b248fEA32101b5220eca - -✔ success Title escrow deployed at 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 -``` - #### Issue document to token registry `Issue` a hash to a token registry deployed on the blockchain. The `tokenId` option would be used to indicate the document hash, and the `to` option to indicate the title escrow address the document is mapped to. diff --git a/package-lock.json b/package-lock.json index a1bd0836..83fc66f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1955,6 +1955,13 @@ "runtypes": "^6.3.0", "snyk": "^1.576.0", "web-did-resolver": "^2.0.4" + }, + "dependencies": { + "@govtechsg/token-registry": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-2.6.1.tgz", + "integrity": "sha512-QnAIlYeGD4zHtYPiZ46SIe6hFc3HyMKvyBJIdlsFxHscMR4f8AENIyUS2AKhqJibCcN2beNJy/bPWlCAtHoT7w==" + } } }, "@govtechsg/open-attestation": { @@ -1978,9 +1985,12 @@ } }, "@govtechsg/token-registry": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-2.5.3.tgz", - "integrity": "sha512-0VIeANA2XpaMNBLBAImwXf3SMV9wQcQeU4HxRgPzWaG4X/MpS2Msxv6YyTwk++p+j57s3PNoUQC5JiIAaY7xZw==" + "version": "4.0.0-beta.15", + "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.0.0-beta.15.tgz", + "integrity": "sha512-wctboADcpR2Df/FFYzv9sLt7zI0ojRywNl30/Ot4ix1uVZev57OeNnVbruxojPm76LGCalgPnqxDNnM9SPWPAQ==", + "requires": { + "@typechain/ethers-v5": "~10.0.0" + } }, "@humanwhocodes/config-array": { "version": "0.5.0", @@ -3551,6 +3561,15 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", "dev": true }, + "@typechain/ethers-v5": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-10.0.0.tgz", + "integrity": "sha512-Kot7fwAqnH96ZbI8xrRgj5Kpv9yCEdjo7mxRqrH7bYpEgijT5MmuOo8IVsdhOu7Uog4ONg7k/d5UdbAtTKUgsA==", + "requires": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + } + }, "@types/babel__core": { "version": "7.1.15", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.15.tgz", @@ -16005,6 +16024,11 @@ "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", "dev": true }, + "ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==" + }, "ts-jest": { "version": "26.5.6", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-26.5.6.tgz", diff --git a/package.json b/package.json index 06426cc7..b7cb9088 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@govtechsg/oa-encryption": "^1.3.3", "@govtechsg/oa-verify": "^7.5.2", "@govtechsg/open-attestation": "^6.4.1", - "@govtechsg/token-registry": "^2.5.3", + "@govtechsg/token-registry": "^4.0.0-beta.15", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", diff --git a/src/commands/deploy/deploy.types.ts b/src/commands/deploy/deploy.types.ts index cad0af2b..aa9d2ac8 100644 --- a/src/commands/deploy/deploy.types.ts +++ b/src/commands/deploy/deploy.types.ts @@ -9,14 +9,7 @@ export type DeployTokenRegistryCommand = NetworkAndWalletSignerOption & GasOption & { registryName: string; registrySymbol: string; - }; - -export type DeployTitleEscrowCreatorCommand = NetworkAndWalletSignerOption & GasOption; - -export type DeployTitleEscrowCommand = NetworkAndWalletSignerOption & - GasOption & { - tokenRegistry: string; - beneficiary: string; - holder: string; - titleEscrowFactory?: string; + verify?: boolean; + standalone?: boolean; + factoryAddress?: string; }; diff --git a/src/commands/deploy/title-escrow-creator.ts b/src/commands/deploy/title-escrow-creator.ts deleted file mode 100644 index a812a799..00000000 --- a/src/commands/deploy/title-escrow-creator.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Argv } from "yargs"; -import { error, info, success } from "signale"; -import { getLogger } from "../../logger"; -import { deployTitleEscrowCreator } from "../../implementations/deploy/title-escrow-creator"; -import { DeployTitleEscrowCreatorCommand } from "./deploy.types"; -import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; -import { getErrorMessage, getEtherscanAddress } from "../../utils"; - -const { trace } = getLogger("deploy:title-escrow-creator"); - -export const command = "title-escrow-creator [options]"; - -export const describe = "Deploys a (global) title escrow creator on the blockchain"; - -export const builder = (yargs: Argv): Argv => withGasPriceOption(withNetworkAndWalletSignerOption(yargs)); - -export const handler = async (args: DeployTitleEscrowCreatorCommand): Promise => { - trace(`Args: ${JSON.stringify(args, null, 2)}`); - try { - info(`Deploying title escrow creator`); - const titleEscrowCreator = await deployTitleEscrowCreator(args); - success(`Title escrow creator deployed at ${titleEscrowCreator.contractAddress}`); - info( - `Find more details at ${getEtherscanAddress({ network: args.network })}/address/${ - titleEscrowCreator.contractAddress - }` - ); - return titleEscrowCreator.contractAddress; - } catch (e) { - error(getErrorMessage(e)); - } -}; diff --git a/src/commands/deploy/title-escrow.ts b/src/commands/deploy/title-escrow.ts deleted file mode 100644 index f0cc37b9..00000000 --- a/src/commands/deploy/title-escrow.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Argv } from "yargs"; -import { error, info, success } from "signale"; -import { getLogger } from "../../logger"; -import { deployTitleEscrow } from "../../implementations/deploy/title-escrow"; -import { DeployTitleEscrowCommand } from "./deploy.types"; -import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; -import { getErrorMessage, getEtherscanAddress } from "../../utils"; - -const { trace } = getLogger("deploy:title-escrow"); - -export const command = "title-escrow [options]"; - -export const describe = "Deploys a title escrow on the blockchain"; - -export const builder = (yargs: Argv): Argv => - withGasPriceOption( - withNetworkAndWalletSignerOption( - yargs - .option("token-registry", { - alias: "r", - description: "Address of ERC721 contract that the escrow will receive the token from", - type: "string", - normalize: true, - required: true, - }) - .option("beneficiary", { - alias: "b", - description: "Beneficiary address", - type: "string", - normalize: true, - required: true, - }) - .option("holder", { - alias: "h", - description: "Holder address", - type: "string", - normalize: true, - required: true, - }) - .option("title-escrow-factory", { - alias: "c", - description: "Address of title escrow creator/factory", - type: "string", - normalize: true, - }) - ) - ); - -export const handler = async (args: DeployTitleEscrowCommand): Promise => { - trace(`Args: ${JSON.stringify(args, null, 2)}`); - try { - info(`Deploying title escrow`); - const titleEscrow = await deployTitleEscrow(args); - success(`Title escrow deployed at ${titleEscrow.contractAddress}`); - info( - `Find more details at ${getEtherscanAddress({ network: args.network })}/address/${titleEscrow.contractAddress}` - ); - return titleEscrow.contractAddress; - } catch (e) { - error(getErrorMessage(e)); - } -}; diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index 603a9650..f8b1c974 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -12,6 +12,8 @@ export const command = "token-registry [option export const describe = "Deploys a token registry contract on the blockchain"; +// Refer to @govtechsg/token-registry tasks/deploy-token.ts + export const builder = (yargs: Argv): Argv => withGasPriceOption( withNetworkAndWalletSignerOption( @@ -24,6 +26,10 @@ export const builder = (yargs: Argv): Argv => description: "Symbol of the token (typically 3 characters)", normalize: true, }) + .positional("factory-address", { + description: "Address of Token Registry factory (Optional)", + normalize: true, + }) ) ); diff --git a/src/commands/title-escrow/endorse-change-of-owner.ts b/src/commands/title-escrow/endorse-change-of-owner.ts index 78f31742..02386729 100644 --- a/src/commands/title-escrow/endorse-change-of-owner.ts +++ b/src/commands/title-escrow/endorse-change-of-owner.ts @@ -1,7 +1,7 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { endorseChangeOfOwner } from "../../implementations/title-escrow/endorseChangeOfOwner"; +import { endorseChangeOfOwner } from "../../implementations/title-escrow/changeOwner"; import { TitleEscrowEndorseChangeOfOwnerCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; diff --git a/src/commands/title-escrow/endorse-transfer-of-owner.ts b/src/commands/title-escrow/endorse-transfer-of-owner.ts index 11d55ca7..080d1925 100644 --- a/src/commands/title-escrow/endorse-transfer-of-owner.ts +++ b/src/commands/title-escrow/endorse-transfer-of-owner.ts @@ -1,8 +1,8 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { endorseTransferOfOwner } from "../../implementations/title-escrow/endorseTransferOfOwner"; -import { BaseTitleEscrowCommand as TitleEscrowEndorseTransferOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { endorseNominatedBeneficiary } from "../../implementations/title-escrow/endorseNominatedBeneficiary"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; @@ -28,10 +28,15 @@ export const builder = (yargs: Argv): Argv => type: "string", demandOption: true, }) + .option("newOwner", { + description: "Address of the beneficiary of the transferable record", + type: "string", + demandOption: true, + }) ) ); -export const handler = async (args: TitleEscrowEndorseTransferOfOwnerCommand): Promise => { +export const handler = async (args: TitleEscrowNominateBeneficiaryCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info( @@ -40,9 +45,9 @@ export const handler = async (args: TitleEscrowEndorseTransferOfOwnerCommand): P warn( `Please note that if you do not have the correct privileges to the transferable record, then this command will fail.` ); - const { transactionReceipt, approvedHolder, approvedOwner } = await endorseTransferOfOwner(args); + const { transactionReceipt, nominatedBeneficiary } = await endorseNominatedBeneficiary(args); success( - `Transferable record with hash ${args.tokenId}'s holder has been successfully endorsed to approved owner at ${approvedOwner} and approved holder at ${approvedHolder}` + `Transferable record with hash ${args.tokenId}'s holder has been successfully endorsed to approved beneficiary at ${nominatedBeneficiary}` ); info( `Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionReceipt.transactionHash}` diff --git a/src/commands/title-escrow/nominate-change-of-owner.ts b/src/commands/title-escrow/nominate-change-of-owner.ts index 654eba4e..069016e2 100644 --- a/src/commands/title-escrow/nominate-change-of-owner.ts +++ b/src/commands/title-escrow/nominate-change-of-owner.ts @@ -1,8 +1,8 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { nominateChangeOfOwner } from "../../implementations/title-escrow/nominateChangeOfOwner"; -import { TitleEscrowNominateChangeOfOwnerCommand } from "./title-escrow-command.type"; +import { nominateBeneficiary } from "../../implementations/title-escrow/nominateBeneficiary"; +import { TitleEscrowNominateBeneficiaryCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; @@ -28,14 +28,14 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("newOwner", { - description: "Address of the new owner of the transferable record", + description: "Address of the beneficiary of the transferable record", type: "string", demandOption: true, }) ) ); -export const handler = async (args: TitleEscrowNominateChangeOfOwnerCommand): Promise => { +export const handler = async (args: TitleEscrowNominateBeneficiaryCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info( @@ -44,7 +44,7 @@ export const handler = async (args: TitleEscrowNominateChangeOfOwnerCommand): Pr warn( `Please note that if you do not have the correct privileges to the transferable record, then this command will fail.` ); - const { transactionHash } = await nominateChangeOfOwner(args); + const { transactionHash } = await nominateBeneficiary(args); success( `Transferable record with hash ${args.tokenId}'s holder has been successfully nominated to new owner with address ${args.newOwner}` ); diff --git a/src/commands/title-escrow/title-escrow-command.type.ts b/src/commands/title-escrow/title-escrow-command.type.ts index 67824dbe..a7ba23e2 100644 --- a/src/commands/title-escrow/title-escrow-command.type.ts +++ b/src/commands/title-escrow/title-escrow-command.type.ts @@ -14,6 +14,6 @@ export type TitleEscrowEndorseChangeOfOwnerCommand = BaseTitleEscrowCommand & { newOwner: string; }; -export type TitleEscrowNominateChangeOfOwnerCommand = BaseTitleEscrowCommand & { +export type TitleEscrowNominateBeneficiaryCommand = BaseTitleEscrowCommand & { newOwner: string; }; diff --git a/src/commands/token-registry/role.ts b/src/commands/token-registry/role.ts new file mode 100644 index 00000000..fe2215bc --- /dev/null +++ b/src/commands/token-registry/role.ts @@ -0,0 +1,9 @@ +import { Argv } from "yargs"; + +export const command = "role "; + +export const describe = "Manages User Roles of Token Registry"; + +export const builder = (yargs: Argv): Argv => yargs.commandDir("role", { extensions: ["ts", "js"] }); + +export const handler = (): void => {}; diff --git a/src/commands/token-registry/role/grant-role.ts b/src/commands/token-registry/role/grant-role.ts new file mode 100644 index 00000000..9f9fcaf0 --- /dev/null +++ b/src/commands/token-registry/role/grant-role.ts @@ -0,0 +1,55 @@ +import { Argv } from "yargs"; +import { error, info, success } from "signale"; +import { getLogger } from "../../../logger"; +import { grantRoleToTokenRegistry } from "../../../implementations/token-registry/role/grant-role"; +import { TokenRegistryRoleCommand } from "../token-registry-command.type"; +import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; +import { getErrorMessage, getEtherscanAddress } from "../../../utils"; +import { getAllRolesInput, getRoleEnumValue } from "./helper"; + +const { trace } = getLogger("token-registry:grant-roles"); + +export const command = "grant-role [options]"; + +export const describe = "Grant Role of Token Registry"; + +export const builder = (yargs: Argv): Argv => + withGasPriceOption( + withNetworkAndWalletSignerOption( + yargs + .option("address", { + alias: "a", + description: "Address of the token registry", + type: "string", + demandOption: true, + }) + .option("role", { + describe: "Role to be granted to receipient", + type: "string", + nargs: 1, + demandOption: true, + choices: getAllRolesInput(), + }) + .option("recipient", { + description: "Recipient of the role", + type: "string", + demandOption: true, + }) + ) + ); + +export const handler = async (args: TokenRegistryRoleCommand): Promise => { + trace(`Args: ${JSON.stringify(args, null, 2)}`); + try { + info(`Assigning ${args.role} to the recipient ${args.recipient} in the registry ${args.address}`); + const { transactionHash } = await grantRoleToTokenRegistry({ + ...args, + role: getRoleEnumValue(args.role), + }); + success(`Role ${args.role} has been assigned to the recipient ${args.recipient} in the registry ${args.address}`); + info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); + return args.address; + } catch (e) { + error(getErrorMessage(e)); + } +}; diff --git a/src/commands/token-registry/role/helper.ts b/src/commands/token-registry/role/helper.ts new file mode 100644 index 00000000..6a66a4c3 --- /dev/null +++ b/src/commands/token-registry/role/helper.ts @@ -0,0 +1,27 @@ +import { constants } from "@govtechsg/token-registry"; + +export const rolesInput = [ + ["default-admin", constants.roleHash.DefaultAdmin], + ["minter", constants.roleHash.MinterRole], + ["accepter", constants.roleHash.AccepterRole], + ["restorer", constants.roleHash.RestorerRole], + ["minter-admin", constants.roleHash.MinterAdminRole], + ["accepter-admin", constants.roleHash.AccepterAdminRole], + ["restorer-admin", constants.roleHash.RestorerAdminRole], +]; + +export const getAllRolesInput = (): string[] => { + return [...adminRolesInput, ...normalRolesInput]; +}; + +export const adminRolesInput = ["default-admin", "minter-admin", "accepter-admin", "restorer-admin"]; +export const normalRolesInput = ["minter", "accepter", "restorer"]; + +export const getRoleEnumValue = (roleNameInString: string): string => { + for (const roleIndex in rolesInput) { + if (rolesInput[roleIndex][0] === roleNameInString) { + return rolesInput[roleIndex][1]; + } + } + throw new Error("Invalid Role"); +}; diff --git a/src/commands/token-registry/role/revoke-role.ts b/src/commands/token-registry/role/revoke-role.ts new file mode 100644 index 00000000..70dbd567 --- /dev/null +++ b/src/commands/token-registry/role/revoke-role.ts @@ -0,0 +1,55 @@ +import { Argv } from "yargs"; +import { error, info, success } from "signale"; +import { getLogger } from "../../../logger"; +import { TokenRegistryRoleCommand } from "../token-registry-command.type"; +import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; +import { getErrorMessage, getEtherscanAddress } from "../../../utils"; +import { getRoleEnumValue, getAllRolesInput } from "./helper"; +import { revokeRoleToTokenRegistry } from "../../../implementations/token-registry/role/revoke-role"; + +const { trace } = getLogger("token-registry:revoke-role"); + +export const command = "revoke-role [options]"; + +export const describe = "Revoke User Role in Token Registry"; + +export const builder = (yargs: Argv): Argv => + withGasPriceOption( + withNetworkAndWalletSignerOption( + yargs + .option("address", { + alias: "a", + description: "Address of the token registry", + type: "string", + demandOption: true, + }) + .option("role", { + describe: "Role to be revoked from receipient", + type: "string", + nargs: 1, + demandOption: true, + choices: getAllRolesInput(), + }) + .option("recipient", { + description: "Recipient of the role revocation", + type: "string", + demandOption: true, + }) + ) + ); + +export const handler = async (args: TokenRegistryRoleCommand): Promise => { + trace(`Args: ${JSON.stringify(args, null, 2)}`); + try { + info(`Revoking ${args.role} role from the recipient ${args.recipient} in the registry ${args.address}`); + const { transactionHash } = await revokeRoleToTokenRegistry({ + ...args, + role: getRoleEnumValue(args.role), + }); + success(`Role ${args.role} has been revoked from the recipient ${args.recipient} in the registry ${args.address}`); + info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); + return args.address; + } catch (e) { + error(getErrorMessage(e)); + } +}; diff --git a/src/commands/token-registry/role/set-role.ts b/src/commands/token-registry/role/set-role.ts new file mode 100644 index 00000000..3c9c52f0 --- /dev/null +++ b/src/commands/token-registry/role/set-role.ts @@ -0,0 +1,58 @@ +import { Argv } from "yargs"; +import { error, info, success } from "signale"; +import { getLogger } from "../../../logger"; +import { TokenRegistrySetRoleCommand } from "../token-registry-command.type"; +import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; +import { getErrorMessage, getEtherscanAddress } from "../../../utils"; +import { getRoleEnumValue, normalRolesInput, adminRolesInput } from "./helper"; +import { setRoleToTokenRegistry } from "../../../implementations/token-registry/role/set-role"; + +const { trace } = getLogger("token-registry:set-roles"); + +export const command = "set-role [options]"; + +export const describe = "Set Role of Token Registry"; + +export const builder = (yargs: Argv): Argv => + withGasPriceOption( + withNetworkAndWalletSignerOption( + yargs + .option("address", { + alias: "a", + description: "Address of the token registry", + type: "string", + demandOption: true, + }) + .option("role", { + describe: "Role to be set", + type: "string", + nargs: 1, + demandOption: true, + choices: normalRolesInput, + }) + .option("adminRole", { + describe: "Role to be set to Admin Role", + type: "string", + nargs: 1, + demandOption: true, + choices: adminRolesInput, + }) + ) + ); + +export const handler = async (args: TokenRegistrySetRoleCommand): Promise => { + trace(`Args: ${JSON.stringify(args, null, 2)}`); + try { + info(`Setting ${args.adminRole} to the recipient role ${args.role} in the registry ${args.address}`); + const { transactionHash } = await setRoleToTokenRegistry({ + ...args, + role: getRoleEnumValue(args.role), + adminRole: getRoleEnumValue(args.adminRole), + }); + success(`Role ${args.adminRole} has been assigned to the recipient ${args.role} in the registry ${args.address}`); + info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); + return args.address; + } catch (e) { + error(getErrorMessage(e)); + } +}; diff --git a/src/commands/token-registry/token-registry-command.type.ts b/src/commands/token-registry/token-registry-command.type.ts index b6dc6fcf..9bfa4470 100644 --- a/src/commands/token-registry/token-registry-command.type.ts +++ b/src/commands/token-registry/token-registry-command.type.ts @@ -6,3 +6,17 @@ export type TokenRegistryIssueCommand = NetworkAndWalletSignerOption & to: string; tokenId: string; }; + +export type TokenRegistryRoleCommand = NetworkAndWalletSignerOption & + GasOption & { + address: string; + role: string; + recipient: string; + }; + +export type TokenRegistrySetRoleCommand = NetworkAndWalletSignerOption & + GasOption & { + address: string; + role: string; + adminRole: string; + }; diff --git a/src/implementations/deploy/title-escrow-creator/index.ts b/src/implementations/deploy/title-escrow-creator/index.ts deleted file mode 100644 index 02b22336..00000000 --- a/src/implementations/deploy/title-escrow-creator/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./title-escrow-creator"; diff --git a/src/implementations/deploy/title-escrow-creator/title-escrow-creator.test.ts b/src/implementations/deploy/title-escrow-creator/title-escrow-creator.test.ts deleted file mode 100644 index 18dc07fe..00000000 --- a/src/implementations/deploy/title-escrow-creator/title-escrow-creator.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { deployTitleEscrowCreator } from "./title-escrow-creator"; -import { join } from "path"; -import { TitleEscrowCreatorFactory } from "@govtechsg/token-registry"; -import { Wallet } from "ethers"; -import { DeployTitleEscrowCreatorCommand } from "../../../commands/deploy/deploy.types"; - -jest.mock("@govtechsg/token-registry"); - -const deployParams: DeployTitleEscrowCreatorCommand = { - network: "ropsten", - key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, - dryRun: false, -}; - -describe("token-registry", () => { - describe("deployTitleEscrowCreator", () => { - const tokenFactory: any = TitleEscrowCreatorFactory; - const mockedTokenFactory: jest.Mock = tokenFactory; - const mockedDeploy: jest.Mock = mockedTokenFactory.prototype.deploy; - // increase timeout because ethers is throttling - jest.setTimeout(30000); - - beforeEach(() => { - mockedTokenFactory.mockReset(); - mockedDeploy.mockReset(); - mockedDeploy.mockResolvedValue({ - deployTransaction: { hash: "hash", wait: () => Promise.resolve({ contractAddress: "contractAddress" }) }, - }); - }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await deployTitleEscrowCreator({ - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await deployTitleEscrowCreator({ - network: "ropsten", - keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - - it("should pass in the correct params and return the deployed instance", async () => { - const instance = await deployTitleEscrowCreator(deployParams); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - - expect(passedSigner.privateKey).toBe(`0x${deployParams.key}`); - // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][0].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); - expect(instance.contractAddress).toBe("contractAddress"); - }); - - it("should allow errors to bubble up", async () => { - mockedDeploy.mockRejectedValue(new Error("An Error")); - await expect(deployTitleEscrowCreator(deployParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - delete process.env.OA_PRIVATE_KEY; - await expect( - deployTitleEscrowCreator({ - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }) - ).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" - ); - }); - }); -}); diff --git a/src/implementations/deploy/title-escrow-creator/title-escrow-creator.ts b/src/implementations/deploy/title-escrow-creator/title-escrow-creator.ts deleted file mode 100644 index a2a99a58..00000000 --- a/src/implementations/deploy/title-escrow-creator/title-escrow-creator.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TitleEscrowCreatorFactory } from "@govtechsg/token-registry"; -import { getWalletOrSigner } from "../../utils/wallet"; -import signale from "signale"; -import { getLogger } from "../../../logger"; -import { TransactionReceipt } from "@ethersproject/providers"; -import { DeployTitleEscrowCreatorCommand } from "../../../commands/deploy/deploy.types"; -import { dryRunMode } from "../../utils/dryRun"; - -const { trace } = getLogger("deploy:title-escrow-creator"); - -export const deployTitleEscrowCreator = async ({ - network, - gasPriceScale, - dryRun, - ...rest -}: DeployTitleEscrowCreatorCommand): Promise => { - if (dryRun) { - const factory = new TitleEscrowCreatorFactory(); - await dryRunMode({ - network, - gasPriceScale: gasPriceScale, - transaction: factory.getDeployTransaction(), - }); - process.exit(0); - } - const wallet = await getWalletOrSigner({ network, ...rest }); - const gasPrice = await wallet.provider.getGasPrice(); - const factory = new TitleEscrowCreatorFactory(wallet); - signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy({ gasPrice: gasPrice.mul(gasPriceScale) }); - trace(`Tx hash: ${transaction.deployTransaction.hash}`); - trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); - return transaction.deployTransaction.wait(); -}; diff --git a/src/implementations/deploy/title-escrow/index.ts b/src/implementations/deploy/title-escrow/index.ts deleted file mode 100644 index 5363eeee..00000000 --- a/src/implementations/deploy/title-escrow/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./title-escrow"; diff --git a/src/implementations/deploy/title-escrow/title-escrow.test.ts b/src/implementations/deploy/title-escrow/title-escrow.test.ts deleted file mode 100644 index 1894269f..00000000 --- a/src/implementations/deploy/title-escrow/title-escrow.test.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { deployTitleEscrow } from "./title-escrow"; -import { join } from "path"; -import { TitleEscrowFactory } from "@govtechsg/token-registry"; -import { Wallet } from "ethers"; -import { DeployTitleEscrowCommand } from "../../../commands/deploy/deploy.types"; - -jest.mock("@govtechsg/token-registry"); - -const deployParams: DeployTitleEscrowCommand = { - tokenRegistry: "0x0000000000000000000000000000000000000000", - beneficiary: "0x0000000000000000000000000000000000000001", - holder: "0x0000000000000000000000000000000000000002", - titleEscrowFactory: "0x0000000000000000000000000000000000000003", - network: "ropsten", - key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, - dryRun: false, -}; - -describe("token-registry", () => { - describe("deployTitleEscrow", () => { - const tokenFactory: any = TitleEscrowFactory; - const mockedTokenFactory: jest.Mock = tokenFactory; - const mockedDeploy: jest.Mock = mockedTokenFactory.prototype.deploy; - // increase timeout because ethers is throttling - jest.setTimeout(30000); - - beforeEach(() => { - mockedTokenFactory.mockReset(); - mockedDeploy.mockReset(); - mockedDeploy.mockResolvedValue({ - deployTransaction: { hash: "hash", wait: () => Promise.resolve({ contractAddress: "contractAddress" }) }, - }); - }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await deployTitleEscrow({ - tokenRegistry: "0x0000000000000000000000000000000000000000", - beneficiary: "0x0000000000000000000000000000000000000001", - holder: "0x0000000000000000000000000000000000000002", - titleEscrowFactory: "0x0000000000000000000000000000000000000003", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await deployTitleEscrow({ - network: "ropsten", - tokenRegistry: "0x0000000000000000000000000000000000000000", - beneficiary: "0x0000000000000000000000000000000000000001", - holder: "0x0000000000000000000000000000000000000002", - titleEscrowFactory: "0x0000000000000000000000000000000000000003", - keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - - it("should pass in the correct params and return the deployed instance", async () => { - const instance = await deployTitleEscrow(deployParams); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - - expect(passedSigner.privateKey).toBe(`0x${deployParams.key}`); - expect(mockedDeploy.mock.calls[0][0]).toEqual("0x0000000000000000000000000000000000000000"); - expect(mockedDeploy.mock.calls[0][1]).toEqual("0x0000000000000000000000000000000000000001"); - expect(mockedDeploy.mock.calls[0][2]).toEqual("0x0000000000000000000000000000000000000002"); - expect(mockedDeploy.mock.calls[0][3]).toEqual("0x0000000000000000000000000000000000000003"); - // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][4].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); - expect(instance.contractAddress).toBe("contractAddress"); - }); - - it("should allow errors to bubble up", async () => { - mockedDeploy.mockRejectedValue(new Error("An Error")); - await expect(deployTitleEscrow(deployParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - delete process.env.OA_PRIVATE_KEY; - await expect( - deployTitleEscrow({ - network: "ropsten", - tokenRegistry: "0x0000000000000000000000000000000000000000", - beneficiary: "0x0000000000000000000000000000000000000001", - holder: "0x0000000000000000000000000000000000000002", - titleEscrowFactory: "0x0000000000000000000000000000000000000003", - gasPriceScale: 1, - dryRun: false, - }) - ).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" - ); - }); - }); -}); diff --git a/src/implementations/deploy/title-escrow/title-escrow.ts b/src/implementations/deploy/title-escrow/title-escrow.ts deleted file mode 100644 index 82dee9e5..00000000 --- a/src/implementations/deploy/title-escrow/title-escrow.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { TitleEscrowFactory } from "@govtechsg/token-registry"; -import { getWalletOrSigner } from "../../utils/wallet"; -import signale from "signale"; -import { getLogger } from "../../../logger"; -import { TransactionReceipt } from "@ethersproject/providers"; -import { DeployTitleEscrowCommand } from "../../../commands/deploy/deploy.types"; -import { validateAddress } from "../../utils/validation"; -import { dryRunMode } from "../../utils/dryRun"; - -const { trace } = getLogger("deploy:title-escrow"); - -const CREATOR_CONTRACTS: { [network: string]: string } = { - mainnet: "0x907A4D491A09D59Bcb5dC38eeb9d121ac47237F1", - ropsten: "0xB0dE5E22bAc12820b6dbF6f63287B1ec44026c83", - rinkeby: "0xa51B8dAC076d5aC80507041146AC769542aAe195", -}; - -export const getDefaultEscrowFactory = (network: string): string => { - const address = CREATOR_CONTRACTS[network]; - if (!address) - throw new Error( - "Title escrow creator not found on this network, please deploy one onto this network and specify the address with the -c flag" - ); - return address; -}; - -export const deployTitleEscrow = async ({ - tokenRegistry, - beneficiary, - holder, - titleEscrowFactory, - network, - gasPriceScale, - dryRun, - ...rest -}: DeployTitleEscrowCommand): Promise => { - const titleEscrowFactoryAddress = titleEscrowFactory || getDefaultEscrowFactory(network); - validateAddress(tokenRegistry); - validateAddress(beneficiary); - validateAddress(holder); - validateAddress(titleEscrowFactoryAddress); - - if (dryRun) { - const factory = new TitleEscrowFactory(); - await dryRunMode({ - network, - gasPriceScale: gasPriceScale, - transaction: factory.getDeployTransaction(tokenRegistry, beneficiary, holder, titleEscrowFactoryAddress), - }); - process.exit(0); - } - - const wallet = await getWalletOrSigner({ network, ...rest }); - const gasPrice = await wallet.provider.getGasPrice(); - - const factory = new TitleEscrowFactory(wallet); - signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(tokenRegistry, beneficiary, holder, titleEscrowFactoryAddress, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - trace(`Tx hash: ${transaction.deployTransaction.hash}`); - trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); - return transaction.deployTransaction.wait(); -}; diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 3924e2ac..92b20a59 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -1,15 +1,16 @@ import { deployTokenRegistry } from "./token-registry"; import { join } from "path"; -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const deployParams: DeployTokenRegistryCommand = { registryName: "Test", registrySymbol: "Tst", network: "ropsten", + factoryAddress: "0x0", key: "0000000000000000000000000000000000000000000000000000000000000001", gasPriceScale: 1, dryRun: false, @@ -17,8 +18,8 @@ const deployParams: DeployTokenRegistryCommand = { describe("token-registry", () => { describe("deployTokenRegistry", () => { - const tokenFactory: any = TradeTrustErc721Factory; - const mockedTokenFactory: jest.Mock = tokenFactory; + const tokenFactory: any = TradeTrustERC721__factory; + const mockedTokenFactory: jest.Mock = tokenFactory; const mockedDeploy: jest.Mock = mockedTokenFactory.prototype.deploy; // increase timeout because ethers is throttling jest.setTimeout(30000); @@ -68,8 +69,10 @@ describe("token-registry", () => { expect(passedSigner.privateKey).toBe(`0x${deployParams.key}`); expect(mockedDeploy.mock.calls[0][0]).toEqual(deployParams.registryName); expect(mockedDeploy.mock.calls[0][1]).toEqual(deployParams.registrySymbol); + expect(mockedDeploy.mock.calls[0][2]).toEqual(deployParams.factoryAddress); + // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][2].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); + expect(mockedDeploy.mock.calls[0][3].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); expect(instance.contractAddress).toBe("contractAddress"); }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index cb10069a..f0bfe8ac 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -1,26 +1,45 @@ -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { getWalletOrSigner } from "../../utils/wallet"; import signale from "signale"; import { getLogger } from "../../../logger"; import { TransactionReceipt } from "@ethersproject/providers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { dryRunMode } from "../../utils/dryRun"; +import { constants } from "@govtechsg/token-registry"; const { trace } = getLogger("deploy:token-registry"); export const deployTokenRegistry = async ({ registryName, registrySymbol, + factoryAddress, network, gasPriceScale, dryRun, ...rest }: DeployTokenRegistryCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const factory = new TradeTrustErc721Factory(wallet); + const factory = new TradeTrustERC721__factory(wallet); + const chainId = await wallet.getChainId(); + const deployerAddress = await wallet.getAddress(); + const { contractAddress } = constants; + + if (!chainId) { + throw new Error(`Invalid chain ID: ${chainId}`); + } + + console.log(`[Deployer] ${deployerAddress}`); + + if (!factoryAddress) { + factoryAddress = contractAddress.TitleEscrowFactory[chainId]; + if (!factoryAddress) { + throw new Error(`Network ${network} currently is not supported. Supply a factory address.`); + } + console.log(`[Status] Using ${factoryAddress} as Title Escrow factory.`); + } + if (dryRun) { - const unsignedTx = factory.getDeployTransaction(registryName, registrySymbol, {}); - const tx = await wallet.populateTransaction(unsignedTx); + const tx = factory.getDeployTransaction(registryName, registrySymbol, factoryAddress, {}); await dryRunMode({ network, gasPriceScale: gasPriceScale, @@ -30,7 +49,10 @@ export const deployTokenRegistry = async ({ } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(registryName, registrySymbol, { gasPrice: gasPrice.mul(gasPriceScale) }); + + const transaction = await factory.deploy(registryName, registrySymbol, factoryAddress, { + gasPrice: gasPrice.mul(gasPriceScale), + }); trace(`Tx hash: ${transaction.deployTransaction.hash}`); trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 5466fc64..0e564235 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -1,10 +1,10 @@ -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { acceptSurrendered } from "./acceptSurrendered"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", @@ -14,35 +14,35 @@ const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("accepts surrendered transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockDestroyToken = jest.fn(); - const mockCallStaticDestroyToken = jest.fn().mockResolvedValue(undefined); + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockBurnToken = jest.fn(); + const mockCallStaticBurnToken = jest.fn().mockResolvedValue(undefined); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockReset(); + mockedTradeTrustERC721Factory.mockReset(); mockedConnectERC721.mockReset(); - mockDestroyToken.mockReturnValue({ + mockBurnToken.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); mockedConnectERC721.mockReturnValue({ - destroyToken: mockDestroyToken, + burn: mockBurnToken, callStatic: { - destroyToken: mockCallStaticDestroyToken, + burn: mockCallStaticBurnToken, }, }); - mockDestroyToken.mockClear(); - mockCallStaticDestroyToken.mockClear(); + mockBurnToken.mockClear(); + mockCallStaticBurnToken.mockClear(); }); it("should take in the key from environment variable", async () => { @@ -75,8 +75,8 @@ describe("title-escrow", () => { expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(acceptSurrenderedDocumentParams.tokenRegistry, passedSigner); - expect(mockCallStaticDestroyToken).toHaveBeenCalledTimes(1); - expect(mockDestroyToken).toHaveBeenCalledTimes(1); + expect(mockCallStaticBurnToken).toHaveBeenCalledTimes(1); + expect(mockBurnToken).toHaveBeenCalledTimes(1); }); it("should allow errors to bubble up", async () => { diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index 8ce8e90d..2e2aa9a6 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -1,4 +1,3 @@ -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; @@ -6,6 +5,7 @@ import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from ". import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/dist/contracts"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -18,19 +18,19 @@ export const acceptSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance = await TradeTrustErc721Factory.connect(address, wallet); + const tokenRegistryInstance = await TradeTrustERC721__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistryInstance.estimateGas.destroyToken(tokenId), + estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - await tokenRegistryInstance.callStatic.destroyToken(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); - const transaction = await tokenRegistryInstance.destroyToken(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + await tokenRegistryInstance.callStatic.burn(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + const transaction = await tokenRegistryInstance.burn(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/changeHolder.test.ts index a02e487a..c510a54b 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/changeHolder.test.ts @@ -1,12 +1,12 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { TitleEscrowChangeHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { changeHolderOfTitleEscrow } from "./changeHolder"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); -const changeHolderParams: TitleEscrowChangeHolderCommand = { +const transferHolderParams: TitleEscrowChangeHolderCommand = { to: "0xabcd", tokenId: "0xzyxw", tokenRegistry: "0x1234", @@ -15,24 +15,25 @@ const changeHolderParams: TitleEscrowChangeHolderCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("change holder of transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTokenFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + + const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; const mockedOwnerOf = jest.fn(); - const mockChangeHolder = jest.fn(); - const mockCallStaticChangeHolder = jest.fn().mockResolvedValue(undefined); + const mockTransferHolder = jest.fn(); + const mockCallStaticTransferHolder = jest.fn().mockResolvedValue(undefined); const mockedTitleEscrowAddress = "0x2133"; mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); - mockChangeHolder.mockReturnValue({ + mockTransferHolder.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); @@ -40,35 +41,26 @@ describe("title-escrow", () => { ownerOf: mockedOwnerOf, }); mockedConnectTokenFactory.mockReturnValue({ - changeHolder: mockChangeHolder, + transferHolder: mockTransferHolder, callStatic: { - changeHolder: mockCallStaticChangeHolder, + transferHolder: mockCallStaticTransferHolder, }, }); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockClear(); + mockedTradeTrustERC721Factory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); mockedOwnerOf.mockClear(); - mockChangeHolder.mockClear(); - mockCallStaticChangeHolder.mockClear(); - }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await changeHolderOfTitleEscrow(changeHolderParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); + mockTransferHolder.mockClear(); + mockCallStaticTransferHolder.mockClear(); }); it("should take in the key from key file", async () => { await changeHolderOfTitleEscrow({ - ...changeHolderParams, + ...transferHolderParams, keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), }); @@ -79,18 +71,18 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke a change in holder of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await changeHolderOfTitleEscrow({ - ...changeHolderParams, + ...transferHolderParams, key: privateKey, }); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(changeHolderParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(changeHolderParams.tokenId); + expect(mockedConnectERC721).toHaveBeenCalledWith(transferHolderParams.tokenRegistry, passedSigner); + expect(mockedOwnerOf).toHaveBeenCalledWith(transferHolderParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); - expect(mockCallStaticChangeHolder).toHaveBeenCalledTimes(1); - expect(mockChangeHolder).toHaveBeenCalledTimes(1); + expect(mockCallStaticTransferHolder).toHaveBeenCalledTimes(1); + expect(mockTransferHolder).toHaveBeenCalledTimes(1); }); it("should allow errors to bubble up", async () => { @@ -98,13 +90,7 @@ describe("title-escrow", () => { mockedConnectERC721.mockImplementation(() => { throw new Error("An Error"); }); - await expect(changeHolderOfTitleEscrow(changeHolderParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(changeHolderOfTitleEscrow(changeHolderParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); + await expect(changeHolderOfTitleEscrow(transferHolderParams)).rejects.toThrow("An Error"); }); }); }); diff --git a/src/implementations/title-escrow/changeHolder.ts b/src/implementations/title-escrow/changeHolder.ts index 29b57650..d5ccc61a 100644 --- a/src/implementations/title-escrow/changeHolder.ts +++ b/src/implementations/title-escrow/changeHolder.ts @@ -19,20 +19,19 @@ export const changeHolderOfTitleEscrow = async ({ ...rest }: TitleEscrowChangeHolderCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); + const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); if (dryRun) { - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.changeHolder(to), + estimatedGas: await titleEscrow.estimateGas.transferHolder(to), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await titleEscrow.callStatic.changeHolder(to); - const transaction = await titleEscrow.changeHolder(to, { gasPrice: gasPrice.mul(gasPriceScale) }); + await titleEscrow.callStatic.transferHolder(to); + const transaction = await titleEscrow.transferHolder(to, { gasPrice: gasPrice.mul(gasPriceScale) }); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/endorseChangeOfOwner.test.ts b/src/implementations/title-escrow/changeOwner.test.ts similarity index 82% rename from src/implementations/title-escrow/endorseChangeOfOwner.test.ts rename to src/implementations/title-escrow/changeOwner.test.ts index 5b9663c1..8c02f393 100644 --- a/src/implementations/title-escrow/endorseChangeOfOwner.test.ts +++ b/src/implementations/title-escrow/changeOwner.test.ts @@ -1,10 +1,10 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { TitleEscrowEndorseChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { endorseChangeOfOwner } from "./endorseChangeOfOwner"; +import { endorseChangeOfOwner } from "./changeOwner"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { newHolder: "0xabcd", @@ -16,21 +16,22 @@ const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("endorse change of owner of transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTokenFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method + const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; const mockedOwnerOf = jest.fn(); - const mockTransferToNewEscrow = jest.fn(); - const mockCallStaticTransferToNewEscrow = jest.fn().mockResolvedValue(undefined); + const mockTransferOwners = jest.fn(); + const mockCallStaticTransferOwners = jest.fn().mockResolvedValue(undefined); const mockedTitleEscrowAddress = "0x2133"; const mockedBeneficiary = "0xdssfs"; const mockedHolder = "0xdsfls"; @@ -42,30 +43,30 @@ describe("title-escrow", () => { ownerOf: mockedOwnerOf, }); mockedConnectTokenFactory.mockReturnValue({ - transferToNewEscrow: mockTransferToNewEscrow, + transferOwners: mockTransferOwners, beneficiary: mockGetBeneficiary, holder: mockGetHolder, callStatic: { - transferToNewEscrow: mockCallStaticTransferToNewEscrow, + transferOwners: mockCallStaticTransferOwners, }, }); mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); - mockTransferToNewEscrow.mockReturnValue({ + mockTransferOwners.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockClear(); + mockedTradeTrustERC721Factory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); mockedOwnerOf.mockClear(); - mockTransferToNewEscrow.mockClear(); + mockTransferOwners.mockClear(); mockGetBeneficiary.mockClear(); mockGetHolder.mockClear(); - mockCallStaticTransferToNewEscrow.mockClear(); + mockCallStaticTransferOwners.mockClear(); }); it("should take in the key from environment variable", async () => { @@ -102,8 +103,8 @@ describe("title-escrow", () => { expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockGetBeneficiary).toHaveBeenCalledTimes(1); expect(mockGetHolder).toHaveBeenCalledTimes(1); - expect(mockCallStaticTransferToNewEscrow).toHaveBeenCalledTimes(1); - expect(mockTransferToNewEscrow).toHaveBeenCalledTimes(1); + expect(mockCallStaticTransferOwners).toHaveBeenCalledTimes(1); + expect(mockTransferOwners).toHaveBeenCalledTimes(1); }); it("should throw an error if new owner and new holder addresses are the same as current owner and holder addressses", async () => { diff --git a/src/implementations/title-escrow/endorseChangeOfOwner.ts b/src/implementations/title-escrow/changeOwner.ts similarity index 78% rename from src/implementations/title-escrow/endorseChangeOfOwner.ts rename to src/implementations/title-escrow/changeOwner.ts index 7743502d..a909d9ed 100644 --- a/src/implementations/title-escrow/endorseChangeOfOwner.ts +++ b/src/implementations/title-escrow/changeOwner.ts @@ -20,24 +20,22 @@ export const endorseChangeOfOwner = async ({ ...rest }: TitleEscrowEndorseChangeOfOwnerCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); + const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); + await validateEndorseChangeOwner({ newHolder, newOwner, titleEscrow }); if (dryRun) { - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await validateEndorseChangeOwner({ newHolder, newOwner, titleEscrow }); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.transferToNewEscrow(newOwner, newHolder), + estimatedGas: await titleEscrow.estimateGas.transferOwners(newOwner, newHolder), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await validateEndorseChangeOwner({ newHolder, newOwner, titleEscrow }); - await titleEscrow.callStatic.transferToNewEscrow(newOwner, newHolder, { + await titleEscrow.callStatic.transferOwners(newOwner, newHolder, { gasPrice: gasPrice.mul(gasPriceScale), }); - const transaction = await titleEscrow.transferToNewEscrow(newOwner, newHolder, { + const transaction = await titleEscrow.transferOwners(newOwner, newHolder, { gasPrice: gasPrice.mul(gasPriceScale), }); trace(`Tx hash: ${transaction.hash}`); diff --git a/src/implementations/title-escrow/endorseTransferOfOwner.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts similarity index 76% rename from src/implementations/title-escrow/endorseTransferOfOwner.test.ts rename to src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts index 19188f07..ca1a09aa 100644 --- a/src/implementations/title-escrow/endorseTransferOfOwner.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts @@ -1,29 +1,30 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet, constants } from "ethers"; import { join } from "path"; -import { BaseTitleEscrowCommand as TitleEscrowEndorseTransferOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { endorseTransferOfOwner } from "./endorseTransferOfOwner"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { endorseNominatedBeneficiary } from "./endorseNominatedBeneficiary"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); -const endorseTransferOfOwnerParams: TitleEscrowEndorseTransferOfOwnerCommand = { +const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { tokenId: "0xzyxw", tokenRegistry: "0x1234", + newOwner: "0x1232", network: "ropsten", gasPriceScale: 1, dryRun: false, }; const GENESIS_ADDRESS = constants.AddressZero; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("endorse transfer of owner of transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTokenFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; @@ -56,7 +57,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockClear(); + mockedTradeTrustERC721Factory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); @@ -70,15 +71,15 @@ describe("title-escrow", () => { it("should take in the key from environment variable", async () => { process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - await endorseTransferOfOwner(endorseTransferOfOwnerParams); + await endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); }); it("should take in the key from key file", async () => { - await endorseTransferOfOwner({ - ...endorseTransferOfOwnerParams, + await endorseNominatedBeneficiary({ + ...endorseNominatedBeneficiaryParams, keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), }); @@ -88,16 +89,16 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke an endorsement of transfer of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await endorseTransferOfOwner({ - ...endorseTransferOfOwnerParams, + await endorseNominatedBeneficiary({ + ...endorseNominatedBeneficiaryParams, key: privateKey, }); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(endorseTransferOfOwnerParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(endorseTransferOfOwnerParams.tokenId); + expect(mockedConnectERC721).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenRegistry, passedSigner); + expect(mockedOwnerOf).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockGetApprovedBeneficiary).toHaveBeenCalledTimes(1); expect(mockGetApprovedHolder).toHaveBeenCalledTimes(1); @@ -110,8 +111,8 @@ describe("title-escrow", () => { mockGetApprovedHolder.mockReturnValue(GENESIS_ADDRESS); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( - endorseTransferOfOwner({ - ...endorseTransferOfOwnerParams, + endorseNominatedBeneficiary({ + ...endorseNominatedBeneficiaryParams, key: privateKey, }) ).rejects.toThrow( @@ -124,8 +125,8 @@ describe("title-escrow", () => { mockGetApprovedHolder.mockReturnValue(""); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( - endorseTransferOfOwner({ - ...endorseTransferOfOwnerParams, + endorseNominatedBeneficiary({ + ...endorseNominatedBeneficiaryParams, key: privateKey, }) ).rejects.toThrow( @@ -138,11 +139,11 @@ describe("title-escrow", () => { mockedConnectERC721.mockImplementation(() => { throw new Error("An Error"); }); - await expect(endorseTransferOfOwner(endorseTransferOfOwnerParams)).rejects.toThrow("An Error"); + await expect(endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams)).rejects.toThrow("An Error"); }); it("should throw when keys are not found anywhere", async () => { - await expect(endorseTransferOfOwner(endorseTransferOfOwnerParams)).rejects.toThrow( + await expect(endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams)).rejects.toThrow( "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" ); }); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts new file mode 100644 index 00000000..edec53e6 --- /dev/null +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts @@ -0,0 +1,52 @@ +import signale from "signale"; +import { getLogger } from "../../logger"; +import { getWalletOrSigner } from "../utils/wallet"; +import { connectToTitleEscrow, validateNominateBeneficiary } from "./helpers"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; + +import { dryRunMode } from "../utils/dryRun"; +import { TransactionReceipt } from "@ethersproject/providers"; + +const { trace } = getLogger("title-escrow:endorseTransferOfOwner"); + +export const endorseNominatedBeneficiary = async ({ + tokenRegistry: address, + tokenId, + newOwner, + network, + gasPriceScale, + dryRun, + ...rest +}: TitleEscrowNominateBeneficiaryCommand): Promise<{ + transactionReceipt: TransactionReceipt; + nominatedBeneficiary: string; +}> => { + const wallet = await getWalletOrSigner({ network, ...rest }); + const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); + const nominatedBeneficiary = newOwner; + await validateNominateBeneficiary({ beneficiaryNominee: nominatedBeneficiary, titleEscrow }); + if (dryRun) { + await dryRunMode({ + gasPriceScale: gasPriceScale, + estimatedGas: await titleEscrow.estimateGas.transferBeneficiary(nominatedBeneficiary), + network, + }); + process.exit(0); + } + const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); + await titleEscrow.callStatic.transferBeneficiary(nominatedBeneficiary, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + const transaction = await titleEscrow.transferBeneficiary(nominatedBeneficiary, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + const transactionReceipt = await transaction.wait(); + return { + transactionReceipt, + nominatedBeneficiary: nominatedBeneficiary, + }; +}; diff --git a/src/implementations/title-escrow/endorseTransferOfOwner.ts b/src/implementations/title-escrow/endorseTransferOfOwner.ts deleted file mode 100644 index 0c200ebd..00000000 --- a/src/implementations/title-escrow/endorseTransferOfOwner.ts +++ /dev/null @@ -1,58 +0,0 @@ -import signale from "signale"; -import { getLogger } from "../../logger"; -import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow, validateEndorseTransferOwner } from "./helpers"; -import { BaseTitleEscrowCommand as TitleEscrowEndorseTransferOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; - -import { dryRunMode } from "../utils/dryRun"; -import { TransactionReceipt } from "@ethersproject/providers"; - -const { trace } = getLogger("title-escrow:endorseTransferOfOwner"); - -export const endorseTransferOfOwner = async ({ - tokenRegistry: address, - tokenId, - network, - gasPriceScale, - dryRun, - ...rest -}: TitleEscrowEndorseTransferOfOwnerCommand): Promise<{ - transactionReceipt: TransactionReceipt; - approvedOwner: string; - approvedHolder: string; -}> => { - const wallet = await getWalletOrSigner({ network, ...rest }); - if (dryRun) { - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const approvedBeneficiary = await titleEscrow.approvedBeneficiary(); - const approvedHolder = await titleEscrow.approvedHolder(); - await validateEndorseTransferOwner({ approvedOwner: approvedBeneficiary, approvedHolder }); - await dryRunMode({ - gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.transferToNewEscrow(approvedBeneficiary, approvedHolder), - network, - }); - process.exit(0); - } - const gasPrice = await wallet.provider.getGasPrice(); - signale.await(`Sending transaction to pool`); - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const approvedBeneficiary = await titleEscrow.approvedBeneficiary(); - const approvedHolder = await titleEscrow.approvedHolder(); - await validateEndorseTransferOwner({ approvedOwner: approvedBeneficiary, approvedHolder }); - await titleEscrow.callStatic.transferToNewEscrow(approvedBeneficiary, approvedHolder, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await titleEscrow.transferToNewEscrow(approvedBeneficiary, approvedHolder, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - const transactionReceipt = await transaction.wait(); - return { - transactionReceipt, - approvedOwner: approvedBeneficiary, - approvedHolder, - }; -}; diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index 9809beff..bce43e05 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -1,4 +1,9 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { + TitleEscrow, + TitleEscrow__factory, + TradeTrustERC721, + TradeTrustERC721__factory, +} from "@govtechsg/token-registry/contracts"; import { Wallet, constants } from "ethers"; import signale from "signale"; import { ConnectedSigner } from "../utils/wallet"; @@ -9,23 +14,27 @@ interface ConnectToTitleEscrowArgs { wallet: Wallet | ConnectedSigner; } -type TitleEscrowInstanceType = ReturnType; - export const connectToTitleEscrow = async ({ tokenId, address, wallet, -}: ConnectToTitleEscrowArgs): Promise => { - const tokenRegistry = await TradeTrustErc721Factory.connect(address, wallet); +}: ConnectToTitleEscrowArgs): Promise => { + const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId); - const titleEscrow = await TitleEscrowFactory.connect(titleEscrowAddress, wallet); - return titleEscrow; + return await connectToTitleEscrowFactory(titleEscrowAddress, wallet); +}; + +export const connectToTitleEscrowFactory = async ( + titleEscrowAddress: string, + wallet: Wallet | ConnectedSigner +): Promise => { + return await TitleEscrow__factory.connect(titleEscrowAddress, wallet); }; interface validateEndorseChangeOwnerArgs { newHolder: string; newOwner: string; - titleEscrow: TitleEscrowInstanceType; + titleEscrow: TitleEscrow; } export const validateEndorseChangeOwner = async ({ newHolder, @@ -41,17 +50,17 @@ export const validateEndorseChangeOwner = async ({ } }; -interface validateNominateChangeOwnerArgs { - newOwner: string; - titleEscrow: TitleEscrowInstanceType; +interface validateNominateBeneficiaryArgs { + beneficiaryNominee: string; + titleEscrow: TitleEscrow; } -export const validateNominateChangeOwner = async ({ - newOwner, +export const validateNominateBeneficiary = async ({ + beneficiaryNominee, titleEscrow, -}: validateNominateChangeOwnerArgs): Promise => { +}: validateNominateBeneficiaryArgs): Promise => { const beneficiary = await titleEscrow.beneficiary(); - if (newOwner === beneficiary) { - const error = "new owner address is the same as the current owner address"; + if (beneficiaryNominee === beneficiary) { + const error = "new beneficiary address is the same as the current beneficiary address"; signale.error(error); throw new Error(error); } diff --git a/src/implementations/title-escrow/nominateChangeOfOwner.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts similarity index 61% rename from src/implementations/title-escrow/nominateChangeOfOwner.test.ts rename to src/implementations/title-escrow/nominateBeneficiary.test.ts index 6f4e2315..f384037e 100644 --- a/src/implementations/title-escrow/nominateChangeOfOwner.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -1,12 +1,12 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; -import { TitleEscrowNominateChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { nominateChangeOfOwner } from "./nominateChangeOfOwner"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { nominateBeneficiary } from "./nominateBeneficiary"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); -const nominateChangeOfOwnerParams: TitleEscrowNominateChangeOfOwnerCommand = { +const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { newOwner: "0fosui", tokenId: "0xzyxw", tokenRegistry: "0x1234", @@ -15,70 +15,70 @@ const nominateChangeOfOwnerParams: TitleEscrowNominateChangeOfOwnerCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("nominate change of owner of transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTokenFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; const mockedOwnerOf = jest.fn(); - const mockApproveNewTransferTargets = jest.fn(); + const mockNominateBeneficiary = jest.fn(); const mockedTitleEscrowAddress = "0x2133"; const mockedBeneficiary = "0xdssfs"; const mockedHolder = "0xdsfls"; const mockGetBeneficiary = jest.fn(); const mockGetHolder = jest.fn(); - const mockCallStaticApproveNewTransferTargets = jest.fn().mockResolvedValue(undefined); + const mockCallStaticNominateBeneficiary = jest.fn().mockResolvedValue(undefined); mockGetBeneficiary.mockResolvedValue(mockedBeneficiary); mockGetHolder.mockResolvedValue(mockedHolder); mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, }); mockedConnectTokenFactory.mockReturnValue({ - approveNewTransferTargets: mockApproveNewTransferTargets, + nominate: mockNominateBeneficiary, beneficiary: mockGetBeneficiary, holder: mockGetHolder, callStatic: { - approveNewTransferTargets: mockCallStaticApproveNewTransferTargets, + nominate: mockCallStaticNominateBeneficiary, }, }); mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); - mockApproveNewTransferTargets.mockReturnValue({ + mockNominateBeneficiary.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockClear(); + mockedTradeTrustERC721Factory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); mockedOwnerOf.mockClear(); - mockApproveNewTransferTargets.mockClear(); + mockNominateBeneficiary.mockClear(); mockGetBeneficiary.mockClear(); mockGetHolder.mockClear(); - mockCallStaticApproveNewTransferTargets.mockClear(); + mockCallStaticNominateBeneficiary.mockClear(); }); it("should take in the key from environment variable", async () => { process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - await nominateChangeOfOwner(nominateChangeOfOwnerParams); + await nominateBeneficiary(nominateBeneficiaryParams); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); }); it("should take in the key from key file", async () => { - await nominateChangeOfOwner({ - ...nominateChangeOfOwnerParams, + await nominateBeneficiary({ + ...nominateBeneficiaryParams, keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), }); @@ -88,32 +88,30 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke an nomination of change of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await nominateChangeOfOwner({ - ...nominateChangeOfOwnerParams, + await nominateBeneficiary({ + ...nominateBeneficiaryParams, key: privateKey, }); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(nominateChangeOfOwnerParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(nominateChangeOfOwnerParams.tokenId); + expect(mockedConnectERC721).toHaveBeenCalledWith(nominateBeneficiaryParams.tokenRegistry, passedSigner); + expect(mockedOwnerOf).toHaveBeenCalledWith(nominateBeneficiaryParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); - expect(mockGetHolder).toHaveBeenCalledTimes(1); - expect(mockGetBeneficiary).toHaveBeenCalledTimes(1); - expect(mockCallStaticApproveNewTransferTargets).toHaveBeenCalledTimes(1); - expect(mockApproveNewTransferTargets).toHaveBeenCalledTimes(1); + expect(mockCallStaticNominateBeneficiary).toHaveBeenCalledTimes(1); + expect(mockNominateBeneficiary).toHaveBeenCalledTimes(1); }); it("should throw an error if new owner addresses is the same as current owner", async () => { - mockGetBeneficiary.mockReturnValue(nominateChangeOfOwnerParams.newOwner); + mockGetBeneficiary.mockReturnValue(nominateBeneficiaryParams.newOwner); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( - nominateChangeOfOwner({ - ...nominateChangeOfOwnerParams, + nominateBeneficiary({ + ...nominateBeneficiaryParams, key: privateKey, }) - ).rejects.toThrow("new owner address is the same as the current owner address"); + ).rejects.toThrow("new beneficiary address is the same as the current beneficiary address"); }); it("should allow errors to bubble up", async () => { @@ -121,11 +119,11 @@ describe("title-escrow", () => { mockedConnectERC721.mockImplementation(() => { throw new Error("An Error"); }); - await expect(nominateChangeOfOwner(nominateChangeOfOwnerParams)).rejects.toThrow("An Error"); + await expect(nominateBeneficiary(nominateBeneficiaryParams)).rejects.toThrow("An Error"); }); it("should throw when keys are not found anywhere", async () => { - await expect(nominateChangeOfOwner(nominateChangeOfOwnerParams)).rejects.toThrow( + await expect(nominateBeneficiary(nominateBeneficiaryParams)).rejects.toThrow( "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" ); }); diff --git a/src/implementations/title-escrow/nominateChangeOfOwner.ts b/src/implementations/title-escrow/nominateBeneficiary.ts similarity index 55% rename from src/implementations/title-escrow/nominateChangeOfOwner.ts rename to src/implementations/title-escrow/nominateBeneficiary.ts index 792e6a84..d102d0ee 100644 --- a/src/implementations/title-escrow/nominateChangeOfOwner.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.ts @@ -1,15 +1,15 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow, validateNominateChangeOwner } from "./helpers"; -import { TitleEscrowNominateChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { connectToTitleEscrow, validateNominateBeneficiary } from "./helpers"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; const { trace } = getLogger("title-escrow:nominateChangeOfOwner"); -export const nominateChangeOfOwner = async ({ +export const nominateBeneficiary = async ({ tokenRegistry: address, tokenId, newOwner, @@ -17,28 +17,25 @@ export const nominateChangeOfOwner = async ({ gasPriceScale, dryRun, ...rest -}: TitleEscrowNominateChangeOfOwnerCommand): Promise => { +}: TitleEscrowNominateBeneficiaryCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); + const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); if (dryRun) { - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const holder = await titleEscrow.holder(); - await validateNominateChangeOwner({ newOwner, titleEscrow }); + await validateNominateBeneficiary({ beneficiaryNominee: newOwner, titleEscrow }); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.approveNewTransferTargets(newOwner, holder), + estimatedGas: await titleEscrow.estimateGas.nominate(newOwner), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const holder = await titleEscrow.holder(); - await validateNominateChangeOwner({ newOwner, titleEscrow }); - await titleEscrow.callStatic.approveNewTransferTargets(newOwner, holder, { + await validateNominateBeneficiary({ beneficiaryNominee: newOwner, titleEscrow }); + await titleEscrow.callStatic.nominate(newOwner, { gasPrice: gasPrice.mul(gasPriceScale), }); - const transaction = await titleEscrow.approveNewTransferTargets(newOwner, holder, { + const transaction = await titleEscrow.nominate(newOwner, { gasPrice: gasPrice.mul(gasPriceScale), }); trace(`Tx hash: ${transaction.hash}`); diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 2bda573c..7cc3a3b1 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -1,10 +1,10 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { rejectSurrendered } from "./rejectSurrendered"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", @@ -14,25 +14,25 @@ const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("rejects surrendered transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721Factory: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTitleEscrowFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTitleEscrowFactory: jest.Mock = mockedTitleEscrowFactory.connect; const mockedBeneficiary = jest.fn(); const mockedHolder = jest.fn(); - const mockSendToNewTitleEscrow = jest.fn(); + const mockRestoreTitle = jest.fn(); const mockTransferEvent = jest.fn(); const mockQueryFilter = jest.fn(); - const mockCallStaticSendToNewTitleEscrow = jest.fn().mockResolvedValue(undefined); + const mockCallStaticRestoreTitle = jest.fn().mockResolvedValue(undefined); const mockedLastTitleEscrowAddress = "0xMockedLastTitleEscrowAddress"; const mockedLastBeneficiary = "0xMockedLastBeneficiaryAddress"; @@ -40,14 +40,14 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockReset(); - mockedConnectERC721Factory.mockReset(); + mockedTradeTrustERC721Factory.mockReset(); + mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); mockedBeneficiary.mockReturnValue(mockedLastBeneficiary); mockedHolder.mockReturnValue(mockedLastHolder); - mockSendToNewTitleEscrow.mockReturnValue({ + mockRestoreTitle.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); @@ -65,21 +65,20 @@ describe("title-escrow", () => { beneficiary: mockedBeneficiary, holder: mockedHolder, }); - mockedConnectERC721Factory.mockReturnValue({ - sendToNewTitleEscrow: mockSendToNewTitleEscrow, + mockedConnectERC721.mockReturnValue({ + restore: mockRestoreTitle, filters: { Transfer: mockTransferEvent }, queryFilter: mockQueryFilter, callStatic: { - sendToNewTitleEscrow: mockCallStaticSendToNewTitleEscrow, + restore: mockCallStaticRestoreTitle, }, }); - mockedBeneficiary.mockClear(); mockedHolder.mockClear(); - mockSendToNewTitleEscrow.mockClear(); + mockRestoreTitle.mockClear(); mockTransferEvent.mockClear(); mockQueryFilter.mockClear(); - mockCallStaticSendToNewTitleEscrow.mockClear(); + mockCallStaticRestoreTitle.mockClear(); }); it("should take in the key from environment variable", async () => { @@ -87,7 +86,7 @@ describe("title-escrow", () => { await rejectSurrendered(rejectSurrenderedDocumentParams); - const passedSigner: Wallet = mockedConnectERC721Factory.mock.calls[0][1]; + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); }); @@ -97,7 +96,7 @@ describe("title-escrow", () => { keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), }); - const passedSigner: Wallet = mockedConnectERC721Factory.mock.calls[0][1]; + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); }); @@ -108,23 +107,17 @@ describe("title-escrow", () => { key: privateKey, }); - const passedSigner: Wallet = mockedConnectERC721Factory.mock.calls[0][1]; + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721Factory).toHaveBeenCalledWith( - rejectSurrenderedDocumentParams.tokenRegistry, - passedSigner - ); - expect(mockedConnectTitleEscrowFactory).toHaveBeenCalledWith(mockedLastTitleEscrowAddress, passedSigner); - expect(mockedBeneficiary).toHaveBeenCalledTimes(1); - expect(mockedHolder).toHaveBeenCalledTimes(1); - expect(mockCallStaticSendToNewTitleEscrow).toHaveBeenCalledTimes(1); - expect(mockSendToNewTitleEscrow).toHaveBeenCalledTimes(1); + expect(mockedConnectERC721).toHaveBeenCalledWith(rejectSurrenderedDocumentParams.tokenRegistry, passedSigner); + expect(mockCallStaticRestoreTitle).toHaveBeenCalledTimes(1); + expect(mockRestoreTitle).toHaveBeenCalledWith(rejectSurrenderedDocumentParams.tokenId); }); it("should allow errors to bubble up", async () => { process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721Factory.mockImplementation(() => { + mockedConnectERC721.mockImplementation(() => { throw new Error("An Error"); }); await expect(rejectSurrendered(rejectSurrenderedDocumentParams)).rejects.toThrow("An Error"); diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index 7144716c..42287165 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -1,30 +1,13 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; -import { ConnectedSigner, getWalletOrSigner } from "../utils/wallet"; +import { getWalletOrSigner } from "../utils/wallet"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { TradeTrustERC721 } from "@govtechsg/token-registry/dist/ts/contracts"; -import { Wallet } from "ethers"; const { trace } = getLogger("title-escrow:acceptSurrendered"); -const retrieveLastBeneficiaryAndHolder = async ( - tokenRegistryInstance: TradeTrustERC721, - tokenId: string, - wallet: Wallet | ConnectedSigner -): Promise<{ lastBeneficiary: string; lastHolder: string }> => { - // Fetch transfer logs from token registry - const transferLogFilter = tokenRegistryInstance.filters.Transfer(null, null, tokenId); - const logs = await tokenRegistryInstance.queryFilter(transferLogFilter, 0); - const lastTitleEscrowAddress = logs[logs.length - 1].args?.[0]; - const lastTitleEscrowInstance = await TitleEscrowFactory.connect(lastTitleEscrowAddress, wallet); - const lastBeneficiary = await lastTitleEscrowInstance.beneficiary(); - const lastHolder = await lastTitleEscrowInstance.holder(); - return { lastBeneficiary, lastHolder }; -}; - export const rejectSurrendered = async ({ tokenRegistry: address, tokenId, @@ -34,33 +17,19 @@ export const rejectSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance = await TradeTrustErc721Factory.connect(address, wallet); + const tokenRegistryInstance: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); if (dryRun) { - const { lastBeneficiary, lastHolder } = await retrieveLastBeneficiaryAndHolder( - tokenRegistryInstance, - tokenId, - wallet - ); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistryInstance.estimateGas.sendToNewTitleEscrow(lastBeneficiary, lastHolder, tokenId), + estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const { lastBeneficiary, lastHolder } = await retrieveLastBeneficiaryAndHolder( - tokenRegistryInstance, - tokenId, - wallet - ); - await tokenRegistryInstance.callStatic.sendToNewTitleEscrow(lastBeneficiary, lastHolder, tokenId, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await tokenRegistryInstance.sendToNewTitleEscrow(lastBeneficiary, lastHolder, tokenId, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + await tokenRegistryInstance.callStatic.restore(tokenId); + const transaction = await tokenRegistryInstance.restore(tokenId); + trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 734abfc8..d0653d59 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -1,10 +1,10 @@ -import { TitleEscrowFactory, TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { surrenderDocument } from "./surrenderDocument"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", @@ -14,32 +14,32 @@ const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("title-escrow", () => { describe("surrender transferable record", () => { - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustErc721Factory.connect; - const mockedTitleEscrowFactory: jest.Mock = TitleEscrowFactory as any; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTitleEscrowFactory: jest.Mock = mockedTitleEscrowFactory.connect; const mockedOwnerOf = jest.fn(); - const mockTransferTo = jest.fn(); - const mockCallStaticTransferTo = jest.fn().mockResolvedValue(undefined); + const mockSurrender = jest.fn(); + const mockCallStaticSurrender = jest.fn().mockResolvedValue(undefined); const mockedTitleEscrowAddress = "0x2133"; beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockReset(); + mockedTradeTrustERC721Factory.mockReset(); mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); - mockTransferTo.mockReturnValue({ + mockSurrender.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); @@ -47,15 +47,15 @@ describe("title-escrow", () => { ownerOf: mockedOwnerOf, }); mockedConnectTitleEscrowFactory.mockReturnValue({ - transferTo: mockTransferTo, + surrender: mockSurrender, callStatic: { - transferTo: mockCallStaticTransferTo, + surrender: mockCallStaticSurrender, }, }); mockedOwnerOf.mockClear(); - mockTransferTo.mockClear(); - mockCallStaticTransferTo.mockClear(); + mockSurrender.mockClear(); + mockCallStaticSurrender.mockClear(); }); it("should take in the key from environment variable", async () => { @@ -90,8 +90,8 @@ describe("title-escrow", () => { expect(mockedConnectERC721).toHaveBeenCalledWith(surrenderDocumentParams.tokenRegistry, passedSigner); expect(mockedOwnerOf).toHaveBeenCalledWith(surrenderDocumentParams.tokenId); expect(mockedConnectTitleEscrowFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); - expect(mockCallStaticTransferTo).toHaveBeenCalledTimes(1); - expect(mockTransferTo).toHaveBeenCalledTimes(1); + expect(mockCallStaticSurrender).toHaveBeenCalledTimes(1); + expect(mockSurrender).toHaveBeenCalledTimes(1); }); it("should allow errors to bubble up", async () => { diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index 3476f752..a38322bf 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -1,11 +1,13 @@ import signale from "signale"; import { getLogger } from "../../logger"; -import { getWalletOrSigner } from "../utils/wallet"; +import { ConnectedSigner, getWalletOrSigner } from "../utils/wallet"; import { connectToTitleEscrow } from "./helpers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; +import { ContractTransaction, Wallet } from "ethers"; +import { TitleEscrow } from "@govtechsg/token-registry/contracts"; const { trace } = getLogger("title-escrow:surrenderDocument"); @@ -18,22 +20,47 @@ export const surrenderDocument = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); + const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); + + const transaction: ContractTransaction = await surrendeDocument({ + tokenRegistry: address, + tokenId, + network, + gasPriceScale, + dryRun, + titleEscrow, + wallet, + }); + + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + return transaction.wait(); +}; + +export type VersionedTitleEscrowSurrenderDocumentCommand = TitleEscrowSurrenderDocumentCommand & { + titleEscrow: TitleEscrow; + wallet: Wallet | ConnectedSigner; +}; + +export const surrendeDocument = async ({ + network, + gasPriceScale, + dryRun, + titleEscrow, + wallet, +}: VersionedTitleEscrowSurrenderDocumentCommand): Promise => { if (dryRun) { - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.transferTo(address), + estimatedGas: await titleEscrow.estimateGas.surrender(), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await titleEscrow.callStatic.transferTo(address, { gasPrice: gasPrice.mul(gasPriceScale) }); - const transaction = await titleEscrow.transferTo(address, { gasPrice: gasPrice.mul(gasPriceScale) }); - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - return transaction.wait(); + await titleEscrow.callStatic.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); + const transaction = await titleEscrow.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); + return transaction; }; diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index 0c1fcb7c..f4df7047 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -1,11 +1,11 @@ -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { join } from "path"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { addAddressPrefix } from "../../utils"; import { issueToTokenRegistry } from "./issue"; -jest.mock("@govtechsg/token-registry"); +jest.mock("@govtechsg/token-registry/contracts"); const deployParams: TokenRegistryIssueCommand = { to: "0xabcd", @@ -16,40 +16,43 @@ const deployParams: TokenRegistryIssueCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustErc721Factory +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory // ideally must setup ganache, and run the function over it describe("token-registry", () => { describe("issue", () => { jest.setTimeout(30000); - const mockedTradeTrustErc721Factory: jest.Mock = TradeTrustErc721Factory as any; + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnect: jest.Mock = mockedTradeTrustErc721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; const mockedIssue = jest.fn(); const mockCallStaticSafeMint = jest.fn().mockResolvedValue(undefined); + + mockedIssue.mockReturnValue({ + hash: "hash", + wait: () => Promise.resolve({ transactionHash: "transactionHash" }), + }); + + const mockTTERC721Contract = { + mint: mockedIssue, + callStatic: { + mint: mockCallStaticSafeMint, + }, + }; + beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustErc721Factory.mockReset(); - mockedConnect.mockReset(); + mockedTradeTrustERC721Factory.mockClear(); mockCallStaticSafeMint.mockClear(); - mockedConnect.mockReturnValue({ - "safeMint(address,uint256)": mockedIssue, - callStatic: { - "safeMint(address,uint256)": mockCallStaticSafeMint, - }, - }); - mockedIssue.mockReturnValue({ - hash: "hash", - wait: () => Promise.resolve({ transactionHash: "transactionHash" }), - }); + mockedConnectERC721.mockReset(); + mockedConnectERC721.mockResolvedValue(mockTTERC721Contract); }); it("should take in the key from environment variable", async () => { process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; await issueToTokenRegistry(deployParams); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); }); @@ -59,7 +62,7 @@ describe("token-registry", () => { keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), }); - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); }); @@ -70,12 +73,12 @@ describe("token-registry", () => { key: privateKey, }); - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnect.mock.calls[0][0]).toEqual(deployParams.address); + expect(mockedConnectERC721.mock.calls[0][0]).toEqual(deployParams.address); expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.to); - expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.tokenId); + expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.to); + expect(mockedIssue.mock.calls[0][2]).toEqual(deployParams.tokenId); expect(mockCallStaticSafeMint).toHaveBeenCalledTimes(1); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); }); @@ -88,24 +91,16 @@ describe("token-registry", () => { tokenId: addAddressPrefix("zyxw"), }); - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnect.mock.calls[0][0]).toEqual(deployParams.address); + expect(mockedConnectERC721.mock.calls[0][0]).toEqual(deployParams.address); expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.to); - expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.tokenId); + expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.to); + expect(mockedIssue.mock.calls[0][2]).toEqual(deployParams.tokenId); expect(mockCallStaticSafeMint).toHaveBeenCalledTimes(1); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); }); - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnect.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(issueToTokenRegistry(deployParams)).rejects.toThrow("An Error"); - }); - it("should throw when keys are not found anywhere", async () => { await expect(issueToTokenRegistry(deployParams)).rejects.toThrow( "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" diff --git a/src/implementations/token-registry/issue.ts b/src/implementations/token-registry/issue.ts index 2c0e52d7..8f8f81ef 100644 --- a/src/implementations/token-registry/issue.ts +++ b/src/implementations/token-registry/issue.ts @@ -1,4 +1,4 @@ -import { TradeTrustErc721Factory } from "@govtechsg/token-registry"; +import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; @@ -18,22 +18,22 @@ export const issueToTokenRegistry = async ({ ...rest }: TokenRegistryIssueCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); + const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + if (dryRun) { - const tokenRegistry = await TradeTrustErc721Factory.connect(address, wallet); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistry.estimateGas["safeMint(address,uint256)"](to, tokenId), + estimatedGas: await tokenRegistry.estimateGas.mint(to, to, tokenId), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const erc721 = await TradeTrustErc721Factory.connect(address, wallet); - await erc721.callStatic["safeMint(address,uint256)"](to, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); - // must invoke the function manually, the lib doesn't handle overload functions - // https://github.com/ethereum-ts/TypeChain/issues/150 - const transaction = await erc721["safeMint(address,uint256)"](to, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + await tokenRegistry.callStatic.mint(to, to, tokenId, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + const transaction = await tokenRegistry.mint(to, to, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts new file mode 100644 index 00000000..c92229a3 --- /dev/null +++ b/src/implementations/token-registry/role/grant-role.test.ts @@ -0,0 +1,74 @@ +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { Wallet } from "ethers"; +import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { grantRoleToTokenRegistry } from "./grant-role"; + +jest.mock("@govtechsg/token-registry/contracts"); + +const roleParams: TokenRegistryRoleCommand = { + address: "0x1122", + role: "0x1", + recipient: "0x12345", + network: "ropsten", + gasPriceScale: 1, + dryRun: false, +}; + +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory +// ideally must setup ganache, and run the function over it +describe("token-registry", () => { + describe("grant role for token registry", () => { + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockGrantRole = jest.fn(); + const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); + + beforeEach(() => { + delete process.env.OA_PRIVATE_KEY; + mockedTradeTrustERC721Factory.mockReset(); + mockedConnectERC721.mockReset(); + + mockGrantRole.mockReturnValue({ + hash: "hash", + wait: () => Promise.resolve({ transactionHash: "transactionHash" }), + }); + + mockedConnectERC721.mockReturnValue({ + grantRole: mockGrantRole, + callStatic: { + grantRole: mockCallStaticGrantRole, + }, + }); + mockGrantRole.mockClear(); + mockCallStaticGrantRole.mockClear(); + }); + + it("should pass in the correct params and successfully accepts grant role", async () => { + const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; + await grantRoleToTokenRegistry({ + ...roleParams, + key: privateKey, + }); + + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; + + expect(passedSigner.privateKey).toBe(`0x${privateKey}`); + expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); + expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); + expect(mockGrantRole).toHaveBeenCalledTimes(1); + + expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); + expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); + }); + + it("should allow errors to bubble up", async () => { + process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; + mockGrantRole.mockImplementation(() => { + throw new Error("An Error"); + }); + await expect(grantRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); + }); + }); +}); diff --git a/src/implementations/token-registry/role/grant-role.ts b/src/implementations/token-registry/role/grant-role.ts new file mode 100644 index 00000000..433926bd --- /dev/null +++ b/src/implementations/token-registry/role/grant-role.ts @@ -0,0 +1,41 @@ +import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import signale from "signale"; +import { getLogger } from "../../../logger"; +import { getWalletOrSigner } from "../../utils/wallet"; +import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { dryRunMode } from "../../utils/dryRun"; +import { TransactionReceipt } from "@ethersproject/providers"; + +const { trace } = getLogger("token-registry:grant-role"); + +export const grantRoleToTokenRegistry = async ({ + address, + recipient, + role, + network, + gasPriceScale, + dryRun, + ...rest +}: TokenRegistryRoleCommand): Promise => { + const wallet = await getWalletOrSigner({ network, ...rest }); + const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + + if (dryRun) { + await dryRunMode({ + gasPriceScale: gasPriceScale, + estimatedGas: await tokenRegistry.estimateGas.grantRole(role, recipient), + network, + }); + process.exit(0); + } + const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); + await tokenRegistry.callStatic.grantRole(role, recipient, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + const transaction = await tokenRegistry.grantRole(role, recipient, { gasPrice: gasPrice.mul(gasPriceScale) }); + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + return transaction.wait(); +}; diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts new file mode 100644 index 00000000..bc67afc5 --- /dev/null +++ b/src/implementations/token-registry/role/revoke-role.test.ts @@ -0,0 +1,74 @@ +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { Wallet } from "ethers"; +import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { revokeRoleToTokenRegistry } from "./revoke-role"; + +jest.mock("@govtechsg/token-registry/contracts"); + +const roleParams: TokenRegistryRoleCommand = { + address: "0x1122", + role: "0x1", + recipient: "0x12345", + network: "ropsten", + gasPriceScale: 1, + dryRun: false, +}; + +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory +// ideally must setup ganache, and run the function over it +describe("token-registry", () => { + describe("revoke role for token registry", () => { + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockGrantRole = jest.fn(); + const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); + + beforeEach(() => { + delete process.env.OA_PRIVATE_KEY; + mockedTradeTrustERC721Factory.mockReset(); + mockedConnectERC721.mockReset(); + + mockGrantRole.mockReturnValue({ + hash: "hash", + wait: () => Promise.resolve({ transactionHash: "transactionHash" }), + }); + + mockedConnectERC721.mockReturnValue({ + revokeRole: mockGrantRole, + callStatic: { + revokeRole: mockCallStaticGrantRole, + }, + }); + mockGrantRole.mockClear(); + mockCallStaticGrantRole.mockClear(); + }); + + it("should pass in the correct params and successfully accepts revoked role", async () => { + const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; + await revokeRoleToTokenRegistry({ + ...roleParams, + key: privateKey, + }); + + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; + + expect(passedSigner.privateKey).toBe(`0x${privateKey}`); + expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); + expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); + expect(mockGrantRole).toHaveBeenCalledTimes(1); + + expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); + expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); + }); + + it("should allow errors to bubble up", async () => { + process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; + mockedConnectERC721.mockImplementation(() => { + throw new Error("An Error"); + }); + await expect(revokeRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); + }); + }); +}); diff --git a/src/implementations/token-registry/role/revoke-role.ts b/src/implementations/token-registry/role/revoke-role.ts new file mode 100644 index 00000000..330acccf --- /dev/null +++ b/src/implementations/token-registry/role/revoke-role.ts @@ -0,0 +1,41 @@ +import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import signale from "signale"; +import { getLogger } from "../../../logger"; +import { getWalletOrSigner } from "../../utils/wallet"; +import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { dryRunMode } from "../../utils/dryRun"; +import { TransactionReceipt } from "@ethersproject/providers"; + +const { trace } = getLogger("token-registry:revoke-role"); + +export const revokeRoleToTokenRegistry = async ({ + address, + recipient, + role, + network, + gasPriceScale, + dryRun, + ...rest +}: TokenRegistryRoleCommand): Promise => { + const wallet = await getWalletOrSigner({ network, ...rest }); + const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + + if (dryRun) { + await dryRunMode({ + gasPriceScale: gasPriceScale, + estimatedGas: await tokenRegistry.estimateGas.revokeRole(role, recipient), + network, + }); + process.exit(0); + } + const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); + await tokenRegistry.callStatic.revokeRole(role, recipient, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + const transaction = await tokenRegistry.revokeRole(role, recipient, { gasPrice: gasPrice.mul(gasPriceScale) }); + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + return transaction.wait(); +}; diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts new file mode 100644 index 00000000..3e628f4b --- /dev/null +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -0,0 +1,73 @@ +import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { Wallet } from "ethers"; +import { TokenRegistrySetRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { setRoleToTokenRegistry } from "./set-role"; + +jest.mock("@govtechsg/token-registry/contracts"); +const roleParams: TokenRegistrySetRoleCommand = { + address: "0x1122", + role: "0x1", + adminRole: "0x2", + network: "ropsten", + gasPriceScale: 1, + dryRun: false, +}; + +// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory +// ideally must setup ganache, and run the function over it +describe("token-registry", () => { + describe("set role for token registry", () => { + const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockGrantRole = jest.fn(); + const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); + + beforeEach(() => { + delete process.env.OA_PRIVATE_KEY; + mockedTradeTrustERC721Factory.mockReset(); + mockedConnectERC721.mockReset(); + + mockGrantRole.mockReturnValue({ + hash: "hash", + wait: () => Promise.resolve({ transactionHash: "transactionHash" }), + }); + + mockedConnectERC721.mockReturnValue({ + setRoleAdmin: mockGrantRole, + callStatic: { + setRoleAdmin: mockCallStaticGrantRole, + }, + }); + mockGrantRole.mockClear(); + mockCallStaticGrantRole.mockClear(); + }); + + it("should pass in the correct params and successfully accepts set role", async () => { + const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; + await setRoleToTokenRegistry({ + ...roleParams, + key: privateKey, + }); + + const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; + + expect(passedSigner.privateKey).toBe(`0x${privateKey}`); + expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); + expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); + expect(mockGrantRole).toHaveBeenCalledTimes(1); + + expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); + expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.adminRole); + }); + + it("should allow errors to bubble up", async () => { + process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; + mockedConnectERC721.mockImplementation(() => { + throw new Error("An Error"); + }); + await expect(setRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); + }); + }); +}); diff --git a/src/implementations/token-registry/role/set-role.ts b/src/implementations/token-registry/role/set-role.ts new file mode 100644 index 00000000..678c314e --- /dev/null +++ b/src/implementations/token-registry/role/set-role.ts @@ -0,0 +1,41 @@ +import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import signale from "signale"; +import { getLogger } from "../../../logger"; +import { getWalletOrSigner } from "../../utils/wallet"; +import { TokenRegistrySetRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { dryRunMode } from "../../utils/dryRun"; +import { TransactionReceipt } from "@ethersproject/providers"; + +const { trace } = getLogger("token-registry:set-role"); + +export const setRoleToTokenRegistry = async ({ + address, + role, + adminRole, + network, + gasPriceScale, + dryRun, + ...rest +}: TokenRegistrySetRoleCommand): Promise => { + const wallet = await getWalletOrSigner({ network, ...rest }); + const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + + if (dryRun) { + await dryRunMode({ + gasPriceScale: gasPriceScale, + estimatedGas: await tokenRegistry.estimateGas.setRoleAdmin(role, adminRole), + network, + }); + process.exit(0); + } + const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); + await tokenRegistry.callStatic.setRoleAdmin(role, adminRole, { + gasPrice: gasPrice.mul(gasPriceScale), + }); + const transaction = await tokenRegistry.setRoleAdmin(role, adminRole, { gasPrice: gasPrice.mul(gasPriceScale) }); + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + return transaction.wait(); +}; From b221d77a939a5ee8759464594b29f1cd55bd52d0 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Sep 2022 15:21:13 +0800 Subject: [PATCH 02/63] fix: added roles to token-registry issue --- src/commands/token-registry/issue.ts | 15 +++++++++++---- .../role/{set-role.ts => set-admin-role.ts} | 14 +++++++------- .../token-registry/token-registry-command.type.ts | 5 +++-- .../deploy/token-registry/token-registry.ts | 15 ++++++--------- src/implementations/token-registry/issue.test.ts | 11 ++++++----- src/implementations/token-registry/issue.ts | 9 +++++---- .../token-registry/role/set-role.test.ts | 10 +++++----- .../token-registry/role/set-role.ts | 6 +++--- 8 files changed, 46 insertions(+), 39 deletions(-) rename src/commands/token-registry/role/{set-role.ts => set-admin-role.ts} (75%) diff --git a/src/commands/token-registry/issue.ts b/src/commands/token-registry/issue.ts index 6eac80f7..2d527285 100644 --- a/src/commands/token-registry/issue.ts +++ b/src/commands/token-registry/issue.ts @@ -27,8 +27,13 @@ export const builder = (yargs: Argv): Argv => type: "string", demandOption: true, }) - .option("to", { - description: "Initial recipient of the tokenId", + .option("beneficiary", { + description: "Initial beneficiary of the tokenId", + type: "string", + demandOption: true, + }) + .option("holder", { + description: "Initial holder of the tokenId", type: "string", demandOption: true, }) @@ -38,13 +43,15 @@ export const builder = (yargs: Argv): Argv => export const handler = async (args: TokenRegistryIssueCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { - info(`Issuing ${args.tokenId} to the initial recipient ${args.to} in the registry ${args.address}`); + info( + `Issuing ${args.tokenId} to the initial recipient ${args.beneficiary} and initial holder ${args.holder} in the registry ${args.address}` + ); const { transactionHash } = await issueToTokenRegistry({ ...args, tokenId: addAddressPrefix(args.tokenId), }); success( - `Token with hash ${args.tokenId} has been issued on ${args.address} with the initial recipient being ${args.to}` + `Token with hash ${args.tokenId} has been issued on ${args.address} with the initial recipient being ${args.beneficiary} and initial holder ${args.holder}` ); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); return args.address; diff --git a/src/commands/token-registry/role/set-role.ts b/src/commands/token-registry/role/set-admin-role.ts similarity index 75% rename from src/commands/token-registry/role/set-role.ts rename to src/commands/token-registry/role/set-admin-role.ts index 3c9c52f0..490f11c1 100644 --- a/src/commands/token-registry/role/set-role.ts +++ b/src/commands/token-registry/role/set-admin-role.ts @@ -1,17 +1,17 @@ import { Argv } from "yargs"; import { error, info, success } from "signale"; import { getLogger } from "../../../logger"; -import { TokenRegistrySetRoleCommand } from "../token-registry-command.type"; +import { TokenRegistrySetRoleAdminCommand } from "../token-registry-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; import { getErrorMessage, getEtherscanAddress } from "../../../utils"; import { getRoleEnumValue, normalRolesInput, adminRolesInput } from "./helper"; -import { setRoleToTokenRegistry } from "../../../implementations/token-registry/role/set-role"; +import { setRoleAdminTokenRegistry } from "../../../implementations/token-registry/role/set-role"; -const { trace } = getLogger("token-registry:set-roles"); +const { trace } = getLogger("token-registry:set-role-admin"); -export const command = "set-role [options]"; +export const command = "set-admin-role [options]"; -export const describe = "Set Role of Token Registry"; +export const describe = "Set Admin Role to Role of Token Registry"; export const builder = (yargs: Argv): Argv => withGasPriceOption( @@ -40,11 +40,11 @@ export const builder = (yargs: Argv): Argv => ) ); -export const handler = async (args: TokenRegistrySetRoleCommand): Promise => { +export const handler = async (args: TokenRegistrySetRoleAdminCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info(`Setting ${args.adminRole} to the recipient role ${args.role} in the registry ${args.address}`); - const { transactionHash } = await setRoleToTokenRegistry({ + const { transactionHash } = await setRoleAdminTokenRegistry({ ...args, role: getRoleEnumValue(args.role), adminRole: getRoleEnumValue(args.adminRole), diff --git a/src/commands/token-registry/token-registry-command.type.ts b/src/commands/token-registry/token-registry-command.type.ts index 9bfa4470..f336f759 100644 --- a/src/commands/token-registry/token-registry-command.type.ts +++ b/src/commands/token-registry/token-registry-command.type.ts @@ -3,7 +3,8 @@ import { GasOption, NetworkAndWalletSignerOption } from "../shared"; export type TokenRegistryIssueCommand = NetworkAndWalletSignerOption & GasOption & { address: string; - to: string; + beneficiary: string; + holder: string; tokenId: string; }; @@ -14,7 +15,7 @@ export type TokenRegistryRoleCommand = NetworkAndWalletSignerOption & recipient: string; }; -export type TokenRegistrySetRoleCommand = NetworkAndWalletSignerOption & +export type TokenRegistrySetRoleAdminCommand = NetworkAndWalletSignerOption & GasOption & { address: string; role: string; diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index f0bfe8ac..fdd74685 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -21,23 +21,20 @@ export const deployTokenRegistry = async ({ const wallet = await getWalletOrSigner({ network, ...rest }); const factory = new TradeTrustERC721__factory(wallet); const chainId = await wallet.getChainId(); - const deployerAddress = await wallet.getAddress(); const { contractAddress } = constants; - if (!chainId) { - throw new Error(`Invalid chain ID: ${chainId}`); - } - - console.log(`[Deployer] ${deployerAddress}`); - if (!factoryAddress) { + if (!chainId) { + throw new Error(`Invalid chain ID: ${chainId}`); + } factoryAddress = contractAddress.TitleEscrowFactory[chainId]; if (!factoryAddress) { - throw new Error(`Network ${network} currently is not supported. Supply a factory address.`); + throw new Error(`Network ${network} currently is not supported. Supply a factory address.`) ; } - console.log(`[Status] Using ${factoryAddress} as Title Escrow factory.`); } + signale.info(`Using ${factoryAddress} as Title Escrow factory.`); + if (dryRun) { const tx = factory.getDeployTransaction(registryName, registrySymbol, factoryAddress, {}); await dryRunMode({ diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index f4df7047..d0493488 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -8,7 +8,8 @@ import { issueToTokenRegistry } from "./issue"; jest.mock("@govtechsg/token-registry/contracts"); const deployParams: TokenRegistryIssueCommand = { - to: "0xabcd", + beneficiary: "0xabcd", + holder: "0xabce", tokenId: "0xzyxw", address: "0x1234", network: "ropsten", @@ -76,8 +77,8 @@ describe("token-registry", () => { const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721.mock.calls[0][0]).toEqual(deployParams.address); - expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.to); - expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.to); + expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.beneficiary); + expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.holder); expect(mockedIssue.mock.calls[0][2]).toEqual(deployParams.tokenId); expect(mockCallStaticSafeMint).toHaveBeenCalledTimes(1); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); @@ -94,8 +95,8 @@ describe("token-registry", () => { const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721.mock.calls[0][0]).toEqual(deployParams.address); - expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.to); - expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.to); + expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.beneficiary); + expect(mockedIssue.mock.calls[0][1]).toEqual(deployParams.holder); expect(mockedIssue.mock.calls[0][2]).toEqual(deployParams.tokenId); expect(mockCallStaticSafeMint).toHaveBeenCalledTimes(1); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); diff --git a/src/implementations/token-registry/issue.ts b/src/implementations/token-registry/issue.ts index 8f8f81ef..467881a2 100644 --- a/src/implementations/token-registry/issue.ts +++ b/src/implementations/token-registry/issue.ts @@ -10,7 +10,8 @@ const { trace } = getLogger("token-registry:issue"); export const issueToTokenRegistry = async ({ address, - to, + beneficiary, + holder, tokenId, network, gasPriceScale, @@ -23,17 +24,17 @@ export const issueToTokenRegistry = async ({ if (dryRun) { await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistry.estimateGas.mint(to, to, tokenId), + estimatedGas: await tokenRegistry.estimateGas.mint(beneficiary, holder, tokenId), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - await tokenRegistry.callStatic.mint(to, to, tokenId, { + await tokenRegistry.callStatic.mint(beneficiary, holder, tokenId, { gasPrice: gasPrice.mul(gasPriceScale), }); - const transaction = await tokenRegistry.mint(to, to, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + const transaction = await tokenRegistry.mint(beneficiary, holder, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts index 3e628f4b..9fb34423 100644 --- a/src/implementations/token-registry/role/set-role.test.ts +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -1,10 +1,10 @@ import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { TokenRegistrySetRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { setRoleToTokenRegistry } from "./set-role"; +import { TokenRegistrySetRoleAdminCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { setRoleAdminTokenRegistry } from "./set-role"; jest.mock("@govtechsg/token-registry/contracts"); -const roleParams: TokenRegistrySetRoleCommand = { +const roleParams: TokenRegistrySetRoleAdminCommand = { address: "0x1122", role: "0x1", adminRole: "0x2", @@ -46,7 +46,7 @@ describe("token-registry", () => { it("should pass in the correct params and successfully accepts set role", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await setRoleToTokenRegistry({ + await setRoleAdminTokenRegistry({ ...roleParams, key: privateKey, }); @@ -67,7 +67,7 @@ describe("token-registry", () => { mockedConnectERC721.mockImplementation(() => { throw new Error("An Error"); }); - await expect(setRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); + await expect(setRoleAdminTokenRegistry(roleParams)).rejects.toThrow("An Error"); }); }); }); diff --git a/src/implementations/token-registry/role/set-role.ts b/src/implementations/token-registry/role/set-role.ts index 678c314e..6ce63142 100644 --- a/src/implementations/token-registry/role/set-role.ts +++ b/src/implementations/token-registry/role/set-role.ts @@ -2,13 +2,13 @@ import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-re import signale from "signale"; import { getLogger } from "../../../logger"; import { getWalletOrSigner } from "../../utils/wallet"; -import { TokenRegistrySetRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { TokenRegistrySetRoleAdminCommand } from "../../../commands/token-registry/token-registry-command.type"; import { dryRunMode } from "../../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; const { trace } = getLogger("token-registry:set-role"); -export const setRoleToTokenRegistry = async ({ +export const setRoleAdminTokenRegistry = async ({ address, role, adminRole, @@ -16,7 +16,7 @@ export const setRoleToTokenRegistry = async ({ gasPriceScale, dryRun, ...rest -}: TokenRegistrySetRoleCommand): Promise => { +}: TokenRegistrySetRoleAdminCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); From e3ec56bd305b65dfa65bcd7d24c7fe6b836c255d Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Sep 2022 16:25:51 +0800 Subject: [PATCH 03/63] fix: rolesInput datatype --- src/commands/token-registry/role/helper.ts | 24 +++++++++---------- .../deploy/token-registry/token-registry.ts | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/commands/token-registry/role/helper.ts b/src/commands/token-registry/role/helper.ts index 6a66a4c3..d77fc0ad 100644 --- a/src/commands/token-registry/role/helper.ts +++ b/src/commands/token-registry/role/helper.ts @@ -1,14 +1,14 @@ import { constants } from "@govtechsg/token-registry"; -export const rolesInput = [ - ["default-admin", constants.roleHash.DefaultAdmin], - ["minter", constants.roleHash.MinterRole], - ["accepter", constants.roleHash.AccepterRole], - ["restorer", constants.roleHash.RestorerRole], - ["minter-admin", constants.roleHash.MinterAdminRole], - ["accepter-admin", constants.roleHash.AccepterAdminRole], - ["restorer-admin", constants.roleHash.RestorerAdminRole], -]; +export const rolesInput: Record = { + "default-admin": constants.roleHash.DefaultAdmin, + minter: constants.roleHash.MinterRole, + accepter: constants.roleHash.AccepterRole, + restorer: constants.roleHash.RestorerRole, + "minter-admin": constants.roleHash.MinterAdminRole, + "accepter-admin": constants.roleHash.AccepterAdminRole, + "restorer-admin": constants.roleHash.RestorerAdminRole, +}; export const getAllRolesInput = (): string[] => { return [...adminRolesInput, ...normalRolesInput]; @@ -18,10 +18,8 @@ export const adminRolesInput = ["default-admin", "minter-admin", "accepter-admin export const normalRolesInput = ["minter", "accepter", "restorer"]; export const getRoleEnumValue = (roleNameInString: string): string => { - for (const roleIndex in rolesInput) { - if (rolesInput[roleIndex][0] === roleNameInString) { - return rolesInput[roleIndex][1]; - } + if (!(roleNameInString in rolesInput)) { + return rolesInput[roleNameInString]; } throw new Error("Invalid Role"); }; diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index fdd74685..f89f8b60 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -29,7 +29,7 @@ export const deployTokenRegistry = async ({ } factoryAddress = contractAddress.TitleEscrowFactory[chainId]; if (!factoryAddress) { - throw new Error(`Network ${network} currently is not supported. Supply a factory address.`) ; + throw new Error(`Network ${network} currently is not supported. Supply a factory address.`); } } From 674d817e5b0342123f3bf6ed9ea23474782bd156 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Sep 2022 17:50:26 +0800 Subject: [PATCH 04/63] feat: updated README --- README.md | 56 +++++++++++++++++++++++++-- src/commands/deploy/token-registry.ts | 2 +- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 50de1fe1..12c90d7d 100644 --- a/README.md +++ b/README.md @@ -254,7 +254,7 @@ open-attestation decrypt ./src/__tests__/fixture/did-dns-encrypted.json decrypte Deploys a token registry contract on the blockchain ```bash -open-attestation deploy token-registry [options] +open-attestation deploy token-registry --factory-address [options] ``` Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). @@ -270,7 +270,7 @@ open-attestation deploy token-registry "My Sample Token" MST --network ropsten `Issue` a hash to a token registry deployed on the blockchain. The `tokenId` option would be used to indicate the document hash, and the `to` option to indicate the title escrow address the document is mapped to. ```bash -open-attestation token-registry issue --network --address --tokenId --to [options] +open-attestation token-registry issue --network --address --tokenId --beneficiary --holder [options] ``` Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). @@ -284,6 +284,56 @@ open-attestation token-registry mint --network ropsten --address 0x6133f580aE903 `mint` can be used instead of issue and will be strictly equivalent. +#### Token Registry Roles - Grant + +Assign a role to a wallet address on the token registry deployed on the blockchain. The `recipient` option to indicate the wallet address that will be assigned the role, and the `role` option would be used to indicate the role given to the wallet address on the token registry. + +```bash +open-attestation token-registry role grant-role --network --address --recipient --role [options] +``` + +Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). + +```bash +open-attestation token-registry role grant-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role restorer --recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 + +✔ success Role restorer has been assigned to the recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 +``` + +#### Token Registry Roles - Revoke + +Revoke a role of a wallet address on the token registry deployed on the blockchain. The `recipient` option indicates the wallet address that will be revoked of the role, and the `role` option would be used to indicate the role to be revoked from the wallet address on the token registry. + +```bash +open-attestation token-registry role revoke-role --network --address --recipient --role [options] +``` + +Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). + +```bash +open-attestation token-registry role revoke-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role restorer --recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 + +✔ success Role restorer has been revoked from the recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 +``` + + +#### Token Registry Roles - Set Role + +Set role on the token registry to be have additional admin roles on the blockchain. The `role` option is the role to be provided additional roles, and the `adminRole` option sets the additional role granted to the `role`. + +```bash +open-attestation token-registry role set-role --network --address --role --adminRole [options] +``` + +Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). + +```bash +0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 +open-attestation token-registry role set-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role minter --adminRole minterAdmin + +✔ success Role minterAdmin has been assigned to the recipient minter in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 +``` + ### Document Store #### Deploy new document store @@ -595,7 +645,7 @@ This command will allow the holder of the transferable record to endorse the tra **This command will fail if there is no approved owner or holder record on the transferable record.** ```bash -open-attestation title-escrow endorse-transfer-owner --token-registry --tokenId [options] +open-attestation title-escrow endorse-transfer-owner --token-registry --tokenId --newOwner [options] ``` Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index f8b1c974..3fd8093d 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -26,7 +26,7 @@ export const builder = (yargs: Argv): Argv => description: "Symbol of the token (typically 3 characters)", normalize: true, }) - .positional("factory-address", { + .option("factory-address", { description: "Address of Token Registry factory (Optional)", normalize: true, }) From 7ddd12e72766cb3186901ed2749b5e64903204cf Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 13 Sep 2022 15:24:38 +0800 Subject: [PATCH 05/63] feat: e2e tests (wip) --- package-lock.json | 283 +++++++++++++++++++++++ package.json | 1 + src/__tests__/token-registry.e2e.test.ts | 255 ++++++++++++++++++++ 3 files changed, 539 insertions(+) create mode 100644 src/__tests__/token-registry.e2e.test.ts diff --git a/package-lock.json b/package-lock.json index a1bd0836..e7b478a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7905,6 +7905,289 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "ganache": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.4.3.tgz", + "integrity": "sha512-RpEDUiCkqbouyE7+NMXG26ynZ+7sGiODU84Kz+FVoXUnQ4qQM4M8wif3Y4qUCt+D/eM1RVeGq0my62FPD6Y1KA==", + "requires": { + "@trufflesuite/bigint-buffer": "1.1.10", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "5.1.1", + "@types/seedrandom": "3.0.1", + "bufferutil": "4.0.5", + "emittery": "0.10.0", + "keccak": "3.0.2", + "leveldown": "6.1.0", + "secp256k1": "4.0.3", + "utf-8-validate": "5.0.7" + }, + "dependencies": { + "@trufflesuite/bigint-buffer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz", + "integrity": "sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==", + "requires": { + "node-gyp-build": "4.4.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" + } + } + }, + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==" + }, + "@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" + }, + "@types/seedrandom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.1.tgz", + "integrity": "sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw==" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "bufferutil": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", + "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "catering": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", + "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", + "requires": { + "queue-tick": "^1.0.0" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==" + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "leveldown": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", + "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", + "requires": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "dependencies": { + "abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "requires": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + } + }, + "level-concat-iterator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "requires": { + "catering": "^2.1.0" + } + }, + "level-supports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==" + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "queue-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", + "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==" + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "utf-8-validate": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", + "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + } + } + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", diff --git a/package.json b/package.json index 06426cc7..1f7dd13c 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "debug": "^4.3.2", "ethers": "^5.4.7", "ethers-aws-kms-signer": "^1.3.2", + "ganache": "^7.4.3", "inquirer": "^8.0.0", "mkdirp": "^1.0.4", "node-fetch": "^2.6.1", diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts new file mode 100644 index 00000000..a0e71506 --- /dev/null +++ b/src/__tests__/token-registry.e2e.test.ts @@ -0,0 +1,255 @@ +import { ethers, Wallet } from "ethers"; +import { DeployTokenRegistryCommand } from "../commands/deploy/deploy.types"; +import { NetworkOption, WalletOrSignerOption } from "../commands/shared"; +import { + BaseTitleEscrowCommand, + TitleEscrowChangeHolderCommand, + TitleEscrowEndorseChangeOfOwnerCommand, + TitleEscrowNominateChangeOfOwnerCommand, +} from "../commands/title-escrow/title-escrow-command.type"; +import { TokenRegistryIssueCommand } from "../commands/token-registry/token-registry-command.type"; +import { deployTokenRegistry } from "../implementations/deploy/token-registry"; +import { surrenderDocument } from "../implementations/title-escrow/surrenderDocument"; +import { issueToTokenRegistry } from "../implementations/token-registry/issue"; +import { progress as defaultProgress } from "../implementations/utils/progress"; +import { ConnectedSigner, getWalletOrSigner } from "../implementations/utils/wallet"; +import { TransactionReceipt } from "@ethersproject/providers"; +import { acceptSurrendered } from "../implementations/title-escrow/acceptSurrendered"; +import { rejectSurrendered } from "../implementations/title-escrow/rejectSurrendered"; +import { changeHolderOfTitleEscrow } from "../implementations/title-escrow/changeHolder"; +import { nominateChangeOfOwner } from "../implementations/title-escrow/nominateChangeOfOwner"; +import { endorseTransferOfOwner } from "../implementations/title-escrow/endorseTransferOfOwner"; +import { endorseChangeOfOwner } from "../implementations/title-escrow/endorseChangeOfOwner"; + +import ganache from "ganache"; + +jest.mock("../implementations/utils/wallet", () => { + const originalModule = jest.requireActual("../implementations/utils/wallet"); + return { + __esModule: true, + ...originalModule, + getWalletOrSigner: jest.fn(), + }; +}); + +const accounts = { + mnemonic: "indicate swing place chair flight used hammer soon photo region volume shuffle", + owner: { + ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", + publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", + privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", + }, + receiver: { + ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", + publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", + privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", + }, +}; + +const ganacheOptions = { + mnemonic: accounts.mnemonic, +}; +const regexEthAddress = new RegExp("^0x[a-fA-F0-9]{40}$"); + +describe("token-registry", () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedGetWalletOrSigner: jest.Mock = getWalletOrSigner as jest.Mock; + + let tokenRegistryAddress = ""; + const defaults = { + network: "mainnet", + gasPriceScale: 1, + dryRun: false, + }; + + beforeAll(() => { + const provider = new ethers.providers.Web3Provider(ganache.provider(ganacheOptions)); + mockedGetWalletOrSigner.mockImplementation( + async ({ + network, + progress = defaultProgress("Decrypting Wallet"), + ...options + }: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< + Wallet | ConnectedSigner + > => { + const wallet = await ethers.Wallet.fromMnemonic(accounts.mnemonic, "m/44'/60'/0'/0/0"); + const connectedWallet = wallet.connect(provider); + return connectedWallet; + } + ); + }); + + it("should be able to deploy token-registry", async () => { + const tokenRegistryParameter: DeployTokenRegistryCommand = { + registryName: "Test Token", + registrySymbol: "TKN", + ...defaults, + }; + const tokenRegistryTransaction = await deployTokenRegistry(tokenRegistryParameter); + expect(tokenRegistryTransaction.confirmations).toBeGreaterThanOrEqual(1); + expect(tokenRegistryTransaction.status).toBe(1); + const validTokenRegistryDeploy = regexEthAddress.test(tokenRegistryTransaction.contractAddress); + expect(validTokenRegistryDeploy).toBe(true); + tokenRegistryAddress = tokenRegistryTransaction.contractAddress; + }); + + const mintTransactionParameter = { + to: accounts.owner.ethAddress, + ...defaults, + }; + + const mintTransaction = async ( + retrievedTokenRegistryAddress: string, + tokenId: string + ): Promise => { + const transactionParameter: TokenRegistryIssueCommand = { + address: retrievedTokenRegistryAddress, + tokenId: tokenId, + ...mintTransactionParameter, + }; + const transaction = await issueToTokenRegistry(transactionParameter); + return transaction; + }; + + it("should be able to mint title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000000"; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + const transaction = await mintTransaction(retrievedTokenRegistryAddress, tokenId); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + + describe("title-escrow surrender", () => { + const surrenderTransaction = async ( + retrievedTokenRegistryAddress: string, + tokenId: string + ): Promise => { + const transactionParameter: BaseTitleEscrowCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + ...defaults, + }; + const transaction = await surrenderDocument(transactionParameter); + return transaction; + }; + + it("should be able to surrender title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000001"; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transaction = await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + + describe("title-escrow surrender response", () => { + it("should be able to accept surrender title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000002"; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: BaseTitleEscrowCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + ...defaults, + }; + const transaction = await acceptSurrendered(transactionParameter); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + + it("should be able to reject surrender title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000003"; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: BaseTitleEscrowCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + ...defaults, + }; + const transaction = await rejectSurrendered(transactionParameter); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + }); + }); + + describe("title-escrow transfer", () => { + it("should be able to change holder of title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000004"; + const destinationWalletAddress = accounts.receiver.ethAddress; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: TitleEscrowChangeHolderCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + to: destinationWalletAddress, + ...defaults, + }; + const transaction = await changeHolderOfTitleEscrow(transactionParameter); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + + it("should be able to nominate change of holder of title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000005"; + const destinationWalletAddress = accounts.receiver.ethAddress; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: TitleEscrowNominateChangeOfOwnerCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + newOwner: destinationWalletAddress, + ...defaults, + }; + const transaction = await nominateChangeOfOwner(transactionParameter); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + + it("should be able to endorse transfer of owner of title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000006"; + const destinationWalletAddress = accounts.receiver.ethAddress; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: BaseTitleEscrowCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + ...defaults, + }; + const transaction = await endorseTransferOfOwner(transactionParameter); + expect(transaction.transactionReceipt.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.transactionReceipt.status).toBe(1); + // TODO expect approvedOwner/approvedHolder + }); + + it("should be able to endorse change of owner of title-escrow", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000007"; + const destinationWalletAddress = accounts.receiver.ethAddress; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: TitleEscrowEndorseChangeOfOwnerCommand = { + tokenId: tokenId, + tokenRegistry: retrievedTokenRegistryAddress, + newHolder: destinationWalletAddress, + newOwner: destinationWalletAddress, + ...defaults, + }; + const transaction = await endorseChangeOfOwner(transactionParameter); + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); + }); + }); + + const getTokenRegistryAddress = async (): Promise => { + if (tokenRegistryAddress === "") { + const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + await delay(3000); + return await getTokenRegistryAddress(); + } else { + return tokenRegistryAddress; + } + }; +}); From b61727f4f91342c652fef1df1895c5f95cee689a Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 13 Sep 2022 16:43:55 +0800 Subject: [PATCH 06/63] feat: remove redundant tests --- .../document-store/issue.test.ts | 36 ------------- .../document-store/revoke.test.ts | 53 +------------------ .../document-store/transfer-ownership.test.ts | 53 +------------------ .../title-escrow/acceptSurrendered.test.ts | 36 +------------ .../title-escrow/changeHolder.test.ts | 20 +------ .../title-escrow/changeOwner.test.ts | 35 +----------- .../endorseNominatedBeneficiary.test..ts | 35 +----------- .../title-escrow/nominateBeneficiary.test.ts | 35 +----------- .../title-escrow/rejectSurrendered.test.ts | 35 +----------- .../title-escrow/surrenderDocument.test.ts | 36 +------------ .../token-registry/issue.test.ts | 20 +------ .../token-registry/role/grant-role.test.ts | 8 --- .../token-registry/role/revoke-role.test.ts | 8 --- .../token-registry/role/set-role.test.ts | 8 --- 14 files changed, 10 insertions(+), 408 deletions(-) diff --git a/src/implementations/document-store/issue.test.ts b/src/implementations/document-store/issue.test.ts index 578e9b96..dd983854 100644 --- a/src/implementations/document-store/issue.test.ts +++ b/src/implementations/document-store/issue.test.ts @@ -1,5 +1,4 @@ import { issueToDocumentStore } from "./issue"; -import { join } from "path"; import { Wallet } from "ethers"; import { DocumentStoreFactory } from "@govtechsg/document-store"; import { DocumentStoreIssueCommand } from "../../commands/document-store/document-store-command.type"; @@ -61,20 +60,6 @@ describe("document-store", () => { expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); }); - it("should take in the key from key file", async () => { - await issueToDocumentStore({ - hash: "0xabcd", - address: "0x1234", - network: "ropsten", - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and return the deployed instance", async () => { const instance = await issueToDocumentStore(deployParams); @@ -98,26 +83,5 @@ describe("document-store", () => { expect(mockedIssue.mock.calls[0][0]).toEqual(deployParams.hash); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); }); - - it("should allow errors to bubble up", async () => { - mockedConnect.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(issueToDocumentStore(deployParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect( - issueToDocumentStore({ - hash: "0xabcd", - address: "0x1234", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }) - ).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" - ); - }); }); }); diff --git a/src/implementations/document-store/revoke.test.ts b/src/implementations/document-store/revoke.test.ts index 9f18629a..3280a162 100644 --- a/src/implementations/document-store/revoke.test.ts +++ b/src/implementations/document-store/revoke.test.ts @@ -1,5 +1,5 @@ import { revokeToDocumentStore } from "./revoke"; -import { join } from "path"; + import { Wallet } from "ethers"; import { DocumentStoreFactory } from "@govtechsg/document-store"; import { DocumentStoreRevokeCommand } from "../../commands/document-store/document-store-command.type"; @@ -45,36 +45,6 @@ describe("document-store", () => { wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await revokeToDocumentStore({ - hash: "0xabcd", - address: "0x1234", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await revokeToDocumentStore({ - hash: "0xabcd", - address: "0x1234", - network: "ropsten", - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and return the deployed instance", async () => { const instance = await revokeToDocumentStore(deployParams); @@ -98,26 +68,5 @@ describe("document-store", () => { expect(mockedRevoke.mock.calls[0][0]).toEqual(deployParams.hash); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); }); - - it("should allow errors to bubble up", async () => { - mockedConnect.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(revokeToDocumentStore(deployParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect( - revokeToDocumentStore({ - hash: "0xabcd", - address: "0x1234", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }) - ).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" - ); - }); }); }); diff --git a/src/implementations/document-store/transfer-ownership.test.ts b/src/implementations/document-store/transfer-ownership.test.ts index 10900b45..d59b35e9 100644 --- a/src/implementations/document-store/transfer-ownership.test.ts +++ b/src/implementations/document-store/transfer-ownership.test.ts @@ -1,5 +1,5 @@ import { transferDocumentStoreOwnershipToWallet } from "./transfer-ownership"; -import { join } from "path"; + import { Wallet } from "ethers"; import { DocumentStoreFactory } from "@govtechsg/document-store"; import { DocumentStoreTransferOwnershipCommand } from "../../commands/document-store/document-store-command.type"; @@ -45,36 +45,6 @@ describe("document-store", () => { wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await transferDocumentStoreOwnershipToWallet({ - newOwner: "0xabcd", - address: "0x1234", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await transferDocumentStoreOwnershipToWallet({ - newOwner: "0xabcd", - address: "0x1234", - network: "ropsten", - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedConnect.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and return the deployed instance", async () => { const instance = await transferDocumentStoreOwnershipToWallet(deployParams); @@ -101,26 +71,5 @@ describe("document-store", () => { expect(mockedTransfer.mock.calls[0][0]).toEqual(deployParams.newOwner); expect(instance).toStrictEqual({ transactionHash: "transactionHash" }); }); - - it("should allow errors to bubble up", async () => { - mockedConnect.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(transferDocumentStoreOwnershipToWallet(deployParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect( - transferDocumentStoreOwnershipToWallet({ - newOwner: "0xabcd", - address: "0x1234", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, - }) - ).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" - ); - }); }); }); diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 0e564235..8637a291 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -1,6 +1,6 @@ import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { acceptSurrendered } from "./acceptSurrendered"; @@ -44,26 +44,6 @@ describe("title-escrow", () => { mockBurnToken.mockClear(); mockCallStaticBurnToken.mockClear(); }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await acceptSurrendered(acceptSurrenderedDocumentParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await acceptSurrendered({ - ...acceptSurrenderedDocumentParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and successfully accepts a surrendered transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await acceptSurrendered({ @@ -78,19 +58,5 @@ describe("title-escrow", () => { expect(mockCallStaticBurnToken).toHaveBeenCalledTimes(1); expect(mockBurnToken).toHaveBeenCalledTimes(1); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(acceptSurrendered(acceptSurrenderedDocumentParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(acceptSurrendered(acceptSurrenderedDocumentParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/changeHolder.test.ts index c510a54b..265a9348 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/changeHolder.test.ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { TitleEscrowChangeHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { changeHolderOfTitleEscrow } from "./changeHolder"; @@ -58,16 +58,6 @@ describe("title-escrow", () => { mockCallStaticTransferHolder.mockClear(); }); - it("should take in the key from key file", async () => { - await changeHolderOfTitleEscrow({ - ...transferHolderParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and call the following procedures to invoke a change in holder of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await changeHolderOfTitleEscrow({ @@ -84,13 +74,5 @@ describe("title-escrow", () => { expect(mockCallStaticTransferHolder).toHaveBeenCalledTimes(1); expect(mockTransferHolder).toHaveBeenCalledTimes(1); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(changeHolderOfTitleEscrow(transferHolderParams)).rejects.toThrow("An Error"); - }); }); }); diff --git a/src/implementations/title-escrow/changeOwner.test.ts b/src/implementations/title-escrow/changeOwner.test.ts index 8c02f393..341d273a 100644 --- a/src/implementations/title-escrow/changeOwner.test.ts +++ b/src/implementations/title-escrow/changeOwner.test.ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { TitleEscrowEndorseChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { endorseChangeOfOwner } from "./changeOwner"; @@ -69,25 +69,6 @@ describe("title-escrow", () => { mockCallStaticTransferOwners.mockClear(); }); - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await endorseChangeOfOwner(endorseChangeOwnerParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await endorseChangeOfOwner({ - ...endorseChangeOwnerParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and call the following procedures to invoke an endorsement of change of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await endorseChangeOfOwner({ @@ -118,19 +99,5 @@ describe("title-escrow", () => { }) ).rejects.toThrow("new owner and new holder addresses are the same as the current owner and holder addresses"); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(endorseChangeOfOwner(endorseChangeOwnerParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(endorseChangeOfOwner(endorseChangeOwnerParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts index ca1a09aa..c9642986 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet, constants } from "ethers"; -import { join } from "path"; + import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { endorseNominatedBeneficiary } from "./endorseNominatedBeneficiary"; @@ -68,25 +68,6 @@ describe("title-escrow", () => { mockCallStaticTransferToNewEscrow.mockClear(); }); - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await endorseNominatedBeneficiary({ - ...endorseNominatedBeneficiaryParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and call the following procedures to invoke an endorsement of transfer of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await endorseNominatedBeneficiary({ @@ -133,19 +114,5 @@ describe("title-escrow", () => { `there is no approved owner or holder or the approved owner or holder is equal to the genesis address: ${GENESIS_ADDRESS}` ); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(endorseNominatedBeneficiary(endorseNominatedBeneficiaryParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index f384037e..e958e016 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { nominateBeneficiary } from "./nominateBeneficiary"; @@ -67,25 +67,6 @@ describe("title-escrow", () => { mockCallStaticNominateBeneficiary.mockClear(); }); - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await nominateBeneficiary(nominateBeneficiaryParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await nominateBeneficiary({ - ...nominateBeneficiaryParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and call the following procedures to invoke an nomination of change of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await nominateBeneficiary({ @@ -113,19 +94,5 @@ describe("title-escrow", () => { }) ).rejects.toThrow("new beneficiary address is the same as the current beneficiary address"); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(nominateBeneficiary(nominateBeneficiaryParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(nominateBeneficiary(nominateBeneficiaryParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 7cc3a3b1..3b01ade1 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { rejectSurrendered } from "./rejectSurrendered"; @@ -81,25 +81,6 @@ describe("title-escrow", () => { mockCallStaticRestoreTitle.mockClear(); }); - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await rejectSurrendered(rejectSurrenderedDocumentParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await rejectSurrendered({ - ...rejectSurrenderedDocumentParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and successfully rejects a surrendered transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await rejectSurrendered({ @@ -114,19 +95,5 @@ describe("title-escrow", () => { expect(mockCallStaticRestoreTitle).toHaveBeenCalledTimes(1); expect(mockRestoreTitle).toHaveBeenCalledWith(rejectSurrenderedDocumentParams.tokenId); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(rejectSurrendered(rejectSurrenderedDocumentParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(rejectSurrendered(rejectSurrenderedDocumentParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index d0653d59..688e2f6b 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -1,6 +1,6 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { surrenderDocument } from "./surrenderDocument"; @@ -57,26 +57,6 @@ describe("title-escrow", () => { mockSurrender.mockClear(); mockCallStaticSurrender.mockClear(); }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await surrenderDocument(surrenderDocumentParams); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await surrenderDocument({ - ...surrenderDocumentParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and successfully surrender a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await surrenderDocument({ @@ -93,19 +73,5 @@ describe("title-escrow", () => { expect(mockCallStaticSurrender).toHaveBeenCalledTimes(1); expect(mockSurrender).toHaveBeenCalledTimes(1); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(surrenderDocument(surrenderDocumentParams)).rejects.toThrow("An Error"); - }); - - it("should throw when keys are not found anywhere", async () => { - await expect(surrenderDocument(surrenderDocumentParams)).rejects.toThrow( - "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path" - ); - }); }); }); diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index d0493488..a38372ab 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -1,6 +1,6 @@ import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { join } from "path"; + import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { addAddressPrefix } from "../../utils"; import { issueToTokenRegistry } from "./issue"; @@ -49,24 +49,6 @@ describe("token-registry", () => { mockedConnectERC721.mockResolvedValue(mockTTERC721Contract); }); - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await issueToTokenRegistry(deployParams); - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await issueToTokenRegistry({ - ...deployParams, - keyFile: join(__dirname, "..", "..", "..", "examples", "sample-key"), - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); - }); - it("should pass in the correct params and return the deployed instance", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; const instance = await issueToTokenRegistry({ diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts index c92229a3..3283e0b9 100644 --- a/src/implementations/token-registry/role/grant-role.test.ts +++ b/src/implementations/token-registry/role/grant-role.test.ts @@ -62,13 +62,5 @@ describe("token-registry", () => { expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockGrantRole.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(grantRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); - }); }); }); diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts index bc67afc5..5098d11f 100644 --- a/src/implementations/token-registry/role/revoke-role.test.ts +++ b/src/implementations/token-registry/role/revoke-role.test.ts @@ -62,13 +62,5 @@ describe("token-registry", () => { expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(revokeRoleToTokenRegistry(roleParams)).rejects.toThrow("An Error"); - }); }); }); diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts index 9fb34423..d24194c5 100644 --- a/src/implementations/token-registry/role/set-role.test.ts +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -61,13 +61,5 @@ describe("token-registry", () => { expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.adminRole); }); - - it("should allow errors to bubble up", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - mockedConnectERC721.mockImplementation(() => { - throw new Error("An Error"); - }); - await expect(setRoleAdminTokenRegistry(roleParams)).rejects.toThrow("An Error"); - }); }); }); From 068f7f73a2b1678de9dd5010fa886c2f6a4d302f Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 14 Sep 2022 18:03:39 +0800 Subject: [PATCH 07/63] fix: token registry deploy --- src/commands/deploy/token-registry.ts | 8 +- src/implementations/config/helpers.ts | 3 +- .../deploy/token-registry/token-registry.ts | 101 +++++++++++++----- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index 3fd8093d..bedc6f24 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -38,11 +38,9 @@ export const handler = async (args: DeployTokenRegistryCommand): Promise => { info(`Enter password to continue deployment of Token Registry`); - const tokenRegistry = await deployTokenRegistry({ + const contractAddress = await deployTokenRegistry({ encryptedWalletPath, network: "ropsten", gasPriceScale: 1, @@ -95,7 +95,6 @@ export const getTokenRegistryAddress = async (encryptedWalletPath: string): Prom registryName: "Token Registry", registrySymbol: "TR", }); - const { contractAddress } = tokenRegistry; success(`Token registry deployed, address: ${highlight(contractAddress)}`); return contractAddress; }; diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index f89f8b60..76de0806 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -1,14 +1,21 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TDocDeployer, TDocDeployer__factory } from "@govtechsg/token-registry/contracts"; import { getWalletOrSigner } from "../../utils/wallet"; import signale from "signale"; import { getLogger } from "../../../logger"; -import { TransactionReceipt } from "@ethersproject/providers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -import { dryRunMode } from "../../utils/dryRun"; import { constants } from "@govtechsg/token-registry"; +import { BigNumber, ethers } from "ethers"; +import { encodeInitParams, getEventFromReceipt } from "@govtechsg/token-registry/dist/types/utils"; +import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; const { trace } = getLogger("deploy:token-registry"); +interface DeployContractAddress { + titleEscrowFactory: string; + tokenImplementation: string; + deployer: string; +} + export const deployTokenRegistry = async ({ registryName, registrySymbol, @@ -17,41 +24,81 @@ export const deployTokenRegistry = async ({ gasPriceScale, dryRun, ...rest -}: DeployTokenRegistryCommand): Promise => { +}: DeployTokenRegistryCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const factory = new TradeTrustERC721__factory(wallet); const chainId = await wallet.getChainId(); - const { contractAddress } = constants; - - if (!factoryAddress) { - if (!chainId) { - throw new Error(`Invalid chain ID: ${chainId}`); - } - factoryAddress = contractAddress.TitleEscrowFactory[chainId]; - if (!factoryAddress) { - throw new Error(`Network ${network} currently is not supported. Supply a factory address.`); - } - } + const deployContractAddress: DeployContractAddress = retrieveFactoryAddress(chainId, factoryAddress); + const factory = new ethers.Contract( + deployContractAddress.deployer, + TDocDeployer__factory.createInterface(), + wallet + ) as TDocDeployer; signale.info(`Using ${factoryAddress} as Title Escrow factory.`); + const initParam = encodeInitParams({ + name: registryName, + symbol: registrySymbol, + deployer: await wallet.getAddress(), + }); + if (dryRun) { - const tx = factory.getDeployTransaction(registryName, registrySymbol, factoryAddress, {}); - await dryRunMode({ - network, - gasPriceScale: gasPriceScale, - transaction: tx, - }); + const estimatedGas: BigNumber = await factory.estimateGas.deploy( + deployContractAddress.tokenImplementation, + initParam + ); + signale.info("Dry Run is unavailable for token reigstry deploy"); + signale.info(`Estimated Gas Required: ${estimatedGas.toString()}`); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(registryName, registrySymbol, factoryAddress, { + const transaction = await factory.deploy(deployContractAddress.tokenImplementation, initParam, { gasPrice: gasPrice.mul(gasPriceScale), }); - trace(`Tx hash: ${transaction.deployTransaction.hash}`); - trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); - return transaction.deployTransaction.wait(); + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + const receipt = await transaction.wait(); + const registryAddress = getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) + .args.deployed; + return registryAddress; +}; + +const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { + const { contractAddress } = constants; + + if (!chainId) { + throw new Error(`Invalid chain ID: ${chainId}`); + } + + const deployContractAddress = { + titleEscrowFactory: factoryAddress, + tokenImplementation: contractAddress.TokenImplementation[chainId], + deployer: contractAddress.Deployer[chainId], + } as DeployContractAddress; + + if (!deployContractAddress["tokenImplementation"] || !deployContractAddress["deployer"]) { + throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); + } + + if (!factoryAddress) { + deployContractAddress["titleEscrowFactory"] = contractAddress.TitleEscrowFactory[chainId]; + if (!factoryAddress) { + throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); + } + } + + if (!factoryAddress) { + if (!chainId) { + throw new Error(`Invalid chain ID: ${chainId}`); + } + factoryAddress = contractAddress.TitleEscrowFactory[chainId]; + if (!factoryAddress) { + throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); + } + } + + return deployContractAddress; }; From 0540e29ca55f88a76436acfd9b6e0796be2046ca Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 16 Sep 2022 18:38:53 +0800 Subject: [PATCH 08/63] fix: token-registry deploy --- src/commands/deploy/token-registry.ts | 6 +- src/implementations/config/helpers.ts | 3 +- .../token-registry/token-registry.test.ts | 86 +++++++-------- .../deploy/token-registry/token-registry.ts | 100 +++++++++++++----- 4 files changed, 118 insertions(+), 77 deletions(-) diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index bedc6f24..703088b2 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -38,9 +38,9 @@ export const handler = async (args: DeployTokenRegistryCommand): Promise => { info(`Enter password to continue deployment of Token Registry`); - const contractAddress = await deployTokenRegistry({ + const tokenRegistry = await deployTokenRegistry({ encryptedWalletPath, network: "ropsten", gasPriceScale: 1, @@ -95,6 +95,7 @@ export const getTokenRegistryAddress = async (encryptedWalletPath: string): Prom registryName: "Token Registry", registrySymbol: "TR", }); + const { contractAddress } = tokenRegistry; success(`Token registry deployed, address: ${highlight(contractAddress)}`); return contractAddress; }; diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 92b20a59..fad3348f 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -1,16 +1,12 @@ -import { deployTokenRegistry } from "./token-registry"; -import { join } from "path"; -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import { Wallet } from "ethers"; +import { deployTokenRegistry, encodeInitParams } from "./token-registry"; +import { Contract } from "ethers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; - -jest.mock("@govtechsg/token-registry/contracts"); +import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; const deployParams: DeployTokenRegistryCommand = { registryName: "Test", registrySymbol: "Tst", network: "ropsten", - factoryAddress: "0x0", key: "0000000000000000000000000000000000000000000000000000000000000001", gasPriceScale: 1, dryRun: false, @@ -18,62 +14,56 @@ const deployParams: DeployTokenRegistryCommand = { describe("token-registry", () => { describe("deployTokenRegistry", () => { - const tokenFactory: any = TradeTrustERC721__factory; - const mockedTokenFactory: jest.Mock = tokenFactory; - const mockedDeploy: jest.Mock = mockedTokenFactory.prototype.deploy; + const mockedEthersContract: jest.Mock = Contract as any; + mockedEthersContract.prototype.deploy = jest.fn() + const mockedDeploy: jest.Mock = mockedEthersContract.prototype.deploy; + // increase timeout because ethers is throttling jest.setTimeout(30000); beforeEach(() => { - mockedTokenFactory.mockReset(); mockedDeploy.mockReset(); mockedDeploy.mockResolvedValue({ - deployTransaction: { hash: "hash", wait: () => Promise.resolve({ contractAddress: "contractAddress" }) }, - }); - }); - - it("should take in the key from environment variable", async () => { - process.env.OA_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000002"; - - await deployTokenRegistry({ - registryName: "Test", - registrySymbol: "Tst", - network: "ropsten", - gasPriceScale: 1, - dryRun: false, + hash: "hash", + blockNumber: "blockNumber", + wait: () => Promise.resolve( + { + events: [{ + topics: [ + '0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5',// deployment + '0x000000000000000000000000426c58c2b29111eafc53bdcb9c99dc7714fdb262', + '0x000000000000000000000000e5c75026d5f636c89cc77583b6bce7c99f512763', + '0x0000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca6' + ], + data: "0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", + args: [ + '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', + '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', + '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', + '0x878A327daA390Bc602Ae259D3A374610356b6485', + '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', + ] as unknown as DeploymentEvent, + }] + } + ) }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x${process.env.OA_PRIVATE_KEY}`); - }); - - it("should take in the key from key file", async () => { - await deployTokenRegistry({ - registryName: "Test", - registrySymbol: "Tst", - network: "ropsten", - keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, - dryRun: false, - }); - - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; - expect(passedSigner.privateKey).toBe(`0x0000000000000000000000000000000000000000000000000000000000000003`); }); it("should pass in the correct params and return the deployed instance", async () => { const instance = await deployTokenRegistry(deployParams); - const passedSigner: Wallet = mockedTokenFactory.mock.calls[0][0]; + const expectedInitParams = encodeInitParams({ + name: deployParams.registryName, + symbol: deployParams.registrySymbol, + deployer: "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf", + }) - expect(passedSigner.privateKey).toBe(`0x${deployParams.key}`); - expect(mockedDeploy.mock.calls[0][0]).toEqual(deployParams.registryName); - expect(mockedDeploy.mock.calls[0][1]).toEqual(deployParams.registrySymbol); - expect(mockedDeploy.mock.calls[0][2]).toEqual(deployParams.factoryAddress); + expect(mockedDeploy.mock.calls[0][0]).toEqual("0xE5C75026d5f636C89cc77583B6BCe7C99F512763"); + expect(mockedDeploy.mock.calls[0][1]).toEqual(expectedInitParams); // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][3].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); - expect(instance.contractAddress).toBe("contractAddress"); + expect(mockedDeploy.mock.calls[0][2].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); + // expect(instance.contractAddress).toBe("contractAddress"); // TODO }); it("should allow errors to bubble up", async () => { diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 76de0806..50ed5bc8 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -4,9 +4,9 @@ import signale from "signale"; import { getLogger } from "../../../logger"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { constants } from "@govtechsg/token-registry"; -import { BigNumber, ethers } from "ethers"; -import { encodeInitParams, getEventFromReceipt } from "@govtechsg/token-registry/dist/types/utils"; +import { BigNumber, ContractReceipt, ethers } from "ethers"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; +import { TypedEvent } from "@govtechsg/token-registry/dist/contracts/common"; const { trace } = getLogger("deploy:token-registry"); @@ -24,7 +24,7 @@ export const deployTokenRegistry = async ({ gasPriceScale, dryRun, ...rest -}: DeployTokenRegistryCommand): Promise => { +}: DeployTokenRegistryCommand): Promise<{ contractAddress: string }> => { const wallet = await getWalletOrSigner({ network, ...rest }); const chainId = await wallet.getChainId(); const deployContractAddress: DeployContractAddress = retrieveFactoryAddress(chainId, factoryAddress); @@ -34,7 +34,7 @@ export const deployTokenRegistry = async ({ TDocDeployer__factory.createInterface(), wallet ) as TDocDeployer; - signale.info(`Using ${factoryAddress} as Title Escrow factory.`); + signale.info(`Using ${deployContractAddress.titleEscrowFactory} as Title Escrow factory.`); const initParam = encodeInitParams({ name: registryName, @@ -63,7 +63,18 @@ export const deployTokenRegistry = async ({ const receipt = await transaction.wait(); const registryAddress = getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) .args.deployed; - return registryAddress; + // console.log(getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")).args) + return {contractAddress: registryAddress}; +}; + +interface Params { + name: string; + symbol: string; + deployer: string; +} + +export const encodeInitParams = ({ name, symbol, deployer }: Params) => { + return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); }; const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { @@ -73,32 +84,71 @@ const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefi throw new Error(`Invalid chain ID: ${chainId}`); } - const deployContractAddress = { - titleEscrowFactory: factoryAddress, - tokenImplementation: contractAddress.TokenImplementation[chainId], - deployer: contractAddress.Deployer[chainId], - } as DeployContractAddress; - - if (!deployContractAddress["tokenImplementation"] || !deployContractAddress["deployer"]) { + let titleEscrowFactory = factoryAddress; + let tokenImplementation = contractAddress.TokenImplementation[chainId]; + let deployer = contractAddress.Deployer[chainId]; + + if (!tokenImplementation || !deployer) { throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); } - if (!factoryAddress) { - deployContractAddress["titleEscrowFactory"] = contractAddress.TitleEscrowFactory[chainId]; - if (!factoryAddress) { + if (!titleEscrowFactory) { + titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId]; + if (!titleEscrowFactory) { throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); } } - if (!factoryAddress) { - if (!chainId) { - throw new Error(`Invalid chain ID: ${chainId}`); - } - factoryAddress = contractAddress.TitleEscrowFactory[chainId]; - if (!factoryAddress) { - throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); - } - } + return { + titleEscrowFactory: titleEscrowFactory, + tokenImplementation: tokenImplementation, + deployer: deployer, + } as DeployContractAddress; +}; + +export const getEventFromReceipt = >( + receipt: ContractReceipt, + topic: string, + iface?: ethers.utils.Interface +) => { + if (!receipt.events) throw new Error("Events object is undefined"); + const event = receipt.events.find((evt) => evt.topics[0] === topic); + if (!event) throw new Error(`Cannot find topic ${topic}`); + + - return deployContractAddress; + if (iface) return iface.parseLog(event) as unknown as T + // console.log(event) + // console.log(event as T) + return event as T; }; + + +// const deo = { +// deployed: '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', +// implementation: '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', +// deployer: '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', +// titleEscrowFactory: '0x878A327daA390Bc602Ae259D3A374610356b6485', +// params: '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000' +// } as DeploymentEventObject + +// const why = [ +// '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', +// '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', +// '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', +// '0x878A327daA390Bc602Ae259D3A374610356b6485', +// '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', +// ] as [string, string, string, string, string], + + +// const test: DeploymentEvent = [ + +// '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', +// '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', +// '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', +// '0x878A327daA390Bc602Ae259D3A374610356b6485', +// '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', + + + +// ] as unknown as DeploymentEvent; \ No newline at end of file From c0975548d48fdd4a0d8e8a2e90e29206a7f24810 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Mon, 19 Sep 2022 18:00:03 +0800 Subject: [PATCH 09/63] feat: token-registry e2e test --- src/__tests__/token-registry.e2e.test.ts | 138 +++++++++++------- src/commands/deploy/token-registry.ts | 4 +- .../token-registry/token-registry.test.ts | 45 +++--- .../deploy/token-registry/token-registry.ts | 49 +------ 4 files changed, 119 insertions(+), 117 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index a0e71506..f0dff709 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -5,23 +5,22 @@ import { BaseTitleEscrowCommand, TitleEscrowChangeHolderCommand, TitleEscrowEndorseChangeOfOwnerCommand, - TitleEscrowNominateChangeOfOwnerCommand, + TitleEscrowNominateBeneficiaryCommand, } from "../commands/title-escrow/title-escrow-command.type"; import { TokenRegistryIssueCommand } from "../commands/token-registry/token-registry-command.type"; import { deployTokenRegistry } from "../implementations/deploy/token-registry"; import { surrenderDocument } from "../implementations/title-escrow/surrenderDocument"; import { issueToTokenRegistry } from "../implementations/token-registry/issue"; -import { progress as defaultProgress } from "../implementations/utils/progress"; import { ConnectedSigner, getWalletOrSigner } from "../implementations/utils/wallet"; import { TransactionReceipt } from "@ethersproject/providers"; import { acceptSurrendered } from "../implementations/title-escrow/acceptSurrendered"; import { rejectSurrendered } from "../implementations/title-escrow/rejectSurrendered"; import { changeHolderOfTitleEscrow } from "../implementations/title-escrow/changeHolder"; -import { nominateChangeOfOwner } from "../implementations/title-escrow/nominateChangeOfOwner"; -import { endorseTransferOfOwner } from "../implementations/title-escrow/endorseTransferOfOwner"; -import { endorseChangeOfOwner } from "../implementations/title-escrow/endorseChangeOfOwner"; import ganache from "ganache"; +import { endorseChangeOfOwner } from "../implementations/title-escrow/changeOwner"; +import { nominateBeneficiary } from "../implementations/title-escrow/nominateBeneficiary"; +import { endorseNominatedBeneficiary } from "../implementations/title-escrow/endorseNominatedBeneficiary"; jest.mock("../implementations/utils/wallet", () => { const originalModule = jest.requireActual("../implementations/utils/wallet"); @@ -46,9 +45,6 @@ const accounts = { }, }; -const ganacheOptions = { - mnemonic: accounts.mnemonic, -}; const regexEthAddress = new RegExp("^0x[a-fA-F0-9]{40}$"); describe("token-registry", () => { @@ -62,15 +58,29 @@ describe("token-registry", () => { gasPriceScale: 1, dryRun: false, }; + const ganacheOptions = { + logging: { + debug: false, + quiet: true, + verbose: false, + }, + chain: { + chainId: 3, + }, + wallet: { + mnemonic: accounts.mnemonic, + }, + fork: { + network: "ropsten", + }, + }; + + // chainId: 1 beforeAll(() => { const provider = new ethers.providers.Web3Provider(ganache.provider(ganacheOptions)); mockedGetWalletOrSigner.mockImplementation( - async ({ - network, - progress = defaultProgress("Decrypting Wallet"), - ...options - }: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< + async ({}: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< Wallet | ConnectedSigner > => { const wallet = await ethers.Wallet.fromMnemonic(accounts.mnemonic, "m/44'/60'/0'/0/0"); @@ -87,8 +97,8 @@ describe("token-registry", () => { ...defaults, }; const tokenRegistryTransaction = await deployTokenRegistry(tokenRegistryParameter); - expect(tokenRegistryTransaction.confirmations).toBeGreaterThanOrEqual(1); - expect(tokenRegistryTransaction.status).toBe(1); + // expect(tokenRegistryTransaction.confirmations).toBeGreaterThanOrEqual(1); + // expect(tokenRegistryTransaction.status).toBe(1); const validTokenRegistryDeploy = regexEthAddress.test(tokenRegistryTransaction.contractAddress); expect(validTokenRegistryDeploy).toBe(true); tokenRegistryAddress = tokenRegistryTransaction.contractAddress; @@ -106,6 +116,8 @@ describe("token-registry", () => { const transactionParameter: TokenRegistryIssueCommand = { address: retrievedTokenRegistryAddress, tokenId: tokenId, + beneficiary: accounts.owner.ethAddress, + holder: accounts.owner.ethAddress, ...mintTransactionParameter, }; const transaction = await issueToTokenRegistry(transactionParameter); @@ -176,77 +188,99 @@ describe("token-registry", () => { }); }); - describe("title-escrow transfer", () => { - it("should be able to change holder of title-escrow", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000004"; - const destinationWalletAddress = accounts.receiver.ethAddress; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); + describe("title-escrow transfers", () => { + const changeHolder = async ( + retrievedTokenRegistryAddress: string, + tokenId: string + ): Promise => { const transactionParameter: TitleEscrowChangeHolderCommand = { tokenRegistry: retrievedTokenRegistryAddress, tokenId: tokenId, - to: destinationWalletAddress, + to: accounts.receiver.ethAddress, ...defaults, }; const transaction = await changeHolderOfTitleEscrow(transactionParameter); + return transaction; + }; + + const changeOwner = async (retrievedTokenRegistryAddress: string, tokenId: string): Promise => { + const transactionParameter: TitleEscrowEndorseChangeOfOwnerCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + newHolder: accounts.receiver.ethAddress, + newOwner: accounts.receiver.ethAddress, + ...defaults, + }; + const transaction = await endorseChangeOfOwner(transactionParameter); + return transaction; + }; + + const nominateTitleEscrowBeneficiary = async ( + retrievedTokenRegistryAddress: string, + tokenId: string + ): Promise => { + const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { + tokenRegistry: retrievedTokenRegistryAddress, + tokenId: tokenId, + newOwner: accounts.receiver.ethAddress, + ...defaults, + }; + const transaction = await nominateBeneficiary(transactionParameter); + return transaction; + }; + + it("should be able to change title escrow holder", async () => { + const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000004"; + const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); + await mintTransaction(retrievedTokenRegistryAddress, tokenId); + const transaction = await changeHolder(retrievedTokenRegistryAddress, tokenId); expect(transaction.confirmations).toBeGreaterThanOrEqual(1); expect(transaction.status).toBe(1); }); - it("should be able to nominate change of holder of title-escrow", async () => { + it("should be able to change title escrow owner", async () => { const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000005"; - const destinationWalletAddress = accounts.receiver.ethAddress; const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: TitleEscrowNominateChangeOfOwnerCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - newOwner: destinationWalletAddress, - ...defaults, - }; - const transaction = await nominateChangeOfOwner(transactionParameter); + const transaction = await changeOwner(retrievedTokenRegistryAddress, tokenId); expect(transaction.confirmations).toBeGreaterThanOrEqual(1); expect(transaction.status).toBe(1); }); - it("should be able to endorse transfer of owner of title-escrow", async () => { + it("should be able to nominate title escrow beneficiaries", async () => { const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000006"; - const destinationWalletAddress = accounts.receiver.ethAddress; const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: BaseTitleEscrowCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - ...defaults, - }; - const transaction = await endorseTransferOfOwner(transactionParameter); - expect(transaction.transactionReceipt.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.transactionReceipt.status).toBe(1); - // TODO expect approvedOwner/approvedHolder + const transaction = await nominateTitleEscrowBeneficiary(retrievedTokenRegistryAddress, tokenId); + + expect(transaction.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.status).toBe(1); }); - it("should be able to endorse change of owner of title-escrow", async () => { + it("should be able to complete transfer of title escrow beneficiaries", async () => { const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000007"; - const destinationWalletAddress = accounts.receiver.ethAddress; const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: TitleEscrowEndorseChangeOfOwnerCommand = { - tokenId: tokenId, + await nominateTitleEscrowBeneficiary(retrievedTokenRegistryAddress, tokenId); + const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { tokenRegistry: retrievedTokenRegistryAddress, - newHolder: destinationWalletAddress, - newOwner: destinationWalletAddress, + tokenId: tokenId, + newOwner: accounts.receiver.ethAddress, ...defaults, }; - const transaction = await endorseChangeOfOwner(transactionParameter); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); + const transaction = await endorseNominatedBeneficiary(transactionParameter); + + expect(transaction.nominatedBeneficiary).toBe(accounts.receiver.ethAddress); + expect(transaction.transactionReceipt.confirmations).toBeGreaterThanOrEqual(1); + expect(transaction.transactionReceipt.status).toBe(1); }); }); const getTokenRegistryAddress = async (): Promise => { if (tokenRegistryAddress === "") { - const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); + const delay = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); await delay(3000); + console.log("Delayed By 3s"); return await getTokenRegistryAddress(); } else { return tokenRegistryAddress; diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index 703088b2..b0738764 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -39,7 +39,9 @@ export const handler = async (args: DeployTokenRegistryCommand): Promise { describe("deployTokenRegistry", () => { const mockedEthersContract: jest.Mock = Contract as any; - mockedEthersContract.prototype.deploy = jest.fn() + jest.spyOn(mockedEthersContract.prototype, "deploy").mockImplementation(); const mockedDeploy: jest.Mock = mockedEthersContract.prototype.deploy; // increase timeout because ethers is throttling @@ -26,26 +26,27 @@ describe("token-registry", () => { mockedDeploy.mockResolvedValue({ hash: "hash", blockNumber: "blockNumber", - wait: () => Promise.resolve( - { - events: [{ - topics: [ - '0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5',// deployment - '0x000000000000000000000000426c58c2b29111eafc53bdcb9c99dc7714fdb262', - '0x000000000000000000000000e5c75026d5f636c89cc77583b6bce7c99f512763', - '0x0000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca6' - ], - data: "0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", - args: [ - '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', - '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', - '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', - '0x878A327daA390Bc602Ae259D3A374610356b6485', - '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', - ] as unknown as DeploymentEvent, - }] - } - ) + wait: () => + Promise.resolve({ + events: [ + { + topics: [ + "0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5", // deployment + "0x000000000000000000000000426c58c2b29111eafc53bdcb9c99dc7714fdb262", + "0x000000000000000000000000e5c75026d5f636c89cc77583b6bce7c99f512763", + "0x0000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca6", + ], + data: "0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", + args: [ + "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7", + "0xE5C75026d5f636C89cc77583B6BCe7C99F512763", + "0x8d366250A96deBE81C8619459a503a0eEBE33ca6", + "0x878A327daA390Bc602Ae259D3A374610356b6485", + "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", + ] as unknown as DeploymentEvent, + }, + ], + }), }); }); @@ -56,7 +57,7 @@ describe("token-registry", () => { name: deployParams.registryName, symbol: deployParams.registrySymbol, deployer: "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf", - }) + }); expect(mockedDeploy.mock.calls[0][0]).toEqual("0xE5C75026d5f636C89cc77583B6BCe7C99F512763"); expect(mockedDeploy.mock.calls[0][1]).toEqual(expectedInitParams); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 50ed5bc8..e12b65e9 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -63,8 +63,7 @@ export const deployTokenRegistry = async ({ const receipt = await transaction.wait(); const registryAddress = getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) .args.deployed; - // console.log(getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")).args) - return {contractAddress: registryAddress}; + return { contractAddress: registryAddress }; }; interface Params { @@ -73,7 +72,7 @@ interface Params { deployer: string; } -export const encodeInitParams = ({ name, symbol, deployer }: Params) => { +export const encodeInitParams = ({ name, symbol, deployer }: Params): string => { return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); }; @@ -85,9 +84,9 @@ const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefi } let titleEscrowFactory = factoryAddress; - let tokenImplementation = contractAddress.TokenImplementation[chainId]; - let deployer = contractAddress.Deployer[chainId]; - + const tokenImplementation = contractAddress.TokenImplementation[chainId]; + const deployer = contractAddress.Deployer[chainId]; + if (!tokenImplementation || !deployer) { throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); } @@ -110,45 +109,11 @@ export const getEventFromReceipt = >( receipt: ContractReceipt, topic: string, iface?: ethers.utils.Interface -) => { +): any => { if (!receipt.events) throw new Error("Events object is undefined"); const event = receipt.events.find((evt) => evt.topics[0] === topic); if (!event) throw new Error(`Cannot find topic ${topic}`); - - - if (iface) return iface.parseLog(event) as unknown as T - // console.log(event) - // console.log(event as T) + if (iface) return iface.parseLog(event) as unknown as T; return event as T; }; - - -// const deo = { -// deployed: '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', -// implementation: '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', -// deployer: '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', -// titleEscrowFactory: '0x878A327daA390Bc602Ae259D3A374610356b6485', -// params: '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000' -// } as DeploymentEventObject - -// const why = [ -// '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', -// '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', -// '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', -// '0x878A327daA390Bc602Ae259D3A374610356b6485', -// '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', -// ] as [string, string, string, string, string], - - -// const test: DeploymentEvent = [ - -// '0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7', -// '0xE5C75026d5f636C89cc77583B6BCe7C99F512763', -// '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', -// '0x878A327daA390Bc602Ae259D3A374610356b6485', -// '0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', - - - -// ] as unknown as DeploymentEvent; \ No newline at end of file From d38e6a859359b63adbf219fa350ecc6638d9762c Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 21 Sep 2022 17:04:08 +0800 Subject: [PATCH 10/63] feat: fixed linting --- src/__tests__/token-registry.e2e.test.ts | 8 ++++---- .../deploy/token-registry/token-registry.test.ts | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index f0dff709..a188ff27 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -53,8 +53,10 @@ describe("token-registry", () => { const mockedGetWalletOrSigner: jest.Mock = getWalletOrSigner as jest.Mock; let tokenRegistryAddress = ""; + const defaultNetwork = "ropsten"; + const defaults = { - network: "mainnet", + network: defaultNetwork, gasPriceScale: 1, dryRun: false, }; @@ -71,12 +73,10 @@ describe("token-registry", () => { mnemonic: accounts.mnemonic, }, fork: { - network: "ropsten", + network: defaultNetwork, }, }; - // chainId: 1 - beforeAll(() => { const provider = new ethers.providers.Web3Provider(ganache.provider(ganacheOptions)); mockedGetWalletOrSigner.mockImplementation( diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 4dc90233..57ac77d6 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -15,7 +15,8 @@ const deployParams: DeployTokenRegistryCommand = { describe("token-registry", () => { describe("deployTokenRegistry", () => { const mockedEthersContract: jest.Mock = Contract as any; - jest.spyOn(mockedEthersContract.prototype, "deploy").mockImplementation(); + // eslint-disable-next-line jest/prefer-spy-on + mockedEthersContract.prototype.deploy = jest.fn(); const mockedDeploy: jest.Mock = mockedEthersContract.prototype.deploy; // increase timeout because ethers is throttling @@ -51,7 +52,7 @@ describe("token-registry", () => { }); it("should pass in the correct params and return the deployed instance", async () => { - const instance = await deployTokenRegistry(deployParams); + await deployTokenRegistry(deployParams); const expectedInitParams = encodeInitParams({ name: deployParams.registryName, From 7f56f7cddd2750d213354b1c7dd7e3e3ff31407e Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 21 Sep 2022 23:42:22 +0800 Subject: [PATCH 11/63] feat: fixed e2e test disconnect --- src/__tests__/token-registry.e2e.test.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index a188ff27..7471200a 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -52,6 +52,8 @@ describe("token-registry", () => { // @ts-ignore mock static method const mockedGetWalletOrSigner: jest.Mock = getWalletOrSigner as jest.Mock; + jest.setTimeout(90000); + let tokenRegistryAddress = ""; const defaultNetwork = "ropsten"; @@ -77,12 +79,14 @@ describe("token-registry", () => { }, }; + const ganacheProvider = ganache.provider(ganacheOptions); + beforeAll(() => { - const provider = new ethers.providers.Web3Provider(ganache.provider(ganacheOptions)); mockedGetWalletOrSigner.mockImplementation( async ({}: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< Wallet | ConnectedSigner > => { + const provider = new ethers.providers.Web3Provider(ganacheProvider); const wallet = await ethers.Wallet.fromMnemonic(accounts.mnemonic, "m/44'/60'/0'/0/0"); const connectedWallet = wallet.connect(provider); return connectedWallet; @@ -90,6 +94,10 @@ describe("token-registry", () => { ); }); + afterAll(async () => { + await ganacheProvider.disconnect(); + }); + it("should be able to deploy token-registry", async () => { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", From d4fc2e137f0af12634fb32b4291e54f124c03ab2 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 21 Sep 2022 23:51:38 +0800 Subject: [PATCH 12/63] fix: removed fragile test message, e2e added --- src/implementations/title-escrow/acceptSurrendered.test.ts | 4 ++-- src/implementations/title-escrow/changeHolder.test.ts | 4 ++-- src/implementations/title-escrow/changeOwner.test.ts | 4 ++-- .../title-escrow/endorseNominatedBeneficiary.test..ts | 4 ++-- src/implementations/title-escrow/nominateBeneficiary.test.ts | 4 ++-- src/implementations/title-escrow/rejectSurrendered.test.ts | 4 ++-- src/implementations/title-escrow/surrenderDocument.test.ts | 4 ++-- src/implementations/token-registry/issue.test.ts | 4 ++-- src/implementations/token-registry/role/grant-role.test.ts | 4 ++-- src/implementations/token-registry/role/revoke-role.test.ts | 4 ++-- src/implementations/token-registry/role/set-role.test.ts | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 8637a291..293b1f89 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -14,8 +14,8 @@ const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("accepts surrendered transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/changeHolder.test.ts index 265a9348..798b8cb2 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/changeHolder.test.ts @@ -15,8 +15,8 @@ const transferHolderParams: TitleEscrowChangeHolderCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("change holder of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/changeOwner.test.ts b/src/implementations/title-escrow/changeOwner.test.ts index 341d273a..8632f0dc 100644 --- a/src/implementations/title-escrow/changeOwner.test.ts +++ b/src/implementations/title-escrow/changeOwner.test.ts @@ -16,8 +16,8 @@ const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("endorse change of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts index c9642986..120424bb 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts @@ -16,8 +16,8 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = }; const GENESIS_ADDRESS = constants.AddressZero; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("endorse transfer of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index e958e016..362a59ae 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -15,8 +15,8 @@ const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("nominate change of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 3b01ade1..90ca079b 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -14,8 +14,8 @@ const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("rejects surrendered transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 688e2f6b..1cba33eb 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -14,8 +14,8 @@ const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("title-escrow", () => { describe("surrender transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index a38372ab..05c6d047 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -17,8 +17,8 @@ const deployParams: TokenRegistryIssueCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("token-registry", () => { describe("issue", () => { jest.setTimeout(30000); diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts index 3283e0b9..bcdbbf4e 100644 --- a/src/implementations/token-registry/role/grant-role.test.ts +++ b/src/implementations/token-registry/role/grant-role.test.ts @@ -14,8 +14,8 @@ const roleParams: TokenRegistryRoleCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("token-registry", () => { describe("grant role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts index 5098d11f..de2e028d 100644 --- a/src/implementations/token-registry/role/revoke-role.test.ts +++ b/src/implementations/token-registry/role/revoke-role.test.ts @@ -14,8 +14,8 @@ const roleParams: TokenRegistryRoleCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("token-registry", () => { describe("revoke role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts index d24194c5..f0238726 100644 --- a/src/implementations/token-registry/role/set-role.test.ts +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -13,8 +13,8 @@ const roleParams: TokenRegistrySetRoleAdminCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of TradeTrustERC721Factory -// ideally must setup ganache, and run the function over it + + describe("token-registry", () => { describe("set role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; From 79338a395e22a05c55765b34ffda18219d219924 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 21 Sep 2022 23:57:50 +0800 Subject: [PATCH 13/63] fix: linting --- src/__tests__/token-registry.e2e.test.ts | 2 -- src/implementations/title-escrow/acceptSurrendered.test.ts | 2 -- src/implementations/title-escrow/changeHolder.test.ts | 2 -- src/implementations/title-escrow/changeOwner.test.ts | 2 -- .../title-escrow/endorseNominatedBeneficiary.test..ts | 2 -- src/implementations/title-escrow/nominateBeneficiary.test.ts | 2 -- src/implementations/title-escrow/rejectSurrendered.test.ts | 2 -- src/implementations/title-escrow/surrenderDocument.test.ts | 2 -- src/implementations/token-registry/issue.test.ts | 2 -- src/implementations/token-registry/role/grant-role.test.ts | 2 -- src/implementations/token-registry/role/revoke-role.test.ts | 2 -- src/implementations/token-registry/role/set-role.test.ts | 2 -- 12 files changed, 24 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index 7471200a..f69a31fa 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -105,8 +105,6 @@ describe("token-registry", () => { ...defaults, }; const tokenRegistryTransaction = await deployTokenRegistry(tokenRegistryParameter); - // expect(tokenRegistryTransaction.confirmations).toBeGreaterThanOrEqual(1); - // expect(tokenRegistryTransaction.status).toBe(1); const validTokenRegistryDeploy = regexEthAddress.test(tokenRegistryTransaction.contractAddress); expect(validTokenRegistryDeploy).toBe(true); tokenRegistryAddress = tokenRegistryTransaction.contractAddress; diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 293b1f89..a39db117 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -14,8 +14,6 @@ const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("accepts surrendered transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/changeHolder.test.ts index 798b8cb2..170f3e66 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/changeHolder.test.ts @@ -15,8 +15,6 @@ const transferHolderParams: TitleEscrowChangeHolderCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("change holder of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/changeOwner.test.ts b/src/implementations/title-escrow/changeOwner.test.ts index 8632f0dc..62437aff 100644 --- a/src/implementations/title-escrow/changeOwner.test.ts +++ b/src/implementations/title-escrow/changeOwner.test.ts @@ -16,8 +16,6 @@ const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("endorse change of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts index 120424bb..3c47f7c9 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts @@ -16,8 +16,6 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = }; const GENESIS_ADDRESS = constants.AddressZero; - - describe("title-escrow", () => { describe("endorse transfer of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index 362a59ae..17e5f868 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -15,8 +15,6 @@ const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("nominate change of owner of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 90ca079b..0d26e73b 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -14,8 +14,6 @@ const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("rejects surrendered transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 1cba33eb..26644887 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -14,8 +14,6 @@ const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { dryRun: false, }; - - describe("title-escrow", () => { describe("surrender transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index 05c6d047..d6b0cdae 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -17,8 +17,6 @@ const deployParams: TokenRegistryIssueCommand = { dryRun: false, }; - - describe("token-registry", () => { describe("issue", () => { jest.setTimeout(30000); diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts index bcdbbf4e..ae86fa02 100644 --- a/src/implementations/token-registry/role/grant-role.test.ts +++ b/src/implementations/token-registry/role/grant-role.test.ts @@ -14,8 +14,6 @@ const roleParams: TokenRegistryRoleCommand = { dryRun: false, }; - - describe("token-registry", () => { describe("grant role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts index de2e028d..60a41c94 100644 --- a/src/implementations/token-registry/role/revoke-role.test.ts +++ b/src/implementations/token-registry/role/revoke-role.test.ts @@ -14,8 +14,6 @@ const roleParams: TokenRegistryRoleCommand = { dryRun: false, }; - - describe("token-registry", () => { describe("revoke role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts index f0238726..01496400 100644 --- a/src/implementations/token-registry/role/set-role.test.ts +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -13,8 +13,6 @@ const roleParams: TokenRegistrySetRoleAdminCommand = { dryRun: false, }; - - describe("token-registry", () => { describe("set role for token registry", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; From 71ed72ab2a590c2896fd8df6624c1fe33fcdf879 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 00:12:30 +0800 Subject: [PATCH 14/63] fix: typescript casting --- src/__tests__/token-registry.e2e.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index f69a31fa..3c91c928 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -77,7 +77,7 @@ describe("token-registry", () => { fork: { network: defaultNetwork, }, - }; + } as any; const ganacheProvider = ganache.provider(ganacheOptions); @@ -86,7 +86,7 @@ describe("token-registry", () => { async ({}: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< Wallet | ConnectedSigner > => { - const provider = new ethers.providers.Web3Provider(ganacheProvider); + const provider = new ethers.providers.Web3Provider(ganacheProvider as any); const wallet = await ethers.Wallet.fromMnemonic(accounts.mnemonic, "m/44'/60'/0'/0/0"); const connectedWallet = wallet.connect(provider); return connectedWallet; From f80a0eff2257923ba480ea389162217b442952c8 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 00:26:09 +0800 Subject: [PATCH 15/63] fix: setAdminRole - update wording --- src/commands/token-registry/role/set-admin-role.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/token-registry/role/set-admin-role.ts b/src/commands/token-registry/role/set-admin-role.ts index 490f11c1..c30025b6 100644 --- a/src/commands/token-registry/role/set-admin-role.ts +++ b/src/commands/token-registry/role/set-admin-role.ts @@ -31,7 +31,7 @@ export const builder = (yargs: Argv): Argv => choices: normalRolesInput, }) .option("adminRole", { - describe: "Role to be set to Admin Role", + describe: "Admin Role to be set to Role", type: "string", nargs: 1, demandOption: true, From 208452c01dcf68887eaaeff5ce5f3e64fe7efb7d Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 16:34:22 +0800 Subject: [PATCH 16/63] feat: update token registry --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ddbf138f..fde5d016 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@govtechsg/oa-encryption": "^1.3.3", "@govtechsg/oa-verify": "^7.11.0", "@govtechsg/open-attestation": "^6.4.1", - "@govtechsg/token-registry": "^4.0.0-beta.15", + "@govtechsg/token-registry": "^4.0.0-beta.18", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", From ad97c6c140ffc5ffcc0c1076f69899e098d27378 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 16:38:41 +0800 Subject: [PATCH 17/63] fix: update package-lock --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 885e1d8d..ea2430fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2002,9 +2002,9 @@ } }, "@govtechsg/token-registry": { - "version": "4.0.0-beta.15", - "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.0.0-beta.15.tgz", - "integrity": "sha512-wctboADcpR2Df/FFYzv9sLt7zI0ojRywNl30/Ot4ix1uVZev57OeNnVbruxojPm76LGCalgPnqxDNnM9SPWPAQ==", + "version": "4.0.0-beta.18", + "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.0.0-beta.18.tgz", + "integrity": "sha512-Wp2xxbjVaYiDV/ocGugl5GwGU9ouw0B5Vzce1mgjWqJX2clWnM+hU0RcDj9srww9GtS0vKX43dyymng16MZ7ww==", "requires": { "@typechain/ethers-v5": "~10.0.0" } From 28969f9abd4ac74029432094af34d867c145e47f Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 22 Sep 2022 18:43:16 +0800 Subject: [PATCH 18/63] feat: update token-registry e2e default goerli --- src/__tests__/token-registry.e2e.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index 3c91c928..795eadcb 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -55,7 +55,7 @@ describe("token-registry", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; - const defaultNetwork = "ropsten"; + const defaultNetwork = "goerli"; const defaults = { network: defaultNetwork, From 38680bbf66fedaff91e651eed49ac0cd21e75fbb Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 29 Sep 2022 10:11:47 +0800 Subject: [PATCH 19/63] fix: code --- src/__tests__/token-registry.e2e.test.ts | 56 ++++++++++-------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index 795eadcb..e95c8b45 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -21,6 +21,7 @@ import ganache from "ganache"; import { endorseChangeOfOwner } from "../implementations/title-escrow/changeOwner"; import { nominateBeneficiary } from "../implementations/title-escrow/nominateBeneficiary"; import { endorseNominatedBeneficiary } from "../implementations/title-escrow/endorseNominatedBeneficiary"; +import { isAddress } from "ethers/lib/utils"; jest.mock("../implementations/utils/wallet", () => { const originalModule = jest.requireActual("../implementations/utils/wallet"); @@ -31,21 +32,18 @@ jest.mock("../implementations/utils/wallet", () => { }; }); -const accounts = { - mnemonic: "indicate swing place chair flight used hammer soon photo region volume shuffle", - owner: { - ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", - publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", - privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", - }, - receiver: { - ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", - publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", - privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", - }, +const mnemonic = "indicate swing place chair flight used hammer soon photo region volume shuffle"; +const owner = { + ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", + publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", + privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", }; -const regexEthAddress = new RegExp("^0x[a-fA-F0-9]{40}$"); +const receiver = { + ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", + publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", + privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", +}; describe("token-registry", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -55,7 +53,7 @@ describe("token-registry", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; - const defaultNetwork = "goerli"; + const defaultNetwork = "ropsten"; const defaults = { network: defaultNetwork, @@ -72,7 +70,7 @@ describe("token-registry", () => { chainId: 3, }, wallet: { - mnemonic: accounts.mnemonic, + mnemonic: mnemonic, }, fork: { network: defaultNetwork, @@ -87,7 +85,7 @@ describe("token-registry", () => { Wallet | ConnectedSigner > => { const provider = new ethers.providers.Web3Provider(ganacheProvider as any); - const wallet = await ethers.Wallet.fromMnemonic(accounts.mnemonic, "m/44'/60'/0'/0/0"); + const wallet = await ethers.Wallet.fromMnemonic(mnemonic, "m/44'/60'/0'/0/0"); const connectedWallet = wallet.connect(provider); return connectedWallet; } @@ -105,16 +103,10 @@ describe("token-registry", () => { ...defaults, }; const tokenRegistryTransaction = await deployTokenRegistry(tokenRegistryParameter); - const validTokenRegistryDeploy = regexEthAddress.test(tokenRegistryTransaction.contractAddress); - expect(validTokenRegistryDeploy).toBe(true); + expect(isAddress(tokenRegistryTransaction.contractAddress)).toBe(true); tokenRegistryAddress = tokenRegistryTransaction.contractAddress; }); - const mintTransactionParameter = { - to: accounts.owner.ethAddress, - ...defaults, - }; - const mintTransaction = async ( retrievedTokenRegistryAddress: string, tokenId: string @@ -122,9 +114,9 @@ describe("token-registry", () => { const transactionParameter: TokenRegistryIssueCommand = { address: retrievedTokenRegistryAddress, tokenId: tokenId, - beneficiary: accounts.owner.ethAddress, - holder: accounts.owner.ethAddress, - ...mintTransactionParameter, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + ...defaults, }; const transaction = await issueToTokenRegistry(transactionParameter); return transaction; @@ -202,7 +194,7 @@ describe("token-registry", () => { const transactionParameter: TitleEscrowChangeHolderCommand = { tokenRegistry: retrievedTokenRegistryAddress, tokenId: tokenId, - to: accounts.receiver.ethAddress, + to: receiver.ethAddress, ...defaults, }; const transaction = await changeHolderOfTitleEscrow(transactionParameter); @@ -213,8 +205,8 @@ describe("token-registry", () => { const transactionParameter: TitleEscrowEndorseChangeOfOwnerCommand = { tokenRegistry: retrievedTokenRegistryAddress, tokenId: tokenId, - newHolder: accounts.receiver.ethAddress, - newOwner: accounts.receiver.ethAddress, + newHolder: receiver.ethAddress, + newOwner: receiver.ethAddress, ...defaults, }; const transaction = await endorseChangeOfOwner(transactionParameter); @@ -228,7 +220,7 @@ describe("token-registry", () => { const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { tokenRegistry: retrievedTokenRegistryAddress, tokenId: tokenId, - newOwner: accounts.receiver.ethAddress, + newOwner: receiver.ethAddress, ...defaults, }; const transaction = await nominateBeneficiary(transactionParameter); @@ -271,12 +263,12 @@ describe("token-registry", () => { const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { tokenRegistry: retrievedTokenRegistryAddress, tokenId: tokenId, - newOwner: accounts.receiver.ethAddress, + newOwner: receiver.ethAddress, ...defaults, }; const transaction = await endorseNominatedBeneficiary(transactionParameter); - expect(transaction.nominatedBeneficiary).toBe(accounts.receiver.ethAddress); + expect(transaction.nominatedBeneficiary).toBe(receiver.ethAddress); expect(transaction.transactionReceipt.confirmations).toBeGreaterThanOrEqual(1); expect(transaction.transactionReceipt.status).toBe(1); }); From 517f1a6454b40f84340e46ba56814030e079f54b Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:23:55 +0800 Subject: [PATCH 20/63] fix: typo and moved to goerli --- src/__tests__/token-registry.e2e.test.ts | 2 +- .../token-registry/role/grant-role.ts | 2 +- .../token-registry/role/revoke-role.ts | 2 +- .../token-registry/token-registry.test.ts | 163 +++++++++++++++++- .../deploy/token-registry/token-registry.ts | 2 +- .../document-store/transfer-ownership.test.ts | 2 +- .../title-escrow/acceptSurrendered.test.ts | 2 +- .../title-escrow/changeHolder.test.ts | 2 +- .../title-escrow/changeOwner.test.ts | 2 +- .../endorseNominatedBeneficiary.test..ts | 2 +- .../title-escrow/nominateBeneficiary.test.ts | 2 +- .../title-escrow/rejectSurrendered.test.ts | 2 +- .../title-escrow/surrenderDocument.test.ts | 2 +- .../title-escrow/surrenderDocument.ts | 40 +---- .../token-registry/issue.test.ts | 2 +- .../token-registry/role/grant-role.test.ts | 2 +- .../token-registry/role/revoke-role.test.ts | 2 +- .../token-registry/role/set-role.test.ts | 2 +- 18 files changed, 181 insertions(+), 54 deletions(-) diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts index e95c8b45..75ba863f 100644 --- a/src/__tests__/token-registry.e2e.test.ts +++ b/src/__tests__/token-registry.e2e.test.ts @@ -53,7 +53,7 @@ describe("token-registry", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; - const defaultNetwork = "ropsten"; + const defaultNetwork = "goerli"; const defaults = { network: defaultNetwork, diff --git a/src/commands/token-registry/role/grant-role.ts b/src/commands/token-registry/role/grant-role.ts index 9f9fcaf0..adf9fcb3 100644 --- a/src/commands/token-registry/role/grant-role.ts +++ b/src/commands/token-registry/role/grant-role.ts @@ -24,7 +24,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("role", { - describe: "Role to be granted to receipient", + describe: "Role to be granted to recipient", type: "string", nargs: 1, demandOption: true, diff --git a/src/commands/token-registry/role/revoke-role.ts b/src/commands/token-registry/role/revoke-role.ts index 70dbd567..68e514a3 100644 --- a/src/commands/token-registry/role/revoke-role.ts +++ b/src/commands/token-registry/role/revoke-role.ts @@ -24,7 +24,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("role", { - describe: "Role to be revoked from receipient", + describe: "Role to be revoked from recipient", type: "string", nargs: 1, demandOption: true, diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 57ac77d6..9840b70b 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -1,12 +1,13 @@ import { deployTokenRegistry, encodeInitParams } from "./token-registry"; -import { Contract } from "ethers"; +import { BigNumber, Contract, ContractReceipt } from "ethers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; +import { getEventFromReceipt } from "./token-registry"; const deployParams: DeployTokenRegistryCommand = { registryName: "Test", registrySymbol: "Tst", - network: "ropsten", + network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", gasPriceScale: 1, dryRun: false, @@ -74,12 +75,11 @@ describe("token-registry", () => { }); it("should throw when keys are not found anywhere", async () => { - delete process.env.OA_PRIVATE_KEY; await expect( deployTokenRegistry({ registryName: "Test", registrySymbol: "Tst", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }) @@ -88,4 +88,159 @@ describe("token-registry", () => { ); }); }); + + describe("getEventFromReceipt", () => { + it("should return the event from the receipt", async () => { + const receipt = { + to: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', + from: '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', + contractAddress: null, + transactionIndex: 36, + gasUsed: { _hex: '0x0496e5', _isBigNumber: true } as BigNumber, + logsBloom: '0x0000000400000080000000000000800000000100000000000000000000000000000000008000000000000000000000410000000000000000000200000000000000000000000000000000000000000000000000001800000040000000000000000040000002000000000000000000080000100000100000000000000000100000000000004000000040000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000110080000000000000000000000000000000000000002000100000000000010000000000002000000000000000000000000000010001000040000000c400400000000001400000', + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + logs: [ + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 86, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 87, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 88, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 89, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', + topics: [], + data: '0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', + logIndex: 90, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' + } + ], + blockNumber: 7725626, + confirmations: 1, + cumulativeGasUsed: { _hex: '0x013255bb', _isBigNumber: true } as BigNumber, + effectiveGasPrice: { _hex: '0x030d31', _isBigNumber: true } as BigNumber, + status: 1, + type: 2, + byzantium: true, + events: [ + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 86, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + removeListener: [Function], + getBlock: [Function], + getTransaction: [Function], + getTransactionReceipt: [Function] + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 87, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + removeListener: [Function], + getBlock: [Function], + getTransaction: [Function], + getTransactionReceipt: [Function] + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 88, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + removeListener: [Function], + getBlock: [Function], + getTransaction: [Function], + getTransactionReceipt: [Function] + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', + topics: [], + data: '0x', + logIndex: 89, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + removeListener: [Function], + getBlock: [Function], + getTransaction: [Function], + getTransactionReceipt: [Function] + }, + { + transactionIndex: 36, + blockNumber: 7725626, + transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', + address: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', + topics: ['0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5'], + data: '0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', + logIndex: 90, + blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', + args: [], + decode: [], + event: 'Deployment', + eventSignature: 'Deployment(address,address,address,address,bytes)', + removeListener: [], + getBlock: [], + getTransaction: [], + getTransactionReceipt: [] + } + ] + } as unknown as ContractReceipt; + + const topics = '0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5'; + + console.log(getEventFromReceipt(receipt, topics, undefined)); + + }); + }) }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index e12b65e9..8103288e 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -47,7 +47,7 @@ export const deployTokenRegistry = async ({ deployContractAddress.tokenImplementation, initParam ); - signale.info("Dry Run is unavailable for token reigstry deploy"); + signale.info("Dry Run is unavailable for token registry deploy"); signale.info(`Estimated Gas Required: ${estimatedGas.toString()}`); process.exit(0); } diff --git a/src/implementations/document-store/transfer-ownership.test.ts b/src/implementations/document-store/transfer-ownership.test.ts index d59b35e9..f43ab650 100644 --- a/src/implementations/document-store/transfer-ownership.test.ts +++ b/src/implementations/document-store/transfer-ownership.test.ts @@ -10,7 +10,7 @@ jest.mock("@govtechsg/document-store"); const deployParams: DocumentStoreTransferOwnershipCommand = { newOwner: "0xabcd", address: "0x1234", - network: "ropsten", + network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", gasPriceScale: 1, dryRun: false, diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index a39db117..2b6c9799 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -9,7 +9,7 @@ jest.mock("@govtechsg/token-registry/contracts"); const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/changeHolder.test.ts index 170f3e66..de9b8b3c 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/changeHolder.test.ts @@ -10,7 +10,7 @@ const transferHolderParams: TitleEscrowChangeHolderCommand = { to: "0xabcd", tokenId: "0xzyxw", tokenRegistry: "0x1234", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/changeOwner.test.ts b/src/implementations/title-escrow/changeOwner.test.ts index 62437aff..00ae8fb6 100644 --- a/src/implementations/title-escrow/changeOwner.test.ts +++ b/src/implementations/title-escrow/changeOwner.test.ts @@ -11,7 +11,7 @@ const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { newOwner: "0fosui", tokenId: "0xzyxw", tokenRegistry: "0x1234", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts index 3c47f7c9..25f582e6 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts @@ -10,7 +10,7 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = tokenId: "0xzyxw", tokenRegistry: "0x1234", newOwner: "0x1232", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index 17e5f868..1dbd498d 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -10,7 +10,7 @@ const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { newOwner: "0fosui", tokenId: "0xzyxw", tokenRegistry: "0x1234", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 0d26e73b..f02eeaa6 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -9,7 +9,7 @@ jest.mock("@govtechsg/token-registry/contracts"); const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 26644887..1edd8220 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -9,7 +9,7 @@ jest.mock("@govtechsg/token-registry/contracts"); const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index a38322bf..75c83c94 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -1,13 +1,10 @@ import signale from "signale"; import { getLogger } from "../../logger"; -import { ConnectedSigner, getWalletOrSigner } from "../utils/wallet"; +import { getWalletOrSigner } from "../utils/wallet"; import { connectToTitleEscrow } from "./helpers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; - import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { ContractTransaction, Wallet } from "ethers"; -import { TitleEscrow } from "@govtechsg/token-registry/contracts"; const { trace } = getLogger("title-escrow:surrenderDocument"); @@ -22,34 +19,6 @@ export const surrenderDocument = async ({ const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const transaction: ContractTransaction = await surrendeDocument({ - tokenRegistry: address, - tokenId, - network, - gasPriceScale, - dryRun, - titleEscrow, - wallet, - }); - - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - return transaction.wait(); -}; - -export type VersionedTitleEscrowSurrenderDocumentCommand = TitleEscrowSurrenderDocumentCommand & { - titleEscrow: TitleEscrow; - wallet: Wallet | ConnectedSigner; -}; - -export const surrendeDocument = async ({ - network, - gasPriceScale, - dryRun, - titleEscrow, - wallet, -}: VersionedTitleEscrowSurrenderDocumentCommand): Promise => { if (dryRun) { await dryRunMode({ gasPriceScale: gasPriceScale, @@ -62,5 +31,8 @@ export const surrendeDocument = async ({ signale.await(`Sending transaction to pool`); await titleEscrow.callStatic.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); const transaction = await titleEscrow.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); - return transaction; -}; + trace(`Tx hash: ${transaction.hash}`); + trace(`Block Number: ${transaction.blockNumber}`); + signale.await(`Waiting for transaction ${transaction.hash} to be mined`); + return transaction.wait(); +}; \ No newline at end of file diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index d6b0cdae..e505930c 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -12,7 +12,7 @@ const deployParams: TokenRegistryIssueCommand = { holder: "0xabce", tokenId: "0xzyxw", address: "0x1234", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts index ae86fa02..35cc0b68 100644 --- a/src/implementations/token-registry/role/grant-role.test.ts +++ b/src/implementations/token-registry/role/grant-role.test.ts @@ -9,7 +9,7 @@ const roleParams: TokenRegistryRoleCommand = { address: "0x1122", role: "0x1", recipient: "0x12345", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts index 60a41c94..0a193648 100644 --- a/src/implementations/token-registry/role/revoke-role.test.ts +++ b/src/implementations/token-registry/role/revoke-role.test.ts @@ -9,7 +9,7 @@ const roleParams: TokenRegistryRoleCommand = { address: "0x1122", role: "0x1", recipient: "0x12345", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts index 01496400..77a37bf0 100644 --- a/src/implementations/token-registry/role/set-role.test.ts +++ b/src/implementations/token-registry/role/set-role.test.ts @@ -8,7 +8,7 @@ const roleParams: TokenRegistrySetRoleAdminCommand = { address: "0x1122", role: "0x1", adminRole: "0x2", - network: "ropsten", + network: "goerli", gasPriceScale: 1, dryRun: false, }; From 65f300c2326e317b8ef1b03024a47d6648a069db Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Mon, 10 Oct 2022 13:10:10 +0800 Subject: [PATCH 21/63] fix: clean up token regostry deploy --- README.md | 6 +- src/commands/deploy/deploy.types.ts | 2 - .../token-registry/token-registry.test.ts | 179 +++--------------- .../deploy/token-registry/token-registry.ts | 2 +- 4 files changed, 27 insertions(+), 162 deletions(-) diff --git a/README.md b/README.md index 56a51b86..6096b482 100644 --- a/README.md +++ b/README.md @@ -247,11 +247,11 @@ open-attestation decrypt ./src/__tests__/fixture/did-dns-encrypted.json decrypte ✔ success Decrypted document saved to: decrypted.json ``` -### Token registry +### Token Registry -#### Deploy new token registry +#### Deploy new Token Registry -Deploys a token registry contract on the blockchain +Deploys a token registry contract on the blockchain. Factory Contract that have been deployed using token-registry can be used with the factory address flag. To deploy a standalone token registry, please refer to [Token-Registry](https://github.com/Open-Attestation/token-registry) deployment. ```bash open-attestation deploy token-registry --factory-address [options] diff --git a/src/commands/deploy/deploy.types.ts b/src/commands/deploy/deploy.types.ts index aa9d2ac8..3665e1f6 100644 --- a/src/commands/deploy/deploy.types.ts +++ b/src/commands/deploy/deploy.types.ts @@ -9,7 +9,5 @@ export type DeployTokenRegistryCommand = NetworkAndWalletSignerOption & GasOption & { registryName: string; registrySymbol: string; - verify?: boolean; - standalone?: boolean; factoryAddress?: string; }; diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 9840b70b..e1ae5e78 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -1,8 +1,8 @@ -import { deployTokenRegistry, encodeInitParams } from "./token-registry"; -import { BigNumber, Contract, ContractReceipt } from "ethers"; +import { deployTokenRegistry, encodeInitParams, retrieveFactoryAddress } from "./token-registry"; +import { Contract } from "ethers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; -import { getEventFromReceipt } from "./token-registry"; +import { isAddress } from "ethers/lib/utils"; const deployParams: DeployTokenRegistryCommand = { registryName: "Test", @@ -87,160 +87,27 @@ describe("token-registry", () => { "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" ); }); - }); - describe("getEventFromReceipt", () => { - it("should return the event from the receipt", async () => { - const receipt = { - to: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', - from: '0x8d366250A96deBE81C8619459a503a0eEBE33ca6', - contractAddress: null, - transactionIndex: 36, - gasUsed: { _hex: '0x0496e5', _isBigNumber: true } as BigNumber, - logsBloom: '0x0000000400000080000000000000800000000100000000000000000000000000000000008000000000000000000000410000000000000000000200000000000000000000000000000000000000000000000000001800000040000000000000000040000002000000000000000000080000100000100000000000000000100000000000004000000040000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000110080000000000000000000000000000000000000002000100000000000010000000000002000000000000000000000000000010001000040000000c400400000000001400000', - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - logs: [ - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 86, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 87, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 88, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 89, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', - topics: [], - data: '0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', - logIndex: 90, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826' - } - ], - blockNumber: 7725626, - confirmations: 1, - cumulativeGasUsed: { _hex: '0x013255bb', _isBigNumber: true } as BigNumber, - effectiveGasPrice: { _hex: '0x030d31', _isBigNumber: true } as BigNumber, - status: 1, - type: 2, - byzantium: true, - events: [ - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 86, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - removeListener: [Function], - getBlock: [Function], - getTransaction: [Function], - getTransactionReceipt: [Function] - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 87, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - removeListener: [Function], - getBlock: [Function], - getTransaction: [Function], - getTransactionReceipt: [Function] - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 88, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - removeListener: [Function], - getBlock: [Function], - getTransaction: [Function], - getTransactionReceipt: [Function] - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x426c58C2B29111eAfc53bDcB9C99DC7714FDb262', - topics: [], - data: '0x', - logIndex: 89, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - removeListener: [Function], - getBlock: [Function], - getTransaction: [Function], - getTransactionReceipt: [Function] - }, - { - transactionIndex: 36, - blockNumber: 7725626, - transactionHash: '0x3deb27a2513e3e421e12aa1ff54f11c98abe78020bff9c0b902861f83a808346', - address: '0x9eBC30E7506E6Ce36eAc5507FCF0121BaF7AeA57', - topics: ['0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5'], - data: '0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000', - logIndex: 90, - blockHash: '0xc9b9a44452c0131ed1859f79b90ca4eb5b66a90b458cf852faedaa38e3d40826', - args: [], - decode: [], - event: 'Deployment', - eventSignature: 'Deployment(address,address,address,address,bytes)', - removeListener: [], - getBlock: [], - getTransaction: [], - getTransactionReceipt: [] - } - ] - } as unknown as ContractReceipt; - - const topics = '0x3588ebb5c75fdf91927f8472318f41513ee567c2612a5ce52ac840dcf6f162f5'; + describe("Valid Token Registry Factory Address", () => { - console.log(getEventFromReceipt(receipt, topics, undefined)); + it("should return valid deployer address", () => { + const address = retrieveFactoryAddress(5, undefined); + + expect(isAddress(address.titleEscrowFactory)).toBe(true); + expect(isAddress(address.tokenImplementation)).toBe(true); + expect(isAddress(address.deployer)).toBe(true); + }); - }); - }) + it("should return valid deployer address", () => { + const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7" + const address = retrieveFactoryAddress(5, suppliedAddress); + + expect(address.titleEscrowFactory).toBe(suppliedAddress); + expect(isAddress(address.tokenImplementation)).toBe(true); + expect(isAddress(address.deployer)).toBe(true); + }); + + }) + + }); }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 8103288e..1c6c7cd3 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -76,7 +76,7 @@ export const encodeInitParams = ({ name, symbol, deployer }: Params): string => return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); }; -const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { +export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { const { contractAddress } = constants; if (!chainId) { From 1867a2188d8e1729837ee63754c0bd4c2df37bab Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Mon, 10 Oct 2022 18:18:52 +0800 Subject: [PATCH 22/63] chore: remove files based on discussion --- README.md | 52 +--- package-lock.json | 283 ----------------- package.json | 1 - src/__tests__/token-registry.e2e.test.ts | 287 ------------------ src/commands/token-registry/role.ts | 9 - .../token-registry/role/grant-role.ts | 55 ---- src/commands/token-registry/role/helper.ts | 25 -- .../token-registry/role/revoke-role.ts | 55 ---- .../token-registry/role/set-admin-role.ts | 58 ---- .../token-registry-command.type.ts | 16 +- src/implementations/title-escrow/helpers.ts | 7 - .../token-registry/role/grant-role.test.ts | 64 ---- .../token-registry/role/grant-role.ts | 41 --- .../token-registry/role/revoke-role.test.ts | 64 ---- .../token-registry/role/revoke-role.ts | 41 --- .../token-registry/role/set-role.test.ts | 63 ---- .../token-registry/role/set-role.ts | 41 --- 17 files changed, 3 insertions(+), 1159 deletions(-) delete mode 100644 src/__tests__/token-registry.e2e.test.ts delete mode 100644 src/commands/token-registry/role.ts delete mode 100644 src/commands/token-registry/role/grant-role.ts delete mode 100644 src/commands/token-registry/role/helper.ts delete mode 100644 src/commands/token-registry/role/revoke-role.ts delete mode 100644 src/commands/token-registry/role/set-admin-role.ts delete mode 100644 src/implementations/token-registry/role/grant-role.test.ts delete mode 100644 src/implementations/token-registry/role/grant-role.ts delete mode 100644 src/implementations/token-registry/role/revoke-role.test.ts delete mode 100644 src/implementations/token-registry/role/revoke-role.ts delete mode 100644 src/implementations/token-registry/role/set-role.test.ts delete mode 100644 src/implementations/token-registry/role/set-role.ts diff --git a/README.md b/README.md index 6096b482..e37da297 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,6 @@ npx -p @govtechsg/open-attestation-cli open-attestation | Document store transfer ownership | ✔ | ✔ | ✔ | | Token registry issue | ✔ | ✔ | ✔ | | Token registry mint | ✔ | ✔ | ✔ | -| Token registry grant role | ✔ | ✔ | ✔ | -| Token registry revoke role | ✔ | ✔ | ✔ | -| Token registry set role | ✔ | ✔ | ✔ | | Transaction cancel | ✔ | ✔ | ✔ | | Wallet create | ❎ | ❎ | ❎ | | Wallet decrypt | ❎ | ❎ | ❎ | @@ -284,55 +281,10 @@ open-attestation token-registry mint --network ropsten --address 0x6133f580aE903 `mint` can be used instead of issue and will be strictly equivalent. -#### Token Registry Roles - Grant +#### Token Registry Roles -Assign a role to a wallet address on the token registry deployed on the blockchain. The `recipient` option to indicate the wallet address that will be assigned the role, and the `role` option would be used to indicate the role given to the wallet address on the token registry. +Interfaces for the Assignment and Revocation of roles are available on the Token Registry repository. -```bash -open-attestation token-registry role grant-role --network --address --recipient --role [options] -``` - -Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). - -```bash -open-attestation token-registry role grant-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role restorer --recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 - -✔ success Role restorer has been assigned to the recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 -``` - -#### Token Registry Roles - Revoke - -Revoke a role of a wallet address on the token registry deployed on the blockchain. The `recipient` option indicates the wallet address that will be revoked of the role, and the `role` option would be used to indicate the role to be revoked from the wallet address on the token registry. - -```bash -open-attestation token-registry role revoke-role --network --address --recipient --role [options] -``` - -Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). - -```bash -open-attestation token-registry role revoke-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role restorer --recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 - -✔ success Role restorer has been revoked from the recipient 0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 -``` - - -#### Token Registry Roles - Set Role - -Set role on the token registry to be have additional admin roles on the blockchain. The `role` option is the role to be provided additional roles, and the `adminRole` option sets the additional role granted to the `role`. - -```bash -open-attestation token-registry role set-role --network --address --role --adminRole [options] -``` - -Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). - -```bash -0x90264b594B8dc2225cb7D05a14e78483BAc7FBF7 -open-attestation token-registry role set-role --address 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 --role minter --adminRole minterAdmin - -✔ success Role minterAdmin has been assigned to the recipient minter in the registry 0x405b976660b94e0839C4dBdCcb8D4837B9869AC5 -``` ### Document Store diff --git a/package-lock.json b/package-lock.json index ea2430fb..be4aa22f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7941,289 +7941,6 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, - "ganache": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.4.3.tgz", - "integrity": "sha512-RpEDUiCkqbouyE7+NMXG26ynZ+7sGiODU84Kz+FVoXUnQ4qQM4M8wif3Y4qUCt+D/eM1RVeGq0my62FPD6Y1KA==", - "requires": { - "@trufflesuite/bigint-buffer": "1.1.10", - "@types/bn.js": "^5.1.0", - "@types/lru-cache": "5.1.1", - "@types/seedrandom": "3.0.1", - "bufferutil": "4.0.5", - "emittery": "0.10.0", - "keccak": "3.0.2", - "leveldown": "6.1.0", - "secp256k1": "4.0.3", - "utf-8-validate": "5.0.7" - }, - "dependencies": { - "@trufflesuite/bigint-buffer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz", - "integrity": "sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==", - "requires": { - "node-gyp-build": "4.4.0" - }, - "dependencies": { - "node-gyp-build": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", - "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" - } - } - }, - "@types/bn.js": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", - "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", - "requires": { - "@types/node": "*" - } - }, - "@types/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==" - }, - "@types/node": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", - "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==" - }, - "@types/seedrandom": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.1.tgz", - "integrity": "sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "bufferutil": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", - "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "catering": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", - "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", - "requires": { - "queue-tick": "^1.0.0" - } - }, - "elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "requires": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - }, - "dependencies": { - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - } - } - }, - "emittery": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", - "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==" - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "is-buffer": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", - "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" - }, - "keccak": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", - "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", - "requires": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.6.0" - } - }, - "leveldown": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", - "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", - "requires": { - "abstract-leveldown": "^7.2.0", - "napi-macros": "~2.0.0", - "node-gyp-build": "^4.3.0" - }, - "dependencies": { - "abstract-leveldown": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", - "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", - "requires": { - "buffer": "^6.0.3", - "catering": "^2.0.0", - "is-buffer": "^2.0.5", - "level-concat-iterator": "^3.0.0", - "level-supports": "^2.0.1", - "queue-microtask": "^1.2.3" - } - }, - "level-concat-iterator": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", - "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", - "requires": { - "catering": "^2.1.0" - } - }, - "level-supports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", - "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==" - } - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "napi-macros": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", - "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==" - }, - "node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" - }, - "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "queue-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", - "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==" - }, - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - }, - "secp256k1": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", - "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", - "requires": { - "elliptic": "^6.5.4", - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "utf-8-validate": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", - "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", - "optional": true, - "requires": { - "node-gyp-build": "^4.3.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - } - } - }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", diff --git a/package.json b/package.json index fde5d016..4d0ad336 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,6 @@ "debug": "^4.3.2", "ethers": "^5.4.7", "ethers-aws-kms-signer": "^1.3.2", - "ganache": "^7.4.3", "inquirer": "^8.0.0", "mkdirp": "^1.0.4", "node-fetch": "^2.6.1", diff --git a/src/__tests__/token-registry.e2e.test.ts b/src/__tests__/token-registry.e2e.test.ts deleted file mode 100644 index 75ba863f..00000000 --- a/src/__tests__/token-registry.e2e.test.ts +++ /dev/null @@ -1,287 +0,0 @@ -import { ethers, Wallet } from "ethers"; -import { DeployTokenRegistryCommand } from "../commands/deploy/deploy.types"; -import { NetworkOption, WalletOrSignerOption } from "../commands/shared"; -import { - BaseTitleEscrowCommand, - TitleEscrowChangeHolderCommand, - TitleEscrowEndorseChangeOfOwnerCommand, - TitleEscrowNominateBeneficiaryCommand, -} from "../commands/title-escrow/title-escrow-command.type"; -import { TokenRegistryIssueCommand } from "../commands/token-registry/token-registry-command.type"; -import { deployTokenRegistry } from "../implementations/deploy/token-registry"; -import { surrenderDocument } from "../implementations/title-escrow/surrenderDocument"; -import { issueToTokenRegistry } from "../implementations/token-registry/issue"; -import { ConnectedSigner, getWalletOrSigner } from "../implementations/utils/wallet"; -import { TransactionReceipt } from "@ethersproject/providers"; -import { acceptSurrendered } from "../implementations/title-escrow/acceptSurrendered"; -import { rejectSurrendered } from "../implementations/title-escrow/rejectSurrendered"; -import { changeHolderOfTitleEscrow } from "../implementations/title-escrow/changeHolder"; - -import ganache from "ganache"; -import { endorseChangeOfOwner } from "../implementations/title-escrow/changeOwner"; -import { nominateBeneficiary } from "../implementations/title-escrow/nominateBeneficiary"; -import { endorseNominatedBeneficiary } from "../implementations/title-escrow/endorseNominatedBeneficiary"; -import { isAddress } from "ethers/lib/utils"; - -jest.mock("../implementations/utils/wallet", () => { - const originalModule = jest.requireActual("../implementations/utils/wallet"); - return { - __esModule: true, - ...originalModule, - getWalletOrSigner: jest.fn(), - }; -}); - -const mnemonic = "indicate swing place chair flight used hammer soon photo region volume shuffle"; -const owner = { - ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", - publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", - privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", -}; - -const receiver = { - ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", - publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", - privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", -}; - -describe("token-registry", () => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore mock static method - const mockedGetWalletOrSigner: jest.Mock = getWalletOrSigner as jest.Mock; - - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - const defaultNetwork = "goerli"; - - const defaults = { - network: defaultNetwork, - gasPriceScale: 1, - dryRun: false, - }; - const ganacheOptions = { - logging: { - debug: false, - quiet: true, - verbose: false, - }, - chain: { - chainId: 3, - }, - wallet: { - mnemonic: mnemonic, - }, - fork: { - network: defaultNetwork, - }, - } as any; - - const ganacheProvider = ganache.provider(ganacheOptions); - - beforeAll(() => { - mockedGetWalletOrSigner.mockImplementation( - async ({}: WalletOrSignerOption & Partial & { progress?: (progress: number) => void }): Promise< - Wallet | ConnectedSigner - > => { - const provider = new ethers.providers.Web3Provider(ganacheProvider as any); - const wallet = await ethers.Wallet.fromMnemonic(mnemonic, "m/44'/60'/0'/0/0"); - const connectedWallet = wallet.connect(provider); - return connectedWallet; - } - ); - }); - - afterAll(async () => { - await ganacheProvider.disconnect(); - }); - - it("should be able to deploy token-registry", async () => { - const tokenRegistryParameter: DeployTokenRegistryCommand = { - registryName: "Test Token", - registrySymbol: "TKN", - ...defaults, - }; - const tokenRegistryTransaction = await deployTokenRegistry(tokenRegistryParameter); - expect(isAddress(tokenRegistryTransaction.contractAddress)).toBe(true); - tokenRegistryAddress = tokenRegistryTransaction.contractAddress; - }); - - const mintTransaction = async ( - retrievedTokenRegistryAddress: string, - tokenId: string - ): Promise => { - const transactionParameter: TokenRegistryIssueCommand = { - address: retrievedTokenRegistryAddress, - tokenId: tokenId, - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - ...defaults, - }; - const transaction = await issueToTokenRegistry(transactionParameter); - return transaction; - }; - - it("should be able to mint title-escrow", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000000"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - const transaction = await mintTransaction(retrievedTokenRegistryAddress, tokenId); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - describe("title-escrow surrender", () => { - const surrenderTransaction = async ( - retrievedTokenRegistryAddress: string, - tokenId: string - ): Promise => { - const transactionParameter: BaseTitleEscrowCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - ...defaults, - }; - const transaction = await surrenderDocument(transactionParameter); - return transaction; - }; - - it("should be able to surrender title-escrow", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000001"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transaction = await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - describe("title-escrow surrender response", () => { - it("should be able to accept surrender title-escrow", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000002"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: BaseTitleEscrowCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - ...defaults, - }; - const transaction = await acceptSurrendered(transactionParameter); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - it("should be able to reject surrender title-escrow", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000003"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - await surrenderTransaction(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: BaseTitleEscrowCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - ...defaults, - }; - const transaction = await rejectSurrendered(transactionParameter); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - }); - }); - - describe("title-escrow transfers", () => { - const changeHolder = async ( - retrievedTokenRegistryAddress: string, - tokenId: string - ): Promise => { - const transactionParameter: TitleEscrowChangeHolderCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - to: receiver.ethAddress, - ...defaults, - }; - const transaction = await changeHolderOfTitleEscrow(transactionParameter); - return transaction; - }; - - const changeOwner = async (retrievedTokenRegistryAddress: string, tokenId: string): Promise => { - const transactionParameter: TitleEscrowEndorseChangeOfOwnerCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - newHolder: receiver.ethAddress, - newOwner: receiver.ethAddress, - ...defaults, - }; - const transaction = await endorseChangeOfOwner(transactionParameter); - return transaction; - }; - - const nominateTitleEscrowBeneficiary = async ( - retrievedTokenRegistryAddress: string, - tokenId: string - ): Promise => { - const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - newOwner: receiver.ethAddress, - ...defaults, - }; - const transaction = await nominateBeneficiary(transactionParameter); - return transaction; - }; - - it("should be able to change title escrow holder", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000004"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transaction = await changeHolder(retrievedTokenRegistryAddress, tokenId); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - it("should be able to change title escrow owner", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000005"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transaction = await changeOwner(retrievedTokenRegistryAddress, tokenId); - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - it("should be able to nominate title escrow beneficiaries", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000006"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - const transaction = await nominateTitleEscrowBeneficiary(retrievedTokenRegistryAddress, tokenId); - - expect(transaction.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.status).toBe(1); - }); - - it("should be able to complete transfer of title escrow beneficiaries", async () => { - const tokenId = "0x0000000000000000000000000000000000000000000000000000000000000007"; - const retrievedTokenRegistryAddress = await getTokenRegistryAddress(); - await mintTransaction(retrievedTokenRegistryAddress, tokenId); - await nominateTitleEscrowBeneficiary(retrievedTokenRegistryAddress, tokenId); - const transactionParameter: TitleEscrowNominateBeneficiaryCommand = { - tokenRegistry: retrievedTokenRegistryAddress, - tokenId: tokenId, - newOwner: receiver.ethAddress, - ...defaults, - }; - const transaction = await endorseNominatedBeneficiary(transactionParameter); - - expect(transaction.nominatedBeneficiary).toBe(receiver.ethAddress); - expect(transaction.transactionReceipt.confirmations).toBeGreaterThanOrEqual(1); - expect(transaction.transactionReceipt.status).toBe(1); - }); - }); - - const getTokenRegistryAddress = async (): Promise => { - if (tokenRegistryAddress === "") { - const delay = (ms: number): Promise => new Promise((resolve) => setTimeout(resolve, ms)); - await delay(3000); - console.log("Delayed By 3s"); - return await getTokenRegistryAddress(); - } else { - return tokenRegistryAddress; - } - }; -}); diff --git a/src/commands/token-registry/role.ts b/src/commands/token-registry/role.ts deleted file mode 100644 index fe2215bc..00000000 --- a/src/commands/token-registry/role.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Argv } from "yargs"; - -export const command = "role "; - -export const describe = "Manages User Roles of Token Registry"; - -export const builder = (yargs: Argv): Argv => yargs.commandDir("role", { extensions: ["ts", "js"] }); - -export const handler = (): void => {}; diff --git a/src/commands/token-registry/role/grant-role.ts b/src/commands/token-registry/role/grant-role.ts deleted file mode 100644 index adf9fcb3..00000000 --- a/src/commands/token-registry/role/grant-role.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Argv } from "yargs"; -import { error, info, success } from "signale"; -import { getLogger } from "../../../logger"; -import { grantRoleToTokenRegistry } from "../../../implementations/token-registry/role/grant-role"; -import { TokenRegistryRoleCommand } from "../token-registry-command.type"; -import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; -import { getErrorMessage, getEtherscanAddress } from "../../../utils"; -import { getAllRolesInput, getRoleEnumValue } from "./helper"; - -const { trace } = getLogger("token-registry:grant-roles"); - -export const command = "grant-role [options]"; - -export const describe = "Grant Role of Token Registry"; - -export const builder = (yargs: Argv): Argv => - withGasPriceOption( - withNetworkAndWalletSignerOption( - yargs - .option("address", { - alias: "a", - description: "Address of the token registry", - type: "string", - demandOption: true, - }) - .option("role", { - describe: "Role to be granted to recipient", - type: "string", - nargs: 1, - demandOption: true, - choices: getAllRolesInput(), - }) - .option("recipient", { - description: "Recipient of the role", - type: "string", - demandOption: true, - }) - ) - ); - -export const handler = async (args: TokenRegistryRoleCommand): Promise => { - trace(`Args: ${JSON.stringify(args, null, 2)}`); - try { - info(`Assigning ${args.role} to the recipient ${args.recipient} in the registry ${args.address}`); - const { transactionHash } = await grantRoleToTokenRegistry({ - ...args, - role: getRoleEnumValue(args.role), - }); - success(`Role ${args.role} has been assigned to the recipient ${args.recipient} in the registry ${args.address}`); - info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); - return args.address; - } catch (e) { - error(getErrorMessage(e)); - } -}; diff --git a/src/commands/token-registry/role/helper.ts b/src/commands/token-registry/role/helper.ts deleted file mode 100644 index d77fc0ad..00000000 --- a/src/commands/token-registry/role/helper.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { constants } from "@govtechsg/token-registry"; - -export const rolesInput: Record = { - "default-admin": constants.roleHash.DefaultAdmin, - minter: constants.roleHash.MinterRole, - accepter: constants.roleHash.AccepterRole, - restorer: constants.roleHash.RestorerRole, - "minter-admin": constants.roleHash.MinterAdminRole, - "accepter-admin": constants.roleHash.AccepterAdminRole, - "restorer-admin": constants.roleHash.RestorerAdminRole, -}; - -export const getAllRolesInput = (): string[] => { - return [...adminRolesInput, ...normalRolesInput]; -}; - -export const adminRolesInput = ["default-admin", "minter-admin", "accepter-admin", "restorer-admin"]; -export const normalRolesInput = ["minter", "accepter", "restorer"]; - -export const getRoleEnumValue = (roleNameInString: string): string => { - if (!(roleNameInString in rolesInput)) { - return rolesInput[roleNameInString]; - } - throw new Error("Invalid Role"); -}; diff --git a/src/commands/token-registry/role/revoke-role.ts b/src/commands/token-registry/role/revoke-role.ts deleted file mode 100644 index 68e514a3..00000000 --- a/src/commands/token-registry/role/revoke-role.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Argv } from "yargs"; -import { error, info, success } from "signale"; -import { getLogger } from "../../../logger"; -import { TokenRegistryRoleCommand } from "../token-registry-command.type"; -import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; -import { getErrorMessage, getEtherscanAddress } from "../../../utils"; -import { getRoleEnumValue, getAllRolesInput } from "./helper"; -import { revokeRoleToTokenRegistry } from "../../../implementations/token-registry/role/revoke-role"; - -const { trace } = getLogger("token-registry:revoke-role"); - -export const command = "revoke-role [options]"; - -export const describe = "Revoke User Role in Token Registry"; - -export const builder = (yargs: Argv): Argv => - withGasPriceOption( - withNetworkAndWalletSignerOption( - yargs - .option("address", { - alias: "a", - description: "Address of the token registry", - type: "string", - demandOption: true, - }) - .option("role", { - describe: "Role to be revoked from recipient", - type: "string", - nargs: 1, - demandOption: true, - choices: getAllRolesInput(), - }) - .option("recipient", { - description: "Recipient of the role revocation", - type: "string", - demandOption: true, - }) - ) - ); - -export const handler = async (args: TokenRegistryRoleCommand): Promise => { - trace(`Args: ${JSON.stringify(args, null, 2)}`); - try { - info(`Revoking ${args.role} role from the recipient ${args.recipient} in the registry ${args.address}`); - const { transactionHash } = await revokeRoleToTokenRegistry({ - ...args, - role: getRoleEnumValue(args.role), - }); - success(`Role ${args.role} has been revoked from the recipient ${args.recipient} in the registry ${args.address}`); - info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); - return args.address; - } catch (e) { - error(getErrorMessage(e)); - } -}; diff --git a/src/commands/token-registry/role/set-admin-role.ts b/src/commands/token-registry/role/set-admin-role.ts deleted file mode 100644 index c30025b6..00000000 --- a/src/commands/token-registry/role/set-admin-role.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Argv } from "yargs"; -import { error, info, success } from "signale"; -import { getLogger } from "../../../logger"; -import { TokenRegistrySetRoleAdminCommand } from "../token-registry-command.type"; -import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../../shared"; -import { getErrorMessage, getEtherscanAddress } from "../../../utils"; -import { getRoleEnumValue, normalRolesInput, adminRolesInput } from "./helper"; -import { setRoleAdminTokenRegistry } from "../../../implementations/token-registry/role/set-role"; - -const { trace } = getLogger("token-registry:set-role-admin"); - -export const command = "set-admin-role [options]"; - -export const describe = "Set Admin Role to Role of Token Registry"; - -export const builder = (yargs: Argv): Argv => - withGasPriceOption( - withNetworkAndWalletSignerOption( - yargs - .option("address", { - alias: "a", - description: "Address of the token registry", - type: "string", - demandOption: true, - }) - .option("role", { - describe: "Role to be set", - type: "string", - nargs: 1, - demandOption: true, - choices: normalRolesInput, - }) - .option("adminRole", { - describe: "Admin Role to be set to Role", - type: "string", - nargs: 1, - demandOption: true, - choices: adminRolesInput, - }) - ) - ); - -export const handler = async (args: TokenRegistrySetRoleAdminCommand): Promise => { - trace(`Args: ${JSON.stringify(args, null, 2)}`); - try { - info(`Setting ${args.adminRole} to the recipient role ${args.role} in the registry ${args.address}`); - const { transactionHash } = await setRoleAdminTokenRegistry({ - ...args, - role: getRoleEnumValue(args.role), - adminRole: getRoleEnumValue(args.adminRole), - }); - success(`Role ${args.adminRole} has been assigned to the recipient ${args.role} in the registry ${args.address}`); - info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); - return args.address; - } catch (e) { - error(getErrorMessage(e)); - } -}; diff --git a/src/commands/token-registry/token-registry-command.type.ts b/src/commands/token-registry/token-registry-command.type.ts index f336f759..5930818e 100644 --- a/src/commands/token-registry/token-registry-command.type.ts +++ b/src/commands/token-registry/token-registry-command.type.ts @@ -6,18 +6,4 @@ export type TokenRegistryIssueCommand = NetworkAndWalletSignerOption & beneficiary: string; holder: string; tokenId: string; - }; - -export type TokenRegistryRoleCommand = NetworkAndWalletSignerOption & - GasOption & { - address: string; - role: string; - recipient: string; - }; - -export type TokenRegistrySetRoleAdminCommand = NetworkAndWalletSignerOption & - GasOption & { - address: string; - role: string; - adminRole: string; - }; + }; \ No newline at end of file diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index bce43e05..e4f58623 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -21,13 +21,6 @@ export const connectToTitleEscrow = async ({ }: ConnectToTitleEscrowArgs): Promise => { const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId); - return await connectToTitleEscrowFactory(titleEscrowAddress, wallet); -}; - -export const connectToTitleEscrowFactory = async ( - titleEscrowAddress: string, - wallet: Wallet | ConnectedSigner -): Promise => { return await TitleEscrow__factory.connect(titleEscrowAddress, wallet); }; diff --git a/src/implementations/token-registry/role/grant-role.test.ts b/src/implementations/token-registry/role/grant-role.test.ts deleted file mode 100644 index 35cc0b68..00000000 --- a/src/implementations/token-registry/role/grant-role.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import { Wallet } from "ethers"; -import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { grantRoleToTokenRegistry } from "./grant-role"; - -jest.mock("@govtechsg/token-registry/contracts"); - -const roleParams: TokenRegistryRoleCommand = { - address: "0x1122", - role: "0x1", - recipient: "0x12345", - network: "goerli", - gasPriceScale: 1, - dryRun: false, -}; - -describe("token-registry", () => { - describe("grant role for token registry", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; - const mockGrantRole = jest.fn(); - const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); - - beforeEach(() => { - delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); - mockedConnectERC721.mockReset(); - - mockGrantRole.mockReturnValue({ - hash: "hash", - wait: () => Promise.resolve({ transactionHash: "transactionHash" }), - }); - - mockedConnectERC721.mockReturnValue({ - grantRole: mockGrantRole, - callStatic: { - grantRole: mockCallStaticGrantRole, - }, - }); - mockGrantRole.mockClear(); - mockCallStaticGrantRole.mockClear(); - }); - - it("should pass in the correct params and successfully accepts grant role", async () => { - const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await grantRoleToTokenRegistry({ - ...roleParams, - key: privateKey, - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); - expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); - expect(mockGrantRole).toHaveBeenCalledTimes(1); - - expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); - expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); - }); - }); -}); diff --git a/src/implementations/token-registry/role/grant-role.ts b/src/implementations/token-registry/role/grant-role.ts deleted file mode 100644 index 433926bd..00000000 --- a/src/implementations/token-registry/role/grant-role.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import signale from "signale"; -import { getLogger } from "../../../logger"; -import { getWalletOrSigner } from "../../utils/wallet"; -import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { dryRunMode } from "../../utils/dryRun"; -import { TransactionReceipt } from "@ethersproject/providers"; - -const { trace } = getLogger("token-registry:grant-role"); - -export const grantRoleToTokenRegistry = async ({ - address, - recipient, - role, - network, - gasPriceScale, - dryRun, - ...rest -}: TokenRegistryRoleCommand): Promise => { - const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); - - if (dryRun) { - await dryRunMode({ - gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistry.estimateGas.grantRole(role, recipient), - network, - }); - process.exit(0); - } - const gasPrice = await wallet.provider.getGasPrice(); - signale.await(`Sending transaction to pool`); - await tokenRegistry.callStatic.grantRole(role, recipient, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await tokenRegistry.grantRole(role, recipient, { gasPrice: gasPrice.mul(gasPriceScale) }); - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - return transaction.wait(); -}; diff --git a/src/implementations/token-registry/role/revoke-role.test.ts b/src/implementations/token-registry/role/revoke-role.test.ts deleted file mode 100644 index 0a193648..00000000 --- a/src/implementations/token-registry/role/revoke-role.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import { Wallet } from "ethers"; -import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { revokeRoleToTokenRegistry } from "./revoke-role"; - -jest.mock("@govtechsg/token-registry/contracts"); - -const roleParams: TokenRegistryRoleCommand = { - address: "0x1122", - role: "0x1", - recipient: "0x12345", - network: "goerli", - gasPriceScale: 1, - dryRun: false, -}; - -describe("token-registry", () => { - describe("revoke role for token registry", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; - const mockGrantRole = jest.fn(); - const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); - - beforeEach(() => { - delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); - mockedConnectERC721.mockReset(); - - mockGrantRole.mockReturnValue({ - hash: "hash", - wait: () => Promise.resolve({ transactionHash: "transactionHash" }), - }); - - mockedConnectERC721.mockReturnValue({ - revokeRole: mockGrantRole, - callStatic: { - revokeRole: mockCallStaticGrantRole, - }, - }); - mockGrantRole.mockClear(); - mockCallStaticGrantRole.mockClear(); - }); - - it("should pass in the correct params and successfully accepts revoked role", async () => { - const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await revokeRoleToTokenRegistry({ - ...roleParams, - key: privateKey, - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); - expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); - expect(mockGrantRole).toHaveBeenCalledTimes(1); - - expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); - expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.recipient); - }); - }); -}); diff --git a/src/implementations/token-registry/role/revoke-role.ts b/src/implementations/token-registry/role/revoke-role.ts deleted file mode 100644 index 330acccf..00000000 --- a/src/implementations/token-registry/role/revoke-role.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import signale from "signale"; -import { getLogger } from "../../../logger"; -import { getWalletOrSigner } from "../../utils/wallet"; -import { TokenRegistryRoleCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { dryRunMode } from "../../utils/dryRun"; -import { TransactionReceipt } from "@ethersproject/providers"; - -const { trace } = getLogger("token-registry:revoke-role"); - -export const revokeRoleToTokenRegistry = async ({ - address, - recipient, - role, - network, - gasPriceScale, - dryRun, - ...rest -}: TokenRegistryRoleCommand): Promise => { - const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); - - if (dryRun) { - await dryRunMode({ - gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistry.estimateGas.revokeRole(role, recipient), - network, - }); - process.exit(0); - } - const gasPrice = await wallet.provider.getGasPrice(); - signale.await(`Sending transaction to pool`); - await tokenRegistry.callStatic.revokeRole(role, recipient, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await tokenRegistry.revokeRole(role, recipient, { gasPrice: gasPrice.mul(gasPriceScale) }); - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - return transaction.wait(); -}; diff --git a/src/implementations/token-registry/role/set-role.test.ts b/src/implementations/token-registry/role/set-role.test.ts deleted file mode 100644 index 77a37bf0..00000000 --- a/src/implementations/token-registry/role/set-role.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import { Wallet } from "ethers"; -import { TokenRegistrySetRoleAdminCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { setRoleAdminTokenRegistry } from "./set-role"; - -jest.mock("@govtechsg/token-registry/contracts"); -const roleParams: TokenRegistrySetRoleAdminCommand = { - address: "0x1122", - role: "0x1", - adminRole: "0x2", - network: "goerli", - gasPriceScale: 1, - dryRun: false, -}; - -describe("token-registry", () => { - describe("set role for token registry", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; - const mockGrantRole = jest.fn(); - const mockCallStaticGrantRole = jest.fn().mockResolvedValue(undefined); - - beforeEach(() => { - delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); - mockedConnectERC721.mockReset(); - - mockGrantRole.mockReturnValue({ - hash: "hash", - wait: () => Promise.resolve({ transactionHash: "transactionHash" }), - }); - - mockedConnectERC721.mockReturnValue({ - setRoleAdmin: mockGrantRole, - callStatic: { - setRoleAdmin: mockCallStaticGrantRole, - }, - }); - mockGrantRole.mockClear(); - mockCallStaticGrantRole.mockClear(); - }); - - it("should pass in the correct params and successfully accepts set role", async () => { - const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await setRoleAdminTokenRegistry({ - ...roleParams, - key: privateKey, - }); - - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(roleParams.address, passedSigner); - expect(mockCallStaticGrantRole).toHaveBeenCalledTimes(1); - expect(mockGrantRole).toHaveBeenCalledTimes(1); - - expect(mockGrantRole.mock.calls[0][0]).toEqual(roleParams.role); - expect(mockGrantRole.mock.calls[0][1]).toEqual(roleParams.adminRole); - }); - }); -}); diff --git a/src/implementations/token-registry/role/set-role.ts b/src/implementations/token-registry/role/set-role.ts deleted file mode 100644 index 6ce63142..00000000 --- a/src/implementations/token-registry/role/set-role.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import signale from "signale"; -import { getLogger } from "../../../logger"; -import { getWalletOrSigner } from "../../utils/wallet"; -import { TokenRegistrySetRoleAdminCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { dryRunMode } from "../../utils/dryRun"; -import { TransactionReceipt } from "@ethersproject/providers"; - -const { trace } = getLogger("token-registry:set-role"); - -export const setRoleAdminTokenRegistry = async ({ - address, - role, - adminRole, - network, - gasPriceScale, - dryRun, - ...rest -}: TokenRegistrySetRoleAdminCommand): Promise => { - const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); - - if (dryRun) { - await dryRunMode({ - gasPriceScale: gasPriceScale, - estimatedGas: await tokenRegistry.estimateGas.setRoleAdmin(role, adminRole), - network, - }); - process.exit(0); - } - const gasPrice = await wallet.provider.getGasPrice(); - signale.await(`Sending transaction to pool`); - await tokenRegistry.callStatic.setRoleAdmin(role, adminRole, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await tokenRegistry.setRoleAdmin(role, adminRole, { gasPrice: gasPrice.mul(gasPriceScale) }); - trace(`Tx hash: ${transaction.hash}`); - trace(`Block Number: ${transaction.blockNumber}`); - signale.await(`Waiting for transaction ${transaction.hash} to be mined`); - return transaction.wait(); -}; From e7e46c1a3c16fef1926dcf635ddfd25369e313df Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:00:50 +0800 Subject: [PATCH 23/63] chore: update naming --- .../title-escrow/nominate-change-of-owner.ts | 7 ++++--- .../title-escrow/title-escrow-command.type.ts | 2 +- .../deploy/token-registry/token-registry.ts | 21 ++++--------------- .../title-escrow/nominateBeneficiary.test.ts | 4 ++-- .../title-escrow/nominateBeneficiary.ts | 12 +++++------ 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/commands/title-escrow/nominate-change-of-owner.ts b/src/commands/title-escrow/nominate-change-of-owner.ts index 069016e2..8887cedb 100644 --- a/src/commands/title-escrow/nominate-change-of-owner.ts +++ b/src/commands/title-escrow/nominate-change-of-owner.ts @@ -27,7 +27,8 @@ export const builder = (yargs: Argv): Argv => type: "string", demandOption: true, }) - .option("newOwner", { + .option("newBeneficiary", { + alias: "newOwner", description: "Address of the beneficiary of the transferable record", type: "string", demandOption: true, @@ -39,14 +40,14 @@ export const handler = async (args: TitleEscrowNominateBeneficiaryCommand): Prom trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info( - `Connecting to the registry ${args.tokenRegistry} and attempting to nominate the change of owner of the transferable record ${args.tokenId} to new owner at ${args.newOwner}` + `Connecting to the registry ${args.tokenRegistry} and attempting to nominate the change of owner of the transferable record ${args.tokenId} to new owner at ${args.newBeneficiary}` ); warn( `Please note that if you do not have the correct privileges to the transferable record, then this command will fail.` ); const { transactionHash } = await nominateBeneficiary(args); success( - `Transferable record with hash ${args.tokenId}'s holder has been successfully nominated to new owner with address ${args.newOwner}` + `Transferable record with hash ${args.tokenId}'s holder has been successfully nominated to new owner with address ${args.newBeneficiary}` ); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); } catch (e) { diff --git a/src/commands/title-escrow/title-escrow-command.type.ts b/src/commands/title-escrow/title-escrow-command.type.ts index a7ba23e2..da7b738e 100644 --- a/src/commands/title-escrow/title-escrow-command.type.ts +++ b/src/commands/title-escrow/title-escrow-command.type.ts @@ -15,5 +15,5 @@ export type TitleEscrowEndorseChangeOfOwnerCommand = BaseTitleEscrowCommand & { }; export type TitleEscrowNominateBeneficiaryCommand = BaseTitleEscrowCommand & { - newOwner: string; + newBeneficiary: string; }; diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 1c6c7cd3..d8453e3c 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -4,9 +4,9 @@ import signale from "signale"; import { getLogger } from "../../../logger"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { constants } from "@govtechsg/token-registry"; -import { BigNumber, ContractReceipt, ethers } from "ethers"; +import { BigNumber, ethers } from "ethers"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; -import { TypedEvent } from "@govtechsg/token-registry/dist/contracts/common"; +import { utils } from "@govtechsg/token-registry"; const { trace } = getLogger("deploy:token-registry"); @@ -61,7 +61,7 @@ export const deployTokenRegistry = async ({ trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); const receipt = await transaction.wait(); - const registryAddress = getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) + const registryAddress = utils.getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) .args.deployed; return { contractAddress: registryAddress }; }; @@ -103,17 +103,4 @@ export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | tokenImplementation: tokenImplementation, deployer: deployer, } as DeployContractAddress; -}; - -export const getEventFromReceipt = >( - receipt: ContractReceipt, - topic: string, - iface?: ethers.utils.Interface -): any => { - if (!receipt.events) throw new Error("Events object is undefined"); - const event = receipt.events.find((evt) => evt.topics[0] === topic); - if (!event) throw new Error(`Cannot find topic ${topic}`); - - if (iface) return iface.parseLog(event) as unknown as T; - return event as T; -}; +}; \ No newline at end of file diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index 1dbd498d..d7c945ca 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -7,7 +7,7 @@ import { nominateBeneficiary } from "./nominateBeneficiary"; jest.mock("@govtechsg/token-registry/contracts"); const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { - newOwner: "0fosui", + newBeneficiary: "0fosui", tokenId: "0xzyxw", tokenRegistry: "0x1234", network: "goerli", @@ -83,7 +83,7 @@ describe("title-escrow", () => { }); it("should throw an error if new owner addresses is the same as current owner", async () => { - mockGetBeneficiary.mockReturnValue(nominateBeneficiaryParams.newOwner); + mockGetBeneficiary.mockReturnValue(nominateBeneficiaryParams.newBeneficiary); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( nominateBeneficiary({ diff --git a/src/implementations/title-escrow/nominateBeneficiary.ts b/src/implementations/title-escrow/nominateBeneficiary.ts index d102d0ee..ab444c97 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.ts @@ -12,7 +12,7 @@ const { trace } = getLogger("title-escrow:nominateChangeOfOwner"); export const nominateBeneficiary = async ({ tokenRegistry: address, tokenId, - newOwner, + newBeneficiary, network, gasPriceScale, dryRun, @@ -21,21 +21,21 @@ export const nominateBeneficiary = async ({ const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); if (dryRun) { - await validateNominateBeneficiary({ beneficiaryNominee: newOwner, titleEscrow }); + await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); await dryRunMode({ gasPriceScale: gasPriceScale, - estimatedGas: await titleEscrow.estimateGas.nominate(newOwner), + estimatedGas: await titleEscrow.estimateGas.nominate(newBeneficiary), network, }); process.exit(0); } const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); - await validateNominateBeneficiary({ beneficiaryNominee: newOwner, titleEscrow }); - await titleEscrow.callStatic.nominate(newOwner, { + await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); + await titleEscrow.callStatic.nominate(newBeneficiary, { gasPrice: gasPrice.mul(gasPriceScale), }); - const transaction = await titleEscrow.nominate(newOwner, { + const transaction = await titleEscrow.nominate(newBeneficiary, { gasPrice: gasPrice.mul(gasPriceScale), }); trace(`Tx hash: ${transaction.hash}`); From f5dc87da571b773d25504b0ee71a315b176ac9e7 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 11 Oct 2022 14:02:27 +0800 Subject: [PATCH 24/63] chore: rename files --- src/commands/title-escrow/change-holder.ts | 2 +- src/commands/title-escrow/endorse-change-of-owner.ts | 2 +- .../{changeHolder.test.ts => transferHolder.test.ts} | 2 +- .../title-escrow/{changeHolder.ts => transferHolder.ts} | 0 .../title-escrow/{changeOwner.test.ts => transferOwner.test.ts} | 2 +- .../title-escrow/{changeOwner.ts => transferOwner.ts} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename src/implementations/title-escrow/{changeHolder.test.ts => transferHolder.test.ts} (98%) rename src/implementations/title-escrow/{changeHolder.ts => transferHolder.ts} (100%) rename src/implementations/title-escrow/{changeOwner.test.ts => transferOwner.test.ts} (98%) rename src/implementations/title-escrow/{changeOwner.ts => transferOwner.ts} (100%) diff --git a/src/commands/title-escrow/change-holder.ts b/src/commands/title-escrow/change-holder.ts index 89e8ae89..e582bab6 100644 --- a/src/commands/title-escrow/change-holder.ts +++ b/src/commands/title-escrow/change-holder.ts @@ -1,7 +1,7 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { changeHolderOfTitleEscrow } from "../../implementations/title-escrow/changeHolder"; +import { changeHolderOfTitleEscrow } from "../../implementations/title-escrow/transferHolder"; import { TitleEscrowChangeHolderCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; diff --git a/src/commands/title-escrow/endorse-change-of-owner.ts b/src/commands/title-escrow/endorse-change-of-owner.ts index 02386729..4ca8af15 100644 --- a/src/commands/title-escrow/endorse-change-of-owner.ts +++ b/src/commands/title-escrow/endorse-change-of-owner.ts @@ -1,7 +1,7 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { endorseChangeOfOwner } from "../../implementations/title-escrow/changeOwner"; +import { endorseChangeOfOwner } from "../../implementations/title-escrow/transferOwner"; import { TitleEscrowEndorseChangeOfOwnerCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; diff --git a/src/implementations/title-escrow/changeHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts similarity index 98% rename from src/implementations/title-escrow/changeHolder.test.ts rename to src/implementations/title-escrow/transferHolder.test.ts index de9b8b3c..68c0e10f 100644 --- a/src/implementations/title-escrow/changeHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -2,7 +2,7 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/toke import { Wallet } from "ethers"; import { TitleEscrowChangeHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { changeHolderOfTitleEscrow } from "./changeHolder"; +import { changeHolderOfTitleEscrow } from "./transferHolder"; jest.mock("@govtechsg/token-registry/contracts"); diff --git a/src/implementations/title-escrow/changeHolder.ts b/src/implementations/title-escrow/transferHolder.ts similarity index 100% rename from src/implementations/title-escrow/changeHolder.ts rename to src/implementations/title-escrow/transferHolder.ts diff --git a/src/implementations/title-escrow/changeOwner.test.ts b/src/implementations/title-escrow/transferOwner.test.ts similarity index 98% rename from src/implementations/title-escrow/changeOwner.test.ts rename to src/implementations/title-escrow/transferOwner.test.ts index 00ae8fb6..150069be 100644 --- a/src/implementations/title-escrow/changeOwner.test.ts +++ b/src/implementations/title-escrow/transferOwner.test.ts @@ -2,7 +2,7 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/toke import { Wallet } from "ethers"; import { TitleEscrowEndorseChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { endorseChangeOfOwner } from "./changeOwner"; +import { endorseChangeOfOwner } from "./transferOwner"; jest.mock("@govtechsg/token-registry/contracts"); diff --git a/src/implementations/title-escrow/changeOwner.ts b/src/implementations/title-escrow/transferOwner.ts similarity index 100% rename from src/implementations/title-escrow/changeOwner.ts rename to src/implementations/title-escrow/transferOwner.ts From e226910678b3c49f0e32875b4032029aeede3509 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 12 Oct 2022 17:20:40 +0800 Subject: [PATCH 25/63] chore: linting --- .../token-registry-command.type.ts | 2 +- .../token-registry/token-registry.test.ts | 19 ++++++++----------- .../deploy/token-registry/token-registry.ts | 8 +++++--- .../title-escrow/surrenderDocument.ts | 2 +- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/commands/token-registry/token-registry-command.type.ts b/src/commands/token-registry/token-registry-command.type.ts index 5930818e..24f212d2 100644 --- a/src/commands/token-registry/token-registry-command.type.ts +++ b/src/commands/token-registry/token-registry-command.type.ts @@ -6,4 +6,4 @@ export type TokenRegistryIssueCommand = NetworkAndWalletSignerOption & beneficiary: string; holder: string; tokenId: string; - }; \ No newline at end of file + }; diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index e1ae5e78..f4b9075e 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -88,26 +88,23 @@ describe("token-registry", () => { ); }); - describe("Valid Token Registry Factory Address", () => { - - it("should return valid deployer address", () => { + describe("valid Token Registry Factory Address", () => { + it("should return deployer address", () => { const address = retrieveFactoryAddress(5, undefined); - + expect(isAddress(address.titleEscrowFactory)).toBe(true); expect(isAddress(address.tokenImplementation)).toBe(true); expect(isAddress(address.deployer)).toBe(true); }); - it("should return valid deployer address", () => { - const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7" - const address = retrieveFactoryAddress(5, suppliedAddress); - + it("should return provided deployer address", () => { + const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7"; + const address = retrieveFactoryAddress(5, suppliedAddress); + expect(address.titleEscrowFactory).toBe(suppliedAddress); expect(isAddress(address.tokenImplementation)).toBe(true); expect(isAddress(address.deployer)).toBe(true); }); - - }) - + }); }); }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index d8453e3c..ebf85174 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -61,8 +61,10 @@ export const deployTokenRegistry = async ({ trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); const receipt = await transaction.wait(); - const registryAddress = utils.getEventFromReceipt(receipt, factory.interface.getEventTopic("Deployment")) - .args.deployed; + const registryAddress = utils.getEventFromReceipt( + receipt, + factory.interface.getEventTopic("Deployment") + ).args.deployed; return { contractAddress: registryAddress }; }; @@ -103,4 +105,4 @@ export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | tokenImplementation: tokenImplementation, deployer: deployer, } as DeployContractAddress; -}; \ No newline at end of file +}; diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index 75c83c94..999b9cce 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -35,4 +35,4 @@ export const surrenderDocument = async ({ trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); return transaction.wait(); -}; \ No newline at end of file +}; From ea3ba41c398c9c33afda3eb183fe1bbabc0a1920 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 12 Oct 2022 22:17:23 +0800 Subject: [PATCH 26/63] fix: merge error --- .../title-escrow/endorseNominatedBeneficiary.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts index edec53e6..89cab792 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts @@ -12,7 +12,7 @@ const { trace } = getLogger("title-escrow:endorseTransferOfOwner"); export const endorseNominatedBeneficiary = async ({ tokenRegistry: address, tokenId, - newOwner, + newBeneficiary, network, gasPriceScale, dryRun, @@ -23,7 +23,7 @@ export const endorseNominatedBeneficiary = async ({ }> => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - const nominatedBeneficiary = newOwner; + const nominatedBeneficiary = newBeneficiary; await validateNominateBeneficiary({ beneficiaryNominee: nominatedBeneficiary, titleEscrow }); if (dryRun) { await dryRunMode({ From fc1fa19a550798d07116565f62d2fc2d238e6f29 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:32:35 +0800 Subject: [PATCH 27/63] chore: split token-registry deploy helpers --- .../deploy/token-registry/helpers.test.ts | 43 +++++++++++++++++ .../deploy/token-registry/helpers.ts | 47 ++++++++++++++++++ .../token-registry/token-registry.test.ts | 23 +-------- .../deploy/token-registry/token-registry.ts | 48 +------------------ 4 files changed, 93 insertions(+), 68 deletions(-) create mode 100644 src/implementations/deploy/token-registry/helpers.test.ts create mode 100644 src/implementations/deploy/token-registry/helpers.ts diff --git a/src/implementations/deploy/token-registry/helpers.test.ts b/src/implementations/deploy/token-registry/helpers.test.ts new file mode 100644 index 00000000..f48a52e5 --- /dev/null +++ b/src/implementations/deploy/token-registry/helpers.test.ts @@ -0,0 +1,43 @@ +import { encodeInitParams, retrieveFactoryAddress } from "./helpers"; +import { isAddress } from "ethers/lib/utils"; + +describe("valid Token Registry Factory Address", () => { + it("should return deployer address", () => { + const address = retrieveFactoryAddress(5, undefined); + + expect(isAddress(address.titleEscrowFactory)).toBe(true); + expect(isAddress(address.tokenImplementation)).toBe(true); + expect(isAddress(address.deployer)).toBe(true); + }); + + it("should return provided deployer address", () => { + const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7"; + const address = retrieveFactoryAddress(5, suppliedAddress); + + expect(address.titleEscrowFactory).toBe(suppliedAddress); + expect(isAddress(address.tokenImplementation)).toBe(true); + expect(isAddress(address.deployer)).toBe(true); + }); + + it("should reject invalid chainId", () => { + try { + const address = retrieveFactoryAddress(2022, undefined); + fail("invalid chainId failed to fail"); + } catch (e) { + expect(e).toBeDefined(); + } + }); +}); + +describe("valid encodeInit parameters", () => { + it("should encode parameters correctly", () => { + const params = encodeInitParams({ + name: "Token Registry Factory", + symbol: "TCR", + deployer: "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7", + }); + expect(params).toContain( + "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000d6c249d0756059e21ef4aef4711b69b76927bea70000000000000000000000000000000000000000000000000000000000000016546f6b656e20526567697374727920466163" + ); + }); +}); diff --git a/src/implementations/deploy/token-registry/helpers.ts b/src/implementations/deploy/token-registry/helpers.ts new file mode 100644 index 00000000..6804b38f --- /dev/null +++ b/src/implementations/deploy/token-registry/helpers.ts @@ -0,0 +1,47 @@ +import { ethers } from "ethers"; +import { constants } from "@govtechsg/token-registry"; + +export interface DeployContractAddress { + titleEscrowFactory: string; + tokenImplementation: string; + deployer: string; +} + +export interface Params { + name: string; + symbol: string; + deployer: string; +} + +export const encodeInitParams = ({ name, symbol, deployer }: Params): string => { + return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); +}; + +export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { + const { contractAddress } = constants; + + if (!chainId) { + throw new Error(`Invalid chain ID: ${chainId}`); + } + + let titleEscrowFactory = factoryAddress; + const tokenImplementation = contractAddress.TokenImplementation[chainId]; + const deployer = contractAddress.Deployer[chainId]; + + if (!tokenImplementation || !deployer) { + throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); + } + + if (!titleEscrowFactory) { + titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId]; + if (!titleEscrowFactory) { + throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); + } + } + + return { + titleEscrowFactory: titleEscrowFactory, + tokenImplementation: tokenImplementation, + deployer: deployer, + } as DeployContractAddress; +}; diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index f4b9075e..876c34db 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -1,8 +1,8 @@ -import { deployTokenRegistry, encodeInitParams, retrieveFactoryAddress } from "./token-registry"; +import { deployTokenRegistry } from "./token-registry"; +import { encodeInitParams } from "./helpers"; import { Contract } from "ethers"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; -import { isAddress } from "ethers/lib/utils"; const deployParams: DeployTokenRegistryCommand = { registryName: "Test", @@ -87,24 +87,5 @@ describe("token-registry", () => { "No private key found in OA_PRIVATE_KEY, key, key-file, please supply at least one or supply an encrypted wallet path, or provide aws kms signer information" ); }); - - describe("valid Token Registry Factory Address", () => { - it("should return deployer address", () => { - const address = retrieveFactoryAddress(5, undefined); - - expect(isAddress(address.titleEscrowFactory)).toBe(true); - expect(isAddress(address.tokenImplementation)).toBe(true); - expect(isAddress(address.deployer)).toBe(true); - }); - - it("should return provided deployer address", () => { - const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7"; - const address = retrieveFactoryAddress(5, suppliedAddress); - - expect(address.titleEscrowFactory).toBe(suppliedAddress); - expect(isAddress(address.tokenImplementation)).toBe(true); - expect(isAddress(address.deployer)).toBe(true); - }); - }); }); }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index ebf85174..cd2d36bb 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -3,19 +3,12 @@ import { getWalletOrSigner } from "../../utils/wallet"; import signale from "signale"; import { getLogger } from "../../../logger"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -import { constants } from "@govtechsg/token-registry"; import { BigNumber, ethers } from "ethers"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; import { utils } from "@govtechsg/token-registry"; - +import { DeployContractAddress, encodeInitParams, retrieveFactoryAddress } from "./helpers"; const { trace } = getLogger("deploy:token-registry"); -interface DeployContractAddress { - titleEscrowFactory: string; - tokenImplementation: string; - deployer: string; -} - export const deployTokenRegistry = async ({ registryName, registrySymbol, @@ -67,42 +60,3 @@ export const deployTokenRegistry = async ({ ).args.deployed; return { contractAddress: registryAddress }; }; - -interface Params { - name: string; - symbol: string; - deployer: string; -} - -export const encodeInitParams = ({ name, symbol, deployer }: Params): string => { - return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); -}; - -export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { - const { contractAddress } = constants; - - if (!chainId) { - throw new Error(`Invalid chain ID: ${chainId}`); - } - - let titleEscrowFactory = factoryAddress; - const tokenImplementation = contractAddress.TokenImplementation[chainId]; - const deployer = contractAddress.Deployer[chainId]; - - if (!tokenImplementation || !deployer) { - throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); - } - - if (!titleEscrowFactory) { - titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId]; - if (!titleEscrowFactory) { - throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); - } - } - - return { - titleEscrowFactory: titleEscrowFactory, - tokenImplementation: tokenImplementation, - deployer: deployer, - } as DeployContractAddress; -}; From 68afa4f5610a8be81767f601db69babca92e472c Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 13 Oct 2022 10:38:50 +0800 Subject: [PATCH 28/63] fix: lint --- src/implementations/deploy/token-registry/helpers.test.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/implementations/deploy/token-registry/helpers.test.ts b/src/implementations/deploy/token-registry/helpers.test.ts index f48a52e5..3a3ace14 100644 --- a/src/implementations/deploy/token-registry/helpers.test.ts +++ b/src/implementations/deploy/token-registry/helpers.test.ts @@ -20,11 +20,13 @@ describe("valid Token Registry Factory Address", () => { }); it("should reject invalid chainId", () => { + let validTest = false; try { - const address = retrieveFactoryAddress(2022, undefined); - fail("invalid chainId failed to fail"); + retrieveFactoryAddress(2022, undefined); } catch (e) { - expect(e).toBeDefined(); + validTest = true; + } finally { + expect(validTest).toBe(true); } }); }); From 861a3baa53d8418158f8f70d7b783904c985ceb8 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 13 Oct 2022 15:43:59 +0800 Subject: [PATCH 29/63] fix: rename and update tests --- .../title-escrow/endorse-change-of-owner.ts | 8 +-- .../title-escrow/title-escrow-command.type.ts | 2 +- ...ts => endorseNominatedBeneficiary.test.ts} | 64 +++++++------------ .../title-escrow/transferOwner.test.ts | 10 +-- .../title-escrow/transferOwner.ts | 6 +- 5 files changed, 36 insertions(+), 54 deletions(-) rename src/implementations/title-escrow/{endorseNominatedBeneficiary.test..ts => endorseNominatedBeneficiary.test.ts} (59%) diff --git a/src/commands/title-escrow/endorse-change-of-owner.ts b/src/commands/title-escrow/endorse-change-of-owner.ts index 4ca8af15..55fbd5f6 100644 --- a/src/commands/title-escrow/endorse-change-of-owner.ts +++ b/src/commands/title-escrow/endorse-change-of-owner.ts @@ -1,8 +1,8 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { endorseChangeOfOwner } from "../../implementations/title-escrow/transferOwner"; -import { TitleEscrowEndorseChangeOfOwnerCommand } from "./title-escrow-command.type"; +import { transferOwners } from "../../implementations/title-escrow/transferOwner"; +import { TitleEscrowEndorseTransferOfOwnersCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; @@ -40,7 +40,7 @@ export const builder = (yargs: Argv): Argv => ) ); -export const handler = async (args: TitleEscrowEndorseChangeOfOwnerCommand): Promise => { +export const handler = async (args: TitleEscrowEndorseTransferOfOwnersCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info( @@ -49,7 +49,7 @@ export const handler = async (args: TitleEscrowEndorseChangeOfOwnerCommand): Pro warn( `Please note that you have to be both the holder and owner of the transferable record, otherwise this command will fail.` ); - const { transactionHash } = await endorseChangeOfOwner(args); + const { transactionHash } = await transferOwners(args); success( `Transferable record with hash ${args.tokenId}'s holder has been successfully endorsed to new owner with address ${args.newOwner} and new holder with address: ${args.newHolder}` ); diff --git a/src/commands/title-escrow/title-escrow-command.type.ts b/src/commands/title-escrow/title-escrow-command.type.ts index da7b738e..279bc423 100644 --- a/src/commands/title-escrow/title-escrow-command.type.ts +++ b/src/commands/title-escrow/title-escrow-command.type.ts @@ -9,7 +9,7 @@ export type TitleEscrowChangeHolderCommand = BaseTitleEscrowCommand & { to: string; }; -export type TitleEscrowEndorseChangeOfOwnerCommand = BaseTitleEscrowCommand & { +export type TitleEscrowEndorseTransferOfOwnersCommand = BaseTitleEscrowCommand & { newHolder: string; newOwner: string; }; diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts similarity index 59% rename from src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts rename to src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index c17b7bdb..bf4ed014 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test..ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -26,29 +26,30 @@ describe("title-escrow", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; - const mockedOwnerOf = jest.fn(); - const mockTransferToNewEscrow = jest.fn(); + const mockedTitleEscrowAddress = "0x2133"; - const mockedApprovedBeneficiary = "0xdssfs"; - const mockedApprovedHolder = "0xdsfls"; - const mockGetApprovedBeneficiary = jest.fn(); - const mockGetApprovedHolder = jest.fn(); - const mockCallStaticTransferToNewEscrow = jest.fn().mockResolvedValue(undefined); - mockGetApprovedBeneficiary.mockReturnValue(mockedApprovedBeneficiary); - mockGetApprovedHolder.mockReturnValue(mockedApprovedHolder); + const mockedOwnerOf = jest.fn(); + mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); + + const mockTransferOwners = jest.fn(); + const mockCallStaticTransferOwners = jest.fn().mockResolvedValue(undefined); + + const mockedBeneficiary = "0xdssfs"; + const mockGetBeneficiary = jest.fn(); + mockGetBeneficiary.mockReturnValue(mockedBeneficiary); + mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, }); + mockedConnectTokenFactory.mockReturnValue({ - transferToNewEscrow: mockTransferToNewEscrow, - approvedBeneficiary: mockGetApprovedBeneficiary, - approvedHolder: mockGetApprovedHolder, + transferBeneficiary: mockTransferOwners, + beneficiary: mockGetBeneficiary, callStatic: { - transferToNewEscrow: mockCallStaticTransferToNewEscrow, + transferBeneficiary: mockCallStaticTransferOwners, }, }); - mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); - mockTransferToNewEscrow.mockReturnValue({ + mockTransferOwners.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); @@ -60,10 +61,8 @@ describe("title-escrow", () => { mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); mockedOwnerOf.mockClear(); - mockTransferToNewEscrow.mockClear(); - mockGetApprovedBeneficiary.mockClear(); - mockGetApprovedHolder.mockClear(); - mockCallStaticTransferToNewEscrow.mockClear(); + mockTransferOwners.mockClear(); + mockCallStaticTransferOwners.mockClear(); }); it("should pass in the correct params and call the following procedures to invoke an endorsement of transfer of owner of a transferable record", async () => { @@ -79,37 +78,20 @@ describe("title-escrow", () => { expect(mockedConnectERC721).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenRegistry, passedSigner); expect(mockedOwnerOf).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); - expect(mockGetApprovedBeneficiary).toHaveBeenCalledTimes(1); - expect(mockGetApprovedHolder).toHaveBeenCalledTimes(1); - expect(mockCallStaticTransferToNewEscrow).toHaveBeenCalledTimes(1); - expect(mockTransferToNewEscrow).toHaveBeenCalledTimes(1); - }); - - it("should throw an error if approved owner or approved holder addresses is the Genesis address", async () => { - mockGetApprovedBeneficiary.mockReturnValue(GENESIS_ADDRESS); - mockGetApprovedHolder.mockReturnValue(GENESIS_ADDRESS); - const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await expect( - endorseNominatedBeneficiary({ - ...endorseNominatedBeneficiaryParams, - key: privateKey, - }) - ).rejects.toThrow( - `there is no approved owner or holder or the approved owner or holder is equal to the genesis address: ${GENESIS_ADDRESS}` - ); + expect(mockCallStaticTransferOwners).toHaveBeenCalledTimes(1); + expect(mockTransferOwners).toHaveBeenCalledTimes(1); }); - it("should throw an error if approved owner or approved holder addresses does not exist", async () => { - mockGetApprovedBeneficiary.mockReturnValue(""); - mockGetApprovedHolder.mockReturnValue(""); + it("should throw an error if nominee is the owner address", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( endorseNominatedBeneficiary({ ...endorseNominatedBeneficiaryParams, + newBeneficiary: "0xdssfs", key: privateKey, }) ).rejects.toThrow( - `there is no approved owner or holder or the approved owner or holder is equal to the genesis address: ${GENESIS_ADDRESS}` + `new beneficiary address is the same as the current beneficiary address` ); }); }); diff --git a/src/implementations/title-escrow/transferOwner.test.ts b/src/implementations/title-escrow/transferOwner.test.ts index 150069be..dc39abef 100644 --- a/src/implementations/title-escrow/transferOwner.test.ts +++ b/src/implementations/title-escrow/transferOwner.test.ts @@ -1,12 +1,12 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { TitleEscrowEndorseChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { endorseChangeOfOwner } from "./transferOwner"; +import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { transferOwners } from "./transferOwner"; jest.mock("@govtechsg/token-registry/contracts"); -const endorseChangeOwnerParams: TitleEscrowEndorseChangeOfOwnerCommand = { +const endorseChangeOwnerParams: TitleEscrowEndorseTransferOfOwnersCommand = { newHolder: "0xabcd", newOwner: "0fosui", tokenId: "0xzyxw", @@ -69,7 +69,7 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke an endorsement of change of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await endorseChangeOfOwner({ + await transferOwners({ ...endorseChangeOwnerParams, key: privateKey, }); @@ -91,7 +91,7 @@ describe("title-escrow", () => { mockGetHolder.mockReturnValue(endorseChangeOwnerParams.newHolder); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( - endorseChangeOfOwner({ + transferOwners({ ...endorseChangeOwnerParams, key: privateKey, }) diff --git a/src/implementations/title-escrow/transferOwner.ts b/src/implementations/title-escrow/transferOwner.ts index a909d9ed..23186488 100644 --- a/src/implementations/title-escrow/transferOwner.ts +++ b/src/implementations/title-escrow/transferOwner.ts @@ -2,14 +2,14 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; import { connectToTitleEscrow, validateEndorseChangeOwner } from "./helpers"; -import { TitleEscrowEndorseChangeOfOwnerCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; const { trace } = getLogger("title-escrow:endorseChangeOfOwner"); -export const endorseChangeOfOwner = async ({ +export const transferOwners = async ({ tokenRegistry: address, tokenId, newHolder, @@ -18,7 +18,7 @@ export const endorseChangeOfOwner = async ({ gasPriceScale, dryRun, ...rest -}: TitleEscrowEndorseChangeOfOwnerCommand): Promise => { +}: TitleEscrowEndorseTransferOfOwnersCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); await validateEndorseChangeOwner({ newHolder, newOwner, titleEscrow }); From c7ee59adbfa8a949c5c32a4f4775b4cbc2949db5 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 13 Oct 2022 16:06:42 +0800 Subject: [PATCH 30/63] chore: renaming --- README.md | 4 ++-- src/commands/title-escrow/change-holder.ts | 14 +++++++------- .../title-escrow/endorse-change-of-owner.ts | 2 +- .../title-escrow/title-escrow-command.type.ts | 4 ++-- .../endorseNominatedBeneficiary.test.ts | 7 ++----- .../title-escrow/transferHolder.test.ts | 10 +++++----- src/implementations/title-escrow/transferHolder.ts | 10 +++++----- ...ransferOwner.test.ts => transferOwners.test.ts} | 2 +- .../{transferOwner.ts => transferOwners.ts} | 0 9 files changed, 25 insertions(+), 28 deletions(-) rename src/implementations/title-escrow/{transferOwner.test.ts => transferOwners.test.ts} (98%) rename src/implementations/title-escrow/{transferOwner.ts => transferOwners.ts} (100%) diff --git a/README.md b/README.md index e37da297..3bd984fd 100644 --- a/README.md +++ b/README.md @@ -563,13 +563,13 @@ open-attestation transaction cancel --transaction-hash 0x000 --network ropsten - This command will allow the owner of a transferable record to change its holder. ```bash -open-attestation title-escrow change-holder --token-registry --tokenId --to [options] +open-attestation title-escrow change-holder --token-registry --tokenId --newHolder [options] ``` Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). ```bash -open-attestation title-escrow change-holder --token-registry 0x4933e30eF8A083f49d14759b2eafC94E56F0b3A7 --tokenId 0x951b39bcaddc0e8882883db48ca258ca35ccb01fee328355f0dfda1ff9be9990 --to 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 +open-attestation title-escrow change-holder --token-registry 0x4933e30eF8A083f49d14759b2eafC94E56F0b3A7 --tokenId 0x951b39bcaddc0e8882883db48ca258ca35ccb01fee328355f0dfda1ff9be9990 --newHolder 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 ✔ success Transferable record with hash 0x951b39bcaddc0e8882883db48ca258ca35ccb01fee328355f0dfda1ff9be9990's holder has been successfully changed to holder with address: 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 ``` diff --git a/src/commands/title-escrow/change-holder.ts b/src/commands/title-escrow/change-holder.ts index e582bab6..c7fad906 100644 --- a/src/commands/title-escrow/change-holder.ts +++ b/src/commands/title-escrow/change-holder.ts @@ -1,8 +1,8 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { changeHolderOfTitleEscrow } from "../../implementations/title-escrow/transferHolder"; -import { TitleEscrowChangeHolderCommand } from "./title-escrow-command.type"; +import { transferHolder } from "../../implementations/title-escrow/transferHolder"; +import { TitleEscrowTransferHolderCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; @@ -27,7 +27,7 @@ export const builder = (yargs: Argv): Argv => type: "string", demandOption: true, }) - .option("to", { + .option("newHolder", { description: "Address of the new holder of the transferable record", type: "string", demandOption: true, @@ -35,18 +35,18 @@ export const builder = (yargs: Argv): Argv => ) ); -export const handler = async (args: TitleEscrowChangeHolderCommand): Promise => { +export const handler = async (args: TitleEscrowTransferHolderCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); try { info( - `Connecting to the registry ${args.tokenRegistry} and attempting to change the holder of the transferable record ${args.tokenId} to ${args.to}` + `Connecting to the registry ${args.tokenRegistry} and attempting to change the holder of the transferable record ${args.tokenId} to ${args.newHolder}` ); warn( `Please note that only current holders can change the holder of the transferable record, otherwise this command will fail.` ); - const { transactionHash } = await changeHolderOfTitleEscrow(args); + const { transactionHash } = await transferHolder(args); success( - `Transferable record with hash ${args.tokenId}'s holder has been successfully changed to holder with address: ${args.to}` + `Transferable record with hash ${args.tokenId}'s holder has been successfully changed to holder with address: ${args.newHolder}` ); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transactionHash}`); } catch (e) { diff --git a/src/commands/title-escrow/endorse-change-of-owner.ts b/src/commands/title-escrow/endorse-change-of-owner.ts index 55fbd5f6..3db4fe20 100644 --- a/src/commands/title-escrow/endorse-change-of-owner.ts +++ b/src/commands/title-escrow/endorse-change-of-owner.ts @@ -1,7 +1,7 @@ import { Argv } from "yargs"; import { error, info, success, warn } from "signale"; import { getLogger } from "../../logger"; -import { transferOwners } from "../../implementations/title-escrow/transferOwner"; +import { transferOwners } from "../../implementations/title-escrow/transferOwners"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "./title-escrow-command.type"; import { withGasPriceOption, withNetworkAndWalletSignerOption } from "../shared"; import { getErrorMessage, getEtherscanAddress } from "../../utils"; diff --git a/src/commands/title-escrow/title-escrow-command.type.ts b/src/commands/title-escrow/title-escrow-command.type.ts index 279bc423..3885464c 100644 --- a/src/commands/title-escrow/title-escrow-command.type.ts +++ b/src/commands/title-escrow/title-escrow-command.type.ts @@ -5,8 +5,8 @@ export type BaseTitleEscrowCommand = NetworkAndWalletSignerOption & tokenRegistry: string; tokenId: string; }; -export type TitleEscrowChangeHolderCommand = BaseTitleEscrowCommand & { - to: string; +export type TitleEscrowTransferHolderCommand = BaseTitleEscrowCommand & { + newHolder: string; }; export type TitleEscrowEndorseTransferOfOwnersCommand = BaseTitleEscrowCommand & { diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index bf4ed014..6d2d10e4 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -1,5 +1,5 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; -import { Wallet, constants } from "ethers"; +import { Wallet } from "ethers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { endorseNominatedBeneficiary } from "./endorseNominatedBeneficiary"; @@ -14,7 +14,6 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = gasPriceScale: 1, dryRun: false, }; -const GENESIS_ADDRESS = constants.AddressZero; describe("title-escrow", () => { describe("endorse transfer of owner of transferable record", () => { @@ -90,9 +89,7 @@ describe("title-escrow", () => { newBeneficiary: "0xdssfs", key: privateKey, }) - ).rejects.toThrow( - `new beneficiary address is the same as the current beneficiary address` - ); + ).rejects.toThrow(`new beneficiary address is the same as the current beneficiary address`); }); }); }); diff --git a/src/implementations/title-escrow/transferHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts index 68c0e10f..0883ad4b 100644 --- a/src/implementations/title-escrow/transferHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -1,13 +1,13 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; -import { TitleEscrowChangeHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { changeHolderOfTitleEscrow } from "./transferHolder"; +import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { transferHolder } from "./transferHolder"; jest.mock("@govtechsg/token-registry/contracts"); -const transferHolderParams: TitleEscrowChangeHolderCommand = { - to: "0xabcd", +const transferHolderParams: TitleEscrowTransferHolderCommand = { + newHolder: "0xabcd", tokenId: "0xzyxw", tokenRegistry: "0x1234", network: "goerli", @@ -58,7 +58,7 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke a change in holder of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; - await changeHolderOfTitleEscrow({ + await transferHolder({ ...transferHolderParams, key: privateKey, }); diff --git a/src/implementations/title-escrow/transferHolder.ts b/src/implementations/title-escrow/transferHolder.ts index d5ccc61a..880d6824 100644 --- a/src/implementations/title-escrow/transferHolder.ts +++ b/src/implementations/title-escrow/transferHolder.ts @@ -2,22 +2,22 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; import { connectToTitleEscrow } from "./helpers"; -import { TitleEscrowChangeHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -const { trace } = getLogger("title-escrow:changeHolder"); +const { trace } = getLogger("title-escrow:transferHolder"); -export const changeHolderOfTitleEscrow = async ({ +export const transferHolder = async ({ tokenRegistry: address, - to, + newHolder: to, tokenId, network, gasPriceScale, dryRun, ...rest -}: TitleEscrowChangeHolderCommand): Promise => { +}: TitleEscrowTransferHolderCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); if (dryRun) { diff --git a/src/implementations/title-escrow/transferOwner.test.ts b/src/implementations/title-escrow/transferOwners.test.ts similarity index 98% rename from src/implementations/title-escrow/transferOwner.test.ts rename to src/implementations/title-escrow/transferOwners.test.ts index dc39abef..5ba6c6cd 100644 --- a/src/implementations/title-escrow/transferOwner.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -2,7 +2,7 @@ import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/toke import { Wallet } from "ethers"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { transferOwners } from "./transferOwner"; +import { transferOwners } from "./transferOwners"; jest.mock("@govtechsg/token-registry/contracts"); diff --git a/src/implementations/title-escrow/transferOwner.ts b/src/implementations/title-escrow/transferOwners.ts similarity index 100% rename from src/implementations/title-escrow/transferOwner.ts rename to src/implementations/title-escrow/transferOwners.ts From 8947ba868ed282c3611f4b5c95918bfa4d112ed2 Mon Sep 17 00:00:00 2001 From: puayhiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 13 Oct 2022 16:15:21 +0800 Subject: [PATCH 31/63] feat: alias as parameter fallback --- src/commands/title-escrow/change-holder.ts | 1 + src/commands/title-escrow/endorse-change-of-owner.ts | 1 + src/commands/title-escrow/endorse-transfer-of-owner.ts | 1 + 3 files changed, 3 insertions(+) diff --git a/src/commands/title-escrow/change-holder.ts b/src/commands/title-escrow/change-holder.ts index c7fad906..c446bba2 100644 --- a/src/commands/title-escrow/change-holder.ts +++ b/src/commands/title-escrow/change-holder.ts @@ -28,6 +28,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("newHolder", { + alias: "to", description: "Address of the new holder of the transferable record", type: "string", demandOption: true, diff --git a/src/commands/title-escrow/endorse-change-of-owner.ts b/src/commands/title-escrow/endorse-change-of-owner.ts index 3db4fe20..0c8af672 100644 --- a/src/commands/title-escrow/endorse-change-of-owner.ts +++ b/src/commands/title-escrow/endorse-change-of-owner.ts @@ -28,6 +28,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("newOwner", { + alias: "newBeneficiary", description: "Address of the new owner of the transferable record", type: "string", demandOption: true, diff --git a/src/commands/title-escrow/endorse-transfer-of-owner.ts b/src/commands/title-escrow/endorse-transfer-of-owner.ts index 080d1925..9f191ffd 100644 --- a/src/commands/title-escrow/endorse-transfer-of-owner.ts +++ b/src/commands/title-escrow/endorse-transfer-of-owner.ts @@ -29,6 +29,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("newOwner", { + alias: "to", description: "Address of the beneficiary of the transferable record", type: "string", demandOption: true, From 3d26bf58daf169f71850bf5c5d377283ccdb4a65 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 4 Nov 2022 01:27:32 +0800 Subject: [PATCH 32/63] feat: allow custom token-registry deploy factories --- src/commands/deploy/deploy.types.ts | 3 +++ src/commands/deploy/token-registry.ts | 8 ++++++++ .../deploy/token-registry/helpers.ts | 19 ++++++++----------- .../deploy/token-registry/token-registry.ts | 9 ++++++++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/commands/deploy/deploy.types.ts b/src/commands/deploy/deploy.types.ts index 3665e1f6..a66d6f4c 100644 --- a/src/commands/deploy/deploy.types.ts +++ b/src/commands/deploy/deploy.types.ts @@ -9,5 +9,8 @@ export type DeployTokenRegistryCommand = NetworkAndWalletSignerOption & GasOption & { registryName: string; registrySymbol: string; + factoryAddress?: string; + tokenImplementationAddress?: string; + deployerAddress?: string; }; diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index b0738764..31d2f371 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -30,6 +30,14 @@ export const builder = (yargs: Argv): Argv => description: "Address of Token Registry factory (Optional)", normalize: true, }) + .option("token-implementation-address", { + description: "Address of Token Implementation (Optional)", + normalize: true, + }) + .option("deployer-address", { + description: "Address of Deployer (Optional)", + normalize: true, + }) ) ); diff --git a/src/implementations/deploy/token-registry/helpers.ts b/src/implementations/deploy/token-registry/helpers.ts index 6804b38f..00c721d7 100644 --- a/src/implementations/deploy/token-registry/helpers.ts +++ b/src/implementations/deploy/token-registry/helpers.ts @@ -17,31 +17,28 @@ export const encodeInitParams = ({ name, symbol, deployer }: Params): string => return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); }; -export const retrieveFactoryAddress = (chainId: number, factoryAddress: string | undefined): DeployContractAddress => { +export const retrieveFactoryAddress = (chainId: number, inputAddress: DeployContractAddress): DeployContractAddress => { const { contractAddress } = constants; if (!chainId) { throw new Error(`Invalid chain ID: ${chainId}`); } - let titleEscrowFactory = factoryAddress; - const tokenImplementation = contractAddress.TokenImplementation[chainId]; - const deployer = contractAddress.Deployer[chainId]; + const titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId] || inputAddress.titleEscrowFactory; + const tokenImplementation = contractAddress.TokenImplementation[chainId] || inputAddress.tokenImplementation; + const deployer = contractAddress.Deployer[chainId] || inputAddress.deployer; if (!tokenImplementation || !deployer) { throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); } if (!titleEscrowFactory) { - titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId]; - if (!titleEscrowFactory) { - throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); - } + throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); } return { - titleEscrowFactory: titleEscrowFactory, - tokenImplementation: tokenImplementation, - deployer: deployer, + titleEscrowFactory, + tokenImplementation, + deployer, } as DeployContractAddress; }; diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index cd2d36bb..f689a680 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -13,6 +13,8 @@ export const deployTokenRegistry = async ({ registryName, registrySymbol, factoryAddress, + tokenImplementationAddress, + deployerAddress, network, gasPriceScale, dryRun, @@ -20,7 +22,12 @@ export const deployTokenRegistry = async ({ }: DeployTokenRegistryCommand): Promise<{ contractAddress: string }> => { const wallet = await getWalletOrSigner({ network, ...rest }); const chainId = await wallet.getChainId(); - const deployContractAddress: DeployContractAddress = retrieveFactoryAddress(chainId, factoryAddress); + const deployContractAddressInput: DeployContractAddress = { + titleEscrowFactory: factoryAddress || "", + tokenImplementation: tokenImplementationAddress || "", + deployer: deployerAddress || "", + } + const deployContractAddress: DeployContractAddress = retrieveFactoryAddress(chainId, deployContractAddressInput); const factory = new ethers.Contract( deployContractAddress.deployer, From 7a5498117be58632a39252f40a22bd6d4dd6915f Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 4 Nov 2022 01:49:08 +0800 Subject: [PATCH 33/63] fix: test --- .../deploy/token-registry/helpers.test.ts | 10 +++++++--- src/implementations/deploy/token-registry/helpers.ts | 11 +++++++---- .../deploy/token-registry/token-registry.ts | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/implementations/deploy/token-registry/helpers.test.ts b/src/implementations/deploy/token-registry/helpers.test.ts index 3a3ace14..a5c4e71e 100644 --- a/src/implementations/deploy/token-registry/helpers.test.ts +++ b/src/implementations/deploy/token-registry/helpers.test.ts @@ -11,10 +11,14 @@ describe("valid Token Registry Factory Address", () => { }); it("should return provided deployer address", () => { - const suppliedAddress = "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7"; + const suppliedAddress = { + titleEscrowFactory: "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7", + tokenImplementation: "", + deployer: "", + }; const address = retrieveFactoryAddress(5, suppliedAddress); - expect(address.titleEscrowFactory).toBe(suppliedAddress); + expect(address.titleEscrowFactory).toBe(suppliedAddress.titleEscrowFactory); expect(isAddress(address.tokenImplementation)).toBe(true); expect(isAddress(address.deployer)).toBe(true); }); @@ -22,7 +26,7 @@ describe("valid Token Registry Factory Address", () => { it("should reject invalid chainId", () => { let validTest = false; try { - retrieveFactoryAddress(2022, undefined); + retrieveFactoryAddress(2022); } catch (e) { validTest = true; } finally { diff --git a/src/implementations/deploy/token-registry/helpers.ts b/src/implementations/deploy/token-registry/helpers.ts index 00c721d7..f4e1f438 100644 --- a/src/implementations/deploy/token-registry/helpers.ts +++ b/src/implementations/deploy/token-registry/helpers.ts @@ -17,16 +17,19 @@ export const encodeInitParams = ({ name, symbol, deployer }: Params): string => return ethers.utils.defaultAbiCoder.encode(["string", "string", "address"], [name, symbol, deployer]); }; -export const retrieveFactoryAddress = (chainId: number, inputAddress: DeployContractAddress): DeployContractAddress => { +export const retrieveFactoryAddress = ( + chainId: number, + inputAddress?: DeployContractAddress +): DeployContractAddress => { const { contractAddress } = constants; if (!chainId) { throw new Error(`Invalid chain ID: ${chainId}`); } - const titleEscrowFactory = contractAddress.TitleEscrowFactory[chainId] || inputAddress.titleEscrowFactory; - const tokenImplementation = contractAddress.TokenImplementation[chainId] || inputAddress.tokenImplementation; - const deployer = contractAddress.Deployer[chainId] || inputAddress.deployer; + const titleEscrowFactory = inputAddress?.titleEscrowFactory || contractAddress.TitleEscrowFactory[chainId]; + const tokenImplementation = inputAddress?.tokenImplementation || contractAddress.TokenImplementation[chainId]; + const deployer = inputAddress?.deployer || contractAddress.Deployer[chainId]; if (!tokenImplementation || !deployer) { throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index f689a680..2ee286a9 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -26,7 +26,7 @@ export const deployTokenRegistry = async ({ titleEscrowFactory: factoryAddress || "", tokenImplementation: tokenImplementationAddress || "", deployer: deployerAddress || "", - } + }; const deployContractAddress: DeployContractAddress = retrieveFactoryAddress(chainId, deployContractAddressInput); const factory = new ethers.Contract( From 039a0869e10ef023b0e63624017817b2c8d97e3d Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:23:00 +0800 Subject: [PATCH 34/63] fix: address parsing error --- src/commands/deploy/token-registry.ts | 6 +++--- src/implementations/deploy/token-registry/helpers.ts | 11 ++++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/commands/deploy/token-registry.ts b/src/commands/deploy/token-registry.ts index 31d2f371..3d5aecc6 100644 --- a/src/commands/deploy/token-registry.ts +++ b/src/commands/deploy/token-registry.ts @@ -28,15 +28,15 @@ export const builder = (yargs: Argv): Argv => }) .option("factory-address", { description: "Address of Token Registry factory (Optional)", - normalize: true, + type: "string", }) .option("token-implementation-address", { description: "Address of Token Implementation (Optional)", - normalize: true, + type: "string", }) .option("deployer-address", { description: "Address of Deployer (Optional)", - normalize: true, + type: "string", }) ) ); diff --git a/src/implementations/deploy/token-registry/helpers.ts b/src/implementations/deploy/token-registry/helpers.ts index f4e1f438..68393d93 100644 --- a/src/implementations/deploy/token-registry/helpers.ts +++ b/src/implementations/deploy/token-registry/helpers.ts @@ -1,5 +1,6 @@ import { ethers } from "ethers"; import { constants } from "@govtechsg/token-registry"; +import { isAddress } from "ethers/lib/utils"; export interface DeployContractAddress { titleEscrowFactory: string; @@ -27,15 +28,15 @@ export const retrieveFactoryAddress = ( throw new Error(`Invalid chain ID: ${chainId}`); } - const titleEscrowFactory = inputAddress?.titleEscrowFactory || contractAddress.TitleEscrowFactory[chainId]; - const tokenImplementation = inputAddress?.tokenImplementation || contractAddress.TokenImplementation[chainId]; - const deployer = inputAddress?.deployer || contractAddress.Deployer[chainId]; + const titleEscrowFactory = inputAddress?.titleEscrowFactory || contractAddress.TitleEscrowFactory[chainId] || ""; + const tokenImplementation = inputAddress?.tokenImplementation || contractAddress.TokenImplementation[chainId] || ""; + const deployer = inputAddress?.deployer || contractAddress.Deployer[chainId] || ""; - if (!tokenImplementation || !deployer) { + if (!isAddress(tokenImplementation) || !isAddress(deployer)) { throw new Error(`ChainId ${chainId} currently is not supported. Use token-registry to deploy.`); } - if (!titleEscrowFactory) { + if (!isAddress(titleEscrowFactory)) { throw new Error(`ChainId ${chainId} currently is not supported. Supply a factory address.`); } From bd66537eaf67db7e5435f4ec0c42d9815daeabd9 Mon Sep 17 00:00:00 2001 From: isaackps Date: Thu, 27 Oct 2022 14:33:28 +0800 Subject: [PATCH 35/63] feat: deprecate ropsten and rinkeby (#230) --- README.md | 57 +++++++++++-------- src/commands/networks.ts | 10 ---- src/commands/wallet/create.ts | 22 +++---- .../config/__tests__/error-config-file.json | 2 +- .../expected-config-file-output.json | 2 +- .../config/__tests__/input-config-file.json | 2 +- src/implementations/wallet/create.ts | 16 +----- 7 files changed, 44 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 3bd984fd..f461fa35 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,6 @@ npx -p @govtechsg/open-attestation-cli open-attestation | Network | Chain ID | Type | | ------- | -------- | ---------- | | mainnet | 1 | Production | -| ropsten | 3 | Test | -| rinkeby | 4 | Test | | goerli | 5 | Test | | polygon | 137 | Production | | mumbai | 80001 | Test | @@ -257,7 +255,7 @@ open-attestation deploy token-registry --facto Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). ```bash -open-attestation deploy token-registry "My Sample Token" MST --network ropsten +open-attestation deploy token-registry "My Sample Token" MST --network goerli ✔ success Token registry deployed at 0x4B127b8d5e53872d403ce43414afeb1db67B1842 ``` @@ -273,7 +271,7 @@ open-attestation token-registry issue --network --address [options] Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). ```bash -open-attestation deploy document-store "My Name" --network ropsten +open-attestation deploy document-store "My Name" --network goerli ✔ success Document store deployed at 0x4B127b8d5e53872d403ce43414afeb1db67B1842 ``` @@ -315,7 +313,7 @@ open-attestation document-store issue --address --hash Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). ```bash -open-attestation document-store issue --network ropsten --address 0x19f89607b52268D0A19543e48F790c65750869c6 --hash 0x43033b53a462036304f526aeaf3aaeea8d905997d6fde3bb1a02188eadbaaec1 +open-attestation document-store issue --network goerli --address 0x19f89607b52268D0A19543e48F790c65750869c6 --hash 0x43033b53a462036304f526aeaf3aaeea8d905997d6fde3bb1a02188eadbaaec1 ✔ success Document/Document Batch with hash 0x0c1a666aa55d17d26412bb57fbed96f40ec5a08e2f995a108faf45429ae3511f has been issued on 0x19f89607b52268D0A19543e48F790c65750869c6 ``` @@ -331,7 +329,7 @@ open-attestation document-store revoke --address --hash Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). ```bash -open-attestation document-store revoke --network ropsten --address 0x19f89607b52268D0A19543e48F790c65750869c6 --hash 0x43033b53a462036304f526aeaf3aaeea8d905997d6fde3bb1a02188eadbaaec1 +open-attestation document-store revoke --network goerli --address 0x19f89607b52268D0A19543e48F790c65750869c6 --hash 0x43033b53a462036304f526aeaf3aaeea8d905997d6fde3bb1a02188eadbaaec1 ✔ success Document/Document Batch with hash 0x0c1a666aa55d17d26412bb57fbed96f40ec5a08e2f995a108faf45429ae3511f has been revoked on 0x19f89607b52268D0A19543e48F790c65750869c6 ``` @@ -347,7 +345,7 @@ open-attestation document-store transfer-ownership --address > ./examples/sample-key -open-attestation deploy document-store "My Name" --network ropsten --key-file ./examples/sample-key +open-attestation deploy document-store "My Name" --network goerli --key-file ./examples/sample-key rm ./examples/sample-key # Providing the key to the command -open-attestation deploy document-store "My Name" --network ropsten --key 0000000000000000000000000000000000000000000000000000000000000003 +open-attestation deploy document-store "My Name" --network goerli --key 0000000000000000000000000000000000000000000000000000000000000003 ``` ### Config (Create configuration file) This command will generate a config file with sandbox DNS, document store and token registry. -> Please note that a wallet.json file in ropsten network with sufficient **funds** must be provided in order for this command to work. +> Please note that a wallet.json file with sufficient **funds** in goerli network must be provided in order for this command to work. You will need: @@ -499,16 +497,21 @@ There are 2 ways of using this command to generate a config file, both in which, This method will generate the most basic config file with a sandbox DNS, document store and token registry. The reference config templates are [here](https://github.com/TradeTrust/document-creator-website/tree/master/src/test/fixtures/config/_generated-config-files/v2). -Step 1: Generate a wallet.json file +Step 1a: Generate a wallet.json file ``` -// If you already have a wallet.json that is in ropsten network with sufficient funds, you can skip this step. -open-attestation wallet create --output-file wallet.json --fund ropsten +// If you already have a wallet.json that has sufficient funds in goerli network, you can skip this step. +open-attestation wallet create --output-file wallet.json ``` +Step 1b: Add fund into the newly created wallet.json + +Currently, we do not provide any faucet to dispense any funds into the wallet.json. You can search the web for some faucets. + Step 2: Generate config file by passing in the generated wallet.json file ``` +// Please note that to proceed successfully with this step you would require a wallet.json with sufficient funds. open-attestation config create --output-dir ./example-configs --encrypted-wallet-path /wallet.json --config-template-url ``` @@ -516,13 +519,17 @@ open-attestation config create --output-dir ./example-configs --encrypted-wallet This method will generate a copy of your existing config file with the updated sandbox DNS, document store and token registry. -Step 1: Generate a wallet.json file +Step 1a: Generate a wallet.json file ``` -// If you already have a wallet.json that is in ropsten network with sufficient funds, you can skip this step. -open-attestation wallet create --output-file wallet.json --fund ropsten +// If you already have a wallet.json that has sufficient funds in goerli network, you can skip this step. +open-attestation wallet create --output-file wallet.json ``` +Step 1b: Add fund into the newly created wallet.json + +Currently, we do not provide any faucet to dispense any funds into the wallet.json. You can search the web for some faucets. + Step 2: Generate config file by passing in the generated wallet.json file and a existing config file ``` @@ -549,11 +556,11 @@ open-attestation transaction cancel --nonce --gas-pr Examples: ``` -open-attestation transaction cancel --nonce 1 --gas-price 300 --network ropsten --encrypted-wallet-path /path/to/wallet +open-attestation transaction cancel --nonce 1 --gas-price 300 --network goerli --encrypted-wallet-path /path/to/wallet ``` ``` -open-attestation transaction cancel --transaction-hash 0x000 --network ropsten --encrypted-wallet-path /path/to/wallet +open-attestation transaction cancel --transaction-hash 0x000 --network goerli --encrypted-wallet-path /path/to/wallet ``` ### Title Escrow @@ -636,7 +643,7 @@ open-attestation title-escrow surrender --token-registry - yargs - .option("output-file", { - alias: "of", - description: "Write output to a file", - type: "string", - demandOption: true, - }) - .option("fund", { - description: "Automatically add funds for the specified network", - type: "string", - choices: ["ropsten"], - }); + yargs.option("output-file", { + alias: "of", + description: "Write output to a file", + type: "string", + demandOption: true, + }); export const handler = async (args: CreateWalletCommand): Promise => { trace(`Args: ${JSON.stringify(args, null, 2)}`); diff --git a/src/implementations/config/__tests__/error-config-file.json b/src/implementations/config/__tests__/error-config-file.json index 2f20594d..58d7ce54 100644 --- a/src/implementations/config/__tests__/error-config-file.json +++ b/src/implementations/config/__tests__/error-config-file.json @@ -1,5 +1,5 @@ { - "network": "ropsten", + "network": "goerli", "wallet": { "type": "ENCRYPTED_JSON", "encryptedJson": "{\"address\":\"1245e5b64d785b25057f7438f715f4aa5d965733\",\"id\":\"bf069d1b-4e88-487c-b695-f2e03ed7c1ff\",\"version\":3,\"Crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"1f34e7bfdaee4b0778ecea4c8d12a543\"},\"ciphertext\":\"4f6cee88b4776f4f6f8eedf3da11c6a13542aa4bb65d46a5c1bc44c100a96f54\",\"kdf\":\"scrypt\",\"kdfparams\":{\"salt\":\"d931e0ea13032fd70060e40054c5a76c0571f4d840ec91eeda1bf68bdcad84db\",\"n\":1,\"dklen\":32,\"p\":1,\"r\":8},\"mac\":\"06c7897e3ff04245bf4f0765d8b6a8482c1c9981cb46ae88f636f9c83cd0b891\"},\"x-ethers\":{\"client\":\"ethers.js\",\"gethFilename\":\"UTC--2020-05-15T09-03-13.0Z--1245e5b64d785b25057f7438f715f4aa5d965733\",\"mnemonicCounter\":\"99b7f5b6897dcfe22fc7aa00d8e3cf5e\",\"mnemonicCiphertext\":\"6e7c1d38f162e54050b125f1f51b43ca\",\"path\":\"m/44'/60'/0'/0/0\",\"version\":\"0.1\"}}" diff --git a/src/implementations/config/__tests__/expected-config-file-output.json b/src/implementations/config/__tests__/expected-config-file-output.json index 0ced60e2..02d95f88 100644 --- a/src/implementations/config/__tests__/expected-config-file-output.json +++ b/src/implementations/config/__tests__/expected-config-file-output.json @@ -1,5 +1,5 @@ { - "network": "ropsten", + "network": "goerli", "wallet": { "type": "ENCRYPTED_JSON", "encryptedJson": "{\"address\":\"709731d94d65b078496937655582401157c8a640\",\"id\":\"90167e7e-af5c-44b1-a6a3-2525300d1032\",\"version\":3,\"Crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"02004e981623b906938a205c24805bef\"},\"ciphertext\":\"06568387223b88fe860bfed23442966124fe38e463fdb5501a0a0f8b9d1519db\",\"kdf\":\"scrypt\",\"kdfparams\":{\"salt\":\"56b3c1e89f4d8a3f76564d4e6f64e832e46729c881764328a4509a2e96c052fe\",\"n\":131072,\"dklen\":32,\"p\":1,\"r\":8},\"mac\":\"7611744a709d7cac37379617e8ddd9f134658b7a99b09f55eeaa50b4af6e0d39\"},\"x-ethers\":{\"client\":\"ethers.js\",\"gethFilename\":\"UTC--2021-02-01T06-07-08.0Z--709731d94d65b078496937655582401157c8a640\",\"mnemonicCounter\":\"f2706de1481a3541e7b49885f9a21fa7\",\"mnemonicCiphertext\":\"7eb14f3487659d100e5dddac1cef72dd\",\"path\":\"m/44'/60'/0'/0/0\",\"locale\":\"en\",\"version\":\"0.1\"}}" diff --git a/src/implementations/config/__tests__/input-config-file.json b/src/implementations/config/__tests__/input-config-file.json index 202f2484..99e5d5d5 100644 --- a/src/implementations/config/__tests__/input-config-file.json +++ b/src/implementations/config/__tests__/input-config-file.json @@ -1,5 +1,5 @@ { - "network": "ropsten", + "network": "goerli", "wallet": { "type": "ENCRYPTED_JSON", "encryptedJson": "{\"address\":\"1245e5b64d785b25057f7438f715f4aa5d965733\",\"id\":\"bf069d1b-4e88-487c-b695-f2e03ed7c1ff\",\"version\":3,\"Crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"1f34e7bfdaee4b0778ecea4c8d12a543\"},\"ciphertext\":\"4f6cee88b4776f4f6f8eedf3da11c6a13542aa4bb65d46a5c1bc44c100a96f54\",\"kdf\":\"scrypt\",\"kdfparams\":{\"salt\":\"d931e0ea13032fd70060e40054c5a76c0571f4d840ec91eeda1bf68bdcad84db\",\"n\":1,\"dklen\":32,\"p\":1,\"r\":8},\"mac\":\"06c7897e3ff04245bf4f0765d8b6a8482c1c9981cb46ae88f636f9c83cd0b891\"},\"x-ethers\":{\"client\":\"ethers.js\",\"gethFilename\":\"UTC--2020-05-15T09-03-13.0Z--1245e5b64d785b25057f7438f715f4aa5d965733\",\"mnemonicCounter\":\"99b7f5b6897dcfe22fc7aa00d8e3cf5e\",\"mnemonicCiphertext\":\"6e7c1d38f162e54050b125f1f51b43ca\",\"path\":\"m/44'/60'/0'/0/0\",\"version\":\"0.1\"}}" diff --git a/src/implementations/wallet/create.ts b/src/implementations/wallet/create.ts index d3adae5e..c1a7a63b 100644 --- a/src/implementations/wallet/create.ts +++ b/src/implementations/wallet/create.ts @@ -1,7 +1,6 @@ import { ethers } from "ethers"; import fs from "fs"; import inquirer from "inquirer"; -import fetch from "node-fetch"; import path from "path"; import signale from "signale"; import { CreateWalletCommand } from "../../commands/wallet/wallet.type"; @@ -9,7 +8,6 @@ import { progress as defaultProgress } from "../../implementations/utils/progres import { getEtherscanAddress, highlight } from "../../utils"; export const create = async ({ - fund, progress = defaultProgress("Encrypting Wallet"), outputFile, }: CreateWalletCommand & { progress?: (progress: number) => void }): Promise => { @@ -24,20 +22,8 @@ export const create = async ({ const outputPath = path.resolve(outputFile); fs.writeFileSync(outputPath, json); - if (fund === "ropsten") { - const response = await fetch(`https://faucet.openattestation.com/donate/${wallet.address}`).then((res) => - res.json() - ); - if (response.message) { - signale.warn(`[ropsten] Adding fund to ${wallet.address} failed: ${response.message}`); - } else { - signale.info( - `[ropsten] Request to add funds into ${wallet.address} sent. Please wait a while before the funds being added into your wallet. You can check the transaction at https://ropsten.etherscan.io/tx/${response.txhash}` - ); - } - } signale.info(`Wallet with public address ${highlight(wallet.address)} successfully created.`); - signale.info(`Find more details at ${getEtherscanAddress({ network: "ropsten" })}/address/${wallet.address}`); + signale.info(`Find more details at ${getEtherscanAddress({ network: "goerli" })}/address/${wallet.address}`); return outputPath; }; From 52cd61b67d80c250f504487f226e1141e7634f49 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 9 Nov 2022 16:05:34 +0800 Subject: [PATCH 36/63] fix: renamed newOwner to newBeneficiary --- README.md | 2 +- .../title-escrow/endorse-transfer-of-owner.ts | 4 ++-- .../title-escrow/transferOwners.test.ts | 16 ++++++++-------- .../title-escrow/transferOwners.ts | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index f461fa35..ea2ec7fe 100644 --- a/README.md +++ b/README.md @@ -604,7 +604,7 @@ This command will allow the holder of the transferable record to endorse the tra **This command will fail if there is no approved owner or holder record on the transferable record.** ```bash -open-attestation title-escrow endorse-transfer-owner --token-registry --tokenId --newOwner [options] +open-attestation title-escrow endorse-transfer-owner --token-registry --tokenId --newBeneficiary [options] ``` Example - with private key set in `OA_PRIVATE_KEY` environment variable (recommended). [More options](#providing-the-wallet). diff --git a/src/commands/title-escrow/endorse-transfer-of-owner.ts b/src/commands/title-escrow/endorse-transfer-of-owner.ts index 9f191ffd..b9652883 100644 --- a/src/commands/title-escrow/endorse-transfer-of-owner.ts +++ b/src/commands/title-escrow/endorse-transfer-of-owner.ts @@ -28,8 +28,8 @@ export const builder = (yargs: Argv): Argv => type: "string", demandOption: true, }) - .option("newOwner", { - alias: "to", + .option("newBeneficiary", { + alias: ["to","newOwner"], description: "Address of the beneficiary of the transferable record", type: "string", demandOption: true, diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index 5ba6c6cd..f7f111e4 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -6,7 +6,7 @@ import { transferOwners } from "./transferOwners"; jest.mock("@govtechsg/token-registry/contracts"); -const endorseChangeOwnerParams: TitleEscrowEndorseTransferOfOwnersCommand = { +const endorseChangeOwnersParams: TitleEscrowEndorseTransferOfOwnersCommand = { newHolder: "0xabcd", newOwner: "0fosui", tokenId: "0xzyxw", @@ -17,7 +17,7 @@ const endorseChangeOwnerParams: TitleEscrowEndorseTransferOfOwnersCommand = { }; describe("title-escrow", () => { - describe("endorse change of owner of transferable record", () => { + describe("endorse change of owners of transferable record", () => { const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -70,15 +70,15 @@ describe("title-escrow", () => { it("should pass in the correct params and call the following procedures to invoke an endorsement of change of owner of a transferable record", async () => { const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await transferOwners({ - ...endorseChangeOwnerParams, + ...endorseChangeOwnersParams, key: privateKey, }); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; expect(passedSigner.privateKey).toBe(`0x${privateKey}`); - expect(mockedConnectERC721).toHaveBeenCalledWith(endorseChangeOwnerParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(endorseChangeOwnerParams.tokenId); + expect(mockedConnectERC721).toHaveBeenCalledWith(endorseChangeOwnersParams.tokenRegistry, passedSigner); + expect(mockedOwnerOf).toHaveBeenCalledWith(endorseChangeOwnersParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockGetBeneficiary).toHaveBeenCalledTimes(1); expect(mockGetHolder).toHaveBeenCalledTimes(1); @@ -87,12 +87,12 @@ describe("title-escrow", () => { }); it("should throw an error if new owner and new holder addresses are the same as current owner and holder addressses", async () => { - mockGetBeneficiary.mockReturnValue(endorseChangeOwnerParams.newOwner); - mockGetHolder.mockReturnValue(endorseChangeOwnerParams.newHolder); + mockGetBeneficiary.mockReturnValue(endorseChangeOwnersParams.newOwner); + mockGetHolder.mockReturnValue(endorseChangeOwnersParams.newHolder); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( transferOwners({ - ...endorseChangeOwnerParams, + ...endorseChangeOwnersParams, key: privateKey, }) ).rejects.toThrow("new owner and new holder addresses are the same as the current owner and holder addresses"); diff --git a/src/implementations/title-escrow/transferOwners.ts b/src/implementations/title-escrow/transferOwners.ts index 23186488..580a8a1d 100644 --- a/src/implementations/title-escrow/transferOwners.ts +++ b/src/implementations/title-escrow/transferOwners.ts @@ -1,7 +1,7 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow, validateEndorseChangeOwner } from "./helpers"; +import { connectToTitleEscrow, validateEndorseChangeOwner as validateEndorseChangeOwners } from "./helpers"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; @@ -21,7 +21,7 @@ export const transferOwners = async ({ }: TitleEscrowEndorseTransferOfOwnersCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await validateEndorseChangeOwner({ newHolder, newOwner, titleEscrow }); + await validateEndorseChangeOwners({ newHolder, newOwner, titleEscrow }); if (dryRun) { await dryRunMode({ gasPriceScale: gasPriceScale, From e3171aff7ee0e73292601e6433f4f34106539bdf Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 10 Nov 2022 19:36:33 +0800 Subject: [PATCH 37/63] fix: renaming --- .DS_Store | Bin 0 -> 8196 bytes README.md | 4 +- sigh/config.json | 976 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 978 insertions(+), 2 deletions(-) create mode 100644 .DS_Store create mode 100644 sigh/config.json diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..c2cfc0681767194c22d71c3ecf99ffc708c7baaa GIT binary patch literal 8196 zcmeHMTWl3Y7@lui=AD=AZwc z`DbUo`Tm_Vdl+L#l?rzrTM!k`o?dC}T;ELXn zAwnQRAVMHQAVMHQ;6^}z&TNtRHO_t68kG?O5dt?Q0^*xhaL9`xdw#q0XA#Onodt# zknNQ_3<&@o07T=Ur!4(G=}{ zdDkutJ6=Yw&1da=$g|SblS-do97oStk;c2#^Q>X?0eal>kYiWl(UYMEdQ8%h7n(?a{ax1 z1)A4Rw;)C=1TBUUU&i@fVecrKR7$gEG_E9vY}%uxh0|QUMpbn$eVF!Fx@s-0T-6JE z>}<}oL(_&fGHvfGOMFA)J)1erzPUf|4iD3MJZUyk9h~du4v1&($a;SFi0O>aDz%mK zL2oEqG`mNMU=@$;oCkYGcHy$6VEJxQ0und6IUf*%wHFFBj=r#d!2`PugEq!;$`;X? zHe9k=|C)2&kX$MECjhk}nUI=FN0h-<(^1&P_A!%{s>&yU6}RHKw5k9JN@4Td){Q(1cd3!+NB!9XqfS-AH3U4j_Xp4#LFhCBDT^_!+<8BL2odxTL7cTxFSZhq6Lx zR8}f2$_AxfPF<-)%iv_%G}OrK7Smuh3IDW)qFXi{ArOK5r(g^?Qgw#1q=9b77RX>FQbO#vm< zP1-X80S=^{M-15w{*AF@x0sOO2Ozp>xhpX?Hmb2jRUn9H#OjcCRyBIgFQ zVIwwS3$~&Q+lZ=Z^r8;~7(^Z>5p@U_ittfF84u$TqU$L+z^)j0k}U zfg2P7RCo4tieCcPdfAG*cAWBqltmK##-t2fs1RL*J-CjO9RI_R>hZ8G8Okv!sfE)2 U{vlxE58deekIw&qg*RXEFN!-G2LJ#7 literal 0 HcmV?d00001 diff --git a/README.md b/README.md index ea2ec7fe..89c5d55e 100644 --- a/README.md +++ b/README.md @@ -610,9 +610,9 @@ open-attestation title-escrow endorse-transfer-owner --token-registry Date: Mon, 14 Nov 2022 15:47:32 +0800 Subject: [PATCH 38/63] fix: linting --- src/commands/title-escrow/endorse-transfer-of-owner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/title-escrow/endorse-transfer-of-owner.ts b/src/commands/title-escrow/endorse-transfer-of-owner.ts index b9652883..5f73c43c 100644 --- a/src/commands/title-escrow/endorse-transfer-of-owner.ts +++ b/src/commands/title-escrow/endorse-transfer-of-owner.ts @@ -29,7 +29,7 @@ export const builder = (yargs: Argv): Argv => demandOption: true, }) .option("newBeneficiary", { - alias: ["to","newOwner"], + alias: ["to", "newOwner"], description: "Address of the beneficiary of the transferable record", type: "string", demandOption: true, From 3127d743db566db5e817fd14f78a7e7f51a85e99 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 16 Nov 2022 20:00:14 +0800 Subject: [PATCH 39/63] fix: remove gas price scale --- .../document-store/document-store.test.ts | 2 +- .../deploy/document-store/document-store.ts | 6 +- .../token-registry/token-registry.test.ts | 2 +- .../deploy/token-registry/token-registry.ts | 7 +- src/implementations/document-store/issue.ts | 7 +- src/implementations/document-store/revoke.ts | 8 +- .../document-store/transfer-ownership.ts | 7 +- .../title-escrow/acceptSurrendered.ts | 8 +- .../endorseNominatedBeneficiary.ts | 12 +- .../title-escrow/nominateBeneficiary.ts | 12 +- .../title-escrow/rejectSurrendered.ts | 2 - .../title-escrow/surrenderDocument.ts | 8 +- .../title-escrow/transferHolder.ts | 6 +- .../title-escrow/transferOwners.ts | 12 +- src/implementations/token-registry/issue.ts | 10 +- src/implementations/utils/dryRun.ts | 212 +++++++++--------- 16 files changed, 142 insertions(+), 179 deletions(-) diff --git a/src/implementations/deploy/document-store/document-store.test.ts b/src/implementations/deploy/document-store/document-store.test.ts index 5dbc7175..dfec0149 100644 --- a/src/implementations/deploy/document-store/document-store.test.ts +++ b/src/implementations/deploy/document-store/document-store.test.ts @@ -66,7 +66,7 @@ describe("document-store", () => { expect(passedSigner.privateKey).toBe(`0x${deployParams.key}`); expect(mockedDeploy.mock.calls[0][0]).toStrictEqual(deployParams.storeName); // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][1].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); + // expect(mockedDeploy.mock.calls[0][1].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); expect(instance.contractAddress).toBe("contractAddress"); }); diff --git a/src/implementations/deploy/document-store/document-store.ts b/src/implementations/deploy/document-store/document-store.ts index 0dbd315a..21c1fe3c 100644 --- a/src/implementations/deploy/document-store/document-store.ts +++ b/src/implementations/deploy/document-store/document-store.ts @@ -10,13 +10,11 @@ const { trace } = getLogger("deploy:document-store"); export const deployDocumentStore = async ({ storeName, network, - gasPriceScale, dryRun, ...rest }: DeployDocumentStoreCommand): Promise<{ contractAddress: string }> => { if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, transaction: new DocumentStoreFactory().getDeployTransaction(storeName), network, }); @@ -24,10 +22,10 @@ export const deployDocumentStore = async ({ } const wallet = await getWalletOrSigner({ network, ...rest }); - const gasPrice = await wallet.provider.getGasPrice(); + const factory = new DocumentStoreFactory(wallet); signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(storeName, { gasPrice: gasPrice.mul(gasPriceScale) }); + const transaction = await factory.deploy(storeName); trace(`Tx hash: ${transaction.deployTransaction.hash}`); trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 876c34db..1f9c441a 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -65,7 +65,7 @@ describe("token-registry", () => { expect(mockedDeploy.mock.calls[0][1]).toEqual(expectedInitParams); // price should be any length string of digits - expect(mockedDeploy.mock.calls[0][2].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); + // expect(mockedDeploy.mock.calls[0][2].gasPrice.toString()).toStrictEqual(expect.stringMatching(/\d+/)); // expect(instance.contractAddress).toBe("contractAddress"); // TODO }); diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 2ee286a9..79f864f5 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -16,7 +16,6 @@ export const deployTokenRegistry = async ({ tokenImplementationAddress, deployerAddress, network, - gasPriceScale, dryRun, ...rest }: DeployTokenRegistryCommand): Promise<{ contractAddress: string }> => { @@ -51,12 +50,10 @@ export const deployTokenRegistry = async ({ signale.info(`Estimated Gas Required: ${estimatedGas.toString()}`); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(deployContractAddress.tokenImplementation, initParam, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + const transaction = await factory.deploy(deployContractAddress.tokenImplementation, initParam); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/document-store/issue.ts b/src/implementations/document-store/issue.ts index 7387ef8c..76172451 100644 --- a/src/implementations/document-store/issue.ts +++ b/src/implementations/document-store/issue.ts @@ -12,7 +12,6 @@ export const issueToDocumentStore = async ({ address, hash, network, - gasPriceScale, dryRun, ...rest }: DocumentStoreIssueCommand): Promise => { @@ -20,21 +19,17 @@ export const issueToDocumentStore = async ({ if (dryRun) { const documentStore = await DocumentStoreFactory.connect(address, wallet); await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await documentStore.estimateGas.issue(hash), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); const documentStore = await DocumentStoreFactory.connect(address, wallet); await documentStore.callStatic.issue(hash); - const transaction = await documentStore.issue(hash, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + const transaction = await documentStore.issue(hash); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/document-store/revoke.ts b/src/implementations/document-store/revoke.ts index c5e2aceb..72d1227a 100644 --- a/src/implementations/document-store/revoke.ts +++ b/src/implementations/document-store/revoke.ts @@ -11,7 +11,6 @@ export const revokeToDocumentStore = async ({ address, hash, network, - gasPriceScale, dryRun, ...rest }: DocumentStoreRevokeCommand): Promise<{ transactionHash: string }> => { @@ -19,19 +18,16 @@ export const revokeToDocumentStore = async ({ if (dryRun) { const documentStore = await DocumentStoreFactory.connect(address, wallet); await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await documentStore.estimateGas.revoke(hash), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); const documentStore = await DocumentStoreFactory.connect(address, wallet); await documentStore.callStatic.revoke(hash); - const transaction = await documentStore.revoke(hash, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + const transaction = await documentStore.revoke(hash); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/document-store/transfer-ownership.ts b/src/implementations/document-store/transfer-ownership.ts index dd49230c..a9200ef5 100644 --- a/src/implementations/document-store/transfer-ownership.ts +++ b/src/implementations/document-store/transfer-ownership.ts @@ -12,7 +12,6 @@ export const transferDocumentStoreOwnershipToWallet = async ({ address, newOwner, network, - gasPriceScale, dryRun, ...rest }: DocumentStoreTransferOwnershipCommand): Promise => { @@ -20,20 +19,16 @@ export const transferDocumentStoreOwnershipToWallet = async ({ if (dryRun) { const documentStore = await DocumentStoreFactory.connect(address, wallet); await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await documentStore.estimateGas.transferOwnership(newOwner), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); signale.await(`Sending transaction to pool`); const documentStore = await DocumentStoreFactory.connect(address, wallet); await documentStore.callStatic.transferOwnership(newOwner); - const transaction = await documentStore.transferOwnership(newOwner, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + const transaction = await documentStore.transferOwnership(newOwner); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index 2e2aa9a6..5cd472fd 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -13,7 +13,6 @@ export const acceptSurrendered = async ({ tokenRegistry: address, tokenId, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { @@ -21,16 +20,15 @@ export const acceptSurrendered = async ({ const tokenRegistryInstance = await TradeTrustERC721__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - await tokenRegistryInstance.callStatic.burn(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); - const transaction = await tokenRegistryInstance.burn(tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + await tokenRegistryInstance.callStatic.burn(tokenId); + const transaction = await tokenRegistryInstance.burn(tokenId); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts index 89cab792..df952f28 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts @@ -14,7 +14,6 @@ export const endorseNominatedBeneficiary = async ({ tokenId, newBeneficiary, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowNominateBeneficiaryCommand): Promise<{ @@ -27,20 +26,15 @@ export const endorseNominatedBeneficiary = async ({ await validateNominateBeneficiary({ beneficiaryNominee: nominatedBeneficiary, titleEscrow }); if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await titleEscrow.estimateGas.transferBeneficiary(nominatedBeneficiary), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - await titleEscrow.callStatic.transferBeneficiary(nominatedBeneficiary, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await titleEscrow.transferBeneficiary(nominatedBeneficiary, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + await titleEscrow.callStatic.transferBeneficiary(nominatedBeneficiary); + const transaction = await titleEscrow.transferBeneficiary(nominatedBeneficiary); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/nominateBeneficiary.ts b/src/implementations/title-escrow/nominateBeneficiary.ts index ab444c97..7bddd11b 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.ts @@ -14,7 +14,6 @@ export const nominateBeneficiary = async ({ tokenId, newBeneficiary, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowNominateBeneficiaryCommand): Promise => { @@ -23,21 +22,16 @@ export const nominateBeneficiary = async ({ if (dryRun) { await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await titleEscrow.estimateGas.nominate(newBeneficiary), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); - await titleEscrow.callStatic.nominate(newBeneficiary, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await titleEscrow.nominate(newBeneficiary, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + await titleEscrow.callStatic.nominate(newBeneficiary); + const transaction = await titleEscrow.nominate(newBeneficiary); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index 42287165..36338a33 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -12,7 +12,6 @@ export const rejectSurrendered = async ({ tokenRegistry: address, tokenId, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { @@ -20,7 +19,6 @@ export const rejectSurrendered = async ({ const tokenRegistryInstance: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), network, }); diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index 999b9cce..00d62a00 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -12,7 +12,6 @@ export const surrenderDocument = async ({ tokenRegistry: address, tokenId, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { @@ -21,16 +20,15 @@ export const surrenderDocument = async ({ if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await titleEscrow.estimateGas.surrender(), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - await titleEscrow.callStatic.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); - const transaction = await titleEscrow.surrender({ gasPrice: gasPrice.mul(gasPriceScale) }); + await titleEscrow.callStatic.surrender(); + const transaction = await titleEscrow.surrender(); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/transferHolder.ts b/src/implementations/title-escrow/transferHolder.ts index 880d6824..aaa21687 100644 --- a/src/implementations/title-escrow/transferHolder.ts +++ b/src/implementations/title-escrow/transferHolder.ts @@ -14,7 +14,6 @@ export const transferHolder = async ({ newHolder: to, tokenId, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowTransferHolderCommand): Promise => { @@ -22,16 +21,15 @@ export const transferHolder = async ({ const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await titleEscrow.estimateGas.transferHolder(to), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); await titleEscrow.callStatic.transferHolder(to); - const transaction = await titleEscrow.transferHolder(to, { gasPrice: gasPrice.mul(gasPriceScale) }); + const transaction = await titleEscrow.transferHolder(to); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/transferOwners.ts b/src/implementations/title-escrow/transferOwners.ts index 580a8a1d..2baf0393 100644 --- a/src/implementations/title-escrow/transferOwners.ts +++ b/src/implementations/title-escrow/transferOwners.ts @@ -15,7 +15,6 @@ export const transferOwners = async ({ newHolder, newOwner, network, - gasPriceScale, dryRun, ...rest }: TitleEscrowEndorseTransferOfOwnersCommand): Promise => { @@ -24,20 +23,15 @@ export const transferOwners = async ({ await validateEndorseChangeOwners({ newHolder, newOwner, titleEscrow }); if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await titleEscrow.estimateGas.transferOwners(newOwner, newHolder), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - await titleEscrow.callStatic.transferOwners(newOwner, newHolder, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await titleEscrow.transferOwners(newOwner, newHolder, { - gasPrice: gasPrice.mul(gasPriceScale), - }); + await titleEscrow.callStatic.transferOwners(newOwner, newHolder); + const transaction = await titleEscrow.transferOwners(newOwner, newHolder); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/token-registry/issue.ts b/src/implementations/token-registry/issue.ts index 467881a2..c729f5e8 100644 --- a/src/implementations/token-registry/issue.ts +++ b/src/implementations/token-registry/issue.ts @@ -14,7 +14,6 @@ export const issueToTokenRegistry = async ({ holder, tokenId, network, - gasPriceScale, dryRun, ...rest }: TokenRegistryIssueCommand): Promise => { @@ -23,18 +22,15 @@ export const issueToTokenRegistry = async ({ if (dryRun) { await dryRunMode({ - gasPriceScale: gasPriceScale, estimatedGas: await tokenRegistry.estimateGas.mint(beneficiary, holder, tokenId), network, }); process.exit(0); } - const gasPrice = await wallet.provider.getGasPrice(); + signale.await(`Sending transaction to pool`); - await tokenRegistry.callStatic.mint(beneficiary, holder, tokenId, { - gasPrice: gasPrice.mul(gasPriceScale), - }); - const transaction = await tokenRegistry.mint(beneficiary, holder, tokenId, { gasPrice: gasPrice.mul(gasPriceScale) }); + await tokenRegistry.callStatic.mint(beneficiary, holder, tokenId); + const transaction = await tokenRegistry.mint(beneficiary, holder, tokenId); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/utils/dryRun.ts b/src/implementations/utils/dryRun.ts index b367a24d..86f67717 100644 --- a/src/implementations/utils/dryRun.ts +++ b/src/implementations/utils/dryRun.ts @@ -1,116 +1,128 @@ -import { ethers, utils } from "ethers"; -import fetch from "node-fetch"; -import { green, highlight, red } from "../../utils"; import { BigNumber } from "ethers"; import { TransactionRequest } from "@ethersproject/providers"; +// export const dryRunMode = ("dryRun"); + export const dryRunMode = async ({ - gasPriceScale, transaction, estimatedGas, network, }: { - gasPriceScale: number; network: string; transaction?: TransactionRequest; estimatedGas?: BigNumber; }): Promise => { - // estimated gas or a transaction must be provided, if a transaction is provided let's estimate the gas automatically - // the transaction is run on the provided network - let _estimatedGas = estimatedGas; - if (!estimatedGas && transaction) { - const provider = ethers.getDefaultProvider(network); - _estimatedGas = await provider.estimateGas(transaction); - } - if (!_estimatedGas) { - throw new Error("Please provide estimatedGas or transaction"); - } + transaction; + estimatedGas; + network; +}; - // get gas price on mainnet - const { fast, fastest, safeLow, average } = await fetch("https://ethgasstation.info/api/ethgasAPI.json").then( - async (response) => { - if (response.ok) return response.json(); - else { - throw new Error(`Unable to get gas price - ${response.statusText}`); - } - } - ); - const gasPrice = await ethers.getDefaultProvider().getGasPrice(); - const gasPriceAsGwei = Number(utils.formatUnits(gasPrice, "gwei")); - // the return value will be used in BigNumber operations subsequently - // but BigNumbers can only have integer values, hence rounding off here - // https://github.com/ethers-io/ethers.js/issues/488 - const convertGasApiToGwei = (value: number): number => Math.round(value / 10); - const convertGasApiToWei = (value: number): BigNumber => utils.parseUnits(Math.round(value / 10).toString(), "gwei"); - const formatGwei = (value: BigNumber): string => utils.formatUnits(value, "gwei"); +// export const dryRunMode = async ({ +// transaction, +// estimatedGas, +// network, +// }: { +// gasPriceScale: number; +// network: string; +// transaction?: TransactionRequest; +// estimatedGas?: BigNumber; +// }): Promise => { +// // estimated gas or a transaction must be provided, if a transaction is provided let's estimate the gas automatically +// // the transaction is run on the provided network +// let _estimatedGas = estimatedGas; +// if (!estimatedGas && transaction) { +// const provider = ethers.getDefaultProvider(network); +// _estimatedGas = await provider.estimateGas(transaction); +// } +// if (!_estimatedGas) { +// throw new Error("Please provide estimatedGas or transaction"); +// } - console.log(red("\n\n/!\\ Welcome to the dry run mode. Please read the information below to understand the table")); - console.log( - `\nThe table below display information about the cost of the transaction on the mainnet network, depending on the gas price selected. Multiple modes are displayed to help you better help you to choose a gas price depending on your needs: -- ${highlight("current")} mode display information depending on the current information provided to the cli. -- ${highlight("fastest")} mode display information in order to run a transaction in less than 30s. -- ${highlight("fast")} mode display information in order to run a transaction in less than 2 mins. -- ${highlight("average")} mode display information in order to run a transaction in less than 5 mins. -- ${highlight("safe")} mode display information in order to run a transaction in less than 30 mins. - -For each mode the following information will be shown: -- ${highlight("gas price (gwei)")}: the gas price in gwei used for the transaction. -- ${highlight( - "tx price (gwei)" - )}: the price of the transaction in gwei. This is the amount payed for the transaction (outside of dry-run) -- ${highlight( - "tx price (eth)" - )}: the price of the transaction in ethereum. This is the amount payed for the transaction (outside of dry-run). You can directly use that amount to convert it to your currency using any currency converter supporting ethereum. -- ${highlight( - "gas price scale" - )}: this is an estimation of the value you must set for the '--gas-price-scale' parameter. Keep in mind that two successive runs will likely produce 2 different values as the gas price is fluctuating. +// // get gas price on mainnet +// const { fast, fastest, safeLow, average } = await fetch("https://ethgasstation.info/api/ethgasAPI.json").then( +// async (response) => { +// if (response.ok) return response.json(); +// else { +// throw new Error(`Unable to get gas price - ${response.statusText}`); +// } +// } +// ); +// const gasPrice = await ethers.getDefaultProvider().getGasPrice(); +// const gasPriceAsGwei = Number(utils.formatUnits(gasPrice, "gwei")); +// // the return value will be used in BigNumber operations subsequently +// // but BigNumbers can only have integer values, hence rounding off here +// // https://github.com/ethers-io/ethers.js/issues/488 +// const convertGasApiToGwei = (value: number): number => Math.round(value / 10); +// const convertGasApiToWei = (value: number): BigNumber => utils.parseUnits(Math.round(value / 10).toString(), "gwei"); +// const formatGwei = (value: BigNumber): string => utils.formatUnits(value, "gwei"); -Get more information about gas: https://ethereum.stackexchange.com/questions/3/what-is-meant-by-the-term-gas\n\n` - ); +// console.log(red("\n\n/!\\ Welcome to the dry run mode. Please read the information below to understand the table")); +// console.log( +// `\nThe table below display information about the cost of the transaction on the mainnet network, depending on the gas price selected. Multiple modes are displayed to help you better help you to choose a gas price depending on your needs: +// - ${highlight("current")} mode display information depending on the current information provided to the cli. +// - ${highlight("fastest")} mode display information in order to run a transaction in less than 30s. +// - ${highlight("fast")} mode display information in order to run a transaction in less than 2 mins. +// - ${highlight("average")} mode display information in order to run a transaction in less than 5 mins. +// - ${highlight("safe")} mode display information in order to run a transaction in less than 30 mins. - console.log(green("Information about the transaction:")); - console.log( - `Estimated gas required: ${highlight(_estimatedGas.toNumber())} gas, which will cost approximately ${highlight( - utils.formatEther(_estimatedGas.mul(gasPrice)) - )} eth based on the selected gas price` - ); - const scaledGasPrice = utils.parseUnits(Math.round(gasPriceAsGwei * gasPriceScale).toString(), "gwei"); - console.table({ - current: { - time: "N/A", - "gas price (gwei)": Number(formatGwei(scaledGasPrice)), - "tx price (gwei)": formatGwei(_estimatedGas.mul(scaledGasPrice)), - "tx price (eth)": utils.formatEther(_estimatedGas.mul(scaledGasPrice)), - "gas price scale": Number(gasPriceScale), - }, - fastest: { - time: "< 30 s", - "gas price (gwei)": convertGasApiToGwei(fastest), - "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fastest))), - "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fastest))), - "gas price scale": Number((convertGasApiToGwei(fastest) / gasPriceAsGwei).toFixed(2)), - }, - fast: { - time: "< 2 mins", - "gas price (gwei)": convertGasApiToGwei(fast), - "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fast))), - "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fast))), - "gas price scale": Number((convertGasApiToGwei(fast) / gasPriceAsGwei).toFixed(2)), - }, - average: { - time: "< 5 mins", - "gas price (gwei)": convertGasApiToGwei(average), - "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(average))), - "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(average))), - "gas price scale": Number((convertGasApiToGwei(average) / gasPriceAsGwei).toFixed(2)), - }, - safe: { - time: "< 30 mins", - "gas price (gwei)": convertGasApiToGwei(safeLow), - "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(safeLow))), - "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(safeLow))), - "gas price scale": Number((convertGasApiToGwei(safeLow) / gasPriceAsGwei).toFixed(2)), - }, - }); - console.log(red("Please read the information above to understand the table")); -}; +// For each mode the following information will be shown: +// - ${highlight("gas price (gwei)")}: the gas price in gwei used for the transaction. +// - ${highlight( +// "tx price (gwei)" +// )}: the price of the transaction in gwei. This is the amount payed for the transaction (outside of dry-run) +// - ${highlight( +// "tx price (eth)" +// )}: the price of the transaction in ethereum. This is the amount payed for the transaction (outside of dry-run). You can directly use that amount to convert it to your currency using any currency converter supporting ethereum. +// - ${highlight( +// "gas price scale" +// )}: this is an estimation of the value you must set for the '--gas-price-scale' parameter. Keep in mind that two successive runs will likely produce 2 different values as the gas price is fluctuating. + +// Get more information about gas: https://ethereum.stackexchange.com/questions/3/what-is-meant-by-the-term-gas\n\n` +// ); + +// console.log(green("Information about the transaction:")); +// console.log( +// `Estimated gas required: ${highlight(_estimatedGas.toNumber())} gas, which will cost approximately ${highlight( +// utils.formatEther(_estimatedGas.mul(gasPrice)) +// )} eth based on the selected gas price` +// ); +// const scaledGasPrice = utils.parseUnits(Math.round(gasPriceAsGwei * gasPriceScale).toString(), "gwei"); +// console.table({ +// current: { +// time: "N/A", +// "gas price (gwei)": Number(formatGwei(scaledGasPrice)), +// "tx price (gwei)": formatGwei(_estimatedGas.mul(scaledGasPrice)), +// "tx price (eth)": utils.formatEther(_estimatedGas.mul(scaledGasPrice)), +// "gas price scale": Number(gasPriceScale), +// }, +// fastest: { +// time: "< 30 s", +// "gas price (gwei)": convertGasApiToGwei(fastest), +// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fastest))), +// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fastest))), +// "gas price scale": Number((convertGasApiToGwei(fastest) / gasPriceAsGwei).toFixed(2)), +// }, +// fast: { +// time: "< 2 mins", +// "gas price (gwei)": convertGasApiToGwei(fast), +// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fast))), +// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fast))), +// "gas price scale": Number((convertGasApiToGwei(fast) / gasPriceAsGwei).toFixed(2)), +// }, +// average: { +// time: "< 5 mins", +// "gas price (gwei)": convertGasApiToGwei(average), +// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(average))), +// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(average))), +// "gas price scale": Number((convertGasApiToGwei(average) / gasPriceAsGwei).toFixed(2)), +// }, +// safe: { +// time: "< 30 mins", +// "gas price (gwei)": convertGasApiToGwei(safeLow), +// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(safeLow))), +// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(safeLow))), +// "gas price scale": Number((convertGasApiToGwei(safeLow) / gasPriceAsGwei).toFixed(2)), +// }, +// }); +// console.log(red("Please read the information above to understand the table")); +// }; From 6e09f0d091edf4c720327f507993361eba0241b4 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 29 Nov 2022 14:22:14 +0800 Subject: [PATCH 40/63] feat: upgrade to Token Registry 4.1.0 --- package-lock.json | 6 +- package.json | 2 +- sigh/config.json | 976 ------------------ .../token-registry/token-registry.test.ts | 4 +- .../title-escrow/acceptSurrendered.test.ts | 8 +- .../title-escrow/acceptSurrendered.ts | 4 +- .../endorseNominatedBeneficiary.test.ts | 8 +- src/implementations/title-escrow/helpers.ts | 6 +- .../title-escrow/nominateBeneficiary.test.ts | 8 +- .../title-escrow/rejectSurrendered.test.ts | 8 +- .../title-escrow/rejectSurrendered.ts | 4 +- .../title-escrow/surrenderDocument.test.ts | 8 +- .../title-escrow/transferHolder.test.ts | 8 +- .../title-escrow/transferOwners.test.ts | 8 +- .../token-registry/issue.test.ts | 8 +- src/implementations/token-registry/issue.ts | 4 +- 16 files changed, 47 insertions(+), 1023 deletions(-) delete mode 100644 sigh/config.json diff --git a/package-lock.json b/package-lock.json index be4aa22f..6ab2230b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2002,9 +2002,9 @@ } }, "@govtechsg/token-registry": { - "version": "4.0.0-beta.18", - "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.0.0-beta.18.tgz", - "integrity": "sha512-Wp2xxbjVaYiDV/ocGugl5GwGU9ouw0B5Vzce1mgjWqJX2clWnM+hU0RcDj9srww9GtS0vKX43dyymng16MZ7ww==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.1.0.tgz", + "integrity": "sha512-GuOM9aYIcOwInczKq9YVpM1q0R5tI1kT7Lz62r2u2IkDLjaDgSiEU9wR1oqTsY+sXINDKgm2qyDj/XMNwMt62g==", "requires": { "@typechain/ethers-v5": "~10.0.0" } diff --git a/package.json b/package.json index 4d0ad336..d2ab8ca4 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@govtechsg/oa-encryption": "^1.3.3", "@govtechsg/oa-verify": "^7.11.0", "@govtechsg/open-attestation": "^6.4.1", - "@govtechsg/token-registry": "^4.0.0-beta.18", + "@govtechsg/token-registry": "^4.1.0", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", diff --git a/sigh/config.json b/sigh/config.json deleted file mode 100644 index 33465cc4..00000000 --- a/sigh/config.json +++ /dev/null @@ -1,976 +0,0 @@ -{ - "network": "goerli", - "wallet": { - "type": "ENCRYPTED_JSON", - "encryptedJson": "{\"address\":\"8d366250a96debe81c8619459a503a0eebe33ca6\",\"id\":\"10a031af-eec2-4906-b6b6-d4b1b915826b\",\"version\":3,\"Crypto\":{\"cipher\":\"aes-128-ctr\",\"cipherparams\":{\"iv\":\"23bc1b677da293448c91247d76b478b0\"},\"ciphertext\":\"6452df0b66904299a55e3eca5f4910768a7e0f42319953db39c13a90c28888d5\",\"kdf\":\"scrypt\",\"kdfparams\":{\"salt\":\"f7472c0ef5d893361bc10bc2db620c60ca62ce1155f7e43424fcf6160b5e56f5\",\"n\":131072,\"dklen\":32,\"p\":1,\"r\":8},\"mac\":\"ea07a3637d224503fc24ac5e64e8a0d422489aaf0f8545c32853593a35076236\"},\"x-ethers\":{\"client\":\"ethers.js\",\"gethFilename\":\"UTC--2022-08-31T09-21-01.0Z--8d366250a96debe81c8619459a503a0eebe33ca6\",\"mnemonicCounter\":\"540049786649300ef011292ff5eefb3d\",\"mnemonicCiphertext\":\"b802c48b79ec162a0ad6675666b18a72\",\"path\":\"m/44'/60'/0'/0/0\",\"locale\":\"en\",\"version\":\"0.1\"}}" - }, - "documentStorage": { - "apiKey": "randomKey", - "url": "https://tradetrust-functions.netlify.app/.netlify/functions/storage" - }, - "forms": [ - { - "name": "TradeTrust Bill of Lading v3", - "type": "TRANSFERABLE_RECORD", - "defaults": { - "version": "https://schema.openattestation.com/3.0/schema.json", - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schemata.openattestation.com/com/openattestation/1.0/OpenAttestation.v3.json", - "https://schemata.openattestation.com/io/tradetrust/bill-of-lading/1.0/bill-of-lading-context.json" - ], - "type": [ - "VerifiableCredential", - "OpenAttestationCredential" - ], - "issuanceDate": "2010-01-01T19:23:24Z", - "openAttestationMetadata": { - "template": { - "type": "EMBEDDED_RENDERER", - "name": "BILL_OF_LADING", - "url": "https://generic-templates.tradetrust.io" - }, - "proof": { - "type": "OpenAttestationProofMethod", - "method": "TOKEN_REGISTRY", - "value": "0x9E1b69b5ceA6bD860b55dBE3adbF6CDEfcF5DDb1", - "revocation": { - "type": "NONE" - } - }, - "identityProof": { - "type": "DNS-TXT", - "identifier": "considerable-brown-spider.sandbox.fyntech.io" - } - }, - "credentialSubject": {}, - "issuer": { - "id": "https://example.com", - "name": "DEMO TOKEN REGISTRY", - "type": "OpenAttestationIssuer" - } - }, - "schema": { - "type": "object", - "additionalProperties": false, - "required": [ - "blNumber", - "scac" - ], - "properties": { - "blNumber": { - "type": "string", - "title": "BL Number" - }, - "scac": { - "type": "string", - "title": "Standard Carrier Alpha Code (SCAC)" - }, - "carrierName": { - "title": "Signed for the Carrier", - "type": "string" - }, - "shipper": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "address": { - "type": "object", - "properties": { - "street": { - "type": "string" - }, - "country": { - "type": "string" - } - } - } - } - }, - "consignee": { - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - }, - "notifyParty": { - "title": "Notify Party", - "type": "object", - "properties": { - "name": { - "type": "string" - } - } - }, - "vessel": { - "type": "string" - }, - "voyageNo": { - "title": "Voyage No.", - "type": "string" - }, - "portOfLoading": { - "title": "Port of Loading", - "type": "string" - }, - "portOfDischarge": { - "title": "Port of Discharge", - "type": "string" - }, - "placeOfReceipt": { - "title": "Place of Receipt", - "type": "string" - }, - "placeOfDelivery": { - "title": "Place of Delivery", - "type": "string" - }, - "packages": { - "type": "array", - "title": "Packages", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "measurement": { - "type": "string" - }, - "weight": { - "type": "string" - } - } - } - } - } - } - }, - { - "name": "TradeTrust ChAFTA Certificate of Origin v3", - "type": "VERIFIABLE_DOCUMENT", - "defaults": { - "version": "https://schema.openattestation.com/3.0/schema.json", - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schemata.openattestation.com/io/tradetrust/certificate-of-origin/1.0/certificate-of-origin-context.json", - "https://schemata.openattestation.com/com/openattestation/1.0/OpenAttestation.v3.json" - ], - "type": [ - "VerifiableCredential", - "OpenAttestationCredential" - ], - "issuanceDate": "2010-01-01T19:23:24Z", - "openAttestationMetadata": { - "template": { - "type": "EMBEDDED_RENDERER", - "name": "CHAFTA_COO", - "url": "https://generic-templates.tradetrust.io" - }, - "proof": { - "type": "OpenAttestationProofMethod", - "method": "DOCUMENT_STORE", - "value": "0xd85fD109c5C2D0b8De79F01aD5FBD8c4A7F7a598", - "revocation": { - "type": "NONE" - } - }, - "identityProof": { - "type": "DNS-TXT", - "identifier": "vast-yellow-fowl.sandbox.fyntech.io" - } - }, - "credentialSubject": {}, - "issuer": { - "id": "https://example.com", - "name": "DEMO DOCUMENT STORE", - "type": "OpenAttestationIssuer" - } - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "iD": { - "type": "string", - "title": "COO ID" - }, - "issueDateTime": { - "type": "string", - "title": "Issued Date & Time" - }, - "firstSignatoryAuthentication": { - "title": "Signatory Authentication", - "type": "object", - "properties": { - "signature": { - "type": "string", - "title": "First Signatory" - }, - "actualDateTime": { - "type": "string", - "title": "Actual Date Time" - } - } - }, - "supplyChainConsignment": { - "type": "object", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "information": { - "type": "string", - "title": "Consignment Information" - }, - "exportCountry": { - "title": "Export country", - "type": "object", - "properties": { - "code": { - "type": "string", - "title": "Country code" - } - } - }, - "exporter": { - "title": "Exporter", - "type": "object", - "properties": { - "iD": { - "title": "iD", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "postalAddress": { - "title": "", - "type": "object", - "properties": { - "line1": { - "type": "string", - "title": "Address Line 1" - }, - "line2": { - "type": "string", - "title": "Address Line 2" - }, - "cityName": { - "type": "string", - "title": "City" - }, - "postcode": { - "type": "string", - "title": "Postal code" - }, - "countrySubDivisionName": { - "type": "string", - "title": "Country Sub Division name" - }, - "countryCode": { - "type": "string", - "title": "Country code" - } - } - } - } - }, - "importCountry": { - "type": "object", - "title": "Import country", - "properties": { - "code": { - "type": "string", - "title": "Country code" - } - } - }, - "importer": { - "title": "Importer's Details (if known)", - "type": "object", - "properties": { - "iD": { - "title": "importer iD", - "type": "string" - }, - "name": { - "title": "Name", - "type": "string" - }, - "postalAddress": { - "title": "", - "type": "object", - "properties": { - "line1": { - "type": "string", - "title": "Address Line 1" - }, - "line2": { - "type": "string", - "title": "Address Line 2" - }, - "cityName": { - "type": "string", - "title": "City" - }, - "postcode": { - "type": "string", - "title": "Postal code" - }, - "countrySubDivisionName": { - "type": "string", - "title": "Country Sub Division name" - }, - "countryCode": { - "type": "string", - "title": "Country code" - } - } - } - } - }, - "includedConsignmentItems": { - "type": "array", - "title": "Included Consignment Items", - "items": { - "type": "object", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "information": { - "type": "string", - "title": "Information" - }, - "crossBorderRegulatoryProcedure": { - "type": "object", - "title": "", - "properties": { - "originCriteriaText": { - "type": "string", - "title": "Origin criteria text" - } - } - }, - "manufacturer": { - "type": "object", - "title": "Manufacturer", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "name": { - "type": "string", - "title": "Name" - }, - "postalAddress": { - "title": "", - "type": "object", - "properties": { - "line1": { - "type": "string", - "title": "Address Line 1" - }, - "line2": { - "type": "string", - "title": "Address Line 2" - }, - "cityName": { - "type": "string", - "title": "City" - }, - "postcode": { - "type": "string", - "title": "Postal code" - }, - "countrySubDivisionName": { - "type": "string", - "title": "Country Sub Division name" - }, - "countryCode": { - "type": "string", - "title": "Country code" - } - } - } - } - }, - "tradeLineItems": { - "type": "array", - "title": "Trade line Items", - "items": { - "type": "object", - "properties": { - "sequenceNumber": { - "type": "integer", - "title": "Sequence Number" - }, - "invoiceReference": { - "type": "object", - "title": "Invoice reference", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "formattedIssueDateTime": { - "type": "string", - "title": "Formatted issue date & time" - }, - "attachedBinaryFile": { - "type": "object", - "title": "", - "properties": { - "uRI": { - "type": "string", - "title": "Attached binary file uRI" - } - } - } - } - }, - "tradeProduct": { - "type": "object", - "title": "Trade product", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "description": { - "type": "string", - "title": "Description" - }, - "harmonisedTariffCode": { - "type": "object", - "title": "", - "properties": { - "classCode": { - "type": "string", - "title": "Harmonised tariff class code" - }, - "className": { - "type": "string", - "title": "Harmonised tariff class name" - } - } - }, - "originCountry": { - "type": "object", - "title": "Origin country", - "properties": { - "code": { - "type": "string", - "title": "Code" - } - } - } - } - }, - "transportPackages": { - "type": "array", - "title": "Transport packages", - "items": { - "type": "object", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "grossVolume": { - "type": "string", - "title": "Gross volume" - }, - "grossWeight": { - "type": "string", - "title": "Gross weight" - } - } - } - } - } - } - } - } - } - }, - "loadingBaseportLocation": { - "type": "object", - "title": "Loading Baseport Location", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "name": { - "type": "string", - "title": "Name" - } - } - }, - "mainCarriageTransportMovement": { - "title": "Main Carraige Transport Movement", - "type": "object", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "information": { - "type": "string", - "title": "Information" - }, - "usedTransportMeans": { - "title": "", - "type": "object", - "properties": { - "name": { - "type": "string", - "title": "Used transport" - }, - "iD": { - "type": "string", - "title": "Used transport iD" - } - } - }, - "departureEvent": { - "title": "", - "type": "object", - "properties": { - "departureDateTime": { - "type": "string", - "title": "Departure date and time" - } - } - } - } - }, - "unloadingBaseportLocation": { - "type": "object", - "title": "Unloading Baseport Location", - "properties": { - "iD": { - "type": "string", - "title": "iD" - }, - "name": { - "type": "string", - "title": "Name" - } - } - } - } - } - } - }, - "uiSchema": { - "firstSignatoryAuthentication": { - "signature": { - "ui:widget": "file", - "ui:options": { - "text": "Upload Signature", - "accept": ".png, .jpeg, .jpg" - } - }, - "actualDateTime": { - "ui:widget": "datetime" - } - }, - "issueDateTime": { - "ui:widget": "datetime" - }, - "supplyChainConsignment": { - "includedConsignmentItems": { - "items": { - "tradeLineItems": { - "items": { - "invoiceReference": { - "formattedIssueDateTime": { - "ui:widget": "datetime" - } - } - } - } - } - }, - "mainCarriageTransportMovement": { - "departureEvent": { - "departureDateTime": { - "ui:widget": "datetime" - } - } - } - } - }, - "attachments": { - "allow": true, - "accept": ".pdf" - }, - "extension": "tt" - }, - { - "name": "TradeTrust Invoice v3 (DNS-DID)", - "type": "VERIFIABLE_DOCUMENT", - "defaults": { - "version": "https://schema.openattestation.com/3.0/schema.json", - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schemata.openattestation.com/io/tradetrust/Invoice/1.0/invoice-context.json", - "https://schemata.openattestation.com/com/openattestation/1.0/OpenAttestation.v3.json" - ], - "type": [ - "VerifiableCredential", - "OpenAttestationCredential" - ], - "issuanceDate": "2010-01-01T19:23:24Z", - "openAttestationMetadata": { - "template": { - "type": "EMBEDDED_RENDERER", - "name": "INVOICE", - "url": "https://generic-templates.tradetrust.io" - }, - "proof": { - "type": "OpenAttestationProofMethod", - "method": "DID", - "value": "did:ethr:0x8d366250a96debe81c8619459a503a0eebe33ca6", - "revocation": { - "type": "NONE" - } - }, - "identityProof": { - "type": "DNS-DID", - "identifier": "sensible-silver-loon.sandbox.fyntech.io" - } - }, - "credentialSubject": {}, - "issuer": { - "id": "https://example.com", - "name": "DEMO DNS-DID", - "type": "OpenAttestationIssuer" - } - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "title": "Invoice ID" - }, - "date": { - "type": "string", - "title": "Date" - }, - "customerId": { - "type": "string", - "title": "Customer ID" - }, - "terms": { - "type": "string", - "title": "Terms" - }, - "billFrom": { - "type": "object", - "title": "Bill From", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "streetAddress": { - "type": "string", - "title": "Street Address" - }, - "city": { - "type": "string", - "title": "City" - }, - "postalCode": { - "type": "string", - "title": "Postal Code" - }, - "phoneNumber": { - "type": "string", - "title": "Phone Number" - } - } - }, - "billTo": { - "type": "object", - "title": "Bill To", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "email": { - "type": "string", - "title": "Email" - }, - "company": { - "type": "object", - "title": "Bill To Company", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "streetAddress": { - "type": "string", - "title": "Street Address" - }, - "city": { - "type": "string", - "title": "City" - }, - "postalCode": { - "type": "string", - "title": "Postal Code" - }, - "phoneNumber": { - "type": "string", - "title": "Phone Number" - } - } - } - } - }, - "billableItems": { - "type": "array", - "title": "Billable Items", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string", - "title": "Description" - }, - "quantity": { - "type": "string", - "title": "Quantity" - }, - "unitPrice": { - "type": "string", - "title": "Unit Price" - }, - "amount": { - "type": "string", - "title": "Amount" - } - } - } - }, - "subtotal": { - "type": "string", - "title": "Subtotal" - }, - "tax": { - "type": "string", - "title": "Tax (%)" - }, - "taxTotal": { - "type": "string", - "title": "Tax Total" - }, - "total": { - "type": "string", - "title": "Total" - } - } - }, - "uiSchema": { - "date": { - "ui:widget": "date" - } - }, - "extension": "tt" - }, - { - "name": "TradeTrust Invoice v3", - "type": "VERIFIABLE_DOCUMENT", - "defaults": { - "version": "https://schema.openattestation.com/3.0/schema.json", - "@context": [ - "https://www.w3.org/2018/credentials/v1", - "https://schemata.openattestation.com/io/tradetrust/Invoice/1.0/invoice-context.json", - "https://schemata.openattestation.com/com/openattestation/1.0/OpenAttestation.v3.json" - ], - "type": [ - "VerifiableCredential", - "OpenAttestationCredential" - ], - "issuanceDate": "2010-01-01T19:23:24Z", - "openAttestationMetadata": { - "template": { - "type": "EMBEDDED_RENDERER", - "name": "INVOICE", - "url": "https://generic-templates.tradetrust.io" - }, - "proof": { - "type": "OpenAttestationProofMethod", - "method": "DOCUMENT_STORE", - "value": "0xd85fD109c5C2D0b8De79F01aD5FBD8c4A7F7a598", - "revocation": { - "type": "NONE" - } - }, - "identityProof": { - "type": "DNS-TXT", - "identifier": "vast-yellow-fowl.sandbox.fyntech.io" - } - }, - "credentialSubject": {}, - "issuer": { - "id": "https://example.com", - "name": "DEMO DOCUMENT STORE", - "type": "OpenAttestationIssuer" - } - }, - "schema": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "title": "Invoice ID" - }, - "date": { - "type": "string", - "title": "Date" - }, - "customerId": { - "type": "string", - "title": "Customer ID" - }, - "terms": { - "type": "string", - "title": "Terms" - }, - "billFrom": { - "type": "object", - "title": "Bill From", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "streetAddress": { - "type": "string", - "title": "Street Address" - }, - "city": { - "type": "string", - "title": "City" - }, - "postalCode": { - "type": "string", - "title": "Postal Code" - }, - "phoneNumber": { - "type": "string", - "title": "Phone Number" - } - } - }, - "billTo": { - "type": "object", - "title": "Bill To", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "email": { - "type": "string", - "title": "Email" - }, - "company": { - "type": "object", - "title": "Bill To Company", - "properties": { - "name": { - "type": "string", - "title": "Name" - }, - "streetAddress": { - "type": "string", - "title": "Street Address" - }, - "city": { - "type": "string", - "title": "City" - }, - "postalCode": { - "type": "string", - "title": "Postal Code" - }, - "phoneNumber": { - "type": "string", - "title": "Phone Number" - } - } - } - } - }, - "billableItems": { - "type": "array", - "title": "Billable Items", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string", - "title": "Description" - }, - "quantity": { - "type": "string", - "title": "Quantity" - }, - "unitPrice": { - "type": "string", - "title": "Unit Price" - }, - "amount": { - "type": "string", - "title": "Amount" - } - } - } - }, - "subtotal": { - "type": "string", - "title": "Subtotal" - }, - "tax": { - "type": "string", - "title": "Tax (%)" - }, - "taxTotal": { - "type": "string", - "title": "Tax Total" - }, - "total": { - "type": "string", - "title": "Total" - } - } - }, - "uiSchema": { - "date": { - "ui:widget": "date" - } - }, - "extension": "tt" - } - ] -} \ No newline at end of file diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index 1f9c441a..d522d100 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -41,7 +41,7 @@ describe("token-registry", () => { data: "0x000000000000000000000000878a327daa390bc602ae259d3a374610356b6485000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", args: [ "0xd6C249d0756059E21Ef4Aef4711B69b76927BEA7", - "0xE5C75026d5f636C89cc77583B6BCe7C99F512763", + "0xC78BA1a49663Ef8b920F36B036E91Ab40D8F26D6", "0x8d366250A96deBE81C8619459a503a0eEBE33ca6", "0x878A327daA390Bc602Ae259D3A374610356b6485", "0x000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000008d366250a96debe81c8619459a503a0eebe33ca60000000000000000000000000000000000000000000000000000000000000011563420546f6b656e20526567697374727900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000034d54540000000000000000000000000000000000000000000000000000000000", @@ -61,7 +61,7 @@ describe("token-registry", () => { deployer: "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf", }); - expect(mockedDeploy.mock.calls[0][0]).toEqual("0xE5C75026d5f636C89cc77583B6BCe7C99F512763"); + expect(mockedDeploy.mock.calls[0][0]).toEqual("0xC78BA1a49663Ef8b920F36B036E91Ab40D8F26D6"); expect(mockedDeploy.mock.calls[0][1]).toEqual(expectedInitParams); // price should be any length string of digits diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 2b6c9799..916fd710 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -1,4 +1,4 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -16,16 +16,16 @@ const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { describe("title-escrow", () => { describe("accepts surrendered transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockBurnToken = jest.fn(); const mockCallStaticBurnToken = jest.fn().mockResolvedValue(undefined); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); + mockedTradeTrustTokenFactory.mockReset(); mockedConnectERC721.mockReset(); mockBurnToken.mockReturnValue({ diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index 5cd472fd..010805f8 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -5,7 +5,7 @@ import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from ". import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/dist/contracts"; +import { TradeTrustToken__factory } from "@govtechsg/token-registry/dist/contracts"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -17,7 +17,7 @@ export const acceptSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance = await TradeTrustERC721__factory.connect(address, wallet); + const tokenRegistryInstance = await TradeTrustToken__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index 6d2d10e4..fdf6e341 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -17,10 +17,10 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = describe("title-escrow", () => { describe("endorse transfer of owner of transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -55,7 +55,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockClear(); + mockedTradeTrustTokenFactory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index e4f58623..41593019 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -1,8 +1,8 @@ import { TitleEscrow, TitleEscrow__factory, - TradeTrustERC721, - TradeTrustERC721__factory, + TradeTrustToken, + TradeTrustToken__factory, } from "@govtechsg/token-registry/contracts"; import { Wallet, constants } from "ethers"; import signale from "signale"; @@ -19,7 +19,7 @@ export const connectToTitleEscrow = async ({ address, wallet, }: ConnectToTitleEscrowArgs): Promise => { - const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId); return await TitleEscrow__factory.connect(titleEscrowAddress, wallet); }; diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index d7c945ca..8f0d3075 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -17,10 +17,10 @@ const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { describe("title-escrow", () => { describe("nominate change of owner of transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -54,7 +54,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockClear(); + mockedTradeTrustTokenFactory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index f02eeaa6..691d26ab 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -16,10 +16,10 @@ const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { describe("title-escrow", () => { describe("rejects surrendered transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -38,7 +38,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); + mockedTradeTrustTokenFactory.mockReset(); mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index 36338a33..098fb0ef 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -1,4 +1,4 @@ -import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; @@ -16,7 +16,7 @@ export const rejectSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 1edd8220..91618d3d 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -16,10 +16,10 @@ const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { describe("title-escrow", () => { describe("surrender transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -31,7 +31,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockReset(); + mockedTradeTrustTokenFactory.mockReset(); mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); diff --git a/src/implementations/title-escrow/transferHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts index 0883ad4b..d6ed40e9 100644 --- a/src/implementations/title-escrow/transferHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -17,10 +17,10 @@ const transferHolderParams: TitleEscrowTransferHolderCommand = { describe("title-escrow", () => { describe("change holder of transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -47,7 +47,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockClear(); + mockedTradeTrustTokenFactory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index f7f111e4..7bc5246c 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -1,4 +1,4 @@ -import { TitleEscrow__factory, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; @@ -18,10 +18,10 @@ const endorseChangeOwnersParams: TitleEscrowEndorseTransferOfOwnersCommand = { describe("title-escrow", () => { describe("endorse change of owners of transferable record", () => { - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method @@ -56,7 +56,7 @@ describe("title-escrow", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockClear(); + mockedTradeTrustTokenFactory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index e505930c..bfde6b2e 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -1,4 +1,4 @@ -import { TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; @@ -20,10 +20,10 @@ const deployParams: TokenRegistryIssueCommand = { describe("token-registry", () => { describe("issue", () => { jest.setTimeout(30000); - const mockedTradeTrustERC721Factory: jest.Mock = TradeTrustERC721__factory as any; + const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectERC721: jest.Mock = mockedTradeTrustERC721Factory.connect; + const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; const mockedIssue = jest.fn(); const mockCallStaticSafeMint = jest.fn().mockResolvedValue(undefined); @@ -41,7 +41,7 @@ describe("token-registry", () => { beforeEach(() => { delete process.env.OA_PRIVATE_KEY; - mockedTradeTrustERC721Factory.mockClear(); + mockedTradeTrustTokenFactory.mockClear(); mockCallStaticSafeMint.mockClear(); mockedConnectERC721.mockReset(); mockedConnectERC721.mockResolvedValue(mockTTERC721Contract); diff --git a/src/implementations/token-registry/issue.ts b/src/implementations/token-registry/issue.ts index c729f5e8..1b845468 100644 --- a/src/implementations/token-registry/issue.ts +++ b/src/implementations/token-registry/issue.ts @@ -1,4 +1,4 @@ -import { TradeTrustERC721, TradeTrustERC721__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; @@ -18,7 +18,7 @@ export const issueToTokenRegistry = async ({ ...rest }: TokenRegistryIssueCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistry: TradeTrustERC721 = await TradeTrustERC721__factory.connect(address, wallet); + const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); if (dryRun) { await dryRunMode({ From 067448764e16f757ad094455d23bd96946faff3f Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:05:48 +0800 Subject: [PATCH 41/63] chore: remove gas-price-scale --- src/commands/shared.ts | 19 +- .../deploy/document-store/document-store.ts | 2 - src/implementations/utils/dryRun.ts | 208 ++++++++---------- 3 files changed, 101 insertions(+), 128 deletions(-) diff --git a/src/commands/shared.ts b/src/commands/shared.ts index f464e28f..83e04c19 100644 --- a/src/commands/shared.ts +++ b/src/commands/shared.ts @@ -58,19 +58,12 @@ export const withNetworkOption = (yargs: Argv): Argv => description: "Ethereum network to deploy to", }); export const withGasPriceOption = (yargs: Argv): Argv => - yargs - .option("gas-price-scale", { - alias: "gps", - type: "number", - default: 1, - description: "Gas price scale to apply to the estimated gas price", - }) - .option("dry-run", { - alias: "dr", - type: "boolean", - default: false, - description: "Dry run", - }); + yargs.option("dry-run", { + alias: "dr", + type: "boolean", + default: false, + description: "Dry run", + }); export const withPrivateKeyOption = (yargs: Argv): Argv => yargs diff --git a/src/implementations/deploy/document-store/document-store.ts b/src/implementations/deploy/document-store/document-store.ts index d4cb474c..079d6006 100644 --- a/src/implementations/deploy/document-store/document-store.ts +++ b/src/implementations/deploy/document-store/document-store.ts @@ -9,13 +9,11 @@ const { trace } = getLogger("deploy:document-store"); export const deployDocumentStore = async ({ storeName, - owner, network, dryRun, ...rest }: DeployDocumentStoreCommand): Promise<{ contractAddress: string }> => { const wallet = await getWalletOrSigner({ network, ...rest }); - const ownerAddress = owner ?? (await wallet.getAddress()); if (dryRun) { await dryRunMode({ transaction: new DocumentStoreFactory().getDeployTransaction(storeName), diff --git a/src/implementations/utils/dryRun.ts b/src/implementations/utils/dryRun.ts index 86f67717..ee342fa7 100644 --- a/src/implementations/utils/dryRun.ts +++ b/src/implementations/utils/dryRun.ts @@ -1,8 +1,9 @@ +import { ethers, utils } from "ethers"; +import fetch from "node-fetch"; +import { green, highlight, red } from "../../utils"; import { BigNumber } from "ethers"; import { TransactionRequest } from "@ethersproject/providers"; -// export const dryRunMode = ("dryRun"); - export const dryRunMode = async ({ transaction, estimatedGas, @@ -12,117 +13,98 @@ export const dryRunMode = async ({ transaction?: TransactionRequest; estimatedGas?: BigNumber; }): Promise => { - transaction; - estimatedGas; - network; -}; - -// export const dryRunMode = async ({ -// transaction, -// estimatedGas, -// network, -// }: { -// gasPriceScale: number; -// network: string; -// transaction?: TransactionRequest; -// estimatedGas?: BigNumber; -// }): Promise => { -// // estimated gas or a transaction must be provided, if a transaction is provided let's estimate the gas automatically -// // the transaction is run on the provided network -// let _estimatedGas = estimatedGas; -// if (!estimatedGas && transaction) { -// const provider = ethers.getDefaultProvider(network); -// _estimatedGas = await provider.estimateGas(transaction); -// } -// if (!_estimatedGas) { -// throw new Error("Please provide estimatedGas or transaction"); -// } + // estimated gas or a transaction must be provided, if a transaction is provided let's estimate the gas automatically + // the transaction is run on the provided network + let _estimatedGas = estimatedGas; + if (!estimatedGas && transaction) { + const provider = ethers.getDefaultProvider(network); + _estimatedGas = await provider.estimateGas(transaction); + } + if (!_estimatedGas) { + throw new Error("Please provide estimatedGas or transaction"); + } -// // get gas price on mainnet -// const { fast, fastest, safeLow, average } = await fetch("https://ethgasstation.info/api/ethgasAPI.json").then( -// async (response) => { -// if (response.ok) return response.json(); -// else { -// throw new Error(`Unable to get gas price - ${response.statusText}`); -// } -// } -// ); -// const gasPrice = await ethers.getDefaultProvider().getGasPrice(); -// const gasPriceAsGwei = Number(utils.formatUnits(gasPrice, "gwei")); -// // the return value will be used in BigNumber operations subsequently -// // but BigNumbers can only have integer values, hence rounding off here -// // https://github.com/ethers-io/ethers.js/issues/488 -// const convertGasApiToGwei = (value: number): number => Math.round(value / 10); -// const convertGasApiToWei = (value: number): BigNumber => utils.parseUnits(Math.round(value / 10).toString(), "gwei"); -// const formatGwei = (value: BigNumber): string => utils.formatUnits(value, "gwei"); + // get gas price on mainnet + const { fast, fastest, safeLow, average } = await fetch("https://ethgasstation.info/api/ethgasAPI.json").then( + async (response) => { + if (response.ok) return response.json(); + else { + throw new Error(`Unable to get gas price - ${response.statusText}`); + } + } + ); + const gasPrice = await ethers.getDefaultProvider().getGasPrice(); + const gasPriceAsGwei = Number(utils.formatUnits(gasPrice, "gwei")); + // the return value will be used in BigNumber operations subsequently + // but BigNumbers can only have integer values, hence rounding off here + // https://github.com/ethers-io/ethers.js/issues/488 + const convertGasApiToGwei = (value: number): number => Math.round(value / 10); + const convertGasApiToWei = (value: number): BigNumber => utils.parseUnits(Math.round(value / 10).toString(), "gwei"); + const formatGwei = (value: BigNumber): string => utils.formatUnits(value, "gwei"); -// console.log(red("\n\n/!\\ Welcome to the dry run mode. Please read the information below to understand the table")); -// console.log( -// `\nThe table below display information about the cost of the transaction on the mainnet network, depending on the gas price selected. Multiple modes are displayed to help you better help you to choose a gas price depending on your needs: -// - ${highlight("current")} mode display information depending on the current information provided to the cli. -// - ${highlight("fastest")} mode display information in order to run a transaction in less than 30s. -// - ${highlight("fast")} mode display information in order to run a transaction in less than 2 mins. -// - ${highlight("average")} mode display information in order to run a transaction in less than 5 mins. -// - ${highlight("safe")} mode display information in order to run a transaction in less than 30 mins. + console.log(red("\n\n/!\\ Welcome to the dry run mode. Please read the information below to understand the table")); + console.log( + `\nThe table below display information about the cost of the transaction on the mainnet network, depending on the gas price selected. Multiple modes are displayed to help you better help you to choose a gas price depending on your needs: +- ${highlight("current")} mode display information depending on the current information provided to the cli. +- ${highlight("fastest")} mode display information in order to run a transaction in less than 30s. +- ${highlight("fast")} mode display information in order to run a transaction in less than 2 mins. +- ${highlight("average")} mode display information in order to run a transaction in less than 5 mins. +- ${highlight("safe")} mode display information in order to run a transaction in less than 30 mins. + +For each mode the following information will be shown: +- ${highlight("gas price (gwei)")}: the gas price in gwei used for the transaction. +- ${highlight( + "tx price (gwei)" + )}: the price of the transaction in gwei. This is the amount payed for the transaction (outside of dry-run) +- ${highlight( + "tx price (eth)" + )}: the price of the transaction in ethereum. This is the amount payed for the transaction (outside of dry-run). You can directly use that amount to convert it to your currency using any currency converter supporting ethereum. + +Get more information about gas: https://ethereum.stackexchange.com/questions/3/what-is-meant-by-the-term-gas\n\n` + ); -// For each mode the following information will be shown: -// - ${highlight("gas price (gwei)")}: the gas price in gwei used for the transaction. -// - ${highlight( -// "tx price (gwei)" -// )}: the price of the transaction in gwei. This is the amount payed for the transaction (outside of dry-run) -// - ${highlight( -// "tx price (eth)" -// )}: the price of the transaction in ethereum. This is the amount payed for the transaction (outside of dry-run). You can directly use that amount to convert it to your currency using any currency converter supporting ethereum. -// - ${highlight( -// "gas price scale" -// )}: this is an estimation of the value you must set for the '--gas-price-scale' parameter. Keep in mind that two successive runs will likely produce 2 different values as the gas price is fluctuating. - -// Get more information about gas: https://ethereum.stackexchange.com/questions/3/what-is-meant-by-the-term-gas\n\n` -// ); - -// console.log(green("Information about the transaction:")); -// console.log( -// `Estimated gas required: ${highlight(_estimatedGas.toNumber())} gas, which will cost approximately ${highlight( -// utils.formatEther(_estimatedGas.mul(gasPrice)) -// )} eth based on the selected gas price` -// ); -// const scaledGasPrice = utils.parseUnits(Math.round(gasPriceAsGwei * gasPriceScale).toString(), "gwei"); -// console.table({ -// current: { -// time: "N/A", -// "gas price (gwei)": Number(formatGwei(scaledGasPrice)), -// "tx price (gwei)": formatGwei(_estimatedGas.mul(scaledGasPrice)), -// "tx price (eth)": utils.formatEther(_estimatedGas.mul(scaledGasPrice)), -// "gas price scale": Number(gasPriceScale), -// }, -// fastest: { -// time: "< 30 s", -// "gas price (gwei)": convertGasApiToGwei(fastest), -// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fastest))), -// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fastest))), -// "gas price scale": Number((convertGasApiToGwei(fastest) / gasPriceAsGwei).toFixed(2)), -// }, -// fast: { -// time: "< 2 mins", -// "gas price (gwei)": convertGasApiToGwei(fast), -// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fast))), -// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fast))), -// "gas price scale": Number((convertGasApiToGwei(fast) / gasPriceAsGwei).toFixed(2)), -// }, -// average: { -// time: "< 5 mins", -// "gas price (gwei)": convertGasApiToGwei(average), -// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(average))), -// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(average))), -// "gas price scale": Number((convertGasApiToGwei(average) / gasPriceAsGwei).toFixed(2)), -// }, -// safe: { -// time: "< 30 mins", -// "gas price (gwei)": convertGasApiToGwei(safeLow), -// "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(safeLow))), -// "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(safeLow))), -// "gas price scale": Number((convertGasApiToGwei(safeLow) / gasPriceAsGwei).toFixed(2)), -// }, -// }); -// console.log(red("Please read the information above to understand the table")); -// }; + console.log(green("Information about the transaction:")); + console.log( + `Estimated gas required: ${highlight(_estimatedGas.toNumber())} gas, which will cost approximately ${highlight( + utils.formatEther(_estimatedGas.mul(gasPrice)) + )} eth based on the selected gas price` + ); + const scaledGasPrice = utils.parseUnits(Math.round(gasPriceAsGwei).toString(), "gwei"); + console.table({ + current: { + time: "N/A", + "gas price (gwei)": Number(formatGwei(scaledGasPrice)), + "tx price (gwei)": formatGwei(_estimatedGas.mul(scaledGasPrice)), + "tx price (eth)": utils.formatEther(_estimatedGas.mul(scaledGasPrice)), + }, + fastest: { + time: "< 30 s", + "gas price (gwei)": convertGasApiToGwei(fastest), + "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fastest))), + "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fastest))), + "gas price scale": Number((convertGasApiToGwei(fastest) / gasPriceAsGwei).toFixed(2)), + }, + fast: { + time: "< 2 mins", + "gas price (gwei)": convertGasApiToGwei(fast), + "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(fast))), + "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(fast))), + "gas price scale": Number((convertGasApiToGwei(fast) / gasPriceAsGwei).toFixed(2)), + }, + average: { + time: "< 5 mins", + "gas price (gwei)": convertGasApiToGwei(average), + "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(average))), + "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(average))), + "gas price scale": Number((convertGasApiToGwei(average) / gasPriceAsGwei).toFixed(2)), + }, + safe: { + time: "< 30 mins", + "gas price (gwei)": convertGasApiToGwei(safeLow), + "tx price (gwei)": formatGwei(_estimatedGas.mul(convertGasApiToWei(safeLow))), + "tx price (eth)": utils.formatEther(_estimatedGas.mul(convertGasApiToWei(safeLow))), + "gas price scale": Number((convertGasApiToGwei(safeLow) / gasPriceAsGwei).toFixed(2)), + }, + }); + console.log(red("Please read the information above to understand the table")); +}; From 0bf6c9916700caebdef400e866d1c500872c20c0 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 30 Nov 2022 17:40:36 +0800 Subject: [PATCH 42/63] chore: remove gps from tests --- src/commands/shared.ts | 1 - src/implementations/config/helpers.ts | 2 -- .../deploy/document-store/document-store.test.ts | 5 ----- src/implementations/deploy/document-store/document-store.ts | 6 ++++-- .../deploy/token-registry/token-registry.test.ts | 2 -- src/implementations/document-store/issue.test.ts | 2 -- src/implementations/document-store/revoke.test.ts | 1 - .../document-store/transfer-ownership.test.ts | 1 - src/implementations/title-escrow/acceptSurrendered.test.ts | 1 - .../title-escrow/endorseNominatedBeneficiary.test.ts | 1 - .../title-escrow/nominateBeneficiary.test.ts | 1 - src/implementations/title-escrow/rejectSurrendered.test.ts | 1 - src/implementations/title-escrow/surrenderDocument.test.ts | 1 - src/implementations/title-escrow/transferHolder.test.ts | 1 - src/implementations/title-escrow/transferOwners.test.ts | 1 - src/implementations/token-registry/issue.test.ts | 1 - 16 files changed, 4 insertions(+), 24 deletions(-) diff --git a/src/commands/shared.ts b/src/commands/shared.ts index 83e04c19..650c1bee 100644 --- a/src/commands/shared.ts +++ b/src/commands/shared.ts @@ -44,7 +44,6 @@ export const isWalletOption = (option: any): option is WalletOption => { export type WalletOrSignerOption = Partial | Partial | Partial; export interface GasOption { - gasPriceScale: number; dryRun: boolean; } diff --git a/src/implementations/config/helpers.ts b/src/implementations/config/helpers.ts index f21cf31a..9c68fb73 100644 --- a/src/implementations/config/helpers.ts +++ b/src/implementations/config/helpers.ts @@ -90,7 +90,6 @@ export const getTokenRegistryAddress = async (encryptedWalletPath: string): Prom const tokenRegistry = await deployTokenRegistry({ encryptedWalletPath, network: "goerli", - gasPriceScale: 1, dryRun: false, registryName: "Token Registry", registrySymbol: "TR", @@ -105,7 +104,6 @@ export const getDocumentStoreAddress = async (encryptedWalletPath: string): Prom const documentStore = await deployDocumentStore({ encryptedWalletPath, network: "goerli", - gasPriceScale: 1, dryRun: false, storeName: "Document Store", }); diff --git a/src/implementations/deploy/document-store/document-store.test.ts b/src/implementations/deploy/document-store/document-store.test.ts index 698e8e47..79a51cff 100644 --- a/src/implementations/deploy/document-store/document-store.test.ts +++ b/src/implementations/deploy/document-store/document-store.test.ts @@ -11,7 +11,6 @@ const deployParams: DeployDocumentStoreCommand = { owner: "0x1234", network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, dryRun: false, }; @@ -38,7 +37,6 @@ describe("document-store", () => { await deployDocumentStore({ storeName: "Test", network: "goerli", - gasPriceScale: 1, dryRun: false, }); @@ -51,7 +49,6 @@ describe("document-store", () => { storeName: "Test", network: "goerli", keyFile: join(__dirname, "..", "..", "..", "..", "examples", "sample-key"), - gasPriceScale: 1, dryRun: false, }); @@ -81,7 +78,6 @@ describe("document-store", () => { deployDocumentStore({ storeName: "Test", network: "goerli", - gasPriceScale: 1, dryRun: false, }) ).rejects.toThrow( @@ -95,7 +91,6 @@ describe("document-store", () => { await deployDocumentStore({ storeName: "Test", network: "goerli", - gasPriceScale: 1, dryRun: false, }); diff --git a/src/implementations/deploy/document-store/document-store.ts b/src/implementations/deploy/document-store/document-store.ts index 079d6006..1a10c6d2 100644 --- a/src/implementations/deploy/document-store/document-store.ts +++ b/src/implementations/deploy/document-store/document-store.ts @@ -9,21 +9,23 @@ const { trace } = getLogger("deploy:document-store"); export const deployDocumentStore = async ({ storeName, + owner, network, dryRun, ...rest }: DeployDocumentStoreCommand): Promise<{ contractAddress: string }> => { const wallet = await getWalletOrSigner({ network, ...rest }); + const ownerAddress = owner ?? (await wallet.getAddress()); if (dryRun) { await dryRunMode({ - transaction: new DocumentStoreFactory().getDeployTransaction(storeName), + transaction: new DocumentStoreFactory().getDeployTransaction(storeName, ownerAddress), network, }); process.exit(0); } const factory = new DocumentStoreFactory(wallet); signale.await(`Sending transaction to pool`); - const transaction = await factory.deploy(storeName); + const transaction = await factory.deploy(storeName, ownerAddress); trace(`Tx hash: ${transaction.deployTransaction.hash}`); trace(`Block Number: ${transaction.deployTransaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.deployTransaction.hash} to be mined`); diff --git a/src/implementations/deploy/token-registry/token-registry.test.ts b/src/implementations/deploy/token-registry/token-registry.test.ts index d522d100..290558d7 100644 --- a/src/implementations/deploy/token-registry/token-registry.test.ts +++ b/src/implementations/deploy/token-registry/token-registry.test.ts @@ -9,7 +9,6 @@ const deployParams: DeployTokenRegistryCommand = { registrySymbol: "Tst", network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, dryRun: false, }; @@ -80,7 +79,6 @@ describe("token-registry", () => { registryName: "Test", registrySymbol: "Tst", network: "goerli", - gasPriceScale: 1, dryRun: false, }) ).rejects.toThrow( diff --git a/src/implementations/document-store/issue.test.ts b/src/implementations/document-store/issue.test.ts index ae7bc017..c2a83a6a 100644 --- a/src/implementations/document-store/issue.test.ts +++ b/src/implementations/document-store/issue.test.ts @@ -11,7 +11,6 @@ const deployParams: DocumentStoreIssueCommand = { address: "0x1234", network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, dryRun: false, }; @@ -52,7 +51,6 @@ describe("document-store", () => { hash: "0xabcd", address: "0x1234", network: "goerli", - gasPriceScale: 1, dryRun: false, }); diff --git a/src/implementations/document-store/revoke.test.ts b/src/implementations/document-store/revoke.test.ts index d4d69db1..a3770605 100644 --- a/src/implementations/document-store/revoke.test.ts +++ b/src/implementations/document-store/revoke.test.ts @@ -12,7 +12,6 @@ const deployParams: DocumentStoreRevokeCommand = { address: "0x1234", network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/document-store/transfer-ownership.test.ts b/src/implementations/document-store/transfer-ownership.test.ts index f43ab650..c1c69395 100644 --- a/src/implementations/document-store/transfer-ownership.test.ts +++ b/src/implementations/document-store/transfer-ownership.test.ts @@ -12,7 +12,6 @@ const deployParams: DocumentStoreTransferOwnershipCommand = { address: "0x1234", network: "goerli", key: "0000000000000000000000000000000000000000000000000000000000000001", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 916fd710..6ec16afb 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -10,7 +10,6 @@ const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index fdf6e341..ee1ef662 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -11,7 +11,6 @@ const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = tokenRegistry: "0x1234", newBeneficiary: "0x1232", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index 8f0d3075..eb755c91 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -11,7 +11,6 @@ const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { tokenId: "0xzyxw", tokenRegistry: "0x1234", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 691d26ab..e8ab72b1 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -10,7 +10,6 @@ const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 91618d3d..bc01d275 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -10,7 +10,6 @@ const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { tokenRegistry: "0x1122", tokenId: "0x12345", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/transferHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts index d6ed40e9..7b6ff058 100644 --- a/src/implementations/title-escrow/transferHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -11,7 +11,6 @@ const transferHolderParams: TitleEscrowTransferHolderCommand = { tokenId: "0xzyxw", tokenRegistry: "0x1234", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index 7bc5246c..9f411473 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -12,7 +12,6 @@ const endorseChangeOwnersParams: TitleEscrowEndorseTransferOfOwnersCommand = { tokenId: "0xzyxw", tokenRegistry: "0x1234", network: "goerli", - gasPriceScale: 1, dryRun: false, }; diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index bfde6b2e..1bf33268 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -13,7 +13,6 @@ const deployParams: TokenRegistryIssueCommand = { tokenId: "0xzyxw", address: "0x1234", network: "goerli", - gasPriceScale: 1, dryRun: false, }; From bef0e5950b6600d8cb64f15adc2fc5b8dcacfdf2 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 2 Dec 2022 19:02:22 +0800 Subject: [PATCH 43/63] feat: (wip) e2e tests --- package-lock.json | 357 ++++++++++++++++++ package.json | 4 + src/__tests__/token-registry/accounts.ts | 27 ++ .../token-registry/deploy.e2e.test.ts | 60 +++ src/__tests__/token-registry/mint.e2e.test.ts | 26 ++ src/__tests__/token-registry/utils.ts | 106 ++++++ .../document-store/issue.test.ts | 2 - .../document-store/revoke.test.ts | 2 - .../document-store/transfer-ownership.test.ts | 2 - 9 files changed, 580 insertions(+), 6 deletions(-) create mode 100644 src/__tests__/token-registry/accounts.ts create mode 100644 src/__tests__/token-registry/deploy.e2e.test.ts create mode 100644 src/__tests__/token-registry/mint.e2e.test.ts create mode 100644 src/__tests__/token-registry/utils.ts diff --git a/package-lock.json b/package-lock.json index af0ad84d..14b27425 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3882,6 +3882,16 @@ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.7.tgz", "integrity": "sha512-4g1jrL98mdOIwSOUh6LTlB0Cs9I0dQPwINUhBg7C6pN4HLr8GS8xsksJxilW6S6dQHVi2K/o+lQuQcg7LroCnw==" }, + "@types/shelljs": { + "version": "0.8.11", + "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.11.tgz", + "integrity": "sha512-x9yaMvEh5BEaZKeVQC4vp3l+QoFj3BXcd4aYfuKSzIIyihjdVARAadYy3SMNIz0WCCdS2vB9JL/U6GQk5PaxQw==", + "dev": true, + "requires": { + "@types/glob": "*", + "@types/node": "*" + } + }, "@types/signale": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/@types/signale/-/signale-1.4.2.tgz", @@ -7938,6 +7948,327 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "ganache": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/ganache/-/ganache-7.5.0.tgz", + "integrity": "sha512-afNTJYBEaFrLPRrn7eUxH39TgnrffvHn/4T6THzQrc3rpfe4DOxw2nY2XEQxfsq1t4OqKSXtxomzyo26RZiOzw==", + "dev": true, + "requires": { + "@trufflesuite/bigint-buffer": "1.1.10", + "@types/bn.js": "^5.1.0", + "@types/lru-cache": "5.1.1", + "@types/seedrandom": "3.0.1", + "bufferutil": "4.0.5", + "emittery": "0.10.0", + "keccak": "3.0.2", + "leveldown": "6.1.0", + "secp256k1": "4.0.3", + "utf-8-validate": "5.0.7" + }, + "dependencies": { + "@trufflesuite/bigint-buffer": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@trufflesuite/bigint-buffer/-/bigint-buffer-1.1.10.tgz", + "integrity": "sha512-pYIQC5EcMmID74t26GCC67946mgTJFiLXOT/BYozgrd4UEY2JHEGLhWi9cMiQCt5BSqFEvKkCHNnoj82SRjiEw==", + "dev": true, + "requires": { + "node-gyp-build": "4.4.0" + }, + "dependencies": { + "node-gyp-build": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", + "dev": true + } + } + }, + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==", + "dev": true + }, + "@types/node": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.0.tgz", + "integrity": "sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==", + "dev": true + }, + "@types/seedrandom": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.1.tgz", + "integrity": "sha512-giB9gzDeiCeloIXDgzFBCgjj1k4WxcDrZtGl6h1IqmUPlxF+Nx8Ve+96QCyDZ/HseB/uvDsKbpib9hU5cU53pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "bufferutil": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", + "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", + "dev": true, + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "catering": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/catering/-/catering-2.1.0.tgz", + "integrity": "sha512-M5imwzQn6y+ODBfgi+cfgZv2hIUI6oYU/0f35Mdb1ujGeqeoI5tOnl9Q13DTH7LW+7er+NYq8stNOKZD/Z3U/A==", + "dev": true, + "requires": { + "queue-tick": "^1.0.0" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + } + } + }, + "emittery": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.0.tgz", + "integrity": "sha512-AGvFfs+d0JKCJQ4o01ASQLGPmSCxgfU9RFXvzPvZdjKK8oscynksuJhWrSTSw7j7Ep/sZct5b5ZhYCi8S/t0HQ==", + "dev": true + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true + }, + "keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "dev": true, + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, + "leveldown": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.1.0.tgz", + "integrity": "sha512-8C7oJDT44JXxh04aSSsfcMI8YiaGRhOFI9/pMEL7nWJLVsWajDPTRxsSHTM2WcTVY5nXM+SuRHzPPi0GbnDX+w==", + "dev": true, + "requires": { + "abstract-leveldown": "^7.2.0", + "napi-macros": "~2.0.0", + "node-gyp-build": "^4.3.0" + }, + "dependencies": { + "abstract-leveldown": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.2.0.tgz", + "integrity": "sha512-DnhQwcFEaYsvYDnACLZhMmCWd3rkOeEvglpa4q5i/5Jlm3UIsWaxVzuXvDLFCSCWRO3yy2/+V/G7FusFgejnfQ==", + "dev": true, + "requires": { + "buffer": "^6.0.3", + "catering": "^2.0.0", + "is-buffer": "^2.0.5", + "level-concat-iterator": "^3.0.0", + "level-supports": "^2.0.1", + "queue-microtask": "^1.2.3" + } + }, + "level-concat-iterator": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.1.0.tgz", + "integrity": "sha512-BWRCMHBxbIqPxJ8vHOvKUsaO0v1sLYZtjN3K2iZJsRBYtp+ONsY6Jfi6hy9K3+zolgQRryhIn2NRZjZnWJ9NmQ==", + "dev": true, + "requires": { + "catering": "^2.1.0" + } + }, + "level-supports": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.1.0.tgz", + "integrity": "sha512-E486g1NCjW5cF78KGPrMDRBYzPuueMZ6VBXHT6gC7A8UYWGiM14fGgp+s/L1oFfDWSPV/+SFkYCmZ0SiESkRKA==", + "dev": true + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "napi-macros": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz", + "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg==", + "dev": true + }, + "node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", + "dev": true + }, + "node-gyp-build": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", + "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "queue-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.0.tgz", + "integrity": "sha512-ULWhjjE8BmiICGn3G8+1L9wFpERNxkf8ysxkAer4+TFdRefDaXOCV5m92aMB9FtBVmn/8sETXLXY6BfW7hyaWQ==", + "dev": true + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "dev": true, + "requires": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "utf-8-validate": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", + "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", + "dev": true, + "optional": true, + "requires": { + "node-gyp-build": "^4.3.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + } + } + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -8750,6 +9081,12 @@ } } }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, "into-stream": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-6.0.0.tgz", @@ -13416,6 +13753,15 @@ } } }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, "redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -14216,6 +14562,17 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + } + }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", diff --git a/package.json b/package.json index ffe2fda9..7d338dae 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", + "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", @@ -47,6 +48,7 @@ "@types/node": "^15.3.0", "@types/node-fetch": "^2.5.10", "@types/rimraf": "^3.0.0", + "@types/shelljs": "^0.8.11", "@types/signale": "^1.4.1", "@types/tmp": "^0.2.0", "@typescript-eslint/eslint-plugin": "^4.24.0", @@ -56,6 +58,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^24.3.6", "eslint-plugin-prettier": "^3.4.0", + "ganache": "^7.4.3", "git-cz": "^4.7.6", "jest": "^26.1.0", "jest-watch-typeahead": "^0.6.3", @@ -64,6 +67,7 @@ "proxyquire": "^2.1.3", "rimraf": "^3.0.2", "semantic-release": "^17.4.3", + "shelljs": "^0.8.5", "tmp": "^0.2.1", "ts-jest": "^26.5.6", "ts-node": "^9.1.1", diff --git a/src/__tests__/token-registry/accounts.ts b/src/__tests__/token-registry/accounts.ts new file mode 100644 index 00000000..aa90ad06 --- /dev/null +++ b/src/__tests__/token-registry/accounts.ts @@ -0,0 +1,27 @@ +import { constants } from "@govtechsg/token-registry"; + +export const { contractAddress } = constants; + +export const network = "local"; +export const chainId = 1337 +export const forkedNetwork = 5 + +export const mnemonic = "indicate swing place chair flight used hammer soon photo region volume shuffle"; + +export const owner = { + ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", + publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", + privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", +}; + +export const receiver = { + ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", + publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", + privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", +}; + +export const creators = { + titleEscrowFactory: contractAddress.TitleEscrowFactory[forkedNetwork], + deployer: contractAddress.Deployer[forkedNetwork], + tokenImplementation: contractAddress.TokenImplementation[forkedNetwork], +} diff --git a/src/__tests__/token-registry/deploy.e2e.test.ts b/src/__tests__/token-registry/deploy.e2e.test.ts new file mode 100644 index 00000000..aaca5d93 --- /dev/null +++ b/src/__tests__/token-registry/deploy.e2e.test.ts @@ -0,0 +1,60 @@ +import shell, { ShellString } from "shelljs"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; +import { isAddress } from "web3-utils"; +import { creators, network, owner } from "./accounts"; +import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils"; + +const defaults = { + factoryAddress: creators.titleEscrowFactory, + tokenImplementationAddress: creators.tokenImplementation, + deployerAddress: creators.deployer, + network: network, + dryRun: false, +} + +describe("deploy token-registry", () => { + jest.setTimeout(90000); + + + it("should be able to deploy token-registry", async () => { + const tokenRegistryParameter: DeployTokenRegistryCommand = { + registryName: "Test Token", + registrySymbol: "TKN", + ...defaults + }; + + const command = generateDeployTokenRegistryCommand(tokenRegistryParameter, owner.privateKey); + const results: ShellString = shell.exec(command); + const tokenRegistrySuccessFormat = "✔ success Token registry deployed at "; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const splitResults = results.trim().split("\n"); + const tokenRegistryAddressLine = splitResults[splitResults.length - 2] + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) + expect(isAddress(tokenRegistryAddress)).toBe(true); + }); +}); + + +describe("deploy document-store", () => { + jest.setTimeout(90000); + + + it("should be able to deploy document-store", async () => { + + const documentStoreParameters: DeployDocumentStoreCommand = { + storeName: "Test Document Store", + ...defaults + }; + + const command = generateDeployDocumentStoreCommand(documentStoreParameters, owner.privateKey); + const results: ShellString = shell.exec(command); + const tokenRegistrySuccessFormat = "✔ success Document store Test Document Store deployed at "; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const splitResults = results.trim().split("\n"); + const tokenRegistryAddressLine = splitResults[splitResults.length - 2] + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) + expect(isAddress(tokenRegistryAddress)).toBe(true); + }); +}); diff --git a/src/__tests__/token-registry/mint.e2e.test.ts b/src/__tests__/token-registry/mint.e2e.test.ts new file mode 100644 index 00000000..28fed12d --- /dev/null +++ b/src/__tests__/token-registry/mint.e2e.test.ts @@ -0,0 +1,26 @@ +import shell, { ShellString } from "shelljs"; +import { deployTokenRegistry, generateTokenId } from "./utils"; +import { network, owner } from "./accounts"; +import { isAddress } from "web3-utils"; + +describe("deploy token-registry", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress: string = ''; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }) + + it("should be able to mint title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}` + const results: ShellString = shell.exec(command); + const tokenRegistrySuccessFormat = "✔ success Token with hash "; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const splitResults = results.trim().split("\n"); + const titleEscrowAddressLine = splitResults[splitResults.length - 2] + const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42) + expect(isAddress(titleEscrowAddress)).toBe(true); + }); +}); \ No newline at end of file diff --git a/src/__tests__/token-registry/utils.ts b/src/__tests__/token-registry/utils.ts new file mode 100644 index 00000000..7af4d5db --- /dev/null +++ b/src/__tests__/token-registry/utils.ts @@ -0,0 +1,106 @@ +import { isAddress } from "web3-utils"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; +import { creators, network } from "./accounts"; +import shell, { ShellString } from "shelljs"; +import { Wallet } from "ethers"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; + +const defaults = { + factoryAddress: creators.titleEscrowFactory, + tokenImplementationAddress: creators.tokenImplementation, + deployerAddress: creators.deployer, + network: network, + dryRun: false, +} + + +export const generateDeployTokenRegistryCommand = (tokenRegistryParameter: DeployTokenRegistryCommand, privateKey: string) => { + return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}` +} + +export const generateDeployDocumentStoreCommand = (documentStoreParameter: DeployDocumentStoreCommand, privateKey: string) => { + return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}` +} + +export const generateMintTitleEscrowCommand = (titleEscrowParameter: TokenRegistryIssueCommand, privateKey: string) => { + return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} --n ${titleEscrowParameter.network}` +} + + + +export const deployTokenRegistry = (privateKey: string, tokenRegistryParameters?: DeployTokenRegistryCommand): string => { + if (!tokenRegistryParameters) { + tokenRegistryParameters = { + registryName: "Test Token", + registrySymbol: "TKN", + ...defaults + }; + } + + const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); + const results: ShellString = shell.exec(command); + const tokenRegistrySuccessFormat = "✔ success Token registry deployed at "; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + if (!checkSuccess) throw new Error("Unable to deploy the token registry"); + const splitResults = results.trim().split("\n"); + const tokenRegistryAddressLine = splitResults[splitResults.length - 2] + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) + if (!isAddress(tokenRegistryAddress)) throw new Error("Unable to find token registry address"); + return tokenRegistryAddress; +} + +export const deployDocumentStore = (privateKey: string, documentStoreParameters?: DeployDocumentStoreCommand): string => { + if (!documentStoreParameters) { + documentStoreParameters = { + storeName: "Test Document Store", + ...defaults + }; + } + const command = generateDeployDocumentStoreCommand(documentStoreParameters, privateKey); + const results: ShellString = shell.exec(command); + const documentStoreSuccessFormat = "✔ success Document store Test Document Store deployed at "; + const checkSuccess = results.includes(documentStoreSuccessFormat); + if (!checkSuccess) throw new Error("Unable to deploy document store"); + const splitResults = results.trim().split("\n"); + const documentStoreAddressLine = splitResults[splitResults.length - 2] + const documentStoreAddress = documentStoreAddressLine.trim().substring(documentStoreSuccessFormat.length) + if (!isAddress(documentStoreAddress)) throw new Error("Unable to find document store address"); + return documentStoreAddress; +} + +const usedTokenIds = new Set(); +export const generateTokenId = () => { + for (let count = 0; count < 10; count = count + 1) { + const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')}`; + const unique = !usedTokenIds.has(generatedTokenId); + if(unique) { + usedTokenIds.add(generatedTokenId); + return generatedTokenId; + } + } + throw new Error("Unable to generate tokenIds") +} + +export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand) => { + if (!titleEscrowParameter) { + const wallet = new Wallet(privateKey); + titleEscrowParameter = { + address: deployTokenRegistry(privateKey), + beneficiary: wallet.address, + holder: wallet.address, + tokenId: generateTokenId(), + ...defaults, + } + } + + const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); + const results: ShellString = shell.exec(command); + const tokenRegistrySuccessFormat = "✔ success Token with hash "; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + if (!checkSuccess) throw new Error("Unable to mint token"); + const splitResults = results.trim().split("\n"); + const titleEscrowAddressLine = splitResults[splitResults.length - 2] + const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42) + if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); +} + diff --git a/src/implementations/document-store/issue.test.ts b/src/implementations/document-store/issue.test.ts index c2a83a6a..c2ab352a 100644 --- a/src/implementations/document-store/issue.test.ts +++ b/src/implementations/document-store/issue.test.ts @@ -14,8 +14,6 @@ const deployParams: DocumentStoreIssueCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of DocumentStoreFactory -// ideally must setup ganache, and run the function over it describe("document-store", () => { // increase timeout because ethers is throttling jest.setTimeout(30000); diff --git a/src/implementations/document-store/revoke.test.ts b/src/implementations/document-store/revoke.test.ts index a3770605..4c3d8c97 100644 --- a/src/implementations/document-store/revoke.test.ts +++ b/src/implementations/document-store/revoke.test.ts @@ -15,8 +15,6 @@ const deployParams: DocumentStoreRevokeCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of DocumentStoreFactory -// ideally must setup ganache, and run the function over it describe("document-store", () => { // increase timeout because ethers is throttling jest.setTimeout(30000); diff --git a/src/implementations/document-store/transfer-ownership.test.ts b/src/implementations/document-store/transfer-ownership.test.ts index c1c69395..e5e7ab94 100644 --- a/src/implementations/document-store/transfer-ownership.test.ts +++ b/src/implementations/document-store/transfer-ownership.test.ts @@ -15,8 +15,6 @@ const deployParams: DocumentStoreTransferOwnershipCommand = { dryRun: false, }; -// TODO the following test is very fragile and might break on every interface change of DocumentStoreFactory -// ideally must setup ganache, and run the function over it describe("document-store", () => { // increase timeout because ethers is throttling jest.setTimeout(30000); From 6bcaf9c892c9b595a6b08b7a1c0d2b89dff8d016 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Dec 2022 14:11:05 +0800 Subject: [PATCH 44/63] fix: resolve ganache transaction fee spike --- package.json | 2 +- src/__tests__/fixture/e2e/commands.ts | 23 ++++ .../accounts.ts => fixture/e2e/constants.ts} | 17 ++- src/__tests__/fixture/e2e/shell.ts | 72 ++++++++++++ src/__tests__/fixture/e2e/utils.ts | 108 ++++++++++++++++++ .../token-registry/deploy.e2e.test.ts | 36 +++--- src/__tests__/token-registry/mint.e2e.test.ts | 22 ++-- src/__tests__/token-registry/utils.ts | 106 ----------------- 8 files changed, 242 insertions(+), 144 deletions(-) create mode 100644 src/__tests__/fixture/e2e/commands.ts rename src/__tests__/{token-registry/accounts.ts => fixture/e2e/constants.ts} (71%) create mode 100644 src/__tests__/fixture/e2e/shell.ts create mode 100644 src/__tests__/fixture/e2e/utils.ts delete mode 100644 src/__tests__/token-registry/utils.ts diff --git a/package.json b/package.json index 7d338dae..ec970697 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", - "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli", + "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --miner.blockTime 1", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", diff --git a/src/__tests__/fixture/e2e/commands.ts b/src/__tests__/fixture/e2e/commands.ts new file mode 100644 index 00000000..150875e7 --- /dev/null +++ b/src/__tests__/fixture/e2e/commands.ts @@ -0,0 +1,23 @@ +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; + +export const generateDeployTokenRegistryCommand = ( + tokenRegistryParameter: DeployTokenRegistryCommand, + privateKey: string +): string => { + return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}`; +}; + +export const generateDeployDocumentStoreCommand = ( + documentStoreParameter: DeployDocumentStoreCommand, + privateKey: string +): string => { + return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}`; +}; + +export const generateMintTitleEscrowCommand = ( + titleEscrowParameter: TokenRegistryIssueCommand, + privateKey: string +): string => { + return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} --n ${titleEscrowParameter.network}`; +}; diff --git a/src/__tests__/token-registry/accounts.ts b/src/__tests__/fixture/e2e/constants.ts similarity index 71% rename from src/__tests__/token-registry/accounts.ts rename to src/__tests__/fixture/e2e/constants.ts index aa90ad06..64ebd81b 100644 --- a/src/__tests__/token-registry/accounts.ts +++ b/src/__tests__/fixture/e2e/constants.ts @@ -3,8 +3,8 @@ import { constants } from "@govtechsg/token-registry"; export const { contractAddress } = constants; export const network = "local"; -export const chainId = 1337 -export const forkedNetwork = 5 +export const chainId = 1337; +export const forkedNetwork = 5; export const mnemonic = "indicate swing place chair flight used hammer soon photo region volume shuffle"; @@ -21,7 +21,12 @@ export const receiver = { }; export const creators = { - titleEscrowFactory: contractAddress.TitleEscrowFactory[forkedNetwork], - deployer: contractAddress.Deployer[forkedNetwork], - tokenImplementation: contractAddress.TokenImplementation[forkedNetwork], -} + titleEscrowFactory: contractAddress.TitleEscrowFactory[forkedNetwork], + deployer: contractAddress.Deployer[forkedNetwork], + tokenImplementation: contractAddress.TokenImplementation[forkedNetwork], +}; + +export const emoji = { + tick: "✔", + cross: "✖", +}; diff --git a/src/__tests__/fixture/e2e/shell.ts b/src/__tests__/fixture/e2e/shell.ts new file mode 100644 index 00000000..f04badd9 --- /dev/null +++ b/src/__tests__/fixture/e2e/shell.ts @@ -0,0 +1,72 @@ +import shell, { ShellString } from "shelljs"; +import { log } from "signale"; +import { emoji } from "./constants"; +shell.config.silent = true; + +interface LineInfo { + lineNumber: number; + lineContent: string; +} + +const run = (command: string, silent = false): string => { + const rawResults: ShellString = shell.exec(command); + const results = stripAnsi(rawResults.trim()); + if (!silent) { + const success = `${emoji.tick} success`; + const failure = `${emoji.cross} error`; + let successLines = extractLine(results, success); + if (!successLines) successLines = []; + let failureLines = extractLine(results, failure); + if (!failureLines) failureLines = []; + const statusLines: LineInfo[] = [...successLines, ...failureLines]; + log(command); + printLines(statusLines); + } + return results; +}; + +const printLines = (lines: LineInfo[]): void => { + lines.sort((a: LineInfo, b: LineInfo): number => { + return a.lineNumber - b.lineNumber; + }); + for (const line of lines) { + log(`${line.lineNumber}: ${line.lineContent}`); + } +}; + +const extractLine = (result: string, query: string): LineInfo[] | void => { + const splitResults = result.trim().split("\n"); + const matchedLines = []; + for (let count = 0; count < splitResults.length; count++) { + const line = splitResults[count].trim(); + const containsQueryString = line.includes(query); + if (containsQueryString) { + matchedLines.push({ + lineNumber: count, + lineContent: line, + }); + } + } + if (matchedLines.length > 0) return matchedLines; + else return; +}; + +// https://github.com/chalk/strip-ansi/blob/main/index.js +export function stripAnsi(ansiString: string): string { + if (typeof ansiString !== "string") { + throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); + } + return ansiString.replace(ansiRegex(), ""); +} + +// https://github.com/chalk/ansi-regex/blob/main/index.js +export function ansiRegex({ onlyFirst = false } = {}): RegExp { + const pattern = [ + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + ].join("|"); + + return new RegExp(pattern, onlyFirst ? undefined : "g"); +} + +export { shell, ShellString, run }; diff --git a/src/__tests__/fixture/e2e/utils.ts b/src/__tests__/fixture/e2e/utils.ts new file mode 100644 index 00000000..7123663f --- /dev/null +++ b/src/__tests__/fixture/e2e/utils.ts @@ -0,0 +1,108 @@ +import { isAddress } from "web3-utils"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { creators, emoji, network } from "./constants"; +import { run } from "./shell"; +import { Wallet } from "ethers"; +import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { + generateDeployDocumentStoreCommand, + generateDeployTokenRegistryCommand, + generateMintTitleEscrowCommand, +} from "./commands"; + +const defaults = { + factoryAddress: creators.titleEscrowFactory, + tokenImplementationAddress: creators.tokenImplementation, + deployerAddress: creators.deployer, + network: network, + dryRun: false, +}; + +const numberGenerator = (range: number): number => { + return Math.floor(Math.random() * range); +}; + +export const deployTokenRegistry = ( + privateKey: string, + tokenRegistryParameters?: DeployTokenRegistryCommand +): string => { + if (!tokenRegistryParameters) { + const index = numberGenerator(2); + tokenRegistryParameters = { + registryName: `Test Tokenx ${index}`, + registrySymbol: `TKNx${index}`, + ...defaults, + }; + } + + const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); + const results = run(command, true); + const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + if (!checkSuccess) throw new Error("Unable to deploy the token registry"); + const splitResults = results.trim().split("\n"); + const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); + if (!isAddress(tokenRegistryAddress)) throw new Error("Unable to find token registry address"); + return tokenRegistryAddress; +}; + +export const deployDocumentStore = ( + privateKey: string, + documentStoreParameters?: DeployDocumentStoreCommand +): string => { + if (!documentStoreParameters) { + const index = numberGenerator(2); + documentStoreParameters = { + storeName: `Test Document Store ${index}`, + ...defaults, + }; + } + const command = generateDeployDocumentStoreCommand(documentStoreParameters, privateKey); + const results = run(command, true); + const documentStoreSuccessFormat = `${emoji.tick} success Document store Test Document Store deployed at `; + const checkSuccess = results.includes(documentStoreSuccessFormat); + if (!checkSuccess) throw new Error("Unable to deploy document store"); + const splitResults = results.trim().split("\n"); + const documentStoreAddressLine = splitResults[splitResults.length - 2]; + const documentStoreAddress = documentStoreAddressLine.trim().substring(documentStoreSuccessFormat.length); + if (!isAddress(documentStoreAddress)) throw new Error("Unable to find document store address"); + return documentStoreAddress; +}; + +const usedTokenIds = new Set(); +export const generateTokenId = (): string => { + for (let count = 0; count < 10; count = count + 1) { + const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join("")}`; + const unique = !usedTokenIds.has(generatedTokenId); + if (unique) { + usedTokenIds.add(generatedTokenId); + return generatedTokenId; + } + } + throw new Error("Unable to generate tokenIds"); +}; + +export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand): string => { + if (!titleEscrowParameter) { + const wallet = new Wallet(privateKey); + titleEscrowParameter = { + address: deployTokenRegistry(privateKey), + beneficiary: wallet.address, + holder: wallet.address, + tokenId: generateTokenId(), + ...defaults, + }; + } + + const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); + const results = run(command, true); + const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; + const checkSuccess = results.includes(tokenRegistrySuccessFormat); + if (!checkSuccess) throw new Error("Unable to mint token"); + const splitResults = results.trim().split("\n"); + const titleEscrowAddressLine = splitResults[splitResults.length - 2]; + const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); + if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); + return titleEscrowAddress; +}; diff --git a/src/__tests__/token-registry/deploy.e2e.test.ts b/src/__tests__/token-registry/deploy.e2e.test.ts index aaca5d93..33f42ba0 100644 --- a/src/__tests__/token-registry/deploy.e2e.test.ts +++ b/src/__tests__/token-registry/deploy.e2e.test.ts @@ -1,8 +1,8 @@ -import shell, { ShellString } from "shelljs"; +import { run } from "../fixture/e2e/shell"; import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; import { isAddress } from "web3-utils"; -import { creators, network, owner } from "./accounts"; -import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils"; +import { creators, emoji, network, owner } from "../fixture/e2e/constants"; +import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "../fixture/e2e/commands"; const defaults = { factoryAddress: creators.titleEscrowFactory, @@ -10,51 +10,47 @@ const defaults = { deployerAddress: creators.deployer, network: network, dryRun: false, -} +}; describe("deploy token-registry", () => { jest.setTimeout(90000); - it("should be able to deploy token-registry", async () => { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", registrySymbol: "TKN", - ...defaults + ...defaults, }; const command = generateDeployTokenRegistryCommand(tokenRegistryParameter, owner.privateKey); - const results: ShellString = shell.exec(command); - const tokenRegistrySuccessFormat = "✔ success Token registry deployed at "; + const results = run(command); + const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); expect(checkSuccess).toBe(true); const splitResults = results.trim().split("\n"); - const tokenRegistryAddressLine = splitResults[splitResults.length - 2] - const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) + const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); expect(isAddress(tokenRegistryAddress)).toBe(true); }); }); - describe("deploy document-store", () => { jest.setTimeout(90000); - it("should be able to deploy document-store", async () => { - const documentStoreParameters: DeployDocumentStoreCommand = { storeName: "Test Document Store", - ...defaults - }; - + ...defaults, + }; + const command = generateDeployDocumentStoreCommand(documentStoreParameters, owner.privateKey); - const results: ShellString = shell.exec(command); - const tokenRegistrySuccessFormat = "✔ success Document store Test Document Store deployed at "; + const results = run(command); + const tokenRegistrySuccessFormat = `${emoji.tick} success Document store Test Document Store deployed at `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); expect(checkSuccess).toBe(true); const splitResults = results.trim().split("\n"); - const tokenRegistryAddressLine = splitResults[splitResults.length - 2] - const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) + const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; + const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); expect(isAddress(tokenRegistryAddress)).toBe(true); }); }); diff --git a/src/__tests__/token-registry/mint.e2e.test.ts b/src/__tests__/token-registry/mint.e2e.test.ts index 28fed12d..a6414fa8 100644 --- a/src/__tests__/token-registry/mint.e2e.test.ts +++ b/src/__tests__/token-registry/mint.e2e.test.ts @@ -1,26 +1,26 @@ -import shell, { ShellString } from "shelljs"; -import { deployTokenRegistry, generateTokenId } from "./utils"; -import { network, owner } from "./accounts"; +import { deployTokenRegistry, generateTokenId } from "../fixture/e2e/utils"; +import { run } from "../fixture/e2e/shell"; +import { emoji, network, owner } from "../fixture/e2e/constants"; import { isAddress } from "web3-utils"; describe("deploy token-registry", () => { jest.setTimeout(90000); - let tokenRegistryAddress: string = ''; + let tokenRegistryAddress = ""; beforeAll(() => { tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }) + }); it("should be able to mint title-escrow on token-registry", async () => { const tokenId = generateTokenId(); - const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}` - const results: ShellString = shell.exec(command); - const tokenRegistrySuccessFormat = "✔ success Token with hash "; + const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; + const results = run(command); + const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); expect(checkSuccess).toBe(true); const splitResults = results.trim().split("\n"); - const titleEscrowAddressLine = splitResults[splitResults.length - 2] - const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42) + const titleEscrowAddressLine = splitResults[splitResults.length - 2]; + const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); expect(isAddress(titleEscrowAddress)).toBe(true); }); -}); \ No newline at end of file +}); diff --git a/src/__tests__/token-registry/utils.ts b/src/__tests__/token-registry/utils.ts deleted file mode 100644 index 7af4d5db..00000000 --- a/src/__tests__/token-registry/utils.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { isAddress } from "web3-utils"; -import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; -import { creators, network } from "./accounts"; -import shell, { ShellString } from "shelljs"; -import { Wallet } from "ethers"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; - -const defaults = { - factoryAddress: creators.titleEscrowFactory, - tokenImplementationAddress: creators.tokenImplementation, - deployerAddress: creators.deployer, - network: network, - dryRun: false, -} - - -export const generateDeployTokenRegistryCommand = (tokenRegistryParameter: DeployTokenRegistryCommand, privateKey: string) => { - return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}` -} - -export const generateDeployDocumentStoreCommand = (documentStoreParameter: DeployDocumentStoreCommand, privateKey: string) => { - return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}` -} - -export const generateMintTitleEscrowCommand = (titleEscrowParameter: TokenRegistryIssueCommand, privateKey: string) => { - return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} --n ${titleEscrowParameter.network}` -} - - - -export const deployTokenRegistry = (privateKey: string, tokenRegistryParameters?: DeployTokenRegistryCommand): string => { - if (!tokenRegistryParameters) { - tokenRegistryParameters = { - registryName: "Test Token", - registrySymbol: "TKN", - ...defaults - }; - } - - const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); - const results: ShellString = shell.exec(command); - const tokenRegistrySuccessFormat = "✔ success Token registry deployed at "; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - if (!checkSuccess) throw new Error("Unable to deploy the token registry"); - const splitResults = results.trim().split("\n"); - const tokenRegistryAddressLine = splitResults[splitResults.length - 2] - const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length) - if (!isAddress(tokenRegistryAddress)) throw new Error("Unable to find token registry address"); - return tokenRegistryAddress; -} - -export const deployDocumentStore = (privateKey: string, documentStoreParameters?: DeployDocumentStoreCommand): string => { - if (!documentStoreParameters) { - documentStoreParameters = { - storeName: "Test Document Store", - ...defaults - }; - } - const command = generateDeployDocumentStoreCommand(documentStoreParameters, privateKey); - const results: ShellString = shell.exec(command); - const documentStoreSuccessFormat = "✔ success Document store Test Document Store deployed at "; - const checkSuccess = results.includes(documentStoreSuccessFormat); - if (!checkSuccess) throw new Error("Unable to deploy document store"); - const splitResults = results.trim().split("\n"); - const documentStoreAddressLine = splitResults[splitResults.length - 2] - const documentStoreAddress = documentStoreAddressLine.trim().substring(documentStoreSuccessFormat.length) - if (!isAddress(documentStoreAddress)) throw new Error("Unable to find document store address"); - return documentStoreAddress; -} - -const usedTokenIds = new Set(); -export const generateTokenId = () => { - for (let count = 0; count < 10; count = count + 1) { - const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join('')}`; - const unique = !usedTokenIds.has(generatedTokenId); - if(unique) { - usedTokenIds.add(generatedTokenId); - return generatedTokenId; - } - } - throw new Error("Unable to generate tokenIds") -} - -export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand) => { - if (!titleEscrowParameter) { - const wallet = new Wallet(privateKey); - titleEscrowParameter = { - address: deployTokenRegistry(privateKey), - beneficiary: wallet.address, - holder: wallet.address, - tokenId: generateTokenId(), - ...defaults, - } - } - - const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); - const results: ShellString = shell.exec(command); - const tokenRegistrySuccessFormat = "✔ success Token with hash "; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - if (!checkSuccess) throw new Error("Unable to mint token"); - const splitResults = results.trim().split("\n"); - const titleEscrowAddressLine = splitResults[splitResults.length - 2] - const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42) - if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); -} - From fce3481875a7d9b2a499d40c496bc06f3171a946 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 6 Dec 2022 18:39:28 +0800 Subject: [PATCH 45/63] feat: most e2e working except surrender --- package.json | 2 +- src/__tests__/fixture/e2e/commands.ts | 50 +++++++-- src/__tests__/fixture/e2e/constants.ts | 3 + src/__tests__/fixture/e2e/shell.ts | 102 +++++++++--------- src/__tests__/fixture/e2e/utils.ts | 61 +++++++++-- .../token-registry/change-holder.e2e.test.ts | 58 ++++++++++ .../endorse-change-owner.e2e.test.ts | 71 ++++++++++++ .../endorse-transfer.e2e.test.ts | 60 +++++++++++ src/__tests__/token-registry/mint.e2e.test.ts | 15 ++- .../token-registry/nominate.e2e.test.ts | 59 ++++++++++ .../token-registry/surrender.e2e.test.ts | 56 ++++++++++ .../title-escrow/surrender-document.ts | 1 + 12 files changed, 467 insertions(+), 71 deletions(-) create mode 100644 src/__tests__/token-registry/change-holder.e2e.test.ts create mode 100644 src/__tests__/token-registry/endorse-change-owner.e2e.test.ts create mode 100644 src/__tests__/token-registry/endorse-transfer.e2e.test.ts create mode 100644 src/__tests__/token-registry/nominate.e2e.test.ts create mode 100644 src/__tests__/token-registry/surrender.e2e.test.ts diff --git a/package.json b/package.json index ec970697..5f36ab88 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", - "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --miner.blockTime 1", + "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --miner.blockTime 12", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", diff --git a/src/__tests__/fixture/e2e/commands.ts b/src/__tests__/fixture/e2e/commands.ts index 150875e7..0910cee4 100644 --- a/src/__tests__/fixture/e2e/commands.ts +++ b/src/__tests__/fixture/e2e/commands.ts @@ -1,23 +1,55 @@ import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { TitleEscrowEndorseTransferOfOwnersCommand, TitleEscrowNominateBeneficiaryCommand, TitleEscrowtransferOwnerCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; export const generateDeployTokenRegistryCommand = ( - tokenRegistryParameter: DeployTokenRegistryCommand, - privateKey: string + tokenRegistryParameter: DeployTokenRegistryCommand, + privateKey: string ): string => { - return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}`; + return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}`; }; export const generateDeployDocumentStoreCommand = ( - documentStoreParameter: DeployDocumentStoreCommand, - privateKey: string + documentStoreParameter: DeployDocumentStoreCommand, + privateKey: string ): string => { - return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}`; + return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}`; }; export const generateMintTitleEscrowCommand = ( - titleEscrowParameter: TokenRegistryIssueCommand, - privateKey: string + titleEscrowParameter: TokenRegistryIssueCommand, + privateKey: string ): string => { - return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} --n ${titleEscrowParameter.network}`; + return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} -n ${titleEscrowParameter.network}`; }; + +export const generateChangeHolderCommand = ( + changeHolderParameter: TitleEscrowtransferOwnerCommand, + privateKey: string +): string => { + return `npm run dev -- title-escrow change-holder --token-registry ${changeHolderParameter.tokenRegistry} --tokenId ${changeHolderParameter.tokenId} --newHolder ${changeHolderParameter.newHolder} -k ${privateKey} --network ${changeHolderParameter.network}`; +}; +export const generateTransferOwnersCommand = ( + transferOwners: TitleEscrowEndorseTransferOfOwnersCommand, + privateKey: string +): string => { + return `npm run dev -- title-escrow endorse-change-owner --token-registry ${transferOwners.tokenRegistry} --tokenId ${transferOwners.tokenId} --newOwner ${transferOwners.newOwner} --newHolder ${transferOwners.newHolder} -k ${privateKey} --network ${transferOwners.network}`; +} + +export const generateEndorseTransferOwnerCommand = ( + transferOwner: TitleEscrowNominateBeneficiaryCommand, + privateKey: string +): string => { +// const command = `npm run dev -- title-escrow endorse-transfer-owner --token-registry ${transferHolder.tokenRegistry} --tokenId ${transferHolder.tokenId} --newBeneficiary ${transferHolder.newBeneficiary} -k ${owner.privateKey} --network ${transferHolder.network}`; + return `npm run dev -- title-escrow endorse-transfer-owner --token-registry ${transferOwner.tokenRegistry} --tokenId ${transferOwner.tokenId} --newBeneficiary ${transferOwner.newBeneficiary} -k ${privateKey} --network ${transferOwner.network}`; +} + + +export const generateNominateCommand = ( + nominateParameter: TitleEscrowNominateBeneficiaryCommand, + privateKey: string +): string => { +// const command = `npm run dev -- title-escrow nominate-change-owner --token-registry ${transferHolder.tokenRegistry} --tokenId ${transferHolder.tokenId} --newOwner ${transferHolder.newBeneficiary} -k ${owner.privateKey} --network ${transferHolder.network}`; + return `npm run dev -- title-escrow nominate-change-owner --token-registry ${nominateParameter.tokenRegistry} --tokenId ${nominateParameter.tokenId} --newOwner ${nominateParameter.newBeneficiary} -k ${privateKey} --network ${nominateParameter.network}`; +} + diff --git a/src/__tests__/fixture/e2e/constants.ts b/src/__tests__/fixture/e2e/constants.ts index 64ebd81b..5c3d3fef 100644 --- a/src/__tests__/fixture/e2e/constants.ts +++ b/src/__tests__/fixture/e2e/constants.ts @@ -30,3 +30,6 @@ export const emoji = { tick: "✔", cross: "✖", }; + +export const silent = true; +export const verbose = true; diff --git a/src/__tests__/fixture/e2e/shell.ts b/src/__tests__/fixture/e2e/shell.ts index f04badd9..15c0e80f 100644 --- a/src/__tests__/fixture/e2e/shell.ts +++ b/src/__tests__/fixture/e2e/shell.ts @@ -1,72 +1,74 @@ import shell, { ShellString } from "shelljs"; import { log } from "signale"; -import { emoji } from "./constants"; +import { emoji, verbose } from "./constants"; shell.config.silent = true; -interface LineInfo { - lineNumber: number; - lineContent: string; +export interface LineInfo { + lineNumber: number; + lineContent: string; } -const run = (command: string, silent = false): string => { - const rawResults: ShellString = shell.exec(command); - const results = stripAnsi(rawResults.trim()); - if (!silent) { - const success = `${emoji.tick} success`; - const failure = `${emoji.cross} error`; - let successLines = extractLine(results, success); - if (!successLines) successLines = []; - let failureLines = extractLine(results, failure); - if (!failureLines) failureLines = []; - const statusLines: LineInfo[] = [...successLines, ...failureLines]; - log(command); - printLines(statusLines); - } - return results; +export const run = (command: string, silent = false): string => { + shell.config.silent = !(!silent && verbose); + const rawResults: ShellString = shell.exec(command); + const results = stripAnsi(rawResults.trim()); + if (!silent) { + const success = `${emoji.tick} success`; + const failure = `${emoji.cross} error`; + let successLines = extractLine(results, success); + if (!successLines) successLines = []; + let failureLines = extractLine(results, failure); + if (!failureLines) failureLines = []; + const statusLines: LineInfo[] = [...successLines, ...failureLines]; + log(command); + printLines(statusLines); + if(verbose && failureLines.length > 0) log(rawResults) + } + return results; }; -const printLines = (lines: LineInfo[]): void => { - lines.sort((a: LineInfo, b: LineInfo): number => { - return a.lineNumber - b.lineNumber; - }); - for (const line of lines) { - log(`${line.lineNumber}: ${line.lineContent}`); - } +export const printLines = (lines: LineInfo[]): void => { + lines.sort((a: LineInfo, b: LineInfo): number => { + return a.lineNumber - b.lineNumber; + }); + for (const line of lines) { + log(`${line.lineNumber}: ${line.lineContent}`); + } }; -const extractLine = (result: string, query: string): LineInfo[] | void => { - const splitResults = result.trim().split("\n"); - const matchedLines = []; - for (let count = 0; count < splitResults.length; count++) { - const line = splitResults[count].trim(); - const containsQueryString = line.includes(query); - if (containsQueryString) { - matchedLines.push({ - lineNumber: count, - lineContent: line, - }); +export const extractLine = (result: string, query: string): LineInfo[] | void => { + const splitResults = result.trim().split("\n"); + const matchedLines = []; + for (let count = 0; count < splitResults.length; count++) { + const line = splitResults[count].trim(); + const containsQueryString = line.includes(query); + if (containsQueryString) { + matchedLines.push({ + lineNumber: count, + lineContent: line, + }); + } } - } - if (matchedLines.length > 0) return matchedLines; - else return; + if (matchedLines.length > 0) return matchedLines; + else return; }; // https://github.com/chalk/strip-ansi/blob/main/index.js export function stripAnsi(ansiString: string): string { - if (typeof ansiString !== "string") { - throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); - } - return ansiString.replace(ansiRegex(), ""); + if (typeof ansiString !== "string") { + throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); + } + return ansiString.replace(ansiRegex(), ""); } // https://github.com/chalk/ansi-regex/blob/main/index.js export function ansiRegex({ onlyFirst = false } = {}): RegExp { - const pattern = [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", - ].join("|"); + const pattern = [ + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + ].join("|"); - return new RegExp(pattern, onlyFirst ? undefined : "g"); + return new RegExp(pattern, onlyFirst ? undefined : "g"); } -export { shell, ShellString, run }; +export { shell, ShellString }; diff --git a/src/__tests__/fixture/e2e/utils.ts b/src/__tests__/fixture/e2e/utils.ts index 7123663f..95885205 100644 --- a/src/__tests__/fixture/e2e/utils.ts +++ b/src/__tests__/fixture/e2e/utils.ts @@ -1,19 +1,18 @@ import { isAddress } from "web3-utils"; import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { creators, emoji, network } from "./constants"; -import { run } from "./shell"; +import { extractLine, LineInfo, run } from "./shell"; import { Wallet } from "ethers"; import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand, generateMintTitleEscrowCommand, + generateNominateCommand, } from "./commands"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; const defaults = { - factoryAddress: creators.titleEscrowFactory, - tokenImplementationAddress: creators.tokenImplementation, - deployerAddress: creators.deployer, network: network, dryRun: false, }; @@ -27,14 +26,16 @@ export const deployTokenRegistry = ( tokenRegistryParameters?: DeployTokenRegistryCommand ): string => { if (!tokenRegistryParameters) { - const index = numberGenerator(2); + const index = numberGenerator(100); tokenRegistryParameters = { registryName: `Test Tokenx ${index}`, registrySymbol: `TKNx${index}`, + factoryAddress: creators.titleEscrowFactory, + tokenImplementationAddress: creators.tokenImplementation, + deployerAddress: creators.deployer, ...defaults, }; } - const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); const results = run(command, true); const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; @@ -52,7 +53,7 @@ export const deployDocumentStore = ( documentStoreParameters?: DeployDocumentStoreCommand ): string => { if (!documentStoreParameters) { - const index = numberGenerator(2); + const index = numberGenerator(100); documentStoreParameters = { storeName: `Test Document Store ${index}`, ...defaults, @@ -83,7 +84,13 @@ export const generateTokenId = (): string => { throw new Error("Unable to generate tokenIds"); }; -export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand): string => { +export interface TokenInfo { + tokenRegistry: string, + tokenId: string, + titleEscrowAddress?: string, +} + +export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand): TokenInfo => { if (!titleEscrowParameter) { const wallet = new Wallet(privateKey); titleEscrowParameter = { @@ -104,5 +111,41 @@ export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegist const titleEscrowAddressLine = splitResults[splitResults.length - 2]; const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); - return titleEscrowAddress; + return { + tokenRegistry: titleEscrowParameter.address, + tokenId: titleEscrowParameter.tokenId, + titleEscrowAddress + }; +}; + +export const mintNominatedToken = (privateKey: string, nominee: string) => { + const { tokenRegistry, tokenId } = mintToken(privateKey); + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newBeneficiary: nominee, + ...defaults + } + nominateToken(privateKey, nominateParameter); + return { tokenRegistry, tokenId }; +} + +export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand) => { + const command = generateNominateCommand(nominateParameter, privateKey); + const results = run(command, true); + const frontFormat = `${emoji.tick} success Transferable record with hash `; + const middleFormat = `'s holder has been successfully nominated to new owner with address ` + const queryResults = extractLine(results, frontFormat); + if (!queryResults) throw new Error("Unable to nominate token"); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(frontFormat); + const checkContext = filteredLine.includes(middleFormat); + expect(checkSuccess && checkContext).toBe(true); + if (!checkSuccess || !checkContext) throw new Error("Unexpected nominate token format"); + const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); + expect(resultTokenId).toBe(nominateParameter.tokenId); + if (resultTokenId !== nominateParameter.tokenId) throw new Error("Unexpected nominate tokenid"); + const destination = filteredLine.trim().substring(filteredLine.length - 42); + if (destination !== nominateParameter.newBeneficiary) throw new Error("Unexpected nominee"); }; + diff --git a/src/__tests__/token-registry/change-holder.e2e.test.ts b/src/__tests__/token-registry/change-holder.e2e.test.ts new file mode 100644 index 00000000..22790378 --- /dev/null +++ b/src/__tests__/token-registry/change-holder.e2e.test.ts @@ -0,0 +1,58 @@ +import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { generateChangeHolderCommand } from "../fixture/e2e/commands"; + +describe("transfer holder title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + + const defaultTransferHolder = { + newHolder: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to transfer holder title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrow: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + ...defaultTitleEscrow, + } + mintToken(owner.privateKey, titleEscrow); + const transferHolder: TitleEscrowTransferHolderCommand = { + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + ...defaultTransferHolder, + } + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + const frontFormat = `${emoji.tick} success Transferable record with hash `; + const middleFormat = `'s holder has been successfully changed to holder with address: ` + const queryResults = extractLine(results, frontFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(frontFormat); + const checkContext = filteredLine.includes(middleFormat); + expect(checkSuccess && checkContext).toBe(true); + const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); + expect(resultTokenId).toBe(transferHolder.tokenId); + const destination = filteredLine.trim().substring(filteredLine.length - 42); + expect(destination).toBe(transferHolder.newHolder); + }); +}); diff --git a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts new file mode 100644 index 00000000..2a16fe13 --- /dev/null +++ b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts @@ -0,0 +1,71 @@ + +import { deployTokenRegistry, generateTokenId, mintToken, nominateToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { TitleEscrowEndorseTransferOfOwnersCommand, TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { generateTransferOwnersCommand } from "../fixture/e2e/commands"; + +describe("nominate title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + + const defaultTransferOwners = { + newOwner: receiver.ethAddress, + newHolder: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to nominate title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrow: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + ...defaultTitleEscrow, + } + mintToken(owner.privateKey, titleEscrow); + const nominateOnwer: TitleEscrowNominateBeneficiaryCommand = { + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + newBeneficiary: defaultTransferOwners.newOwner, + ...defaultTransferOwners, + } + const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + ...defaultTransferOwners, + } + nominateToken(owner.privateKey, nominateOnwer) + const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); + const results = run(command); + const frontFormat = `${emoji.tick} success Transferable record with hash `; + const middleFormat = `'s holder has been successfully endorsed to new owner with address ` + const rearFormat = ` and new holder with address: ` + const queryResults = extractLine(results, frontFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(frontFormat); + const checkOwner = filteredLine.includes(middleFormat); + const checkHolder = filteredLine.includes(rearFormat); + expect(checkSuccess && checkOwner && checkHolder).toBe(true); + const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); + expect(resultTokenId).toBe(transferOwners.tokenId); + const resultOwner = filteredLine.trim().substring(frontFormat.length + 66 + middleFormat.length, frontFormat.length + 66 + middleFormat.length + 42); + expect(resultOwner).toBe(transferOwners.newOwner); + const destination = filteredLine.trim().substring(filteredLine.length - 42); + expect(destination).toBe(transferOwners.newHolder); + }); +}); diff --git a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts new file mode 100644 index 00000000..a68d7bec --- /dev/null +++ b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts @@ -0,0 +1,60 @@ +import { deployTokenRegistry, generateTokenId, mintToken, nominateToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { generateEndorseTransferOwnerCommand } from "../fixture/e2e/commands"; + +describe("nominate title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + + const defaultTransferHolder = { + newBeneficiary: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to nominate title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrow: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + ...defaultTitleEscrow, + } + mintToken(owner.privateKey, titleEscrow); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + ...defaultTransferHolder, + } + nominateToken(owner.privateKey, transferHolder) + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey) + const results = run(command); + const frontFormat = `${emoji.tick} success Transferable record with hash `; + const middleFormat = `'s holder has been successfully endorsed to approved beneficiary at ` + const queryResults = extractLine(results, frontFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(frontFormat); + const checkContext = filteredLine.includes(middleFormat); + expect(checkSuccess && checkContext).toBe(true); + const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); + expect(resultTokenId).toBe(transferHolder.tokenId); + const destination = filteredLine.trim().substring(filteredLine.length - 42); + expect(destination).toBe(transferHolder.newBeneficiary); + }); +}); diff --git a/src/__tests__/token-registry/mint.e2e.test.ts b/src/__tests__/token-registry/mint.e2e.test.ts index a6414fa8..ff3d494f 100644 --- a/src/__tests__/token-registry/mint.e2e.test.ts +++ b/src/__tests__/token-registry/mint.e2e.test.ts @@ -1,7 +1,9 @@ import { deployTokenRegistry, generateTokenId } from "../fixture/e2e/utils"; import { run } from "../fixture/e2e/shell"; -import { emoji, network, owner } from "../fixture/e2e/constants"; +import { emoji, network, owner, silent } from "../fixture/e2e/constants"; import { isAddress } from "web3-utils"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { generateMintTitleEscrowCommand } from "../fixture/e2e/commands"; describe("deploy token-registry", () => { jest.setTimeout(90000); @@ -13,7 +15,16 @@ describe("deploy token-registry", () => { it("should be able to mint title-escrow on token-registry", async () => { const tokenId = generateTokenId(); - const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + } + // const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); diff --git a/src/__tests__/token-registry/nominate.e2e.test.ts b/src/__tests__/token-registry/nominate.e2e.test.ts new file mode 100644 index 00000000..9e9d3de1 --- /dev/null +++ b/src/__tests__/token-registry/nominate.e2e.test.ts @@ -0,0 +1,59 @@ +// title-escrow nominate-change-owner --token-registry 0x4933e30eF8A083f49d14759b2eafC94E56F0b3A7 --tokenId 0x951b39bcaddc0e8882883db48ca258ca35ccb01fee328355f0dfda1ff9be9990 --newOwner 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 + +import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { generateNominateCommand } from "../fixture/e2e/commands"; + +describe("nominate title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + const defaultTransferHolder = { + newBeneficiary: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to nominate title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrow: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + ...defaultTitleEscrow, + } + mintToken(owner.privateKey, titleEscrow); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + ...defaultTransferHolder, + } + const command = generateNominateCommand(transferHolder, owner.privateKey); + const results = run(command); + const frontFormat = `${emoji.tick} success Transferable record with hash `; + const middleFormat = `'s holder has been successfully nominated to new owner with address ` + const queryResults = extractLine(results, frontFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(frontFormat); + const checkContext = filteredLine.includes(middleFormat); + expect(checkSuccess && checkContext).toBe(true); + const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); + expect(resultTokenId).toBe(transferHolder.tokenId); + const destination = filteredLine.trim().substring(filteredLine.length - 42); + expect(destination).toBe(transferHolder.newBeneficiary); + }); +}); diff --git a/src/__tests__/token-registry/surrender.e2e.test.ts b/src/__tests__/token-registry/surrender.e2e.test.ts new file mode 100644 index 00000000..142d14ba --- /dev/null +++ b/src/__tests__/token-registry/surrender.e2e.test.ts @@ -0,0 +1,56 @@ +import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; +import { run } from "../fixture/e2e/shell"; +import { emoji, network, owner } from "../fixture/e2e/constants"; +import { isAddress } from "web3-utils"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; +import { defaultSeverityColor } from "snyk/dist/lib/snyk-test/common"; + +describe("surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + it.todo("surrender is not working ????"); + it("should be able to surrender title-escrow on token-registry", async () => { + expect(true).toBe(false); + // const tokenId = generateTokenId(); + // const surrenderTitleEscrow: TokenRegistryIssueCommand = { + // address: tokenRegistryAddress, + // tokenId: tokenId, + // ...defaultTitleEscrow, + // } + // const titleEscrowAddress = mintToken(owner.privateKey, surrenderTitleEscrow); + // console.log(titleEscrowAddress); + // const command = `npm run dev -- title-escrow surrender --token-registry ${surrenderTitleEscrow.address} --tokenId ${surrenderTitleEscrow.tokenId} -k ${owner.privateKey} --network ${surrenderTitleEscrow.network}`; + + // const results = run(command); + // const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; + // const checkSuccess = results.includes(tokenRegistrySuccessFormat); + // expect(checkSuccess).toBe(true); + // const splitResults = results.trim().split("\n"); + // const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; + // const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); + // expect(isAddress(tokenRegistryAddress)).toBe(true); + + // const tokenId = generateTokenId(); + // const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; + // const results = run(command); + // const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; + // const checkSuccess = results.includes(tokenRegistrySuccessFormat); + // expect(checkSuccess).toBe(true); + // const splitResults = results.trim().split("\n"); + // const titleEscrowAddressLine = splitResults[splitResults.length - 2]; + // const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); + // expect(isAddress(titleEscrowAddress)).toBe(true); + }); +}); diff --git a/src/commands/title-escrow/surrender-document.ts b/src/commands/title-escrow/surrender-document.ts index e418f635..275408ec 100644 --- a/src/commands/title-escrow/surrender-document.ts +++ b/src/commands/title-escrow/surrender-document.ts @@ -38,6 +38,7 @@ export const handler = async (args: TitleEscrowSurrenderDocumentCommand): Promis success(`Transferable record with hash ${args.tokenId} has been surrendered.`); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transaction.transactionHash}`); } catch (e) { + console.log(e) error(getErrorMessage(e)); } }; From a8d573a0441ef32d3c6ba701e43979041cbe64ec Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:11:31 +0800 Subject: [PATCH 46/63] feat: surrender complete --- src/__tests__/fixture/e2e/commands.ts | 76 ++++++++------ src/__tests__/fixture/e2e/shell.ts | 92 ++++++++--------- src/__tests__/fixture/e2e/utils.ts | 99 +++++++++++++------ .../accept-surrender.e2e.test.ts | 39 ++++++++ .../token-registry/change-holder.e2e.test.ts | 34 +++---- .../endorse-change-owner.e2e.test.ts | 54 +++++----- .../endorse-transfer.e2e.test.ts | 45 ++++----- src/__tests__/token-registry/mint.e2e.test.ts | 5 +- .../token-registry/nominate.e2e.test.ts | 20 ++-- .../reject-surrender.e2e.test.ts | 39 ++++++++ .../token-registry/surrender.e2e.test.ts | 56 +++++------ .../title-escrow/surrender-document.ts | 1 - 12 files changed, 329 insertions(+), 231 deletions(-) create mode 100644 src/__tests__/token-registry/accept-surrender.e2e.test.ts create mode 100644 src/__tests__/token-registry/reject-surrender.e2e.test.ts diff --git a/src/__tests__/fixture/e2e/commands.ts b/src/__tests__/fixture/e2e/commands.ts index 0910cee4..c7f4c273 100644 --- a/src/__tests__/fixture/e2e/commands.ts +++ b/src/__tests__/fixture/e2e/commands.ts @@ -1,55 +1,75 @@ import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -import { TitleEscrowEndorseTransferOfOwnersCommand, TitleEscrowNominateBeneficiaryCommand, TitleEscrowtransferOwnerCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { + BaseTitleEscrowCommand, + TitleEscrowEndorseTransferOfOwnersCommand, + TitleEscrowNominateBeneficiaryCommand, + TitleEscrowTransferHolderCommand, +} from "../../../commands/title-escrow/title-escrow-command.type"; import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; +const command = `npm run dev --`; + export const generateDeployTokenRegistryCommand = ( - tokenRegistryParameter: DeployTokenRegistryCommand, - privateKey: string + tokenRegistryParameter: DeployTokenRegistryCommand, + privateKey: string ): string => { - return `npm run dev -- deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} -n ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}`; + return `${command} deploy token-registry "${tokenRegistryParameter.registryName}" ${tokenRegistryParameter.registrySymbol} --network ${tokenRegistryParameter.network} -k ${privateKey} --factory-address ${tokenRegistryParameter.factoryAddress} --token-implementation-address ${tokenRegistryParameter.tokenImplementationAddress} --deployer-address ${tokenRegistryParameter.deployerAddress}`; }; export const generateDeployDocumentStoreCommand = ( - documentStoreParameter: DeployDocumentStoreCommand, - privateKey: string + documentStoreParameter: DeployDocumentStoreCommand, + privateKey: string ): string => { - return `npm run dev -- deploy document-store "${documentStoreParameter.storeName}" -n ${documentStoreParameter.network} -k ${privateKey}`; + return `${command} deploy document-store "${documentStoreParameter.storeName}" --network ${documentStoreParameter.network} -k ${privateKey}`; }; export const generateMintTitleEscrowCommand = ( - titleEscrowParameter: TokenRegistryIssueCommand, - privateKey: string + titleEscrowParameter: TokenRegistryIssueCommand, + privateKey: string ): string => { - return `npm run dev -- token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} -n ${titleEscrowParameter.network}`; + return `${command} token-registry mint --address ${titleEscrowParameter.address} --tokenId ${titleEscrowParameter.tokenId} --beneficiary ${titleEscrowParameter.beneficiary} --holder ${titleEscrowParameter.holder} -k ${privateKey} --network ${titleEscrowParameter.network}`; }; export const generateChangeHolderCommand = ( - changeHolderParameter: TitleEscrowtransferOwnerCommand, - privateKey: string + changeHolderParameter: TitleEscrowTransferHolderCommand, + privateKey: string ): string => { - return `npm run dev -- title-escrow change-holder --token-registry ${changeHolderParameter.tokenRegistry} --tokenId ${changeHolderParameter.tokenId} --newHolder ${changeHolderParameter.newHolder} -k ${privateKey} --network ${changeHolderParameter.network}`; + return `${command} title-escrow change-holder --token-registry ${changeHolderParameter.tokenRegistry} --tokenId ${changeHolderParameter.tokenId} --newHolder ${changeHolderParameter.newHolder} -k ${privateKey} --network ${changeHolderParameter.network}`; }; export const generateTransferOwnersCommand = ( - transferOwners: TitleEscrowEndorseTransferOfOwnersCommand, - privateKey: string + transferOwners: TitleEscrowEndorseTransferOfOwnersCommand, + privateKey: string ): string => { - return `npm run dev -- title-escrow endorse-change-owner --token-registry ${transferOwners.tokenRegistry} --tokenId ${transferOwners.tokenId} --newOwner ${transferOwners.newOwner} --newHolder ${transferOwners.newHolder} -k ${privateKey} --network ${transferOwners.network}`; -} + return `${command} title-escrow endorse-change-owner --token-registry ${transferOwners.tokenRegistry} --tokenId ${transferOwners.tokenId} --newOwner ${transferOwners.newOwner} --newHolder ${transferOwners.newHolder} -k ${privateKey} --network ${transferOwners.network}`; +}; export const generateEndorseTransferOwnerCommand = ( - transferOwner: TitleEscrowNominateBeneficiaryCommand, - privateKey: string + transferOwner: TitleEscrowNominateBeneficiaryCommand, + privateKey: string ): string => { -// const command = `npm run dev -- title-escrow endorse-transfer-owner --token-registry ${transferHolder.tokenRegistry} --tokenId ${transferHolder.tokenId} --newBeneficiary ${transferHolder.newBeneficiary} -k ${owner.privateKey} --network ${transferHolder.network}`; - return `npm run dev -- title-escrow endorse-transfer-owner --token-registry ${transferOwner.tokenRegistry} --tokenId ${transferOwner.tokenId} --newBeneficiary ${transferOwner.newBeneficiary} -k ${privateKey} --network ${transferOwner.network}`; -} - + return `${command} title-escrow endorse-transfer-owner --token-registry ${transferOwner.tokenRegistry} --tokenId ${transferOwner.tokenId} --newBeneficiary ${transferOwner.newBeneficiary} -k ${privateKey} --network ${transferOwner.network}`; +}; export const generateNominateCommand = ( - nominateParameter: TitleEscrowNominateBeneficiaryCommand, - privateKey: string + nominateParameter: TitleEscrowNominateBeneficiaryCommand, + privateKey: string ): string => { -// const command = `npm run dev -- title-escrow nominate-change-owner --token-registry ${transferHolder.tokenRegistry} --tokenId ${transferHolder.tokenId} --newOwner ${transferHolder.newBeneficiary} -k ${owner.privateKey} --network ${transferHolder.network}`; - return `npm run dev -- title-escrow nominate-change-owner --token-registry ${nominateParameter.tokenRegistry} --tokenId ${nominateParameter.tokenId} --newOwner ${nominateParameter.newBeneficiary} -k ${privateKey} --network ${nominateParameter.network}`; -} + return `${command} title-escrow nominate-change-owner --token-registry ${nominateParameter.tokenRegistry} --tokenId ${nominateParameter.tokenId} --newOwner ${nominateParameter.newBeneficiary} -k ${privateKey} --network ${nominateParameter.network}`; +}; +export const generateSurrenderCommand = (surrenderParameter: BaseTitleEscrowCommand, privateKey: string): string => { + return `${command} title-escrow surrender --token-registry ${surrenderParameter.tokenRegistry} --tokenId ${surrenderParameter.tokenId} -k ${privateKey} --network ${surrenderParameter.network}`; +}; + +export const generateRejectSurrenderCommand = ( + surrenderParameter: BaseTitleEscrowCommand, + privateKey: string +): string => { + return `${command} title-escrow reject-surrendered --token-registry ${surrenderParameter.tokenRegistry} --tokenId ${surrenderParameter.tokenId} --network ${surrenderParameter.network} -k ${privateKey}`; +}; +export const generateAcceptSurrenderCommand = ( + surrenderParameter: BaseTitleEscrowCommand, + privateKey: string +): string => { + return `${command} title-escrow accept-surrendered --token-registry ${surrenderParameter.tokenRegistry} --tokenId ${surrenderParameter.tokenId} --network ${surrenderParameter.network} -k ${privateKey}`; +}; diff --git a/src/__tests__/fixture/e2e/shell.ts b/src/__tests__/fixture/e2e/shell.ts index 15c0e80f..e33a3fb3 100644 --- a/src/__tests__/fixture/e2e/shell.ts +++ b/src/__tests__/fixture/e2e/shell.ts @@ -4,71 +4,71 @@ import { emoji, verbose } from "./constants"; shell.config.silent = true; export interface LineInfo { - lineNumber: number; - lineContent: string; + lineNumber: number; + lineContent: string; } export const run = (command: string, silent = false): string => { - shell.config.silent = !(!silent && verbose); - const rawResults: ShellString = shell.exec(command); - const results = stripAnsi(rawResults.trim()); - if (!silent) { - const success = `${emoji.tick} success`; - const failure = `${emoji.cross} error`; - let successLines = extractLine(results, success); - if (!successLines) successLines = []; - let failureLines = extractLine(results, failure); - if (!failureLines) failureLines = []; - const statusLines: LineInfo[] = [...successLines, ...failureLines]; - log(command); - printLines(statusLines); - if(verbose && failureLines.length > 0) log(rawResults) - } - return results; + shell.config.silent = !(!silent && verbose); + const rawResults: ShellString = shell.exec(command); + const results = stripAnsi(rawResults.trim()); + if (!silent) { + const success = `${emoji.tick} success`; + const failure = `${emoji.cross} error`; + let successLines = extractLine(results, success); + if (!successLines) successLines = []; + let failureLines = extractLine(results, failure); + if (!failureLines) failureLines = []; + const statusLines: LineInfo[] = [...successLines, ...failureLines]; + log(command); + printLines(statusLines); + if (verbose && failureLines.length > 0) log(rawResults); + } + return results; }; export const printLines = (lines: LineInfo[]): void => { - lines.sort((a: LineInfo, b: LineInfo): number => { - return a.lineNumber - b.lineNumber; - }); - for (const line of lines) { - log(`${line.lineNumber}: ${line.lineContent}`); - } + lines.sort((a: LineInfo, b: LineInfo): number => { + return a.lineNumber - b.lineNumber; + }); + for (const line of lines) { + log(`${line.lineNumber}: ${line.lineContent}`); + } }; export const extractLine = (result: string, query: string): LineInfo[] | void => { - const splitResults = result.trim().split("\n"); - const matchedLines = []; - for (let count = 0; count < splitResults.length; count++) { - const line = splitResults[count].trim(); - const containsQueryString = line.includes(query); - if (containsQueryString) { - matchedLines.push({ - lineNumber: count, - lineContent: line, - }); - } + const splitResults = result.trim().split("\n"); + const matchedLines = []; + for (let count = 0; count < splitResults.length; count++) { + const line = splitResults[count].trim(); + const containsQueryString = line.includes(query); + if (containsQueryString) { + matchedLines.push({ + lineNumber: count, + lineContent: line, + }); } - if (matchedLines.length > 0) return matchedLines; - else return; + } + if (matchedLines.length > 0) return matchedLines; + else return; }; // https://github.com/chalk/strip-ansi/blob/main/index.js export function stripAnsi(ansiString: string): string { - if (typeof ansiString !== "string") { - throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); - } - return ansiString.replace(ansiRegex(), ""); + if (typeof ansiString !== "string") { + throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); + } + return ansiString.replace(ansiRegex(), ""); } // https://github.com/chalk/ansi-regex/blob/main/index.js export function ansiRegex({ onlyFirst = false } = {}): RegExp { - const pattern = [ - "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", - "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", - ].join("|"); + const pattern = [ + "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", + "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", + ].join("|"); - return new RegExp(pattern, onlyFirst ? undefined : "g"); + return new RegExp(pattern, onlyFirst ? undefined : "g"); } export { shell, ShellString }; diff --git a/src/__tests__/fixture/e2e/utils.ts b/src/__tests__/fixture/e2e/utils.ts index 95885205..b4b94268 100644 --- a/src/__tests__/fixture/e2e/utils.ts +++ b/src/__tests__/fixture/e2e/utils.ts @@ -9,8 +9,17 @@ import { generateDeployTokenRegistryCommand, generateMintTitleEscrowCommand, generateNominateCommand, + generateSurrenderCommand, } from "./commands"; -import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { + BaseTitleEscrowCommand, + TitleEscrowNominateBeneficiaryCommand, +} from "../../../commands/title-escrow/title-escrow-command.type"; +export interface TokenInfo { + tokenRegistry: string; + tokenId: string; + titleEscrowAddress?: string; +} const defaults = { network: network, @@ -28,8 +37,8 @@ export const deployTokenRegistry = ( if (!tokenRegistryParameters) { const index = numberGenerator(100); tokenRegistryParameters = { - registryName: `Test Tokenx ${index}`, - registrySymbol: `TKNx${index}`, + registryName: `Test Token ${index}`, + registrySymbol: `TKN${index}`, factoryAddress: creators.titleEscrowFactory, tokenImplementationAddress: creators.tokenImplementation, deployerAddress: creators.deployer, @@ -71,9 +80,10 @@ export const deployDocumentStore = ( return documentStoreAddress; }; +const retries = 10; const usedTokenIds = new Set(); export const generateTokenId = (): string => { - for (let count = 0; count < 10; count = count + 1) { + for (let count = 0; count < retries; count = count + 1) { const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join("")}`; const unique = !usedTokenIds.has(generatedTokenId); if (unique) { @@ -84,24 +94,24 @@ export const generateTokenId = (): string => { throw new Error("Unable to generate tokenIds"); }; -export interface TokenInfo { - tokenRegistry: string, - tokenId: string, - titleEscrowAddress?: string, -} - -export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegistryIssueCommand): TokenInfo => { - if (!titleEscrowParameter) { - const wallet = new Wallet(privateKey); - titleEscrowParameter = { - address: deployTokenRegistry(privateKey), - beneficiary: wallet.address, - holder: wallet.address, - tokenId: generateTokenId(), - ...defaults, - }; +export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { + if (!tokenRegistryAddress) { + tokenRegistryAddress = deployTokenRegistry(privateKey); } + if (!isAddress(tokenRegistryAddress)) throw new Error("Invalid Token Registry Address"); + const wallet = new Wallet(privateKey); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + beneficiary: wallet.address, + holder: wallet.address, + tokenId: generateTokenId(), + ...defaults, + }; + return mintToken(privateKey, titleEscrowParameter); +}; + +export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); const results = run(command, true); const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; @@ -111,41 +121,68 @@ export const mintToken = (privateKey: string, titleEscrowParameter?: TokenRegist const titleEscrowAddressLine = splitResults[splitResults.length - 2]; const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); + if (titleEscrowAddress !== titleEscrowParameter.tokenId) throw new Error("tokenId mismatch"); return { tokenRegistry: titleEscrowParameter.address, tokenId: titleEscrowParameter.tokenId, - titleEscrowAddress + titleEscrowAddress, }; }; -export const mintNominatedToken = (privateKey: string, nominee: string) => { - const { tokenRegistry, tokenId } = mintToken(privateKey); +export const mintNominatedToken = (privateKey: string, nominee: string, tokenRegistryAddress?: string): TokenInfo => { + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = tokenDetails; const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { tokenId: tokenId, tokenRegistry: tokenRegistry, newBeneficiary: nominee, - ...defaults - } + ...defaults, + }; nominateToken(privateKey, nominateParameter); - return { tokenRegistry, tokenId }; -} + return tokenDetails; +}; -export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand) => { +export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { const command = generateNominateCommand(nominateParameter, privateKey); const results = run(command, true); const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully nominated to new owner with address ` + const middleFormat = `'s holder has been successfully nominated to new owner with address `; const queryResults = extractLine(results, frontFormat); if (!queryResults) throw new Error("Unable to nominate token"); const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); const checkSuccess = filteredLine.includes(frontFormat); const checkContext = filteredLine.includes(middleFormat); - expect(checkSuccess && checkContext).toBe(true); if (!checkSuccess || !checkContext) throw new Error("Unexpected nominate token format"); const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - expect(resultTokenId).toBe(nominateParameter.tokenId); if (resultTokenId !== nominateParameter.tokenId) throw new Error("Unexpected nominate tokenid"); const destination = filteredLine.trim().substring(filteredLine.length - 42); if (destination !== nominateParameter.newBeneficiary) throw new Error("Unexpected nominee"); }; +export const mintSurrenderToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = tokenDetails; + const surrenderParameter: BaseTitleEscrowCommand = { + tokenRegistry: tokenRegistry, + tokenId: tokenId, + ...defaults, + }; + surrenderToken(privateKey, surrenderParameter); + return tokenDetails; +}; + +export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { + const command = generateSurrenderCommand(surrenderParameter, privateKey); + const results = run(command); + + const tokenRegistrySuccessFormat = `${emoji.tick} success Transferable record with hash `; + const queryResults = extractLine(results, tokenRegistrySuccessFormat); + if (!queryResults) throw new Error("Unable to surrender token"); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); + if (!checkSuccess) throw new Error("Unexpected surrender token format"); + const resultTokenId = filteredLine + .trim() + .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); + if (resultTokenId !== surrenderParameter.tokenId) throw new Error("Unexpected surrendered token"); +}; diff --git a/src/__tests__/token-registry/accept-surrender.e2e.test.ts b/src/__tests__/token-registry/accept-surrender.e2e.test.ts new file mode 100644 index 00000000..19ef40f7 --- /dev/null +++ b/src/__tests__/token-registry/accept-surrender.e2e.test.ts @@ -0,0 +1,39 @@ +import { deployTokenRegistry, mintSurrenderToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner } from "../fixture/e2e/constants"; +import { generateAcceptSurrenderCommand } from "../fixture/e2e/commands"; + +describe("surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to surrender title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + + const tokenRegistrySuccessFormat = `${emoji.tick} success Surrendered transferable record with hash `; + const queryResults = extractLine(results, tokenRegistrySuccessFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const resultTokenId = filteredLine + .trim() + .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); + expect(resultTokenId).toBe(tokenId); + }); + + it.todo("should be fail when permission is denied"); +}); diff --git a/src/__tests__/token-registry/change-holder.e2e.test.ts b/src/__tests__/token-registry/change-holder.e2e.test.ts index 22790378..c64538fd 100644 --- a/src/__tests__/token-registry/change-holder.e2e.test.ts +++ b/src/__tests__/token-registry/change-holder.e2e.test.ts @@ -1,7 +1,6 @@ -import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; +import { deployTokenRegistry, mintTokenRegistry } from "../fixture/e2e/utils"; import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateChangeHolderCommand } from "../fixture/e2e/commands"; @@ -13,13 +12,12 @@ describe("transfer holder title-escrow", () => { tokenRegistryAddress = deployTokenRegistry(owner.privateKey); }); - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - + // const defaultTitleEscrow = { + // beneficiary: owner.ethAddress, + // holder: owner.ethAddress, + // network: network, + // dryRun: false, + // }; const defaultTransferHolder = { newHolder: receiver.ethAddress, @@ -28,22 +26,16 @@ describe("transfer holder title-escrow", () => { }; it("should be able to transfer holder title-escrow on token-registry", async () => { - const tokenId = generateTokenId(); - const titleEscrow: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - ...defaultTitleEscrow, - } - mintToken(owner.privateKey, titleEscrow); + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - ...defaultTransferHolder, - } + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferHolder, + }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully changed to holder with address: ` + const middleFormat = `'s holder has been successfully changed to holder with address: `; const queryResults = extractLine(results, frontFormat); expect(queryResults).toBeTruthy(); const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); diff --git a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts index 2a16fe13..c6209848 100644 --- a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts +++ b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts @@ -1,9 +1,7 @@ - -import { deployTokenRegistry, generateTokenId, mintToken, nominateToken } from "../fixture/e2e/utils"; +import { deployTokenRegistry, mintNominatedToken } from "../fixture/e2e/utils"; import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { TitleEscrowEndorseTransferOfOwnersCommand, TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateTransferOwnersCommand } from "../fixture/e2e/commands"; describe("nominate title-escrow", () => { @@ -14,13 +12,12 @@ describe("nominate title-escrow", () => { tokenRegistryAddress = deployTokenRegistry(owner.privateKey); }); - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - + // const defaultTitleEscrow = { + // beneficiary: owner.ethAddress, + // holder: owner.ethAddress, + // network: network, + // dryRun: false, + // }; const defaultTransferOwners = { newOwner: receiver.ethAddress, @@ -30,30 +27,21 @@ describe("nominate title-escrow", () => { }; it("should be able to nominate title-escrow on token-registry", async () => { - const tokenId = generateTokenId(); - const titleEscrow: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - ...defaultTitleEscrow, - } - mintToken(owner.privateKey, titleEscrow); - const nominateOnwer: TitleEscrowNominateBeneficiaryCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - newBeneficiary: defaultTransferOwners.newOwner, - ...defaultTransferOwners, - } + const { tokenRegistry, tokenId } = mintNominatedToken( + owner.privateKey, + defaultTransferOwners.newOwner, + tokenRegistryAddress + ); const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - ...defaultTransferOwners, - } - nominateToken(owner.privateKey, nominateOnwer) + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferOwners, + }; const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully endorsed to new owner with address ` - const rearFormat = ` and new holder with address: ` + const middleFormat = `'s holder has been successfully endorsed to new owner with address `; + const rearFormat = ` and new holder with address: `; const queryResults = extractLine(results, frontFormat); expect(queryResults).toBeTruthy(); const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); @@ -63,7 +51,9 @@ describe("nominate title-escrow", () => { expect(checkSuccess && checkOwner && checkHolder).toBe(true); const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); expect(resultTokenId).toBe(transferOwners.tokenId); - const resultOwner = filteredLine.trim().substring(frontFormat.length + 66 + middleFormat.length, frontFormat.length + 66 + middleFormat.length + 42); + const resultOwner = filteredLine + .trim() + .substring(frontFormat.length + 66 + middleFormat.length, frontFormat.length + 66 + middleFormat.length + 42); expect(resultOwner).toBe(transferOwners.newOwner); const destination = filteredLine.trim().substring(filteredLine.length - 42); expect(destination).toBe(transferOwners.newHolder); diff --git a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts index a68d7bec..d188ef58 100644 --- a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts +++ b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts @@ -1,8 +1,7 @@ -import { deployTokenRegistry, generateTokenId, mintToken, nominateToken } from "../fixture/e2e/utils"; +import { deployTokenRegistry, mintNominatedToken } from "../fixture/e2e/utils"; import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateEndorseTransferOwnerCommand } from "../fixture/e2e/commands"; describe("nominate title-escrow", () => { @@ -13,13 +12,12 @@ describe("nominate title-escrow", () => { tokenRegistryAddress = deployTokenRegistry(owner.privateKey); }); - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - + // const defaultTitleEscrow = { + // beneficiary: owner.ethAddress, + // holder: owner.ethAddress, + // network: network, + // dryRun: false, + // }; const defaultTransferHolder = { newBeneficiary: receiver.ethAddress, @@ -28,24 +26,21 @@ describe("nominate title-escrow", () => { }; it("should be able to nominate title-escrow on token-registry", async () => { - const tokenId = generateTokenId(); - const titleEscrow: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - ...defaultTitleEscrow, - } - mintToken(owner.privateKey, titleEscrow); + const { tokenRegistry, tokenId } = mintNominatedToken( + owner.privateKey, + defaultTransferHolder.newBeneficiary, + tokenRegistryAddress + ); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - ...defaultTransferHolder, - } - nominateToken(owner.privateKey, transferHolder) - - const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey) + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferHolder, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully endorsed to approved beneficiary at ` + const middleFormat = `'s holder has been successfully endorsed to approved beneficiary at `; const queryResults = extractLine(results, frontFormat); expect(queryResults).toBeTruthy(); const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); diff --git a/src/__tests__/token-registry/mint.e2e.test.ts b/src/__tests__/token-registry/mint.e2e.test.ts index ff3d494f..98ed5348 100644 --- a/src/__tests__/token-registry/mint.e2e.test.ts +++ b/src/__tests__/token-registry/mint.e2e.test.ts @@ -1,6 +1,6 @@ import { deployTokenRegistry, generateTokenId } from "../fixture/e2e/utils"; import { run } from "../fixture/e2e/shell"; -import { emoji, network, owner, silent } from "../fixture/e2e/constants"; +import { emoji, network, owner } from "../fixture/e2e/constants"; import { isAddress } from "web3-utils"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { generateMintTitleEscrowCommand } from "../fixture/e2e/commands"; @@ -22,8 +22,7 @@ describe("deploy token-registry", () => { holder: owner.ethAddress, network: network, dryRun: false, - } - // const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; + }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; diff --git a/src/__tests__/token-registry/nominate.e2e.test.ts b/src/__tests__/token-registry/nominate.e2e.test.ts index 9e9d3de1..7fda263c 100644 --- a/src/__tests__/token-registry/nominate.e2e.test.ts +++ b/src/__tests__/token-registry/nominate.e2e.test.ts @@ -4,7 +4,7 @@ import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/ import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateNominateCommand } from "../fixture/e2e/commands"; describe("nominate title-escrow", () => { @@ -31,20 +31,20 @@ describe("nominate title-escrow", () => { it("should be able to nominate title-escrow on token-registry", async () => { const tokenId = generateTokenId(); const titleEscrow: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - ...defaultTitleEscrow, - } + address: tokenRegistryAddress, + tokenId: tokenId, + ...defaultTitleEscrow, + }; mintToken(owner.privateKey, titleEscrow); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - ...defaultTransferHolder, - } + tokenId: titleEscrow.tokenId, + tokenRegistry: titleEscrow.address, + ...defaultTransferHolder, + }; const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully nominated to new owner with address ` + const middleFormat = `'s holder has been successfully nominated to new owner with address `; const queryResults = extractLine(results, frontFormat); expect(queryResults).toBeTruthy(); const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); diff --git a/src/__tests__/token-registry/reject-surrender.e2e.test.ts b/src/__tests__/token-registry/reject-surrender.e2e.test.ts new file mode 100644 index 00000000..551225a2 --- /dev/null +++ b/src/__tests__/token-registry/reject-surrender.e2e.test.ts @@ -0,0 +1,39 @@ +import { deployTokenRegistry, mintSurrenderToken } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; +import { emoji, network, owner } from "../fixture/e2e/constants"; +import { generateRejectSurrenderCommand } from "../fixture/e2e/commands"; + +describe("surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to surrender title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + + const tokenRegistrySuccessFormat = `${emoji.tick} success Surrendered transferable record with hash `; + const queryResults = extractLine(results, tokenRegistrySuccessFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const resultTokenId = filteredLine + .trim() + .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); + expect(resultTokenId).toBe(tokenId); + }); + + it.todo("should be fail when user without permission attempts reject surrender"); +}); diff --git a/src/__tests__/token-registry/surrender.e2e.test.ts b/src/__tests__/token-registry/surrender.e2e.test.ts index 142d14ba..9cc8d7ea 100644 --- a/src/__tests__/token-registry/surrender.e2e.test.ts +++ b/src/__tests__/token-registry/surrender.e2e.test.ts @@ -1,9 +1,8 @@ -import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; -import { run } from "../fixture/e2e/shell"; +import { deployTokenRegistry, mintTokenRegistry } from "../fixture/e2e/utils"; +import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner } from "../fixture/e2e/constants"; -import { isAddress } from "web3-utils"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { defaultSeverityColor } from "snyk/dist/lib/snyk-test/common"; +import { BaseTitleEscrowCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { generateSurrenderCommand } from "../fixture/e2e/commands"; describe("surrender title-escrow", () => { jest.setTimeout(90000); @@ -20,37 +19,26 @@ describe("surrender title-escrow", () => { dryRun: false, }; - it.todo("surrender is not working ????"); it("should be able to surrender title-escrow on token-registry", async () => { - expect(true).toBe(false); - // const tokenId = generateTokenId(); - // const surrenderTitleEscrow: TokenRegistryIssueCommand = { - // address: tokenRegistryAddress, - // tokenId: tokenId, - // ...defaultTitleEscrow, - // } - // const titleEscrowAddress = mintToken(owner.privateKey, surrenderTitleEscrow); - // console.log(titleEscrowAddress); - // const command = `npm run dev -- title-escrow surrender --token-registry ${surrenderTitleEscrow.address} --tokenId ${surrenderTitleEscrow.tokenId} -k ${owner.privateKey} --network ${surrenderTitleEscrow.network}`; + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + tokenRegistry, + tokenId, + ...defaultTitleEscrow, + }; - // const results = run(command); - // const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; - // const checkSuccess = results.includes(tokenRegistrySuccessFormat); - // expect(checkSuccess).toBe(true); - // const splitResults = results.trim().split("\n"); - // const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; - // const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); - // expect(isAddress(tokenRegistryAddress)).toBe(true); + const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); + const results = run(command); - // const tokenId = generateTokenId(); - // const command = `npm run dev -- token-registry mint --address ${tokenRegistryAddress} --tokenId ${tokenId} --beneficiary ${owner.ethAddress} --holder ${owner.ethAddress} -k ${owner.privateKey} --network ${network}`; - // const results = run(command); - // const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; - // const checkSuccess = results.includes(tokenRegistrySuccessFormat); - // expect(checkSuccess).toBe(true); - // const splitResults = results.trim().split("\n"); - // const titleEscrowAddressLine = splitResults[splitResults.length - 2]; - // const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); - // expect(isAddress(titleEscrowAddress)).toBe(true); + const tokenRegistrySuccessFormat = `${emoji.tick} success Transferable record with hash `; + const queryResults = extractLine(results, tokenRegistrySuccessFormat); + expect(queryResults).toBeTruthy(); + const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); + const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); + expect(checkSuccess).toBe(true); + const resultTokenId = filteredLine + .trim() + .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); + expect(resultTokenId).toBe(surrenderTitleEscrow.tokenId); }); }); diff --git a/src/commands/title-escrow/surrender-document.ts b/src/commands/title-escrow/surrender-document.ts index 275408ec..e418f635 100644 --- a/src/commands/title-escrow/surrender-document.ts +++ b/src/commands/title-escrow/surrender-document.ts @@ -38,7 +38,6 @@ export const handler = async (args: TitleEscrowSurrenderDocumentCommand): Promis success(`Transferable record with hash ${args.tokenId} has been surrendered.`); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transaction.transactionHash}`); } catch (e) { - console.log(e) error(getErrorMessage(e)); } }; From 3de6ad26345cd60e57dd2169511da001fc10efaa Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 7 Dec 2022 17:14:32 +0800 Subject: [PATCH 47/63] feat: update token-registry to 4.1.2 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index af0ad84d..3d51cb1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1999,9 +1999,9 @@ } }, "@govtechsg/token-registry": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.1.0.tgz", - "integrity": "sha512-GuOM9aYIcOwInczKq9YVpM1q0R5tI1kT7Lz62r2u2IkDLjaDgSiEU9wR1oqTsY+sXINDKgm2qyDj/XMNwMt62g==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@govtechsg/token-registry/-/token-registry-4.1.2.tgz", + "integrity": "sha512-RD/J868KB36QIuQ+sjEO5hIEmLi+Mc7ft/H2WVVBR2bfRjNhH1Q//bw4yvZBuodLgbUWC5ybHOkLk2mvE3fwOg==", "requires": { "@typechain/ethers-v5": "~10.0.0" } diff --git a/package.json b/package.json index ffe2fda9..0ff7b120 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "@govtechsg/oa-encryption": "^1.3.3", "@govtechsg/oa-verify": "^7.11.0", "@govtechsg/open-attestation": "^6.4.1", - "@govtechsg/token-registry": "^4.1.0", + "@govtechsg/token-registry": "^4.1.2", "ajv": "^8.4.0", "ajv-formats": "^2.1.0", "chalk": "^4.1.2", From d4995eda85cb5e7ec6e175f7f1b4820ee4109ece Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:01:28 +0800 Subject: [PATCH 48/63] fix: rename --- package.json | 2 +- src/__tests__/fixture/e2e/constants.ts | 2 +- src/__tests__/fixture/e2e/utils.ts | 1 - src/__tests__/token-registry/accept-surrender.e2e.test.ts | 4 ++-- src/__tests__/token-registry/endorse-change-owner.e2e.test.ts | 4 ++-- src/__tests__/token-registry/endorse-transfer.e2e.test.ts | 4 ++-- src/__tests__/token-registry/reject-surrender.e2e.test.ts | 4 ++-- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index 7a4e31b2..fc7342b1 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", - "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --miner.blockTime 12", + "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", diff --git a/src/__tests__/fixture/e2e/constants.ts b/src/__tests__/fixture/e2e/constants.ts index 5c3d3fef..c0f94982 100644 --- a/src/__tests__/fixture/e2e/constants.ts +++ b/src/__tests__/fixture/e2e/constants.ts @@ -32,4 +32,4 @@ export const emoji = { }; export const silent = true; -export const verbose = true; +export const verbose = false; diff --git a/src/__tests__/fixture/e2e/utils.ts b/src/__tests__/fixture/e2e/utils.ts index b4b94268..e8fdd73f 100644 --- a/src/__tests__/fixture/e2e/utils.ts +++ b/src/__tests__/fixture/e2e/utils.ts @@ -121,7 +121,6 @@ export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistr const titleEscrowAddressLine = splitResults[splitResults.length - 2]; const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); - if (titleEscrowAddress !== titleEscrowParameter.tokenId) throw new Error("tokenId mismatch"); return { tokenRegistry: titleEscrowParameter.address, tokenId: titleEscrowParameter.tokenId, diff --git a/src/__tests__/token-registry/accept-surrender.e2e.test.ts b/src/__tests__/token-registry/accept-surrender.e2e.test.ts index 19ef40f7..f5afce54 100644 --- a/src/__tests__/token-registry/accept-surrender.e2e.test.ts +++ b/src/__tests__/token-registry/accept-surrender.e2e.test.ts @@ -3,7 +3,7 @@ import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner } from "../fixture/e2e/constants"; import { generateAcceptSurrenderCommand } from "../fixture/e2e/commands"; -describe("surrender title-escrow", () => { +describe("accept-surrender title-escrow", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; @@ -18,7 +18,7 @@ describe("surrender title-escrow", () => { dryRun: false, }; - it("should be able to surrender title-escrow on token-registry", async () => { + it("should be able to accept-surrender title-escrow on token-registry", async () => { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); diff --git a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts index c6209848..9fce049e 100644 --- a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts +++ b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts @@ -4,7 +4,7 @@ import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateTransferOwnersCommand } from "../fixture/e2e/commands"; -describe("nominate title-escrow", () => { +describe("endorse change owner title-escrow", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; @@ -26,7 +26,7 @@ describe("nominate title-escrow", () => { dryRun: false, }; - it("should be able to nominate title-escrow on token-registry", async () => { + it("should be able to endorse change owner title-escrow on token-registry", async () => { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, defaultTransferOwners.newOwner, diff --git a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts index d188ef58..bf189829 100644 --- a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts +++ b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts @@ -4,7 +4,7 @@ import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { generateEndorseTransferOwnerCommand } from "../fixture/e2e/commands"; -describe("nominate title-escrow", () => { +describe("endorse transfer title-escrow", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; @@ -25,7 +25,7 @@ describe("nominate title-escrow", () => { dryRun: false, }; - it("should be able to nominate title-escrow on token-registry", async () => { + it("should be able to endorse transfer title-escrow on token-registry", async () => { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, defaultTransferHolder.newBeneficiary, diff --git a/src/__tests__/token-registry/reject-surrender.e2e.test.ts b/src/__tests__/token-registry/reject-surrender.e2e.test.ts index 551225a2..44671292 100644 --- a/src/__tests__/token-registry/reject-surrender.e2e.test.ts +++ b/src/__tests__/token-registry/reject-surrender.e2e.test.ts @@ -3,7 +3,7 @@ import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; import { emoji, network, owner } from "../fixture/e2e/constants"; import { generateRejectSurrenderCommand } from "../fixture/e2e/commands"; -describe("surrender title-escrow", () => { +describe("reject surrender title-escrow", () => { jest.setTimeout(90000); let tokenRegistryAddress = ""; @@ -18,7 +18,7 @@ describe("surrender title-escrow", () => { dryRun: false, }; - it("should be able to surrender title-escrow on token-registry", async () => { + it("should be able to reject surrender title-escrow on token-registry", async () => { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); From 3dbe1abaebba5eec0bf6536e10104f790f8577ca Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:57:43 +0800 Subject: [PATCH 49/63] fix: lint --- src/implementations/deploy/token-registry/token-registry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 6b6d3a0e..9ae3f288 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -22,7 +22,7 @@ export const deployTokenRegistry = async ({ dryRun, passedOnWallet, // passedOnWallet variable will only be used if we are calling it from create. ...rest -}: DeployTokenRegistryCommand): Promise<{contractAddress: string}> => { +}: DeployTokenRegistryCommand): Promise<{ contractAddress: string }> => { const wallet = passedOnWallet ? passedOnWallet : await getWalletOrSigner({ network, ...rest }); const chainId = await wallet.getChainId(); const deployContractAddressInput: DeployContractAddress = { From 0fdd1510ab454c56ea61e25dc7ae125c734dffa2 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 7 Dec 2022 18:58:14 +0800 Subject: [PATCH 50/63] fix: lint --- src/implementations/deploy/token-registry/token-registry.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/implementations/deploy/token-registry/token-registry.ts b/src/implementations/deploy/token-registry/token-registry.ts index 9ae3f288..e243113e 100644 --- a/src/implementations/deploy/token-registry/token-registry.ts +++ b/src/implementations/deploy/token-registry/token-registry.ts @@ -3,11 +3,9 @@ import { BigNumber, ethers } from "ethers"; import { DeploymentEvent } from "@govtechsg/token-registry/dist/contracts/contracts/utils/TDocDeployer"; import { utils } from "@govtechsg/token-registry"; import { DeployContractAddress, encodeInitParams, retrieveFactoryAddress } from "./helpers"; -import { TransactionReceipt } from "@ethersproject/providers"; import signale from "signale"; import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; import { getLogger } from "../../../logger"; -import { dryRunMode } from "../../utils/dryRun"; import { getWalletOrSigner } from "../../utils/wallet"; const { trace } = getLogger("deploy:token-registry"); From 4799fea13a690762cd16d2eb354a58bd627d6479 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 6 Jan 2023 16:11:15 +0800 Subject: [PATCH 51/63] feat: tests --- package-lock.json | 464 +++++++++++++++++- package.json | 2 + src/__tests__/fixture/e2e/utils.ts | 187 ------- .../accept-surrender.e2e.test.ts | 39 -- .../token-registry/change-holder.e2e.test.ts | 50 -- .../endorse-change-owner.e2e.test.ts | 61 --- .../endorse-transfer.e2e.test.ts | 55 --- src/__tests__/token-registry/mint.e2e.test.ts | 36 -- .../token-registry/nominate.e2e.test.ts | 59 --- .../reject-surrender.e2e.test.ts | 39 -- .../token-registry/surrender.e2e.test.ts | 44 -- .../title-escrow/accept-surrendered.ts | 1 + src/e2e/accept-surrender.test.ts | 60 +++ src/e2e/change-holder.test.ts | 103 ++++ .../deploy.e2e.test.ts => e2e/deploy.test.ts} | 41 +- src/e2e/endorse-change-owner.test.ts | 55 +++ src/e2e/endorse-transfer.test.ts | 56 +++ src/e2e/mint.test.ts | 158 ++++++ src/e2e/nominate.test.ts | 109 ++++ src/e2e/reject-surrender.test.ts | 63 +++ src/e2e/surrender.test.ts | 100 ++++ src/e2e/utils/bootstrap/accept-surrender.ts | 20 + src/e2e/utils/bootstrap/change-holder.ts | 45 ++ src/e2e/utils/bootstrap/common.ts | 9 + src/e2e/utils/bootstrap/deploy.ts | 47 ++ src/e2e/utils/bootstrap/endorse-owners.ts | 28 ++ src/e2e/utils/bootstrap/endorse-transfer.ts | 23 + src/e2e/utils/bootstrap/index.ts | 11 + src/e2e/utils/bootstrap/mint.ts | 85 ++++ src/e2e/utils/bootstrap/nominate.ts | 54 ++ src/e2e/utils/bootstrap/reject-surrender.ts | 20 + src/e2e/utils/bootstrap/surrender.ts | 48 ++ .../fixture/e2e => e2e/utils}/commands.ts | 6 +- .../fixture/e2e => e2e/utils}/constants.ts | 36 +- src/e2e/utils/contract-checks.ts | 170 +++++++ .../fixture/e2e => e2e/utils}/shell.ts | 25 +- src/e2e/utils/token-management.ts | 22 + 37 files changed, 1816 insertions(+), 615 deletions(-) delete mode 100644 src/__tests__/fixture/e2e/utils.ts delete mode 100644 src/__tests__/token-registry/accept-surrender.e2e.test.ts delete mode 100644 src/__tests__/token-registry/change-holder.e2e.test.ts delete mode 100644 src/__tests__/token-registry/endorse-change-owner.e2e.test.ts delete mode 100644 src/__tests__/token-registry/endorse-transfer.e2e.test.ts delete mode 100644 src/__tests__/token-registry/mint.e2e.test.ts delete mode 100644 src/__tests__/token-registry/nominate.e2e.test.ts delete mode 100644 src/__tests__/token-registry/reject-surrender.e2e.test.ts delete mode 100644 src/__tests__/token-registry/surrender.e2e.test.ts create mode 100644 src/e2e/accept-surrender.test.ts create mode 100644 src/e2e/change-holder.test.ts rename src/{__tests__/token-registry/deploy.e2e.test.ts => e2e/deploy.test.ts} (54%) create mode 100644 src/e2e/endorse-change-owner.test.ts create mode 100644 src/e2e/endorse-transfer.test.ts create mode 100644 src/e2e/mint.test.ts create mode 100644 src/e2e/nominate.test.ts create mode 100644 src/e2e/reject-surrender.test.ts create mode 100644 src/e2e/surrender.test.ts create mode 100644 src/e2e/utils/bootstrap/accept-surrender.ts create mode 100644 src/e2e/utils/bootstrap/change-holder.ts create mode 100644 src/e2e/utils/bootstrap/common.ts create mode 100644 src/e2e/utils/bootstrap/deploy.ts create mode 100644 src/e2e/utils/bootstrap/endorse-owners.ts create mode 100644 src/e2e/utils/bootstrap/endorse-transfer.ts create mode 100644 src/e2e/utils/bootstrap/index.ts create mode 100644 src/e2e/utils/bootstrap/mint.ts create mode 100644 src/e2e/utils/bootstrap/nominate.ts create mode 100644 src/e2e/utils/bootstrap/reject-surrender.ts create mode 100644 src/e2e/utils/bootstrap/surrender.ts rename src/{__tests__/fixture/e2e => e2e/utils}/commands.ts (94%) rename src/{__tests__/fixture/e2e => e2e/utils}/constants.ts (58%) create mode 100644 src/e2e/utils/contract-checks.ts rename src/{__tests__/fixture/e2e => e2e/utils}/shell.ts (71%) create mode 100644 src/e2e/utils/token-management.ts diff --git a/package-lock.json b/package-lock.json index a5fe303e..2cbcf9f7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1638,6 +1638,464 @@ "@ethersproject/transactions": "^5.4.0" } }, + "@ethersproject/experimental": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/experimental/-/experimental-5.7.0.tgz", + "integrity": "sha512-DWvhuw7Dg8JPyhMbh/CNYOwsTLjXRx/HGkacIL5rBocG8jJC0kmixwoK/J3YblO4vtcyBLMa+sV74RJZK2iyHg==", + "dev": true, + "requires": { + "@ethersproject/web": "^5.7.0", + "ethers": "^5.7.0", + "scrypt-js": "3.0.1" + }, + "dependencies": { + "@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "dev": true, + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "dev": true, + "requires": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "dev": true + }, + "@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "dev": true, + "requires": { + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "dev": true, + "requires": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "dev": true, + "requires": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "dev": true, + "requires": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "dev": true, + "requires": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "dev": true, + "requires": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "dev": true + }, + "ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "dev": true, + "requires": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + } + } + }, "@ethersproject/hash": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.4.0.tgz", @@ -5276,9 +5734,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001243", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001243.tgz", - "integrity": "sha512-vNxw9mkTBtkmLFnJRv/2rhs1yufpDfCkBZexG3Y0xdOH2Z/eE/85E4Dl5j1YUN34nZVsSp6vVRFQRrez9wJMRA==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "dev": true }, "canonicalize": { diff --git a/package.json b/package.json index fc7342b1..10e83e70 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli", + "test:e2e": "jest --ci src/e2e/", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", @@ -39,6 +40,7 @@ "@commitlint/cli": "^12.1.4", "@commitlint/config-conventional": "^12.1.4", "@commitlint/prompt": "^12.1.4", + "@ethersproject/experimental": "^5.7.0", "@ls-age/commitlint-circle": "1.0.0", "@semantic-release/exec": "^5.0.0", "@types/debug": "4.1.5", diff --git a/src/__tests__/fixture/e2e/utils.ts b/src/__tests__/fixture/e2e/utils.ts deleted file mode 100644 index e8fdd73f..00000000 --- a/src/__tests__/fixture/e2e/utils.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { isAddress } from "web3-utils"; -import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -import { creators, emoji, network } from "./constants"; -import { extractLine, LineInfo, run } from "./shell"; -import { Wallet } from "ethers"; -import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; -import { - generateDeployDocumentStoreCommand, - generateDeployTokenRegistryCommand, - generateMintTitleEscrowCommand, - generateNominateCommand, - generateSurrenderCommand, -} from "./commands"; -import { - BaseTitleEscrowCommand, - TitleEscrowNominateBeneficiaryCommand, -} from "../../../commands/title-escrow/title-escrow-command.type"; -export interface TokenInfo { - tokenRegistry: string; - tokenId: string; - titleEscrowAddress?: string; -} - -const defaults = { - network: network, - dryRun: false, -}; - -const numberGenerator = (range: number): number => { - return Math.floor(Math.random() * range); -}; - -export const deployTokenRegistry = ( - privateKey: string, - tokenRegistryParameters?: DeployTokenRegistryCommand -): string => { - if (!tokenRegistryParameters) { - const index = numberGenerator(100); - tokenRegistryParameters = { - registryName: `Test Token ${index}`, - registrySymbol: `TKN${index}`, - factoryAddress: creators.titleEscrowFactory, - tokenImplementationAddress: creators.tokenImplementation, - deployerAddress: creators.deployer, - ...defaults, - }; - } - const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); - const results = run(command, true); - const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - if (!checkSuccess) throw new Error("Unable to deploy the token registry"); - const splitResults = results.trim().split("\n"); - const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; - const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); - if (!isAddress(tokenRegistryAddress)) throw new Error("Unable to find token registry address"); - return tokenRegistryAddress; -}; - -export const deployDocumentStore = ( - privateKey: string, - documentStoreParameters?: DeployDocumentStoreCommand -): string => { - if (!documentStoreParameters) { - const index = numberGenerator(100); - documentStoreParameters = { - storeName: `Test Document Store ${index}`, - ...defaults, - }; - } - const command = generateDeployDocumentStoreCommand(documentStoreParameters, privateKey); - const results = run(command, true); - const documentStoreSuccessFormat = `${emoji.tick} success Document store Test Document Store deployed at `; - const checkSuccess = results.includes(documentStoreSuccessFormat); - if (!checkSuccess) throw new Error("Unable to deploy document store"); - const splitResults = results.trim().split("\n"); - const documentStoreAddressLine = splitResults[splitResults.length - 2]; - const documentStoreAddress = documentStoreAddressLine.trim().substring(documentStoreSuccessFormat.length); - if (!isAddress(documentStoreAddress)) throw new Error("Unable to find document store address"); - return documentStoreAddress; -}; - -const retries = 10; -const usedTokenIds = new Set(); -export const generateTokenId = (): string => { - for (let count = 0; count < retries; count = count + 1) { - const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join("")}`; - const unique = !usedTokenIds.has(generatedTokenId); - if (unique) { - usedTokenIds.add(generatedTokenId); - return generatedTokenId; - } - } - throw new Error("Unable to generate tokenIds"); -}; - -export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { - if (!tokenRegistryAddress) { - tokenRegistryAddress = deployTokenRegistry(privateKey); - } - if (!isAddress(tokenRegistryAddress)) throw new Error("Invalid Token Registry Address"); - const wallet = new Wallet(privateKey); - const titleEscrowParameter: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - beneficiary: wallet.address, - holder: wallet.address, - tokenId: generateTokenId(), - ...defaults, - }; - - return mintToken(privateKey, titleEscrowParameter); -}; - -export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { - const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); - const results = run(command, true); - const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - if (!checkSuccess) throw new Error("Unable to mint token"); - const splitResults = results.trim().split("\n"); - const titleEscrowAddressLine = splitResults[splitResults.length - 2]; - const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); - if (!isAddress(titleEscrowAddress)) throw new Error("Unable to find token"); - return { - tokenRegistry: titleEscrowParameter.address, - tokenId: titleEscrowParameter.tokenId, - titleEscrowAddress, - }; -}; - -export const mintNominatedToken = (privateKey: string, nominee: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); - const { tokenRegistry, tokenId } = tokenDetails; - const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - tokenId: tokenId, - tokenRegistry: tokenRegistry, - newBeneficiary: nominee, - ...defaults, - }; - nominateToken(privateKey, nominateParameter); - return tokenDetails; -}; - -export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { - const command = generateNominateCommand(nominateParameter, privateKey); - const results = run(command, true); - const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully nominated to new owner with address `; - const queryResults = extractLine(results, frontFormat); - if (!queryResults) throw new Error("Unable to nominate token"); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(frontFormat); - const checkContext = filteredLine.includes(middleFormat); - if (!checkSuccess || !checkContext) throw new Error("Unexpected nominate token format"); - const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - if (resultTokenId !== nominateParameter.tokenId) throw new Error("Unexpected nominate tokenid"); - const destination = filteredLine.trim().substring(filteredLine.length - 42); - if (destination !== nominateParameter.newBeneficiary) throw new Error("Unexpected nominee"); -}; - -export const mintSurrenderToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); - const { tokenRegistry, tokenId } = tokenDetails; - const surrenderParameter: BaseTitleEscrowCommand = { - tokenRegistry: tokenRegistry, - tokenId: tokenId, - ...defaults, - }; - surrenderToken(privateKey, surrenderParameter); - return tokenDetails; -}; - -export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { - const command = generateSurrenderCommand(surrenderParameter, privateKey); - const results = run(command); - - const tokenRegistrySuccessFormat = `${emoji.tick} success Transferable record with hash `; - const queryResults = extractLine(results, tokenRegistrySuccessFormat); - if (!queryResults) throw new Error("Unable to surrender token"); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); - if (!checkSuccess) throw new Error("Unexpected surrender token format"); - const resultTokenId = filteredLine - .trim() - .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); - if (resultTokenId !== surrenderParameter.tokenId) throw new Error("Unexpected surrendered token"); -}; diff --git a/src/__tests__/token-registry/accept-surrender.e2e.test.ts b/src/__tests__/token-registry/accept-surrender.e2e.test.ts deleted file mode 100644 index f5afce54..00000000 --- a/src/__tests__/token-registry/accept-surrender.e2e.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { deployTokenRegistry, mintSurrenderToken } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner } from "../fixture/e2e/constants"; -import { generateAcceptSurrenderCommand } from "../fixture/e2e/commands"; - -describe("accept-surrender title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to accept-surrender title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); - const results = run(command); - - const tokenRegistrySuccessFormat = `${emoji.tick} success Surrendered transferable record with hash `; - const queryResults = extractLine(results, tokenRegistrySuccessFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); - const resultTokenId = filteredLine - .trim() - .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); - expect(resultTokenId).toBe(tokenId); - }); - - it.todo("should be fail when permission is denied"); -}); diff --git a/src/__tests__/token-registry/change-holder.e2e.test.ts b/src/__tests__/token-registry/change-holder.e2e.test.ts deleted file mode 100644 index c64538fd..00000000 --- a/src/__tests__/token-registry/change-holder.e2e.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { deployTokenRegistry, mintTokenRegistry } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { generateChangeHolderCommand } from "../fixture/e2e/commands"; - -describe("transfer holder title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - // const defaultTitleEscrow = { - // beneficiary: owner.ethAddress, - // holder: owner.ethAddress, - // network: network, - // dryRun: false, - // }; - - const defaultTransferHolder = { - newHolder: receiver.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to transfer holder title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const transferHolder: TitleEscrowTransferHolderCommand = { - tokenId: tokenId, - tokenRegistry: tokenRegistry, - ...defaultTransferHolder, - }; - const command = generateChangeHolderCommand(transferHolder, owner.privateKey); - const results = run(command); - const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully changed to holder with address: `; - const queryResults = extractLine(results, frontFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(frontFormat); - const checkContext = filteredLine.includes(middleFormat); - expect(checkSuccess && checkContext).toBe(true); - const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - expect(resultTokenId).toBe(transferHolder.tokenId); - const destination = filteredLine.trim().substring(filteredLine.length - 42); - expect(destination).toBe(transferHolder.newHolder); - }); -}); diff --git a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts b/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts deleted file mode 100644 index 9fce049e..00000000 --- a/src/__tests__/token-registry/endorse-change-owner.e2e.test.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { deployTokenRegistry, mintNominatedToken } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { generateTransferOwnersCommand } from "../fixture/e2e/commands"; - -describe("endorse change owner title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - // const defaultTitleEscrow = { - // beneficiary: owner.ethAddress, - // holder: owner.ethAddress, - // network: network, - // dryRun: false, - // }; - - const defaultTransferOwners = { - newOwner: receiver.ethAddress, - newHolder: receiver.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to endorse change owner title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintNominatedToken( - owner.privateKey, - defaultTransferOwners.newOwner, - tokenRegistryAddress - ); - const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { - tokenId: tokenId, - tokenRegistry: tokenRegistry, - ...defaultTransferOwners, - }; - const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); - const results = run(command); - const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully endorsed to new owner with address `; - const rearFormat = ` and new holder with address: `; - const queryResults = extractLine(results, frontFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(frontFormat); - const checkOwner = filteredLine.includes(middleFormat); - const checkHolder = filteredLine.includes(rearFormat); - expect(checkSuccess && checkOwner && checkHolder).toBe(true); - const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - expect(resultTokenId).toBe(transferOwners.tokenId); - const resultOwner = filteredLine - .trim() - .substring(frontFormat.length + 66 + middleFormat.length, frontFormat.length + 66 + middleFormat.length + 42); - expect(resultOwner).toBe(transferOwners.newOwner); - const destination = filteredLine.trim().substring(filteredLine.length - 42); - expect(destination).toBe(transferOwners.newHolder); - }); -}); diff --git a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts b/src/__tests__/token-registry/endorse-transfer.e2e.test.ts deleted file mode 100644 index bf189829..00000000 --- a/src/__tests__/token-registry/endorse-transfer.e2e.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { deployTokenRegistry, mintNominatedToken } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { generateEndorseTransferOwnerCommand } from "../fixture/e2e/commands"; - -describe("endorse transfer title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - // const defaultTitleEscrow = { - // beneficiary: owner.ethAddress, - // holder: owner.ethAddress, - // network: network, - // dryRun: false, - // }; - - const defaultTransferHolder = { - newBeneficiary: receiver.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to endorse transfer title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintNominatedToken( - owner.privateKey, - defaultTransferHolder.newBeneficiary, - tokenRegistryAddress - ); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - tokenId: tokenId, - tokenRegistry: tokenRegistry, - ...defaultTransferHolder, - }; - - const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); - const results = run(command); - const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully endorsed to approved beneficiary at `; - const queryResults = extractLine(results, frontFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(frontFormat); - const checkContext = filteredLine.includes(middleFormat); - expect(checkSuccess && checkContext).toBe(true); - const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - expect(resultTokenId).toBe(transferHolder.tokenId); - const destination = filteredLine.trim().substring(filteredLine.length - 42); - expect(destination).toBe(transferHolder.newBeneficiary); - }); -}); diff --git a/src/__tests__/token-registry/mint.e2e.test.ts b/src/__tests__/token-registry/mint.e2e.test.ts deleted file mode 100644 index 98ed5348..00000000 --- a/src/__tests__/token-registry/mint.e2e.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { deployTokenRegistry, generateTokenId } from "../fixture/e2e/utils"; -import { run } from "../fixture/e2e/shell"; -import { emoji, network, owner } from "../fixture/e2e/constants"; -import { isAddress } from "web3-utils"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { generateMintTitleEscrowCommand } from "../fixture/e2e/commands"; - -describe("deploy token-registry", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - it("should be able to mint title-escrow on token-registry", async () => { - const tokenId = generateTokenId(); - const titleEscrowParameter: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); - const results = run(command); - const tokenRegistrySuccessFormat = `${emoji.tick} success Token with hash `; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); - const splitResults = results.trim().split("\n"); - const titleEscrowAddressLine = splitResults[splitResults.length - 2]; - const titleEscrowAddress = titleEscrowAddressLine.trim().substring(115, 115 + 42); - expect(isAddress(titleEscrowAddress)).toBe(true); - }); -}); diff --git a/src/__tests__/token-registry/nominate.e2e.test.ts b/src/__tests__/token-registry/nominate.e2e.test.ts deleted file mode 100644 index 7fda263c..00000000 --- a/src/__tests__/token-registry/nominate.e2e.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -// title-escrow nominate-change-owner --token-registry 0x4933e30eF8A083f49d14759b2eafC94E56F0b3A7 --tokenId 0x951b39bcaddc0e8882883db48ca258ca35ccb01fee328355f0dfda1ff9be9990 --newOwner 0xB26B4941941C51a4885E5B7D3A1B861E54405f90 - -import { deployTokenRegistry, generateTokenId, mintToken } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner, receiver } from "../fixture/e2e/constants"; -import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; -import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { generateNominateCommand } from "../fixture/e2e/commands"; - -describe("nominate title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - - const defaultTransferHolder = { - newBeneficiary: receiver.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to nominate title-escrow on token-registry", async () => { - const tokenId = generateTokenId(); - const titleEscrow: TokenRegistryIssueCommand = { - address: tokenRegistryAddress, - tokenId: tokenId, - ...defaultTitleEscrow, - }; - mintToken(owner.privateKey, titleEscrow); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - tokenId: titleEscrow.tokenId, - tokenRegistry: titleEscrow.address, - ...defaultTransferHolder, - }; - const command = generateNominateCommand(transferHolder, owner.privateKey); - const results = run(command); - const frontFormat = `${emoji.tick} success Transferable record with hash `; - const middleFormat = `'s holder has been successfully nominated to new owner with address `; - const queryResults = extractLine(results, frontFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(frontFormat); - const checkContext = filteredLine.includes(middleFormat); - expect(checkSuccess && checkContext).toBe(true); - const resultTokenId = filteredLine.trim().substring(frontFormat.length, frontFormat.length + 66); - expect(resultTokenId).toBe(transferHolder.tokenId); - const destination = filteredLine.trim().substring(filteredLine.length - 42); - expect(destination).toBe(transferHolder.newBeneficiary); - }); -}); diff --git a/src/__tests__/token-registry/reject-surrender.e2e.test.ts b/src/__tests__/token-registry/reject-surrender.e2e.test.ts deleted file mode 100644 index 44671292..00000000 --- a/src/__tests__/token-registry/reject-surrender.e2e.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { deployTokenRegistry, mintSurrenderToken } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner } from "../fixture/e2e/constants"; -import { generateRejectSurrenderCommand } from "../fixture/e2e/commands"; - -describe("reject surrender title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to reject surrender title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); - const results = run(command); - - const tokenRegistrySuccessFormat = `${emoji.tick} success Surrendered transferable record with hash `; - const queryResults = extractLine(results, tokenRegistrySuccessFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); - const resultTokenId = filteredLine - .trim() - .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); - expect(resultTokenId).toBe(tokenId); - }); - - it.todo("should be fail when user without permission attempts reject surrender"); -}); diff --git a/src/__tests__/token-registry/surrender.e2e.test.ts b/src/__tests__/token-registry/surrender.e2e.test.ts deleted file mode 100644 index 9cc8d7ea..00000000 --- a/src/__tests__/token-registry/surrender.e2e.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { deployTokenRegistry, mintTokenRegistry } from "../fixture/e2e/utils"; -import { extractLine, LineInfo, run } from "../fixture/e2e/shell"; -import { emoji, network, owner } from "../fixture/e2e/constants"; -import { BaseTitleEscrowCommand } from "../../commands/title-escrow/title-escrow-command.type"; -import { generateSurrenderCommand } from "../fixture/e2e/commands"; - -describe("surrender title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - const defaultTitleEscrow = { - beneficiary: owner.ethAddress, - holder: owner.ethAddress, - network: network, - dryRun: false, - }; - - it("should be able to surrender title-escrow on token-registry", async () => { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const surrenderTitleEscrow: BaseTitleEscrowCommand = { - tokenRegistry, - tokenId, - ...defaultTitleEscrow, - }; - - const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); - const results = run(command); - - const tokenRegistrySuccessFormat = `${emoji.tick} success Transferable record with hash `; - const queryResults = extractLine(results, tokenRegistrySuccessFormat); - expect(queryResults).toBeTruthy(); - const filteredLine = (queryResults as LineInfo[])[0].lineContent.trim(); - const checkSuccess = filteredLine.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); - const resultTokenId = filteredLine - .trim() - .substring(tokenRegistrySuccessFormat.length, tokenRegistrySuccessFormat.length + 66); - expect(resultTokenId).toBe(surrenderTitleEscrow.tokenId); - }); -}); diff --git a/src/commands/title-escrow/accept-surrendered.ts b/src/commands/title-escrow/accept-surrendered.ts index 2c8a426e..64af790e 100644 --- a/src/commands/title-escrow/accept-surrendered.ts +++ b/src/commands/title-escrow/accept-surrendered.ts @@ -35,6 +35,7 @@ export const handler = async (args: TitleEscrowSurrenderDocumentCommand): Promis try { info(`Accepting surrendered document`); const transaction = await acceptSurrendered(args); + console.log(transaction); success(`Surrendered transferable record with hash ${args.tokenId} has been accepted.`); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transaction.transactionHash}`); } catch (e) { diff --git a/src/e2e/accept-surrender.test.ts b/src/e2e/accept-surrender.test.ts new file mode 100644 index 00000000..f8b86e12 --- /dev/null +++ b/src/e2e/accept-surrender.test.ts @@ -0,0 +1,60 @@ +import { extractLine, LineInfo, run } from "./utils/shell"; +import { BurnAddress, EmptyTokenID, EndStatus, network, owner } from "./utils/constants"; +import { generateAcceptSurrenderCommand } from "./utils/commands"; +import { checkFailure, checkSurrenderAcceptSuccess, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; +import { getSigner, retrieveTitleEscrow, retrieveTitleEscrowInfo, retrieveTitleEscrowOwner } from "./utils/contract-checks"; + +describe("accept-surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to accept-surrender title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId, titleEscrowAddress } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); + let titleEscrowOwner: string = await retrieveTitleEscrowOwner( + signer, + tokenRegistry, + tokenId + ); + expect(titleEscrowOwner).toBe(tokenRegistry); + const results = run(command); + titleEscrowOwner = await retrieveTitleEscrowOwner( + signer, + tokenRegistry, + tokenId + ); + expect(titleEscrowOwner).toBe("0x000000000000000000000000000000000000dEaD"); + checkSurrenderAcceptSuccess(results); + }); + + it("should not be able to accept surrender invalid title-escrow on token-registry", async () => { + const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + + it("should not be able to accept surrender title-escrow on invalid token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); + + it.todo("should be fail when permission is denied"); +}); + +// npm run dev -- title-escrow accept-surrendered --token-registry 0x0000000000000000000000000000000000000000 --tokenId 0xf32907ec66ac258f058eae34d76b160b0ca520b5c613ca93ae6bb22a8f9c451f --network local -k 0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7 \ No newline at end of file diff --git a/src/e2e/change-holder.test.ts b/src/e2e/change-holder.test.ts new file mode 100644 index 00000000..12eb4060 --- /dev/null +++ b/src/e2e/change-holder.test.ts @@ -0,0 +1,103 @@ +import { extractLine, LineInfo, run } from "./utils/shell"; +import { BurnAddress, EmptyTokenID, EndStatus, network, owner, receiver } from "./utils/constants"; +import { TitleEscrowTransferHolderCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { generateChangeHolderCommand } from "./utils/commands"; +import { checkFailure, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; +import { changeHolderToken, checkChangeHolderSuccess, defaultTransferHolder } from "./utils/bootstrap"; + +describe("transfer holder title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + it("should be able to transfer holder title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowTransferHolderCommand = { + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferHolder, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + checkChangeHolderSuccess(results); + }); + + + it("holder should be able to transfer holder of title-escrow", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + // Transfer Holder to Receiver + const initialHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: receiver.ethAddress, + }; + changeHolderToken(owner.privateKey, initialHolder); + // Transfer Holder to Receiver + // Holder attempts to transfer Holder with permission + const transferHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: owner.ethAddress, + }; + const command = generateChangeHolderCommand(transferHolder, receiver.privateKey); + // Holder attempts to transfer Holder with permission + const results = run(command); + checkChangeHolderSuccess(results); + }); + + it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowTransferHolderCommand = { + tokenId: EmptyTokenID, + tokenRegistry: tokenRegistry, + ...defaultTransferHolder, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + + it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowTransferHolderCommand = { + tokenId: tokenId, + tokenRegistry: BurnAddress, + ...defaultTransferHolder, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); + + it("beneficiary should not be able to transfer holder of title-escrow", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + // Transfer Holder to Receiver + const initialHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: receiver.ethAddress, + }; + changeHolderToken(owner.privateKey, initialHolder); + // Transfer Holder to Receiver + // Beneficiary attempts to transfer Holder without permission + const transferHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: owner.ethAddress, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + // Beneficiary attempts to transfer Holder without permission + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + +}); diff --git a/src/__tests__/token-registry/deploy.e2e.test.ts b/src/e2e/deploy.test.ts similarity index 54% rename from src/__tests__/token-registry/deploy.e2e.test.ts rename to src/e2e/deploy.test.ts index 33f42ba0..48f489ab 100644 --- a/src/__tests__/token-registry/deploy.e2e.test.ts +++ b/src/e2e/deploy.test.ts @@ -1,16 +1,10 @@ -import { run } from "../fixture/e2e/shell"; -import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; +import { run } from "./utils/shell"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../commands/deploy/deploy.types"; import { isAddress } from "web3-utils"; -import { creators, emoji, network, owner } from "../fixture/e2e/constants"; -import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "../fixture/e2e/commands"; - -const defaults = { - factoryAddress: creators.titleEscrowFactory, - tokenImplementationAddress: creators.tokenImplementation, - deployerAddress: creators.deployer, - network: network, - dryRun: false, -}; +import { defaultRunParameters, EndStatus, owner } from "./utils/constants"; +import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils/commands"; +import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; +import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/bootstrap"; describe("deploy token-registry", () => { jest.setTimeout(90000); @@ -19,18 +13,21 @@ describe("deploy token-registry", () => { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", registrySymbol: "TKN", - ...defaults, + ...defaultTokenRegistry, }; const command = generateDeployTokenRegistryCommand(tokenRegistryParameter, owner.privateKey); const results = run(command); - const tokenRegistrySuccessFormat = `${emoji.tick} success Token registry deployed at `; - const checkSuccess = results.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); - const splitResults = results.trim().split("\n"); - const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; - const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); - expect(isAddress(tokenRegistryAddress)).toBe(true); + const tokenRegistryAddress = checkTokenRegistrySuccess(results); + const signer = getSigner(defaultRunParameters.network, owner.privateKey); + const tokenInfo = await retrieveTokenInfo(signer, tokenRegistryAddress); + expect(tokenInfo.name).toBe(tokenRegistryParameter.registryName); + expect(tokenInfo.symbol).toBe(tokenRegistryParameter.registrySymbol); + const rolesInfo = await rolesCheck(signer, tokenRegistryAddress); + expect(rolesInfo.accepterRole).toBe(true); + expect(rolesInfo.defaultRole).toBe(true); + expect(rolesInfo.minterRole).toBe(true); + expect(rolesInfo.restorerRole).toBe(true); }); }); @@ -40,12 +37,12 @@ describe("deploy document-store", () => { it("should be able to deploy document-store", async () => { const documentStoreParameters: DeployDocumentStoreCommand = { storeName: "Test Document Store", - ...defaults, + ...defaultRunParameters, }; const command = generateDeployDocumentStoreCommand(documentStoreParameters, owner.privateKey); const results = run(command); - const tokenRegistrySuccessFormat = `${emoji.tick} success Document store Test Document Store deployed at `; + const tokenRegistrySuccessFormat = `${EndStatus.success} Document store Test Document Store deployed at `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); expect(checkSuccess).toBe(true); const splitResults = results.trim().split("\n"); diff --git a/src/e2e/endorse-change-owner.test.ts b/src/e2e/endorse-change-owner.test.ts new file mode 100644 index 00000000..5cba8185 --- /dev/null +++ b/src/e2e/endorse-change-owner.test.ts @@ -0,0 +1,55 @@ +import { extractLine, LineInfo, run } from "./utils/shell"; +import { EndStatus, network, owner, receiver } from "./utils/constants"; +import { TitleEscrowEndorseTransferOfOwnersCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { generateTransferOwnersCommand } from "./utils/commands"; +import { changeHolderToken, checkEndorseOwner, checkFailure, deployTokenRegistry, mintNominatedToken, mintTokenRegistry } from "./utils/bootstrap"; + +describe("endorse change owner title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTransferOwners = { + newOwner: receiver.ethAddress, + newHolder: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to endorse change owner title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintNominatedToken( + owner.privateKey, + defaultTransferOwners.newOwner, + tokenRegistryAddress + ); + const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferOwners, + }; + const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); + const results = run(command); + const { beneficiary, holder, tokenId: tokenIdResult } = checkEndorseOwner(results); + expect(beneficiary).toBe(transferOwners.newOwner); + expect(holder).toBe(transferOwners.newHolder); + expect(tokenIdResult).toBe(transferOwners.tokenId); + }); + + it("should not be able to endorse change owner on un-nominated title-escrow", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry( + owner.privateKey, + tokenRegistryAddress + ); + const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { + tokenId: tokenId, + tokenRegistry: tokenRegistry, + ...defaultTransferOwners, + }; + const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); + const results = run(command); + checkFailure(results, "") + }); +}); diff --git a/src/e2e/endorse-transfer.test.ts b/src/e2e/endorse-transfer.test.ts new file mode 100644 index 00000000..3ad49afe --- /dev/null +++ b/src/e2e/endorse-transfer.test.ts @@ -0,0 +1,56 @@ +import { extractLine, LineInfo, run } from "./utils/shell"; +import { BurnAddress, EndStatus, network, owner, receiver } from "./utils/constants"; +import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { generateEndorseTransferOwnerCommand } from "./utils/commands"; +import { checkEndorseTransfer, checkFailure, deployTokenRegistry, mintNominatedToken, mintToken, mintTokenRegistry } from "./utils/bootstrap"; + +describe("endorse transfer title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTransferHolder = { + newBeneficiary: receiver.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to endorse transfer title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintNominatedToken( + owner.privateKey, + defaultTransferHolder.newBeneficiary, + tokenRegistryAddress + ); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferHolder, + tokenId, + tokenRegistry, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); + const results = run(command); + checkEndorseTransfer(results); + }); + + + it("should not be able to endorse un-nominated title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry( + owner.privateKey, + tokenRegistryAddress + ); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferHolder, + tokenId, + tokenRegistry, + newBeneficiary: BurnAddress + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, ""); + }); + +}); diff --git a/src/e2e/mint.test.ts b/src/e2e/mint.test.ts new file mode 100644 index 00000000..19f6c5f5 --- /dev/null +++ b/src/e2e/mint.test.ts @@ -0,0 +1,158 @@ +import { generateTokenId, isTokenId } from "./utils/token-management"; +import { extractStatus, run } from "./utils/shell"; +import { + AddressLength, + BurnAddress, + defaultRunParameters, + EndStatus, + network, + owner, + receiver, + TokenIdLength, + TokenInfo, +} from "./utils/constants"; +import { isAddress } from "web3-utils"; +import { TokenRegistryIssueCommand } from "../commands/token-registry/token-registry-command.type"; +import { generateMintTitleEscrowCommand } from "./utils/commands"; +import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; +import { BigNumber } from "ethers"; +import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/bootstrap"; + +describe("deploy token-registry", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + it("should be able to mint title-escrow on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + const mintResults = checkMintSuccess(results); + validateMintData(titleEscrowParameter as MintData, mintResults); + + const signer = await getSigner(titleEscrowParameter.network, owner.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + titleEscrowParameter.address, + titleEscrowParameter.tokenId + ); + expect(titleEscrowInfo.active).toBe(true); + expect(titleEscrowInfo.beneficiary).toBe(titleEscrowParameter.beneficiary); + expect(titleEscrowInfo.holder).toBe(titleEscrowParameter.holder); + expect(titleEscrowInfo.isHoldingToken).toBe(true); + expect(titleEscrowInfo.nominee).toBe(BurnAddress); + expect(titleEscrowInfo.registry).toBe(titleEscrowParameter.address); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); + expect(correctTokenID).toBe(true); + }); + + it("should be able to mint title-escrow for a different wallet on token-registry", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: receiver.ethAddress, + holder: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + const mintResults = checkMintSuccess(results); + validateMintData(titleEscrowParameter as MintData, mintResults); + + const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + titleEscrowParameter.address, + titleEscrowParameter.tokenId + ); + expect(titleEscrowInfo.active).toBe(true); + expect(titleEscrowInfo.beneficiary).toBe(titleEscrowParameter.beneficiary); + expect(titleEscrowInfo.holder).toBe(titleEscrowParameter.holder); + expect(titleEscrowInfo.isHoldingToken).toBe(true); + expect(titleEscrowInfo.nominee).toBe(BurnAddress); + expect(titleEscrowInfo.registry).toBe(titleEscrowParameter.address); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); + expect(correctTokenID).toBe(true); + }); + + it("should fail with invalid token id", async () => { + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: "0xZ", + beneficiary: receiver.ethAddress, + holder: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + checkFailure(results, "invalid BigNumber string"); + }); + + it("should fail with invalid token registry", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: BurnAddress, + tokenId: tokenId, + beneficiary: receiver.ethAddress, + holder: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); + + it("should fail with invalid beneficiary", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: BurnAddress, + holder: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + it("should fail with invalid holder", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: receiver.ethAddress, + holder: BurnAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + it("should fail with no funds", async () => { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + ...defaultRunParameters, + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: receiver.ethAddress, + holder: receiver.ethAddress, + network: "mainnet", + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); +}); diff --git a/src/e2e/nominate.test.ts b/src/e2e/nominate.test.ts new file mode 100644 index 00000000..664a2ec4 --- /dev/null +++ b/src/e2e/nominate.test.ts @@ -0,0 +1,109 @@ +import { run } from "./utils/shell"; +import { + BurnAddress, + defaultRunParameters, + owner, + receiver, +} from "./utils/constants"; +import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { generateNominateCommand } from "./utils/commands"; +import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; +import { checkFailure, checkNominateSuccess, defaultNominateBeneficiary, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; + +describe("nominate title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + it("should be able to nominate title-escrow on token-registry", async () => { + const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + tokenId, + tokenRegistry, + newBeneficiary: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateNominateCommand(transferHolder, owner.privateKey); + const results = run(command); + const nominateInfo = checkNominateSuccess(results); + expect(nominateInfo.tokenId).toBe(transferHolder.tokenId); + expect(nominateInfo.nominee).toBe(transferHolder.newBeneficiary); + const signer = await getSigner(transferHolder.network, owner.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); + expect(titleEscrowInfo.nominee).toBe(transferHolder.newBeneficiary); + }); + + it("should be able to cancel nomination of title-escrow on token-registry", async () => { + const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId, + tokenRegistry, + }; + let results = run(generateNominateCommand(transferHolder, owner.privateKey)); + transferHolder.newBeneficiary = BurnAddress; + const command = generateNominateCommand(transferHolder, owner.privateKey); + results = run(command); + const nominateInfo = checkNominateSuccess(results); + expect(nominateInfo.tokenId).toBe(transferHolder.tokenId); + expect(nominateInfo.nominee).toBe(transferHolder.newBeneficiary); + + const signer = await getSigner(transferHolder.network, owner.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); + expect(titleEscrowInfo.nominee).toBe(BurnAddress); + }); + + it("should not be able to nominate self", async () => { + const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId, + tokenRegistry, + newBeneficiary: owner.ethAddress, + }; + const command = generateNominateCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "new beneficiary address is the same as the current beneficiary address"); + }); + + it("should not be able to nominate unowned token", async () => { + const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId, + tokenRegistry, + newBeneficiary: receiver.ethAddress, + }; + const command = generateNominateCommand(transferHolder, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + it("should not be able to nominate non-existent token", async () => { + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", + tokenRegistry: tokenRegistryAddress, + newBeneficiary: receiver.ethAddress, + }; + const command = generateNominateCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + it("should not be able to nominate non-existent token registry", async () => { + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", + tokenRegistry: "0x0000000000000000000000000000000000000000", + newBeneficiary: receiver.ethAddress, + }; + const command = generateNominateCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); +}); diff --git a/src/e2e/reject-surrender.test.ts b/src/e2e/reject-surrender.test.ts new file mode 100644 index 00000000..07eeff8a --- /dev/null +++ b/src/e2e/reject-surrender.test.ts @@ -0,0 +1,63 @@ +// import { deployTokenRegistry, mintSurrenderToken } from "./utils/utils"; +import { extractLine, LineInfo, run } from "./utils/shell"; +import { BurnAddress, EmptyTokenID, EndStatus, network, owner } from "./utils/constants"; +import { generateRejectSurrenderCommand } from "./utils/commands"; +import { checkFailure, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; +import { checkSurrenderRejectSuccess } from "./utils/bootstrap"; +import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; +import { isAddress } from "web3-utils"; + +describe("reject surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + const defaultTitleEscrow = { + beneficiary: owner.ethAddress, + holder: owner.ethAddress, + network: network, + dryRun: false, + }; + + it("should be able to reject surrender title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); + const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); + + let titleEscrowOwner: string = await retrieveTitleEscrowOwner( + signer, + tokenRegistry, + tokenId + ); + expect(titleEscrowOwner).toBe(tokenRegistry); + const results = run(command); + checkSurrenderRejectSuccess(results); + titleEscrowOwner = await retrieveTitleEscrowOwner( + signer, + tokenRegistry, + tokenId + ); + expect(isAddress(titleEscrowOwner)).toBe(true); + expect(titleEscrowOwner).not.toBe(tokenRegistry); + }); + + it("should not be able to reject surrender invalid title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + + it("should not be able to reject surrender title-escrow on invalid token-registry", async () => { + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); + + it.todo("should be fail when user without permission attempts reject surrender"); +}); diff --git a/src/e2e/surrender.test.ts b/src/e2e/surrender.test.ts new file mode 100644 index 00000000..5ea47dfe --- /dev/null +++ b/src/e2e/surrender.test.ts @@ -0,0 +1,100 @@ +import { isTokenId } from "./utils/token-management"; +import { extractLine, extractStatus, LineInfo, run } from "./utils/shell"; +import { BurnAddress, defaultRunParameters, EndStatus, network, owner, receiver, TokenIdLength, TokenInfo } from "./utils/constants"; +import { BaseTitleEscrowCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { generateSurrenderCommand } from "./utils/commands"; +import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; +import { isAddress } from "web3-utils"; +import { deployTokenRegistry, mintTokenRegistry, checkSurrenderSuccess, checkFailure } from "./utils/bootstrap"; + + +const defaultTitleEscrow = { + ...defaultRunParameters, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, +}; + + +describe("surrender title-escrow", () => { + jest.setTimeout(90000); + + let tokenRegistryAddress = ""; + beforeAll(() => { + tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + }); + + it("should be able to surrender title-escrow on token-registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry, + tokenId, + }; + const signer = await getSigner(surrenderTitleEscrow.network, owner.privateKey); + let titleEscrowOwner: string = await retrieveTitleEscrowOwner( + signer, + surrenderTitleEscrow.tokenRegistry, + surrenderTitleEscrow.tokenId + ); + expect(isAddress(titleEscrowOwner)).toBe(true); + expect(titleEscrowOwner).not.toBe(surrenderTitleEscrow.tokenRegistry); + const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); + const results = run(command); + const surrenderResults = checkSurrenderSuccess(results); + expect(surrenderResults.tokenId).toBe(surrenderTitleEscrow.tokenId); + titleEscrowOwner = await retrieveTitleEscrowOwner( + signer, + surrenderTitleEscrow.tokenRegistry, + surrenderTitleEscrow.tokenId + ); + expect(titleEscrowOwner).toBe(surrenderTitleEscrow.tokenRegistry); + }); + + it("should not surrender unowned title escrow", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry, + tokenId, + }; + const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + const signer = await getSigner(surrenderTitleEscrow.network, owner.privateKey); + const titleEscrowOwner: string = await retrieveTitleEscrowOwner( + signer, + surrenderTitleEscrow.tokenRegistry, + surrenderTitleEscrow.tokenId + ); + expect(isAddress(titleEscrowOwner)).toBe(true); + expect(titleEscrowOwner).not.toBe(surrenderTitleEscrow.tokenRegistry); + }); + + it("should not surrender invalid title escrow", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry, + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", + }; + const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + }); + + it("should not surrender invalid title escrow with invalid token registry", async () => { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry: BurnAddress, + tokenId, + }; + const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); + const results = run(command); + checkFailure(results, "null"); + }); +}); diff --git a/src/e2e/utils/bootstrap/accept-surrender.ts b/src/e2e/utils/bootstrap/accept-surrender.ts new file mode 100644 index 00000000..4db06ade --- /dev/null +++ b/src/e2e/utils/bootstrap/accept-surrender.ts @@ -0,0 +1,20 @@ + +import { EndStatus, TokenIdLength } from "../constants"; +import { extractStatus } from "../shell"; +import { isTokenId } from "../token-management"; + +export const checkSurrenderAcceptSuccess = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, + }; + }; + \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/change-holder.ts b/src/e2e/utils/bootstrap/change-holder.ts new file mode 100644 index 00000000..849ee09a --- /dev/null +++ b/src/e2e/utils/bootstrap/change-holder.ts @@ -0,0 +1,45 @@ + +import { isAddress } from "web3-utils"; +import { mintTokenRegistry } from "."; +import { TitleEscrowTransferHolderCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { generateChangeHolderCommand } from "../commands"; +import { AddressLength, BurnAddress, defaultRunParameters, EndStatus, network, receiver, TokenIdLength } from "../constants"; +import { extractStatus, run } from "../shell"; +import { isTokenId } from "../token-management"; + +// ✔ success Transferable record with hash 0x9837ba0954300cf74dea2d7ee9f294a3d1ca0ce2fb8025a3de505440971a7baf's holder has been successfully changed to holder with address: 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 + + +export const defaultTransferHolder = { + newHolder: receiver.ethAddress, + network: network, + dryRun: false, + }; + +export const checkChangeHolderSuccess = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Change Holder failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const holder = titleEscrowAddressLine.substring(173, 173 + AddressLength); + + const holderIsAddress = isAddress(holder); + const isValidTokenId = isTokenId(tokenId); + + if (!holderIsAddress) throw new Error("Invalid holder address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + newHolder: holder, + tokenId, + }; + }; + + export const changeHolderToken = (privateKey: string, transferHolder: TitleEscrowTransferHolderCommand) => { + const command = generateChangeHolderCommand(transferHolder, privateKey); + const results = run(command); + checkChangeHolderSuccess(results); + } + + + \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/common.ts b/src/e2e/utils/bootstrap/common.ts new file mode 100644 index 00000000..2ff1b25e --- /dev/null +++ b/src/e2e/utils/bootstrap/common.ts @@ -0,0 +1,9 @@ +import { EndStatus } from "../constants"; +import { extractStatus } from "../shell"; + +export const checkFailure = (results: string, expectedErrorMessage: string) => { + const statusMessage = extractStatus(results, EndStatus.error); + expect(statusMessage.length).toBeGreaterThan(0); + const errorMessage = statusMessage[0].lineContent.substring(13); + expect(errorMessage).toContain(expectedErrorMessage); +}; \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/deploy.ts b/src/e2e/utils/bootstrap/deploy.ts new file mode 100644 index 00000000..d213b537 --- /dev/null +++ b/src/e2e/utils/bootstrap/deploy.ts @@ -0,0 +1,47 @@ +import { isAddress } from "web3-utils"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "../commands"; +import { defaultRunParameters, creators, EndStatus, AddressLength } from "../constants"; +import { extractStatus, run } from "../shell"; + +export const defaultTokenRegistry = { + ...defaultRunParameters, + factoryAddress: creators.titleEscrowFactory, + tokenImplementationAddress: creators.tokenImplementation, + deployerAddress: creators.deployer, +}; + +const numberGenerator = (range: number): number => { + return Math.floor(Math.random() * range); +}; + + +export const checkTokenRegistrySuccess = (results: string): string => { + const statusLine = extractStatus(results, EndStatus.success, "Token registry deployed at "); + if (statusLine.length <= 0) throw new Error("Deployment failed"); + const tokenRegistryDeploymentLine = statusLine[0].lineContent; + const tokenRegistry = tokenRegistryDeploymentLine.substring(40, 40 + AddressLength); + + const tokenRegistryIsAddress = isAddress(tokenRegistry); + if (!tokenRegistryIsAddress) throw new Error("Invalid token registry address"); + return tokenRegistry; +}; + + +export const deployTokenRegistry = ( + privateKey: string, + tokenRegistryParameters?: DeployTokenRegistryCommand +): string => { + if (!tokenRegistryParameters) { + const index = numberGenerator(100); + tokenRegistryParameters = { + ...defaultTokenRegistry, + registryName: `Test Token ${index}`, + registrySymbol: `TKN${index}`, + }; + } + const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); + const results = run(command); + const tokenRegistryAddress = checkTokenRegistrySuccess(results); + return tokenRegistryAddress; +}; diff --git a/src/e2e/utils/bootstrap/endorse-owners.ts b/src/e2e/utils/bootstrap/endorse-owners.ts new file mode 100644 index 00000000..ecd0c883 --- /dev/null +++ b/src/e2e/utils/bootstrap/endorse-owners.ts @@ -0,0 +1,28 @@ +import { isAddress } from "web3-utils"; +import { AddressLength, EndStatus, TokenIdLength } from "../constants"; +import { extractStatus } from "../shell"; +import { isTokenId } from "../token-management"; + + export const checkEndorseOwner = (results: string) => { + // ✔ success Transferable record with hash 0xffafc068018521a42a40ba1a8b9bf574c99c69763e42e155fae498278edb8074's holder has been successfully endorsed to new owner with address 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 and new holder with address: 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const beneficiary = titleEscrowAddressLine.substring(176, 176 + AddressLength); + const holder = titleEscrowAddressLine.substring(248, 248 + AddressLength); + + const beneficiaryIsAddress = isAddress(beneficiary); + const holderIsAddress = isAddress(holder); + const isValidTokenId = isTokenId(tokenId); + + if (!beneficiaryIsAddress) throw new Error("Invalid beneficiary address"); + if (!holderIsAddress) throw new Error("Invalid holder address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + beneficiary, + holder, + tokenId, + }; + } \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/endorse-transfer.ts b/src/e2e/utils/bootstrap/endorse-transfer.ts new file mode 100644 index 00000000..090628f0 --- /dev/null +++ b/src/e2e/utils/bootstrap/endorse-transfer.ts @@ -0,0 +1,23 @@ +import { isAddress } from "web3-utils"; +import { AddressLength, EndStatus, TokenIdLength } from "../constants"; +import { extractStatus } from "../shell"; +import { isTokenId } from "../token-management"; + + export const checkEndorseTransfer = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const beneficiary = titleEscrowAddressLine.substring(177, 177 + AddressLength); + + const beneficiaryIsAddress = isAddress(beneficiary); + const isValidTokenId = isTokenId(tokenId); + + if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + beneficiary, + tokenId, + }; + } \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/index.ts b/src/e2e/utils/bootstrap/index.ts new file mode 100644 index 00000000..53aea86a --- /dev/null +++ b/src/e2e/utils/bootstrap/index.ts @@ -0,0 +1,11 @@ +export * from "./common"; +export * from "./deploy"; +export * from "./mint"; +export * from "./nominate"; +export * from "./endorse-transfer"; +export * from "./endorse-owners"; +export * from "./change-holder"; +export * from "./surrender"; +export * from "./reject-surrender"; +export * from "./accept-surrender"; + diff --git a/src/e2e/utils/bootstrap/mint.ts b/src/e2e/utils/bootstrap/mint.ts new file mode 100644 index 00000000..d4615fa1 --- /dev/null +++ b/src/e2e/utils/bootstrap/mint.ts @@ -0,0 +1,85 @@ +import { Wallet } from "ethers"; +import { isAddress } from "web3-utils"; +import { deployTokenRegistry } from "."; +import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; +import { generateMintTitleEscrowCommand } from "../commands"; +import { AddressLength, defaultRunParameters, EndStatus, TokenIdLength, TokenInfo } from "../constants"; +import { getSigner, retrieveTitleEscrowOwner } from "../contract-checks"; +import { extractStatus, run } from "../shell"; +import { generateTokenId, isTokenId } from "../token-management"; + +export interface MintData { + tokenId: string; + address: string; + beneficiary: string; + holder: string; +} + +export const validateMintData = (expectedValue: MintData, value: MintData) => { + expect(expectedValue.address).toBe(value.address); + expect(expectedValue.beneficiary).toBe(value.beneficiary); + expect(expectedValue.holder).toBe(value.holder); + expect(expectedValue.tokenId).toBe(value.tokenId); +}; + +export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { + if (!tokenRegistryAddress) { + tokenRegistryAddress = deployTokenRegistry(privateKey); + } + if (!isAddress(tokenRegistryAddress)) throw new Error("Invalid Token Registry Address"); + const wallet = new Wallet(privateKey); + const titleEscrowParameter: TokenRegistryIssueCommand = { + ...defaultRunParameters, + address: tokenRegistryAddress, + beneficiary: wallet.address, + holder: wallet.address, + tokenId: generateTokenId(), + }; + + return mintToken(privateKey, titleEscrowParameter); +}; + + +export const checkMintSuccess = (results: string): MintData => { + const statusLine = extractStatus(results, EndStatus.success, "Token with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(29, 29 + TokenIdLength); + const address = titleEscrowAddressLine.substring(115, 115 + AddressLength); + const beneficiary = titleEscrowAddressLine.substring(191, 191 + AddressLength); + const holder = titleEscrowAddressLine.substring(253, 253 + AddressLength); + + const tokenRegistryAddressIsAddress = isAddress(address); + const beneficiaryIsAddress = isAddress(beneficiary); + const holderIsAddress = isAddress(holder); + const isValidTokenId = isTokenId(tokenId); + + if (!tokenRegistryAddressIsAddress) throw new Error("Invalid token registry address"); + if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); + if (!holderIsAddress) throw new Error("Invalid holder address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + address, + beneficiary, + holder, + tokenId, + }; +}; + +export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { + const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); + const results = run(command); + const {address: tokenRegistry, tokenId, beneficiary, holder} = checkMintSuccess(results); + const signer = getSigner(titleEscrowParameter.network, privateKey); + // let titleEscrowAddress: string = retrieveTitleEscrowOwner( + // signer, + // tokenRegistry, + // tokenId, + // ); + return { + tokenRegistry, + tokenId, + // titleEscrowAddress, + }; +}; diff --git a/src/e2e/utils/bootstrap/nominate.ts b/src/e2e/utils/bootstrap/nominate.ts new file mode 100644 index 00000000..ec476111 --- /dev/null +++ b/src/e2e/utils/bootstrap/nominate.ts @@ -0,0 +1,54 @@ +import { isAddress } from "web3-utils"; +import { mintTokenRegistry } from "."; +import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { generateNominateCommand } from "../commands"; +import { AddressLength, defaultRunParameters, EndStatus, network, owner, receiver, TokenIdLength, TokenInfo } from "../constants"; +import { extractStatus, run } from "../shell"; +import { isTokenId } from "../token-management"; + +export const defaultNominateBeneficiary = { + ...defaultRunParameters, + newBeneficiary: receiver.ethAddress, +}; + +export const mintNominatedToken = (privateKey: string, nominee: string, tokenRegistryAddress?: string): TokenInfo => { + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = tokenDetails; + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newBeneficiary: nominee, + }; + nominateToken(privateKey, nominateParameter); + return tokenDetails; + }; + + + export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { + const command = generateNominateCommand(nominateParameter, privateKey); + const results = run(command); + checkNominateSuccess(results); + }; + + + +export const checkNominateSuccess = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Nomination failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const nominee = titleEscrowAddressLine.substring(177, 177 + AddressLength); + + const nomineeIsAddress = isAddress(nominee); + const isValidTokenId = isTokenId(tokenId); + + if (!nomineeIsAddress) throw new Error("Invalid nominee address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + nominee, + tokenId, + }; + }; + \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/reject-surrender.ts b/src/e2e/utils/bootstrap/reject-surrender.ts new file mode 100644 index 00000000..fef9f0ec --- /dev/null +++ b/src/e2e/utils/bootstrap/reject-surrender.ts @@ -0,0 +1,20 @@ + +import { EndStatus, TokenIdLength } from "../constants"; +import { extractStatus } from "../shell"; +import { isTokenId } from "../token-management"; + +export const checkSurrenderRejectSuccess = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, + }; + }; + \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/surrender.ts b/src/e2e/utils/bootstrap/surrender.ts new file mode 100644 index 00000000..4e215ad6 --- /dev/null +++ b/src/e2e/utils/bootstrap/surrender.ts @@ -0,0 +1,48 @@ +import { mintTokenRegistry } from "."; +import { BaseTitleEscrowCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { generateSurrenderCommand } from "../commands"; +import { defaultRunParameters, EndStatus, owner, TokenIdLength, TokenInfo } from "../constants"; +import { extractStatus, run } from "../shell"; +import { isTokenId } from "../token-management"; + +const defaultTitleEscrow = { + ...defaultRunParameters, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, +}; + +export const mintSurrenderToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId, titleEscrowAddress } = tokenDetails; + const surrenderParameter: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry: tokenRegistry, + tokenId: tokenId, + }; + surrenderToken(privateKey, surrenderParameter); + return tokenDetails; + }; + + + export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { + const command = generateSurrenderCommand(surrenderParameter, privateKey); + const results = run(command); + checkSurrenderSuccess(results); + }; + + +export const checkSurrenderSuccess = (results: string) => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Nomination failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, + }; + }; + \ No newline at end of file diff --git a/src/__tests__/fixture/e2e/commands.ts b/src/e2e/utils/commands.ts similarity index 94% rename from src/__tests__/fixture/e2e/commands.ts rename to src/e2e/utils/commands.ts index c7f4c273..962d8d61 100644 --- a/src/__tests__/fixture/e2e/commands.ts +++ b/src/e2e/utils/commands.ts @@ -1,11 +1,11 @@ -import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../commands/deploy/deploy.types"; import { BaseTitleEscrowCommand, TitleEscrowEndorseTransferOfOwnersCommand, TitleEscrowNominateBeneficiaryCommand, TitleEscrowTransferHolderCommand, -} from "../../../commands/title-escrow/title-escrow-command.type"; -import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; +} from "../../commands/title-escrow/title-escrow-command.type"; +import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; const command = `npm run dev --`; diff --git a/src/__tests__/fixture/e2e/constants.ts b/src/e2e/utils/constants.ts similarity index 58% rename from src/__tests__/fixture/e2e/constants.ts rename to src/e2e/utils/constants.ts index c0f94982..7b0a1ca9 100644 --- a/src/__tests__/fixture/e2e/constants.ts +++ b/src/e2e/utils/constants.ts @@ -1,5 +1,6 @@ +// import { NonceManager } from "@ethersproject/experimental"; import { constants } from "@govtechsg/token-registry"; - +import { providers, Wallet } from "ethers"; export const { contractAddress } = constants; export const network = "local"; @@ -8,6 +9,9 @@ export const forkedNetwork = 5; export const mnemonic = "indicate swing place chair flight used hammer soon photo region volume shuffle"; +export const BurnAddress = "0x0000000000000000000000000000000000000000"; +export const EmptyTokenID = "0x0000000000000000000000000000000000000000000000000000000000000000"; + export const owner = { ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", @@ -26,10 +30,30 @@ export const creators = { tokenImplementation: contractAddress.TokenImplementation[forkedNetwork], }; -export const emoji = { - tick: "✔", - cross: "✖", -}; +export const EndStatus = { + success: "✔ success", + error: "✖ error", +} as const; + +export const TokenIdLength = 66; +export const AddressLength = 42; -export const silent = true; +export type EndStatusType = typeof EndStatus[keyof typeof EndStatus]; + +export const silent = false; export const verbose = false; +export const defaultRunParameters = { + network: network, + dryRun: false, +}; + +export interface TokenInfo { + tokenRegistry: string; + tokenId: string; + titleEscrowAddress?: string; +} + +export interface Owners { + owner: string; + holder: string; +} diff --git a/src/e2e/utils/contract-checks.ts b/src/e2e/utils/contract-checks.ts new file mode 100644 index 00000000..f344eea9 --- /dev/null +++ b/src/e2e/utils/contract-checks.ts @@ -0,0 +1,170 @@ +import { Provider } from "@ethersproject/abstract-provider"; +import { constants } from "@govtechsg/token-registry"; +import { + TitleEscrow__factory, + TradeTrustToken, + TradeTrustToken__factory, +} from "@govtechsg/token-registry/dist/contracts"; +import { BigNumber, Signer, Wallet } from "ethers"; +import { getSupportedNetwork } from "../../commands/networks"; +import { addAddressPrefix } from "../../utils"; +import { TokenInfo } from "./constants"; + +type SignerOrProvider = Signer | Provider; + +export interface TokenRegistryInfo { + name: string; + symbol: string; +} + +export interface TitleEscrowInfo { + titleEscrow: string; + beneficiary: string; + holder: string; + nominee: string; + active: boolean; + tokenId: BigNumber; + registry: string; + isHoldingToken: boolean; +} + +export interface RolesInfo { + minterRole: boolean; + accepterRole: boolean; + restorerRole: boolean; + defaultRole: boolean; +} + +export const retrieveWalletEscrowDetails = async ( + signer: Signer, + tokenInfo: TokenInfo +): Promise => { + const escrowDetails = await retrieveEscrowDetails(signer, tokenInfo); + const titleEscrowDetails = await rolesCheck(signer, tokenInfo.tokenRegistry); + return { + ...escrowDetails, + ...titleEscrowDetails, + }; +}; + +export const retrieveEscrowDetails = async ( + signerOrProvider: SignerOrProvider, + tokenInfo: TokenInfo +): Promise => { + //TODO: check ownership + const { tokenRegistry, tokenId, titleEscrowAddress } = tokenInfo; + if(!titleEscrowAddress) throw new Error("Escrow Address unspecified"); + const tokenDetails = await retrieveTokenInfo(signerOrProvider, tokenRegistry); + let titleEscrowDetails: TitleEscrowInfo | undefined; + if (!titleEscrowAddress) { + titleEscrowDetails = await retrieveTitleEscrowInfo(signerOrProvider, titleEscrowAddress); + } else { + titleEscrowDetails = await retrieveTitleEscrow(signerOrProvider, tokenRegistry, tokenId); + } + return { + ...tokenDetails, + ...titleEscrowDetails, + }; +}; + +export const retrieveTokenInfo = async ( + signerOrProvider: SignerOrProvider, + tokenRegistry: string +): Promise => { + const token: TradeTrustToken = TradeTrustToken__factory.connect(tokenRegistry, signerOrProvider); + const namePromise = token.name(); + const symbolPromise = token.symbol(); + const [name, symbol] = await Promise.all([namePromise, symbolPromise]); + return { + name, + symbol, + }; +}; + +export const retrieveTitleEscrow = async ( + signerOrProvider: SignerOrProvider, + tokenRegistry: string, + tokenId: string +): Promise => { + const token: TradeTrustToken = TradeTrustToken__factory.connect(tokenRegistry, signerOrProvider); + const escrowAddress = await token.ownerOf(tokenId); + return retrieveTitleEscrowInfo(signerOrProvider, escrowAddress); +}; + +export const retrieveTitleEscrowOwner = async ( + signerOrProvider: SignerOrProvider, + tokenRegistry: string, + tokenId: string +): Promise => { + const token: TradeTrustToken = TradeTrustToken__factory.connect(tokenRegistry, signerOrProvider); + const escrowAddress = await token.ownerOf(tokenId); + return escrowAddress; +}; + +export const retrieveTitleEscrowInfo = async ( + signerOrProvider: SignerOrProvider, + titleEscrowAddress: string +): Promise => { + const titleEscrow = TitleEscrow__factory.connect(titleEscrowAddress, signerOrProvider); + const beneficiaryPromise: Promise = titleEscrow.beneficiary(); + const holderPromise: Promise = titleEscrow.holder(); + const nomineePromise: Promise = titleEscrow.nominee(); + const activePromise: Promise = titleEscrow.active(); + const tokenIdPromise: Promise = titleEscrow.tokenId(); + const registryPromise: Promise = titleEscrow.registry(); + const isHoldingTokenPromise: Promise = titleEscrow.isHoldingToken(); + + const [beneficiary, holder, nominee, active, tokenId, registry, isHoldingToken] = await Promise.all([ + beneficiaryPromise, + holderPromise, + nomineePromise, + activePromise, + tokenIdPromise, + registryPromise, + isHoldingTokenPromise, + ]); + return { + titleEscrow: titleEscrowAddress, + beneficiary, + holder, + nominee, + active, + tokenId, + registry, + isHoldingToken, + }; +}; + +export const rolesCheck = async (signerOrProvider: Signer, tokenRegistry: string): Promise => { + const token: TradeTrustToken = TradeTrustToken__factory.connect(tokenRegistry, signerOrProvider); + const walletAddress: string = await signerOrProvider.getAddress(); + const minterPromise = token.hasRole(constants.roleHash.MinterRole, walletAddress); + const accepterPromise = token.hasRole(constants.roleHash.AccepterRole, walletAddress); + const restorerPromise = token.hasRole(constants.roleHash.RestorerRole, walletAddress); + const defaultPromise = token.hasRole(constants.roleHash.DefaultAdmin, walletAddress); + const [minterRole, accepterRole, restorerRole, defaultRole] = await Promise.all([ + minterPromise, + accepterPromise, + restorerPromise, + defaultPromise, + ]); + return { + minterRole, + accepterRole, + restorerRole, + defaultRole, + }; +}; + +export const getSigner = (network: string, privateKey: string): Signer => { + return getSignerOrProvider(network, privateKey) as Signer; +}; + +export const getSignerOrProvider = (network: string, privateKey?: string): SignerOrProvider => { + const provider = getSupportedNetwork(network ?? "local").provider(); + if (privateKey) { + const hexlifiedPrivateKey = addAddressPrefix(privateKey); + return new Wallet(hexlifiedPrivateKey, provider); + } + return provider; +}; diff --git a/src/__tests__/fixture/e2e/shell.ts b/src/e2e/utils/shell.ts similarity index 71% rename from src/__tests__/fixture/e2e/shell.ts rename to src/e2e/utils/shell.ts index e33a3fb3..10aaa9c5 100644 --- a/src/__tests__/fixture/e2e/shell.ts +++ b/src/e2e/utils/shell.ts @@ -1,6 +1,6 @@ import shell, { ShellString } from "shelljs"; import { log } from "signale"; -import { emoji, verbose } from "./constants"; +import { EndStatus, verbose, silent as globalSilent, EndStatusType } from "./constants"; shell.config.silent = true; export interface LineInfo { @@ -8,25 +8,28 @@ export interface LineInfo { lineContent: string; } -export const run = (command: string, silent = false): string => { - shell.config.silent = !(!silent && verbose); +export const run = (command: string, silent = true): string => { + silent = silent && globalSilent; const rawResults: ShellString = shell.exec(command); const results = stripAnsi(rawResults.trim()); if (!silent) { - const success = `${emoji.tick} success`; - const failure = `${emoji.cross} error`; - let successLines = extractLine(results, success); - if (!successLines) successLines = []; - let failureLines = extractLine(results, failure); - if (!failureLines) failureLines = []; - const statusLines: LineInfo[] = [...successLines, ...failureLines]; + const successLines = extractStatus(results, EndStatus.success); + const failureLines = extractStatus(results, EndStatus.error); + const statusLines = [...successLines, ...failureLines]; log(command); printLines(statusLines); - if (verbose && failureLines.length > 0) log(rawResults); + if (verbose && failureLines.length > 0) log(results); } return results; }; +export const extractStatus = (results: string, expectedStatus: EndStatusType, expectedMessage = ""): LineInfo[] => { + const expectedString = `${expectedStatus} ${expectedMessage}`; + let lineInfo = extractLine(results, expectedString); + if (!lineInfo) lineInfo = []; + return lineInfo; +}; + export const printLines = (lines: LineInfo[]): void => { lines.sort((a: LineInfo, b: LineInfo): number => { return a.lineNumber - b.lineNumber; diff --git a/src/e2e/utils/token-management.ts b/src/e2e/utils/token-management.ts new file mode 100644 index 00000000..c5a43384 --- /dev/null +++ b/src/e2e/utils/token-management.ts @@ -0,0 +1,22 @@ +const retries = 10; +const usedTokenIds = new Set(); +export const generateTokenId = (): string => { + for (let count = 0; count < retries; count = count + 1) { + const generatedTokenId = `0x${[...Array(64)].map(() => Math.floor(Math.random() * 16).toString(16)).join("")}`; + const unique = !usedTokenIds.has(generatedTokenId); + if (unique) { + usedTokenIds.add(generatedTokenId); + return generatedTokenId; + } + } + throw new Error("Unable to generate tokenIds"); +}; + +export const isTokenId = (tokenId: string) => { + const hexRegex = /[0-9A-Fa-f]{6}/g; + tokenId = tokenId.trim(); + const containsHexPrefix = tokenId.substring(0, 2) === "0x"; + if (containsHexPrefix) tokenId = tokenId.substring(2); + if (tokenId.length <= 0) return false; + return tokenId.match(hexRegex); +}; From 1a2c73441005cb422a142f1dee6004fde9e9e32f Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Mon, 9 Jan 2023 17:41:37 +0800 Subject: [PATCH 52/63] feat: remove jest --- .circleci/config.yml | 3 + .gitignore | 3 +- package-lock.json | 54 +++++++++++++ package.json | 3 + ...render.test.ts => accept-surrender.e2e.ts} | 39 +++++----- src/e2e/all.ts | 22 ++++++ ...ge-holder.test.ts => change-holder.e2e.ts} | 39 +++++----- src/e2e/{deploy.test.ts => deploy.e2e.ts} | 42 +++++----- ...er.test.ts => endorse-change-owner.e2e.ts} | 29 +++---- ...ansfer.test.ts => endorse-transfer.e2e.ts} | 23 +++--- src/e2e/{mint.test.ts => mint.e2e.ts} | 76 ++++++++++--------- src/e2e/{nominate.test.ts => nominate.e2e.ts} | 55 ++++++++------ ...render.test.ts => reject-surrender.e2e.ts} | 36 ++++----- .../{surrender.test.ts => surrender.e2e.ts} | 39 +++++----- src/e2e/utils/bootstrap/common.ts | 6 +- src/e2e/utils/bootstrap/mint.ts | 8 +- src/e2e/utils/constants.ts | 2 +- 17 files changed, 289 insertions(+), 190 deletions(-) rename src/e2e/{accept-surrender.test.ts => accept-surrender.e2e.ts} (70%) create mode 100644 src/e2e/all.ts rename src/e2e/{change-holder.test.ts => change-holder.e2e.ts} (83%) rename src/e2e/{deploy.test.ts => deploy.e2e.ts} (57%) rename src/e2e/{endorse-change-owner.test.ts => endorse-change-owner.e2e.ts} (68%) rename src/e2e/{endorse-transfer.test.ts => endorse-transfer.e2e.ts} (78%) rename src/e2e/{mint.test.ts => mint.e2e.ts} (65%) rename src/e2e/{nominate.test.ts => nominate.e2e.ts} (72%) rename src/e2e/{reject-surrender.test.ts => reject-surrender.e2e.ts} (68%) rename src/e2e/{surrender.test.ts => surrender.e2e.ts} (76%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a55a07b..ff0ba4dc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,6 +25,9 @@ jobs: - run: name: test command: npm run test -- --runInBand + - run: + name: e2e + command: npm run e2e - run: name: benchmark wrap functionality command: npm run benchmark diff --git a/.gitignore b/.gitignore index ab1e9684..6485857d 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ yarn.lock /tmp key /.vscode/ -/vc-test-suite \ No newline at end of file +/vc-test-suite +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 2cbcf9f7..5c59f67c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6374,6 +6374,48 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concurrently": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz", + "integrity": "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "date-fns": "^2.16.1", + "lodash": "^4.17.21", + "rxjs": "^6.6.3", + "spawn-command": "^0.0.2-1", + "supports-color": "^8.1.0", + "tree-kill": "^1.2.2", + "yargs": "^16.2.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + } + } + }, "configstore": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", @@ -6717,6 +6759,12 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", + "dev": true + }, "dateformat": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", @@ -16082,6 +16130,12 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==", + "dev": true + }, "spawn-error-forwarder": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", diff --git a/package.json b/package.json index 10e83e70..331ecbe5 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "scripts": { "dev": "ts-node src/index.ts", + "e2e": "concurrently -k -s first \"npm:blockchain\" \"npm:e2e-test\"", "build": "npm run clean && npm run build:cjs && npm run build:type", "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", @@ -19,6 +20,7 @@ "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", + "e2e-test": "ts-node src/e2e/all.ts", "lint": "eslint . --ext .ts --max-warnings 0", "lint:fix": "eslint . --ext .ts --fix", "benchmark:make-certs": "./scripts/makeCerts.sh 20000", @@ -56,6 +58,7 @@ "@typescript-eslint/eslint-plugin": "^4.24.0", "@typescript-eslint/parser": "^4.24.0", "commitizen": "^4.2.4", + "concurrently": "^6.2.0", "eslint": "^7.26.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-jest": "^24.3.6", diff --git a/src/e2e/accept-surrender.test.ts b/src/e2e/accept-surrender.e2e.ts similarity index 70% rename from src/e2e/accept-surrender.test.ts rename to src/e2e/accept-surrender.e2e.ts index f8b86e12..3c4ce096 100644 --- a/src/e2e/accept-surrender.test.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -4,14 +4,11 @@ import { generateAcceptSurrenderCommand } from "./utils/commands"; import { checkFailure, checkSurrenderAcceptSuccess, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; import { getSigner, retrieveTitleEscrow, retrieveTitleEscrowInfo, retrieveTitleEscrowOwner } from "./utils/contract-checks"; -describe("accept-surrender title-escrow", () => { - jest.setTimeout(90000); - - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - +// describe("accept-surrender title-escrow", () => { +export const acceptSurrender = async () => { + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + // const errors: Error[] = []; const defaultTitleEscrow = { beneficiary: owner.ethAddress, holder: owner.ethAddress, @@ -19,7 +16,8 @@ describe("accept-surrender title-escrow", () => { dryRun: false, }; - it("should be able to accept-surrender title-escrow on token-registry", async () => { + // it("should be able to accept-surrender title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId, titleEscrowAddress } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); @@ -28,33 +26,36 @@ describe("accept-surrender title-escrow", () => { tokenRegistry, tokenId ); - expect(titleEscrowOwner).toBe(tokenRegistry); + if(!(titleEscrowOwner === tokenRegistry)) throw new Error(`!(titleEscrowOwner === tokenRegistry)`); + const results = run(command); titleEscrowOwner = await retrieveTitleEscrowOwner( signer, tokenRegistry, tokenId ); - expect(titleEscrowOwner).toBe("0x000000000000000000000000000000000000dEaD"); + if(!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")) throw new Error(`!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")`); checkSurrenderAcceptSuccess(results); - }); + } - it("should not be able to accept surrender invalid title-escrow on token-registry", async () => { + // it("should not be able to accept surrender invalid title-escrow on token-registry", async () => { + { const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should not be able to accept surrender title-escrow on invalid token-registry", async () => { + // it("should not be able to accept surrender title-escrow on invalid token-registry", async () => { + { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); - - it.todo("should be fail when permission is denied"); -}); + } + // return errors; + // it.todo("should be fail when permission is denied"); +}; // npm run dev -- title-escrow accept-surrendered --token-registry 0x0000000000000000000000000000000000000000 --tokenId 0xf32907ec66ac258f058eae34d76b160b0ca520b5c613ca93ae6bb22a8f9c451f --network local -k 0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7 \ No newline at end of file diff --git a/src/e2e/all.ts b/src/e2e/all.ts new file mode 100644 index 00000000..1311e709 --- /dev/null +++ b/src/e2e/all.ts @@ -0,0 +1,22 @@ +import { acceptSurrender } from './accept-surrender.e2e' +import { surrender } from './surrender.e2e' +import { changeHolder } from './change-holder.e2e' +import { deployDocumentStore, deployTokenRegistry } from './deploy.e2e'; +import { endorseTransfer } from './endorse-transfer.e2e'; +import { mint } from './mint.e2e'; +import { nominate } from './nominate.e2e'; +import { rejectSurrender } from './reject-surrender.e2e'; + +const awaitForDuration = async (runFunction: Function) => { + await runFunction(); +} + +awaitForDuration(surrender); +awaitForDuration(acceptSurrender); +awaitForDuration(deployDocumentStore); +awaitForDuration(deployTokenRegistry); +awaitForDuration(changeHolder); +awaitForDuration(endorseTransfer); +awaitForDuration(mint); +awaitForDuration(nominate); +awaitForDuration(rejectSurrender); \ No newline at end of file diff --git a/src/e2e/change-holder.test.ts b/src/e2e/change-holder.e2e.ts similarity index 83% rename from src/e2e/change-holder.test.ts rename to src/e2e/change-holder.e2e.ts index 12eb4060..2dd672e1 100644 --- a/src/e2e/change-holder.test.ts +++ b/src/e2e/change-holder.e2e.ts @@ -5,15 +5,14 @@ import { generateChangeHolderCommand } from "./utils/commands"; import { checkFailure, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; import { changeHolderToken, checkChangeHolderSuccess, defaultTransferHolder } from "./utils/bootstrap"; -describe("transfer holder title-escrow", () => { - jest.setTimeout(90000); +// describe("transfer holder title-escrow", () => { +export const changeHolder = async () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - it("should be able to transfer holder title-escrow on token-registry", async () => { + // it("should be able to transfer holder title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: tokenId, @@ -23,10 +22,11 @@ describe("transfer holder title-escrow", () => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); checkChangeHolderSuccess(results); - }); + } - it("holder should be able to transfer holder of title-escrow", async () => { + // it("holder should be able to transfer holder of title-escrow", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver const initialHolder: TitleEscrowTransferHolderCommand = { @@ -48,9 +48,10 @@ describe("transfer holder title-escrow", () => { // Holder attempts to transfer Holder with permission const results = run(command); checkChangeHolderSuccess(results); - }); + } - it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + // it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: EmptyTokenID, @@ -60,10 +61,11 @@ describe("transfer holder title-escrow", () => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + // it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: tokenId, @@ -73,9 +75,10 @@ describe("transfer holder title-escrow", () => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); + } - it("beneficiary should not be able to transfer holder of title-escrow", async () => { + // it("beneficiary should not be able to transfer holder of title-escrow", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver const initialHolder: TitleEscrowTransferHolderCommand = { @@ -97,7 +100,5 @@ describe("transfer holder title-escrow", () => { // Beneficiary attempts to transfer Holder without permission const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); - - -}); + } +}; diff --git a/src/e2e/deploy.test.ts b/src/e2e/deploy.e2e.ts similarity index 57% rename from src/e2e/deploy.test.ts rename to src/e2e/deploy.e2e.ts index 48f489ab..b783fab1 100644 --- a/src/e2e/deploy.test.ts +++ b/src/e2e/deploy.e2e.ts @@ -6,10 +6,12 @@ import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/bootstrap"; -describe("deploy token-registry", () => { - jest.setTimeout(90000); +export const deployTokenRegistry = async () => { +// describe("deploy token-registry", () => { + // jest.setTimeout(90000); - it("should be able to deploy token-registry", async () => { + // it("should be able to deploy token-registry", async () => { + { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", registrySymbol: "TKN", @@ -21,20 +23,21 @@ describe("deploy token-registry", () => { const tokenRegistryAddress = checkTokenRegistrySuccess(results); const signer = getSigner(defaultRunParameters.network, owner.privateKey); const tokenInfo = await retrieveTokenInfo(signer, tokenRegistryAddress); - expect(tokenInfo.name).toBe(tokenRegistryParameter.registryName); - expect(tokenInfo.symbol).toBe(tokenRegistryParameter.registrySymbol); + if(!(tokenInfo.name === tokenRegistryParameter.registryName)){ throw new Error("tokenInfo.name === tokenRegistryParameter.registryName")}; + if(!(tokenInfo.symbol === tokenRegistryParameter.registrySymbol)){ throw new Error("tokenInfo.symbol === tokenRegistryParameter.registrySymbol")}; const rolesInfo = await rolesCheck(signer, tokenRegistryAddress); - expect(rolesInfo.accepterRole).toBe(true); - expect(rolesInfo.defaultRole).toBe(true); - expect(rolesInfo.minterRole).toBe(true); - expect(rolesInfo.restorerRole).toBe(true); - }); -}); + if(!(rolesInfo.accepterRole === true)){ throw new Error("rolesInfo.accepterRole === true")}; + if(!(rolesInfo.defaultRole === true)){ throw new Error("rolesInfo.defaultRole === true")}; + if(!(rolesInfo.minterRole === true)){ throw new Error("rolesInfo.minterRole === true")}; + if(!(rolesInfo.restorerRole === true)){ throw new Error("rolesInfo.restorerRole === true")}; + } +} -describe("deploy document-store", () => { - jest.setTimeout(90000); - - it("should be able to deploy document-store", async () => { +// describe("deploy document-store", () => { +export const deployDocumentStore = () => { + // jest.setTimeout(90000); + // it("should be able to deploy document-store", async () => + { const documentStoreParameters: DeployDocumentStoreCommand = { storeName: "Test Document Store", ...defaultRunParameters, @@ -44,10 +47,11 @@ describe("deploy document-store", () => { const results = run(command); const tokenRegistrySuccessFormat = `${EndStatus.success} Document store Test Document Store deployed at `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); - expect(checkSuccess).toBe(true); + if(!(checkSuccess === true)) throw new Error(`checkSuccess === true)`); const splitResults = results.trim().split("\n"); const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); - expect(isAddress(tokenRegistryAddress)).toBe(true); - }); -}); + if(!(isAddress(tokenRegistryAddress) === true)) throw new Error(`isAddress(tokenRegistryAddress) === true)`); + if(!(isAddress(tokenRegistryAddress) === true)){ throw new Error("isAddress(tokenRegistryAddress) === true")}; + } +} diff --git a/src/e2e/endorse-change-owner.test.ts b/src/e2e/endorse-change-owner.e2e.ts similarity index 68% rename from src/e2e/endorse-change-owner.test.ts rename to src/e2e/endorse-change-owner.e2e.ts index 5cba8185..2f30c756 100644 --- a/src/e2e/endorse-change-owner.test.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -4,13 +4,12 @@ import { TitleEscrowEndorseTransferOfOwnersCommand } from "../commands/title-esc import { generateTransferOwnersCommand } from "./utils/commands"; import { changeHolderToken, checkEndorseOwner, checkFailure, deployTokenRegistry, mintNominatedToken, mintTokenRegistry } from "./utils/bootstrap"; -describe("endorse change owner title-escrow", () => { - jest.setTimeout(90000); +// describe("endorse change owner title-escrow", () => { +export const endorseChangeOwner = () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTransferOwners = { newOwner: receiver.ethAddress, @@ -19,7 +18,8 @@ describe("endorse change owner title-escrow", () => { dryRun: false, }; - it("should be able to endorse change owner title-escrow on token-registry", async () => { + // it("should be able to endorse change owner title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, defaultTransferOwners.newOwner, @@ -33,12 +33,13 @@ describe("endorse change owner title-escrow", () => { const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); const { beneficiary, holder, tokenId: tokenIdResult } = checkEndorseOwner(results); - expect(beneficiary).toBe(transferOwners.newOwner); - expect(holder).toBe(transferOwners.newHolder); - expect(tokenIdResult).toBe(transferOwners.tokenId); - }); + if(!(beneficiary === transferOwners.newOwner)) throw new Error(`beneficiary === transferOwners.newOwner`); + if(!(holder === transferOwners.newHolder)) throw new Error(`holder === transferOwners.newHolder`); + if(!(tokenIdResult === transferOwners.tokenId)) throw new Error(`tokenIdResult === transferOwners.tokenId`); + } - it("should not be able to endorse change owner on un-nominated title-escrow", async () => { + // it("should not be able to endorse change owner on un-nominated title-escrow", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry( owner.privateKey, tokenRegistryAddress @@ -51,5 +52,5 @@ describe("endorse change owner title-escrow", () => { const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); checkFailure(results, "") - }); -}); + } +} diff --git a/src/e2e/endorse-transfer.test.ts b/src/e2e/endorse-transfer.e2e.ts similarity index 78% rename from src/e2e/endorse-transfer.test.ts rename to src/e2e/endorse-transfer.e2e.ts index 3ad49afe..01badae4 100644 --- a/src/e2e/endorse-transfer.test.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -4,13 +4,12 @@ import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/ import { generateEndorseTransferOwnerCommand } from "./utils/commands"; import { checkEndorseTransfer, checkFailure, deployTokenRegistry, mintNominatedToken, mintToken, mintTokenRegistry } from "./utils/bootstrap"; -describe("endorse transfer title-escrow", () => { - jest.setTimeout(90000); +// describe("endorse transfer title-escrow", () => { +export const endorseTransfer = async () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTransferHolder = { newBeneficiary: receiver.ethAddress, @@ -18,7 +17,8 @@ describe("endorse transfer title-escrow", () => { dryRun: false, }; - it("should be able to endorse transfer title-escrow on token-registry", async () => { + // it("should be able to endorse transfer title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, defaultTransferHolder.newBeneficiary, @@ -33,10 +33,11 @@ describe("endorse transfer title-escrow", () => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); checkEndorseTransfer(results); - }); + } - it("should not be able to endorse un-nominated title-escrow on token-registry", async () => { + // it("should not be able to endorse un-nominated title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry( owner.privateKey, tokenRegistryAddress @@ -51,6 +52,6 @@ describe("endorse transfer title-escrow", () => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, ""); - }); + } -}); +} diff --git a/src/e2e/mint.test.ts b/src/e2e/mint.e2e.ts similarity index 65% rename from src/e2e/mint.test.ts rename to src/e2e/mint.e2e.ts index 19f6c5f5..e0c5086e 100644 --- a/src/e2e/mint.test.ts +++ b/src/e2e/mint.e2e.ts @@ -18,15 +18,15 @@ import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/bootstrap"; -describe("deploy token-registry", () => { - jest.setTimeout(90000); +export const mint = async () => { +// describe("deploy token-registry", () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - it("should be able to mint title-escrow on token-registry", async () => { + // it("should be able to mint title-escrow on token-registry", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, @@ -46,17 +46,18 @@ describe("deploy token-registry", () => { titleEscrowParameter.address, titleEscrowParameter.tokenId ); - expect(titleEscrowInfo.active).toBe(true); - expect(titleEscrowInfo.beneficiary).toBe(titleEscrowParameter.beneficiary); - expect(titleEscrowInfo.holder).toBe(titleEscrowParameter.holder); - expect(titleEscrowInfo.isHoldingToken).toBe(true); - expect(titleEscrowInfo.nominee).toBe(BurnAddress); - expect(titleEscrowInfo.registry).toBe(titleEscrowParameter.address); + if(!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if(!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if(!(titleEscrowInfo.holder === titleEscrowParameter.holder)) throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if(!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if(!(titleEscrowInfo.registry === titleEscrowParameter.address)) throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); - expect(correctTokenID).toBe(true); - }); + if(!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } - it("should be able to mint title-escrow for a different wallet on token-registry", async () => { + // it("should be able to mint title-escrow for a different wallet on token-registry", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, @@ -76,17 +77,18 @@ describe("deploy token-registry", () => { titleEscrowParameter.address, titleEscrowParameter.tokenId ); - expect(titleEscrowInfo.active).toBe(true); - expect(titleEscrowInfo.beneficiary).toBe(titleEscrowParameter.beneficiary); - expect(titleEscrowInfo.holder).toBe(titleEscrowParameter.holder); - expect(titleEscrowInfo.isHoldingToken).toBe(true); - expect(titleEscrowInfo.nominee).toBe(BurnAddress); - expect(titleEscrowInfo.registry).toBe(titleEscrowParameter.address); + if(!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if(!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if(!(titleEscrowInfo.holder === titleEscrowParameter.holder)) throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if(!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if(!(titleEscrowInfo.registry === titleEscrowParameter.address)) throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); - expect(correctTokenID).toBe(true); - }); + if(!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } - it("should fail with invalid token id", async () => { + // it("should fail with invalid token id", async () => { + { const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, tokenId: "0xZ", @@ -97,9 +99,10 @@ describe("deploy token-registry", () => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); checkFailure(results, "invalid BigNumber string"); - }); + } - it("should fail with invalid token registry", async () => { + // it("should fail with invalid token registry", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { address: BurnAddress, @@ -111,9 +114,10 @@ describe("deploy token-registry", () => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); + } - it("should fail with invalid beneficiary", async () => { + // it("should fail with invalid beneficiary", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, @@ -125,9 +129,10 @@ describe("deploy token-registry", () => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should fail with invalid holder", async () => { + // it("should fail with invalid holder", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, @@ -139,9 +144,10 @@ describe("deploy token-registry", () => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should fail with no funds", async () => { + // it("should fail with no funds", async () => { + { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { ...defaultRunParameters, @@ -154,5 +160,5 @@ describe("deploy token-registry", () => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); -}); + } +} diff --git a/src/e2e/nominate.test.ts b/src/e2e/nominate.e2e.ts similarity index 72% rename from src/e2e/nominate.test.ts rename to src/e2e/nominate.e2e.ts index 664a2ec4..493ecc41 100644 --- a/src/e2e/nominate.test.ts +++ b/src/e2e/nominate.e2e.ts @@ -10,15 +10,15 @@ import { generateNominateCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { checkFailure, checkNominateSuccess, defaultNominateBeneficiary, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; -describe("nominate title-escrow", () => { - jest.setTimeout(90000); +export const nominate = async () => { +// describe("nominate title-escrow", () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - it("should be able to nominate title-escrow on token-registry", async () => { + // it("should be able to nominate title-escrow on token-registry", async () => { + { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { tokenId, @@ -29,14 +29,15 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); const nominateInfo = checkNominateSuccess(results); - expect(nominateInfo.tokenId).toBe(transferHolder.tokenId); - expect(nominateInfo.nominee).toBe(transferHolder.newBeneficiary); + if(!(nominateInfo.tokenId === transferHolder.tokenId)) throw new Error (`nominateInfo.tokenId === transferHolder.tokenId`); + if(!(nominateInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`nominateInfo.nominee === transferHolder.newBeneficiary`); const signer = await getSigner(transferHolder.network, owner.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); - expect(titleEscrowInfo.nominee).toBe(transferHolder.newBeneficiary); - }); + if(!(titleEscrowInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`titleEscrowInfo.nominee === transferHolder.newBeneficiary`); + } - it("should be able to cancel nomination of title-escrow on token-registry", async () => { + // it("should be able to cancel nomination of title-escrow on token-registry", async () => { + { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -48,15 +49,16 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, owner.privateKey); results = run(command); const nominateInfo = checkNominateSuccess(results); - expect(nominateInfo.tokenId).toBe(transferHolder.tokenId); - expect(nominateInfo.nominee).toBe(transferHolder.newBeneficiary); + if(!(nominateInfo.tokenId === transferHolder.tokenId)) throw new Error (`nominateInfo.tokenId === transferHolder.tokenId`); + if(!(nominateInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`nominateInfo.nominee === transferHolder.newBeneficiary`); const signer = await getSigner(transferHolder.network, owner.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); - expect(titleEscrowInfo.nominee).toBe(BurnAddress); - }); + if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error (`titleEscrowInfo.nominee === BurnAddress`); + } - it("should not be able to nominate self", async () => { + // it("should not be able to nominate self", async () => { + { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -67,9 +69,10 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, "new beneficiary address is the same as the current beneficiary address"); - }); + } - it("should not be able to nominate unowned token", async () => { + // it("should not be able to nominate unowned token", async () => { + { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -80,9 +83,10 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, receiver.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should not be able to nominate non-existent token", async () => { + // it("should not be able to nominate non-existent token", async () => { + { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -93,9 +97,10 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should not be able to nominate non-existent token registry", async () => { + // it("should not be able to nominate non-existent token registry", async () => { + { const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -105,5 +110,5 @@ describe("nominate title-escrow", () => { const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); -}); + } +} diff --git a/src/e2e/reject-surrender.test.ts b/src/e2e/reject-surrender.e2e.ts similarity index 68% rename from src/e2e/reject-surrender.test.ts rename to src/e2e/reject-surrender.e2e.ts index 07eeff8a..0c8b67e3 100644 --- a/src/e2e/reject-surrender.test.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -7,13 +7,12 @@ import { checkSurrenderRejectSuccess } from "./utils/bootstrap"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; -describe("reject surrender title-escrow", () => { - jest.setTimeout(90000); +export const rejectSurrender = async () => { +// describe("reject surrender title-escrow", () => { + // jest.setTimeout(90000); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); + + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTitleEscrow = { beneficiary: owner.ethAddress, @@ -22,7 +21,8 @@ describe("reject surrender title-escrow", () => { dryRun: false, }; - it("should be able to reject surrender title-escrow on token-registry", async () => { + // it("should be able to reject surrender title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); @@ -32,7 +32,7 @@ describe("reject surrender title-escrow", () => { tokenRegistry, tokenId ); - expect(titleEscrowOwner).toBe(tokenRegistry); + if(!(titleEscrowOwner === tokenRegistry)) throw new Error(`titleEscrowOwner === tokenRegistry`); const results = run(command); checkSurrenderRejectSuccess(results); titleEscrowOwner = await retrieveTitleEscrowOwner( @@ -40,24 +40,26 @@ describe("reject surrender title-escrow", () => { tokenRegistry, tokenId ); - expect(isAddress(titleEscrowOwner)).toBe(true); - expect(titleEscrowOwner).not.toBe(tokenRegistry); - }); + if(!(isAddress(titleEscrowOwner) === true)) throw new Error(`isAddress(titleEscrowOwner) === true`); + if(!(titleEscrowOwner !== tokenRegistry)) throw new Error(`titleEscrowOwner !== tokenRegistry`); + } - it("should not be able to reject surrender invalid title-escrow on token-registry", async () => { + // it("should not be able to reject surrender invalid title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + } - it("should not be able to reject surrender title-escrow on invalid token-registry", async () => { + // it("should not be able to reject surrender title-escrow on invalid token-registry", async () => { + { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); const results = run(command); checkFailure(results, "null"); - }); + } - it.todo("should be fail when user without permission attempts reject surrender"); -}); + // it.todo("should be fail when user without permission attempts reject surrender"); +} diff --git a/src/e2e/surrender.test.ts b/src/e2e/surrender.e2e.ts similarity index 76% rename from src/e2e/surrender.test.ts rename to src/e2e/surrender.e2e.ts index 5ea47dfe..469476cf 100644 --- a/src/e2e/surrender.test.ts +++ b/src/e2e/surrender.e2e.ts @@ -15,15 +15,10 @@ const defaultTitleEscrow = { }; -describe("surrender title-escrow", () => { - jest.setTimeout(90000); +export const surrender = async () => { + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - let tokenRegistryAddress = ""; - beforeAll(() => { - tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - }); - - it("should be able to surrender title-escrow on token-registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { @@ -37,21 +32,21 @@ describe("surrender title-escrow", () => { surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - expect(isAddress(titleEscrowOwner)).toBe(true); - expect(titleEscrowOwner).not.toBe(surrenderTitleEscrow.tokenRegistry); + if(isAddress(titleEscrowOwner) !== true){ throw new Error(`(isAddress(titleEscrowOwner) === true);`)}; + if(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`)}; const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); const results = run(command); const surrenderResults = checkSurrenderSuccess(results); - expect(surrenderResults.tokenId).toBe(surrenderTitleEscrow.tokenId); + if(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId){ throw new Error(`(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId);`)}; titleEscrowOwner = await retrieveTitleEscrowOwner( signer, surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - expect(titleEscrowOwner).toBe(surrenderTitleEscrow.tokenRegistry); - }); + if(titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry);`)}; + }; - it("should not surrender unowned title escrow", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { @@ -68,11 +63,11 @@ describe("surrender title-escrow", () => { surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - expect(isAddress(titleEscrowOwner)).toBe(true); - expect(titleEscrowOwner).not.toBe(surrenderTitleEscrow.tokenRegistry); - }); + if(isAddress(titleEscrowOwner) !== true){ throw new Error(`(isAddress(titleEscrowOwner) !== true);`)}; + if(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`)}; + }; - it("should not surrender invalid title escrow", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { @@ -83,9 +78,9 @@ describe("surrender title-escrow", () => { const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }); + }; - it("should not surrender invalid title escrow with invalid token registry", async () => { + { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { @@ -96,5 +91,5 @@ describe("surrender title-escrow", () => { const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); checkFailure(results, "null"); - }); -}); + }; +}; diff --git a/src/e2e/utils/bootstrap/common.ts b/src/e2e/utils/bootstrap/common.ts index 2ff1b25e..a8a2b505 100644 --- a/src/e2e/utils/bootstrap/common.ts +++ b/src/e2e/utils/bootstrap/common.ts @@ -1,9 +1,9 @@ import { EndStatus } from "../constants"; import { extractStatus } from "../shell"; -export const checkFailure = (results: string, expectedErrorMessage: string) => { +export const checkFailure = (results: string, expectedErrorMessage: string) => { //}: Error | undefined => { const statusMessage = extractStatus(results, EndStatus.error); - expect(statusMessage.length).toBeGreaterThan(0); + if(!(statusMessage.length > 0)) throw new Error(`!statusMessage.length > 0`); const errorMessage = statusMessage[0].lineContent.substring(13); - expect(errorMessage).toContain(expectedErrorMessage); + if(!(errorMessage.includes(expectedErrorMessage))){throw new Error(`!errorMessage.includes(expectedErrorMessage)`)}; }; \ No newline at end of file diff --git a/src/e2e/utils/bootstrap/mint.ts b/src/e2e/utils/bootstrap/mint.ts index d4615fa1..8a991baf 100644 --- a/src/e2e/utils/bootstrap/mint.ts +++ b/src/e2e/utils/bootstrap/mint.ts @@ -16,10 +16,10 @@ export interface MintData { } export const validateMintData = (expectedValue: MintData, value: MintData) => { - expect(expectedValue.address).toBe(value.address); - expect(expectedValue.beneficiary).toBe(value.beneficiary); - expect(expectedValue.holder).toBe(value.holder); - expect(expectedValue.tokenId).toBe(value.tokenId); + if(!(expectedValue.address === value.address)) throw new Error(`expectedValue.address === value.address`); + if(!(expectedValue.beneficiary === value.beneficiary)) throw new Error(`expectedValue.beneficiary === value.beneficiary`); + if(!(expectedValue.holder === value.holder)) throw new Error(`expectedValue.holder === value.holder`); + if(!(expectedValue.tokenId === value.tokenId)) throw new Error(`expectedValue.tokenId === value.tokenId`); }; export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { diff --git a/src/e2e/utils/constants.ts b/src/e2e/utils/constants.ts index 7b0a1ca9..fc772f8b 100644 --- a/src/e2e/utils/constants.ts +++ b/src/e2e/utils/constants.ts @@ -40,7 +40,7 @@ export const AddressLength = 42; export type EndStatusType = typeof EndStatus[keyof typeof EndStatus]; -export const silent = false; +export const silent = true; export const verbose = false; export const defaultRunParameters = { network: network, From 4fc67932b8f0785930db7570d9afbc2e81af031b Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 11 Jan 2023 16:48:50 +0800 Subject: [PATCH 53/63] fix: linting --- package.json | 5 +- src/e2e/accept-surrender.e2e.ts | 58 ++++++++-------- src/e2e/all.ts | 24 +++---- src/e2e/change-holder.e2e.ts | 38 ++++++----- src/e2e/deploy.e2e.ts | 49 ++++++++------ src/e2e/endorse-change-owner.e2e.ts | 40 +++++------ src/e2e/endorse-transfer.e2e.ts | 33 +++++----- src/e2e/mint.e2e.ts | 73 +++++++++------------ src/e2e/nominate.e2e.ts | 52 ++++++++------- src/e2e/reject-surrender.e2e.ts | 55 +++++++--------- src/e2e/surrender.e2e.ts | 47 +++++++------ src/e2e/utils/bootstrap/accept-surrender.ts | 28 ++++---- src/e2e/utils/bootstrap/change-holder.ts | 60 ++++++++--------- src/e2e/utils/bootstrap/common.ts | 14 ++-- src/e2e/utils/bootstrap/deploy.ts | 14 ++-- src/e2e/utils/bootstrap/endorse-owners.ts | 45 +++++++------ src/e2e/utils/bootstrap/endorse-transfer.ts | 36 +++++----- src/e2e/utils/bootstrap/index.ts | 1 - src/e2e/utils/bootstrap/mint.ts | 22 ++----- src/e2e/utils/bootstrap/nominate.ts | 66 +++++++++---------- src/e2e/utils/bootstrap/reject-surrender.ts | 28 ++++---- src/e2e/utils/bootstrap/surrender.ts | 63 +++++++++--------- src/e2e/utils/constants.ts | 1 - src/e2e/utils/contract-checks.ts | 2 +- src/e2e/utils/token-management.ts | 7 +- 25 files changed, 413 insertions(+), 448 deletions(-) diff --git a/package.json b/package.json index 331ecbe5..965e4c1c 100644 --- a/package.json +++ b/package.json @@ -10,13 +10,12 @@ }, "scripts": { "dev": "ts-node src/index.ts", - "e2e": "concurrently -k -s first \"npm:blockchain\" \"npm:e2e-test\"", + "e2e": "concurrently -P -k -s first \"npm:e2e-test\" \"npm:blockchain\"", "build": "npm run clean && npm run build:cjs && npm run build:type", "build:cjs": "tsc --module commonjs --outDir dist/cjs --project ./tsconfig.prod.json", "build:type": "tsc -d --emitDeclarationOnly --outDir dist/types", "clean": "rm -rf dist/", - "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli", - "test:e2e": "jest --ci src/e2e/", + "blockchain": "ganache --wallet.mnemonic \"indicate swing place chair flight used hammer soon photo region volume shuffle\" -i 1337 --fork.network goerli --logging.quiet=true", "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", diff --git a/src/e2e/accept-surrender.e2e.ts b/src/e2e/accept-surrender.e2e.ts index 3c4ce096..3ad4d17f 100644 --- a/src/e2e/accept-surrender.e2e.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -1,12 +1,10 @@ -import { extractLine, LineInfo, run } from "./utils/shell"; -import { BurnAddress, EmptyTokenID, EndStatus, network, owner } from "./utils/constants"; -import { generateAcceptSurrenderCommand } from "./utils/commands"; import { checkFailure, checkSurrenderAcceptSuccess, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; -import { getSigner, retrieveTitleEscrow, retrieveTitleEscrowInfo, retrieveTitleEscrowOwner } from "./utils/contract-checks"; +import { generateAcceptSurrenderCommand } from "./utils/commands"; +import { BurnAddress, EmptyTokenID, network, owner } from "./utils/constants"; +import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; +import { run } from "./utils/shell"; -// describe("accept-surrender title-escrow", () => { -export const acceptSurrender = async () => { - +export const acceptSurrender = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); // const errors: Error[] = []; const defaultTitleEscrow = { @@ -16,46 +14,42 @@ export const acceptSurrender = async () => { dryRun: false, }; - // it("should be able to accept-surrender title-escrow on token-registry", async () => { + //"should be able to accept-surrender title-escrow on token-registry" { - const { tokenRegistry, tokenId, titleEscrowAddress } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); - let titleEscrowOwner: string = await retrieveTitleEscrowOwner( - signer, - tokenRegistry, - tokenId - ); - if(!(titleEscrowOwner === tokenRegistry)) throw new Error(`!(titleEscrowOwner === tokenRegistry)`); - + let titleEscrowOwner: string = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); + if (!(titleEscrowOwner === tokenRegistry)) throw new Error(`!(titleEscrowOwner === tokenRegistry)`); + const results = run(command); - titleEscrowOwner = await retrieveTitleEscrowOwner( - signer, - tokenRegistry, - tokenId - ); - if(!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")) throw new Error(`!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")`); + titleEscrowOwner = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); + if (!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")) + throw new Error(`!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")`); checkSurrenderAcceptSuccess(results); } - - // it("should not be able to accept surrender invalid title-escrow on token-registry", async () => { + + //"should not be able to accept surrender invalid title-escrow on token-registry" { const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); + const command = generateAcceptSurrenderCommand( + { tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, + owner.privateKey + ); const results = run(command); checkFailure(results, "missing revert data in call exception"); } - - // it("should not be able to accept surrender title-escrow on invalid token-registry", async () => { + //"should not be able to accept surrender title-escrow on invalid token-registry" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateAcceptSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand( + { tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, + owner.privateKey + ); const results = run(command); checkFailure(results, "null"); } - // return errors; - // it.todo("should be fail when permission is denied"); }; -// npm run dev -- title-escrow accept-surrendered --token-registry 0x0000000000000000000000000000000000000000 --tokenId 0xf32907ec66ac258f058eae34d76b160b0ca520b5c613ca93ae6bb22a8f9c451f --network local -k 0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7 \ No newline at end of file +// npm run dev -- title-escrow accept-surrendered --token-registry 0x0000000000000000000000000000000000000000 --tokenId 0xf32907ec66ac258f058eae34d76b160b0ca520b5c613ca93ae6bb22a8f9c451f --network local -k 0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7 diff --git a/src/e2e/all.ts b/src/e2e/all.ts index 1311e709..8f87e861 100644 --- a/src/e2e/all.ts +++ b/src/e2e/all.ts @@ -1,15 +1,15 @@ -import { acceptSurrender } from './accept-surrender.e2e' -import { surrender } from './surrender.e2e' -import { changeHolder } from './change-holder.e2e' -import { deployDocumentStore, deployTokenRegistry } from './deploy.e2e'; -import { endorseTransfer } from './endorse-transfer.e2e'; -import { mint } from './mint.e2e'; -import { nominate } from './nominate.e2e'; -import { rejectSurrender } from './reject-surrender.e2e'; +import { acceptSurrender } from "./accept-surrender.e2e"; +import { surrender } from "./surrender.e2e"; +import { changeHolder } from "./change-holder.e2e"; +import { deployDocumentStore, deployTokenRegistry } from "./deploy.e2e"; +import { endorseTransfer } from "./endorse-transfer.e2e"; +import { mint } from "./mint.e2e"; +import { nominate } from "./nominate.e2e"; +import { rejectSurrender } from "./reject-surrender.e2e"; -const awaitForDuration = async (runFunction: Function) => { - await runFunction(); -} +const awaitForDuration = async (runFunction: () => void): Promise => { + await runFunction(); +}; awaitForDuration(surrender); awaitForDuration(acceptSurrender); @@ -19,4 +19,4 @@ awaitForDuration(changeHolder); awaitForDuration(endorseTransfer); awaitForDuration(mint); awaitForDuration(nominate); -awaitForDuration(rejectSurrender); \ No newline at end of file +awaitForDuration(rejectSurrender); diff --git a/src/e2e/change-holder.e2e.ts b/src/e2e/change-holder.e2e.ts index 2dd672e1..19891e11 100644 --- a/src/e2e/change-holder.e2e.ts +++ b/src/e2e/change-holder.e2e.ts @@ -1,17 +1,21 @@ -import { extractLine, LineInfo, run } from "./utils/shell"; -import { BurnAddress, EmptyTokenID, EndStatus, network, owner, receiver } from "./utils/constants"; import { TitleEscrowTransferHolderCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { + changeHolderToken, + checkChangeHolderSuccess, + checkFailure, + defaultTransferHolder, + deployTokenRegistry, + mintTokenRegistry, +} from "./utils/bootstrap"; import { generateChangeHolderCommand } from "./utils/commands"; -import { checkFailure, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; -import { changeHolderToken, checkChangeHolderSuccess, defaultTransferHolder } from "./utils/bootstrap"; - -// describe("transfer holder title-escrow", () => { -export const changeHolder = async () => { - // jest.setTimeout(90000); +import { BurnAddress, EmptyTokenID, owner, receiver } from "./utils/constants"; +import { run } from "./utils/shell"; +// "transfer holder title-escrow" +export const changeHolder = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - // it("should be able to transfer holder title-escrow on token-registry", async () => { + //should be able to transfer holder title-escrow on token-registry" { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { @@ -24,8 +28,7 @@ export const changeHolder = async () => { checkChangeHolderSuccess(results); } - - // it("holder should be able to transfer holder of title-escrow", async () => { + //holder should be able to transfer holder of title-escrow" { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver @@ -50,9 +53,9 @@ export const changeHolder = async () => { checkChangeHolderSuccess(results); } - // it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + //should not be able to transfer holder of invalid title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: EmptyTokenID, tokenRegistry: tokenRegistry, @@ -63,10 +66,9 @@ export const changeHolder = async () => { checkFailure(results, "missing revert data in call exception"); } - - // it("should not be able to transfer holder of invalid title-escrow on token-registry", async () => { + //should not be able to transfer holder of invalid title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: tokenId, tokenRegistry: BurnAddress, @@ -77,7 +79,7 @@ export const changeHolder = async () => { checkFailure(results, "null"); } - // it("beneficiary should not be able to transfer holder of title-escrow", async () => { + //beneficiary should not be able to transfer holder of title-escrow" { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver @@ -100,5 +102,5 @@ export const changeHolder = async () => { // Beneficiary attempts to transfer Holder without permission const results = run(command); checkFailure(results, "missing revert data in call exception"); - } + } }; diff --git a/src/e2e/deploy.e2e.ts b/src/e2e/deploy.e2e.ts index b783fab1..62660c7c 100644 --- a/src/e2e/deploy.e2e.ts +++ b/src/e2e/deploy.e2e.ts @@ -6,11 +6,8 @@ import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/bootstrap"; -export const deployTokenRegistry = async () => { -// describe("deploy token-registry", () => { - // jest.setTimeout(90000); - - // it("should be able to deploy token-registry", async () => { +export const deployTokenRegistry = async (): Promise => { + //should be able to deploy token-registry" { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", @@ -23,20 +20,30 @@ export const deployTokenRegistry = async () => { const tokenRegistryAddress = checkTokenRegistrySuccess(results); const signer = getSigner(defaultRunParameters.network, owner.privateKey); const tokenInfo = await retrieveTokenInfo(signer, tokenRegistryAddress); - if(!(tokenInfo.name === tokenRegistryParameter.registryName)){ throw new Error("tokenInfo.name === tokenRegistryParameter.registryName")}; - if(!(tokenInfo.symbol === tokenRegistryParameter.registrySymbol)){ throw new Error("tokenInfo.symbol === tokenRegistryParameter.registrySymbol")}; + if (!(tokenInfo.name === tokenRegistryParameter.registryName)) { + throw new Error("tokenInfo.name === tokenRegistryParameter.registryName"); + } + if (!(tokenInfo.symbol === tokenRegistryParameter.registrySymbol)) { + throw new Error("tokenInfo.symbol === tokenRegistryParameter.registrySymbol"); + } const rolesInfo = await rolesCheck(signer, tokenRegistryAddress); - if(!(rolesInfo.accepterRole === true)){ throw new Error("rolesInfo.accepterRole === true")}; - if(!(rolesInfo.defaultRole === true)){ throw new Error("rolesInfo.defaultRole === true")}; - if(!(rolesInfo.minterRole === true)){ throw new Error("rolesInfo.minterRole === true")}; - if(!(rolesInfo.restorerRole === true)){ throw new Error("rolesInfo.restorerRole === true")}; + if (!(rolesInfo.accepterRole === true)) { + throw new Error("rolesInfo.accepterRole === true"); + } + if (!(rolesInfo.defaultRole === true)) { + throw new Error("rolesInfo.defaultRole === true"); + } + if (!(rolesInfo.minterRole === true)) { + throw new Error("rolesInfo.minterRole === true"); + } + if (!(rolesInfo.restorerRole === true)) { + throw new Error("rolesInfo.restorerRole === true"); + } } -} +}; -// describe("deploy document-store", () => { -export const deployDocumentStore = () => { - // jest.setTimeout(90000); - // it("should be able to deploy document-store", async () => +export const deployDocumentStore = async (): Promise => { + //should be able to deploy document-store { const documentStoreParameters: DeployDocumentStoreCommand = { storeName: "Test Document Store", @@ -47,11 +54,13 @@ export const deployDocumentStore = () => { const results = run(command); const tokenRegistrySuccessFormat = `${EndStatus.success} Document store Test Document Store deployed at `; const checkSuccess = results.includes(tokenRegistrySuccessFormat); - if(!(checkSuccess === true)) throw new Error(`checkSuccess === true)`); + if (!(checkSuccess === true)) throw new Error(`checkSuccess === true)`); const splitResults = results.trim().split("\n"); const tokenRegistryAddressLine = splitResults[splitResults.length - 2]; const tokenRegistryAddress = tokenRegistryAddressLine.trim().substring(tokenRegistrySuccessFormat.length); - if(!(isAddress(tokenRegistryAddress) === true)) throw new Error(`isAddress(tokenRegistryAddress) === true)`); - if(!(isAddress(tokenRegistryAddress) === true)){ throw new Error("isAddress(tokenRegistryAddress) === true")}; + if (!(isAddress(tokenRegistryAddress) === true)) throw new Error(`isAddress(tokenRegistryAddress) === true)`); + if (!(isAddress(tokenRegistryAddress) === true)) { + throw new Error("isAddress(tokenRegistryAddress) === true"); + } } -} +}; diff --git a/src/e2e/endorse-change-owner.e2e.ts b/src/e2e/endorse-change-owner.e2e.ts index 2f30c756..1147cdf7 100644 --- a/src/e2e/endorse-change-owner.e2e.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -1,14 +1,17 @@ -import { extractLine, LineInfo, run } from "./utils/shell"; -import { EndStatus, network, owner, receiver } from "./utils/constants"; +import { run } from "./utils/shell"; +import { network, owner, receiver } from "./utils/constants"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateTransferOwnersCommand } from "./utils/commands"; -import { changeHolderToken, checkEndorseOwner, checkFailure, deployTokenRegistry, mintNominatedToken, mintTokenRegistry } from "./utils/bootstrap"; +import { + checkEndorseOwner, + checkFailure, + deployTokenRegistry, + mintNominatedToken, + mintTokenRegistry, +} from "./utils/bootstrap"; -// describe("endorse change owner title-escrow", () => { -export const endorseChangeOwner = () => { - // jest.setTimeout(90000); - - +// "endorse change owner title-escrow" +export const endorseChangeOwner = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTransferOwners = { @@ -18,7 +21,7 @@ export const endorseChangeOwner = () => { dryRun: false, }; - // it("should be able to endorse change owner title-escrow on token-registry", async () => { + //should be able to endorse change owner title-escrow on token-registry" { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, @@ -33,17 +36,14 @@ export const endorseChangeOwner = () => { const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); const { beneficiary, holder, tokenId: tokenIdResult } = checkEndorseOwner(results); - if(!(beneficiary === transferOwners.newOwner)) throw new Error(`beneficiary === transferOwners.newOwner`); - if(!(holder === transferOwners.newHolder)) throw new Error(`holder === transferOwners.newHolder`); - if(!(tokenIdResult === transferOwners.tokenId)) throw new Error(`tokenIdResult === transferOwners.tokenId`); + if (!(beneficiary === transferOwners.newOwner)) throw new Error(`beneficiary === transferOwners.newOwner`); + if (!(holder === transferOwners.newHolder)) throw new Error(`holder === transferOwners.newHolder`); + if (!(tokenIdResult === transferOwners.tokenId)) throw new Error(`tokenIdResult === transferOwners.tokenId`); } - // it("should not be able to endorse change owner on un-nominated title-escrow", async () => { - { - const { tokenRegistry, tokenId } = mintTokenRegistry( - owner.privateKey, - tokenRegistryAddress - ); + //should not be able to endorse change owner on un-nominated title-escrow" + { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { tokenId: tokenId, tokenRegistry: tokenRegistry, @@ -51,6 +51,6 @@ export const endorseChangeOwner = () => { }; const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); - checkFailure(results, "") + checkFailure(results, ""); } -} +}; diff --git a/src/e2e/endorse-transfer.e2e.ts b/src/e2e/endorse-transfer.e2e.ts index 01badae4..70ee5762 100644 --- a/src/e2e/endorse-transfer.e2e.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -1,14 +1,16 @@ -import { extractLine, LineInfo, run } from "./utils/shell"; -import { BurnAddress, EndStatus, network, owner, receiver } from "./utils/constants"; import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; +import { + checkEndorseTransfer, + checkFailure, + deployTokenRegistry, + mintNominatedToken, + mintTokenRegistry, +} from "./utils/bootstrap"; import { generateEndorseTransferOwnerCommand } from "./utils/commands"; -import { checkEndorseTransfer, checkFailure, deployTokenRegistry, mintNominatedToken, mintToken, mintTokenRegistry } from "./utils/bootstrap"; +import { BurnAddress, network, owner, receiver } from "./utils/constants"; +import { run } from "./utils/shell"; -// describe("endorse transfer title-escrow", () => { -export const endorseTransfer = async () => { - // jest.setTimeout(90000); - - +export const endorseTransfer = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTransferHolder = { @@ -17,7 +19,7 @@ export const endorseTransfer = async () => { dryRun: false, }; - // it("should be able to endorse transfer title-escrow on token-registry", async () => { + //"should be able to endorse transfer title-escrow on token-registry" { const { tokenRegistry, tokenId } = mintNominatedToken( owner.privateKey, @@ -35,23 +37,18 @@ export const endorseTransfer = async () => { checkEndorseTransfer(results); } - - // it("should not be able to endorse un-nominated title-escrow on token-registry", async () => { + //"should not be able to endorse un-nominated title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintTokenRegistry( - owner.privateKey, - tokenRegistryAddress - ); + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultTransferHolder, tokenId, tokenRegistry, - newBeneficiary: BurnAddress + newBeneficiary: BurnAddress, }; const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); checkFailure(results, ""); } - -} +}; diff --git a/src/e2e/mint.e2e.ts b/src/e2e/mint.e2e.ts index e0c5086e..7304e493 100644 --- a/src/e2e/mint.e2e.ts +++ b/src/e2e/mint.e2e.ts @@ -1,31 +1,16 @@ -import { generateTokenId, isTokenId } from "./utils/token-management"; -import { extractStatus, run } from "./utils/shell"; -import { - AddressLength, - BurnAddress, - defaultRunParameters, - EndStatus, - network, - owner, - receiver, - TokenIdLength, - TokenInfo, -} from "./utils/constants"; -import { isAddress } from "web3-utils"; +import { generateTokenId } from "./utils/token-management"; +import { run } from "./utils/shell"; +import { BurnAddress, defaultRunParameters, owner, receiver } from "./utils/constants"; import { TokenRegistryIssueCommand } from "../commands/token-registry/token-registry-command.type"; import { generateMintTitleEscrowCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/bootstrap"; -export const mint = async () => { -// describe("deploy token-registry", () => { - // jest.setTimeout(90000); - - +export const mint = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - // it("should be able to mint title-escrow on token-registry", async () => { + //"should be able to mint title-escrow on token-registry" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -46,17 +31,20 @@ export const mint = async () => { titleEscrowParameter.address, titleEscrowParameter.tokenId ); - if(!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); - if(!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); - if(!(titleEscrowInfo.holder === titleEscrowParameter.holder)) throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); - if(!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); - if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); - if(!(titleEscrowInfo.registry === titleEscrowParameter.address)) throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) + throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if (!(titleEscrowInfo.holder === titleEscrowParameter.holder)) + throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === titleEscrowParameter.address)) + throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); - if(!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); } - // it("should be able to mint title-escrow for a different wallet on token-registry", async () => { + //"should be able to mint title-escrow for a different wallet on token-registry" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -77,17 +65,20 @@ export const mint = async () => { titleEscrowParameter.address, titleEscrowParameter.tokenId ); - if(!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); - if(!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); - if(!(titleEscrowInfo.holder === titleEscrowParameter.holder)) throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); - if(!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); - if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); - if(!(titleEscrowInfo.registry === titleEscrowParameter.address)) throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) + throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if (!(titleEscrowInfo.holder === titleEscrowParameter.holder)) + throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === titleEscrowParameter.address)) + throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); - if(!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); } - // it("should fail with invalid token id", async () => { + //"should fail with invalid token id" { const titleEscrowParameter: TokenRegistryIssueCommand = { address: tokenRegistryAddress, @@ -101,7 +92,7 @@ export const mint = async () => { checkFailure(results, "invalid BigNumber string"); } - // it("should fail with invalid token registry", async () => { + //"should fail with invalid token registry" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -116,7 +107,7 @@ export const mint = async () => { checkFailure(results, "null"); } - // it("should fail with invalid beneficiary", async () => { + //"should fail with invalid beneficiary" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -131,7 +122,7 @@ export const mint = async () => { checkFailure(results, "missing revert data in call exception"); } - // it("should fail with invalid holder", async () => { + //"should fail with invalid holder" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -146,7 +137,7 @@ export const mint = async () => { checkFailure(results, "missing revert data in call exception"); } - // it("should fail with no funds", async () => { + //"should fail with no funds" { const tokenId = generateTokenId(); const titleEscrowParameter: TokenRegistryIssueCommand = { @@ -161,4 +152,4 @@ export const mint = async () => { const results = run(command); checkFailure(results, "null"); } -} +}; diff --git a/src/e2e/nominate.e2e.ts b/src/e2e/nominate.e2e.ts index 493ecc41..fc35daf5 100644 --- a/src/e2e/nominate.e2e.ts +++ b/src/e2e/nominate.e2e.ts @@ -1,23 +1,20 @@ import { run } from "./utils/shell"; -import { - BurnAddress, - defaultRunParameters, - owner, - receiver, -} from "./utils/constants"; +import { BurnAddress, defaultRunParameters, owner, receiver } from "./utils/constants"; import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateNominateCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; -import { checkFailure, checkNominateSuccess, defaultNominateBeneficiary, deployTokenRegistry, mintTokenRegistry } from "./utils/bootstrap"; - -export const nominate = async () => { -// describe("nominate title-escrow", () => { - // jest.setTimeout(90000); +import { + checkFailure, + checkNominateSuccess, + defaultNominateBeneficiary, + deployTokenRegistry, + mintTokenRegistry, +} from "./utils/bootstrap"; - +export const nominate = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - // it("should be able to nominate title-escrow on token-registry", async () => { + //"should be able to nominate title-escrow on token-registry" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { @@ -29,14 +26,17 @@ export const nominate = async () => { const command = generateNominateCommand(transferHolder, owner.privateKey); const results = run(command); const nominateInfo = checkNominateSuccess(results); - if(!(nominateInfo.tokenId === transferHolder.tokenId)) throw new Error (`nominateInfo.tokenId === transferHolder.tokenId`); - if(!(nominateInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`nominateInfo.nominee === transferHolder.newBeneficiary`); + if (!(nominateInfo.tokenId === transferHolder.tokenId)) + throw new Error(`nominateInfo.tokenId === transferHolder.tokenId`); + if (!(nominateInfo.nominee === transferHolder.newBeneficiary)) + throw new Error(`nominateInfo.nominee === transferHolder.newBeneficiary`); const signer = await getSigner(transferHolder.network, owner.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); - if(!(titleEscrowInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`titleEscrowInfo.nominee === transferHolder.newBeneficiary`); + if (!(titleEscrowInfo.nominee === transferHolder.newBeneficiary)) + throw new Error(`titleEscrowInfo.nominee === transferHolder.newBeneficiary`); } - // it("should be able to cancel nomination of title-escrow on token-registry", async () => { + //"should be able to cancel nomination of title-escrow on token-registry" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { @@ -49,15 +49,17 @@ export const nominate = async () => { const command = generateNominateCommand(transferHolder, owner.privateKey); results = run(command); const nominateInfo = checkNominateSuccess(results); - if(!(nominateInfo.tokenId === transferHolder.tokenId)) throw new Error (`nominateInfo.tokenId === transferHolder.tokenId`); - if(!(nominateInfo.nominee === transferHolder.newBeneficiary)) throw new Error (`nominateInfo.nominee === transferHolder.newBeneficiary`); + if (!(nominateInfo.tokenId === transferHolder.tokenId)) + throw new Error(`nominateInfo.tokenId === transferHolder.tokenId`); + if (!(nominateInfo.nominee === transferHolder.newBeneficiary)) + throw new Error(`nominateInfo.nominee === transferHolder.newBeneficiary`); const signer = await getSigner(transferHolder.network, owner.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); - if(!(titleEscrowInfo.nominee === BurnAddress)) throw new Error (`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); } - // it("should not be able to nominate self", async () => { + //"should not be able to nominate self" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { @@ -71,7 +73,7 @@ export const nominate = async () => { checkFailure(results, "new beneficiary address is the same as the current beneficiary address"); } - // it("should not be able to nominate unowned token", async () => { + //"should not be able to nominate unowned token" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { @@ -85,7 +87,7 @@ export const nominate = async () => { checkFailure(results, "missing revert data in call exception"); } - // it("should not be able to nominate non-existent token", async () => { + //"should not be able to nominate non-existent token" { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { @@ -99,7 +101,7 @@ export const nominate = async () => { checkFailure(results, "missing revert data in call exception"); } - // it("should not be able to nominate non-existent token registry", async () => { + //"should not be able to nominate non-existent token registry" { const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -111,4 +113,4 @@ export const nominate = async () => { const results = run(command); checkFailure(results, "null"); } -} +}; diff --git a/src/e2e/reject-surrender.e2e.ts b/src/e2e/reject-surrender.e2e.ts index 0c8b67e3..a1de39d8 100644 --- a/src/e2e/reject-surrender.e2e.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -1,17 +1,13 @@ // import { deployTokenRegistry, mintSurrenderToken } from "./utils/utils"; -import { extractLine, LineInfo, run } from "./utils/shell"; -import { BurnAddress, EmptyTokenID, EndStatus, network, owner } from "./utils/constants"; +import { run } from "./utils/shell"; +import { BurnAddress, EmptyTokenID, network, owner } from "./utils/constants"; import { generateRejectSurrenderCommand } from "./utils/commands"; import { checkFailure, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; import { checkSurrenderRejectSuccess } from "./utils/bootstrap"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; -export const rejectSurrender = async () => { -// describe("reject surrender title-escrow", () => { - // jest.setTimeout(90000); - - +export const rejectSurrender = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTitleEscrow = { @@ -21,45 +17,40 @@ export const rejectSurrender = async () => { dryRun: false, }; - // it("should be able to reject surrender title-escrow on token-registry", async () => { + //"should be able to reject surrender title-escrow on token-registry" { const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); - - let titleEscrowOwner: string = await retrieveTitleEscrowOwner( - signer, - tokenRegistry, - tokenId - ); - if(!(titleEscrowOwner === tokenRegistry)) throw new Error(`titleEscrowOwner === tokenRegistry`); + + let titleEscrowOwner: string = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); + if (!(titleEscrowOwner === tokenRegistry)) throw new Error(`titleEscrowOwner === tokenRegistry`); const results = run(command); checkSurrenderRejectSuccess(results); - titleEscrowOwner = await retrieveTitleEscrowOwner( - signer, - tokenRegistry, - tokenId - ); - if(!(isAddress(titleEscrowOwner) === true)) throw new Error(`isAddress(titleEscrowOwner) === true`); - if(!(titleEscrowOwner !== tokenRegistry)) throw new Error(`titleEscrowOwner !== tokenRegistry`); + titleEscrowOwner = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); + if (!(isAddress(titleEscrowOwner) === true)) throw new Error(`isAddress(titleEscrowOwner) === true`); + if (!(titleEscrowOwner !== tokenRegistry)) throw new Error(`titleEscrowOwner !== tokenRegistry`); } - // it("should not be able to reject surrender invalid title-escrow on token-registry", async () => { + //"should not be able to reject surrender invalid title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey); + const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand( + { tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, + owner.privateKey + ); const results = run(command); checkFailure(results, "missing revert data in call exception"); } - - // it("should not be able to reject surrender title-escrow on invalid token-registry", async () => { + //"should not be able to reject surrender title-escrow on invalid token-registry" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); - const command = generateRejectSurrenderCommand({ tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey); + const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand( + { tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, + owner.privateKey + ); const results = run(command); checkFailure(results, "null"); } - - // it.todo("should be fail when user without permission attempts reject surrender"); -} +}; diff --git a/src/e2e/surrender.e2e.ts b/src/e2e/surrender.e2e.ts index 469476cf..8f8fd6c4 100644 --- a/src/e2e/surrender.e2e.ts +++ b/src/e2e/surrender.e2e.ts @@ -1,22 +1,19 @@ -import { isTokenId } from "./utils/token-management"; -import { extractLine, extractStatus, LineInfo, run } from "./utils/shell"; -import { BurnAddress, defaultRunParameters, EndStatus, network, owner, receiver, TokenIdLength, TokenInfo } from "./utils/constants"; +import { run } from "./utils/shell"; +import { BurnAddress, defaultRunParameters, owner, receiver } from "./utils/constants"; import { BaseTitleEscrowCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateSurrenderCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; import { deployTokenRegistry, mintTokenRegistry, checkSurrenderSuccess, checkFailure } from "./utils/bootstrap"; - const defaultTitleEscrow = { ...defaultRunParameters, beneficiary: owner.ethAddress, holder: owner.ethAddress, }; - -export const surrender = async () => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); +export const surrender = async (): Promise => { + const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); @@ -32,19 +29,27 @@ export const surrender = async () => { surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - if(isAddress(titleEscrowOwner) !== true){ throw new Error(`(isAddress(titleEscrowOwner) === true);`)}; - if(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`)}; + if (isAddress(titleEscrowOwner) !== true) { + throw new Error(`(isAddress(titleEscrowOwner) === true);`); + } + if (titleEscrowOwner === surrenderTitleEscrow.tokenRegistry) { + throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`); + } const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); const results = run(command); const surrenderResults = checkSurrenderSuccess(results); - if(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId){ throw new Error(`(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId);`)}; + if (surrenderResults.tokenId !== surrenderTitleEscrow.tokenId) { + throw new Error(`(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId);`); + } titleEscrowOwner = await retrieveTitleEscrowOwner( signer, surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - if(titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry);`)}; - }; + if (titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry) { + throw new Error(`(titleEscrowOwner !== surrenderTitleEscrow.tokenRegistry);`); + } + } { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); @@ -63,12 +68,16 @@ export const surrender = async () => { surrenderTitleEscrow.tokenRegistry, surrenderTitleEscrow.tokenId ); - if(isAddress(titleEscrowOwner) !== true){ throw new Error(`(isAddress(titleEscrowOwner) !== true);`)}; - if(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry){ throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`)}; - }; + if (isAddress(titleEscrowOwner) !== true) { + throw new Error(`(isAddress(titleEscrowOwner) !== true);`); + } + if (titleEscrowOwner === surrenderTitleEscrow.tokenRegistry) { + throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`); + } + } { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -78,10 +87,10 @@ export const surrender = async () => { const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - }; + } { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -91,5 +100,5 @@ export const surrender = async () => { const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); checkFailure(results, "null"); - }; + } }; diff --git a/src/e2e/utils/bootstrap/accept-surrender.ts b/src/e2e/utils/bootstrap/accept-surrender.ts index 4db06ade..cf2043ef 100644 --- a/src/e2e/utils/bootstrap/accept-surrender.ts +++ b/src/e2e/utils/bootstrap/accept-surrender.ts @@ -1,20 +1,18 @@ - import { EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; -export const checkSurrenderAcceptSuccess = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); - - const isValidTokenId = isTokenId(tokenId); - - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - tokenId, - }; +export const checkSurrenderAcceptSuccess = (results: string): { tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, }; - \ No newline at end of file +}; diff --git a/src/e2e/utils/bootstrap/change-holder.ts b/src/e2e/utils/bootstrap/change-holder.ts index 849ee09a..0c8f4498 100644 --- a/src/e2e/utils/bootstrap/change-holder.ts +++ b/src/e2e/utils/bootstrap/change-holder.ts @@ -1,45 +1,37 @@ - import { isAddress } from "web3-utils"; -import { mintTokenRegistry } from "."; import { TitleEscrowTransferHolderCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { generateChangeHolderCommand } from "../commands"; -import { AddressLength, BurnAddress, defaultRunParameters, EndStatus, network, receiver, TokenIdLength } from "../constants"; +import { AddressLength, EndStatus, network, receiver, TokenIdLength } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -// ✔ success Transferable record with hash 0x9837ba0954300cf74dea2d7ee9f294a3d1ca0ce2fb8025a3de505440971a7baf's holder has been successfully changed to holder with address: 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 +export const defaultTransferHolder = { + newHolder: receiver.ethAddress, + network: network, + dryRun: false, +}; +export const checkChangeHolderSuccess = (results: string): { newHolder: string; tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Change Holder failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const holder = titleEscrowAddressLine.substring(173, 173 + AddressLength); -export const defaultTransferHolder = { - newHolder: receiver.ethAddress, - network: network, - dryRun: false, - }; - -export const checkChangeHolderSuccess = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Change Holder failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - const holder = titleEscrowAddressLine.substring(173, 173 + AddressLength); - - const holderIsAddress = isAddress(holder); - const isValidTokenId = isTokenId(tokenId); - - if (!holderIsAddress) throw new Error("Invalid holder address"); - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - newHolder: holder, - tokenId, - }; - }; + const holderIsAddress = isAddress(holder); + const isValidTokenId = isTokenId(tokenId); - export const changeHolderToken = (privateKey: string, transferHolder: TitleEscrowTransferHolderCommand) => { - const command = generateChangeHolderCommand(transferHolder, privateKey); - const results = run(command); - checkChangeHolderSuccess(results); - } + if (!holderIsAddress) throw new Error("Invalid holder address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + return { + newHolder: holder, + tokenId, + }; +}; - \ No newline at end of file +export const changeHolderToken = (privateKey: string, transferHolder: TitleEscrowTransferHolderCommand): void => { + const command = generateChangeHolderCommand(transferHolder, privateKey); + const results = run(command); + checkChangeHolderSuccess(results); +}; diff --git a/src/e2e/utils/bootstrap/common.ts b/src/e2e/utils/bootstrap/common.ts index a8a2b505..a727d91f 100644 --- a/src/e2e/utils/bootstrap/common.ts +++ b/src/e2e/utils/bootstrap/common.ts @@ -1,9 +1,11 @@ import { EndStatus } from "../constants"; import { extractStatus } from "../shell"; -export const checkFailure = (results: string, expectedErrorMessage: string) => { //}: Error | undefined => { - const statusMessage = extractStatus(results, EndStatus.error); - if(!(statusMessage.length > 0)) throw new Error(`!statusMessage.length > 0`); - const errorMessage = statusMessage[0].lineContent.substring(13); - if(!(errorMessage.includes(expectedErrorMessage))){throw new Error(`!errorMessage.includes(expectedErrorMessage)`)}; -}; \ No newline at end of file +export const checkFailure = (results: string, expectedErrorMessage: string): void => { + const statusMessage = extractStatus(results, EndStatus.error); + if (!(statusMessage.length > 0)) throw new Error(`!statusMessage.length > 0`); + const errorMessage = statusMessage[0].lineContent.substring(13); + if (!errorMessage.includes(expectedErrorMessage)) { + throw new Error(`!errorMessage.includes(expectedErrorMessage)`); + } +}; diff --git a/src/e2e/utils/bootstrap/deploy.ts b/src/e2e/utils/bootstrap/deploy.ts index d213b537..51da7d9d 100644 --- a/src/e2e/utils/bootstrap/deploy.ts +++ b/src/e2e/utils/bootstrap/deploy.ts @@ -1,6 +1,6 @@ import { isAddress } from "web3-utils"; -import { DeployDocumentStoreCommand, DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; -import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "../commands"; +import { DeployTokenRegistryCommand } from "../../../commands/deploy/deploy.types"; +import { generateDeployTokenRegistryCommand } from "../commands"; import { defaultRunParameters, creators, EndStatus, AddressLength } from "../constants"; import { extractStatus, run } from "../shell"; @@ -15,18 +15,16 @@ const numberGenerator = (range: number): number => { return Math.floor(Math.random() * range); }; - export const checkTokenRegistrySuccess = (results: string): string => { const statusLine = extractStatus(results, EndStatus.success, "Token registry deployed at "); if (statusLine.length <= 0) throw new Error("Deployment failed"); const tokenRegistryDeploymentLine = statusLine[0].lineContent; const tokenRegistry = tokenRegistryDeploymentLine.substring(40, 40 + AddressLength); - - const tokenRegistryIsAddress = isAddress(tokenRegistry); - if (!tokenRegistryIsAddress) throw new Error("Invalid token registry address"); - return tokenRegistry; -}; + const tokenRegistryIsAddress = isAddress(tokenRegistry); + if (!tokenRegistryIsAddress) throw new Error("Invalid token registry address"); + return tokenRegistry; +}; export const deployTokenRegistry = ( privateKey: string, diff --git a/src/e2e/utils/bootstrap/endorse-owners.ts b/src/e2e/utils/bootstrap/endorse-owners.ts index ecd0c883..fb52e758 100644 --- a/src/e2e/utils/bootstrap/endorse-owners.ts +++ b/src/e2e/utils/bootstrap/endorse-owners.ts @@ -3,26 +3,25 @@ import { AddressLength, EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; - export const checkEndorseOwner = (results: string) => { - // ✔ success Transferable record with hash 0xffafc068018521a42a40ba1a8b9bf574c99c69763e42e155fae498278edb8074's holder has been successfully endorsed to new owner with address 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 and new holder with address: 0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60 - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Minting failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - const beneficiary = titleEscrowAddressLine.substring(176, 176 + AddressLength); - const holder = titleEscrowAddressLine.substring(248, 248 + AddressLength); - - const beneficiaryIsAddress = isAddress(beneficiary); - const holderIsAddress = isAddress(holder); - const isValidTokenId = isTokenId(tokenId); - - if (!beneficiaryIsAddress) throw new Error("Invalid beneficiary address"); - if (!holderIsAddress) throw new Error("Invalid holder address"); - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - beneficiary, - holder, - tokenId, - }; - } \ No newline at end of file +export const checkEndorseOwner = (results: string): { beneficiary: string; holder: string; tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const beneficiary = titleEscrowAddressLine.substring(176, 176 + AddressLength); + const holder = titleEscrowAddressLine.substring(248, 248 + AddressLength); + + const beneficiaryIsAddress = isAddress(beneficiary); + const holderIsAddress = isAddress(holder); + const isValidTokenId = isTokenId(tokenId); + + if (!beneficiaryIsAddress) throw new Error("Invalid beneficiary address"); + if (!holderIsAddress) throw new Error("Invalid holder address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + beneficiary, + holder, + tokenId, + }; +}; diff --git a/src/e2e/utils/bootstrap/endorse-transfer.ts b/src/e2e/utils/bootstrap/endorse-transfer.ts index 090628f0..e8eadcc4 100644 --- a/src/e2e/utils/bootstrap/endorse-transfer.ts +++ b/src/e2e/utils/bootstrap/endorse-transfer.ts @@ -3,21 +3,21 @@ import { AddressLength, EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; - export const checkEndorseTransfer = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Minting failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - const beneficiary = titleEscrowAddressLine.substring(177, 177 + AddressLength); - - const beneficiaryIsAddress = isAddress(beneficiary); - const isValidTokenId = isTokenId(tokenId); - - if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - beneficiary, - tokenId, - }; - } \ No newline at end of file +export const checkEndorseTransfer = (results: string): { beneficiary: string; tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const beneficiary = titleEscrowAddressLine.substring(177, 177 + AddressLength); + + const beneficiaryIsAddress = isAddress(beneficiary); + const isValidTokenId = isTokenId(tokenId); + + if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + beneficiary, + tokenId, + }; +}; diff --git a/src/e2e/utils/bootstrap/index.ts b/src/e2e/utils/bootstrap/index.ts index 53aea86a..518059ed 100644 --- a/src/e2e/utils/bootstrap/index.ts +++ b/src/e2e/utils/bootstrap/index.ts @@ -8,4 +8,3 @@ export * from "./change-holder"; export * from "./surrender"; export * from "./reject-surrender"; export * from "./accept-surrender"; - diff --git a/src/e2e/utils/bootstrap/mint.ts b/src/e2e/utils/bootstrap/mint.ts index 8a991baf..992571cd 100644 --- a/src/e2e/utils/bootstrap/mint.ts +++ b/src/e2e/utils/bootstrap/mint.ts @@ -4,7 +4,6 @@ import { deployTokenRegistry } from "."; import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; import { generateMintTitleEscrowCommand } from "../commands"; import { AddressLength, defaultRunParameters, EndStatus, TokenIdLength, TokenInfo } from "../constants"; -import { getSigner, retrieveTitleEscrowOwner } from "../contract-checks"; import { extractStatus, run } from "../shell"; import { generateTokenId, isTokenId } from "../token-management"; @@ -15,11 +14,12 @@ export interface MintData { holder: string; } -export const validateMintData = (expectedValue: MintData, value: MintData) => { - if(!(expectedValue.address === value.address)) throw new Error(`expectedValue.address === value.address`); - if(!(expectedValue.beneficiary === value.beneficiary)) throw new Error(`expectedValue.beneficiary === value.beneficiary`); - if(!(expectedValue.holder === value.holder)) throw new Error(`expectedValue.holder === value.holder`); - if(!(expectedValue.tokenId === value.tokenId)) throw new Error(`expectedValue.tokenId === value.tokenId`); +export const validateMintData = (expectedValue: MintData, value: MintData): void => { + if (!(expectedValue.address === value.address)) throw new Error(`expectedValue.address === value.address`); + if (!(expectedValue.beneficiary === value.beneficiary)) + throw new Error(`expectedValue.beneficiary === value.beneficiary`); + if (!(expectedValue.holder === value.holder)) throw new Error(`expectedValue.holder === value.holder`); + if (!(expectedValue.tokenId === value.tokenId)) throw new Error(`expectedValue.tokenId === value.tokenId`); }; export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { @@ -39,7 +39,6 @@ export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: str return mintToken(privateKey, titleEscrowParameter); }; - export const checkMintSuccess = (results: string): MintData => { const statusLine = extractStatus(results, EndStatus.success, "Token with hash "); if (statusLine.length <= 0) throw new Error("Minting failed"); @@ -70,16 +69,9 @@ export const checkMintSuccess = (results: string): MintData => { export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); const results = run(command); - const {address: tokenRegistry, tokenId, beneficiary, holder} = checkMintSuccess(results); - const signer = getSigner(titleEscrowParameter.network, privateKey); - // let titleEscrowAddress: string = retrieveTitleEscrowOwner( - // signer, - // tokenRegistry, - // tokenId, - // ); + const { address: tokenRegistry, tokenId } = checkMintSuccess(results); return { tokenRegistry, tokenId, - // titleEscrowAddress, }; }; diff --git a/src/e2e/utils/bootstrap/nominate.ts b/src/e2e/utils/bootstrap/nominate.ts index ec476111..71477af1 100644 --- a/src/e2e/utils/bootstrap/nominate.ts +++ b/src/e2e/utils/bootstrap/nominate.ts @@ -2,7 +2,7 @@ import { isAddress } from "web3-utils"; import { mintTokenRegistry } from "."; import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { generateNominateCommand } from "../commands"; -import { AddressLength, defaultRunParameters, EndStatus, network, owner, receiver, TokenIdLength, TokenInfo } from "../constants"; +import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength, TokenInfo } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; @@ -12,43 +12,39 @@ export const defaultNominateBeneficiary = { }; export const mintNominatedToken = (privateKey: string, nominee: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); - const { tokenRegistry, tokenId } = tokenDetails; - const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, - tokenId: tokenId, - tokenRegistry: tokenRegistry, - newBeneficiary: nominee, - }; - nominateToken(privateKey, nominateParameter); - return tokenDetails; + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = tokenDetails; + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newBeneficiary: nominee, }; - + nominateToken(privateKey, nominateParameter); + return tokenDetails; +}; - export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { - const command = generateNominateCommand(nominateParameter, privateKey); - const results = run(command); - checkNominateSuccess(results); - }; +export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { + const command = generateNominateCommand(nominateParameter, privateKey); + const results = run(command); + checkNominateSuccess(results); +}; +export const checkNominateSuccess = (results: string): { nominee: string; tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Nomination failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const nominee = titleEscrowAddressLine.substring(177, 177 + AddressLength); + const nomineeIsAddress = isAddress(nominee); + const isValidTokenId = isTokenId(tokenId); -export const checkNominateSuccess = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Nomination failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - const nominee = titleEscrowAddressLine.substring(177, 177 + AddressLength); - - const nomineeIsAddress = isAddress(nominee); - const isValidTokenId = isTokenId(tokenId); - - if (!nomineeIsAddress) throw new Error("Invalid nominee address"); - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - nominee, - tokenId, - }; + if (!nomineeIsAddress) throw new Error("Invalid nominee address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + nominee, + tokenId, }; - \ No newline at end of file +}; diff --git a/src/e2e/utils/bootstrap/reject-surrender.ts b/src/e2e/utils/bootstrap/reject-surrender.ts index fef9f0ec..97a5c4fb 100644 --- a/src/e2e/utils/bootstrap/reject-surrender.ts +++ b/src/e2e/utils/bootstrap/reject-surrender.ts @@ -1,20 +1,18 @@ - import { EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; -export const checkSurrenderRejectSuccess = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); - - const isValidTokenId = isTokenId(tokenId); - - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - tokenId, - }; +export const checkSurrenderRejectSuccess = (results: string): { tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, }; - \ No newline at end of file +}; diff --git a/src/e2e/utils/bootstrap/surrender.ts b/src/e2e/utils/bootstrap/surrender.ts index 4e215ad6..78f16873 100644 --- a/src/e2e/utils/bootstrap/surrender.ts +++ b/src/e2e/utils/bootstrap/surrender.ts @@ -6,43 +6,40 @@ import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; const defaultTitleEscrow = { - ...defaultRunParameters, - beneficiary: owner.ethAddress, - holder: owner.ethAddress, + ...defaultRunParameters, + beneficiary: owner.ethAddress, + holder: owner.ethAddress, }; export const mintSurrenderToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); - const { tokenRegistry, tokenId, titleEscrowAddress } = tokenDetails; - const surrenderParameter: BaseTitleEscrowCommand = { - ...defaultTitleEscrow, - tokenRegistry: tokenRegistry, - tokenId: tokenId, - }; - surrenderToken(privateKey, surrenderParameter); - return tokenDetails; - }; - - - export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { - const command = generateSurrenderCommand(surrenderParameter, privateKey); - const results = run(command); - checkSurrenderSuccess(results); + const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = tokenDetails; + const surrenderParameter: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry: tokenRegistry, + tokenId: tokenId, }; + surrenderToken(privateKey, surrenderParameter); + return tokenDetails; +}; + +export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { + const command = generateSurrenderCommand(surrenderParameter, privateKey); + const results = run(command); + checkSurrenderSuccess(results); +}; +export const checkSurrenderSuccess = (results: string): { tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Nomination failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); -export const checkSurrenderSuccess = (results: string) => { - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Nomination failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - - const isValidTokenId = isTokenId(tokenId); - - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - tokenId, - }; + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, }; - \ No newline at end of file +}; diff --git a/src/e2e/utils/constants.ts b/src/e2e/utils/constants.ts index fc772f8b..e32e45ff 100644 --- a/src/e2e/utils/constants.ts +++ b/src/e2e/utils/constants.ts @@ -1,6 +1,5 @@ // import { NonceManager } from "@ethersproject/experimental"; import { constants } from "@govtechsg/token-registry"; -import { providers, Wallet } from "ethers"; export const { contractAddress } = constants; export const network = "local"; diff --git a/src/e2e/utils/contract-checks.ts b/src/e2e/utils/contract-checks.ts index f344eea9..d47db705 100644 --- a/src/e2e/utils/contract-checks.ts +++ b/src/e2e/utils/contract-checks.ts @@ -53,7 +53,7 @@ export const retrieveEscrowDetails = async ( ): Promise => { //TODO: check ownership const { tokenRegistry, tokenId, titleEscrowAddress } = tokenInfo; - if(!titleEscrowAddress) throw new Error("Escrow Address unspecified"); + if (!titleEscrowAddress) throw new Error("Escrow Address unspecified"); const tokenDetails = await retrieveTokenInfo(signerOrProvider, tokenRegistry); let titleEscrowDetails: TitleEscrowInfo | undefined; if (!titleEscrowAddress) { diff --git a/src/e2e/utils/token-management.ts b/src/e2e/utils/token-management.ts index c5a43384..02d6fefe 100644 --- a/src/e2e/utils/token-management.ts +++ b/src/e2e/utils/token-management.ts @@ -12,11 +12,12 @@ export const generateTokenId = (): string => { throw new Error("Unable to generate tokenIds"); }; -export const isTokenId = (tokenId: string) => { - const hexRegex = /[0-9A-Fa-f]{6}/g; +export const isTokenId = (tokenId: string): boolean => { + const hexRegex = /[0-9A-Fa-f]{64}/g; tokenId = tokenId.trim(); const containsHexPrefix = tokenId.substring(0, 2) === "0x"; if (containsHexPrefix) tokenId = tokenId.substring(2); if (tokenId.length <= 0) return false; - return tokenId.match(hexRegex); + const matchedString = tokenId.match(hexRegex); + return matchedString?.length === 1; }; From 3a61c964dbb48d0bad99bd8369850ced73610ee5 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 19 Jan 2023 01:02:21 +0800 Subject: [PATCH 54/63] fix: check for valid token-registry --- .../title-escrow/acceptSurrendered.test.ts | 1 + .../title-escrow/acceptSurrendered.ts | 8 ++++---- .../endorseNominatedBeneficiary.test.ts | 3 +++ src/implementations/title-escrow/helpers.ts | 18 ++++++++++++++++-- .../title-escrow/nominateBeneficiary.test.ts | 3 +++ .../title-escrow/rejectSurrendered.test.ts | 1 + .../title-escrow/rejectSurrendered.ts | 5 +++-- .../title-escrow/surrenderDocument.test.ts | 3 +++ .../title-escrow/transferHolder.test.ts | 3 +++ .../title-escrow/transferOwners.test.ts | 3 +++ .../token-registry/issue.test.ts | 1 + src/implementations/token-registry/issue.ts | 5 +++-- 12 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 6ec16afb..2471ebf8 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -35,6 +35,7 @@ describe("title-escrow", () => { mockedConnectERC721.mockReturnValue({ burn: mockBurnToken, callStatic: { + genesis: jest.fn().mockResolvedValue(0), burn: mockCallStaticBurnToken, }, }); diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index 010805f8..9cb73dd4 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -2,10 +2,9 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; - import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { TradeTrustToken__factory } from "@govtechsg/token-registry/dist/contracts"; +import { connectToTokenRegistry } from "./helpers"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -17,7 +16,7 @@ export const acceptSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance = await TradeTrustToken__factory.connect(address, wallet); + const tokenRegistryInstance = await connectToTokenRegistry({ address, wallet }); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), @@ -27,8 +26,9 @@ export const acceptSurrendered = async ({ } signale.await(`Sending transaction to pool`); - await tokenRegistryInstance.callStatic.burn(tokenId); + console.log(await tokenRegistryInstance.callStatic.burn(tokenId)); const transaction = await tokenRegistryInstance.burn(tokenId); + console.log(transaction); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index ee1ef662..fbff3be5 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -38,6 +38,9 @@ describe("title-escrow", () => { mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, + callStatic: { + genesis: jest.fn().mockResolvedValue(0), + }, }); mockedConnectTokenFactory.mockReturnValue({ diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index 41593019..ec22278a 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -14,14 +14,28 @@ interface ConnectToTitleEscrowArgs { wallet: Wallet | ConnectedSigner; } +interface ConnectToTokenRegistryArgs { + address: string; + wallet: Wallet | ConnectedSigner; +} + export const connectToTitleEscrow = async ({ tokenId, address, wallet, }: ConnectToTitleEscrowArgs): Promise => { - const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); + const tokenRegistry: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId); - return await TitleEscrow__factory.connect(titleEscrowAddress, wallet); + return TitleEscrow__factory.connect(titleEscrowAddress, wallet); +}; + +export const connectToTokenRegistry = async ({ + address, + wallet, +}: ConnectToTokenRegistryArgs): Promise => { + const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); + await tokenRegistryInstance.callStatic.genesis(); + return tokenRegistryInstance; }; interface validateEndorseChangeOwnerArgs { diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index eb755c91..45a0b229 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -36,6 +36,9 @@ describe("title-escrow", () => { mockGetHolder.mockResolvedValue(mockedHolder); mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, + callStatic: { + genesis: jest.fn().mockResolvedValue(0), + }, }); mockedConnectTokenFactory.mockReturnValue({ nominate: mockNominateBeneficiary, diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index e8ab72b1..40320fca 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -67,6 +67,7 @@ describe("title-escrow", () => { filters: { Transfer: mockTransferEvent }, queryFilter: mockQueryFilter, callStatic: { + genesis: jest.fn().mockResolvedValue(0), restore: mockCallStaticRestoreTitle, }, }); diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index 098fb0ef..de35e1a8 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -1,10 +1,11 @@ -import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; +import { connectToTokenRegistry } from "./helpers"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -16,7 +17,7 @@ export const rejectSurrendered = async ({ ...rest }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); + const tokenRegistryInstance: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index bc01d275..22aa8041 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -41,6 +41,9 @@ describe("title-escrow", () => { wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); mockedConnectERC721.mockReturnValue({ + callStatic: { + genesis: jest.fn().mockResolvedValue(0), + }, ownerOf: mockedOwnerOf, }); mockedConnectTitleEscrowFactory.mockReturnValue({ diff --git a/src/implementations/title-escrow/transferHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts index 7b6ff058..552c0c1f 100644 --- a/src/implementations/title-escrow/transferHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -36,6 +36,9 @@ describe("title-escrow", () => { }); mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, + callStatic: { + genesis: jest.fn().mockResolvedValue(0), + }, }); mockedConnectTokenFactory.mockReturnValue({ transferHolder: mockTransferHolder, diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index 9f411473..2ceb6a4d 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -38,6 +38,9 @@ describe("title-escrow", () => { mockGetHolder.mockReturnValue(mockedHolder); mockedConnectERC721.mockReturnValue({ ownerOf: mockedOwnerOf, + callStatic: { + genesis: jest.fn().mockResolvedValue(0), + }, }); mockedConnectTokenFactory.mockReturnValue({ transferOwners: mockTransferOwners, diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index 1bf33268..a26d5546 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -34,6 +34,7 @@ describe("token-registry", () => { const mockTTERC721Contract = { mint: mockedIssue, callStatic: { + genesis: jest.fn().mockResolvedValue(0), mint: mockCallStaticSafeMint, }, }; diff --git a/src/implementations/token-registry/issue.ts b/src/implementations/token-registry/issue.ts index 1b845468..cc750d39 100644 --- a/src/implementations/token-registry/issue.ts +++ b/src/implementations/token-registry/issue.ts @@ -1,10 +1,11 @@ -import { TradeTrustToken, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; +import { TradeTrustToken } from "@govtechsg/token-registry/contracts"; import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; +import { connectToTokenRegistry } from "../title-escrow/helpers"; const { trace } = getLogger("token-registry:issue"); @@ -18,7 +19,7 @@ export const issueToTokenRegistry = async ({ ...rest }: TokenRegistryIssueCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); - const tokenRegistry: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); + const tokenRegistry: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); if (dryRun) { await dryRunMode({ From 6a4313db8f613fabe2ef83641c39df509703937b Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 19 Jan 2023 01:02:42 +0800 Subject: [PATCH 55/63] feat: e2e tests --- .circleci/config.yml | 2 +- src/e2e/accept-surrender.e2e.ts | 37 ++++- src/e2e/all.ts | 16 +- src/e2e/change-holder.e2e.ts | 54 ++++++- src/e2e/deploy.e2e.ts | 2 +- src/e2e/endorse-change-owner.e2e.ts | 126 ++++++++++++++- src/e2e/endorse-transfer.e2e.ts | 147 +++++++++++++++--- src/e2e/mint.e2e.ts | 70 ++++++++- src/e2e/nominate.e2e.ts | 96 ++++++++---- src/e2e/reject-surrender.e2e.ts | 31 +++- src/e2e/surrender.e2e.ts | 65 ++++++-- src/e2e/utils/bootstrap/accept-surrender.ts | 18 --- src/e2e/utils/bootstrap/endorse-transfer.ts | 23 --- src/e2e/utils/constants.ts | 12 +- src/e2e/utils/helpers/accept-surrender.ts | 41 +++++ .../{bootstrap => helpers}/change-holder.ts | 5 +- .../utils/{bootstrap => helpers}/common.ts | 0 .../utils/{bootstrap => helpers}/deploy.ts | 0 src/e2e/utils/helpers/endorse-beneficiary.ts | 48 ++++++ .../{bootstrap => helpers}/endorse-owners.ts | 0 src/e2e/utils/{bootstrap => helpers}/index.ts | 2 +- src/e2e/utils/{bootstrap => helpers}/mint.ts | 0 .../utils/{bootstrap => helpers}/nominate.ts | 0 .../reject-surrender.ts | 0 .../utils/{bootstrap => helpers}/surrender.ts | 0 tsconfig.prod.json | 3 +- 26 files changed, 658 insertions(+), 140 deletions(-) delete mode 100644 src/e2e/utils/bootstrap/accept-surrender.ts delete mode 100644 src/e2e/utils/bootstrap/endorse-transfer.ts create mode 100644 src/e2e/utils/helpers/accept-surrender.ts rename src/e2e/utils/{bootstrap => helpers}/change-holder.ts (91%) rename src/e2e/utils/{bootstrap => helpers}/common.ts (100%) rename src/e2e/utils/{bootstrap => helpers}/deploy.ts (100%) create mode 100644 src/e2e/utils/helpers/endorse-beneficiary.ts rename src/e2e/utils/{bootstrap => helpers}/endorse-owners.ts (100%) rename src/e2e/utils/{bootstrap => helpers}/index.ts (87%) rename src/e2e/utils/{bootstrap => helpers}/mint.ts (100%) rename src/e2e/utils/{bootstrap => helpers}/nominate.ts (100%) rename src/e2e/utils/{bootstrap => helpers}/reject-surrender.ts (100%) rename src/e2e/utils/{bootstrap => helpers}/surrender.ts (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index ff0ba4dc..7dd24d25 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ jobs: command: npm run lint - run: name: test - command: npm run test -- --runInBand + command: npm run test -- - run: name: e2e command: npm run e2e diff --git a/src/e2e/accept-surrender.e2e.ts b/src/e2e/accept-surrender.e2e.ts index 3ad4d17f..541323e3 100644 --- a/src/e2e/accept-surrender.e2e.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -1,6 +1,12 @@ -import { checkFailure, checkSurrenderAcceptSuccess, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; +import { + checkFailure, + checkSurrenderAcceptSuccess, + deployTokenRegistry, + mintSurrenderToken, + mintTokenRegistry, +} from "./utils/helpers"; import { generateAcceptSurrenderCommand } from "./utils/commands"; -import { BurnAddress, EmptyTokenID, network, owner } from "./utils/constants"; +import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from "./utils/constants"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { run } from "./utils/shell"; @@ -8,10 +14,9 @@ export const acceptSurrender = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); // const errors: Error[] = []; const defaultTitleEscrow = { + ...defaultRunParameters, beneficiary: owner.ethAddress, holder: owner.ethAddress, - network: network, - dryRun: false, }; //"should be able to accept-surrender title-escrow on token-registry" @@ -50,6 +55,26 @@ export const acceptSurrender = async (): Promise => { const results = run(command); checkFailure(results, "null"); } -}; -// npm run dev -- title-escrow accept-surrendered --token-registry 0x0000000000000000000000000000000000000000 --tokenId 0xf32907ec66ac258f058eae34d76b160b0ca520b5c613ca93ae6bb22a8f9c451f --network local -k 0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7 + //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" + { + const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand( + { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, + receiver.privateKey + ); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to accept un-surrendered title-escrow on token-registry" + { + const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const command = generateAcceptSurrenderCommand( + { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, + owner.privateKey + ); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } +}; diff --git a/src/e2e/all.ts b/src/e2e/all.ts index 8f87e861..e9116aa9 100644 --- a/src/e2e/all.ts +++ b/src/e2e/all.ts @@ -6,17 +6,23 @@ import { endorseTransfer } from "./endorse-transfer.e2e"; import { mint } from "./mint.e2e"; import { nominate } from "./nominate.e2e"; import { rejectSurrender } from "./reject-surrender.e2e"; +import { endorseChangeOwner } from "./endorse-change-owner.e2e"; const awaitForDuration = async (runFunction: () => void): Promise => { await runFunction(); + console.log(runFunction.name) }; -awaitForDuration(surrender); -awaitForDuration(acceptSurrender); awaitForDuration(deployDocumentStore); awaitForDuration(deployTokenRegistry); -awaitForDuration(changeHolder); -awaitForDuration(endorseTransfer); + awaitForDuration(mint); -awaitForDuration(nominate); + +awaitForDuration(surrender); awaitForDuration(rejectSurrender); +awaitForDuration(acceptSurrender); + +awaitForDuration(nominate); +awaitForDuration(changeHolder); +awaitForDuration(endorseTransfer); +awaitForDuration(endorseChangeOwner); diff --git a/src/e2e/change-holder.e2e.ts b/src/e2e/change-holder.e2e.ts index 19891e11..e7ad11b0 100644 --- a/src/e2e/change-holder.e2e.ts +++ b/src/e2e/change-holder.e2e.ts @@ -5,11 +5,15 @@ import { checkFailure, defaultTransferHolder, deployTokenRegistry, + mintBurntToken, + mintSurrenderToken, mintTokenRegistry, -} from "./utils/bootstrap"; +} from "./utils/helpers"; import { generateChangeHolderCommand } from "./utils/commands"; import { BurnAddress, EmptyTokenID, owner, receiver } from "./utils/constants"; import { run } from "./utils/shell"; +import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; +import { BigNumber } from "ethers"; // "transfer holder title-escrow" export const changeHolder = async (): Promise => { @@ -26,6 +30,18 @@ export const changeHolder = async (): Promise => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); checkChangeHolderSuccess(results); + + const signer = await getSigner(transferHolder.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.holder === transferHolder.newHolder)) + throw new Error(`titleEscrowInfo.holder === transferHolder.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === transferHolder.tokenRegistry)) + throw new Error(`titleEscrowInfo.registry === transferHolder.address`); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(transferHolder.tokenId)); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); } //holder should be able to transfer holder of title-escrow" @@ -66,7 +82,7 @@ export const changeHolder = async (): Promise => { checkFailure(results, "missing revert data in call exception"); } - //should not be able to transfer holder of invalid title-escrow on token-registry" + //should not be able to transfer holder of title-escrow on invalid token-registry" { const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { @@ -103,4 +119,38 @@ export const changeHolder = async (): Promise => { const results = run(command); checkFailure(results, "missing revert data in call exception"); } + + //should not be able to transfer holder of surrendered title-escrow" + { + console.info("Skipped Test"); + console.info("should not be able to transfer holder of surrendered title-escrow"); + return; + const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: owner.ethAddress, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //should not be able to transfer holder of burnt title-escrow" + { + console.info("Skipped Test"); + console.info("should not be able to transfer holder of burnt title-escrow"); + return; + const { tokenRegistry, tokenId } = mintBurntToken(owner.privateKey, tokenRegistryAddress); + const transferHolder: TitleEscrowTransferHolderCommand = { + ...defaultTransferHolder, + tokenId: tokenId, + tokenRegistry: tokenRegistry, + newHolder: owner.ethAddress, + }; + const command = generateChangeHolderCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } }; diff --git a/src/e2e/deploy.e2e.ts b/src/e2e/deploy.e2e.ts index 62660c7c..f546aff7 100644 --- a/src/e2e/deploy.e2e.ts +++ b/src/e2e/deploy.e2e.ts @@ -4,7 +4,7 @@ import { isAddress } from "web3-utils"; import { defaultRunParameters, EndStatus, owner } from "./utils/constants"; import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils/commands"; import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; -import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/bootstrap"; +import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/helpers"; export const deployTokenRegistry = async (): Promise => { //should be able to deploy token-registry" diff --git a/src/e2e/endorse-change-owner.e2e.ts b/src/e2e/endorse-change-owner.e2e.ts index 1147cdf7..9f7c447d 100644 --- a/src/e2e/endorse-change-owner.e2e.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -1,24 +1,28 @@ import { run } from "./utils/shell"; -import { network, owner, receiver } from "./utils/constants"; +import { BurnAddress, defaultRunParameters, owner, receiver, thirdParty } from "./utils/constants"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateTransferOwnersCommand } from "./utils/commands"; import { + burnToken, + changeHolderToken, checkEndorseOwner, checkFailure, deployTokenRegistry, mintNominatedToken, mintTokenRegistry, -} from "./utils/bootstrap"; + surrenderToken, +} from "./utils/helpers"; +import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; +import { BigNumber } from "ethers"; // "endorse change owner title-escrow" export const endorseChangeOwner = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTransferOwners = { + ...defaultRunParameters, newOwner: receiver.ethAddress, newHolder: receiver.ethAddress, - network: network, - dryRun: false, }; //should be able to endorse change owner title-escrow on token-registry" @@ -39,10 +43,99 @@ export const endorseChangeOwner = async (): Promise => { if (!(beneficiary === transferOwners.newOwner)) throw new Error(`beneficiary === transferOwners.newOwner`); if (!(holder === transferOwners.newHolder)) throw new Error(`holder === transferOwners.newHolder`); if (!(tokenIdResult === transferOwners.tokenId)) throw new Error(`tokenIdResult === transferOwners.tokenId`); + + const signer = await getSigner(transferOwners.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow(signer, transferOwners.tokenRegistry, transferOwners.tokenId); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === transferOwners.newOwner)) + throw new Error(`titleEscrowInfo.beneficiary === transferOwners.beneficiary`); + if (!(titleEscrowInfo.holder === transferOwners.newHolder)) + throw new Error(`titleEscrowInfo.holder === transferOwners.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === transferOwners.tokenRegistry)) + throw new Error(`titleEscrowInfo.registry === transferOwners.address`); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(transferOwners.tokenId)); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } + + //"should not be able to endorse change owner from just beneficiary title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + changeHolderToken(owner.privateKey, { + ...defaultTransferOwners, + tokenRegistry: tokenRegistry, + tokenId: tokenId, + newHolder: receiver.ethAddress, + }); + const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }; + + const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse change owner from nominee title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }; + + const command = generateTransferOwnersCommand(transferHolder, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse surrendered title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); + surrenderToken(owner.privateKey, { + ...defaultTransferOwners, + tokenRegistry, + tokenId, + }); + const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }; + + const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse burnt title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); + burnToken(owner.privateKey, { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }); + const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }; + + const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); } - //should not be able to endorse change owner on un-nominated title-escrow" + //"should not be able to endorse change owner on un-nominated title-escrow" { + console.info("Skipped Test"); + console.info("should not be able to endorse change owner on un-nominated title-escrow"); + return; const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { tokenId: tokenId, @@ -53,4 +146,27 @@ export const endorseChangeOwner = async (): Promise => { const results = run(command); checkFailure(results, ""); } + + //"should not be able to endorse change owner from holder title-escrow on token-registry" + { + console.info("Skipped Test"); + console.info("should not be able to endorse change owner from holder title-escrow on token-registry"); + return; + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + changeHolderToken(owner.privateKey, { + ...defaultTransferOwners, + tokenRegistry: tokenRegistry, + tokenId: tokenId, + newHolder: thirdParty.ethAddress, + }); + const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { + ...defaultTransferOwners, + tokenId, + tokenRegistry, + }; + + const command = generateTransferOwnersCommand(transferHolder, thirdParty.privateKey); + const results = run(command); + checkFailure(results, "null"); + } }; diff --git a/src/e2e/endorse-transfer.e2e.ts b/src/e2e/endorse-transfer.e2e.ts index 70ee5762..8fa96b23 100644 --- a/src/e2e/endorse-transfer.e2e.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -1,54 +1,161 @@ import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; import { - checkEndorseTransfer, + burnToken, + changeHolderToken, + checkEndorseBeneficiary, checkFailure, + defaultTransferBeneficiary, deployTokenRegistry, mintNominatedToken, mintTokenRegistry, -} from "./utils/bootstrap"; + surrenderToken, +} from "./utils/helpers"; import { generateEndorseTransferOwnerCommand } from "./utils/commands"; -import { BurnAddress, network, owner, receiver } from "./utils/constants"; +import { owner, receiver, thirdParty } from "./utils/constants"; import { run } from "./utils/shell"; +import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; +import { BigNumber } from "ethers"; export const endorseTransfer = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - const defaultTransferHolder = { - newBeneficiary: receiver.ethAddress, - network: network, - dryRun: false, - }; - //"should be able to endorse transfer title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken( - owner.privateKey, - defaultTransferHolder.newBeneficiary, - tokenRegistryAddress - ); + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); + const results = run(command); + checkEndorseBeneficiary(results); + + const signer = await getSigner(transferHolder.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === transferHolder.newBeneficiary)) + throw new Error(`titleEscrowInfo.beneficiary === transferHolder.beneficiary`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.registry === transferHolder.tokenRegistry)) + throw new Error(`titleEscrowInfo.registry === transferHolder.tokenRegistry`); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(transferHolder.tokenId)); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } + + //"should not be able to endorse transfer from just beneficiary title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + changeHolderToken(owner.privateKey, { + ...defaultTransferBeneficiary, + tokenRegistry: tokenRegistry, + tokenId: tokenId, + newHolder: receiver.ethAddress, + }); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse transfer from nominee title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse surrendered title-escrow on token-registry" + { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); + surrenderToken(owner.privateKey, { + ...defaultTransferBeneficiary, + tokenRegistry, + tokenId, + }); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferHolder, + ...defaultTransferBeneficiary, tokenId, tokenRegistry, + newBeneficiary: receiver.ethAddress, }; const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkEndorseTransfer(results); + checkFailure(results, "missing revert data in call exception"); } - //"should not be able to endorse un-nominated title-escrow on token-registry" + //"should not be able to endorse burnt title-escrow on token-registry" { + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); + burnToken(owner.privateKey, { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + }); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + newBeneficiary: receiver.ethAddress, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); + const results = run(command); + checkFailure(results, "null"); + } + + ("should not be able to endorse un-nominated title-escrow on token-registry"); + { + console.info("Skipped Test"); + console.info("should not be able to endorse un-nominated title-escrow on token-registry"); + return; const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferHolder, + ...defaultTransferBeneficiary, tokenId, tokenRegistry, - newBeneficiary: BurnAddress, + newBeneficiary: receiver.ethAddress, }; const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, ""); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to endorse transfer from holder title-escrow on token-registry" + { + console.info("Skipped Test"); + console.info("should not be able to endorse transfer from holder title-escrow on token-registry"); + return; + const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + changeHolderToken(owner.privateKey, { + ...defaultTransferBeneficiary, + tokenRegistry: tokenRegistry, + tokenId: tokenId, + newHolder: thirdParty.ethAddress, + }); + const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + ...defaultTransferBeneficiary, + tokenId, + tokenRegistry, + }; + + const command = generateEndorseTransferOwnerCommand(transferHolder, thirdParty.privateKey); + const results = run(command); + checkFailure(results, "null"); } }; diff --git a/src/e2e/mint.e2e.ts b/src/e2e/mint.e2e.ts index 7304e493..27b4b02c 100644 --- a/src/e2e/mint.e2e.ts +++ b/src/e2e/mint.e2e.ts @@ -5,7 +5,7 @@ import { TokenRegistryIssueCommand } from "../commands/token-registry/token-regi import { generateMintTitleEscrowCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; -import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/bootstrap"; +import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/helpers"; export const mint = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); @@ -78,6 +78,74 @@ export const mint = async (): Promise => { if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); } + //"should be able to mint title-escrow for a different beneficiary on token-registry" + { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: receiver.ethAddress, + holder: owner.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + const mintResults = checkMintSuccess(results); + validateMintData(titleEscrowParameter as MintData, mintResults); + + const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + titleEscrowParameter.address, + titleEscrowParameter.tokenId + ); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) + throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if (!(titleEscrowInfo.holder === titleEscrowParameter.holder)) + throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === titleEscrowParameter.address)) + throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } + + //"should be able to mint title-escrow for a different holder on token-registry" + { + const tokenId = generateTokenId(); + const titleEscrowParameter: TokenRegistryIssueCommand = { + address: tokenRegistryAddress, + tokenId: tokenId, + beneficiary: owner.ethAddress, + holder: receiver.ethAddress, + ...defaultRunParameters, + }; + const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); + const results = run(command); + const mintResults = checkMintSuccess(results); + validateMintData(titleEscrowParameter as MintData, mintResults); + + const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + titleEscrowParameter.address, + titleEscrowParameter.tokenId + ); + if (!(titleEscrowInfo.active === true)) throw new Error(`titleEscrowInfo.active === true`); + if (!(titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary)) + throw new Error(`titleEscrowInfo.beneficiary === titleEscrowParameter.beneficiary`); + if (!(titleEscrowInfo.holder === titleEscrowParameter.holder)) + throw new Error(`titleEscrowInfo.holder === titleEscrowParameter.holder`); + if (!(titleEscrowInfo.isHoldingToken === true)) throw new Error(`titleEscrowInfo.isHoldingToken === true`); + if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); + if (!(titleEscrowInfo.registry === titleEscrowParameter.address)) + throw new Error(`titleEscrowInfo.registry === titleEscrowParameter.address`); + const correctTokenID = titleEscrowInfo.tokenId.eq(BigNumber.from(titleEscrowParameter.tokenId)); + if (!(correctTokenID === true)) throw new Error(`correctTokenID === true`); + } + //"should fail with invalid token id" { const titleEscrowParameter: TokenRegistryIssueCommand = { diff --git a/src/e2e/nominate.e2e.ts b/src/e2e/nominate.e2e.ts index fc35daf5..1dc0b563 100644 --- a/src/e2e/nominate.e2e.ts +++ b/src/e2e/nominate.e2e.ts @@ -1,15 +1,16 @@ import { run } from "./utils/shell"; -import { BurnAddress, defaultRunParameters, owner, receiver } from "./utils/constants"; +import { BurnAddress, defaultRunParameters, owner, receiver, thirdParty } from "./utils/constants"; import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateNominateCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { + changeHolderToken, checkFailure, checkNominateSuccess, defaultNominateBeneficiary, deployTokenRegistry, mintTokenRegistry, -} from "./utils/bootstrap"; +} from "./utils/helpers"; export const nominate = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); @@ -17,58 +18,71 @@ export const nominate = async (): Promise => { //"should be able to nominate title-escrow on token-registry" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, ...defaultRunParameters, }; - const command = generateNominateCommand(transferHolder, owner.privateKey); + const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); const nominateInfo = checkNominateSuccess(results); - if (!(nominateInfo.tokenId === transferHolder.tokenId)) - throw new Error(`nominateInfo.tokenId === transferHolder.tokenId`); - if (!(nominateInfo.nominee === transferHolder.newBeneficiary)) - throw new Error(`nominateInfo.nominee === transferHolder.newBeneficiary`); - const signer = await getSigner(transferHolder.network, owner.privateKey); - const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); - if (!(titleEscrowInfo.nominee === transferHolder.newBeneficiary)) - throw new Error(`titleEscrowInfo.nominee === transferHolder.newBeneficiary`); + if (!(nominateInfo.tokenId === nominateParameter.tokenId)) + throw new Error(`nominateInfo.tokenId === nominateParameter.tokenId`); + if (!(nominateInfo.nominee === nominateParameter.newBeneficiary)) + throw new Error(`nominateInfo.nominee === nominateParameter.newBeneficiary`); + const signer = await getSigner(nominateParameter.network, owner.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + nominateParameter.tokenRegistry, + nominateParameter.tokenId + ); + if (!(titleEscrowInfo.nominee === nominateParameter.newBeneficiary)) + throw new Error(`titleEscrowInfo.nominee === nominateParameter.newBeneficiary`); } //"should be able to cancel nomination of title-escrow on token-registry" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const transferReceiverNominee: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId, tokenRegistry, }; - let results = run(generateNominateCommand(transferHolder, owner.privateKey)); - transferHolder.newBeneficiary = BurnAddress; - const command = generateNominateCommand(transferHolder, owner.privateKey); - results = run(command); + const receiverNominateCommand = generateNominateCommand(transferReceiverNominee, owner.privateKey); + const receiverNominateResults = run(receiverNominateCommand); + checkNominateSuccess(receiverNominateResults); + const transferBurnNominee = { + ...transferReceiverNominee, + newBeneficiary: BurnAddress, + }; + const command = generateNominateCommand(transferBurnNominee, owner.privateKey); + const results = run(command); const nominateInfo = checkNominateSuccess(results); - if (!(nominateInfo.tokenId === transferHolder.tokenId)) - throw new Error(`nominateInfo.tokenId === transferHolder.tokenId`); - if (!(nominateInfo.nominee === transferHolder.newBeneficiary)) - throw new Error(`nominateInfo.nominee === transferHolder.newBeneficiary`); + if (!(nominateInfo.tokenId === transferBurnNominee.tokenId)) + throw new Error(`nominateInfo.tokenId === transferBurnNominee.tokenId`); + if (!(nominateInfo.nominee === transferBurnNominee.newBeneficiary)) + throw new Error(`nominateInfo.nominee === transferBurnNominee.newBeneficiary`); - const signer = await getSigner(transferHolder.network, owner.privateKey); - const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); + const signer = await getSigner(transferBurnNominee.network, owner.privateKey); + const titleEscrowInfo = await retrieveTitleEscrow( + signer, + transferBurnNominee.tokenRegistry, + transferBurnNominee.tokenId + ); if (!(titleEscrowInfo.nominee === BurnAddress)) throw new Error(`titleEscrowInfo.nominee === BurnAddress`); } //"should not be able to nominate self" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId, tokenRegistry, newBeneficiary: owner.ethAddress, }; - const command = generateNominateCommand(transferHolder, owner.privateKey); + const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); checkFailure(results, "new beneficiary address is the same as the current beneficiary address"); } @@ -76,13 +90,33 @@ export const nominate = async (): Promise => { //"should not be able to nominate unowned token" { const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, }; - const command = generateNominateCommand(transferHolder, receiver.privateKey); + const command = generateNominateCommand(nominateParameter, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to nominate token as holder" + { + const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + changeHolderToken(owner.privateKey, { + ...defaultNominateBeneficiary, + newHolder: receiver.ethAddress, + tokenId, + tokenRegistry, + }); + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { + ...defaultNominateBeneficiary, + tokenId, + tokenRegistry, + newBeneficiary: thirdParty.ethAddress, + }; + const command = generateNominateCommand(nominateParameter, receiver.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); } @@ -90,26 +124,26 @@ export const nominate = async (): Promise => { //"should not be able to nominate non-existent token" { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", tokenRegistry: tokenRegistryAddress, newBeneficiary: receiver.ethAddress, }; - const command = generateNominateCommand(transferHolder, owner.privateKey); + const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); } //"should not be able to nominate non-existent token registry" { - const transferHolder: TitleEscrowNominateBeneficiaryCommand = { + const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", tokenRegistry: "0x0000000000000000000000000000000000000000", newBeneficiary: receiver.ethAddress, }; - const command = generateNominateCommand(transferHolder, owner.privateKey); + const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); checkFailure(results, "null"); } diff --git a/src/e2e/reject-surrender.e2e.ts b/src/e2e/reject-surrender.e2e.ts index a1de39d8..94bc47ed 100644 --- a/src/e2e/reject-surrender.e2e.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -1,9 +1,9 @@ // import { deployTokenRegistry, mintSurrenderToken } from "./utils/utils"; import { run } from "./utils/shell"; -import { BurnAddress, EmptyTokenID, network, owner } from "./utils/constants"; +import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from "./utils/constants"; import { generateRejectSurrenderCommand } from "./utils/commands"; -import { checkFailure, deployTokenRegistry, mintSurrenderToken } from "./utils/bootstrap"; -import { checkSurrenderRejectSuccess } from "./utils/bootstrap"; +import { checkFailure, deployTokenRegistry, mintSurrenderToken, mintTokenRegistry } from "./utils/helpers"; +import { checkSurrenderRejectSuccess } from "./utils/helpers"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; @@ -11,10 +11,9 @@ export const rejectSurrender = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const defaultTitleEscrow = { + ...defaultRunParameters, beneficiary: owner.ethAddress, holder: owner.ethAddress, - network: network, - dryRun: false, }; //"should be able to reject surrender title-escrow on token-registry" @@ -53,4 +52,26 @@ export const rejectSurrender = async (): Promise => { const results = run(command); checkFailure(results, "null"); } + + //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" + { + const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand( + { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, + receiver.privateKey + ); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + //"should not be able to accept un-surrendered title-escrow on token-registry" + { + const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const command = generateRejectSurrenderCommand( + { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, + owner.privateKey + ); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } }; diff --git a/src/e2e/surrender.e2e.ts b/src/e2e/surrender.e2e.ts index 8f8fd6c4..2f4ab97f 100644 --- a/src/e2e/surrender.e2e.ts +++ b/src/e2e/surrender.e2e.ts @@ -4,7 +4,14 @@ import { BaseTitleEscrowCommand } from "../commands/title-escrow/title-escrow-co import { generateSurrenderCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; -import { deployTokenRegistry, mintTokenRegistry, checkSurrenderSuccess, checkFailure } from "./utils/bootstrap"; +import { + deployTokenRegistry, + mintTokenRegistry, + checkSurrenderSuccess, + checkFailure, + changeHolderToken, + nominateAndEndorseBeneficiary, +} from "./utils/helpers"; const defaultTitleEscrow = { ...defaultRunParameters, @@ -15,6 +22,7 @@ const defaultTitleEscrow = { export const surrender = async (): Promise => { const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + // "should be able to surrender title-escrow" { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); @@ -51,6 +59,7 @@ export const surrender = async (): Promise => { } } + // "Should not be able to surrender unowned title-escrow" { const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); @@ -62,20 +71,49 @@ export const surrender = async (): Promise => { const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); checkFailure(results, "missing revert data in call exception"); - const signer = await getSigner(surrenderTitleEscrow.network, owner.privateKey); - const titleEscrowOwner: string = await retrieveTitleEscrowOwner( - signer, - surrenderTitleEscrow.tokenRegistry, - surrenderTitleEscrow.tokenId - ); - if (isAddress(titleEscrowOwner) !== true) { - throw new Error(`(isAddress(titleEscrowOwner) !== true);`); - } - if (titleEscrowOwner === surrenderTitleEscrow.tokenRegistry) { - throw new Error(`(titleEscrowOwner === surrenderTitleEscrow.tokenRegistry);`); - } } + // "Should not be able to surrender title-escrow as beneficiary" + { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry, + tokenId, + }; + nominateAndEndorseBeneficiary(owner.privateKey, { + ...defaultTitleEscrow, + tokenId, + tokenRegistry, + newBeneficiary: receiver.ethAddress, + }); + const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + // "Should not be able to surrender title-escrow as holder" + { + const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + + const surrenderTitleEscrow: BaseTitleEscrowCommand = { + ...defaultTitleEscrow, + tokenRegistry, + tokenId, + }; + changeHolderToken(owner.privateKey, { + ...defaultTitleEscrow, + tokenId, + tokenRegistry, + newHolder: receiver.ethAddress, + }); + const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); + const results = run(command); + checkFailure(results, "missing revert data in call exception"); + } + + // "Should not be able to surrender invalid title-escrow" { const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); @@ -89,6 +127,7 @@ export const surrender = async (): Promise => { checkFailure(results, "missing revert data in call exception"); } + // "Should not be able to surrender invalid token-registry" { const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); diff --git a/src/e2e/utils/bootstrap/accept-surrender.ts b/src/e2e/utils/bootstrap/accept-surrender.ts deleted file mode 100644 index cf2043ef..00000000 --- a/src/e2e/utils/bootstrap/accept-surrender.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { EndStatus, TokenIdLength } from "../constants"; -import { extractStatus } from "../shell"; -import { isTokenId } from "../token-management"; - -export const checkSurrenderAcceptSuccess = (results: string): { tokenId: string } => { - const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); - - const isValidTokenId = isTokenId(tokenId); - - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - tokenId, - }; -}; diff --git a/src/e2e/utils/bootstrap/endorse-transfer.ts b/src/e2e/utils/bootstrap/endorse-transfer.ts deleted file mode 100644 index e8eadcc4..00000000 --- a/src/e2e/utils/bootstrap/endorse-transfer.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { isAddress } from "web3-utils"; -import { AddressLength, EndStatus, TokenIdLength } from "../constants"; -import { extractStatus } from "../shell"; -import { isTokenId } from "../token-management"; - -export const checkEndorseTransfer = (results: string): { beneficiary: string; tokenId: string } => { - const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); - if (statusLine.length <= 0) throw new Error("Minting failed"); - const titleEscrowAddressLine = statusLine[0].lineContent; - const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); - const beneficiary = titleEscrowAddressLine.substring(177, 177 + AddressLength); - - const beneficiaryIsAddress = isAddress(beneficiary); - const isValidTokenId = isTokenId(tokenId); - - if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); - if (!isValidTokenId) throw new Error("Invalid token id"); - - return { - beneficiary, - tokenId, - }; -}; diff --git a/src/e2e/utils/constants.ts b/src/e2e/utils/constants.ts index e32e45ff..047e866a 100644 --- a/src/e2e/utils/constants.ts +++ b/src/e2e/utils/constants.ts @@ -2,6 +2,9 @@ import { constants } from "@govtechsg/token-registry"; export const { contractAddress } = constants; +export const silent = true; +export const verbose = false; + export const network = "local"; export const chainId = 1337; export const forkedNetwork = 5; @@ -13,16 +16,19 @@ export const EmptyTokenID = "0x0000000000000000000000000000000000000000000000000 export const owner = { ethAddress: "0xe0A71284EF59483795053266CB796B65E48B5124", - publicKey: "0x02de2454a05cdb55780b85c04128233e31ac9179235607e4d6fa0c6b38140fb51a", privateKey: "0xe82294532bcfcd8e0763ee5cef194f36f00396be59b94fb418f5f8d83140d9a7", }; export const receiver = { ethAddress: "0xcDFAcbb428DD30ddf6d99875dcad04CbEFcd6E60", - publicKey: "0x0396762cb3d373ddab0685bbd5e45ccaf7481d8deb5b75ab38704fba089abed629", privateKey: "0xc58c1ff75001afdca8cecb61b47f36964febe4188b8f7b26252286ecae5a8879", }; +export const thirdParty = { + ethAddress: "0x391aFf3942857a10958425FebF1fC1938D9F5AE7", + privateKey: "0x3760fb287bee810607433485cfa3fc665c2d682a1816991dccce645b096ae19a", +}; + export const creators = { titleEscrowFactory: contractAddress.TitleEscrowFactory[forkedNetwork], deployer: contractAddress.Deployer[forkedNetwork], @@ -39,8 +45,6 @@ export const AddressLength = 42; export type EndStatusType = typeof EndStatus[keyof typeof EndStatus]; -export const silent = true; -export const verbose = false; export const defaultRunParameters = { network: network, dryRun: false, diff --git a/src/e2e/utils/helpers/accept-surrender.ts b/src/e2e/utils/helpers/accept-surrender.ts new file mode 100644 index 00000000..8c43751e --- /dev/null +++ b/src/e2e/utils/helpers/accept-surrender.ts @@ -0,0 +1,41 @@ +import { BaseTitleEscrowCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { generateAcceptSurrenderCommand } from "../commands"; +import { defaultRunParameters, EndStatus, TokenIdLength } from "../constants"; +import { extractStatus, run } from "../shell"; +import { isTokenId } from "../token-management"; +import { mintSurrenderToken, surrenderToken } from "./surrender"; + +export const mintBurntToken = ( + privateKey: string, + tokenRegistryAddress?: string +): { tokenId: string; tokenRegistry: string } => { + const { tokenId, tokenRegistry } = mintSurrenderToken(privateKey, tokenRegistryAddress); + burnSurrenderedToken(privateKey, { tokenRegistry, tokenId, ...defaultRunParameters }); + return { tokenId, tokenRegistry }; +}; + +export const burnSurrenderedToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { + const command = generateAcceptSurrenderCommand(acceptSurrender, privateKey); + const results = run(command); + checkSurrenderAcceptSuccess(results); +}; + +export const burnToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { + surrenderToken(privateKey, acceptSurrender); + burnSurrenderedToken(privateKey, acceptSurrender); +}; + +export const checkSurrenderAcceptSuccess = (results: string): { tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(55, 55 + TokenIdLength); + + const isValidTokenId = isTokenId(tokenId); + + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + tokenId, + }; +}; diff --git a/src/e2e/utils/bootstrap/change-holder.ts b/src/e2e/utils/helpers/change-holder.ts similarity index 91% rename from src/e2e/utils/bootstrap/change-holder.ts rename to src/e2e/utils/helpers/change-holder.ts index 0c8f4498..72a1749b 100644 --- a/src/e2e/utils/bootstrap/change-holder.ts +++ b/src/e2e/utils/helpers/change-holder.ts @@ -1,14 +1,13 @@ import { isAddress } from "web3-utils"; import { TitleEscrowTransferHolderCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { generateChangeHolderCommand } from "../commands"; -import { AddressLength, EndStatus, network, receiver, TokenIdLength } from "../constants"; +import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; export const defaultTransferHolder = { + ...defaultRunParameters, newHolder: receiver.ethAddress, - network: network, - dryRun: false, }; export const checkChangeHolderSuccess = (results: string): { newHolder: string; tokenId: string } => { diff --git a/src/e2e/utils/bootstrap/common.ts b/src/e2e/utils/helpers/common.ts similarity index 100% rename from src/e2e/utils/bootstrap/common.ts rename to src/e2e/utils/helpers/common.ts diff --git a/src/e2e/utils/bootstrap/deploy.ts b/src/e2e/utils/helpers/deploy.ts similarity index 100% rename from src/e2e/utils/bootstrap/deploy.ts rename to src/e2e/utils/helpers/deploy.ts diff --git a/src/e2e/utils/helpers/endorse-beneficiary.ts b/src/e2e/utils/helpers/endorse-beneficiary.ts new file mode 100644 index 00000000..342f13dd --- /dev/null +++ b/src/e2e/utils/helpers/endorse-beneficiary.ts @@ -0,0 +1,48 @@ +import { isAddress } from "web3-utils"; +import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; +import { generateEndorseTransferOwnerCommand } from "../commands"; +import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength } from "../constants"; +import { extractStatus, run } from "../shell"; +import { isTokenId } from "../token-management"; +import { nominateToken } from "./nominate"; + +export const defaultTransferBeneficiary = { + ...defaultRunParameters, + newBeneficiary: receiver.ethAddress, +}; + +export const nominateAndEndorseBeneficiary = ( + privateKey: string, + transferBeneficiary: TitleEscrowNominateBeneficiaryCommand +): void => { + nominateToken(privateKey, transferBeneficiary); + endorseBeneficiary(privateKey, transferBeneficiary); +}; + +export const endorseBeneficiary = ( + privateKey: string, + transferBeneficiary: TitleEscrowNominateBeneficiaryCommand +): void => { + const command = generateEndorseTransferOwnerCommand(transferBeneficiary, privateKey); + const results = run(command); + checkEndorseBeneficiary(results); +}; + +export const checkEndorseBeneficiary = (results: string): { beneficiary: string; tokenId: string } => { + const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); + if (statusLine.length <= 0) throw new Error("Minting failed"); + const titleEscrowAddressLine = statusLine[0].lineContent; + const tokenId = titleEscrowAddressLine.substring(43, 43 + TokenIdLength); + const beneficiary = titleEscrowAddressLine.substring(177, 177 + AddressLength); + + const beneficiaryIsAddress = isAddress(beneficiary); + const isValidTokenId = isTokenId(tokenId); + + if (!beneficiaryIsAddress) throw new Error("Invalid receipient address"); + if (!isValidTokenId) throw new Error("Invalid token id"); + + return { + beneficiary, + tokenId, + }; +}; diff --git a/src/e2e/utils/bootstrap/endorse-owners.ts b/src/e2e/utils/helpers/endorse-owners.ts similarity index 100% rename from src/e2e/utils/bootstrap/endorse-owners.ts rename to src/e2e/utils/helpers/endorse-owners.ts diff --git a/src/e2e/utils/bootstrap/index.ts b/src/e2e/utils/helpers/index.ts similarity index 87% rename from src/e2e/utils/bootstrap/index.ts rename to src/e2e/utils/helpers/index.ts index 518059ed..241fe517 100644 --- a/src/e2e/utils/bootstrap/index.ts +++ b/src/e2e/utils/helpers/index.ts @@ -2,7 +2,7 @@ export * from "./common"; export * from "./deploy"; export * from "./mint"; export * from "./nominate"; -export * from "./endorse-transfer"; +export * from "./endorse-beneficiary"; export * from "./endorse-owners"; export * from "./change-holder"; export * from "./surrender"; diff --git a/src/e2e/utils/bootstrap/mint.ts b/src/e2e/utils/helpers/mint.ts similarity index 100% rename from src/e2e/utils/bootstrap/mint.ts rename to src/e2e/utils/helpers/mint.ts diff --git a/src/e2e/utils/bootstrap/nominate.ts b/src/e2e/utils/helpers/nominate.ts similarity index 100% rename from src/e2e/utils/bootstrap/nominate.ts rename to src/e2e/utils/helpers/nominate.ts diff --git a/src/e2e/utils/bootstrap/reject-surrender.ts b/src/e2e/utils/helpers/reject-surrender.ts similarity index 100% rename from src/e2e/utils/bootstrap/reject-surrender.ts rename to src/e2e/utils/helpers/reject-surrender.ts diff --git a/src/e2e/utils/bootstrap/surrender.ts b/src/e2e/utils/helpers/surrender.ts similarity index 100% rename from src/e2e/utils/bootstrap/surrender.ts rename to src/e2e/utils/helpers/surrender.ts diff --git a/tsconfig.prod.json b/tsconfig.prod.json index 3c455194..ec95fd2f 100644 --- a/tsconfig.prod.json +++ b/tsconfig.prod.json @@ -1,6 +1,7 @@ { "extends": "./tsconfig", "exclude": [ - "**/*.test.ts" + "**/*.test.ts", + "**/*.e2e.ts" ] } From a5973f2b165091e90c3a33b755bbde4a21f93785 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 19 Jan 2023 01:11:38 +0800 Subject: [PATCH 56/63] fix: lint --- package-lock.json | 458 ------------------ package.json | 1 - .../title-escrow/accept-surrendered.ts | 1 - src/e2e/all.ts | 2 +- 4 files changed, 1 insertion(+), 461 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5c59f67c..c7883073 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1638,464 +1638,6 @@ "@ethersproject/transactions": "^5.4.0" } }, - "@ethersproject/experimental": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/experimental/-/experimental-5.7.0.tgz", - "integrity": "sha512-DWvhuw7Dg8JPyhMbh/CNYOwsTLjXRx/HGkacIL5rBocG8jJC0kmixwoK/J3YblO4vtcyBLMa+sV74RJZK2iyHg==", - "dev": true, - "requires": { - "@ethersproject/web": "^5.7.0", - "ethers": "^5.7.0", - "scrypt-js": "3.0.1" - }, - "dependencies": { - "@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", - "dev": true, - "requires": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" - } - }, - "@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" - } - }, - "@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0" - } - }, - "@ethersproject/basex": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", - "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/properties": "^5.7.0" - } - }, - "@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "bn.js": "^5.2.1" - } - }, - "@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.7.0" - } - }, - "@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", - "dev": true, - "requires": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" - } - }, - "@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", - "dev": true, - "requires": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "aes-js": "3.0.0", - "scrypt-js": "3.0.1" - } - }, - "@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "js-sha3": "0.8.0" - } - }, - "@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", - "dev": true - }, - "@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" - } - }, - "@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", - "dev": true, - "requires": { - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/providers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", - "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0", - "bech32": "1.1.4", - "ws": "7.4.6" - } - }, - "@ethersproject/random": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", - "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "hash.js": "1.1.7" - } - }, - "@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "bn.js": "^5.2.1", - "elliptic": "6.5.4", - "hash.js": "1.1.7" - } - }, - "@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", - "dev": true, - "requires": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" - } - }, - "@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", - "dev": true, - "requires": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" - } - }, - "@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", - "dev": true, - "requires": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" - } - }, - "@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", - "dev": true, - "requires": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", - "dev": true, - "requires": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" - } - }, - "bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", - "dev": true - }, - "ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", - "dev": true, - "requires": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" - } - } - } - }, "@ethersproject/hash": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.4.0.tgz", diff --git a/package.json b/package.json index 965e4c1c..8c617ceb 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "@commitlint/cli": "^12.1.4", "@commitlint/config-conventional": "^12.1.4", "@commitlint/prompt": "^12.1.4", - "@ethersproject/experimental": "^5.7.0", "@ls-age/commitlint-circle": "1.0.0", "@semantic-release/exec": "^5.0.0", "@types/debug": "4.1.5", diff --git a/src/commands/title-escrow/accept-surrendered.ts b/src/commands/title-escrow/accept-surrendered.ts index 64af790e..2c8a426e 100644 --- a/src/commands/title-escrow/accept-surrendered.ts +++ b/src/commands/title-escrow/accept-surrendered.ts @@ -35,7 +35,6 @@ export const handler = async (args: TitleEscrowSurrenderDocumentCommand): Promis try { info(`Accepting surrendered document`); const transaction = await acceptSurrendered(args); - console.log(transaction); success(`Surrendered transferable record with hash ${args.tokenId} has been accepted.`); info(`Find more details at ${getEtherscanAddress({ network: args.network })}/tx/${transaction.transactionHash}`); } catch (e) { diff --git a/src/e2e/all.ts b/src/e2e/all.ts index e9116aa9..49f05058 100644 --- a/src/e2e/all.ts +++ b/src/e2e/all.ts @@ -10,7 +10,7 @@ import { endorseChangeOwner } from "./endorse-change-owner.e2e"; const awaitForDuration = async (runFunction: () => void): Promise => { await runFunction(); - console.log(runFunction.name) + console.log(runFunction.name); }; awaitForDuration(deployDocumentStore); From c2cda9e218e185de9fe219352b13433dd9ad7d53 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Thu, 19 Jan 2023 01:25:19 +0800 Subject: [PATCH 57/63] fix: restore jest serial --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7dd24d25..ff0ba4dc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ jobs: command: npm run lint - run: name: test - command: npm run test -- + command: npm run test -- --runInBand - run: name: e2e command: npm run e2e From 2e5c66a121ffdee9bc0c91085bd793f482297e25 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 27 Jan 2023 22:50:20 +0800 Subject: [PATCH 58/63] feat: validation --- src/e2e/accept-surrender.e2e.ts | 8 +- src/e2e/all.ts | 2 +- src/e2e/change-holder.e2e.ts | 18 +- src/e2e/endorse-change-owner.e2e.ts | 18 +- src/e2e/endorse-transfer.e2e.ts | 24 +- src/e2e/mint.e2e.ts | 18 +- src/e2e/nominate.e2e.ts | 13 +- src/e2e/reject-surrender.e2e.ts | 8 +- src/e2e/surrender.e2e.ts | 10 +- .../title-escrow/acceptSurrendered.ts | 6 +- .../endorseNominatedBeneficiary.ts | 5 +- src/implementations/title-escrow/helpers.ts | 243 ++++++++++++++++-- .../title-escrow/nominateBeneficiary.ts | 5 +- .../title-escrow/rejectSurrendered.ts | 3 +- .../title-escrow/surrenderDocument.ts | 5 +- .../title-escrow/transferHolder.ts | 8 +- .../title-escrow/transferOwners.ts | 3 +- 17 files changed, 279 insertions(+), 118 deletions(-) diff --git a/src/e2e/accept-surrender.e2e.ts b/src/e2e/accept-surrender.e2e.ts index 541323e3..48d35bde 100644 --- a/src/e2e/accept-surrender.e2e.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -42,7 +42,7 @@ export const acceptSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Unminted Token"); } //"should not be able to accept surrender title-escrow on invalid token-registry" @@ -53,7 +53,7 @@ export const acceptSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" @@ -64,7 +64,7 @@ export const acceptSurrender = async (): Promise => { receiver.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to accept un-surrendered title-escrow on token-registry" @@ -75,6 +75,6 @@ export const acceptSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has not been surrendered"); } }; diff --git a/src/e2e/all.ts b/src/e2e/all.ts index 49f05058..ad8bdebf 100644 --- a/src/e2e/all.ts +++ b/src/e2e/all.ts @@ -24,5 +24,5 @@ awaitForDuration(acceptSurrender); awaitForDuration(nominate); awaitForDuration(changeHolder); -awaitForDuration(endorseTransfer); awaitForDuration(endorseChangeOwner); +awaitForDuration(endorseTransfer); \ No newline at end of file diff --git a/src/e2e/change-holder.e2e.ts b/src/e2e/change-holder.e2e.ts index e7ad11b0..1ceef336 100644 --- a/src/e2e/change-holder.e2e.ts +++ b/src/e2e/change-holder.e2e.ts @@ -79,7 +79,7 @@ export const changeHolder = async (): Promise => { }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Unminted Token"); } //should not be able to transfer holder of title-escrow on invalid token-registry" @@ -92,7 +92,7 @@ export const changeHolder = async (): Promise => { }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //beneficiary should not be able to transfer holder of title-escrow" @@ -117,14 +117,11 @@ export const changeHolder = async (): Promise => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); // Beneficiary attempts to transfer Holder without permission const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } - //should not be able to transfer holder of surrendered title-escrow" + // should not be able to transfer holder of surrendered title-escrow" { - console.info("Skipped Test"); - console.info("should not be able to transfer holder of surrendered title-escrow"); - return; const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { ...defaultTransferHolder, @@ -134,14 +131,11 @@ export const changeHolder = async (): Promise => { }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has already been surrendered"); } //should not be able to transfer holder of burnt title-escrow" { - console.info("Skipped Test"); - console.info("should not be able to transfer holder of burnt title-escrow"); - return; const { tokenRegistry, tokenId } = mintBurntToken(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { ...defaultTransferHolder, @@ -151,6 +145,6 @@ export const changeHolder = async (): Promise => { }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has already been shredded"); } }; diff --git a/src/e2e/endorse-change-owner.e2e.ts b/src/e2e/endorse-change-owner.e2e.ts index 9f7c447d..d79df33d 100644 --- a/src/e2e/endorse-change-owner.e2e.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -76,7 +76,7 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse change owner from nominee title-escrow on token-registry" @@ -90,7 +90,7 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse surrendered title-escrow on token-registry" @@ -109,7 +109,7 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has already been surrendered"); } //"should not be able to endorse burnt title-escrow on token-registry" @@ -128,14 +128,11 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, "Title Escrow has already been shredded"); } //"should not be able to endorse change owner on un-nominated title-escrow" { - console.info("Skipped Test"); - console.info("should not be able to endorse change owner on un-nominated title-escrow"); - return; const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { tokenId: tokenId, @@ -144,14 +141,11 @@ export const endorseChangeOwner = async (): Promise => { }; const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); - checkFailure(results, ""); + checkFailure(results, "Destination wallet has not been nominated"); } //"should not be able to endorse change owner from holder title-escrow on token-registry" { - console.info("Skipped Test"); - console.info("should not be able to endorse change owner from holder title-escrow on token-registry"); - return; const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); changeHolderToken(owner.privateKey, { ...defaultTransferOwners, @@ -167,6 +161,6 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, thirdParty.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } }; diff --git a/src/e2e/endorse-transfer.e2e.ts b/src/e2e/endorse-transfer.e2e.ts index 8fa96b23..94b798da 100644 --- a/src/e2e/endorse-transfer.e2e.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -61,7 +61,7 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse transfer from nominee title-escrow on token-registry" @@ -75,7 +75,7 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse surrendered title-escrow on token-registry" @@ -95,10 +95,10 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has already been surrendered"); } - //"should not be able to endorse burnt title-escrow on token-registry" + // "should not be able to endorse burnt title-escrow on token-registry" { const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); burnToken(owner.privateKey, { @@ -115,14 +115,11 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, "Title Escrow has already been shredded"); } - ("should not be able to endorse un-nominated title-escrow on token-registry"); + // "should not be able to endorse un-nominated title-escrow on token-registry"; { - console.info("Skipped Test"); - console.info("should not be able to endorse un-nominated title-escrow on token-registry"); - return; const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { ...defaultTransferBeneficiary, @@ -133,14 +130,11 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Destination wallet has not been nominated"); } - //"should not be able to endorse transfer from holder title-escrow on token-registry" + // "should not be able to endorse transfer from holder title-escrow on token-registry" { - console.info("Skipped Test"); - console.info("should not be able to endorse transfer from holder title-escrow on token-registry"); - return; const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); changeHolderToken(owner.privateKey, { ...defaultTransferBeneficiary, @@ -156,6 +150,6 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, thirdParty.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } }; diff --git a/src/e2e/mint.e2e.ts b/src/e2e/mint.e2e.ts index 27b4b02c..90beed9a 100644 --- a/src/e2e/mint.e2e.ts +++ b/src/e2e/mint.e2e.ts @@ -172,7 +172,7 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should fail with invalid beneficiary" @@ -204,20 +204,4 @@ export const mint = async (): Promise => { const results = run(command); checkFailure(results, "missing revert data in call exception"); } - - //"should fail with no funds" - { - const tokenId = generateTokenId(); - const titleEscrowParameter: TokenRegistryIssueCommand = { - ...defaultRunParameters, - address: tokenRegistryAddress, - tokenId: tokenId, - beneficiary: receiver.ethAddress, - holder: receiver.ethAddress, - network: "mainnet", - }; - const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); - const results = run(command); - checkFailure(results, "null"); - } }; diff --git a/src/e2e/nominate.e2e.ts b/src/e2e/nominate.e2e.ts index 1dc0b563..570d44e2 100644 --- a/src/e2e/nominate.e2e.ts +++ b/src/e2e/nominate.e2e.ts @@ -84,7 +84,7 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, "new beneficiary address is the same as the current beneficiary address"); + checkFailure(results, "Destination wallet already has the rights as beneficiary"); } //"should not be able to nominate unowned token" @@ -98,7 +98,7 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to nominate token as holder" @@ -118,12 +118,11 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to nominate non-existent token" { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -132,10 +131,10 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Unminted Token"); } - //"should not be able to nominate non-existent token registry" + // "should not be able to nominate non-existent token registry" { const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { ...defaultNominateBeneficiary, @@ -145,6 +144,6 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } }; diff --git a/src/e2e/reject-surrender.e2e.ts b/src/e2e/reject-surrender.e2e.ts index 94bc47ed..5fca3e35 100644 --- a/src/e2e/reject-surrender.e2e.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -39,7 +39,7 @@ export const rejectSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Unminted Token"); } //"should not be able to reject surrender title-escrow on invalid token-registry" @@ -50,7 +50,7 @@ export const rejectSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" @@ -61,7 +61,7 @@ export const rejectSurrender = async (): Promise => { receiver.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to accept un-surrendered title-escrow on token-registry" @@ -72,6 +72,6 @@ export const rejectSurrender = async (): Promise => { owner.privateKey ); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Title Escrow has not been surrendered"); } }; diff --git a/src/e2e/surrender.e2e.ts b/src/e2e/surrender.e2e.ts index 2f4ab97f..921593db 100644 --- a/src/e2e/surrender.e2e.ts +++ b/src/e2e/surrender.e2e.ts @@ -70,7 +70,7 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender title-escrow as beneficiary" @@ -90,7 +90,7 @@ export const surrender = async (): Promise => { }); const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender title-escrow as holder" @@ -110,7 +110,7 @@ export const surrender = async (): Promise => { }); const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender invalid title-escrow" @@ -124,7 +124,7 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkFailure(results, "Unminted Token"); } // "Should not be able to surrender invalid token-registry" @@ -138,6 +138,6 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "null"); + checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); } }; diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index 9cb73dd4..ccd57cdb 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -4,7 +4,7 @@ import { getWalletOrSigner } from "../utils/wallet"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { connectToTokenRegistry } from "./helpers"; +import { connectToTokenRegistry, validateSurrenderMethod } from "./helpers"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -17,6 +17,7 @@ export const acceptSurrendered = async ({ }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const tokenRegistryInstance = await connectToTokenRegistry({ address, wallet }); + await validateSurrenderMethod({tokenRegistry: tokenRegistryInstance, tokenId, wallet}) if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), @@ -24,11 +25,8 @@ export const acceptSurrendered = async ({ }); process.exit(0); } - signale.await(`Sending transaction to pool`); - console.log(await tokenRegistryInstance.callStatic.burn(tokenId)); const transaction = await tokenRegistryInstance.burn(tokenId); - console.log(transaction); trace(`Tx hash: ${transaction.hash}`); trace(`Block Number: ${transaction.blockNumber}`); signale.await(`Waiting for transaction ${transaction.hash} to be mined`); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts index df952f28..4bb031d1 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.ts @@ -1,7 +1,7 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow, validateNominateBeneficiary } from "./helpers"; +import { connectToTitleEscrow, validateTransferBeneficiary } from "./helpers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; @@ -23,7 +23,8 @@ export const endorseNominatedBeneficiary = async ({ const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); const nominatedBeneficiary = newBeneficiary; - await validateNominateBeneficiary({ beneficiaryNominee: nominatedBeneficiary, titleEscrow }); + const walletAddress = await wallet.getAddress(); + await validateTransferBeneficiary({ to: nominatedBeneficiary, titleEscrow, walletAddress }); if (dryRun) { await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.transferBeneficiary(nominatedBeneficiary), diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index ec22278a..fd46ebca 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -1,77 +1,223 @@ + import { TitleEscrow, + TitleEscrowFactory, + TitleEscrowFactory__factory, TitleEscrow__factory, TradeTrustToken, TradeTrustToken__factory, } from "@govtechsg/token-registry/contracts"; -import { Wallet, constants } from "ethers"; +import { Wallet, constants, Contract } from "ethers"; import signale from "signale"; import { ConnectedSigner } from "../utils/wallet"; +export const BurnAddress = "0x000000000000000000000000000000000000dEaD"; + interface ConnectToTitleEscrowArgs { tokenId: string; address: string; - wallet: Wallet | ConnectedSigner; + wallet: UserWallet; } interface ConnectToTokenRegistryArgs { address: string; - wallet: Wallet | ConnectedSigner; + wallet: UserWallet; +} + +type UserWallet = Wallet | ConnectedSigner; + +export const assertAddressIsSmartContract = async ( + address: string, + account: Wallet | ConnectedSigner +): Promise => { + const code = await account.provider.getCode(address); + const isContract = code !== "0x" && code !== "0x0"; // Ganache uses 0x0 instead + if(!isContract) throw new Error(`Address ${address} is not a valid Contract`); +}; + + +interface ERC165Contract extends Contract { + supportsInterface: (interfaceId: string) => Promise; +} + +export const supportsInterface = async ( + contractInstance: ERC165Contract, + interfaceId: string +): Promise => { + let isSameInterfaceType; + try { + isSameInterfaceType = await contractInstance.supportsInterface(interfaceId); + return isSameInterfaceType; + } catch (e) { + if (e instanceof Error) { + if (e.message.includes("revert") || e.message.includes("cannot estimate gas")) { + return false; + } + } + } +}; + +const isJsonString = (jsonString: string) => { + try { + JSON.parse(jsonString); + } catch (e) { + return false; + } + return true; +} + +export const getTitleEscrowAddress = async (tokenRegistry: TradeTrustToken, tokenId: string) => { + try{ + return await tokenRegistry.ownerOf(tokenId); + } catch (e: any) { + if(e?.code === "CALL_EXCEPTION" && e?.reason === "missing revert data in call exception" && e?.data === "0x"){ + const providerError = e?.error; + if(providerError?.code === "SERVER_ERROR" && providerError?.reason === "processing response error"){ + if(isJsonString(providerError?.body)){ + const VMError: any = JSON.parse(providerError?.body); + if(VMError?.error?.message === "VM Exception while processing transaction: revert ERC721: owner query for nonexistent token"){ + throw new Error(`Unminted Token`); + } + } + } + } + throw e; + } } + +export const connectToTitleEscrowAddress = async ( + address: string, + wallet: UserWallet, +): Promise => { + await assertAddressIsSmartContract(address, wallet); + const titleEscrow = TitleEscrow__factory.connect(address, wallet); + // const isTitleEscrow = await supportsInterface(titleEscrow, "0x8a198f04") + // if(!isTitleEscrow) throw new Error(`Address ${titleEscrowAddress} is not a supported escrow contract`) + return titleEscrow; +}; + export const connectToTitleEscrow = async ({ tokenId, address, wallet, }: ConnectToTitleEscrowArgs): Promise => { + await assertAddressIsSmartContract(address, wallet); const tokenRegistry: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); - const titleEscrowAddress = await tokenRegistry.ownerOf(tokenId); - return TitleEscrow__factory.connect(titleEscrowAddress, wallet); + const titleEscrowAddress = await getTitleEscrowAddress(tokenRegistry, tokenId); + if (titleEscrowAddress === BurnAddress) throw new Error(`Title Escrow has already been shredded`); + if (titleEscrowAddress === address) throw new Error(`Title Escrow has already been surrendered`); + await assertAddressIsSmartContract(titleEscrowAddress, wallet); + const titleEscrow = connectToTitleEscrowAddress(titleEscrowAddress, wallet); + return titleEscrow; }; export const connectToTokenRegistry = async ({ address, wallet, }: ConnectToTokenRegistryArgs): Promise => { + await assertAddressIsSmartContract(address, wallet); const tokenRegistryInstance: TradeTrustToken = await TradeTrustToken__factory.connect(address, wallet); + // const isTokenRegistry = await supportsInterface(tokenRegistryInstance, "0x8a198f04") + // if(!isTokenRegistry) throw new Error(`Address ${address} is not a supported token registry contract`) await tokenRegistryInstance.callStatic.genesis(); return tokenRegistryInstance; }; +// State Checks + +export const validateActiveTitleEscrow = async (titleEscrow: TitleEscrow) => { + const activeEscrow = await titleEscrow.active(); + if (!activeEscrow) throw new Error(`Inactive Title Escrow`); +}; + +// Permissions check + +export const EscrowRoles = { + beneficiary: "beneficiary", + holder: "holder", + nominee: "nominee", +} as const; + +export type EscrowRolesType = typeof EscrowRoles[keyof typeof EscrowRoles]; + +const hasTransferRights = async (titleEscrow: TitleEscrow, walletAddress: string, expectedPermissions: string[]) => { + for (const roles of expectedPermissions) { + let rightsHolder = ""; + let results = true; + switch (roles) { + case EscrowRoles.beneficiary: + rightsHolder = await titleEscrow.beneficiary(); + results = results && (rightsHolder === walletAddress); + break; + case EscrowRoles.holder: + rightsHolder = await titleEscrow.holder(); + results = results && (rightsHolder === walletAddress); + break; + case EscrowRoles.nominee: + rightsHolder = await titleEscrow.nominee(); + results = results && (rightsHolder === walletAddress); + break; + default: + throw new Error(`Unimplemented role: ${roles}`); + } + if(!results) return false; + } + return true; +}; + +interface validateTransferArgs { + titleEscrow: TitleEscrow; + to: string; + walletAddress: string; +} + +export const validateTransferHolder = async ({ titleEscrow, to, walletAddress }: validateTransferArgs) => { + await validateActiveTitleEscrow(titleEscrow); + const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder]); + if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); + const isHolder = await hasTransferRights(titleEscrow, to, [EscrowRoles.holder]); + if (isHolder) throw new Error(`Destination wallet already has the rights of holdership`); +}; + +export const validateTransferBeneficiary = async ({ titleEscrow, to, walletAddress }: validateTransferArgs) => { + await validateActiveTitleEscrow(titleEscrow); + const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.beneficiary, EscrowRoles.holder]); + if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); + const isBeneficiary = await hasTransferRights(titleEscrow, to, [EscrowRoles.beneficiary]); + if (isBeneficiary) throw new Error(`Destination wallet already has the rights as beneficiary`); + const isNominated = await hasTransferRights(titleEscrow, to, [EscrowRoles.nominee]); + if (!isNominated) throw new Error(`Destination wallet has not been nominated`); +}; + +export const validateNominateBeneficiary = async ({ + walletAddress, + to, + titleEscrow, +}: validateTransferArgs): Promise => { + await validateActiveTitleEscrow(titleEscrow); + const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.beneficiary]); + if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); + const isBeneficiary = await hasTransferRights(titleEscrow, to, [EscrowRoles.beneficiary]); + if (isBeneficiary) throw new Error(`Destination wallet already has the rights as beneficiary`); +}; + interface validateEndorseChangeOwnerArgs { newHolder: string; newOwner: string; titleEscrow: TitleEscrow; + walletAddress: string; } export const validateEndorseChangeOwner = async ({ newHolder, newOwner, titleEscrow, + walletAddress, }: validateEndorseChangeOwnerArgs): Promise => { - const beneficiary = await titleEscrow.beneficiary(); - const holder = await titleEscrow.holder(); - if (newOwner === beneficiary && newHolder === holder) { - const error = "new owner and new holder addresses are the same as the current owner and holder addresses"; - signale.error(error); - throw new Error(error); - } + await validateTransferHolder({ titleEscrow, to: newHolder, walletAddress }); + await validateTransferBeneficiary({ titleEscrow, to: newOwner, walletAddress }); }; -interface validateNominateBeneficiaryArgs { - beneficiaryNominee: string; - titleEscrow: TitleEscrow; -} -export const validateNominateBeneficiary = async ({ - beneficiaryNominee, - titleEscrow, -}: validateNominateBeneficiaryArgs): Promise => { - const beneficiary = await titleEscrow.beneficiary(); - if (beneficiaryNominee === beneficiary) { - const error = "new beneficiary address is the same as the current beneficiary address"; - signale.error(error); - throw new Error(error); - } -}; interface validateEndorseTransferOwnerArgs { approvedOwner: string | undefined; @@ -88,3 +234,46 @@ export const validateEndorseTransferOwner = ({ throw new Error(error); } }; + +interface validateSurrenderArgs { + titleEscrow: TitleEscrow, + walletAddress: string, +} + +interface validateAcceptSurrenderArgs { + tokenRegistry: TradeTrustToken, + tokenId: string, + wallet: UserWallet, +} + +export const validateSurrender = async ({ + titleEscrow, + walletAddress, +}: validateSurrenderArgs): Promise => { + const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder, EscrowRoles.beneficiary]); + if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); +}; + +export const connectToTitleEscrowFactory = async (tokenRegistry: TradeTrustToken, wallet: UserWallet): Promise => { + const titleEscrowFactoryAddress = await tokenRegistry.titleEscrowFactory(); + await assertAddressIsSmartContract(titleEscrowFactoryAddress, wallet) + const titleEscrowFactory = TitleEscrowFactory__factory.connect(titleEscrowFactoryAddress, wallet); + return titleEscrowFactory; +} + +export const validateSurrenderMethod = async ({ + tokenRegistry, + tokenId, + wallet, +}: validateAcceptSurrenderArgs): Promise => { + const ownerOfTitleEscrow = await getTitleEscrowAddress(tokenRegistry, tokenId); + if(ownerOfTitleEscrow !== tokenRegistry.address) throw new Error(`Title Escrow has not been surrendered`) + const titleEscrowFactory = await connectToTitleEscrowFactory(tokenRegistry, wallet); + // const isTitleEscrowFactory = await supportsInterface(validateAcceptSurrenderArgs, "?") + // if(!isTitleEscrowFactory) throw new Error(`Address ${address} is not a supported title escrow factory contract`) + const titleEscrowAddress = await titleEscrowFactory.getAddress(tokenRegistry.address, tokenId); + const walletAddress = await wallet.getAddress(); + const titleEscrow = await connectToTitleEscrowAddress(titleEscrowAddress, wallet); + const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder, EscrowRoles.beneficiary]); + if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); +}; \ No newline at end of file diff --git a/src/implementations/title-escrow/nominateBeneficiary.ts b/src/implementations/title-escrow/nominateBeneficiary.ts index 7bddd11b..a5f68a46 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.ts @@ -19,17 +19,16 @@ export const nominateBeneficiary = async ({ }: TitleEscrowNominateBeneficiaryCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); + const walletAddress = await wallet.getAddress(); + await validateNominateBeneficiary({ to: newBeneficiary, titleEscrow, walletAddress }); if (dryRun) { - await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.nominate(newBeneficiary), network, }); process.exit(0); } - signale.await(`Sending transaction to pool`); - await validateNominateBeneficiary({ beneficiaryNominee: newBeneficiary, titleEscrow }); await titleEscrow.callStatic.nominate(newBeneficiary); const transaction = await titleEscrow.nominate(newBeneficiary); trace(`Tx hash: ${transaction.hash}`); diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index de35e1a8..bc441c40 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -5,7 +5,7 @@ import { getWalletOrSigner } from "../utils/wallet"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; -import { connectToTokenRegistry } from "./helpers"; +import { connectToTokenRegistry, validateSurrenderMethod } from "./helpers"; const { trace } = getLogger("title-escrow:acceptSurrendered"); @@ -18,6 +18,7 @@ export const rejectSurrendered = async ({ }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const tokenRegistryInstance: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); + await validateSurrenderMethod({tokenRegistry: tokenRegistryInstance, tokenId, wallet}) if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index 00d62a00..b2186cf8 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -1,7 +1,7 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow } from "./helpers"; +import { connectToTitleEscrow, validateSurrender } from "./helpers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; import { TransactionReceipt } from "@ethersproject/providers"; @@ -17,7 +17,8 @@ export const surrenderDocument = async ({ }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - + const walletAddress = await wallet.getAddress(); + await validateSurrender({titleEscrow, walletAddress}) if (dryRun) { await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.surrender(), diff --git a/src/implementations/title-escrow/transferHolder.ts b/src/implementations/title-escrow/transferHolder.ts index aaa21687..86edc5f0 100644 --- a/src/implementations/title-escrow/transferHolder.ts +++ b/src/implementations/title-escrow/transferHolder.ts @@ -1,7 +1,7 @@ import signale from "signale"; import { getLogger } from "../../logger"; import { getWalletOrSigner } from "../utils/wallet"; -import { connectToTitleEscrow } from "./helpers"; +import { connectToTitleEscrow, validateTransferHolder } from "./helpers"; import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { dryRunMode } from "../utils/dryRun"; @@ -19,6 +19,12 @@ export const transferHolder = async ({ }: TitleEscrowTransferHolderCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); + const walletAddress = await wallet.getAddress(); + await validateTransferHolder({ + walletAddress, + titleEscrow, + to, + }); if (dryRun) { await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.transferHolder(to), diff --git a/src/implementations/title-escrow/transferOwners.ts b/src/implementations/title-escrow/transferOwners.ts index 2baf0393..33ca7d0c 100644 --- a/src/implementations/title-escrow/transferOwners.ts +++ b/src/implementations/title-escrow/transferOwners.ts @@ -20,7 +20,8 @@ export const transferOwners = async ({ }: TitleEscrowEndorseTransferOfOwnersCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); - await validateEndorseChangeOwners({ newHolder, newOwner, titleEscrow }); + const walletAddress = await wallet.getAddress(); + await validateEndorseChangeOwners({ newHolder, newOwner, titleEscrow, walletAddress }); if (dryRun) { await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.transferOwners(newOwner, newHolder), From a6639c5cdbe6849418a058333c9a6f60cff5c4c9 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Fri, 27 Jan 2023 22:56:24 +0800 Subject: [PATCH 59/63] fix: lint --- src/e2e/all.ts | 2 +- .../title-escrow/acceptSurrendered.ts | 2 +- src/implementations/title-escrow/helpers.ts | 100 ++++++++++-------- .../title-escrow/rejectSurrendered.ts | 2 +- .../title-escrow/surrenderDocument.ts | 2 +- 5 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/e2e/all.ts b/src/e2e/all.ts index ad8bdebf..a01b2945 100644 --- a/src/e2e/all.ts +++ b/src/e2e/all.ts @@ -25,4 +25,4 @@ awaitForDuration(acceptSurrender); awaitForDuration(nominate); awaitForDuration(changeHolder); awaitForDuration(endorseChangeOwner); -awaitForDuration(endorseTransfer); \ No newline at end of file +awaitForDuration(endorseTransfer); diff --git a/src/implementations/title-escrow/acceptSurrendered.ts b/src/implementations/title-escrow/acceptSurrendered.ts index ccd57cdb..62b0f596 100644 --- a/src/implementations/title-escrow/acceptSurrendered.ts +++ b/src/implementations/title-escrow/acceptSurrendered.ts @@ -17,7 +17,7 @@ export const acceptSurrendered = async ({ }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const tokenRegistryInstance = await connectToTokenRegistry({ address, wallet }); - await validateSurrenderMethod({tokenRegistry: tokenRegistryInstance, tokenId, wallet}) + await validateSurrenderMethod({ tokenRegistry: tokenRegistryInstance, tokenId, wallet }); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.burn(tokenId), diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index fd46ebca..6a432705 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -1,4 +1,3 @@ - import { TitleEscrow, TitleEscrowFactory, @@ -32,10 +31,9 @@ export const assertAddressIsSmartContract = async ( ): Promise => { const code = await account.provider.getCode(address); const isContract = code !== "0x" && code !== "0x0"; // Ganache uses 0x0 instead - if(!isContract) throw new Error(`Address ${address} is not a valid Contract`); + if (!isContract) throw new Error(`Address ${address} is not a valid Contract`); }; - interface ERC165Contract extends Contract { supportsInterface: (interfaceId: string) => Promise; } @@ -57,25 +55,28 @@ export const supportsInterface = async ( } }; -const isJsonString = (jsonString: string) => { +const isJsonString = (jsonString: string): boolean => { try { - JSON.parse(jsonString); + JSON.parse(jsonString); } catch (e) { - return false; + return false; } return true; -} +}; -export const getTitleEscrowAddress = async (tokenRegistry: TradeTrustToken, tokenId: string) => { - try{ +export const getTitleEscrowAddress = async (tokenRegistry: TradeTrustToken, tokenId: string): Promise => { + try { return await tokenRegistry.ownerOf(tokenId); } catch (e: any) { - if(e?.code === "CALL_EXCEPTION" && e?.reason === "missing revert data in call exception" && e?.data === "0x"){ + if (e?.code === "CALL_EXCEPTION" && e?.reason === "missing revert data in call exception" && e?.data === "0x") { const providerError = e?.error; - if(providerError?.code === "SERVER_ERROR" && providerError?.reason === "processing response error"){ - if(isJsonString(providerError?.body)){ + if (providerError?.code === "SERVER_ERROR" && providerError?.reason === "processing response error") { + if (isJsonString(providerError?.body)) { const VMError: any = JSON.parse(providerError?.body); - if(VMError?.error?.message === "VM Exception while processing transaction: revert ERC721: owner query for nonexistent token"){ + if ( + VMError?.error?.message === + "VM Exception while processing transaction: revert ERC721: owner query for nonexistent token" + ) { throw new Error(`Unminted Token`); } } @@ -83,13 +84,9 @@ export const getTitleEscrowAddress = async (tokenRegistry: TradeTrustToken, toke } throw e; } -} - +}; -export const connectToTitleEscrowAddress = async ( - address: string, - wallet: UserWallet, -): Promise => { +export const connectToTitleEscrowAddress = async (address: string, wallet: UserWallet): Promise => { await assertAddressIsSmartContract(address, wallet); const titleEscrow = TitleEscrow__factory.connect(address, wallet); // const isTitleEscrow = await supportsInterface(titleEscrow, "0x8a198f04") @@ -126,7 +123,7 @@ export const connectToTokenRegistry = async ({ // State Checks -export const validateActiveTitleEscrow = async (titleEscrow: TitleEscrow) => { +export const validateActiveTitleEscrow = async (titleEscrow: TitleEscrow): Promise => { const activeEscrow = await titleEscrow.active(); if (!activeEscrow) throw new Error(`Inactive Title Escrow`); }; @@ -141,27 +138,31 @@ export const EscrowRoles = { export type EscrowRolesType = typeof EscrowRoles[keyof typeof EscrowRoles]; -const hasTransferRights = async (titleEscrow: TitleEscrow, walletAddress: string, expectedPermissions: string[]) => { +const hasTransferRights = async ( + titleEscrow: TitleEscrow, + walletAddress: string, + expectedPermissions: string[] +): Promise => { for (const roles of expectedPermissions) { let rightsHolder = ""; let results = true; switch (roles) { case EscrowRoles.beneficiary: rightsHolder = await titleEscrow.beneficiary(); - results = results && (rightsHolder === walletAddress); + results = results && rightsHolder === walletAddress; break; case EscrowRoles.holder: rightsHolder = await titleEscrow.holder(); - results = results && (rightsHolder === walletAddress); + results = results && rightsHolder === walletAddress; break; case EscrowRoles.nominee: rightsHolder = await titleEscrow.nominee(); - results = results && (rightsHolder === walletAddress); + results = results && rightsHolder === walletAddress; break; - default: + default: throw new Error(`Unimplemented role: ${roles}`); } - if(!results) return false; + if (!results) return false; } return true; }; @@ -172,7 +173,11 @@ interface validateTransferArgs { walletAddress: string; } -export const validateTransferHolder = async ({ titleEscrow, to, walletAddress }: validateTransferArgs) => { +export const validateTransferHolder = async ({ + titleEscrow, + to, + walletAddress, +}: validateTransferArgs): Promise => { await validateActiveTitleEscrow(titleEscrow); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); @@ -180,7 +185,11 @@ export const validateTransferHolder = async ({ titleEscrow, to, walletAddress }: if (isHolder) throw new Error(`Destination wallet already has the rights of holdership`); }; -export const validateTransferBeneficiary = async ({ titleEscrow, to, walletAddress }: validateTransferArgs) => { +export const validateTransferBeneficiary = async ({ + titleEscrow, + to, + walletAddress, +}: validateTransferArgs): Promise => { await validateActiveTitleEscrow(titleEscrow); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.beneficiary, EscrowRoles.holder]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); @@ -218,7 +227,6 @@ export const validateEndorseChangeOwner = async ({ await validateTransferBeneficiary({ titleEscrow, to: newOwner, walletAddress }); }; - interface validateEndorseTransferOwnerArgs { approvedOwner: string | undefined; approvedHolder: string | undefined; @@ -236,30 +244,30 @@ export const validateEndorseTransferOwner = ({ }; interface validateSurrenderArgs { - titleEscrow: TitleEscrow, - walletAddress: string, + titleEscrow: TitleEscrow; + walletAddress: string; } interface validateAcceptSurrenderArgs { - tokenRegistry: TradeTrustToken, - tokenId: string, - wallet: UserWallet, + tokenRegistry: TradeTrustToken; + tokenId: string; + wallet: UserWallet; } -export const validateSurrender = async ({ - titleEscrow, - walletAddress, -}: validateSurrenderArgs): Promise => { +export const validateSurrender = async ({ titleEscrow, walletAddress }: validateSurrenderArgs): Promise => { const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder, EscrowRoles.beneficiary]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); }; -export const connectToTitleEscrowFactory = async (tokenRegistry: TradeTrustToken, wallet: UserWallet): Promise => { +export const connectToTitleEscrowFactory = async ( + tokenRegistry: TradeTrustToken, + wallet: UserWallet +): Promise => { const titleEscrowFactoryAddress = await tokenRegistry.titleEscrowFactory(); - await assertAddressIsSmartContract(titleEscrowFactoryAddress, wallet) + await assertAddressIsSmartContract(titleEscrowFactoryAddress, wallet); const titleEscrowFactory = TitleEscrowFactory__factory.connect(titleEscrowFactoryAddress, wallet); return titleEscrowFactory; -} +}; export const validateSurrenderMethod = async ({ tokenRegistry, @@ -267,13 +275,13 @@ export const validateSurrenderMethod = async ({ wallet, }: validateAcceptSurrenderArgs): Promise => { const ownerOfTitleEscrow = await getTitleEscrowAddress(tokenRegistry, tokenId); - if(ownerOfTitleEscrow !== tokenRegistry.address) throw new Error(`Title Escrow has not been surrendered`) + if (ownerOfTitleEscrow !== tokenRegistry.address) throw new Error(`Title Escrow has not been surrendered`); const titleEscrowFactory = await connectToTitleEscrowFactory(tokenRegistry, wallet); // const isTitleEscrowFactory = await supportsInterface(validateAcceptSurrenderArgs, "?") // if(!isTitleEscrowFactory) throw new Error(`Address ${address} is not a supported title escrow factory contract`) - const titleEscrowAddress = await titleEscrowFactory.getAddress(tokenRegistry.address, tokenId); - const walletAddress = await wallet.getAddress(); - const titleEscrow = await connectToTitleEscrowAddress(titleEscrowAddress, wallet); + const titleEscrowAddress = await titleEscrowFactory.getAddress(tokenRegistry.address, tokenId); + const walletAddress = await wallet.getAddress(); + const titleEscrow = await connectToTitleEscrowAddress(titleEscrowAddress, wallet); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder, EscrowRoles.beneficiary]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); -}; \ No newline at end of file +}; diff --git a/src/implementations/title-escrow/rejectSurrendered.ts b/src/implementations/title-escrow/rejectSurrendered.ts index bc441c40..d86cb8e0 100644 --- a/src/implementations/title-escrow/rejectSurrendered.ts +++ b/src/implementations/title-escrow/rejectSurrendered.ts @@ -18,7 +18,7 @@ export const rejectSurrendered = async ({ }: TitleEscrowSurrenderDocumentCommand): Promise => { const wallet = await getWalletOrSigner({ network, ...rest }); const tokenRegistryInstance: TradeTrustToken = await connectToTokenRegistry({ address, wallet }); - await validateSurrenderMethod({tokenRegistry: tokenRegistryInstance, tokenId, wallet}) + await validateSurrenderMethod({ tokenRegistry: tokenRegistryInstance, tokenId, wallet }); if (dryRun) { await dryRunMode({ estimatedGas: await tokenRegistryInstance.estimateGas.restore(tokenId), diff --git a/src/implementations/title-escrow/surrenderDocument.ts b/src/implementations/title-escrow/surrenderDocument.ts index b2186cf8..7dfc0e9e 100644 --- a/src/implementations/title-escrow/surrenderDocument.ts +++ b/src/implementations/title-escrow/surrenderDocument.ts @@ -18,7 +18,7 @@ export const surrenderDocument = async ({ const wallet = await getWalletOrSigner({ network, ...rest }); const titleEscrow = await connectToTitleEscrow({ tokenId, address, wallet }); const walletAddress = await wallet.getAddress(); - await validateSurrender({titleEscrow, walletAddress}) + await validateSurrender({ titleEscrow, walletAddress }); if (dryRun) { await dryRunMode({ estimatedGas: await titleEscrow.estimateGas.surrender(), From e6bd4937bf9f43ede8806f53b76a5322ea0029d0 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Tue, 31 Jan 2023 03:31:27 +0800 Subject: [PATCH 60/63] feat: update jest tests for validation (wip) --- src/implementations/testsHelpers.ts | 177 ++++++++++++++++++ .../title-escrow/acceptSurrendered.test.ts | 51 ++++- src/implementations/title-escrow/helpers.ts | 10 + .../title-escrow/transferOwners.test.ts | 1 + .../token-registry/issue.test.ts | 19 +- 5 files changed, 241 insertions(+), 17 deletions(-) create mode 100644 src/implementations/testsHelpers.ts diff --git a/src/implementations/testsHelpers.ts b/src/implementations/testsHelpers.ts new file mode 100644 index 00000000..5cf8e026 --- /dev/null +++ b/src/implementations/testsHelpers.ts @@ -0,0 +1,177 @@ +import { TradeTrustToken } from "@govtechsg/token-registry/dist/contracts"; +import { BaseContract, BigNumber, constants } from "ethers"; + +export const AddressZero = constants.AddressZero; +export const BurnAddress = "0x000000000000000000000000000000000000dEaD"; +export const EmptyTokenID = "0x0000000000000000000000000000000000000000000000000000000000000000"; +type defaultMockType = jest.Mock; +type SmartContractDataTypes = BigNumber | number | boolean | string; // bytes and unused not included +type EthersResponseType = SmartContractDataTypes | Error; + +export const mockResolve = (value?: EthersResponseType): defaultMockType => { + const fn = jest.fn(); + if (value instanceof Error) { + fn.mockRejectedValue(value); + } else { + fn.mockResolvedValue(value); + } + return fn; +}; + +export const mockReturn = (value?: EthersResponseType): defaultMockType => { + const fn = jest.fn(); + if (value instanceof Error) { + fn.mockImplementation(() => { + throw value; + }); + } else { + fn.mockRejectedValue(value); + } + return fn; +}; + +export const getMockCode = (): defaultMockType => { + const fn = jest.fn(); + fn.mockResolvedValue(true); + return fn; +}; + +export interface ValidContractMockParameters { + supportInterfaceValue?: boolean | Error; +} + +export const getMockContract = ({ supportInterfaceValue = true }: ValidContractMockParameters) => { + const supportInterface = mockResolve(supportInterfaceValue); + return { + supportInterface, + callStatic: { + supportInterface, + }, + }; +}; + +export interface TokenRegistryMockParameters extends ValidContractMockParameters { + ownerOfValue?: string | Error; + address?: string; + titleEscrowAddress?: string; +} + +export const getMockTokenRegistry = ({ + ownerOfValue = AddressZero, + supportInterfaceValue = true, + address = AddressZero, + titleEscrowAddress = AddressZero, +}: TokenRegistryMockParameters): jest.Mock => { + const validContract = getMockContract({ supportInterfaceValue }); + const ownerOf = mockResolve(ownerOfValue); + const genesis = mockResolve(BigNumber.from(0)); + const titleEscrowFactory = mockResolve(titleEscrowAddress); + const contractFunctions = { + ownerOf, + genesis, + titleEscrowFactory, + }; + const mockTokenRegistry = { + ...contractFunctions, + address: address, + callStatic: contractFunctions, + }; + return mergeMockSmartContract({ base: validContract, override: mockTokenRegistry }); +}; + +export interface TokenRegistryMockParameters extends ValidContractMockParameters { + getAddressValue?: string | Error; +} + +export const getMockTitleEscrowFactory = ({ + getAddressValue = AddressZero, + supportInterfaceValue = true, +}: TokenRegistryMockParameters): jest.Mock => { + const validContract = getMockContract({ supportInterfaceValue }); + const getAddress = mockResolve(getAddressValue); + const contractFunctions = { + getAddress, + }; + const mockTokenRegistry = { + ...contractFunctions, + callStatic: contractFunctions, + }; + return mergeMockSmartContract({ base: validContract, override: mockTokenRegistry }); +}; + +export interface TitleEscrowMockParameters extends ValidContractMockParameters { + beneficiaryValue?: string | Error; + holderValue?: string | Error; + nomineeValue?: string | Error; + activeValue?: boolean | Error; +} + +export const getMockTitleEscrow = ({ + beneficiaryValue = AddressZero, + holderValue = AddressZero, + nomineeValue = AddressZero, + activeValue = true, + supportInterfaceValue = true, +}: TitleEscrowMockParameters) => { + const validContract = getMockContract({ supportInterfaceValue }); + const activeContract = mockResolve(activeValue); + const beneficiary = mockResolve(beneficiaryValue); + const holder = mockResolve(holderValue); + const nominee = mockResolve(nomineeValue); + const contractFunctions = { + activeContract, + beneficiary, + holder, + nominee, + }; + const mockTitleEscrow = { + ...contractFunctions, + callStatic: contractFunctions, + }; + return mergeMockSmartContract({ base: validContract, override: mockTitleEscrow }); +}; + +export interface WalletMockParameters { + codeValue?: string | Error; +} + +export const getValidWalletContract = ({ codeValue = `0x` }: WalletMockParameters) => { + const getCode = mockResolve(codeValue); + return { + provider: { + getCode, + }, + }; +}; + +export interface MergeObjectParameters { + base: any; + override: any; +} + +export const mergeMockSmartContract = ({ base, override }: MergeObjectParameters): any => { + // Sowie + override = mergeMockBaseContract(base, override, "functions"); + override = mergeMockBaseContract(base, override, "callStatic"); + override = mergeMockBaseContract(base, override, "estimateGas"); + override = mergeMockBaseContract(base, override, "populateTransaction"); + override = mergeMockBaseContract(base, override, "filters"); + override = mergeMockBaseContract(base, override, "_runningEvents"); + override = mergeMockBaseContract(base, override, "_wrappedEmits"); + return { + ...base, + ...override, + }; +}; + +const mergeMockBaseContract = (base: any, override: any, keyName: key): any => { + if (keyName in override && keyName in base) { + if (typeof base[keyName] === "object" && typeof override[keyName] === "object") { + override[keyName] = { + ...base[keyName], + ...override[keyName], + }; + } + } + return override; +}; diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 2471ebf8..6ef53bdf 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -1,44 +1,78 @@ -import { TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; +import { + TitleEscrowFactory__factory, + TitleEscrow__factory, + TradeTrustToken__factory, +} from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { + AddressZero, + getMockTitleEscrow, + getMockTitleEscrowFactory, + getMockTokenRegistry, + mergeMockSmartContract, +} from "../testsHelpers"; import { acceptSurrendered } from "./acceptSurrendered"; jest.mock("@govtechsg/token-registry/contracts"); const acceptSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { - tokenRegistry: "0x1122", - tokenId: "0x12345", + tokenRegistry: "0x0000000000000000000000000000000000000001", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; +const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; + describe("title-escrow", () => { describe("accepts surrendered transferable record", () => { const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; + const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; + const mockedTitleEscrowFactoryFactory: jest.Mock = TitleEscrowFactory__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectTitleEscrowFactory: jest.Mock = mockedTitleEscrowFactoryFactory.connect; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectTitleEscrow: jest.Mock = mockedTitleEscrowFactory.connect; const mockBurnToken = jest.fn(); const mockCallStaticBurnToken = jest.fn().mockResolvedValue(undefined); + const tokenRegistryAddress = acceptSurrenderedDocumentParams.tokenRegistry; + const mockBaseTokenRegistry = getMockTokenRegistry({ + ownerOfValue: tokenRegistryAddress, + address: tokenRegistryAddress, + titleEscrowAddress: AddressZero, + }); + let mockTokenRegistry = mockBaseTokenRegistry; + const mockTitleEscrowFactory = getMockTitleEscrowFactory({}); + const mockTitleEscrow = getMockTitleEscrow({ holderValue: walletAddress, beneficiaryValue: walletAddress }); + beforeEach(() => { delete process.env.OA_PRIVATE_KEY; mockedTradeTrustTokenFactory.mockReset(); mockedConnectERC721.mockReset(); - mockBurnToken.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); - - mockedConnectERC721.mockReturnValue({ + const mockCustomTokenRegistry = { burn: mockBurnToken, callStatic: { genesis: jest.fn().mockResolvedValue(0), burn: mockCallStaticBurnToken, }, - }); + }; + + mockTokenRegistry = mergeMockSmartContract({ base: mockBaseTokenRegistry, override: mockCustomTokenRegistry }); + mockedConnectERC721.mockReturnValue(mockTokenRegistry); + mockedConnectTitleEscrow.mockReturnValue(mockTitleEscrow); + mockedConnectTitleEscrowFactory.mockReturnValue(mockTitleEscrowFactory); mockBurnToken.mockClear(); mockCallStaticBurnToken.mockClear(); }); @@ -48,12 +82,9 @@ describe("title-escrow", () => { ...acceptSurrenderedDocumentParams, key: privateKey, }); - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(acceptSurrenderedDocumentParams.tokenRegistry, passedSigner); - expect(mockCallStaticBurnToken).toHaveBeenCalledTimes(1); expect(mockBurnToken).toHaveBeenCalledTimes(1); }); }); diff --git a/src/implementations/title-escrow/helpers.ts b/src/implementations/title-escrow/helpers.ts index 6a432705..88ef978b 100644 --- a/src/implementations/title-escrow/helpers.ts +++ b/src/implementations/title-escrow/helpers.ts @@ -7,6 +7,7 @@ import { TradeTrustToken__factory, } from "@govtechsg/token-registry/contracts"; import { Wallet, constants, Contract } from "ethers"; +import { isAddress } from "ethers/lib/utils"; import signale from "signale"; import { ConnectedSigner } from "../utils/wallet"; @@ -178,6 +179,9 @@ export const validateTransferHolder = async ({ to, walletAddress, }: validateTransferArgs): Promise => { + if (!isAddress(walletAddress)) { + ("Destination Holder is not a valid address"); + } await validateActiveTitleEscrow(titleEscrow); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.holder]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); @@ -190,6 +194,9 @@ export const validateTransferBeneficiary = async ({ to, walletAddress, }: validateTransferArgs): Promise => { + if (!isAddress(walletAddress)) { + ("Destination Beneficiary is not a valid address"); + } await validateActiveTitleEscrow(titleEscrow); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.beneficiary, EscrowRoles.holder]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); @@ -204,6 +211,9 @@ export const validateNominateBeneficiary = async ({ to, titleEscrow, }: validateTransferArgs): Promise => { + if (!isAddress(walletAddress)) { + ("Destination Nominee is not a valid address"); + } await validateActiveTitleEscrow(titleEscrow); const haveRights = await hasTransferRights(titleEscrow, walletAddress, [EscrowRoles.beneficiary]); if (!haveRights) throw new Error(`Wallet lack the rights for the transfer operation`); diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index 2ceb6a4d..b03a6c63 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -37,6 +37,7 @@ describe("title-escrow", () => { mockGetBeneficiary.mockReturnValue(mockedBeneficiary); mockGetHolder.mockReturnValue(mockedHolder); mockedConnectERC721.mockReturnValue({ + supportsInterface: jest.fn().mockReturnValue(true), ownerOf: mockedOwnerOf, callStatic: { genesis: jest.fn().mockResolvedValue(0), diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index a26d5546..80a62c5a 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -3,15 +3,16 @@ import { Wallet } from "ethers"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { addAddressPrefix } from "../../utils"; +import { getMockTokenRegistry, mergeMockSmartContract } from "../testsHelpers"; import { issueToTokenRegistry } from "./issue"; jest.mock("@govtechsg/token-registry/contracts"); const deployParams: TokenRegistryIssueCommand = { - beneficiary: "0xabcd", - holder: "0xabce", - tokenId: "0xzyxw", - address: "0x1234", + address: "0x0000000000000000000000000000000000000001", + beneficiary: "0x0x0000000000000000000000000000000000000002", + holder: "0x0000000000000000000000000000000000000003", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; @@ -31,20 +32,24 @@ describe("token-registry", () => { wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); - const mockTTERC721Contract = { + const mockBaseTokenRegistry = getMockTokenRegistry({}); + const mockCustomTokenRegistry = { mint: mockedIssue, callStatic: { - genesis: jest.fn().mockResolvedValue(0), mint: mockCallStaticSafeMint, }, }; + const mockTokenRegistry = mergeMockSmartContract({ + base: mockBaseTokenRegistry, + override: mockCustomTokenRegistry, + }); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; mockedTradeTrustTokenFactory.mockClear(); mockCallStaticSafeMint.mockClear(); mockedConnectERC721.mockReset(); - mockedConnectERC721.mockResolvedValue(mockTTERC721Contract); + mockedConnectERC721.mockResolvedValue(mockTokenRegistry); }); it("should pass in the correct params and return the deployed instance", async () => { From a070e2c3084a2ecd3d1c921a368bc6c8fe93e275 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:15:53 +0800 Subject: [PATCH 61/63] feat: fix jest tests --- src/implementations/testsHelpers.ts | 79 ++++++++++++--- .../title-escrow/acceptSurrendered.test.ts | 7 +- .../endorseNominatedBeneficiary.test.ts | 46 +++++---- .../title-escrow/nominateBeneficiary.test.ts | 43 ++++----- .../title-escrow/rejectSurrendered.test.ts | 96 ++++++++++--------- .../title-escrow/surrenderDocument.test.ts | 36 +++---- .../title-escrow/transferHolder.test.ts | 36 +++---- .../title-escrow/transferOwners.test.ts | 62 ++++++------ .../token-registry/issue.test.ts | 4 +- 9 files changed, 237 insertions(+), 172 deletions(-) diff --git a/src/implementations/testsHelpers.ts b/src/implementations/testsHelpers.ts index 5cf8e026..c3a8c73d 100644 --- a/src/implementations/testsHelpers.ts +++ b/src/implementations/testsHelpers.ts @@ -1,5 +1,4 @@ -import { TradeTrustToken } from "@govtechsg/token-registry/dist/contracts"; -import { BaseContract, BigNumber, constants } from "ethers"; +import { BaseContract, BigNumber, constants, providers } from "ethers"; export const AddressZero = constants.AddressZero; export const BurnAddress = "0x000000000000000000000000000000000000dEaD"; @@ -40,7 +39,16 @@ export interface ValidContractMockParameters { supportInterfaceValue?: boolean | Error; } -export const getMockContract = ({ supportInterfaceValue = true }: ValidContractMockParameters) => { +interface MockContractInterface { + supportInterface: jest.Mock; + callStatic: { + supportInterface: jest.Mock; + }; +} + +export const getMockContract = ({ + supportInterfaceValue = true, +}: ValidContractMockParameters): MockContractInterface => { const supportInterface = mockResolve(supportInterfaceValue); return { supportInterface, @@ -53,19 +61,32 @@ export const getMockContract = ({ supportInterfaceValue = true }: ValidContractM export interface TokenRegistryMockParameters extends ValidContractMockParameters { ownerOfValue?: string | Error; address?: string; - titleEscrowAddress?: string; + titleEscrowFactoryAddress?: string; +} + +interface MockTokenRegistryInterface { + ownerOf: jest.Mock; + genesis: jest.Mock; + titleEscrowFactory: jest.Mock; + supportInterfaces: jest.Mock; + callStatic: { + ownerOf: jest.Mock; + genesis: jest.Mock; + titleEscrowFactory: jest.Mock; + supportInterfaces: jest.Mock; + }; } export const getMockTokenRegistry = ({ ownerOfValue = AddressZero, supportInterfaceValue = true, address = AddressZero, - titleEscrowAddress = AddressZero, -}: TokenRegistryMockParameters): jest.Mock => { + titleEscrowFactoryAddress = AddressZero, +}: TokenRegistryMockParameters): MockTokenRegistryInterface => { const validContract = getMockContract({ supportInterfaceValue }); const ownerOf = mockResolve(ownerOfValue); const genesis = mockResolve(BigNumber.from(0)); - const titleEscrowFactory = mockResolve(titleEscrowAddress); + const titleEscrowFactory = mockResolve(titleEscrowFactoryAddress); const contractFunctions = { ownerOf, genesis, @@ -83,10 +104,19 @@ export interface TokenRegistryMockParameters extends ValidContractMockParameters getAddressValue?: string | Error; } +interface MockTitleEscrowFactoryInterface { + getAddress: jest.Mock; + supportInterfaces: jest.Mock; + callStatic: { + getAddress: jest.Mock; + supportInterfaces: jest.Mock; + }; +} + export const getMockTitleEscrowFactory = ({ getAddressValue = AddressZero, supportInterfaceValue = true, -}: TokenRegistryMockParameters): jest.Mock => { +}: TokenRegistryMockParameters): MockTitleEscrowFactoryInterface => { const validContract = getMockContract({ supportInterfaceValue }); const getAddress = mockResolve(getAddressValue); const contractFunctions = { @@ -106,20 +136,35 @@ export interface TitleEscrowMockParameters extends ValidContractMockParameters { activeValue?: boolean | Error; } +interface MockTitleEscrowInterface { + active: jest.Mock; + beneficiary: jest.Mock; + holder: jest.Mock; + nominee: jest.Mock; + supportInterfaces: jest.Mock; + callStatic: { + active: jest.Mock; + beneficiary: jest.Mock; + holder: jest.Mock; + nominee: jest.Mock; + supportInterfaces: jest.Mock; + }; +} + export const getMockTitleEscrow = ({ beneficiaryValue = AddressZero, holderValue = AddressZero, nomineeValue = AddressZero, activeValue = true, supportInterfaceValue = true, -}: TitleEscrowMockParameters) => { +}: TitleEscrowMockParameters): MockTitleEscrowInterface => { const validContract = getMockContract({ supportInterfaceValue }); - const activeContract = mockResolve(activeValue); + const active = mockResolve(activeValue); const beneficiary = mockResolve(beneficiaryValue); const holder = mockResolve(holderValue); const nominee = mockResolve(nomineeValue); const contractFunctions = { - activeContract, + active, beneficiary, holder, nominee, @@ -131,11 +176,20 @@ export const getMockTitleEscrow = ({ return mergeMockSmartContract({ base: validContract, override: mockTitleEscrow }); }; +export const initMockGetCode = (fn?: jest.Mock): void => { + if (!fn) { + const fn = jest.fn(); + fn.mockResolvedValue(`0x`); + } + jest.spyOn(providers.BaseProvider.prototype, "getCode").mockImplementation(fn); +}; export interface WalletMockParameters { codeValue?: string | Error; } -export const getValidWalletContract = ({ codeValue = `0x` }: WalletMockParameters) => { +export const getValidWalletContract = ({ + codeValue = `0x`, +}: WalletMockParameters): { provider: { getCode: jest.Mock } } => { const getCode = mockResolve(codeValue); return { provider: { @@ -150,7 +204,6 @@ export interface MergeObjectParameters { } export const mergeMockSmartContract = ({ base, override }: MergeObjectParameters): any => { - // Sowie override = mergeMockBaseContract(base, override, "functions"); override = mergeMockBaseContract(base, override, "callStatic"); override = mergeMockBaseContract(base, override, "estimateGas"); diff --git a/src/implementations/title-escrow/acceptSurrendered.test.ts b/src/implementations/title-escrow/acceptSurrendered.test.ts index 6ef53bdf..3fc1b649 100644 --- a/src/implementations/title-escrow/acceptSurrendered.test.ts +++ b/src/implementations/title-escrow/acceptSurrendered.test.ts @@ -4,13 +4,13 @@ import { TradeTrustToken__factory, } from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; - import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; import { AddressZero, getMockTitleEscrow, getMockTitleEscrowFactory, getMockTokenRegistry, + initMockGetCode, mergeMockSmartContract, } from "../testsHelpers"; import { acceptSurrendered } from "./acceptSurrendered"; @@ -47,7 +47,7 @@ describe("title-escrow", () => { const mockBaseTokenRegistry = getMockTokenRegistry({ ownerOfValue: tokenRegistryAddress, address: tokenRegistryAddress, - titleEscrowAddress: AddressZero, + titleEscrowFactoryAddress: AddressZero, }); let mockTokenRegistry = mockBaseTokenRegistry; const mockTitleEscrowFactory = getMockTitleEscrowFactory({}); @@ -64,11 +64,10 @@ describe("title-escrow", () => { const mockCustomTokenRegistry = { burn: mockBurnToken, callStatic: { - genesis: jest.fn().mockResolvedValue(0), burn: mockCallStaticBurnToken, }, }; - + initMockGetCode(); mockTokenRegistry = mergeMockSmartContract({ base: mockBaseTokenRegistry, override: mockCustomTokenRegistry }); mockedConnectERC721.mockReturnValue(mockTokenRegistry); mockedConnectTitleEscrow.mockReturnValue(mockTitleEscrow); diff --git a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts index fbff3be5..a7e4ddc4 100644 --- a/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts +++ b/src/implementations/title-escrow/endorseNominatedBeneficiary.test.ts @@ -2,14 +2,15 @@ import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token import { Wallet } from "ethers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { getMockTitleEscrow, getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { endorseNominatedBeneficiary } from "./endorseNominatedBeneficiary"; jest.mock("@govtechsg/token-registry/contracts"); const endorseNominatedBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { - tokenId: "0xzyxw", - tokenRegistry: "0x1234", - newBeneficiary: "0x1232", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", + tokenRegistry: "0x0000000000000000000000000000000000000001", + newBeneficiary: "0x0000000000000000000000000000000000000002", network: "goerli", dryRun: false, }; @@ -25,36 +26,50 @@ describe("title-escrow", () => { // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; - const mockedTitleEscrowAddress = "0x2133"; + const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; + + const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; const mockedOwnerOf = jest.fn(); mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); const mockTransferOwners = jest.fn(); const mockCallStaticTransferOwners = jest.fn().mockResolvedValue(undefined); - const mockedBeneficiary = "0xdssfs"; + const mockedBeneficiary = "0x0000000000000000000000000000000000000004"; const mockGetBeneficiary = jest.fn(); mockGetBeneficiary.mockReturnValue(mockedBeneficiary); - mockedConnectERC721.mockReturnValue({ - ownerOf: mockedOwnerOf, - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - }, + const mockBaseTokenRegistry = getMockTokenRegistry({ + ownerOfValue: mockedTitleEscrowAddress, + address: endorseNominatedBeneficiaryParams.tokenRegistry, }); + const mockTokenRegistry = mockBaseTokenRegistry; + const mockBaseTitleEscrow = getMockTitleEscrow({ + holderValue: walletAddress, + beneficiaryValue: walletAddress, + nomineeValue: endorseNominatedBeneficiaryParams.newBeneficiary, + }); + + mockedConnectERC721.mockReturnValue(mockTokenRegistry); - mockedConnectTokenFactory.mockReturnValue({ + const customMockTitleEscrow = { transferBeneficiary: mockTransferOwners, - beneficiary: mockGetBeneficiary, + // beneficiary: mockGetBeneficiary, callStatic: { transferBeneficiary: mockCallStaticTransferOwners, }, - }); + }; + + const mockTitleEscrow = mergeMockSmartContract({ base: mockBaseTitleEscrow, override: customMockTitleEscrow }); + + mockedConnectTokenFactory.mockReturnValue(mockTitleEscrow); mockTransferOwners.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); + initMockGetCode(); + beforeEach(() => { delete process.env.OA_PRIVATE_KEY; mockedTradeTrustTokenFactory.mockClear(); @@ -77,7 +92,6 @@ describe("title-escrow", () => { expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(endorseNominatedBeneficiaryParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockCallStaticTransferOwners).toHaveBeenCalledTimes(1); expect(mockTransferOwners).toHaveBeenCalledTimes(1); @@ -88,10 +102,10 @@ describe("title-escrow", () => { await expect( endorseNominatedBeneficiary({ ...endorseNominatedBeneficiaryParams, - newBeneficiary: "0xdssfs", + newBeneficiary: walletAddress, key: privateKey, }) - ).rejects.toThrow(`new beneficiary address is the same as the current beneficiary address`); + ).rejects.toThrow(`Destination wallet already has the rights as beneficiary`); }); }); }); diff --git a/src/implementations/title-escrow/nominateBeneficiary.test.ts b/src/implementations/title-escrow/nominateBeneficiary.test.ts index 45a0b229..12acf77e 100644 --- a/src/implementations/title-escrow/nominateBeneficiary.test.ts +++ b/src/implementations/title-escrow/nominateBeneficiary.test.ts @@ -2,14 +2,15 @@ import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token import { Wallet } from "ethers"; import { TitleEscrowNominateBeneficiaryCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { getMockTitleEscrow, getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { nominateBeneficiary } from "./nominateBeneficiary"; jest.mock("@govtechsg/token-registry/contracts"); const nominateBeneficiaryParams: TitleEscrowNominateBeneficiaryCommand = { - newBeneficiary: "0fosui", - tokenId: "0xzyxw", - tokenRegistry: "0x1234", + newBeneficiary: "0x0000000000000000000000000000000000000002", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", + tokenRegistry: "0x0000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; @@ -24,31 +25,30 @@ describe("title-escrow", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; - const mockedOwnerOf = jest.fn(); + // const mockedOwnerOf = jest.fn(); const mockNominateBeneficiary = jest.fn(); - const mockedTitleEscrowAddress = "0x2133"; - const mockedBeneficiary = "0xdssfs"; - const mockedHolder = "0xdsfls"; + const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; + const mockedBeneficiary = "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf"; + const mockedHolder = "0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf"; const mockGetBeneficiary = jest.fn(); const mockGetHolder = jest.fn(); const mockCallStaticNominateBeneficiary = jest.fn().mockResolvedValue(undefined); mockGetBeneficiary.mockResolvedValue(mockedBeneficiary); mockGetHolder.mockResolvedValue(mockedHolder); - mockedConnectERC721.mockReturnValue({ - ownerOf: mockedOwnerOf, - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - }, - }); - mockedConnectTokenFactory.mockReturnValue({ + const mockBaseTokenRegistry = getMockTokenRegistry({ ownerOfValue: mockedTitleEscrowAddress }); + mockedConnectERC721.mockReturnValue(mockBaseTokenRegistry); + const mockBaseTitleEscrow = getMockTitleEscrow({ beneficiaryValue: mockedBeneficiary, holderValue: mockedHolder }); + const mockCustomTitleEscrow = { nominate: mockNominateBeneficiary, - beneficiary: mockGetBeneficiary, - holder: mockGetHolder, + // beneficiary: mockGetBeneficiary, + // holder: mockGetHolder, callStatic: { nominate: mockCallStaticNominateBeneficiary, }, - }); - mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); + }; + initMockGetCode(); + const mockTitleEscrow = mergeMockSmartContract({ base: mockBaseTitleEscrow, override: mockCustomTitleEscrow }); + mockedConnectTokenFactory.mockReturnValue(mockTitleEscrow); mockNominateBeneficiary.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), @@ -60,7 +60,6 @@ describe("title-escrow", () => { mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); - mockedOwnerOf.mockClear(); mockNominateBeneficiary.mockClear(); mockGetBeneficiary.mockClear(); mockGetHolder.mockClear(); @@ -75,24 +74,22 @@ describe("title-escrow", () => { }); const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(nominateBeneficiaryParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(nominateBeneficiaryParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockCallStaticNominateBeneficiary).toHaveBeenCalledTimes(1); expect(mockNominateBeneficiary).toHaveBeenCalledTimes(1); }); it("should throw an error if new owner addresses is the same as current owner", async () => { - mockGetBeneficiary.mockReturnValue(nominateBeneficiaryParams.newBeneficiary); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( nominateBeneficiary({ ...nominateBeneficiaryParams, + newBeneficiary: mockedBeneficiary, key: privateKey, }) - ).rejects.toThrow("new beneficiary address is the same as the current beneficiary address"); + ).rejects.toThrow("Destination wallet already has the rights as beneficiary"); }); }); }); diff --git a/src/implementations/title-escrow/rejectSurrendered.test.ts b/src/implementations/title-escrow/rejectSurrendered.test.ts index 40320fca..744d0a14 100644 --- a/src/implementations/title-escrow/rejectSurrendered.test.ts +++ b/src/implementations/title-escrow/rejectSurrendered.test.ts @@ -1,39 +1,74 @@ -import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token-registry/contracts"; +import { + TitleEscrowFactory__factory, + TitleEscrow__factory, + TradeTrustToken__factory, +} from "@govtechsg/token-registry/contracts"; import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { + getMockTitleEscrow, + getMockTitleEscrowFactory, + getMockTokenRegistry, + initMockGetCode, + mergeMockSmartContract, +} from "../testsHelpers"; import { rejectSurrendered } from "./rejectSurrendered"; jest.mock("@govtechsg/token-registry/contracts"); const rejectSurrenderedDocumentParams: TitleEscrowSurrenderDocumentCommand = { - tokenRegistry: "0x1122", - tokenId: "0x12345", + tokenRegistry: "0x0000000000000000000000000000000000000001", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; +const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; + describe("title-escrow", () => { describe("rejects surrendered transferable record", () => { const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; + const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; + const mockedTitleEscrowFactoryFactory: jest.Mock = TitleEscrowFactory__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; - const mockedTitleEscrowFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTitleEscrowFactory: jest.Mock = mockedTitleEscrowFactory.connect; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore mock static method + const mockedConnectTitleEscrowFactoryFactory: jest.Mock = mockedTitleEscrowFactoryFactory.connect; - const mockedBeneficiary = jest.fn(); - const mockedHolder = jest.fn(); const mockRestoreTitle = jest.fn(); - const mockTransferEvent = jest.fn(); - const mockQueryFilter = jest.fn(); const mockCallStaticRestoreTitle = jest.fn().mockResolvedValue(undefined); - const mockedLastTitleEscrowAddress = "0xMockedLastTitleEscrowAddress"; - const mockedLastBeneficiary = "0xMockedLastBeneficiaryAddress"; - const mockedLastHolder = "0xMockedLastHolderAddress"; + const mockedLastTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; + initMockGetCode(); + + const mockBaseTokenRegistry = getMockTokenRegistry({ + ownerOfValue: rejectSurrenderedDocumentParams.tokenRegistry, + address: rejectSurrenderedDocumentParams.tokenRegistry, + }); + + const mockCustomTokenRegistry = { + restore: mockRestoreTitle, + callStatic: { + restore: mockCallStaticRestoreTitle, + }, + }; + const mockTokenRegistry = mergeMockSmartContract({ + base: mockBaseTokenRegistry, + override: mockCustomTokenRegistry, + }); + const mockTitleEscrow = getMockTitleEscrow({ beneficiaryValue: walletAddress, holderValue: walletAddress }); + const mockTitleEscrowFactory = getMockTitleEscrowFactory({ getAddressValue: mockedLastTitleEscrowAddress }); + + mockRestoreTitle.mockReturnValue({ + hash: "hash", + wait: () => Promise.resolve({ transactionHash: "transactionHash" }), + }); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; @@ -41,41 +76,10 @@ describe("title-escrow", () => { mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); - - mockedBeneficiary.mockReturnValue(mockedLastBeneficiary); - mockedHolder.mockReturnValue(mockedLastHolder); - mockRestoreTitle.mockReturnValue({ - hash: "hash", - wait: () => Promise.resolve({ transactionHash: "transactionHash" }), - }); - mockTransferEvent.mockReturnValue({ - address: "0x1122", - topics: ["0x00000", null, null, "0x12345"], - }); - mockQueryFilter.mockReturnValue([ - { - args: [mockedLastTitleEscrowAddress, "0x1122"], - }, - ]); - - mockedConnectTitleEscrowFactory.mockReturnValue({ - beneficiary: mockedBeneficiary, - holder: mockedHolder, - }); - mockedConnectERC721.mockReturnValue({ - restore: mockRestoreTitle, - filters: { Transfer: mockTransferEvent }, - queryFilter: mockQueryFilter, - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - restore: mockCallStaticRestoreTitle, - }, - }); - mockedBeneficiary.mockClear(); - mockedHolder.mockClear(); + mockedConnectERC721.mockReturnValue(mockTokenRegistry); + mockedConnectTitleEscrowFactory.mockReturnValue(mockTitleEscrow); + mockedConnectTitleEscrowFactoryFactory.mockReturnValue(mockTitleEscrowFactory); mockRestoreTitle.mockClear(); - mockTransferEvent.mockClear(); - mockQueryFilter.mockClear(); mockCallStaticRestoreTitle.mockClear(); }); @@ -85,9 +89,7 @@ describe("title-escrow", () => { ...rejectSurrenderedDocumentParams, key: privateKey, }); - const passedSigner: Wallet = mockedConnectERC721.mock.calls[0][1]; - expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(rejectSurrenderedDocumentParams.tokenRegistry, passedSigner); expect(mockCallStaticRestoreTitle).toHaveBeenCalledTimes(1); diff --git a/src/implementations/title-escrow/surrenderDocument.test.ts b/src/implementations/title-escrow/surrenderDocument.test.ts index 22aa8041..42524a8c 100644 --- a/src/implementations/title-escrow/surrenderDocument.test.ts +++ b/src/implementations/title-escrow/surrenderDocument.test.ts @@ -2,17 +2,18 @@ import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token import { Wallet } from "ethers"; import { BaseTitleEscrowCommand as TitleEscrowSurrenderDocumentCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { getMockTitleEscrow, getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { surrenderDocument } from "./surrenderDocument"; jest.mock("@govtechsg/token-registry/contracts"); const surrenderDocumentParams: TitleEscrowSurrenderDocumentCommand = { - tokenRegistry: "0x1122", - tokenId: "0x12345", + tokenRegistry: "0x0000000000000000000000000000000000000001", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; - +const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; describe("title-escrow", () => { describe("surrender transferable record", () => { const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; @@ -23,10 +24,14 @@ describe("title-escrow", () => { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTitleEscrowFactory: jest.Mock = mockedTitleEscrowFactory.connect; - const mockedOwnerOf = jest.fn(); + // const mockedOwnerOf = jest.fn(); const mockSurrender = jest.fn(); const mockCallStaticSurrender = jest.fn().mockResolvedValue(undefined); - const mockedTitleEscrowAddress = "0x2133"; + const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; + initMockGetCode(); + + const mockBaseTokenRegistry = getMockTokenRegistry({ ownerOfValue: mockedTitleEscrowAddress }); + const mockTokenRegistry = mockBaseTokenRegistry; beforeEach(() => { delete process.env.OA_PRIVATE_KEY; @@ -34,26 +39,22 @@ describe("title-escrow", () => { mockedConnectERC721.mockReset(); mockedTitleEscrowFactory.mockReset(); mockedConnectTitleEscrowFactory.mockReset(); - - mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); mockSurrender.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); - mockedConnectERC721.mockReturnValue({ - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - }, - ownerOf: mockedOwnerOf, - }); - mockedConnectTitleEscrowFactory.mockReturnValue({ + + mockedConnectERC721.mockReturnValue(mockTokenRegistry); + + const mockBaseTitleEscrow = getMockTitleEscrow({ beneficiaryValue: walletAddress, holderValue: walletAddress }); + const mockCustomTitleEscrow = { surrender: mockSurrender, callStatic: { surrender: mockCallStaticSurrender, }, - }); - - mockedOwnerOf.mockClear(); + }; + const mockTitleEscrow = mergeMockSmartContract({ base: mockBaseTitleEscrow, override: mockCustomTitleEscrow }); + mockedConnectTitleEscrowFactory.mockReturnValue(mockTitleEscrow); mockSurrender.mockClear(); mockCallStaticSurrender.mockClear(); }); @@ -68,7 +69,6 @@ describe("title-escrow", () => { expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(surrenderDocumentParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(surrenderDocumentParams.tokenId); expect(mockedConnectTitleEscrowFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockCallStaticSurrender).toHaveBeenCalledTimes(1); expect(mockSurrender).toHaveBeenCalledTimes(1); diff --git a/src/implementations/title-escrow/transferHolder.test.ts b/src/implementations/title-escrow/transferHolder.test.ts index 552c0c1f..5832ec4d 100644 --- a/src/implementations/title-escrow/transferHolder.test.ts +++ b/src/implementations/title-escrow/transferHolder.test.ts @@ -2,50 +2,54 @@ import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token import { Wallet } from "ethers"; import { TitleEscrowTransferHolderCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { getMockTitleEscrow, getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { transferHolder } from "./transferHolder"; jest.mock("@govtechsg/token-registry/contracts"); const transferHolderParams: TitleEscrowTransferHolderCommand = { newHolder: "0xabcd", - tokenId: "0xzyxw", - tokenRegistry: "0x1234", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", + tokenRegistry: "0x0000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; +const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; + describe("title-escrow", () => { describe("change holder of transferable record", () => { const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; + const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectERC721: jest.Mock = mockedTradeTrustTokenFactory.connect; - - const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; - const mockedOwnerOf = jest.fn(); + // const mockedOwnerOf = jest.fn(); const mockTransferHolder = jest.fn(); const mockCallStaticTransferHolder = jest.fn().mockResolvedValue(undefined); - const mockedTitleEscrowAddress = "0x2133"; - mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); + const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; mockTransferHolder.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); - mockedConnectERC721.mockReturnValue({ - ownerOf: mockedOwnerOf, - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - }, - }); - mockedConnectTokenFactory.mockReturnValue({ + + initMockGetCode(); + + const mockBaseTokenRegistry = getMockTokenRegistry({ ownerOfValue: mockedTitleEscrowAddress }); + mockedConnectERC721.mockReturnValue(mockBaseTokenRegistry); + + const mockBaseTitleEscrow = getMockTitleEscrow({ beneficiaryValue: walletAddress, holderValue: walletAddress }); + const mockCustomTitleEscrow = { transferHolder: mockTransferHolder, callStatic: { transferHolder: mockCallStaticTransferHolder, }, - }); + }; + const mockTitleEscrow = mergeMockSmartContract({ base: mockBaseTitleEscrow, override: mockCustomTitleEscrow }); + mockedConnectTokenFactory.mockReturnValue(mockTitleEscrow); beforeEach(() => { delete process.env.OA_PRIVATE_KEY; @@ -53,7 +57,6 @@ describe("title-escrow", () => { mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); - mockedOwnerOf.mockClear(); mockTransferHolder.mockClear(); mockCallStaticTransferHolder.mockClear(); }); @@ -69,7 +72,6 @@ describe("title-escrow", () => { expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(transferHolderParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(transferHolderParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); expect(mockCallStaticTransferHolder).toHaveBeenCalledTimes(1); expect(mockTransferHolder).toHaveBeenCalledTimes(1); diff --git a/src/implementations/title-escrow/transferOwners.test.ts b/src/implementations/title-escrow/transferOwners.test.ts index b03a6c63..7bde12d2 100644 --- a/src/implementations/title-escrow/transferOwners.test.ts +++ b/src/implementations/title-escrow/transferOwners.test.ts @@ -2,19 +2,25 @@ import { TitleEscrow__factory, TradeTrustToken__factory } from "@govtechsg/token import { Wallet } from "ethers"; import { TitleEscrowEndorseTransferOfOwnersCommand } from "../../commands/title-escrow/title-escrow-command.type"; +import { getMockTitleEscrow, getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { transferOwners } from "./transferOwners"; jest.mock("@govtechsg/token-registry/contracts"); const endorseChangeOwnersParams: TitleEscrowEndorseTransferOfOwnersCommand = { - newHolder: "0xabcd", - newOwner: "0fosui", - tokenId: "0xzyxw", - tokenRegistry: "0x1234", + newHolder: "0x0000000000000000000000000000000000000004", + newOwner: "0x0000000000000000000000000000000000000004", + tokenId: "0x0000000000000000000000000000000000000000000000000000000000000001", + tokenRegistry: "0x0000000000000000000000000000000000000001", network: "goerli", dryRun: false, }; +const mockedTitleEscrowAddress = "0x0000000000000000000000000000000000000003"; +// const mockedBeneficiary = "0x0000000000000000000000000000000000000004"; +// const mockedHolder = "0xdsfls"; +const walletAddress = `0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf`; + describe("title-escrow", () => { describe("endorse change of owners of transferable record", () => { const mockedTradeTrustTokenFactory: jest.Mock = TradeTrustToken__factory as any; @@ -24,49 +30,42 @@ describe("title-escrow", () => { const mockedTokenFactory: jest.Mock = TitleEscrow__factory as any; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore mock static method - const mockedConnectTokenFactory: jest.Mock = mockedTokenFactory.connect; - const mockedOwnerOf = jest.fn(); + const mockTransferOwners = jest.fn(); const mockCallStaticTransferOwners = jest.fn().mockResolvedValue(undefined); - const mockedTitleEscrowAddress = "0x2133"; - const mockedBeneficiary = "0xdssfs"; - const mockedHolder = "0xdsfls"; - const mockGetBeneficiary = jest.fn(); - const mockGetHolder = jest.fn(); - mockGetBeneficiary.mockReturnValue(mockedBeneficiary); - mockGetHolder.mockReturnValue(mockedHolder); - mockedConnectERC721.mockReturnValue({ - supportsInterface: jest.fn().mockReturnValue(true), - ownerOf: mockedOwnerOf, - callStatic: { - genesis: jest.fn().mockResolvedValue(0), - }, + + const mockBaseTokenRegistry = getMockTokenRegistry({ ownerOfValue: mockedTitleEscrowAddress }); + const mockTokenRegistry = mockBaseTokenRegistry; + mockedConnectERC721.mockReturnValue(mockTokenRegistry); + + const mockBaseTitleEscrow = getMockTitleEscrow({ + beneficiaryValue: walletAddress, + holderValue: walletAddress, + nomineeValue: endorseChangeOwnersParams.newOwner, }); - mockedConnectTokenFactory.mockReturnValue({ + const mockCustomTitleEscrow = { transferOwners: mockTransferOwners, - beneficiary: mockGetBeneficiary, - holder: mockGetHolder, callStatic: { transferOwners: mockCallStaticTransferOwners, }, - }); - mockedOwnerOf.mockReturnValue(mockedTitleEscrowAddress); + }; + const mockTitleEscrow = mergeMockSmartContract({ base: mockBaseTitleEscrow, override: mockCustomTitleEscrow }); + mockedConnectTokenFactory.mockReturnValue(mockTitleEscrow); mockTransferOwners.mockReturnValue({ hash: "hash", wait: () => Promise.resolve({ transactionHash: "transactionHash" }), }); + initMockGetCode(); + beforeEach(() => { delete process.env.OA_PRIVATE_KEY; mockedTradeTrustTokenFactory.mockClear(); mockedConnectERC721.mockClear(); mockedTokenFactory.mockClear(); mockedConnectTokenFactory.mockClear(); - mockedOwnerOf.mockClear(); mockTransferOwners.mockClear(); - mockGetBeneficiary.mockClear(); - mockGetHolder.mockClear(); mockCallStaticTransferOwners.mockClear(); }); @@ -81,24 +80,21 @@ describe("title-escrow", () => { expect(passedSigner.privateKey).toBe(`0x${privateKey}`); expect(mockedConnectERC721).toHaveBeenCalledWith(endorseChangeOwnersParams.tokenRegistry, passedSigner); - expect(mockedOwnerOf).toHaveBeenCalledWith(endorseChangeOwnersParams.tokenId); expect(mockedConnectTokenFactory).toHaveBeenCalledWith(mockedTitleEscrowAddress, passedSigner); - expect(mockGetBeneficiary).toHaveBeenCalledTimes(1); - expect(mockGetHolder).toHaveBeenCalledTimes(1); expect(mockCallStaticTransferOwners).toHaveBeenCalledTimes(1); expect(mockTransferOwners).toHaveBeenCalledTimes(1); }); it("should throw an error if new owner and new holder addresses are the same as current owner and holder addressses", async () => { - mockGetBeneficiary.mockReturnValue(endorseChangeOwnersParams.newOwner); - mockGetHolder.mockReturnValue(endorseChangeOwnersParams.newHolder); const privateKey = "0000000000000000000000000000000000000000000000000000000000000001"; await expect( transferOwners({ ...endorseChangeOwnersParams, + newOwner: walletAddress, + newHolder: walletAddress, key: privateKey, }) - ).rejects.toThrow("new owner and new holder addresses are the same as the current owner and holder addresses"); + ).rejects.toThrow("Destination wallet already has the rights of holdership"); }); }); }); diff --git a/src/implementations/token-registry/issue.test.ts b/src/implementations/token-registry/issue.test.ts index 80a62c5a..cf52f440 100644 --- a/src/implementations/token-registry/issue.test.ts +++ b/src/implementations/token-registry/issue.test.ts @@ -3,7 +3,7 @@ import { Wallet } from "ethers"; import { TokenRegistryIssueCommand } from "../../commands/token-registry/token-registry-command.type"; import { addAddressPrefix } from "../../utils"; -import { getMockTokenRegistry, mergeMockSmartContract } from "../testsHelpers"; +import { getMockTokenRegistry, initMockGetCode, mergeMockSmartContract } from "../testsHelpers"; import { issueToTokenRegistry } from "./issue"; jest.mock("@govtechsg/token-registry/contracts"); @@ -44,6 +44,8 @@ describe("token-registry", () => { override: mockCustomTokenRegistry, }); + initMockGetCode(); + beforeEach(() => { delete process.env.OA_PRIVATE_KEY; mockedTradeTrustTokenFactory.mockClear(); From 0c823f5b3132f9944c01312971b553e90d291bb2 Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 1 Feb 2023 12:51:24 +0800 Subject: [PATCH 62/63] fix: renaming and scope changes --- package.json | 2 +- src/e2e/accept-surrender.e2e.ts | 32 +++---- src/e2e/change-holder.e2e.ts | 68 +++++++------- src/e2e/deploy.e2e.ts | 6 +- src/e2e/endorse-change-owner.e2e.ts | 66 ++++++++------ src/e2e/endorse-transfer.e2e.ts | 94 ++++++++++++-------- src/e2e/{all.ts => index.ts} | 0 src/e2e/mint.e2e.ts | 34 ++++--- src/e2e/nominate.e2e.ts | 56 ++++++------ src/e2e/reject-surrender.e2e.ts | 26 +++--- src/e2e/surrender.e2e.ts | 42 ++++----- src/e2e/utils/constants.ts | 1 - src/e2e/utils/helpers/accept-surrender.ts | 20 ++--- src/e2e/utils/helpers/change-holder.ts | 8 +- src/e2e/utils/helpers/common.ts | 2 +- src/e2e/utils/helpers/deploy.ts | 10 +-- src/e2e/utils/helpers/endorse-beneficiary.ts | 16 ++-- src/e2e/utils/helpers/endorse-owners.ts | 2 +- src/e2e/utils/helpers/mint.ts | 18 ++-- src/e2e/utils/helpers/nominate.ts | 25 ++++-- src/e2e/utils/helpers/reject-surrender.ts | 2 +- src/e2e/utils/helpers/surrender.ts | 18 ++-- src/e2e/utils/shell.ts | 17 ++-- 23 files changed, 303 insertions(+), 262 deletions(-) rename src/e2e/{all.ts => index.ts} (100%) diff --git a/package.json b/package.json index 0b1b85d0..683757d0 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "test": "jest --ci", "test:coverage": "npm run test -- --coverage", "test:watch": "npm run test -- --watch", - "e2e-test": "ts-node src/e2e/all.ts", + "e2e-test": "ts-node src/e2e/index.ts", "lint": "eslint . --ext .ts --max-warnings 0", "lint:fix": "eslint . --ext .ts --fix", "benchmark:make-certs": "./scripts/makeCerts.sh 20000", diff --git a/src/e2e/accept-surrender.e2e.ts b/src/e2e/accept-surrender.e2e.ts index 48d35bde..3f1acea9 100644 --- a/src/e2e/accept-surrender.e2e.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -1,9 +1,9 @@ import { - checkFailure, - checkSurrenderAcceptSuccess, - deployTokenRegistry, - mintSurrenderToken, - mintTokenRegistry, + checkE2EFailure, + checkE2ESurrenderAcceptSuccess, + deployE2ETokenRegistry, + mintSurrenderE2EToken, + mintE2ETokenRegistry, } from "./utils/helpers"; import { generateAcceptSurrenderCommand } from "./utils/commands"; import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from "./utils/constants"; @@ -11,7 +11,7 @@ import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { run } from "./utils/shell"; export const acceptSurrender = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); // const errors: Error[] = []; const defaultTitleEscrow = { ...defaultRunParameters, @@ -21,7 +21,7 @@ export const acceptSurrender = async (): Promise => { //"should be able to accept-surrender title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); let titleEscrowOwner: string = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); @@ -31,50 +31,50 @@ export const acceptSurrender = async (): Promise => { titleEscrowOwner = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); if (!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")) throw new Error(`!(titleEscrowOwner === "0x000000000000000000000000000000000000dEaD")`); - checkSurrenderAcceptSuccess(results); + checkE2ESurrenderAcceptSuccess(results); } //"should not be able to accept surrender invalid title-escrow on token-registry" { - const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand( { tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, "Unminted Token"); + checkE2EFailure(results, "Unminted Token"); } //"should not be able to accept surrender title-escrow on invalid token-registry" { - const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand( { tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" { - const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand( { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, receiver.privateKey ); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to accept un-surrendered title-escrow on token-registry" { - const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const command = generateAcceptSurrenderCommand( { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, "Title Escrow has not been surrendered"); + checkE2EFailure(results, "Title Escrow has not been surrendered"); } }; diff --git a/src/e2e/change-holder.e2e.ts b/src/e2e/change-holder.e2e.ts index 1ceef336..442a9800 100644 --- a/src/e2e/change-holder.e2e.ts +++ b/src/e2e/change-holder.e2e.ts @@ -1,13 +1,13 @@ import { TitleEscrowTransferHolderCommand } from "../commands/title-escrow/title-escrow-command.type"; import { - changeHolderToken, - checkChangeHolderSuccess, - checkFailure, - defaultTransferHolder, - deployTokenRegistry, - mintBurntToken, - mintSurrenderToken, - mintTokenRegistry, + changeHolderE2EToken, + checkE2EChangeHolderSuccess, + checkE2EFailure, + defaultE2ETransferHolder, + deployE2ETokenRegistry, + mintBurntE2EToken, + mintSurrenderE2EToken, + mintE2ETokenRegistry, } from "./utils/helpers"; import { generateChangeHolderCommand } from "./utils/commands"; import { BurnAddress, EmptyTokenID, owner, receiver } from "./utils/constants"; @@ -17,19 +17,19 @@ import { BigNumber } from "ethers"; // "transfer holder title-escrow" export const changeHolder = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //should be able to transfer holder title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: tokenId, tokenRegistry: tokenRegistry, - ...defaultTransferHolder, + ...defaultE2ETransferHolder, }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkChangeHolderSuccess(results); + checkE2EChangeHolderSuccess(results); const signer = await getSigner(transferHolder.network, receiver.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); @@ -46,19 +46,19 @@ export const changeHolder = async (): Promise => { //holder should be able to transfer holder of title-escrow" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver const initialHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: receiver.ethAddress, }; - changeHolderToken(owner.privateKey, initialHolder); + changeHolderE2EToken(owner.privateKey, initialHolder); // Transfer Holder to Receiver // Holder attempts to transfer Holder with permission const transferHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: owner.ethAddress, @@ -66,50 +66,50 @@ export const changeHolder = async (): Promise => { const command = generateChangeHolderCommand(transferHolder, receiver.privateKey); // Holder attempts to transfer Holder with permission const results = run(command); - checkChangeHolderSuccess(results); + checkE2EChangeHolderSuccess(results); } //should not be able to transfer holder of invalid title-escrow on token-registry" { - const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: EmptyTokenID, tokenRegistry: tokenRegistry, - ...defaultTransferHolder, + ...defaultE2ETransferHolder, }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Unminted Token"); + checkE2EFailure(results, "Unminted Token"); } //should not be able to transfer holder of title-escrow on invalid token-registry" { - const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { tokenId: tokenId, tokenRegistry: BurnAddress, - ...defaultTransferHolder, + ...defaultE2ETransferHolder, }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //beneficiary should not be able to transfer holder of title-escrow" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); // Transfer Holder to Receiver const initialHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: receiver.ethAddress, }; - changeHolderToken(owner.privateKey, initialHolder); + changeHolderE2EToken(owner.privateKey, initialHolder); // Transfer Holder to Receiver // Beneficiary attempts to transfer Holder without permission const transferHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: owner.ethAddress, @@ -117,34 +117,34 @@ export const changeHolder = async (): Promise => { const command = generateChangeHolderCommand(transferHolder, owner.privateKey); // Beneficiary attempts to transfer Holder without permission const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } // should not be able to transfer holder of surrendered title-escrow" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: owner.ethAddress, }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been surrendered"); + checkE2EFailure(results, "Title Escrow has already been surrendered"); } //should not be able to transfer holder of burnt title-escrow" { - const { tokenRegistry, tokenId } = mintBurntToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintBurntE2EToken(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowTransferHolderCommand = { - ...defaultTransferHolder, + ...defaultE2ETransferHolder, tokenId: tokenId, tokenRegistry: tokenRegistry, newHolder: owner.ethAddress, }; const command = generateChangeHolderCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been shredded"); + checkE2EFailure(results, "Title Escrow has already been shredded"); } }; diff --git a/src/e2e/deploy.e2e.ts b/src/e2e/deploy.e2e.ts index f546aff7..1579e22d 100644 --- a/src/e2e/deploy.e2e.ts +++ b/src/e2e/deploy.e2e.ts @@ -4,7 +4,7 @@ import { isAddress } from "web3-utils"; import { defaultRunParameters, EndStatus, owner } from "./utils/constants"; import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand } from "./utils/commands"; import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; -import { checkTokenRegistrySuccess, defaultTokenRegistry } from "./utils/helpers"; +import { checkE2ETokenRegistrySuccess, defaultE2ETokenRegistryParams } from "./utils/helpers"; export const deployTokenRegistry = async (): Promise => { //should be able to deploy token-registry" @@ -12,12 +12,12 @@ export const deployTokenRegistry = async (): Promise => { const tokenRegistryParameter: DeployTokenRegistryCommand = { registryName: "Test Token", registrySymbol: "TKN", - ...defaultTokenRegistry, + ...defaultE2ETokenRegistryParams, }; const command = generateDeployTokenRegistryCommand(tokenRegistryParameter, owner.privateKey); const results = run(command); - const tokenRegistryAddress = checkTokenRegistrySuccess(results); + const tokenRegistryAddress = checkE2ETokenRegistrySuccess(results); const signer = getSigner(defaultRunParameters.network, owner.privateKey); const tokenInfo = await retrieveTokenInfo(signer, tokenRegistryAddress); if (!(tokenInfo.name === tokenRegistryParameter.registryName)) { diff --git a/src/e2e/endorse-change-owner.e2e.ts b/src/e2e/endorse-change-owner.e2e.ts index d79df33d..9af962f2 100644 --- a/src/e2e/endorse-change-owner.e2e.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -3,21 +3,21 @@ import { BurnAddress, defaultRunParameters, owner, receiver, thirdParty } from " import { TitleEscrowEndorseTransferOfOwnersCommand } from "../commands/title-escrow/title-escrow-command.type"; import { generateTransferOwnersCommand } from "./utils/commands"; import { - burnToken, - changeHolderToken, - checkEndorseOwner, - checkFailure, - deployTokenRegistry, - mintNominatedToken, - mintTokenRegistry, - surrenderToken, + burnE2EToken, + changeHolderE2EToken, + checkE2EEndorseOwner, + checkE2EFailure, + deployE2ETokenRegistry, + mintNominatedE2EToken, + mintE2ETokenRegistry, + surrenderE2EToken, } from "./utils/helpers"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; // "endorse change owner title-escrow" export const endorseChangeOwner = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); const defaultTransferOwners = { ...defaultRunParameters, @@ -27,7 +27,7 @@ export const endorseChangeOwner = async (): Promise => { //should be able to endorse change owner title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken( + const { tokenRegistry, tokenId } = mintNominatedE2EToken( owner.privateKey, defaultTransferOwners.newOwner, tokenRegistryAddress @@ -39,7 +39,7 @@ export const endorseChangeOwner = async (): Promise => { }; const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); - const { beneficiary, holder, tokenId: tokenIdResult } = checkEndorseOwner(results); + const { beneficiary, holder, tokenId: tokenIdResult } = checkE2EEndorseOwner(results); if (!(beneficiary === transferOwners.newOwner)) throw new Error(`beneficiary === transferOwners.newOwner`); if (!(holder === transferOwners.newHolder)) throw new Error(`holder === transferOwners.newHolder`); if (!(tokenIdResult === transferOwners.tokenId)) throw new Error(`tokenIdResult === transferOwners.tokenId`); @@ -61,8 +61,12 @@ export const endorseChangeOwner = async (): Promise => { //"should not be able to endorse change owner from just beneficiary title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); - changeHolderToken(owner.privateKey, { + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); + changeHolderE2EToken(owner.privateKey, { ...defaultTransferOwners, tokenRegistry: tokenRegistry, tokenId: tokenId, @@ -76,12 +80,16 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse change owner from nominee title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); const transferHolder: TitleEscrowEndorseTransferOfOwnersCommand = { ...defaultTransferOwners, tokenId, @@ -90,13 +98,13 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse surrendered title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); - surrenderToken(owner.privateKey, { + const { tokenRegistry, tokenId } = mintNominatedE2EToken(owner.privateKey, tokenRegistryAddress); + surrenderE2EToken(owner.privateKey, { ...defaultTransferOwners, tokenRegistry, tokenId, @@ -109,13 +117,13 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been surrendered"); + checkE2EFailure(results, "Title Escrow has already been surrendered"); } //"should not be able to endorse burnt title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); - burnToken(owner.privateKey, { + const { tokenRegistry, tokenId } = mintNominatedE2EToken(owner.privateKey, tokenRegistryAddress); + burnE2EToken(owner.privateKey, { ...defaultTransferOwners, tokenId, tokenRegistry, @@ -128,12 +136,12 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been shredded"); + checkE2EFailure(results, "Title Escrow has already been shredded"); } //"should not be able to endorse change owner on un-nominated title-escrow" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferOwners: TitleEscrowEndorseTransferOfOwnersCommand = { tokenId: tokenId, tokenRegistry: tokenRegistry, @@ -141,13 +149,17 @@ export const endorseChangeOwner = async (): Promise => { }; const command = generateTransferOwnersCommand(transferOwners, owner.privateKey); const results = run(command); - checkFailure(results, "Destination wallet has not been nominated"); + checkE2EFailure(results, "Destination wallet has not been nominated"); } //"should not be able to endorse change owner from holder title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); - changeHolderToken(owner.privateKey, { + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); + changeHolderE2EToken(owner.privateKey, { ...defaultTransferOwners, tokenRegistry: tokenRegistry, tokenId: tokenId, @@ -161,6 +173,6 @@ export const endorseChangeOwner = async (): Promise => { const command = generateTransferOwnersCommand(transferHolder, thirdParty.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } }; diff --git a/src/e2e/endorse-transfer.e2e.ts b/src/e2e/endorse-transfer.e2e.ts index 94b798da..df0389b3 100644 --- a/src/e2e/endorse-transfer.e2e.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -1,14 +1,14 @@ import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/title-escrow-command.type"; import { - burnToken, - changeHolderToken, - checkEndorseBeneficiary, - checkFailure, - defaultTransferBeneficiary, - deployTokenRegistry, - mintNominatedToken, - mintTokenRegistry, - surrenderToken, + burnE2EToken, + changeHolderE2EToken, + checkE2EEndorseBeneficiary, + checkE2EFailure, + defaultE2ETransferBeneficiary, + deployE2ETokenRegistry, + mintNominatedE2EToken, + mintE2ETokenRegistry, + surrenderE2EToken, } from "./utils/helpers"; import { generateEndorseTransferOwnerCommand } from "./utils/commands"; import { owner, receiver, thirdParty } from "./utils/constants"; @@ -17,20 +17,24 @@ import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; export const endorseTransfer = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to endorse transfer title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, }; const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkEndorseBeneficiary(results); + checkE2EEndorseBeneficiary(results); const signer = await getSigner(transferHolder.network, receiver.privateKey); const titleEscrowInfo = await retrieveTitleEscrow(signer, transferHolder.tokenRegistry, transferHolder.tokenId); @@ -46,48 +50,56 @@ export const endorseTransfer = async (): Promise => { //"should not be able to endorse transfer from just beneficiary title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); - changeHolderToken(owner.privateKey, { - ...defaultTransferBeneficiary, + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); + changeHolderE2EToken(owner.privateKey, { + ...defaultE2ETransferBeneficiary, tokenRegistry: tokenRegistry, tokenId: tokenId, newHolder: receiver.ethAddress, }); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, }; const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse transfer from nominee title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, }; const command = generateEndorseTransferOwnerCommand(transferHolder, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to endorse surrendered title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); - surrenderToken(owner.privateKey, { - ...defaultTransferBeneficiary, + const { tokenRegistry, tokenId } = mintNominatedE2EToken(owner.privateKey, tokenRegistryAddress); + surrenderE2EToken(owner.privateKey, { + ...defaultE2ETransferBeneficiary, tokenRegistry, tokenId, }); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, @@ -95,19 +107,19 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been surrendered"); + checkE2EFailure(results, "Title Escrow has already been surrendered"); } // "should not be able to endorse burnt title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, tokenRegistryAddress); - burnToken(owner.privateKey, { - ...defaultTransferBeneficiary, + const { tokenRegistry, tokenId } = mintNominatedE2EToken(owner.privateKey, tokenRegistryAddress); + burnE2EToken(owner.privateKey, { + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, }); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, @@ -115,14 +127,14 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Title Escrow has already been shredded"); + checkE2EFailure(results, "Title Escrow has already been shredded"); } // "should not be able to endorse un-nominated title-escrow on token-registry"; { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, @@ -130,26 +142,30 @@ export const endorseTransfer = async (): Promise => { const command = generateEndorseTransferOwnerCommand(transferHolder, owner.privateKey); const results = run(command); - checkFailure(results, "Destination wallet has not been nominated"); + checkE2EFailure(results, "Destination wallet has not been nominated"); } // "should not be able to endorse transfer from holder title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintNominatedToken(owner.privateKey, receiver.ethAddress, tokenRegistryAddress); - changeHolderToken(owner.privateKey, { - ...defaultTransferBeneficiary, + const { tokenRegistry, tokenId } = mintNominatedE2EToken( + owner.privateKey, + receiver.ethAddress, + tokenRegistryAddress + ); + changeHolderE2EToken(owner.privateKey, { + ...defaultE2ETransferBeneficiary, tokenRegistry: tokenRegistry, tokenId: tokenId, newHolder: thirdParty.ethAddress, }); const transferHolder: TitleEscrowNominateBeneficiaryCommand = { - ...defaultTransferBeneficiary, + ...defaultE2ETransferBeneficiary, tokenId, tokenRegistry, }; const command = generateEndorseTransferOwnerCommand(transferHolder, thirdParty.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } }; diff --git a/src/e2e/all.ts b/src/e2e/index.ts similarity index 100% rename from src/e2e/all.ts rename to src/e2e/index.ts diff --git a/src/e2e/mint.e2e.ts b/src/e2e/mint.e2e.ts index 90beed9a..96090801 100644 --- a/src/e2e/mint.e2e.ts +++ b/src/e2e/mint.e2e.ts @@ -5,10 +5,16 @@ import { TokenRegistryIssueCommand } from "../commands/token-registry/token-regi import { generateMintTitleEscrowCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; -import { deployTokenRegistry, validateMintData, MintData, checkFailure, checkMintSuccess } from "./utils/helpers"; +import { + deployE2ETokenRegistry, + validateE2EMintData, + E2EMintData, + checkE2EFailure, + checkE2EMintSuccess, +} from "./utils/helpers"; export const mint = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to mint title-escrow on token-registry" { @@ -22,8 +28,8 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - const mintResults = checkMintSuccess(results); - validateMintData(titleEscrowParameter as MintData, mintResults); + const mintResults = checkE2EMintSuccess(results); + validateE2EMintData(titleEscrowParameter as E2EMintData, mintResults); const signer = await getSigner(titleEscrowParameter.network, owner.privateKey); const titleEscrowInfo = await retrieveTitleEscrow( @@ -56,8 +62,8 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - const mintResults = checkMintSuccess(results); - validateMintData(titleEscrowParameter as MintData, mintResults); + const mintResults = checkE2EMintSuccess(results); + validateE2EMintData(titleEscrowParameter as E2EMintData, mintResults); const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); const titleEscrowInfo = await retrieveTitleEscrow( @@ -90,8 +96,8 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - const mintResults = checkMintSuccess(results); - validateMintData(titleEscrowParameter as MintData, mintResults); + const mintResults = checkE2EMintSuccess(results); + validateE2EMintData(titleEscrowParameter as E2EMintData, mintResults); const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); const titleEscrowInfo = await retrieveTitleEscrow( @@ -124,8 +130,8 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - const mintResults = checkMintSuccess(results); - validateMintData(titleEscrowParameter as MintData, mintResults); + const mintResults = checkE2EMintSuccess(results); + validateE2EMintData(titleEscrowParameter as E2EMintData, mintResults); const signer = await getSigner(titleEscrowParameter.network, receiver.privateKey); const titleEscrowInfo = await retrieveTitleEscrow( @@ -157,7 +163,7 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - checkFailure(results, "invalid BigNumber string"); + checkE2EFailure(results, "invalid BigNumber string"); } //"should fail with invalid token registry" @@ -172,7 +178,7 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should fail with invalid beneficiary" @@ -187,7 +193,7 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkE2EFailure(results, "missing revert data in call exception"); } //"should fail with invalid holder" @@ -202,6 +208,6 @@ export const mint = async (): Promise => { }; const command = generateMintTitleEscrowCommand(titleEscrowParameter, owner.privateKey); const results = run(command); - checkFailure(results, "missing revert data in call exception"); + checkE2EFailure(results, "missing revert data in call exception"); } }; diff --git a/src/e2e/nominate.e2e.ts b/src/e2e/nominate.e2e.ts index 570d44e2..58f2118b 100644 --- a/src/e2e/nominate.e2e.ts +++ b/src/e2e/nominate.e2e.ts @@ -4,20 +4,20 @@ import { TitleEscrowNominateBeneficiaryCommand } from "../commands/title-escrow/ import { generateNominateCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { - changeHolderToken, - checkFailure, - checkNominateSuccess, - defaultNominateBeneficiary, - deployTokenRegistry, - mintTokenRegistry, + changeHolderE2EToken, + checkE2EFailure, + checkE2ENominateSuccess, + defaultE2ENominateBeneficiary, + deployE2ETokenRegistry, + mintE2ETokenRegistry, } from "./utils/helpers"; export const nominate = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to nominate title-escrow on token-registry" { - const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId, tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { tokenId, tokenRegistry, @@ -26,7 +26,7 @@ export const nominate = async (): Promise => { }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - const nominateInfo = checkNominateSuccess(results); + const nominateInfo = checkE2ENominateSuccess(results); if (!(nominateInfo.tokenId === nominateParameter.tokenId)) throw new Error(`nominateInfo.tokenId === nominateParameter.tokenId`); if (!(nominateInfo.nominee === nominateParameter.newBeneficiary)) @@ -43,22 +43,22 @@ export const nominate = async (): Promise => { //"should be able to cancel nomination of title-escrow on token-registry" { - const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId, tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const transferReceiverNominee: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId, tokenRegistry, }; const receiverNominateCommand = generateNominateCommand(transferReceiverNominee, owner.privateKey); const receiverNominateResults = run(receiverNominateCommand); - checkNominateSuccess(receiverNominateResults); + checkE2ENominateSuccess(receiverNominateResults); const transferBurnNominee = { ...transferReceiverNominee, newBeneficiary: BurnAddress, }; const command = generateNominateCommand(transferBurnNominee, owner.privateKey); const results = run(command); - const nominateInfo = checkNominateSuccess(results); + const nominateInfo = checkE2ENominateSuccess(results); if (!(nominateInfo.tokenId === transferBurnNominee.tokenId)) throw new Error(`nominateInfo.tokenId === transferBurnNominee.tokenId`); if (!(nominateInfo.nominee === transferBurnNominee.newBeneficiary)) @@ -75,75 +75,75 @@ export const nominate = async (): Promise => { //"should not be able to nominate self" { - const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId, tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId, tokenRegistry, newBeneficiary: owner.ethAddress, }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, "Destination wallet already has the rights as beneficiary"); + checkE2EFailure(results, "Destination wallet already has the rights as beneficiary"); } //"should not be able to nominate unowned token" { - const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId, tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId, tokenRegistry, newBeneficiary: receiver.ethAddress, }; const command = generateNominateCommand(nominateParameter, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to nominate token as holder" { - const { tokenId, tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); - changeHolderToken(owner.privateKey, { - ...defaultNominateBeneficiary, + const { tokenId, tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); + changeHolderE2EToken(owner.privateKey, { + ...defaultE2ENominateBeneficiary, newHolder: receiver.ethAddress, tokenId, tokenRegistry, }); const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId, tokenRegistry, newBeneficiary: thirdParty.ethAddress, }; const command = generateNominateCommand(nominateParameter, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to nominate non-existent token" { const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", tokenRegistry: tokenRegistryAddress, newBeneficiary: receiver.ethAddress, }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, "Unminted Token"); + checkE2EFailure(results, "Unminted Token"); } // "should not be able to nominate non-existent token registry" { const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId: "0x0000000000000000000000000000000000000000000000000000000000000000", tokenRegistry: "0x0000000000000000000000000000000000000000", newBeneficiary: receiver.ethAddress, }; const command = generateNominateCommand(nominateParameter, owner.privateKey); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } }; diff --git a/src/e2e/reject-surrender.e2e.ts b/src/e2e/reject-surrender.e2e.ts index 5fca3e35..1b65e25a 100644 --- a/src/e2e/reject-surrender.e2e.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -2,13 +2,13 @@ import { run } from "./utils/shell"; import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from "./utils/constants"; import { generateRejectSurrenderCommand } from "./utils/commands"; -import { checkFailure, deployTokenRegistry, mintSurrenderToken, mintTokenRegistry } from "./utils/helpers"; -import { checkSurrenderRejectSuccess } from "./utils/helpers"; +import { checkE2EFailure, deployE2ETokenRegistry, mintSurrenderE2EToken, mintE2ETokenRegistry } from "./utils/helpers"; +import { checkE2ESurrenderRejectSuccess } from "./utils/helpers"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; export const rejectSurrender = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); const defaultTitleEscrow = { ...defaultRunParameters, @@ -18,14 +18,14 @@ export const rejectSurrender = async (): Promise => { //"should be able to reject surrender title-escrow on token-registry" { - const { tokenRegistry, tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const signer = await getSigner(defaultTitleEscrow.network, owner.privateKey); const command = generateRejectSurrenderCommand({ tokenRegistry, tokenId, ...defaultTitleEscrow }, owner.privateKey); let titleEscrowOwner: string = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); if (!(titleEscrowOwner === tokenRegistry)) throw new Error(`titleEscrowOwner === tokenRegistry`); const results = run(command); - checkSurrenderRejectSuccess(results); + checkE2ESurrenderRejectSuccess(results); titleEscrowOwner = await retrieveTitleEscrowOwner(signer, tokenRegistry, tokenId); if (!(isAddress(titleEscrowOwner) === true)) throw new Error(`isAddress(titleEscrowOwner) === true`); if (!(titleEscrowOwner !== tokenRegistry)) throw new Error(`titleEscrowOwner !== tokenRegistry`); @@ -33,45 +33,45 @@ export const rejectSurrender = async (): Promise => { //"should not be able to reject surrender invalid title-escrow on token-registry" { - const { tokenRegistry } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand( { tokenRegistry, tokenId: EmptyTokenID, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, "Unminted Token"); + checkE2EFailure(results, "Unminted Token"); } //"should not be able to reject surrender title-escrow on invalid token-registry" { - const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand( { tokenRegistry: BurnAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } //"should not be able to accept un-owned/held surrendered title-escrow on invalid token-registry" { - const { tokenId } = mintSurrenderToken(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintSurrenderE2EToken(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand( { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, receiver.privateKey ); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } //"should not be able to accept un-surrendered title-escrow on token-registry" { - const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const command = generateRejectSurrenderCommand( { tokenRegistry: tokenRegistryAddress, tokenId, ...defaultTitleEscrow }, owner.privateKey ); const results = run(command); - checkFailure(results, "Title Escrow has not been surrendered"); + checkE2EFailure(results, "Title Escrow has not been surrendered"); } }; diff --git a/src/e2e/surrender.e2e.ts b/src/e2e/surrender.e2e.ts index 921593db..b7e233a8 100644 --- a/src/e2e/surrender.e2e.ts +++ b/src/e2e/surrender.e2e.ts @@ -5,12 +5,12 @@ import { generateSurrenderCommand } from "./utils/commands"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; import { - deployTokenRegistry, - mintTokenRegistry, - checkSurrenderSuccess, - checkFailure, - changeHolderToken, - nominateAndEndorseBeneficiary, + deployE2ETokenRegistry, + mintE2ETokenRegistry, + checkE2ESurrenderSuccess, + checkE2EFailure, + changeHolderE2EToken, + nominateAndEndorseE2EBeneficiary, } from "./utils/helpers"; const defaultTitleEscrow = { @@ -20,11 +20,11 @@ const defaultTitleEscrow = { }; export const surrender = async (): Promise => { - const tokenRegistryAddress = deployTokenRegistry(owner.privateKey); + const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); // "should be able to surrender title-escrow" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -45,7 +45,7 @@ export const surrender = async (): Promise => { } const command = generateSurrenderCommand(surrenderTitleEscrow, owner.privateKey); const results = run(command); - const surrenderResults = checkSurrenderSuccess(results); + const surrenderResults = checkE2ESurrenderSuccess(results); if (surrenderResults.tokenId !== surrenderTitleEscrow.tokenId) { throw new Error(`(surrenderResults.tokenId !== surrenderTitleEscrow.tokenId);`); } @@ -61,7 +61,7 @@ export const surrender = async (): Promise => { // "Should not be able to surrender unowned title-escrow" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -70,19 +70,19 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender title-escrow as beneficiary" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, tokenRegistry, tokenId, }; - nominateAndEndorseBeneficiary(owner.privateKey, { + nominateAndEndorseE2EBeneficiary(owner.privateKey, { ...defaultTitleEscrow, tokenId, tokenRegistry, @@ -90,19 +90,19 @@ export const surrender = async (): Promise => { }); const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender title-escrow as holder" { - const { tokenRegistry, tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry, tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, tokenRegistry, tokenId, }; - changeHolderToken(owner.privateKey, { + changeHolderE2EToken(owner.privateKey, { ...defaultTitleEscrow, tokenId, tokenRegistry, @@ -110,12 +110,12 @@ export const surrender = async (): Promise => { }); const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "Wallet lack the rights for the transfer operation"); + checkE2EFailure(results, "Wallet lack the rights for the transfer operation"); } // "Should not be able to surrender invalid title-escrow" { - const { tokenRegistry } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenRegistry } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -124,12 +124,12 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, "Unminted Token"); + checkE2EFailure(results, "Unminted Token"); } // "Should not be able to surrender invalid token-registry" { - const { tokenId } = mintTokenRegistry(owner.privateKey, tokenRegistryAddress); + const { tokenId } = mintE2ETokenRegistry(owner.privateKey, tokenRegistryAddress); const surrenderTitleEscrow: BaseTitleEscrowCommand = { ...defaultTitleEscrow, @@ -138,6 +138,6 @@ export const surrender = async (): Promise => { }; const command = generateSurrenderCommand(surrenderTitleEscrow, receiver.privateKey); const results = run(command); - checkFailure(results, `Address ${BurnAddress} is not a valid Contract`); + checkE2EFailure(results, `Address ${BurnAddress} is not a valid Contract`); } }; diff --git a/src/e2e/utils/constants.ts b/src/e2e/utils/constants.ts index 047e866a..65bac013 100644 --- a/src/e2e/utils/constants.ts +++ b/src/e2e/utils/constants.ts @@ -1,4 +1,3 @@ -// import { NonceManager } from "@ethersproject/experimental"; import { constants } from "@govtechsg/token-registry"; export const { contractAddress } = constants; diff --git a/src/e2e/utils/helpers/accept-surrender.ts b/src/e2e/utils/helpers/accept-surrender.ts index 8c43751e..5aa87e93 100644 --- a/src/e2e/utils/helpers/accept-surrender.ts +++ b/src/e2e/utils/helpers/accept-surrender.ts @@ -3,29 +3,29 @@ import { generateAcceptSurrenderCommand } from "../commands"; import { defaultRunParameters, EndStatus, TokenIdLength } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -import { mintSurrenderToken, surrenderToken } from "./surrender"; +import { mintSurrenderE2EToken, surrenderE2EToken } from "./surrender"; -export const mintBurntToken = ( +export const mintBurntE2EToken = ( privateKey: string, tokenRegistryAddress?: string ): { tokenId: string; tokenRegistry: string } => { - const { tokenId, tokenRegistry } = mintSurrenderToken(privateKey, tokenRegistryAddress); - burnSurrenderedToken(privateKey, { tokenRegistry, tokenId, ...defaultRunParameters }); + const { tokenId, tokenRegistry } = mintSurrenderE2EToken(privateKey, tokenRegistryAddress); + burnSurrenderedE2EToken(privateKey, { tokenRegistry, tokenId, ...defaultRunParameters }); return { tokenId, tokenRegistry }; }; -export const burnSurrenderedToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { +export const burnSurrenderedE2EToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { const command = generateAcceptSurrenderCommand(acceptSurrender, privateKey); const results = run(command); - checkSurrenderAcceptSuccess(results); + checkE2ESurrenderAcceptSuccess(results); }; -export const burnToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { - surrenderToken(privateKey, acceptSurrender); - burnSurrenderedToken(privateKey, acceptSurrender); +export const burnE2EToken = (privateKey: string, acceptSurrender: BaseTitleEscrowCommand): void => { + surrenderE2EToken(privateKey, acceptSurrender); + burnSurrenderedE2EToken(privateKey, acceptSurrender); }; -export const checkSurrenderAcceptSuccess = (results: string): { tokenId: string } => { +export const checkE2ESurrenderAcceptSuccess = (results: string): { tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/helpers/change-holder.ts b/src/e2e/utils/helpers/change-holder.ts index 72a1749b..e6ad4a26 100644 --- a/src/e2e/utils/helpers/change-holder.ts +++ b/src/e2e/utils/helpers/change-holder.ts @@ -5,12 +5,12 @@ import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -export const defaultTransferHolder = { +export const defaultE2ETransferHolder = { ...defaultRunParameters, newHolder: receiver.ethAddress, }; -export const checkChangeHolderSuccess = (results: string): { newHolder: string; tokenId: string } => { +export const checkE2EChangeHolderSuccess = (results: string): { newHolder: string; tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); if (statusLine.length <= 0) throw new Error("Change Holder failed"); const titleEscrowAddressLine = statusLine[0].lineContent; @@ -29,8 +29,8 @@ export const checkChangeHolderSuccess = (results: string): { newHolder: string; }; }; -export const changeHolderToken = (privateKey: string, transferHolder: TitleEscrowTransferHolderCommand): void => { +export const changeHolderE2EToken = (privateKey: string, transferHolder: TitleEscrowTransferHolderCommand): void => { const command = generateChangeHolderCommand(transferHolder, privateKey); const results = run(command); - checkChangeHolderSuccess(results); + checkE2EChangeHolderSuccess(results); }; diff --git a/src/e2e/utils/helpers/common.ts b/src/e2e/utils/helpers/common.ts index a727d91f..da389f9b 100644 --- a/src/e2e/utils/helpers/common.ts +++ b/src/e2e/utils/helpers/common.ts @@ -1,7 +1,7 @@ import { EndStatus } from "../constants"; import { extractStatus } from "../shell"; -export const checkFailure = (results: string, expectedErrorMessage: string): void => { +export const checkE2EFailure = (results: string, expectedErrorMessage: string): void => { const statusMessage = extractStatus(results, EndStatus.error); if (!(statusMessage.length > 0)) throw new Error(`!statusMessage.length > 0`); const errorMessage = statusMessage[0].lineContent.substring(13); diff --git a/src/e2e/utils/helpers/deploy.ts b/src/e2e/utils/helpers/deploy.ts index 51da7d9d..9d087aca 100644 --- a/src/e2e/utils/helpers/deploy.ts +++ b/src/e2e/utils/helpers/deploy.ts @@ -4,7 +4,7 @@ import { generateDeployTokenRegistryCommand } from "../commands"; import { defaultRunParameters, creators, EndStatus, AddressLength } from "../constants"; import { extractStatus, run } from "../shell"; -export const defaultTokenRegistry = { +export const defaultE2ETokenRegistryParams = { ...defaultRunParameters, factoryAddress: creators.titleEscrowFactory, tokenImplementationAddress: creators.tokenImplementation, @@ -15,7 +15,7 @@ const numberGenerator = (range: number): number => { return Math.floor(Math.random() * range); }; -export const checkTokenRegistrySuccess = (results: string): string => { +export const checkE2ETokenRegistrySuccess = (results: string): string => { const statusLine = extractStatus(results, EndStatus.success, "Token registry deployed at "); if (statusLine.length <= 0) throw new Error("Deployment failed"); const tokenRegistryDeploymentLine = statusLine[0].lineContent; @@ -26,20 +26,20 @@ export const checkTokenRegistrySuccess = (results: string): string => { return tokenRegistry; }; -export const deployTokenRegistry = ( +export const deployE2ETokenRegistry = ( privateKey: string, tokenRegistryParameters?: DeployTokenRegistryCommand ): string => { if (!tokenRegistryParameters) { const index = numberGenerator(100); tokenRegistryParameters = { - ...defaultTokenRegistry, + ...defaultE2ETokenRegistryParams, registryName: `Test Token ${index}`, registrySymbol: `TKN${index}`, }; } const command = generateDeployTokenRegistryCommand(tokenRegistryParameters, privateKey); const results = run(command); - const tokenRegistryAddress = checkTokenRegistrySuccess(results); + const tokenRegistryAddress = checkE2ETokenRegistrySuccess(results); return tokenRegistryAddress; }; diff --git a/src/e2e/utils/helpers/endorse-beneficiary.ts b/src/e2e/utils/helpers/endorse-beneficiary.ts index 342f13dd..fbbab2fa 100644 --- a/src/e2e/utils/helpers/endorse-beneficiary.ts +++ b/src/e2e/utils/helpers/endorse-beneficiary.ts @@ -4,31 +4,31 @@ import { generateEndorseTransferOwnerCommand } from "../commands"; import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -import { nominateToken } from "./nominate"; +import { nominateE2EToken } from "./nominate"; -export const defaultTransferBeneficiary = { +export const defaultE2ETransferBeneficiary = { ...defaultRunParameters, newBeneficiary: receiver.ethAddress, }; -export const nominateAndEndorseBeneficiary = ( +export const nominateAndEndorseE2EBeneficiary = ( privateKey: string, transferBeneficiary: TitleEscrowNominateBeneficiaryCommand ): void => { - nominateToken(privateKey, transferBeneficiary); - endorseBeneficiary(privateKey, transferBeneficiary); + nominateE2EToken(privateKey, transferBeneficiary); + endorseE2EBeneficiary(privateKey, transferBeneficiary); }; -export const endorseBeneficiary = ( +export const endorseE2EBeneficiary = ( privateKey: string, transferBeneficiary: TitleEscrowNominateBeneficiaryCommand ): void => { const command = generateEndorseTransferOwnerCommand(transferBeneficiary, privateKey); const results = run(command); - checkEndorseBeneficiary(results); + checkE2EEndorseBeneficiary(results); }; -export const checkEndorseBeneficiary = (results: string): { beneficiary: string; tokenId: string } => { +export const checkE2EEndorseBeneficiary = (results: string): { beneficiary: string; tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); if (statusLine.length <= 0) throw new Error("Minting failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/helpers/endorse-owners.ts b/src/e2e/utils/helpers/endorse-owners.ts index fb52e758..7a4d923a 100644 --- a/src/e2e/utils/helpers/endorse-owners.ts +++ b/src/e2e/utils/helpers/endorse-owners.ts @@ -3,7 +3,7 @@ import { AddressLength, EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; -export const checkEndorseOwner = (results: string): { beneficiary: string; holder: string; tokenId: string } => { +export const checkE2EEndorseOwner = (results: string): { beneficiary: string; holder: string; tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); if (statusLine.length <= 0) throw new Error("Minting failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/helpers/mint.ts b/src/e2e/utils/helpers/mint.ts index 992571cd..5a917f79 100644 --- a/src/e2e/utils/helpers/mint.ts +++ b/src/e2e/utils/helpers/mint.ts @@ -1,20 +1,20 @@ import { Wallet } from "ethers"; import { isAddress } from "web3-utils"; -import { deployTokenRegistry } from "."; +import { deployE2ETokenRegistry } from "."; import { TokenRegistryIssueCommand } from "../../../commands/token-registry/token-registry-command.type"; import { generateMintTitleEscrowCommand } from "../commands"; import { AddressLength, defaultRunParameters, EndStatus, TokenIdLength, TokenInfo } from "../constants"; import { extractStatus, run } from "../shell"; import { generateTokenId, isTokenId } from "../token-management"; -export interface MintData { +export interface E2EMintData { tokenId: string; address: string; beneficiary: string; holder: string; } -export const validateMintData = (expectedValue: MintData, value: MintData): void => { +export const validateE2EMintData = (expectedValue: E2EMintData, value: E2EMintData): void => { if (!(expectedValue.address === value.address)) throw new Error(`expectedValue.address === value.address`); if (!(expectedValue.beneficiary === value.beneficiary)) throw new Error(`expectedValue.beneficiary === value.beneficiary`); @@ -22,9 +22,9 @@ export const validateMintData = (expectedValue: MintData, value: MintData): void if (!(expectedValue.tokenId === value.tokenId)) throw new Error(`expectedValue.tokenId === value.tokenId`); }; -export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { +export const mintE2ETokenRegistry = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { if (!tokenRegistryAddress) { - tokenRegistryAddress = deployTokenRegistry(privateKey); + tokenRegistryAddress = deployE2ETokenRegistry(privateKey); } if (!isAddress(tokenRegistryAddress)) throw new Error("Invalid Token Registry Address"); const wallet = new Wallet(privateKey); @@ -36,10 +36,10 @@ export const mintTokenRegistry = (privateKey: string, tokenRegistryAddress?: str tokenId: generateTokenId(), }; - return mintToken(privateKey, titleEscrowParameter); + return mintE2EToken(privateKey, titleEscrowParameter); }; -export const checkMintSuccess = (results: string): MintData => { +export const checkE2EMintSuccess = (results: string): E2EMintData => { const statusLine = extractStatus(results, EndStatus.success, "Token with hash "); if (statusLine.length <= 0) throw new Error("Minting failed"); const titleEscrowAddressLine = statusLine[0].lineContent; @@ -66,10 +66,10 @@ export const checkMintSuccess = (results: string): MintData => { }; }; -export const mintToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { +export const mintE2EToken = (privateKey: string, titleEscrowParameter: TokenRegistryIssueCommand): TokenInfo => { const command = generateMintTitleEscrowCommand(titleEscrowParameter, privateKey); const results = run(command); - const { address: tokenRegistry, tokenId } = checkMintSuccess(results); + const { address: tokenRegistry, tokenId } = checkE2EMintSuccess(results); return { tokenRegistry, tokenId, diff --git a/src/e2e/utils/helpers/nominate.ts b/src/e2e/utils/helpers/nominate.ts index 71477af1..612d6dd2 100644 --- a/src/e2e/utils/helpers/nominate.ts +++ b/src/e2e/utils/helpers/nominate.ts @@ -1,36 +1,43 @@ import { isAddress } from "web3-utils"; -import { mintTokenRegistry } from "."; +import { mintE2ETokenRegistry } from "."; import { TitleEscrowNominateBeneficiaryCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { generateNominateCommand } from "../commands"; import { AddressLength, defaultRunParameters, EndStatus, receiver, TokenIdLength, TokenInfo } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -export const defaultNominateBeneficiary = { +export const defaultE2ENominateBeneficiary = { ...defaultRunParameters, newBeneficiary: receiver.ethAddress, }; -export const mintNominatedToken = (privateKey: string, nominee: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); +export const mintNominatedE2EToken = ( + privateKey: string, + nominee: string, + tokenRegistryAddress?: string +): TokenInfo => { + const tokenDetails = mintE2ETokenRegistry(privateKey, tokenRegistryAddress); const { tokenRegistry, tokenId } = tokenDetails; const nominateParameter: TitleEscrowNominateBeneficiaryCommand = { - ...defaultNominateBeneficiary, + ...defaultE2ENominateBeneficiary, tokenId: tokenId, tokenRegistry: tokenRegistry, newBeneficiary: nominee, }; - nominateToken(privateKey, nominateParameter); + nominateE2EToken(privateKey, nominateParameter); return tokenDetails; }; -export const nominateToken = (privateKey: string, nominateParameter: TitleEscrowNominateBeneficiaryCommand): void => { +export const nominateE2EToken = ( + privateKey: string, + nominateParameter: TitleEscrowNominateBeneficiaryCommand +): void => { const command = generateNominateCommand(nominateParameter, privateKey); const results = run(command); - checkNominateSuccess(results); + checkE2ENominateSuccess(results); }; -export const checkNominateSuccess = (results: string): { nominee: string; tokenId: string } => { +export const checkE2ENominateSuccess = (results: string): { nominee: string; tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); if (statusLine.length <= 0) throw new Error("Nomination failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/helpers/reject-surrender.ts b/src/e2e/utils/helpers/reject-surrender.ts index 97a5c4fb..43e04b4c 100644 --- a/src/e2e/utils/helpers/reject-surrender.ts +++ b/src/e2e/utils/helpers/reject-surrender.ts @@ -2,7 +2,7 @@ import { EndStatus, TokenIdLength } from "../constants"; import { extractStatus } from "../shell"; import { isTokenId } from "../token-management"; -export const checkSurrenderRejectSuccess = (results: string): { tokenId: string } => { +export const checkE2ESurrenderRejectSuccess = (results: string): { tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Surrendered transferable record with hash "); if (statusLine.length <= 0) throw new Error("Surrender Reject failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/helpers/surrender.ts b/src/e2e/utils/helpers/surrender.ts index 78f16873..3c9826b6 100644 --- a/src/e2e/utils/helpers/surrender.ts +++ b/src/e2e/utils/helpers/surrender.ts @@ -1,35 +1,35 @@ -import { mintTokenRegistry } from "."; +import { mintE2ETokenRegistry } from "."; import { BaseTitleEscrowCommand } from "../../../commands/title-escrow/title-escrow-command.type"; import { generateSurrenderCommand } from "../commands"; import { defaultRunParameters, EndStatus, owner, TokenIdLength, TokenInfo } from "../constants"; import { extractStatus, run } from "../shell"; import { isTokenId } from "../token-management"; -const defaultTitleEscrow = { +const defaultE2ETitleEscrow = { ...defaultRunParameters, beneficiary: owner.ethAddress, holder: owner.ethAddress, }; -export const mintSurrenderToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { - const tokenDetails = mintTokenRegistry(privateKey, tokenRegistryAddress); +export const mintSurrenderE2EToken = (privateKey: string, tokenRegistryAddress?: string): TokenInfo => { + const tokenDetails = mintE2ETokenRegistry(privateKey, tokenRegistryAddress); const { tokenRegistry, tokenId } = tokenDetails; const surrenderParameter: BaseTitleEscrowCommand = { - ...defaultTitleEscrow, + ...defaultE2ETitleEscrow, tokenRegistry: tokenRegistry, tokenId: tokenId, }; - surrenderToken(privateKey, surrenderParameter); + surrenderE2EToken(privateKey, surrenderParameter); return tokenDetails; }; -export const surrenderToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { +export const surrenderE2EToken = (privateKey: string, surrenderParameter: BaseTitleEscrowCommand): void => { const command = generateSurrenderCommand(surrenderParameter, privateKey); const results = run(command); - checkSurrenderSuccess(results); + checkE2ESurrenderSuccess(results); }; -export const checkSurrenderSuccess = (results: string): { tokenId: string } => { +export const checkE2ESurrenderSuccess = (results: string): { tokenId: string } => { const statusLine = extractStatus(results, EndStatus.success, "Transferable record with hash "); if (statusLine.length <= 0) throw new Error("Nomination failed"); const titleEscrowAddressLine = statusLine[0].lineContent; diff --git a/src/e2e/utils/shell.ts b/src/e2e/utils/shell.ts index 10aaa9c5..0c7fb23f 100644 --- a/src/e2e/utils/shell.ts +++ b/src/e2e/utils/shell.ts @@ -30,7 +30,7 @@ export const extractStatus = (results: string, expectedStatus: EndStatusType, ex return lineInfo; }; -export const printLines = (lines: LineInfo[]): void => { +const printLines = (lines: LineInfo[]): void => { lines.sort((a: LineInfo, b: LineInfo): number => { return a.lineNumber - b.lineNumber; }); @@ -39,7 +39,7 @@ export const printLines = (lines: LineInfo[]): void => { } }; -export const extractLine = (result: string, query: string): LineInfo[] | void => { +const extractLine = (result: string, query: string): LineInfo[] | void => { const splitResults = result.trim().split("\n"); const matchedLines = []; for (let count = 0; count < splitResults.length; count++) { @@ -57,21 +57,22 @@ export const extractLine = (result: string, query: string): LineInfo[] | void => }; // https://github.com/chalk/strip-ansi/blob/main/index.js -export function stripAnsi(ansiString: string): string { +const stripAnsi = (ansiString: string): string => { if (typeof ansiString !== "string") { - throw new TypeError(`Expected a \`string\`, got \`${typeof ansiString}\``); + const errorMessage = `Expected a \`string\`, got \`${typeof ansiString}\``; + throw new TypeError(errorMessage); } return ansiString.replace(ansiRegex(), ""); -} +}; // https://github.com/chalk/ansi-regex/blob/main/index.js -export function ansiRegex({ onlyFirst = false } = {}): RegExp { +const ansiRegex = ({ onlyFirst = false } = {}): RegExp => { const pattern = [ "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", ].join("|"); return new RegExp(pattern, onlyFirst ? undefined : "g"); -} +}; -export { shell, ShellString }; +// export { shell, ShellString }; From 49137d73a0c0a7e9585515223dc34c7bbc40c73f Mon Sep 17 00:00:00 2001 From: Puay Hiang <68947167+puayhiang@users.noreply.github.com> Date: Wed, 1 Feb 2023 13:03:33 +0800 Subject: [PATCH 63/63] fix: rename e2e functions --- src/e2e/accept-surrender.e2e.ts | 2 +- src/e2e/change-holder.e2e.ts | 2 +- src/e2e/deploy.e2e.ts | 4 +-- src/e2e/endorse-change-owner.e2e.ts | 2 +- src/e2e/endorse-transfer.e2e.ts | 2 +- src/e2e/index.ts | 38 ++++++++++++++--------------- src/e2e/mint.e2e.ts | 2 +- src/e2e/nominate.e2e.ts | 2 +- src/e2e/reject-surrender.e2e.ts | 2 +- src/e2e/surrender.e2e.ts | 2 +- 10 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/e2e/accept-surrender.e2e.ts b/src/e2e/accept-surrender.e2e.ts index 3f1acea9..f71cfd15 100644 --- a/src/e2e/accept-surrender.e2e.ts +++ b/src/e2e/accept-surrender.e2e.ts @@ -10,7 +10,7 @@ import { BurnAddress, defaultRunParameters, EmptyTokenID, owner, receiver } from import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { run } from "./utils/shell"; -export const acceptSurrender = async (): Promise => { +export const acceptE2Esurrender = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); // const errors: Error[] = []; const defaultTitleEscrow = { diff --git a/src/e2e/change-holder.e2e.ts b/src/e2e/change-holder.e2e.ts index 442a9800..696f7fbf 100644 --- a/src/e2e/change-holder.e2e.ts +++ b/src/e2e/change-holder.e2e.ts @@ -16,7 +16,7 @@ import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; // "transfer holder title-escrow" -export const changeHolder = async (): Promise => { +export const changeE2EHolder = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //should be able to transfer holder title-escrow on token-registry" diff --git a/src/e2e/deploy.e2e.ts b/src/e2e/deploy.e2e.ts index 1579e22d..75c41e2a 100644 --- a/src/e2e/deploy.e2e.ts +++ b/src/e2e/deploy.e2e.ts @@ -6,7 +6,7 @@ import { generateDeployDocumentStoreCommand, generateDeployTokenRegistryCommand import { getSigner, retrieveTokenInfo, rolesCheck } from "./utils/contract-checks"; import { checkE2ETokenRegistrySuccess, defaultE2ETokenRegistryParams } from "./utils/helpers"; -export const deployTokenRegistry = async (): Promise => { +export const deployE2ETokenRegistry = async (): Promise => { //should be able to deploy token-registry" { const tokenRegistryParameter: DeployTokenRegistryCommand = { @@ -42,7 +42,7 @@ export const deployTokenRegistry = async (): Promise => { } }; -export const deployDocumentStore = async (): Promise => { +export const deployE2EDocumentStore = async (): Promise => { //should be able to deploy document-store { const documentStoreParameters: DeployDocumentStoreCommand = { diff --git a/src/e2e/endorse-change-owner.e2e.ts b/src/e2e/endorse-change-owner.e2e.ts index 9af962f2..77de2cc4 100644 --- a/src/e2e/endorse-change-owner.e2e.ts +++ b/src/e2e/endorse-change-owner.e2e.ts @@ -16,7 +16,7 @@ import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; // "endorse change owner title-escrow" -export const endorseChangeOwner = async (): Promise => { +export const endorseE2EChangeOwner = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); const defaultTransferOwners = { diff --git a/src/e2e/endorse-transfer.e2e.ts b/src/e2e/endorse-transfer.e2e.ts index df0389b3..b93228d2 100644 --- a/src/e2e/endorse-transfer.e2e.ts +++ b/src/e2e/endorse-transfer.e2e.ts @@ -16,7 +16,7 @@ import { run } from "./utils/shell"; import { getSigner, retrieveTitleEscrow } from "./utils/contract-checks"; import { BigNumber } from "ethers"; -export const endorseTransfer = async (): Promise => { +export const endorseE2ETransfer = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to endorse transfer title-escrow on token-registry" diff --git a/src/e2e/index.ts b/src/e2e/index.ts index a01b2945..6678446e 100644 --- a/src/e2e/index.ts +++ b/src/e2e/index.ts @@ -1,28 +1,28 @@ -import { acceptSurrender } from "./accept-surrender.e2e"; -import { surrender } from "./surrender.e2e"; -import { changeHolder } from "./change-holder.e2e"; -import { deployDocumentStore, deployTokenRegistry } from "./deploy.e2e"; -import { endorseTransfer } from "./endorse-transfer.e2e"; -import { mint } from "./mint.e2e"; -import { nominate } from "./nominate.e2e"; -import { rejectSurrender } from "./reject-surrender.e2e"; -import { endorseChangeOwner } from "./endorse-change-owner.e2e"; +import { acceptE2Esurrender } from "./accept-surrender.e2e"; +import { surrenderE2EToken } from "./surrender.e2e"; +import { changeE2EHolder } from "./change-holder.e2e"; +import { deployE2EDocumentStore, deployE2ETokenRegistry } from "./deploy.e2e"; +import { endorseE2ETransfer } from "./endorse-transfer.e2e"; +import { mintE2EToken } from "./mint.e2e"; +import { nominateE2E } from "./nominate.e2e"; +import { rejectE2ESurrender } from "./reject-surrender.e2e"; +import { endorseE2EChangeOwner as endorseE2EChangeOwner } from "./endorse-change-owner.e2e"; const awaitForDuration = async (runFunction: () => void): Promise => { await runFunction(); console.log(runFunction.name); }; -awaitForDuration(deployDocumentStore); -awaitForDuration(deployTokenRegistry); +awaitForDuration(deployE2EDocumentStore); +awaitForDuration(deployE2ETokenRegistry); -awaitForDuration(mint); +awaitForDuration(mintE2EToken); -awaitForDuration(surrender); -awaitForDuration(rejectSurrender); -awaitForDuration(acceptSurrender); +awaitForDuration(surrenderE2EToken); +awaitForDuration(rejectE2ESurrender); +awaitForDuration(acceptE2Esurrender); -awaitForDuration(nominate); -awaitForDuration(changeHolder); -awaitForDuration(endorseChangeOwner); -awaitForDuration(endorseTransfer); +awaitForDuration(nominateE2E); +awaitForDuration(changeE2EHolder); +awaitForDuration(endorseE2EChangeOwner); +awaitForDuration(endorseE2ETransfer); diff --git a/src/e2e/mint.e2e.ts b/src/e2e/mint.e2e.ts index 96090801..3a92d2f0 100644 --- a/src/e2e/mint.e2e.ts +++ b/src/e2e/mint.e2e.ts @@ -13,7 +13,7 @@ import { checkE2EMintSuccess, } from "./utils/helpers"; -export const mint = async (): Promise => { +export const mintE2EToken = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to mint title-escrow on token-registry" diff --git a/src/e2e/nominate.e2e.ts b/src/e2e/nominate.e2e.ts index 58f2118b..96fce166 100644 --- a/src/e2e/nominate.e2e.ts +++ b/src/e2e/nominate.e2e.ts @@ -12,7 +12,7 @@ import { mintE2ETokenRegistry, } from "./utils/helpers"; -export const nominate = async (): Promise => { +export const nominateE2E = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); //"should be able to nominate title-escrow on token-registry" diff --git a/src/e2e/reject-surrender.e2e.ts b/src/e2e/reject-surrender.e2e.ts index 1b65e25a..c18f980c 100644 --- a/src/e2e/reject-surrender.e2e.ts +++ b/src/e2e/reject-surrender.e2e.ts @@ -7,7 +7,7 @@ import { checkE2ESurrenderRejectSuccess } from "./utils/helpers"; import { getSigner, retrieveTitleEscrowOwner } from "./utils/contract-checks"; import { isAddress } from "web3-utils"; -export const rejectSurrender = async (): Promise => { +export const rejectE2ESurrender = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); const defaultTitleEscrow = { diff --git a/src/e2e/surrender.e2e.ts b/src/e2e/surrender.e2e.ts index b7e233a8..a0b6e9f7 100644 --- a/src/e2e/surrender.e2e.ts +++ b/src/e2e/surrender.e2e.ts @@ -19,7 +19,7 @@ const defaultTitleEscrow = { holder: owner.ethAddress, }; -export const surrender = async (): Promise => { +export const surrenderE2EToken = async (): Promise => { const tokenRegistryAddress = deployE2ETokenRegistry(owner.privateKey); // "should be able to surrender title-escrow"