AccessManaged.test.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. const { ethers } = require('hardhat');
  2. const { loadFixture } = require('@nomicfoundation/hardhat-network-helpers');
  3. const { impersonate } = require('../../helpers/account');
  4. const { bigint: time } = require('../../helpers/time');
  5. async function fixture() {
  6. const [admin, roleMember, other] = await ethers.getSigners();
  7. const authority = await ethers.deployContract('$AccessManager', [admin]);
  8. const managed = await ethers.deployContract('$AccessManagedTarget', [authority]);
  9. const anotherAuthority = await ethers.deployContract('$AccessManager', [admin]);
  10. const authorityObserveIsConsuming = await ethers.deployContract('$AuthorityObserveIsConsuming');
  11. await impersonate(authority.target);
  12. const authorityAsSigner = await ethers.getSigner(authority.target);
  13. return {
  14. roleMember,
  15. other,
  16. authorityAsSigner,
  17. authority,
  18. managed,
  19. authorityObserveIsConsuming,
  20. anotherAuthority,
  21. };
  22. }
  23. describe('AccessManaged', function () {
  24. beforeEach(async function () {
  25. Object.assign(this, await loadFixture(fixture));
  26. });
  27. it('sets authority and emits AuthorityUpdated event during construction', async function () {
  28. await expect(this.managed.deploymentTransaction())
  29. .to.emit(this.managed, 'AuthorityUpdated')
  30. .withArgs(this.authority.target);
  31. });
  32. describe('restricted modifier', function () {
  33. beforeEach(async function () {
  34. this.selector = this.managed.fnRestricted.getFragment().selector;
  35. this.role = 42n;
  36. await this.authority.$_setTargetFunctionRole(this.managed, this.selector, this.role);
  37. await this.authority.$_grantRole(this.role, this.roleMember, 0, 0);
  38. });
  39. it('succeeds when role is granted without execution delay', async function () {
  40. await this.managed.connect(this.roleMember)[this.selector]();
  41. });
  42. it('reverts when role is not granted', async function () {
  43. await expect(this.managed.connect(this.other)[this.selector]())
  44. .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
  45. .withArgs(this.other.address);
  46. });
  47. it('panics in short calldata', async function () {
  48. // We avoid adding the `restricted` modifier to the fallback function because other tests may depend on it
  49. // being accessible without restrictions. We check for the internal `_checkCanCall` instead.
  50. await expect(this.managed.$_checkCanCall(this.roleMember, '0x1234')).to.be.reverted;
  51. });
  52. describe('when role is granted with execution delay', function () {
  53. beforeEach(async function () {
  54. const executionDelay = 911n;
  55. await this.authority.$_grantRole(this.role, this.roleMember, 0, executionDelay);
  56. });
  57. it('reverts if the operation is not scheduled', async function () {
  58. const fn = this.managed.interface.getFunction(this.selector);
  59. const calldata = this.managed.interface.encodeFunctionData(fn, []);
  60. const opId = await this.authority.hashOperation(this.roleMember, this.managed, calldata);
  61. await expect(this.managed.connect(this.roleMember)[this.selector]())
  62. .to.be.revertedWithCustomError(this.authority, 'AccessManagerNotScheduled')
  63. .withArgs(opId);
  64. });
  65. it('succeeds if the operation is scheduled', async function () {
  66. // Arguments
  67. const delay = time.duration.hours(12);
  68. const fn = this.managed.interface.getFunction(this.selector);
  69. const calldata = this.managed.interface.encodeFunctionData(fn, []);
  70. // Schedule
  71. const scheduledAt = (await time.clock.timestamp()) + 1n;
  72. const when = scheduledAt + delay;
  73. await time.increaseTo.timestamp(scheduledAt, false);
  74. await this.authority.connect(this.roleMember).schedule(this.managed, calldata, when);
  75. // Set execution date
  76. await time.increaseTo.timestamp(when, false);
  77. // Shouldn't revert
  78. await this.managed.connect(this.roleMember)[this.selector]();
  79. });
  80. });
  81. });
  82. describe('setAuthority', function () {
  83. it('reverts if the caller is not the authority', async function () {
  84. await expect(this.managed.connect(this.other).setAuthority(this.other))
  85. .to.be.revertedWithCustomError(this.managed, 'AccessManagedUnauthorized')
  86. .withArgs(this.other.address);
  87. });
  88. it('reverts if the new authority is not a valid authority', async function () {
  89. await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.other))
  90. .to.be.revertedWithCustomError(this.managed, 'AccessManagedInvalidAuthority')
  91. .withArgs(this.other.address);
  92. });
  93. it('sets authority and emits AuthorityUpdated event', async function () {
  94. await expect(this.managed.connect(this.authorityAsSigner).setAuthority(this.anotherAuthority))
  95. .to.emit(this.managed, 'AuthorityUpdated')
  96. .withArgs(this.anotherAuthority.target);
  97. expect(await this.managed.authority()).to.equal(this.anotherAuthority.target);
  98. });
  99. });
  100. describe('isConsumingScheduledOp', function () {
  101. beforeEach(async function () {
  102. await this.managed.connect(this.authorityAsSigner).setAuthority(this.authorityObserveIsConsuming);
  103. });
  104. it('returns bytes4(0) when not consuming operation', async function () {
  105. expect(await this.managed.isConsumingScheduledOp()).to.equal('0x00000000');
  106. });
  107. it('returns isConsumingScheduledOp selector when consuming operation', async function () {
  108. const isConsumingScheduledOp = this.managed.interface.getFunction('isConsumingScheduledOp()');
  109. const fnRestricted = this.managed.fnRestricted.getFragment();
  110. await expect(this.managed.connect(this.other).fnRestricted())
  111. .to.emit(this.authorityObserveIsConsuming, 'ConsumeScheduledOpCalled')
  112. .withArgs(
  113. this.other.address,
  114. this.managed.interface.encodeFunctionData(fnRestricted, []),
  115. isConsumingScheduledOp.selector,
  116. );
  117. });
  118. });
  119. });