Skip to content

Commit

Permalink
Merge pull request lens-protocol#121 from aave/fix/emergency-admin-scope
Browse files Browse the repository at this point in the history
Feat: Prevent Emergency Admin From Setting State When Paused
  • Loading branch information
donosonaumczuk authored May 6, 2022
2 parents 5bad9db + 6285b92 commit 1456844
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 7 deletions.
1 change: 1 addition & 0 deletions contracts/core/LensHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ contract LensHub is LensNFTBase, VersionedInitializable, LensMultiState, LensHub
if (msg.sender == _emergencyAdmin) {
if (newState == DataTypes.ProtocolState.Unpaused)
revert Errors.EmergencyAdminCannotUnpause();
_validateNotPaused();
} else if (msg.sender != _governance) {
revert Errors.NotGovernanceOrEmergencyAdmin();
}
Expand Down
5 changes: 4 additions & 1 deletion contracts/interfaces/ILensHub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ interface ILensHub {
* @notice Sets the protocol state to either a global pause, a publishing pause or an unpaused state. This function
* can only be called by the governance address or the emergency admin address.
*
* Note that this reverts if the emergency admin calls it if:
* 1. The emergency admin is attempting to unpause.
* 2. The emergency admin is calling while the protocol is already paused.
*
* @param newState The state to set, as a member of the ProtocolState enum.
*/
function setState(DataTypes.ProtocolState newState) external;
Expand Down Expand Up @@ -537,5 +541,4 @@ interface ILensHub {
* @return address The collect NFT implementation address.
*/
function getCollectNFTImpl() external view returns (address);

}
31 changes: 29 additions & 2 deletions test/hub/interactions/multi-state-hub.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,20 +51,29 @@ makeSuiteCleanRoom('Multi-State Hub', function () {
);
});

it('Governance should set user as emergency admin, user should fail to set protocol state to unpaused', async function () {
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
);
});

it('Governance should set user as emergency admin, user should fail to set protocol state to PublishingPaused or Paused from Paused', async function () {
await expect(lensHub.connect(governance).setEmergencyAdmin(userAddress)).to.not.be.reverted;
await expect(lensHub.connect(governance).setState(ProtocolState.Paused)).to.not.be.reverted;
await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.be.revertedWith(
ERRORS.PAUSED
);
await expect(lensHub.setState(ProtocolState.Paused)).to.be.revertedWith(ERRORS.PAUSED);
});
});

context('Scenarios', function () {
it('Governance should set user as emergency admin, user sets protocol state but fails to set emergency admin, governance sets emergency admin to the zero address, user fails to set protocol state', async function () {
await expect(lensHub.connect(governance).setEmergencyAdmin(userAddress)).to.not.be.reverted;

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.Paused)).to.not.be.reverted;
await expect(lensHub.setEmergencyAdmin(ZERO_ADDRESS)).to.be.revertedWith(
ERRORS.NOT_GOVERNANCE
);
Expand Down Expand Up @@ -98,6 +107,23 @@ makeSuiteCleanRoom('Multi-State Hub', function () {
).to.not.be.reverted;
expect(await lensHub.getState()).to.eq(ProtocolState.Unpaused);
});

it('Governance should set user as emergency admin, user should set protocol state to PublishingPaused, then Paused, then fail to set it to PublishingPaused', async function () {
await expect(lensHub.connect(governance).setEmergencyAdmin(userAddress)).to.not.be.reverted;

await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.not.be.reverted;
await expect(lensHub.setState(ProtocolState.Paused)).to.not.be.reverted;
await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.be.revertedWith(
ERRORS.PAUSED
);
});

it('Governance should set user as emergency admin, user should set protocol state to PublishingPaused, then set it to PublishingPaused again without reverting', async function () {
await expect(lensHub.connect(governance).setEmergencyAdmin(userAddress)).to.not.be.reverted;

await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.not.be.reverted;
await expect(lensHub.setState(ProtocolState.PublishingPaused)).to.not.be.reverted;
});
});
});

Expand All @@ -121,6 +147,7 @@ makeSuiteCleanRoom('Multi-State Hub', function () {
lensHub.transferFrom(userAddress, userTwoAddress, FIRST_PROFILE_ID)
).to.be.revertedWith(ERRORS.PAUSED);
});

it('Governance should pause the hub, profile creation should fail, then governance unpauses the hub and profile creation should work', async function () {
await expect(lensHub.connect(governance).setState(ProtocolState.Paused)).to.not.be.reverted;

Expand Down
9 changes: 5 additions & 4 deletions test/other/events.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,23 +148,24 @@ makeSuiteCleanRoom('Events', function () {

it('Protocol state change by emergency admin should emit expected events', async function () {
await waitForTx(lensHub.connect(governance).setEmergencyAdmin(userAddress));
receipt = await waitForTx(lensHub.connect(user).setState(ProtocolState.Paused));

receipt = await waitForTx(lensHub.connect(user).setState(ProtocolState.PublishingPaused));

expect(receipt.logs.length).to.eq(1);
matchEvent(receipt, 'StateSet', [
userAddress,
ProtocolState.Unpaused,
ProtocolState.Paused,
ProtocolState.PublishingPaused,
await getTimestamp(),
]);

receipt = await waitForTx(lensHub.connect(user).setState(ProtocolState.PublishingPaused));
receipt = await waitForTx(lensHub.connect(user).setState(ProtocolState.Paused));

expect(receipt.logs.length).to.eq(1);
matchEvent(receipt, 'StateSet', [
userAddress,
ProtocolState.Paused,
ProtocolState.PublishingPaused,
ProtocolState.Paused,
await getTimestamp(),
]);
});
Expand Down

0 comments on commit 1456844

Please sign in to comment.