123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- const { ethers } = require('hardhat');
- const { expect } = require('chai');
- const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
- const { impersonate } = require('../../helpers/account');
- const time = require('../../helpers/time');
- async function fixture() {
- const [admin, roleMember, other] = await ethers.getSigners();
- const authority = await ethers.deployContract('$AccessManager', [admin]);
- const managed = await ethers.deployContract('$AccessManagedTarget', [authority]);
- const anotherAuthority = await ethers.deployContract('$AccessManager', [admin]);
- const authorityObserveIsConsuming = await ethers.deployContract('$AuthorityObserveIsConsuming');
- await impersonate(authority.target);
- const authorityAsSigner = await ethers.getSigner(authority.target);
- return {
- roleMember,
- other,
- authorityAsSigner,
- authority,
- managed,
- authorityObserveIsConsuming,
- anotherAuthority,
- };
- }
- describe('AccessManaged', function () {
- beforeEach(async function () {
- Object.assign(this, await loadFixture(fixture));
- });
- it('sets authority and emits AuthorityUpdated event during construction', async function () {
- await expect(this.managed.deploymentTransaction())
- .to.emit(this.managed, 'AuthorityUpdated')
- .withArgs(this.authority);
- });
- describe('restricted modifier', function () {
- beforeEach(async function () {
- this.selector = this.managed.fnRestricted.getFragment().selector;
- this.role = 42n;
- await this.authority.$_setTargetFunctionRole(this.managed, this.selector, this.role);
- await this.authority.$_grantRole(this.role, this.roleMember, 0, 0);
- });
- it('succeeds when role is granted without execution delay', async function () {
- await this.managed.connect(this.roleMember)[this.selector]();
- });
- it('reverts when role is not granted', async function () {
- await expect(this.managed.connect(this.other)[this.selector]())
- .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
- .withArgs(this.other);
- });
- it('panics in short calldata', async function () {
- // We avoid adding the `restricted` modifier to the fallback function because other tests may depend on it
- // being accessible without restrictions. We check for the internal `_checkCanCall` instead.
- await expect(this.managed.$_checkCanCall(this.roleMember, '0x1234')).to.be.reverted;
- });
- describe('when role is granted with execution delay', function () {
- beforeEach(async function () {
- const executionDelay = 911n;
- await this.authority.$_grantRole(this.role, this.roleMember, 0, executionDelay);
- });
- it('reverts if the operation is not scheduled', async function () {
- const fn = this.managed.interface.getFunction(this.selector);
- const calldata = this.managed.interface.encodeFunctionData(fn, []);
- const opId = await this.authority.hashOperation(this.roleMember, this.managed, calldata);
- await expect(this.managed.connect(this.roleMember)[this.selector]())
- .to.be.revertedWithCustomError(this.authority, 'AccessManagerNotScheduled')
- .withArgs(opId);
- });
- it('succeeds if the operation is scheduled', async function () {
- // Arguments
- const delay = time.duration.hours(12);
- const fn = this.managed.interface.getFunction(this.selector);
- const calldata = this.managed.interface.encodeFunctionData(fn, []);
- // Schedule
- const scheduledAt = (await time.clock.timestamp()) + 1n;
- const when = scheduledAt + delay;
- await time.increaseTo.timestamp(scheduledAt, false);
- await this.authority.connect(this.roleMember).schedule(this.managed, calldata, when);
- // Set execution date
- await time.increaseTo.timestamp(when, false);
- // Shouldn't revert
- await this.managed.connect(this.roleMember)[this.selector]();
- });
- });
- });
- describe('setAuthority', function () {
- it('reverts if the caller is not the authority', async function () {
- await expect(this.managed.connect(this.other).setAuthority(this.other))
- .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
- .withArgs(this.other);
- });
- it('reverts if the new authority is not a valid authority', async function () {
- await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.other))
- .to.be.revertedWithCustomError(this.managed, 'AccessManagedInvalidAuthority')
- .withArgs(this.other);
- });
- it('sets authority and emits AuthorityUpdated event', async function () {
- await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.anotherAuthority))
- .to.emit(this.managed, 'AuthorityUpdated')
- .withArgs(this.anotherAuthority);
- expect(await this.managed.authority()).to.equal(this.anotherAuthority);
- });
- });
- describe('isConsumingScheduledOp', function () {
- beforeEach(async function () {
- await this.managed.connect(this.authorityAsSigner).setAuthority(this.authorityObserveIsConsuming);
- });
- it('returns bytes4(0) when not consuming operation', async function () {
- expect(await this.managed.isConsumingScheduledOp()).to.equal('0x00000000');
- });
- it('returns isConsumingScheduledOp selector when consuming operation', async function () {
- const isConsumingScheduledOp = this.managed.interface.getFunction('isConsumingScheduledOp()');
- const fnRestricted = this.managed.fnRestricted.getFragment();
- await expect(this.managed.connect(this.other).fnRestricted())
- .to.emit(this.authorityObserveIsConsuming, 'ConsumeScheduledOpCalled')
- .withArgs(
- this.other,
- this.managed.interface.encodeFunctionData(fnRestricted, []),
- isConsumingScheduledOp.selector,
- );
- });
- });
- });
|