From f2db3bde433a8a203dd72564c049dabec5138c9f Mon Sep 17 00:00:00 2001 From: Peter Michael Date: Thu, 21 Apr 2022 11:55:11 -0400 Subject: [PATCH] feat: Prevented emergency admin from unpausing. Also includes follow/collect NFT getter tests. --- contracts/core/LensHub.sol | 8 +++++--- contracts/libraries/Errors.sol | 1 + test/__setup.spec.ts | 10 ++++++---- test/helpers/errors.ts | 3 ++- test/hub/interactions/multi-state-hub.spec.ts | 8 +++++++- test/other/events.spec.ts | 10 ---------- test/other/misc.spec.ts | 10 ++++++++++ 7 files changed, 31 insertions(+), 19 deletions(-) diff --git a/contracts/core/LensHub.sol b/contracts/core/LensHub.sol index 06e3ac9..3259c40 100644 --- a/contracts/core/LensHub.sol +++ b/contracts/core/LensHub.sol @@ -90,11 +90,13 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub /// @inheritdoc ILensHub function setState(DataTypes.ProtocolState newState) external override { - if (msg.sender == _governance || msg.sender == _emergencyAdmin) { - _setState(newState); - } else { + if (msg.sender == _emergencyAdmin) { + if (newState == DataTypes.ProtocolState.Unpaused) + revert Errors.EmergencyAdminCannotUnpause(); + } else if (msg.sender != _governance) { revert Errors.NotGovernanceOrEmergencyAdmin(); } + _setState(newState); } ///@inheritdoc ILensHub diff --git a/contracts/libraries/Errors.sol b/contracts/libraries/Errors.sol index 0648734..9db6c1a 100644 --- a/contracts/libraries/Errors.sol +++ b/contracts/libraries/Errors.sol @@ -13,6 +13,7 @@ library Errors { error TokenDoesNotExist(); error NotGovernance(); error NotGovernanceOrEmergencyAdmin(); + error EmergencyAdminCannotUnpause(); error CallerNotWhitelistedModule(); error CollectModuleNotWhitelisted(); error FollowModuleNotWhitelisted(); diff --git a/test/__setup.spec.ts b/test/__setup.spec.ts index f067df2..f2bbbb6 100644 --- a/test/__setup.spec.ts +++ b/test/__setup.spec.ts @@ -48,6 +48,8 @@ import { LensPeriphery__factory, ProfileFollowModule, ProfileFollowModule__factory, + FollowNFT, + CollectNFT, } from '../typechain-types'; import { LensHubLibraryAddresses } from '../typechain-types/factories/LensHub__factory'; import { FAKE_PRIVATEKEY, ZERO_ADDRESS } from './helpers/constants'; @@ -88,8 +90,6 @@ export let userAddress: string; export let userTwoAddress: string; export let userThreeAddress: string; export let governanceAddress: string; -export let followNFTImplAddress: string; -export let collectNFTImplAddress: string; export let treasuryAddress: string; export let testWallet: Wallet; export let lensHubImpl: LensHub; @@ -102,6 +102,8 @@ export let eventsLib: Events; export let moduleGlobals: ModuleGlobals; export let helper: Helper; export let lensPeriphery: LensPeriphery; +export let followNFTImpl: FollowNFT; +export let collectNFTImpl: CollectNFT; /* Modules */ @@ -178,8 +180,8 @@ before(async function () { const hubProxyAddress = computeContractAddress(deployerAddress, nonce + 3); //'0x' + keccak256(RLP.encode([deployerAddress, hubProxyNonce])).substr(26); - const followNFTImpl = await new FollowNFT__factory(deployer).deploy(hubProxyAddress); - const collectNFTImpl = await new CollectNFT__factory(deployer).deploy(hubProxyAddress); + followNFTImpl = await new FollowNFT__factory(deployer).deploy(hubProxyAddress); + collectNFTImpl = await new CollectNFT__factory(deployer).deploy(hubProxyAddress); lensHubImpl = await new LensHub__factory(hubLibs, deployer).deploy( followNFTImpl.address, diff --git a/test/helpers/errors.ts b/test/helpers/errors.ts index 2544d0a..2c52e13 100644 --- a/test/helpers/errors.ts +++ b/test/helpers/errors.ts @@ -9,6 +9,8 @@ export const ERRORS = { TOKEN_DOES_NOT_EXIST: 'TokenDoesNotExist()', CALLER_NOT_WHITELSITED_MODULE: 'CallerNotWhitelistedModule()', NOT_GOVERNANCE: 'NotGovernance()', + NOT_GOVERNANCE_OR_EMERGENCY_ADMIN: 'NotGovernanceOrEmergencyAdmin()', + EMERGENCY_ADMIN_CANNOT_UNPAUSE: 'EmergencyAdminCannotUnpause()', COLLECT_MODULE_NOT_WHITELISTED: 'CollectModuleNotWhitelisted()', FOLLOW_MODULE_NOT_WHITELISTED: 'FollowModuleNotWhitelisted()', REFERENCE_MODULE_NOT_WHITELISTED: 'ReferenceModuleNotWhitelisted()', @@ -43,7 +45,6 @@ export const ERRORS = { "Transaction reverted: function selector was not recognized and there's no fallback function", PAUSED: 'Paused()', PUBLISHING_PAUSED: 'PublishingPaused()', - NOT_GOVERNANCE_OR_EMERGENCY_ADMIN: 'NotGovernanceOrEmergencyAdmin()', NO_REASON_ABI_DECODE: "Transaction reverted and Hardhat couldn't infer the reason. Please report this to help us improve Hardhat.", }; diff --git a/test/hub/interactions/multi-state-hub.spec.ts b/test/hub/interactions/multi-state-hub.spec.ts index 6e36cdc..481c7ea 100644 --- a/test/hub/interactions/multi-state-hub.spec.ts +++ b/test/hub/interactions/multi-state-hub.spec.ts @@ -50,6 +50,13 @@ makeSuiteCleanRoom('Multi-State Hub', function () { ERRORS.NOT_GOVERNANCE ); }); + + it('Governance should set user as emergency admin, user should fail to set protocol state to unpaused', async function () { + await expect(lensHub.connect(governance).setEmergencyAdmin(userAddress)).to.not.be.reverted; + await expect(lensHub.setState(ProtocolState.Unpaused)).to.be.revertedWith( + ERRORS.EMERGENCY_ADMIN_CANNOT_UNPAUSE + ); + }); }); context('Scenarios', function () { @@ -58,7 +65,6 @@ makeSuiteCleanRoom('Multi-State Hub', function () { await expect(lensHub.setState(ProtocolState.Paused)).to.not.be.reverted; await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.not.be.reverted; - await expect(lensHub.setState(ProtocolState.Unpaused)).to.not.be.reverted; await expect(lensHub.setEmergencyAdmin(ZERO_ADDRESS)).to.be.revertedWith( ERRORS.NOT_GOVERNANCE ); diff --git a/test/other/events.spec.ts b/test/other/events.spec.ts index e91f560..d9ef40f 100644 --- a/test/other/events.spec.ts +++ b/test/other/events.spec.ts @@ -167,16 +167,6 @@ makeSuiteCleanRoom('Events', function () { ProtocolState.PublishingPaused, await getTimestamp(), ]); - - receipt = await waitForTx(lensHub.connect(user).setState(ProtocolState.Unpaused)); - - expect(receipt.logs.length).to.eq(1); - matchEvent(receipt, 'StateSet', [ - userAddress, - ProtocolState.PublishingPaused, - ProtocolState.Unpaused, - await getTimestamp(), - ]); }); it('Follow module whitelisting functions should emit expected event', async function () { diff --git a/test/other/misc.spec.ts b/test/other/misc.spec.ts index d39c61b..2f70399 100644 --- a/test/other/misc.spec.ts +++ b/test/other/misc.spec.ts @@ -43,6 +43,8 @@ import { userThree, testWallet, lensPeriphery, + followNFTImpl, + collectNFTImpl, } from '../__setup.spec'; /** @@ -167,6 +169,14 @@ makeSuiteCleanRoom('Misc', function () { expect(await lensHub.getPubCount(FIRST_PROFILE_ID)).to.eq(expectedCount); }); + it('Follow NFT impl getter should return the correct address', async function () { + expect(await lensHub.getFollowNFTImpl()).to.eq(followNFTImpl.address); + }); + + it('Collect NFT impl getter should return the correct address', async function () { + expect(await lensHub.getCollectNFTImpl()).to.eq(collectNFTImpl.address); + }); + it('Profile tokenURI should return the accurate URI', async function () { const tokenUri = await lensHub.tokenURI(FIRST_PROFILE_ID); const metadata = await getMetadataFromBase64TokenUri(tokenUri);