AccessManager.behavior.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. const { expect } = require('chai');
  2. const {
  3. LIKE_COMMON_IS_EXECUTING,
  4. LIKE_COMMON_GET_ACCESS,
  5. LIKE_COMMON_SCHEDULABLE,
  6. testAsSchedulableOperation,
  7. testAsRestrictedOperation,
  8. testAsDelayedOperation,
  9. testAsCanCall,
  10. testAsHasRole,
  11. } = require('./AccessManager.predicate');
  12. // ============ ADMIN OPERATION ============
  13. /**
  14. * @requires this.{manager,roles,calldata,role}
  15. */
  16. function shouldBehaveLikeDelayedAdminOperation() {
  17. const getAccessPath = LIKE_COMMON_GET_ACCESS;
  18. testAsDelayedOperation.mineDelay = true;
  19. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay =
  20. testAsDelayedOperation;
  21. getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = function () {
  22. beforeEach('set execution delay', async function () {
  23. this.scheduleIn = this.executionDelay; // For testAsDelayedOperation
  24. });
  25. testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE);
  26. };
  27. beforeEach('set target as manager', function () {
  28. this.target = this.manager;
  29. });
  30. testAsRestrictedOperation({
  31. callerIsTheManager: LIKE_COMMON_IS_EXECUTING,
  32. callerIsNotTheManager() {
  33. testAsHasRole({
  34. publicRoleIsRequired() {
  35. it('reverts as AccessManagerUnauthorizedAccount', async function () {
  36. await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
  37. .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
  38. .withArgs(
  39. this.caller,
  40. this.roles.ADMIN.id, // Although PUBLIC is required, target function role doesn't apply to admin ops
  41. );
  42. });
  43. },
  44. specificRoleIsRequired: getAccessPath,
  45. });
  46. },
  47. });
  48. }
  49. /**
  50. * @requires this.{manager,roles,calldata,role}
  51. */
  52. function shouldBehaveLikeNotDelayedAdminOperation() {
  53. const getAccessPath = LIKE_COMMON_GET_ACCESS;
  54. function testScheduleOperation(mineDelay) {
  55. return function self() {
  56. self.mineDelay = mineDelay;
  57. beforeEach('set execution delay', async function () {
  58. this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation
  59. });
  60. testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE);
  61. };
  62. }
  63. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay =
  64. testScheduleOperation(true);
  65. getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false);
  66. beforeEach('set target as manager', function () {
  67. this.target = this.manager;
  68. });
  69. testAsRestrictedOperation({
  70. callerIsTheManager: LIKE_COMMON_IS_EXECUTING,
  71. callerIsNotTheManager() {
  72. testAsHasRole({
  73. publicRoleIsRequired() {
  74. it('reverts as AccessManagerUnauthorizedAccount', async function () {
  75. await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
  76. .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
  77. .withArgs(
  78. this.caller,
  79. this.roles.ADMIN.id, // Although PUBLIC_ROLE is required, admin ops are not subject to target function roles
  80. );
  81. });
  82. },
  83. specificRoleIsRequired: getAccessPath,
  84. });
  85. },
  86. });
  87. }
  88. /**
  89. * @requires this.{manager,roles,calldata,role}
  90. */
  91. function shouldBehaveLikeRoleAdminOperation(roleAdmin) {
  92. const getAccessPath = LIKE_COMMON_GET_ACCESS;
  93. function afterGrantDelay() {
  94. afterGrantDelay.mineDelay = true;
  95. beforeEach('set execution delay', async function () {
  96. this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation
  97. });
  98. testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE);
  99. }
  100. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay = afterGrantDelay;
  101. getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = afterGrantDelay;
  102. beforeEach('set target as manager', function () {
  103. this.target = this.manager;
  104. });
  105. testAsRestrictedOperation({
  106. callerIsTheManager: LIKE_COMMON_IS_EXECUTING,
  107. callerIsNotTheManager() {
  108. testAsHasRole({
  109. publicRoleIsRequired() {
  110. it('reverts as AccessManagerUnauthorizedAccount', async function () {
  111. await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
  112. .to.be.revertedWithCustomError(this.target, 'AccessManagerUnauthorizedAccount')
  113. .withArgs(this.caller, roleAdmin);
  114. });
  115. },
  116. specificRoleIsRequired: getAccessPath,
  117. });
  118. },
  119. });
  120. }
  121. // ============ RESTRICTED OPERATION ============
  122. /**
  123. * @requires this.{manager,roles,calldata,role}
  124. */
  125. function shouldBehaveLikeAManagedRestrictedOperation() {
  126. function revertUnauthorized() {
  127. it('reverts as AccessManagedUnauthorized', async function () {
  128. await expect(this.caller.sendTransaction({ to: this.target, data: this.calldata }))
  129. .to.be.revertedWithCustomError(this.target, 'AccessManagedUnauthorized')
  130. .withArgs(this.caller);
  131. });
  132. }
  133. const getAccessPath = LIKE_COMMON_GET_ACCESS;
  134. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.beforeGrantDelay =
  135. revertUnauthorized;
  136. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasNoExecutionDelay.beforeGrantDelay =
  137. revertUnauthorized;
  138. getAccessPath.requiredRoleIsNotGranted = revertUnauthorized;
  139. function testScheduleOperation(mineDelay) {
  140. return function self() {
  141. self.mineDelay = mineDelay;
  142. beforeEach('sets execution delay', async function () {
  143. this.scheduleIn = this.executionDelay; // For testAsSchedulableOperation
  144. });
  145. testAsSchedulableOperation(LIKE_COMMON_SCHEDULABLE);
  146. };
  147. }
  148. getAccessPath.requiredRoleIsGranted.roleGrantingIsDelayed.callerHasAnExecutionDelay.afterGrantDelay =
  149. testScheduleOperation(true);
  150. getAccessPath.requiredRoleIsGranted.roleGrantingIsNotDelayed.callerHasAnExecutionDelay = testScheduleOperation(false);
  151. const isExecutingPath = LIKE_COMMON_IS_EXECUTING;
  152. isExecutingPath.notExecuting = revertUnauthorized;
  153. testAsCanCall({
  154. closed: revertUnauthorized,
  155. open: {
  156. callerIsTheManager: isExecutingPath,
  157. callerIsNotTheManager: {
  158. publicRoleIsRequired() {
  159. it('succeeds called directly', async function () {
  160. await this.caller.sendTransaction({ to: this.target, data: this.calldata });
  161. });
  162. it('succeeds via execute', async function () {
  163. await this.manager.connect(this.caller).execute(this.target, this.calldata);
  164. });
  165. },
  166. specificRoleIsRequired: getAccessPath,
  167. },
  168. },
  169. });
  170. }
  171. module.exports = {
  172. shouldBehaveLikeDelayedAdminOperation,
  173. shouldBehaveLikeNotDelayedAdminOperation,
  174. shouldBehaveLikeRoleAdminOperation,
  175. shouldBehaveLikeAManagedRestrictedOperation,
  176. };