diff --git a/contracts/_testContracts/OIDImports.sol b/contracts/_testContracts/OIDImports.sol
index f2e9b295..1426a07e 100644
--- a/contracts/_testContracts/OIDImports.sol
+++ b/contracts/_testContracts/OIDImports.sol
@@ -3,6 +3,8 @@ pragma solidity 0.8.17;
import "@onchain-id/solidity/contracts/ClaimIssuer.sol";
import "@onchain-id/solidity/contracts/Identity.sol";
+import "@onchain-id/solidity/contracts/factory/IdFactory.sol";
+import "@onchain-id/solidity/contracts/gateway/Gateway.sol";
import "@onchain-id/solidity/contracts/proxy/ImplementationAuthority.sol";
contract OIDImports {
diff --git a/contracts/factory/ContractsDeployer.sol b/contracts/factory/ContractsDeployer.sol
new file mode 100644
index 00000000..9724cd3b
--- /dev/null
+++ b/contracts/factory/ContractsDeployer.sol
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-3.0
+//
+// :+#####%%%%%%%%%%%%%%+
+// .-*@@@%+.:+%@@@@@%%#***%@@%=
+// :=*%@@@#=. :#@@% *@@@%=
+// .-+*%@%*-.:+%@@@@@@+. -*+: .=#. :%@@@%-
+// :=*@@@@%%@@@@@@@@@%@@@- .=#@@@%@%= =@@@@#.
+// -=+#%@@%#*=:. :%@@@@%. -*@@#*@@@@@@@#=:- *@@@@+
+// =@@%=:. :=: *@@@@@%#- =%*%@@@@#+-. =+ :%@@@%-
+// -@@%. .+@@@ =+=-. @@#- +@@@%- =@@@@%:
+// :@@@. .+@@#%: : .=*=-::.-%@@@+*@@= +@@@@#.
+// %@@: +@%%* =%@@@@@@@@@@@#. .*@%- +@@@@*.
+// #@@= .+@@@@%:=*@@@@@- :%@%: .*@@@@+
+// *@@* +@@@#-@@%-:%@@* +@@#. :%@@@@-
+// -@@% .:-=++*##%%%@@@@@@@@@@@@*. :@+.@@@%: .#@@+ =@@@@#:
+// .@@@*-+*#%%%@@@@@@@@@@@@@@@@%%#**@@%@@@. *@=*@@# :#@%= .#@@@@#-
+// -%@@@@@@@@@@@@@@@*+==-:-@@@= *@# .#@*-=*@@@@%= -%@@@* =@@@@@%-
+// -+%@@@#. %@%%= -@@:+@: -@@* *@@*-:: -%@@%=. .*@@@@@#
+// *@@@* +@* *@@##@@- #@*@@+ -@@= . :+@@@#: .-+@@@%+-
+// +@@@%*@@:..=@@@@* .@@@* .#@#. .=+- .=%@@@*. :+#@@@@*=:
+// =@@@@%@@@@@@@@@@@@@@@@@@@@@@%- :+#*. :*@@@%=. .=#@@@@%+:
+// .%@@= ..... .=#@@+. .#@@@*: -*%@@@@%+.
+// +@@#+===---:::... .=%@@*- +@@@+. -*@@@@@%+.
+// -@@@@@@@@@@@@@@@@@@@@@@%@@@@= -@@@+ -#@@@@@#=.
+// ..:::---===+++***###%%%@@@#- .#@@+ -*@@@@@#=.
+// @@@@@@+. +@@*. .+@@@@@%=.
+// -@@@@@= =@@%: -#@@@@%+.
+// +@@@@@. =@@@= .+@@@@@*:
+// #@@@@#:%@@#. :*@@@@#-
+// @@@@@%@@@= :#@@@@+.
+// :@@@@@@@#.:#@@@%-
+// +@@@@@@-.*@@@*:
+// #@@@@#.=@@@+.
+// @@@@+-%@%=
+// :@@@#%@%=
+// +@@@@%-
+// :#%%=
+//
+/**
+ * NOTICE
+ *
+ * The T-REX software is licensed under a proprietary license or the GPL v.3.
+ * If you choose to receive it under the GPL v.3 license, the following applies:
+ * T-REX is a suite of smart contracts implementing the ERC-3643 standard and
+ * developed by Tokeny to manage and transfer financial assets on EVM blockchains
+ *
+ * Copyright (C) 2023, Tokeny sàrl.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+pragma solidity 0.8.17;
+
+import "../roles/AgentRole.sol";
+
+/// @notice Error thrown when a contract with the same name has already been deployed.
+/// @param addr The address of the previously deployed contract.
+error ContractDeployedAlready(address addr);
+
+contract ContractsDeployer is AgentRole {
+
+ /// @notice Maps a human-readable name to the address of a deployed contract.
+ /// @dev Used to retrieve contract addresses deployed by this deployer.
+ mapping(string => address) private _deployedContracts;
+
+ /// @notice Emitted when a contract is deployed.
+ /// @param name The human-readable name of the deployed contract.
+ /// @param contractAddress The address of the deployed contract.
+ event ContractDeployed(string name, address contractAddress);
+
+
+ /**
+ * @dev Deploys a contract using the create2 opcode, ensuring deterministic address generation.
+ * @param name A human-readable name for the contract, used for referencing in the deployedContracts mapping.
+ * @param bytecode The bytecode of the contract to be deployed.
+ * @return addr The address of the deployed contract.
+ * @notice The function will revert with `ContractDeployedAlready` if a contract with the same name has been deployed.
+ */
+ function deployContract(string memory name, bytes memory bytecode) external onlyAgent returns (address) {
+ bytes32 salt = keccak256(bytecode);
+ if (_deployedContracts[name] != address(0)) {
+ revert ContractDeployedAlready(_deployedContracts[name]);
+ }
+
+ address addr;
+ // solhint-disable-next-line no-inline-assembly
+ assembly {
+ let encoded_data := add(0x20, bytecode) // Load initialization code.
+ let encoded_size := mload(bytecode) // Load init code's length.
+ addr := create2(0, encoded_data, encoded_size, salt)
+ if iszero(extcodesize(addr)) {
+ revert(0, 0)
+ }
+ }
+ _deployedContracts[name] = addr;
+ emit ContractDeployed(name, addr);
+ return addr;
+ }
+
+ /**
+ * @dev Transfers the ownership of a contract to a new owner.
+ * @param _contract The address of the contract whose ownership is to be transferred.
+ * @param _owner The address of the new owner.
+ * @notice This function can only be called by an agent.
+ */
+ function recoverContractOwnership(address _contract, address _owner) external onlyAgent {
+ Ownable(_contract).transferOwnership(_owner);
+ }
+
+ /**
+ * @dev Retrieves the address of a deployed contract by its name.
+ * @param name The name of the contract.
+ * @return The address of the deployed contract.
+ */
+ function getContract(string calldata name) external view returns (address) {
+ return _deployedContracts[name];
+ }
+}
diff --git a/hardhat.config.ts b/hardhat.config.ts
index 688a158c..86aca0e7 100644
--- a/hardhat.config.ts
+++ b/hardhat.config.ts
@@ -4,6 +4,10 @@ import { HardhatUserConfig } from 'hardhat/config';
import 'solidity-coverage';
import '@nomiclabs/hardhat-solhint';
import '@primitivefi/hardhat-dodoc';
+import '@nomiclabs/hardhat-etherscan';
+import * as dotenv from 'dotenv';
+
+dotenv.config();
const config: HardhatUserConfig = {
solidity: {
@@ -21,9 +25,24 @@ const config: HardhatUserConfig = {
dodoc: {
runOnCompile: false,
debugMode: true,
- outputDir: "./docgen",
+ outputDir: './docgen',
freshOutput: true,
},
+ networks: {
+ mumbai: {
+ url: process.env.MUMBAI_RPC_URL,
+ accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`],
+ },
+ polygon: {
+ url: process.env.POLYGON_RPC_URL,
+ accounts: [`0x${process.env.DEPLOYER_PRIVATE_KEY}`],
+ },
+ },
+ etherscan: {
+ apiKey: {
+ polygonMumbai: process.env.POLYGONSCAN_API_KEY,
+ },
+ },
};
export default config;
diff --git a/index.d.ts b/index.d.ts
index 65d49032..190fedbf 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -6,7 +6,7 @@ type ContractJSON = {
bytecode: string;
deployedBytecode: string;
linkReferences: any;
-}
+};
export namespace contracts {
// Token
@@ -48,6 +48,9 @@ export namespace contracts {
export const TREXFactory: ContractJSON;
// gateway
export const TREXGateway: ContractJSON;
+ // contractsDeployer
+
+ export const ContractsDeployer: ContractJSON;
// DVD
export const DVDTransferManager: ContractJSON;
// DVA
diff --git a/index.js b/index.js
index 4a2d8819..fac7cd06 100644
--- a/index.js
+++ b/index.js
@@ -48,6 +48,8 @@ const TREXFactory = require('./artifacts/contracts/factory/TREXFactory.sol/TREXF
// gateway
const ITREXGateway = require('./artifacts/contracts/factory/ITREXGateway.sol/ITREXGateway.json');
const TREXGateway = require('./artifacts/contracts/factory/TREXGateway.sol/TREXGateway.json');
+// contractsDeployer
+const ContractsDeployer = require('./artifacts/contracts/factory/ContractsDeployer.sol/ContractsDeployer.json');
// DVD
const DVDTransferManager = require('./artifacts/contracts/DVD/DVDTransferManager.sol/DVDTransferManager.json');
// DVA
@@ -112,6 +114,8 @@ module.exports = {
TREXFactory,
// gateway
TREXGateway,
+ // contractsDeployer
+ ContractsDeployer,
// DVD
DVDTransferManager,
// DVA
diff --git a/package-lock.json b/package-lock.json
index 0fb59117..3a1904ac 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,14 +11,16 @@
"devDependencies": {
"@commitlint/cli": "^17.6.1",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
+ "@nomiclabs/hardhat-etherscan": "^3.1.8",
"@nomiclabs/hardhat-solhint": "^3.0.1",
- "@onchain-id/solidity": "^2.0.0",
+ "@onchain-id/solidity": "^2.2.0",
"@openzeppelin/contracts": "^4.8.3",
"@openzeppelin/contracts-upgradeable": "^4.8.3",
"@primitivefi/hardhat-dodoc": "^0.2.3",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
"@xyrusworx/hardhat-solidity-json": "^1.0.2",
+ "dotenv": "^16.4.5",
"eslint": "^8.39.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.8.0",
@@ -2282,11 +2284,11 @@
}
},
"node_modules/@nomiclabs/hardhat-etherscan": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.7.tgz",
- "integrity": "sha512-tZ3TvSgpvsQ6B6OGmo1/Au6u8BrAkvs1mIC/eURA3xgIfznUZBhmpne8hv7BXUzw9xNL3fXdpOYgOQlVMTcoHQ==",
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/@nomiclabs/hardhat-etherscan/-/hardhat-etherscan-3.1.8.tgz",
+ "integrity": "sha512-v5F6IzQhrsjHh6kQz4uNrym49brK9K5bYCq2zQZ729RYRaifI9hHbtmK+KkIVevfhut7huQFEQ77JLRMAzWYjQ==",
+ "deprecated": "The @nomiclabs/hardhat-etherscan package is deprecated, please use @nomicfoundation/hardhat-verify instead",
"dev": true,
- "peer": true,
"dependencies": {
"@ethersproject/abi": "^5.1.2",
"@ethersproject/address": "^5.0.2",
@@ -2308,7 +2310,6 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
- "peer": true,
"dependencies": {
"color-convert": "^1.9.0"
},
@@ -2321,7 +2322,6 @@
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
- "peer": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
@@ -2336,7 +2336,6 @@
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
- "peer": true,
"dependencies": {
"color-name": "1.1.3"
}
@@ -2345,15 +2344,13 @@
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true,
- "peer": true
+ "dev": true
},
"node_modules/@nomiclabs/hardhat-etherscan/node_modules/fs-extra": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
- "peer": true,
"dependencies": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
@@ -2368,7 +2365,6 @@
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=4"
}
@@ -2378,7 +2374,6 @@
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
"dev": true,
- "peer": true,
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
@@ -2388,7 +2383,6 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
- "peer": true,
"bin": {
"semver": "bin/semver.js"
}
@@ -2398,7 +2392,6 @@
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
- "peer": true,
"dependencies": {
"has-flag": "^3.0.0"
},
@@ -2411,7 +2404,6 @@
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
"dev": true,
- "peer": true,
"engines": {
"node": ">= 4.0.0"
}
@@ -2429,9 +2421,9 @@
}
},
"node_modules/@onchain-id/solidity": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@onchain-id/solidity/-/solidity-2.1.0.tgz",
- "integrity": "sha512-BBpBmUs8gg99N5NIKzANbs3R6DUhd90z2GEFvScVBhpHvpQhI5IzPNFRP6cXua1Lo0dWdNffxsteB3eUY1XMZw==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@onchain-id/solidity/-/solidity-2.2.0.tgz",
+ "integrity": "sha512-rUE5kFToihuvRAhtZXihOrpsqPOxN66v9hmTzlZOQJ2B+yKruLg4/nU/sJ7VCnheW4IeEm8OlA2oUJsdm1j88w==",
"dev": true
},
"node_modules/@openzeppelin/contracts": {
@@ -3843,7 +3835,6 @@
"resolved": "https://registry.npmjs.org/cbor/-/cbor-8.1.0.tgz",
"integrity": "sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==",
"dev": true,
- "peer": true,
"dependencies": {
"nofilter": "^3.1.0"
},
@@ -4768,6 +4759,18 @@
"node": ">=8"
}
},
+ "node_modules/dotenv": {
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -8994,7 +8997,6 @@
"resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz",
"integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==",
"dev": true,
- "peer": true,
"engines": {
"node": ">=12.19"
}
diff --git a/package.json b/package.json
index 9321c362..ce34c95c 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
],
"scripts": {
"build": "hardhat compile",
+ "deploy:mumbai": "hardhat run scripts/mumbaiDeploy.ts --network mumbai",
"flatten": "node scripts/flatten.js",
"coverage": "hardhat coverage",
"test": "hardhat test",
@@ -43,32 +44,34 @@
"devDependencies": {
"@commitlint/cli": "^17.6.1",
"@nomicfoundation/hardhat-toolbox": "^2.0.2",
+ "@nomiclabs/hardhat-etherscan": "^3.1.8",
"@nomiclabs/hardhat-solhint": "^3.0.1",
- "@onchain-id/solidity": "^2.0.0",
+ "@onchain-id/solidity": "^2.2.0",
"@openzeppelin/contracts": "^4.8.3",
"@openzeppelin/contracts-upgradeable": "^4.8.3",
"@primitivefi/hardhat-dodoc": "^0.2.3",
+ "@typescript-eslint/eslint-plugin": "^6.7.4",
+ "@typescript-eslint/parser": "^6.7.4",
"@xyrusworx/hardhat-solidity-json": "^1.0.2",
+ "dotenv": "^16.4.5",
"eslint": "^8.39.0",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-config-prettier": "^8.8.0",
+ "eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-chai-friendly": "^0.7.2",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-security": "^1.7.1",
+ "eth-gas-reporter": "^0.2.27",
+ "fs-extra": "^11.1.1",
+ "glob": "^10.2.6",
"hardhat": "^2.14.0",
"husky": "^8.0.3",
"lint-staged": "^13.2.2",
"prettier": "^2.8.8",
"prettier-plugin-solidity": "^1.1.3",
"solhint": "^3.4.1",
- "solhint-plugin-prettier": "^0.0.5",
- "glob": "^10.2.6",
- "fs-extra": "^11.1.1",
- "@typescript-eslint/parser": "^6.7.4",
- "@typescript-eslint/eslint-plugin": "^6.7.4",
- "eslint-import-resolver-typescript": "^3.6.1",
- "eth-gas-reporter": "^0.2.27"
+ "solhint-plugin-prettier": "^0.0.5"
},
"lint-staged": {
"*.js": [
diff --git a/scripts/mumbaiDeploy.ts b/scripts/mumbaiDeploy.ts
new file mode 100644
index 00000000..cc9703c2
--- /dev/null
+++ b/scripts/mumbaiDeploy.ts
@@ -0,0 +1,452 @@
+import { ethers, run } from 'hardhat';
+import * as dotenv from 'dotenv';
+
+dotenv.config();
+
+async function main() {
+ // Load private keys
+ const deployerPrivateKey = process.env.DEPLOYER_PRIVATE_KEY!;
+ const interactorPrivateKey = process.env.INTERACTOR_PRIVATE_KEY!;
+
+ // Connect to the network
+ const deployerWallet = new ethers.Wallet(deployerPrivateKey, ethers.provider);
+ const interactorWallet = new ethers.Wallet(interactorPrivateKey, ethers.provider);
+
+ // variable used for constructor arguments
+ let args;
+
+ // Deploy ContractsDeployer contract
+ const ContractsDeployerFactory = await ethers.getContractFactory('ContractsDeployer', deployerWallet);
+ const contractsDeployer = await ContractsDeployerFactory.deploy();
+ await contractsDeployer.deployed();
+ console.log(`ContractsDeployer deployed to: ${contractsDeployer.address}`);
+
+ // Verify ContractsDeployer contract
+ try {
+ await run('verify:verify', {
+ address: contractsDeployer.address,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('ContractsDeployer verification successful');
+ } catch (error) {
+ console.error('ContractsDeployer verification failed:', error);
+ }
+
+ // Add interactor as an agent
+ let tx = await contractsDeployer.connect(deployerWallet).addAgent(interactorWallet.address);
+ await tx.wait();
+ console.log(`Interactor added as an agent.`);
+
+ // Deploy Token contract via ContractsDeployer
+ const TokenFactory = await ethers.getContractFactory('Token');
+ const tokenBytecode = TokenFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('Token_v4.1.3', tokenBytecode);
+ await tx.wait();
+
+ const deployedTokenAddress = await contractsDeployer.getContract('Token_v4.1.3');
+ console.log(`Token contract deployed to: ${deployedTokenAddress}`);
+
+ // Verify Token contract
+ try {
+ await run('verify:verify', {
+ address: deployedTokenAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('Token contract verification successful');
+ } catch (error) {
+ console.error('Token contract verification failed:', error);
+ }
+
+ // Deploy Identity Registry contract via ContractsDeployer
+ const IRFactory = await ethers.getContractFactory('IdentityRegistry');
+ const irBytecode = IRFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('IR_v4.1.3', irBytecode);
+ await tx.wait();
+
+ const deployedIRAddress = await contractsDeployer.getContract('IR_v4.1.3');
+ console.log(`IdentityRegistry contract deployed to: ${deployedIRAddress}`);
+
+ // Verify Identity Registry contract
+ try {
+ await run('verify:verify', {
+ address: deployedIRAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('IdentityRegistry contract verification successful');
+ } catch (error) {
+ console.error('IdentityRegistry contract verification failed:', error);
+ }
+
+ // Deploy Identity Registry Storage contract via ContractsDeployer
+ const IRSFactory = await ethers.getContractFactory('IdentityRegistryStorage');
+ const irsBytecode = IRSFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('IRS_v4.1.3', irsBytecode);
+ await tx.wait();
+
+ const deployedIRSAddress = await contractsDeployer.getContract('IRS_v4.1.3');
+ console.log(`IdentityRegistryStorage contract deployed to: ${deployedIRSAddress}`);
+
+ // Verify Identity Registry Storage contract
+ try {
+ await run('verify:verify', {
+ address: deployedIRSAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('IdentityRegistryStorage contract verification successful');
+ } catch (error) {
+ console.error('IdentityRegistryStorage contract verification failed:', error);
+ }
+
+ // Deploy Trusted Issuers Registry contract via ContractsDeployer
+ const TIRFactory = await ethers.getContractFactory('TrustedIssuersRegistry');
+ const tirBytecode = TIRFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('TIR_v4.1.3', tirBytecode);
+ await tx.wait();
+
+ const deployedTIRAddress = await contractsDeployer.getContract('TIR_v4.1.3');
+ console.log(`IdentityRegistryStorage contract deployed to: ${deployedTIRAddress}`);
+
+ // Verify Trusted Issuers Registry contract
+ try {
+ await run('verify:verify', {
+ address: deployedTIRAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('TrustedIssuersRegistry contract verification successful');
+ } catch (error) {
+ console.error('TrustedIssuersRegistry contract verification failed:', error);
+ }
+
+ // Deploy Claim Topics Registry contract via ContractsDeployer
+ const CTRFactory = await ethers.getContractFactory('ClaimTopicsRegistry');
+ const ctrBytecode = CTRFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('CTR_v4.1.3', ctrBytecode);
+ await tx.wait();
+
+ const deployedCTRAddress = await contractsDeployer.getContract('CTR_v4.1.3');
+ console.log(`ClaimTopicsRegistry contract deployed to: ${deployedCTRAddress}`);
+
+ // Verify Claim Topics Registry contract
+ try {
+ await run('verify:verify', {
+ address: deployedCTRAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('ClaimTopicsRegistry contract verification successful');
+ } catch (error) {
+ console.error('ClaimTopicsRegistry contract verification failed:', error);
+ }
+
+ // Deploy Modular Compliance contract via ContractsDeployer
+ const MCFactory = await ethers.getContractFactory('ModularCompliance');
+ const mcBytecode = MCFactory.bytecode;
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('MC_v4.1.3', mcBytecode);
+ await tx.wait();
+
+ const deployedMCAddress = await contractsDeployer.getContract('MC_v4.1.3');
+ console.log(`ModularCompliance contract deployed to: ${deployedMCAddress}`);
+
+ // Verify Modular Compliance contract
+ try {
+ await run('verify:verify', {
+ address: deployedMCAddress,
+ constructorArguments: [],
+ network: 'mumbai',
+ });
+ console.log('ModularCompliance contract verification successful');
+ } catch (error) {
+ console.error('ModularCompliance contract verification failed:', error);
+ }
+
+ // Deploy Identity contract via ContractsDeployer
+ const IdentityFactory = await ethers.getContractFactory('Identity');
+ const idBytecode = IdentityFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['address', 'bool'], [contractsDeployer.address, true]);
+ const idBytecodeWithArgs = idBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('OID_v2.2.0', idBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedOIDAddress = await contractsDeployer.getContract('OID_v2.2.0');
+ console.log(`Identity contract deployed to: ${deployedOIDAddress}`);
+
+ // Verify Identity contract
+ try {
+ await run('verify:verify', {
+ address: deployedOIDAddress,
+ constructorArguments: [contractsDeployer.address, true],
+ network: 'mumbai',
+ });
+ console.log('Identity contract verification successful');
+ } catch (error) {
+ console.error('Identity contract verification failed:', error);
+ }
+
+ // Deploy Implementation Authority (OID version) contract via ContractsDeployer
+ const IdIAFactory = await ethers.getContractFactory('ImplementationAuthority');
+ const idiaBytecode = IdIAFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['address'], [deployedOIDAddress]);
+ const idiaBytecodeWithArgs = idiaBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('OID_IA_v2.2.0', idiaBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedIdIAAddress = await contractsDeployer.getContract('OID_IA_v2.2.0');
+ console.log(`ImplementationAuthority contract deployed to: ${deployedIdIAAddress}`);
+
+ // Verify Implementation Authority (OID version) contract
+ try {
+ await run('verify:verify', {
+ address: deployedIdIAAddress,
+ constructorArguments: [deployedOIDAddress],
+ network: 'mumbai',
+ });
+ console.log('ImplementationAuthority verification successful');
+ } catch (error) {
+ console.error('ImplementationAuthority verification failed:', error);
+ }
+
+ // Recover ownership of ImplementationAuthority
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedIdIAAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for ImplementationAuthority sent.`);
+
+ // Create a contract instance for ImplementationAuthority
+ const implementationAuthorityInstance = await ethers.getContractAt('ImplementationAuthority', deployedIdIAAddress);
+
+ // Check the current owner of the ImplementationAuthority contract
+ let currentOwner = await implementationAuthorityInstance.owner();
+
+ // Verify ownership has been transferred to interactorWallet
+ if (currentOwner.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of ImplementationAuthority has been successfully transferred to: ${currentOwner}`);
+ } else {
+ console.error(`Ownership transfer of ImplementationAuthority failed. Current owner is: ${currentOwner}`);
+ }
+
+ // Deploy OID Factory contract via ContractsDeployer
+ const OIDFactory = await ethers.getContractFactory('IdFactory');
+ const oidFactoryBytecode = OIDFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['address'], [deployedIdIAAddress]);
+ const oidFactoryBytecodeWithArgs = oidFactoryBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('OID_Factory_v2.2.0', oidFactoryBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedOIDFactoryAddress = await contractsDeployer.getContract('OID_Factory_v2.2.0');
+ console.log(`IdFactory contract deployed to: ${deployedOIDFactoryAddress}`);
+
+ // Verify OID Factory contract
+ try {
+ await run('verify:verify', {
+ address: deployedOIDFactoryAddress,
+ constructorArguments: [deployedIdIAAddress],
+ network: 'mumbai',
+ });
+ console.log('IdFactory verification successful');
+ } catch (error) {
+ console.error('IdFactory verification failed:', error);
+ }
+ // Recover ownership of OID Factory
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedOIDFactoryAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for IdFactory initiated.`);
+
+ // Create a contract instance for IdFactory
+ const oidFactoryContract = await ethers.getContractAt('IdFactory', deployedOIDFactoryAddress, interactorWallet);
+
+ // Check the current owner of the OID Factory contract
+ currentOwner = await oidFactoryContract.owner();
+ if (currentOwner.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of IdFactory successfully transferred to ${currentOwner}.`);
+ } else {
+ console.error(`Ownership transfer of IdFactory failed. Current owner is ${currentOwner}.`);
+ }
+
+ // Deploy TREXImplementationAuthority contract via ContractsDeployer
+ const TREXIAFactory = await ethers.getContractFactory('TREXImplementationAuthority');
+ const trexiaBytecode = TREXIAFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['bool', 'address', 'address'], [true, ethers.constants.AddressZero, ethers.constants.AddressZero]);
+ const trexiaBytecodeWithArgs = trexiaBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('TREX_IA_v1.0.0', trexiaBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedTrexIAAddress = await contractsDeployer.getContract('TREX_IA_v1.0.0');
+ console.log(`TREXImplementationAuthority contract deployed to: ${deployedTrexIAAddress}`);
+
+ // Verify TREXImplementationAuthority contract
+ try {
+ await run('verify:verify', {
+ address: deployedTrexIAAddress,
+ constructorArguments: [true, ethers.constants.AddressZero, ethers.constants.AddressZero],
+ network: 'mumbai',
+ });
+ console.log('TREXImplementationAuthority verification successful');
+ } catch (error) {
+ console.error('TREXImplementationAuthority verification failed:', error);
+ }
+
+ // Recover ownership of TREXImplementationAuthority
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedTrexIAAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for TREXImplementationAuthority initiated.`);
+
+ // Create a contract instance for TREXImplementationAuthority
+ const trexIAContract = await ethers.getContractAt('TREXImplementationAuthority', deployedTrexIAAddress, interactorWallet);
+
+ // Check the current owner of the TREXImplementationAuthority contract
+ const currentOwnerTrexIA = await trexIAContract.owner();
+ if (currentOwnerTrexIA.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of TREXImplementationAuthority successfully transferred to ${currentOwnerTrexIA}.`);
+ } else {
+ console.error(`Ownership transfer of TREXImplementationAuthority failed. Current owner is ${currentOwnerTrexIA}.`);
+ }
+ const version = {
+ major: 4,
+ minor: 1,
+ patch: 3,
+ };
+
+ const trexContracts = {
+ tokenImplementation: deployedTokenAddress,
+ ctrImplementation: deployedCTRAddress,
+ irImplementation: deployedIRAddress,
+ irsImplementation: deployedIRSAddress,
+ tirImplementation: deployedTIRAddress,
+ mcImplementation: deployedMCAddress,
+ };
+ tx = await trexIAContract.connect(interactorWallet).addAndUseTREXVersion(version, trexContracts);
+ const receipt = await tx.wait();
+ const trexVersionAddedEvent = receipt.events?.find((e) => e.event === 'TREXVersionAdded');
+ const versionUpdatedEvent = receipt.events?.find((e) => e.event === 'VersionUpdated');
+
+ if (trexVersionAddedEvent && versionUpdatedEvent) {
+ console.log('TREXVersionAdded and VersionUpdated events were successfully emitted.');
+ } else {
+ console.error('Failed to emit TREXVersionAdded and/or VersionUpdated events.');
+ }
+ // Deploy TREXFactory contract via ContractsDeployer
+ const TREXFactory = await ethers.getContractFactory('TREXFactory');
+ const trexFactoryBytecode = TREXFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['address', 'address'], [deployedTrexIAAddress, deployedOIDFactoryAddress]);
+ const trexFactoryBytecodeWithArgs = trexFactoryBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('TREX_Factory_v4.1.3', trexFactoryBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedTREXFactoryAddress = await contractsDeployer.getContract('TREX_Factory_v4.1.3');
+ console.log(`TREXFactory contract deployed to: ${deployedTREXFactoryAddress}`);
+
+ // Verify TREXFactory contract
+ try {
+ await run('verify:verify', {
+ address: deployedTREXFactoryAddress,
+ constructorArguments: [deployedTrexIAAddress, deployedOIDFactoryAddress],
+ network: 'mumbai',
+ });
+ console.log('TREXFactory verification successful');
+ } catch (error) {
+ console.error('TREXFactory verification failed:', error);
+ }
+ // Recover ownership of TREXFactory
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedTREXFactoryAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for TREXFactory initiated.`);
+
+ // Verify the ownership transfer
+ const trexFactoryContract = await ethers.getContractAt('TREXFactory', deployedTREXFactoryAddress, interactorWallet);
+ const currentOwnerTREXFactory = await trexFactoryContract.owner();
+ if (currentOwnerTREXFactory.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of TREXFactory successfully transferred to ${currentOwnerTREXFactory}.`);
+ } else {
+ console.error(`Ownership transfer of TREXFactory failed. Current owner is ${currentOwnerTREXFactory}.`);
+ }
+ // Deploy TREXGateway contract via ContractsDeployer
+ const TREXGatewayFactory = await ethers.getContractFactory('TREXGateway');
+ const trexGatewayBytecode = TREXGatewayFactory.bytecode;
+ const argsTREXGateway = ethers.utils.defaultAbiCoder.encode(
+ ['address', 'bool'],
+ [deployedTREXFactoryAddress, false], // Using the deployed TREXFactory address and setting publicDeploymentStatus to false
+ );
+ const trexGatewayBytecodeWithArgs = trexGatewayBytecode + argsTREXGateway.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('TREX_Gateway', trexGatewayBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedTREXGatewayAddress = await contractsDeployer.getContract('TREX_Gateway');
+ console.log(`TREXGateway contract deployed to: ${deployedTREXGatewayAddress}`);
+
+ try {
+ await run('verify:verify', {
+ address: deployedTREXGatewayAddress,
+ constructorArguments: [deployedTREXFactoryAddress, false],
+ network: 'mumbai',
+ });
+ console.log('TREXGateway verification successful');
+ } catch (error) {
+ console.error('TREXGateway verification failed:', error);
+ }
+ // Recover ownership of TREXGateway
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedTREXGatewayAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for TREXGateway initiated.`);
+
+ // Confirm the ownership transfer
+ const trexGatewayContract = await ethers.getContractAt('Ownable', deployedTREXGatewayAddress, interactorWallet);
+ const currentOwnerTREXGateway = await trexGatewayContract.owner();
+ if (currentOwnerTREXGateway.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of TREXGateway successfully transferred to ${currentOwnerTREXGateway}.`);
+ } else {
+ console.error(`Ownership transfer of TREXGateway failed. Current owner is ${currentOwnerTREXGateway}.`);
+ }
+ tx = await trexFactoryContract.connect(interactorWallet).transferOwnership(deployedTREXGatewayAddress);
+ await tx.wait();
+ console.log(`Ownership of TREX Factory transferred to TREXGateway.`);
+ tx = await oidFactoryContract.connect(interactorWallet).addTokenFactory(deployedTREXFactoryAddress);
+ await tx.wait();
+ console.log(`TREX Factory registered in IdFactory as a Token Factory`);
+
+ // Deploy Gateway contract via ContractsDeployer
+ const GatewayFactory = await ethers.getContractFactory('Gateway');
+ const gatewayBytecode = GatewayFactory.bytecode;
+ args = ethers.utils.defaultAbiCoder.encode(['address', 'address[]'], [deployedOIDFactoryAddress, []]);
+ const gatewayBytecodeWithArgs = gatewayBytecode + args.slice(2);
+ tx = await contractsDeployer.connect(interactorWallet).deployContract('Gateway', gatewayBytecodeWithArgs);
+ await tx.wait();
+
+ const deployedGatewayAddress = await contractsDeployer.getContract('Gateway');
+ console.log(`Gateway contract deployed to: ${deployedGatewayAddress}`);
+
+ try {
+ await run('verify:verify', {
+ address: deployedGatewayAddress,
+ constructorArguments: [deployedOIDFactoryAddress, []],
+ network: 'mumbai',
+ });
+ console.log('Gateway verification successful');
+ } catch (error) {
+ console.error('Gateway verification failed:', error);
+ }
+ // Recover ownership of Gateway
+ tx = await contractsDeployer.connect(interactorWallet).recoverContractOwnership(deployedGatewayAddress, interactorWallet.address);
+ await tx.wait();
+ console.log(`Ownership recovery transaction for Gateway initiated.`);
+
+ // Confirm the ownership transfer
+ const gatewayContract = await ethers.getContractAt('Gateway', deployedGatewayAddress, interactorWallet);
+ const currentOwnerGateway = await gatewayContract.owner();
+ if (currentOwnerGateway.toLowerCase() === interactorWallet.address.toLowerCase()) {
+ console.log(`Ownership of Gateway successfully transferred to ${currentOwnerGateway}.`);
+ } else {
+ console.error(`Ownership transfer of Gateway failed. Current owner is ${currentOwnerGateway}.`);
+ }
+ tx = await oidFactoryContract.connect(interactorWallet).transferOwnership(deployedGatewayAddress);
+ await tx.wait();
+ console.log(`Ownership of TREX Factory transferred to TREXGateway.`);
+}
+
+main().catch((error) => {
+ console.error(error);
+ process.exit(1);
+});
diff --git a/test/fixtures/deploy-full-suite.fixture.ts b/test/fixtures/deploy-full-suite.fixture.ts
index eefa68ed..56198973 100644
--- a/test/fixtures/deploy-full-suite.fixture.ts
+++ b/test/fixtures/deploy-full-suite.fixture.ts
@@ -12,40 +12,68 @@ export async function deployIdentityProxy(implementationAuthority: Contract['add
return ethers.getContractAt('Identity', identity.address, signer);
}
+// Function to deploy a single contract through ContractsDeployer
+async function deployAndLoadContract(contractsDeployer: Contract, contractName: string): Promise {
+ // Fetch bytecode
+ const ContractFactory = await ethers.getContractFactory(contractName);
+ const bytecode = ContractFactory.bytecode;
+
+ // Deploy contract using ContractsDeployer
+ await contractsDeployer.deployContract(contractName, bytecode);
+
+ // Retrieve the deployed contract address
+ const address = await contractsDeployer.getContract(contractName);
+
+ // Load the contract
+ return ethers.getContractAt(contractName, address);
+}
+
+async function deployAndLoadContractWithArgs(contractsDeployer: Contract, contractName: string, constructorArgs: unknown[]): Promise {
+ // Create a ContractFactory with the ABI, bytecode, and constructor arguments
+ const ContractFactory = await ethers.getContractFactory(contractName);
+ const deployTx = ContractFactory.getDeployTransaction(...constructorArgs);
+
+ // Deploy contract using ContractsDeployer with the combined bytecode and constructor args
+ await contractsDeployer.deployContract(contractName, deployTx.data);
+
+ // Retrieve the deployed contract address
+ const address = await contractsDeployer.getContract(contractName);
+
+ // Load the contract
+ return ethers.getContractAt(contractName, address);
+}
+
export async function deployFullSuiteFixture() {
const [deployer, tokenIssuer, tokenAgent, tokenAdmin, claimIssuer, aliceWallet, bobWallet, charlieWallet, davidWallet, anotherWallet] =
await ethers.getSigners();
const claimIssuerSigningKey = ethers.Wallet.createRandom();
const aliceActionKey = ethers.Wallet.createRandom();
+ const contractsDeployer = await ethers.deployContract('ContractsDeployer', deployer);
+ await contractsDeployer.addAgent(deployer.address);
// Deploy implementations
- const claimTopicsRegistryImplementation = await ethers.deployContract('ClaimTopicsRegistry', deployer);
- const trustedIssuersRegistryImplementation = await ethers.deployContract('TrustedIssuersRegistry', deployer);
- const identityRegistryStorageImplementation = await ethers.deployContract('IdentityRegistryStorage', deployer);
- const identityRegistryImplementation = await ethers.deployContract('IdentityRegistry', deployer);
- const modularComplianceImplementation = await ethers.deployContract('ModularCompliance', deployer);
- const tokenImplementation = await ethers.deployContract('Token', deployer);
- const identityImplementation = await new ethers.ContractFactory(
- OnchainID.contracts.Identity.abi,
- OnchainID.contracts.Identity.bytecode,
- deployer,
- ).deploy(deployer.address, true);
-
- const identityImplementationAuthority = await new ethers.ContractFactory(
- OnchainID.contracts.ImplementationAuthority.abi,
- OnchainID.contracts.ImplementationAuthority.bytecode,
- deployer,
- ).deploy(identityImplementation.address);
+ const claimTopicsRegistryImplementation = await deployAndLoadContract(contractsDeployer, 'ClaimTopicsRegistry');
+ const trustedIssuersRegistryImplementation = await deployAndLoadContract(contractsDeployer, 'TrustedIssuersRegistry');
+ const identityRegistryStorageImplementation = await deployAndLoadContract(contractsDeployer, 'IdentityRegistryStorage');
+ const identityRegistryImplementation = await deployAndLoadContract(contractsDeployer, 'IdentityRegistry');
+ const modularComplianceImplementation = await deployAndLoadContract(contractsDeployer, 'ModularCompliance');
+ const tokenImplementation = await deployAndLoadContract(contractsDeployer, 'Token');
+ const identityImplementation = await deployAndLoadContractWithArgs(contractsDeployer, 'Identity', [deployer.address, true]);
+ const identityImplementationAuthority = await deployAndLoadContractWithArgs(contractsDeployer, 'ImplementationAuthority', [
+ identityImplementation.address,
+ ]);
+ await contractsDeployer.recoverContractOwnership(identityImplementationAuthority.address, deployer.address);
const identityFactory = await new ethers.ContractFactory(OnchainID.contracts.Factory.abi, OnchainID.contracts.Factory.bytecode, deployer).deploy(
identityImplementationAuthority.address,
);
- const trexImplementationAuthority = await ethers.deployContract(
- 'TREXImplementationAuthority',
- [true, ethers.constants.AddressZero, ethers.constants.AddressZero],
- deployer,
- );
+ const trexImplementationAuthority = await deployAndLoadContractWithArgs(contractsDeployer, 'TREXImplementationAuthority', [
+ true,
+ ethers.constants.AddressZero,
+ ethers.constants.AddressZero,
+ ]);
+ await contractsDeployer.recoverContractOwnership(trexImplementationAuthority.address, deployer.address);
const versionStruct = {
major: 4,
minor: 0,