Skip to content

Commit

Permalink
test(withdrawal.queue): add acl tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tamtamchik committed Feb 15, 2024
1 parent 3b1af50 commit 2897c27
Show file tree
Hide file tree
Showing 5 changed files with 219 additions and 8 deletions.
7 changes: 7 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,11 @@ export const ERC4906_INTERFACE_ID = "0x49064906";
// special reserved interface id
export const INVALID_INTERFACE_ID = "0xffffffff";

// OZ Interfaces
export const OZ_ACCESS_CONTROL_INTERFACE_ID = "0x7965db0b";
export const OZ_ACCESS_CONTROL_ENUMERABLE_INTERFACE_ID = "0x5a05180f";

export const BLOCK_TIME = 12n;

// Default admin role for AccessControl compatible contracts
export const DEFAULT_ADMIN_ROLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
4 changes: 2 additions & 2 deletions lib/withdrawal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export const WQ_BUNKER_MODE_DISABLED_TIMESTAMP = MAX_UINT256;
export const WQ_MIN_STETH_WITHDRAWAL_AMOUNT = 100n;
export const WQ_MAX_STETH_WITHDRAWAL_AMOUNT = 10n ** 21n; // 1000 * 1e18

export const WQ_DEFAULT_ADMIN_ROLE = streccak("DEFAULT_ADMIN_ROLE");
export const WQ_FINALIZE_ROLE = streccak("FINALIZE_ROLE");
export const WQ_MANAGE_TOKEN_URI_ROLE = streccak("MANAGE_TOKEN_URI_ROLE");
export const WQ_ORACLE_ROLE = streccak("ORACLE_ROLE");
Expand Down Expand Up @@ -156,9 +155,10 @@ export async function deployWithdrawalQueue({
await queue.connect(queueAdmin).grantRole(WQ_PAUSE_ROLE, queuePauser || queueAdmin);
await queue.connect(queueAdmin).grantRole(WQ_RESUME_ROLE, queueResumer || queueAdmin);
await queue.connect(queueAdmin).grantRole(WQ_ORACLE_ROLE, queueOracle || stEthAddress);
await queue.connect(queueAdmin).grantRole(WQ_MANAGE_TOKEN_URI_ROLE, queueAdmin);

if (doResume) {
await queue.connect(queueAdmin).resume({ from: queueResumer || queueAdmin });
await queue.connect(queueResumer || queueAdmin).resume();
}
}

Expand Down
171 changes: 171 additions & 0 deletions test/0.8.9/withdrawalQueue/withdrawalQueue.acl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
import { expect } from "chai";
import { ethers } from "hardhat";

import { HardhatEthersSigner } from "@nomicfoundation/hardhat-ethers/signers";

import { WithdrawalQueueERC721 } from "typechain-types";

import {
DEFAULT_ADMIN_ROLE,
deployWithdrawalQueue,
ERC165_INTERFACE_ID,
INVALID_INTERFACE_ID,
OZ_ACCESS_CONTROL_ENUMERABLE_INTERFACE_ID,
OZ_ACCESS_CONTROL_INTERFACE_ID,
randomAddress,
Snapshot,
WQ_FINALIZE_ROLE,
WQ_MANAGE_TOKEN_URI_ROLE,
WQ_ORACLE_ROLE,
WQ_PAUSE_ROLE,
WQ_RESUME_ROLE,
} from "lib";

describe(`WithdrawalQueueERC721:ACL`, () => {
let contract: WithdrawalQueueERC721;

let queueAdmin: HardhatEthersSigner;
let stranger: HardhatEthersSigner;
let pauser: HardhatEthersSigner;
let resumer: HardhatEthersSigner;
let oracle: HardhatEthersSigner;
let finalizer: HardhatEthersSigner;

let originalState: string;

before(async () => {
[queueAdmin, stranger, pauser, resumer, oracle, finalizer] = await ethers.getSigners();

const deployed = await deployWithdrawalQueue({
queueAdmin: queueAdmin,
queuePauser: pauser,
queueResumer: resumer,
queueOracle: oracle,
queueFinalizer: finalizer,
});

contract = deployed.queue;
});

beforeEach(async () => (originalState = await Snapshot.take()));

afterEach(async () => await Snapshot.restore(originalState));

context("supportsInterface", () => {
it("should return true for ERC165_INTERFACE_ID", async () => {
expect(await contract.supportsInterface(ERC165_INTERFACE_ID)).to.be.true;
});

it("should return true for AccessControl", async () => {
expect(await contract.supportsInterface(OZ_ACCESS_CONTROL_INTERFACE_ID)).to.be.true;
});

it("Returns true for AccessControlEnumerable", async () => {
expect(await contract.supportsInterface(OZ_ACCESS_CONTROL_ENUMERABLE_INTERFACE_ID)).to.equal(true);
});

it("Returns false for invalid interface", async () => {
expect(await contract.supportsInterface(INVALID_INTERFACE_ID)).to.equal(false);
});
});

context("hasRole", () => {
it("Returns false for a role that has not been granted", async () => {
expect(await contract.hasRole(DEFAULT_ADMIN_ROLE, randomAddress())).to.be.false;
});

it("Returns true for a role that has been granted", async () => {
expect(await contract.hasRole(DEFAULT_ADMIN_ROLE, queueAdmin)).to.be.true;
expect(await contract.hasRole(WQ_PAUSE_ROLE, pauser)).to.be.true;
expect(await contract.hasRole(WQ_RESUME_ROLE, resumer)).to.be.true;
expect(await contract.hasRole(WQ_ORACLE_ROLE, oracle)).to.be.true;
expect(await contract.hasRole(WQ_FINALIZE_ROLE, finalizer)).to.be.true;
expect(await contract.hasRole(WQ_MANAGE_TOKEN_URI_ROLE, queueAdmin)).to.be.true;
});
});

context("getRoleAdmin", () => {
it("Returns the admin role as admin role for itself", async () => {
expect(await contract.getRoleAdmin(DEFAULT_ADMIN_ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
});

it("Returns the default admin as other roles admin", async () => {
expect(await contract.getRoleAdmin(WQ_PAUSE_ROLE)).to.equal(DEFAULT_ADMIN_ROLE);
});
});

context("grantRole", () => {
it("Reverts if caller is not admin", async () => {
await expect(
contract.connect(pauser).grantRole(WQ_PAUSE_ROLE, pauser.address),
).to.be.revertedWithOZAccessControlError(pauser.address, DEFAULT_ADMIN_ROLE);
});

it("Does nothing if role is already granted", async () => {
await expect(contract.grantRole(WQ_PAUSE_ROLE, pauser.address)).not.to.emit(contract, "RoleGranted");
});

it("Grants the role", async () => {
await expect(await contract.grantRole(WQ_PAUSE_ROLE, stranger))
.to.emit(contract, "RoleGranted")
.withArgs(WQ_PAUSE_ROLE, stranger.address, queueAdmin.address);

expect(await contract.hasRole(WQ_PAUSE_ROLE, stranger.address)).to.be.true;
});
});

context("revokeRole", () => {
it("Reverts if caller is not admin", async () => {
await expect(
contract.connect(pauser).revokeRole(WQ_PAUSE_ROLE, pauser.address),
).to.be.revertedWithOZAccessControlError(pauser.address, DEFAULT_ADMIN_ROLE);
});

it("Does nothing if role is already revoked", async () => {
await expect(contract.revokeRole(WQ_RESUME_ROLE, pauser.address)).not.to.emit(contract, "RoleRevoked");
});

it("Revokes the role", async () => {
await expect(await contract.revokeRole(WQ_PAUSE_ROLE, pauser.address))
.to.emit(contract, "RoleRevoked")
.withArgs(WQ_PAUSE_ROLE, pauser.address, queueAdmin.address);

expect(await contract.hasRole(WQ_PAUSE_ROLE, pauser.address)).to.be.false;
});
});

context("renounceRole", () => {
it("Reverts if renounce not for self", async () => {
await expect(contract.renounceRole(WQ_PAUSE_ROLE, pauser.address)).to.be.revertedWith(
"AccessControl: can only renounce roles for self",
);
});

it("Does nothing if role is not assigned", async () => {
await expect(contract.connect(resumer).renounceRole(WQ_PAUSE_ROLE, resumer.address)).not.to.emit(
contract,
"RoleRevoked",
);
});

it("Revokes the role", async () => {
await expect(await contract.connect(resumer).renounceRole(WQ_RESUME_ROLE, resumer.address))
.to.emit(contract, "RoleRevoked")
.withArgs(WQ_RESUME_ROLE, resumer.address, resumer.address);

expect(await contract.hasRole(WQ_RESUME_ROLE, resumer.address)).to.be.false;
});
});

context("getRoleMemberCount", () => {
it("Returns the number of role members", async () => {
expect(await contract.getRoleMemberCount(WQ_PAUSE_ROLE)).to.equal(1);
});
});

context("getRoleMember", () => {
it("Returns the address of the role member", async () => {
expect(await contract.getRoleMember(WQ_PAUSE_ROLE, 0)).to.be.equal(pauser.address);
});
});
});
41 changes: 36 additions & 5 deletions test/0.8.9/withdrawalQueue/withdrawalQueue.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,44 @@ describe("WithdrawalQueueERC721.sol", () => {
it("Disables bunker mode", async () => {
await withdrawalQueue.initialize(queueAdmin.address);

const BUNKER_MODE_DISABLED_TIMESTAMP = await withdrawalQueue.BUNKER_MODE_DISABLED_TIMESTAMP();
const TS = await withdrawalQueue.BUNKER_MODE_DISABLED_TIMESTAMP();

expect(await withdrawalQueue.isBunkerModeActive()).to.equal(false, "isBunkerModeActive");
expect(await withdrawalQueue.bunkerModeSinceTimestamp()).to.equal(
BUNKER_MODE_DISABLED_TIMESTAMP,
"bunkerModeSinceTimestamp",
);
expect(await withdrawalQueue.bunkerModeSinceTimestamp()).to.equal(TS, "bunkerModeSinceTimestamp");
});
});

context("Bunker mode", () => {
beforeEach(async () => {
originalState = await Snapshot.take();
});

afterEach(async () => {
await Snapshot.restore(originalState);
});

context("isBunkerModeActive", () => {
it("Returns true if bunker mode is active", async () => {
expect(await withdrawalQueue.isBunkerModeActive()).to.equal(true);
});

it("Returns false if bunker mode is disabled", async () => {
await withdrawalQueue.initialize(queueAdmin.address);

expect(await withdrawalQueue.isBunkerModeActive()).to.equal(false);
});
});

context("bunkerModeSinceTimestamp", () => {
it("Returns 0 if bunker mode is active", async () => {
expect(await withdrawalQueue.bunkerModeSinceTimestamp()).to.equal(0);
});

it("Returns the timestamp if bunker mode is disabled", async () => {
await withdrawalQueue.initialize(queueAdmin.address);

expect(await withdrawalQueue.bunkerModeSinceTimestamp()).to.equal(WQ_BUNKER_MODE_DISABLED_TIMESTAMP);
});
});
});
});
4 changes: 3 additions & 1 deletion test/common/erc20.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ interface ERC20Target {
* @function testERC20Compliance
* @description This function provides a black-box test suite for verifying
* the compliance of Ethereum contracts with the ERC-20 token standard.
* Reference: https://eips.ethereum.org/EIPS/eip-20
*
* It is designed to strictly adhere to the specifications prescribed in the ERC-20 standard.
* The test suite covers all mandatory aspects of the standard, ensuringthat the contract
* The test suite covers all mandatory aspects of the standard, ensuring that the contract
* correctly implements essential functionalities such as totalSupply, balanceOf, transfer, and approve,
* along with events like Transfer and Approval.
*
Expand Down

0 comments on commit 2897c27

Please sign in to comment.