From e22b1595a0b65d29f0d12492fe88f7fb428c8698 Mon Sep 17 00:00:00 2001 From: Stephane Gosselin Date: Sat, 24 Aug 2019 09:41:53 +0200 Subject: [PATCH] v1.0.0 Mainnet Deployment (#161) * add mainnet deployment scripts * typo renounceOperator, complete coverage Operated * complete coverage for Registry.sol * copy over test for transferOperator/renounceOperator * fix deployment scripts * deploy to mainnet * add fixed commit --- README.md | 20 +++- contracts/agreements/OneWayGriefing.sol | 4 +- contracts/modules/Operated.sol | 4 +- contracts/test-contracts/TestOperated.sol | 8 ++ deployment/deploy.js | 139 +++++++++++++++++----- test/agreements/OneWayGriefing.js | 74 +++++++++++- test/modules/Operated.js | 93 +++++++++++++-- test/modules/Registry.js | 16 +++ 8 files changed, 312 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index c3637a57..ac602d2d 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,19 @@ ### Erasure Fractal -#### Rinkeby v2 -| Contract | Address | +#### v1.0.0 +| Contract | Rinkeby | Mainnet | +| - | - | - | +| [MockNMR](https://github.com/erasureprotocol/erasure-next-contracts/blob/2c14b52b95c15e686d006b8d34411d1321fcfc81/Fractal/contracts/helpers/mock/MockNMR.sol) | [0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9](https://rinkeby.etherscan.io/address/0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9) | +| [Erasure_Posts](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/registries/Erasure_Posts.sol) | [0x036bd70228F7909b5Ef051D5f29f93018e8466f9](https://rinkeby.etherscan.io/address/0x036bd70228F7909b5Ef051D5f29f93018e8466f9) | [0x348FA9DcFf507B81C7A1d7981244eA92E8c6Af29](https://rinkeby.etherscan.io/address/0x348FA9DcFf507B81C7A1d7981244eA92E8c6Af29) | +| [Erasure_Agreements](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/registries/Erasure_Agreements.sol) | [0x3318D98E4CFf8bA162752de3D140640c72D462E9](https://rinkeby.etherscan.io/address/0x3318D98E4CFf8bA162752de3D140640c72D462E9) | [0xa6cf4Bf00feF8866e9F3f61C972bA7C687C6eDbF](https://rinkeby.etherscan.io/address/0xa6cf4Bf00feF8866e9F3f61C972bA7C687C6eDbF) | +| [Erasure_Users](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/registries/Erasure_Users.sol) | [0xc065f32bF6648BBecEBBf683BEAb35a60b93F75D](https://rinkeby.etherscan.io/address/0xc065f32bF6648BBecEBBf683BEAb35a60b93F75D) | [0x789D0082B20A929D6fB64EB4c10c68e827AAB7aB](https://rinkeby.etherscan.io/address/0x789D0082B20A929D6fB64EB4c10c68e827AAB7aB) | +| [Post_Factory](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/posts/Post_Factory.sol) | [0x0611DFe481Ca6D22BEb04cB8b4a5a4001CeBeEa7](https://rinkeby.etherscan.io/address/0x0611DFe481Ca6D22BEb04cB8b4a5a4001CeBeEa7) | [0x480b8d6b5C184C0E34AE66036cC5B4e0390EcA8A](https://rinkeby.etherscan.io/address/0x480b8d6b5C184C0E34AE66036cC5B4e0390EcA8A) | +| [Feed_Factory](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/posts/Feed_Factory.sol) | [0xDCa2Af551f6d7F0Fad5769f5EE8C81eA0a9AE494](https://rinkeby.etherscan.io/address/0xDCa2Af551f6d7F0Fad5769f5EE8C81eA0a9AE494) | [0x1f09dDa453941c2536b9dE8c4382807D1FC603A9](https://rinkeby.etherscan.io/address/0x1f09dDa453941c2536b9dE8c4382807D1FC603A9) | +| [OneWayGriefing_Factory](https://github.com/erasureprotocol/erasure-next-contracts/blob/f2f280a5bf5c9e18a645f4aa24e117099643a8ce/contracts/agreements/OneWayGriefing_Factory.sol) | [0x3Fd3C12F33F5993E2E7cbBEE480aebF71C830C95](https://rinkeby.etherscan.io/address/0x3Fd3C12F33F5993E2E7cbBEE480aebF71C830C95) | [0xF06eA7e3D791D88C7F7A88CE1280F36a823A7A62](https://rinkeby.etherscan.io/address/0xF06eA7e3D791D88C7F7A88CE1280F36a823A7A62) | + +#### v0.2.2 +| Contract | Rinkeby | | - | - | | [MockNMR](https://github.com/erasureprotocol/erasure-next-contracts/blob/2c14b52b95c15e686d006b8d34411d1321fcfc81/Fractal/contracts/helpers/mock/MockNMR.sol) | [0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9](https://rinkeby.etherscan.io/address/0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9) | | [Erasure_Posts](https://github.com/erasureprotocol/erasure-next-contracts/blob/master/contracts/registries/Erasure_Posts.sol) | [0xEd11206a7d07601985DCC4FeD7B3284a928D022B](https://rinkeby.etherscan.io/address/0xEd11206a7d07601985DCC4FeD7B3284a928D022B) | @@ -15,8 +26,9 @@ | [Feed_Factory](https://github.com/erasureprotocol/erasure-next-contracts/blob/master/contracts/posts/Feed_Factory.sol) | [0xabFe46E50D7A72e17688b44ce4f8B95545020560](https://rinkeby.etherscan.io/address/0xabFe46E50D7A72e17688b44ce4f8B95545020560) | | [OneWayGriefing_Factory](https://github.com/erasureprotocol/erasure-next-contracts/blob/master/contracts/agreements/OneWayGriefing_Factory.sol) | [0x91b052E4800DB77d4d0BFE9fe2bE48352695F282](https://rinkeby.etherscan.io/address/0x91b052E4800DB77d4d0BFE9fe2bE48352695F282) | -#### Rinkeby v1 -| Contract | Address | + +#### v0.1.0 +| Contract | Rinkeby | | - | - | | [MockNMR](https://github.com/erasureprotocol/erasure-next-contracts/blob/2c14b52b95c15e686d006b8d34411d1321fcfc81/Fractal/contracts/helpers/mock/MockNMR.sol) | [0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9](https://rinkeby.etherscan.io/address/0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9) | | [Erasure_Posts](https://github.com/erasureprotocol/erasure-next-contracts/blob/2c14b52b95c15e686d006b8d34411d1321fcfc81/Fractal/contracts/registries/Erasure_Posts.sol) | [0x35433De02F91fec112c91e472869b5A210B0E1Bb](https://rinkeby.etherscan.io/address/0x35433De02F91fec112c91e472869b5A210B0E1Bb) | diff --git a/contracts/agreements/OneWayGriefing.sol b/contracts/agreements/OneWayGriefing.sol index 2b740e90..3147b503 100644 --- a/contracts/agreements/OneWayGriefing.sol +++ b/contracts/agreements/OneWayGriefing.sol @@ -133,12 +133,12 @@ contract OneWayGriefing is Countdown, Griefing, Metadata, Operated, Template { Operated._transferOperator(operator); } - function renouceOperator() public { + function renounceOperator() public { // restrict access require(Operated.isActiveOperator(msg.sender), "only active operator"); // transfer operator - Operated._renouceOperator(); + Operated._renounceOperator(); } // view functions diff --git a/contracts/modules/Operated.sol b/contracts/modules/Operated.sol index 1350796b..2d3a9a2a 100644 --- a/contracts/modules/Operated.sol +++ b/contracts/modules/Operated.sol @@ -17,10 +17,12 @@ contract Operated { } function _transferOperator(address operator) internal { + // transferring operator-ship implies there was an operator set before this + require(_operator != address(0), "operator not set"); _setOperator(operator); } - function _renouceOperator() internal { + function _renounceOperator() internal { require(hasActiveOperator(), "only when operator active"); _operator = address(0); _status = false; diff --git a/contracts/test-contracts/TestOperated.sol b/contracts/test-contracts/TestOperated.sol index 8f8cfdd4..68d4525d 100644 --- a/contracts/test-contracts/TestOperated.sol +++ b/contracts/test-contracts/TestOperated.sol @@ -17,4 +17,12 @@ contract TestOperated is Operated { // backdoor function to deactivate Operator for testing Operated._deactivateOperator(); } + + function renounceOperator() public { + Operated._renounceOperator(); + } + + function transferOperator(address newOperator) public { + Operated._transferOperator(newOperator); + } } diff --git a/deployment/deploy.js b/deployment/deploy.js index bec5147f..aa639aa5 100755 --- a/deployment/deploy.js +++ b/deployment/deploy.js @@ -3,10 +3,9 @@ const ethers = require("ethers"); const { createMultihashSha256 } = require("../test/helpers/utils"); require("dotenv").config(); -const tokenAddress = "0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9"; - const deploy = async (network, secret) => { let contracts = { + MockNMR: {artifact: require('../build/MockNMR.json')}, Erasure_Agreements: { artifact: require("../build/Erasure_Agreements.json") }, Erasure_Escrows: { artifact: require("../build/Erasure_Escrows.json") }, Erasure_Posts: { artifact: require("../build/Erasure_Posts.json") }, @@ -19,12 +18,19 @@ const deploy = async (network, secret) => { Post: { artifact: require("../build/Post.json") } }; + let tokenAddress; let deployer; let wallet = new ethers.Wallet(process.env.DEPLOYMENT_PRIV_KEY); + let multisig; console.log(`Deployment Wallet: ${wallet.address}`); + let defaultGas = ethers.utils.parseUnits('10', 'gwei'); + if (network == "rinkeby") { + tokenAddress = "0x1eBf22785bffb6B44fEbBc8a41056b1aD43401f9"; + multisig = "0x6087555A70E2F96B7838806e7743041E035a37e5"; + // connect to rinkeby wallet = await wallet.connect(ethers.getDefaultProvider('rinkeby')); @@ -39,9 +45,43 @@ const deploy = async (network, secret) => { // contracts.Erasure_Posts.instance = await new ethers.Contract('0xEd11206a7d07601985DCC4FeD7B3284a928D022B', contracts.Erasure_Posts.artifact.abi, wallet); // deploy registries - contracts.Erasure_Posts.instance = await deployer.deployAndVerify(contracts.Erasure_Posts.artifact, false); - contracts.Erasure_Agreements.instance = await deployer.deployAndVerify(contracts.Erasure_Agreements.artifact, false); - contracts.Erasure_Users.instance = await deployer.deployAndVerify(contracts.Erasure_Users.artifact, false); + contracts.Erasure_Posts.instance = await deployer.deployAndVerify(contracts.Erasure_Posts.artifact); + contracts.Erasure_Agreements.instance = await deployer.deployAndVerify(contracts.Erasure_Agreements.artifact); + contracts.Erasure_Users.instance = await deployer.deployAndVerify(contracts.Erasure_Users.artifact); + + // deploy factories + contracts.Post_Factory.instance = await deployer.deployAndVerify(contracts.Post_Factory.artifact, false, contracts.Erasure_Posts.instance.contractAddress); + contracts.Feed_Factory.instance = await deployer.deployAndVerify(contracts.Feed_Factory.artifact, false, contracts.Erasure_Posts.instance.contractAddress); + contracts.OneWayGriefing_Factory.instance = await deployer.deployAndVerify(contracts.OneWayGriefing_Factory.artifact, false, contracts.Erasure_Agreements.instance.contractAddress); + +} else if (network == "mainnet") { + + tokenAddress = "0x1776e1F26f98b1A5dF9cD347953a26dd3Cb46671"; + multisig = "0x0000000000377d181a0ebd08590c6b399b272000"; + + // connect to rinkeby + wallet = await wallet.connect(ethers.getDefaultProvider('homestead')); + + // initialize deployer + deployer = await new etherlime.InfuraPrivateKeyDeployer( + wallet.privateKey, + "mainnet", + process.env.INFURA_API_KEY, + { gasPrice: defaultGas } + ); + deployer.setVerifierApiKey(process.env.ETHERSCAN_API_KEY); + + // contracts.Erasure_Posts.instance = await new ethers.Contract('0xF9F79CEe69175B51E4aB2b2D231460B61Ebb2688', contracts.Erasure_Posts.artifact.abi, wallet); + // contracts.Erasure_Agreements.instance = await new ethers.Contract('0xF9F79CEe69175B51E4aB2b2D231460B61Ebb2688', contracts.Erasure_Agreements.artifact.abi, wallet); + // contracts.Erasure_Users.instance = await new ethers.Contract('0xD5fa2751A560b6ca47219224Bc231c56a9849492', contracts.Erasure_Users.artifact.abi, wallet); + // contracts.Post_Factory.instance = await new ethers.Contract('0x750EC6138205Cf1C36b446Dd540E0464E9C0e6Cd', contracts.Post_Factory.artifact.abi, wallet); + // contracts.Feed_Factory.instance = await new ethers.Contract('0x276e1fdB65951B8c1d1c16C5B69a72bE3060E7AA', contracts.Feed_Factory.artifact.abi, wallet); + // contracts.OneWayGriefing_Factory.instance = await new ethers.Contract('0x3A1a3EfeDf5C3932Bac1b637EA8Ac2D904C58480', contracts.OneWayGriefing_Factory.artifact.abi, wallet); + + // deploy registries + contracts.Erasure_Posts.instance = await deployer.deployAndVerify(contracts.Erasure_Posts.artifact); + contracts.Erasure_Agreements.instance = await deployer.deployAndVerify(contracts.Erasure_Agreements.artifact); + contracts.Erasure_Users.instance = await deployer.deployAndVerify(contracts.Erasure_Users.artifact); // deploy factories contracts.Post_Factory.instance = await deployer.deployAndVerify(contracts.Post_Factory.artifact, false, contracts.Erasure_Posts.instance.contractAddress); @@ -49,13 +89,20 @@ const deploy = async (network, secret) => { contracts.OneWayGriefing_Factory.instance = await deployer.deployAndVerify(contracts.OneWayGriefing_Factory.artifact, false, contracts.Erasure_Agreements.instance.contractAddress); } else if (network == "ganache") { + + multisig = wallet.address; + // initialize deployer deployer = new etherlime.EtherlimeGanacheDeployer(); + // deploy mock NMR + contracts.MockNMR.instance = await deployer.deploy(contracts.MockNMR.artifact); + tokenAddress = contracts.MockNMR.instance.contractAddress; + // deploy registries - contracts.Erasure_Posts.instance = await deployer.deploy(contracts.Erasure_Posts.artifact, false); - contracts.Erasure_Agreements.instance = await deployer.deploy(contracts.Erasure_Agreements.artifact, false); - contracts.Erasure_Users.instance = await deployer.deploy(contracts.Erasure_Users.artifact, false); + contracts.Erasure_Posts.instance = await deployer.deploy(contracts.Erasure_Posts.artifact); + contracts.Erasure_Agreements.instance = await deployer.deploy(contracts.Erasure_Agreements.artifact); + contracts.Erasure_Users.instance = await deployer.deploy(contracts.Erasure_Users.artifact); // deploy factories contracts.Post_Factory.instance = await deployer.deploy(contracts.Post_Factory.artifact, false, contracts.Erasure_Posts.instance.contractAddress); @@ -63,35 +110,69 @@ const deploy = async (network, secret) => { contracts.OneWayGriefing_Factory.instance = await deployer.deploy(contracts.OneWayGriefing_Factory.artifact, false, contracts.Erasure_Agreements.instance.contractAddress); } - // register factories + console.log(` +Register Factories + `); await contracts.Erasure_Posts.instance.addFactory( contracts.Post_Factory.instance.contractAddress, ethers.utils.hexlify(0x0) - ); - console.log('Post_Factory is registered'); + ).then(async txn => { + console.log(`addFactory() | Post_Factory => Erasure_Posts`); + const receipt = await contracts.Erasure_Posts.instance.verboseWaitForTransaction(txn); + }); + await contracts.Erasure_Posts.instance.addFactory( contracts.Feed_Factory.instance.contractAddress, - ethers.utils.hexlify(0x0) - ); - console.log('Feed_Factory is registered'); + ethers.utils.hexlify(0x0), + { gasPrice: defaultGas } + ).then(async txn => { + console.log(`addFactory() | Feed_Factory => Erasure_Posts`); + const receipt = await contracts.Erasure_Posts.instance.verboseWaitForTransaction(txn); + }); + await contracts.Erasure_Agreements.instance.addFactory( contracts.OneWayGriefing_Factory.instance.contractAddress, - ethers.utils.hexlify(0x0) - ); - console.log('OneWayGriefing_Factory is registered'); + ethers.utils.hexlify(0x0), + { gasPrice: defaultGas } + ).then(async txn => { + console.log(`addFactory() | OneWayGriefing_Factory => Erasure_Agreements`); + const receipt = await contracts.Erasure_Agreements.instance.verboseWaitForTransaction(txn); + }); - // attempt to create instances + console.log(` +Transfer Registry Ownership + `); + + await contracts.Erasure_Posts.instance.transferOwnership( + multisig, + { gasPrice: defaultGas } + ).then(async txn => { + console.log(`transferOwnership() | Erasure_Posts => ${multisig}`); + const receipt = await contracts.Erasure_Posts.instance.verboseWaitForTransaction(txn); + }); + await contracts.Erasure_Agreements.instance.transferOwnership( + multisig, + { gasPrice: defaultGas } + ).then(async txn => { + console.log(`transferOwnership() | Erasure_Agreements => ${multisig}`); + const receipt = await contracts.Erasure_Agreements.instance.verboseWaitForTransaction(txn); + }); + + console.log(` +Create test instances from factories + `); const userAddress = '0x6087555A70E2F96B7838806e7743041E035a37e5'; const proofHash = createMultihashSha256("proofHash"); - console.log(proofHash); + console.log(`multihash: ${proofHash}`); await contracts.Post_Factory.instance.createExplicit( userAddress, proofHash, '0x0', - '0x0' + '0x0', + { gasPrice: defaultGas } ).then(async txn => { const receipt = await contracts.Post_Factory.instance.verboseWaitForTransaction(txn); const expectedEvent = "InstanceCreated"; @@ -100,13 +181,14 @@ const deploy = async (network, secret) => { "There is no such event" ); contracts.Post.instance = new ethers.Contract(eventFound.args.instance, contracts.Post.artifact.abi, deployer.provider); - console.log(`Post instance created at ${eventFound.args.instance} by ${await contracts.Post.instance.getCreator()}`); + console.log(`createExplicit() | Post_Factory => ${eventFound.args.instance}`); }); await contracts.Feed_Factory.instance.createExplicit( userAddress, contracts.Erasure_Posts.instance.contractAddress, - '0x0' + '0x0', + { gasPrice: defaultGas } ).then(async txn => { const receipt = await contracts.Feed_Factory.instance.verboseWaitForTransaction(txn); const expectedEvent = "InstanceCreated"; @@ -115,7 +197,7 @@ const deploy = async (network, secret) => { "There is no such event" ); contracts.Feed.instance = new ethers.Contract(eventFound.args.instance, contracts.Feed.artifact.abi, deployer.provider); - console.log(`Feed instance created at ${eventFound.args.instance} by ${await contracts.Feed.instance.getCreator()}`); + console.log(`createExplicit() | Feed_Factory => ${eventFound.args.instance}`); }); await contracts.OneWayGriefing_Factory.instance.createExplicit( @@ -126,7 +208,8 @@ const deploy = async (network, secret) => { 1, 2, 100000000, - '0x0' + '0x0', + { gasPrice: defaultGas } ).then(async txn => { const receipt = await contracts.OneWayGriefing_Factory.instance.verboseWaitForTransaction(txn); const expectedEvent = "InstanceCreated"; @@ -135,11 +218,11 @@ const deploy = async (network, secret) => { "There is no such event" ); contracts.OneWayGriefing.instance = new ethers.Contract(eventFound.args.instance, contracts.OneWayGriefing.artifact.abi, deployer.provider); - console.log(`OneWayGriefing instance created at ${eventFound.args.instance} by ${await contracts.OneWayGriefing.instance.getCreator()}`); + console.log(`createExplicit() | OneWayGriefing_Factory => ${eventFound.args.instance}`); }); -}; + console.log(``); -module.exports = { - deploy }; + +module.exports = { deploy }; diff --git a/test/agreements/OneWayGriefing.js b/test/agreements/OneWayGriefing.js index a9947b8b..d86fb556 100644 --- a/test/agreements/OneWayGriefing.js +++ b/test/agreements/OneWayGriefing.js @@ -9,10 +9,16 @@ describe("OneWayGriefing", function() { this.timeout(4000); // wallets and addresses - const [operatorWallet, counterpartyWallet, stakerWallet] = accounts; + const [ + operatorWallet, + counterpartyWallet, + stakerWallet, + newOperatorWallet + ] = accounts; const operator = operatorWallet.signer.signingKey.address; const counterparty = counterpartyWallet.signer.signingKey.address; const staker = stakerWallet.signer.signingKey.address; + const newOperator = newOperatorWallet.signer.signingKey.address; // variables used in initialize() const stakerStake = ethers.utils.parseEther("200"); @@ -693,4 +699,70 @@ describe("OneWayGriefing", function() { assert.equal(actualRetrieveAmount.toString(), stakerStake.toString()); }); }); + + describe("OneWayGriefing.transferOperator", () => { + it("should revert when msg.sender is not operator", async () => { + await assert.revertWith( + this.TestOneWayGriefing.from(counterparty).transferOperator( + newOperator + ), + "only active operator" + ); + }); + + it("should revert when msg.sender is not active operator", async () => { + await this.TestOneWayGriefing.deactivateOperator(); + await assert.revertWith( + this.TestOneWayGriefing.from(counterparty).transferOperator( + newOperator + ), + "only active operator" + ); + await this.TestOneWayGriefing.activateOperator(); + }); + + it("should transfer operator", async () => { + const txn = await this.TestOneWayGriefing.transferOperator(newOperator); + await assert.emit(txn, "OperatorUpdated"); + await assert.emitWithArgs(txn, [newOperator, true]); + + const actualOperator = await this.TestOneWayGriefing.getOperator(); + assert.equal(actualOperator, newOperator); + + const isActive = await this.TestOneWayGriefing.hasActiveOperator(); + assert.equal(isActive, true); + }); + }); + + describe("OneWayGriefing.renounceOperator", () => { + it("should revert when msg.sender is not operator", async () => { + await assert.revertWith( + this.TestOneWayGriefing.from(counterparty).renounceOperator(), + "only active operator" + ); + }); + + it("should revert when msg.sender is not active operator", async () => { + await this.TestOneWayGriefing.deactivateOperator(); + await assert.revertWith( + this.TestOneWayGriefing.from(operator).renounceOperator(), + "only active operator" + ); + await this.TestOneWayGriefing.activateOperator(); + }); + + it("should revert when msg.sender is not active operator", async () => { + const txn = await this.TestOneWayGriefing.from( + newOperator + ).renounceOperator(); + await assert.emit(txn, "OperatorUpdated"); + await assert.emitWithArgs(txn, [ethers.constants.AddressZero, false]); + + const actualOperator = await this.TestOneWayGriefing.getOperator(); + assert.equal(actualOperator, ethers.constants.AddressZero); + + const isActive = await this.TestOneWayGriefing.hasActiveOperator(); + assert.equal(isActive, false); + }); + }); }); diff --git a/test/modules/Operated.js b/test/modules/Operated.js index b74f00b7..7836def3 100644 --- a/test/modules/Operated.js +++ b/test/modules/Operated.js @@ -1,11 +1,9 @@ const { createDeployer } = require("../helpers/setup"); describe("Operated", function() { - let wallets = { - numerai: accounts[0], - seller: accounts[1], - buyer: accounts[2] - }; + const [operatorWallet, newOperatorWallet] = accounts; + const operator = operatorWallet.signer.signingKey.address; + const newOperator = newOperatorWallet.signer.signingKey.address; let contracts = { TestOperated: { @@ -24,9 +22,9 @@ describe("Operated", function() { ); }); - describe("Operator._setOperator", () => { - const operator = wallets.seller.signer.signingKey.address; + // state functions + describe("Operator._setOperator", () => { it("should setOperator correctly", async () => { const txn = await contracts.TestOperated.instance.setOperator(operator); await assert.emit(txn, "OperatorUpdated"); @@ -70,7 +68,7 @@ describe("Operated", function() { }); describe("Operator._deactivateOperator", () => { - it("should deactivateOperator correctly", async () => { + it("should deactivateOperator correctly with zero address", async () => { await contracts.TestOperated.instance.activateOperator(); const txn = await contracts.TestOperated.instance.deactivateOperator(); @@ -81,6 +79,18 @@ describe("Operated", function() { assert.equal(actualIsActive, false); }); + it("should deactivateOperator correctly with active operator", async () => { + await contracts.TestOperated.instance.setOperator(operator); + await contracts.TestOperated.instance.activateOperator(); + + const txn = await contracts.TestOperated.instance.deactivateOperator(); + await assert.emit(txn, "OperatorUpdated"); + await assert.emitWithArgs(txn, [operator, false]); + + const actualIsActive = await contracts.TestOperated.instance.hasActiveOperator(); + assert.equal(actualIsActive, false); + }); + it("should revert when deactivateOperator called when operator not active", async () => { await assert.revertWith( contracts.TestOperated.instance.deactivateOperator(), @@ -89,9 +99,72 @@ describe("Operated", function() { }); }); - describe("Operator.isActiveOperator", () => { - const operator = wallets.seller.signer.signingKey.address; + describe("Operator._transferOperator", () => { + it("should transfer operator correctly", async () => { + await contracts.TestOperated.instance.setOperator(operator); + + const txn = await contracts.TestOperated.instance.transferOperator( + newOperator + ); + await assert.emit(txn, "OperatorUpdated"); + await assert.emitWithArgs(txn, [newOperator, false]); + + const actualOperator = await contracts.TestOperated.instance.getOperator(); + assert.equal(actualOperator, newOperator); + + const isOperator = await contracts.TestOperated.instance.isOperator( + newOperator + ); + assert.equal(isOperator, true); + }); + it("should revert when no operator was set", async () => { + await assert.revertWith( + contracts.TestOperated.instance.transferOperator(newOperator), + "operator not set" + ); + }); + + // other revert cases are covered in Operated._setOperator tests already + }); + + describe("Operator._renounceOperator", () => { + it("should renounce operator correctly", async () => { + await contracts.TestOperated.instance.activateOperator(); + + const txn = await contracts.TestOperated.instance.renounceOperator(); + await assert.emit(txn, "OperatorUpdated"); + await assert.emitWithArgs(txn, [ethers.constants.AddressZero, false]); + + const actualOperator = await contracts.TestOperated.instance.getOperator(); + assert.equal(actualOperator, ethers.constants.AddressZero); + + const status = await contracts.TestOperated.instance.hasActiveOperator(); + assert.equal(status, false); + }); + + it("should revert when operator is not active", async () => { + await contracts.TestOperated.instance.activateOperator(); + + await contracts.TestOperated.instance.deactivateOperator(); + + await assert.revertWith( + contracts.TestOperated.instance.renounceOperator(), + "only when operator active" + ); + }); + + it("should revert when no operator is set", async () => { + await assert.revertWith( + contracts.TestOperated.instance.renounceOperator(), + "only when operator active" + ); + }); + }); + + // view functions + + describe("Operator.isActiveOperator", () => { it("should get isActiveOperator=true correctly", async () => { await contracts.TestOperated.instance.activateOperator(); await contracts.TestOperated.instance.setOperator(operator); diff --git a/test/modules/Registry.js b/test/modules/Registry.js index d90ef6ac..df4642c1 100644 --- a/test/modules/Registry.js +++ b/test/modules/Registry.js @@ -245,8 +245,24 @@ describe("Registry", function() { }); }); + describe("Registry.getFactoryAddress", () => { + it("gets factory address correctly", async () => { + this.timeout(6000); // increase timeout because getFactoryAddress take long + + for (let factoryId = 0; factoryId < factories.length; factoryId++) { + const factoryAddress = factories[factoryId]; + const actualFactoryAddress = await this.Registry.getFactoryAddress( + factoryId + ); + assert.equal(factoryAddress, actualFactoryAddress); + } + }); + }); + describe("Registry.getFactories", () => { it("should get factories correctly", async () => { + this.timeout(6000); // increase timeout because getFactories take long + const actualFactories = await this.Registry.getFactories(); assert.deepEqual(actualFactories, factories); });