diff --git a/contracts/IBadger.sol b/contracts/IBadger.sol new file mode 100644 index 000000000..8d91966e2 --- /dev/null +++ b/contracts/IBadger.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +// Copyright (C) 2021 PrimeDao + +pragma solidity ^0.8.6; + +interface IBadger { + function balanceOf(address account, uint256 id) + external + view + returns (uint256); + + function mintBatch( + address to, + uint256[] memory ids, + uint256[] memory amounts + ) external view returns (uint256); + + function mint( + address account, + uint256 id, + uint256 amount + ) external; +} diff --git a/contracts/Permissions.sol b/contracts/Permissions.sol index 9472fdbbb..0f25622a6 100644 --- a/contracts/Permissions.sol +++ b/contracts/Permissions.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.6; import "@gnosis.pm/safe-contracts/contracts/common/Enum.sol"; +import "./IBadger.sol"; enum ParameterType { Static, @@ -35,7 +36,6 @@ struct TargetAddress { } struct Role { - mapping(address => bool) members; mapping(address => TargetAddress) targets; mapping(bytes32 => uint256) functions; mapping(bytes32 => bytes32) compValues; @@ -46,27 +46,27 @@ library Permissions { uint256 internal constant SCOPE_MAX_PARAMS = 48; event AllowTarget( - uint16 role, + uint256 badgeId, address targetAddress, ExecutionOptions options ); - event RevokeTarget(uint16 role, address targetAddress); - event ScopeTarget(uint16 role, address targetAddress); + event RevokeTarget(uint256 badgeId, address targetAddress); + event ScopeTarget(uint256 badgeId, address targetAddress); event ScopeAllowFunction( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 selector, ExecutionOptions options, uint256 resultingScopeConfig ); event ScopeRevokeFunction( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 selector, uint256 resultingScopeConfig ); event ScopeFunction( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 functionSig, bool[] isParamScoped, @@ -77,14 +77,14 @@ library Permissions { uint256 resultingScopeConfig ); event ScopeFunctionExecutionOptions( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 functionSig, ExecutionOptions options, uint256 resultingScopeConfig ); event ScopeParameter( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index, @@ -94,7 +94,7 @@ library Permissions { uint256 resultingScopeConfig ); event ScopeParameterAsOneOf( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index, @@ -103,7 +103,7 @@ library Permissions { uint256 resultingScopeConfig ); event UnscopeParameter( - uint16 role, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index, @@ -179,9 +179,11 @@ library Permissions { address to, uint256 value, bytes calldata data, - Enum.Operation operation + Enum.Operation operation, + IBadger badger, + uint256 badgeId ) public view { - if (!role.members[msg.sender]) { + if ((badger.balanceOf(msg.sender, badgeId)) == 0) { revert NoMembership(); } if (multisend == to) { @@ -377,41 +379,41 @@ library Permissions { function allowTarget( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, ExecutionOptions options ) external { role.targets[targetAddress] = TargetAddress(Clearance.Target, options); - emit AllowTarget(roleId, targetAddress, options); + emit AllowTarget(badgeId, targetAddress, options); } function revokeTarget( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress ) external { role.targets[targetAddress] = TargetAddress( Clearance.None, ExecutionOptions.None ); - emit RevokeTarget(roleId, targetAddress); + emit RevokeTarget(badgeId, targetAddress); } function scopeTarget( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress ) external { role.targets[targetAddress] = TargetAddress( Clearance.Function, ExecutionOptions.None ); - emit ScopeTarget(roleId, targetAddress); + emit ScopeTarget(badgeId, targetAddress); } function scopeAllowFunction( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, ExecutionOptions options @@ -428,8 +430,9 @@ library Permissions { role.functions[ keyForFunctions(targetAddress, functionSig) ] = scopeConfig; + emit ScopeAllowFunction( - roleId, + badgeId, targetAddress, functionSig, options, @@ -439,17 +442,17 @@ library Permissions { function scopeRevokeFunction( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig ) external { role.functions[keyForFunctions(targetAddress, functionSig)] = 0; - emit ScopeRevokeFunction(roleId, targetAddress, functionSig, 0); + emit ScopeRevokeFunction(badgeId, targetAddress, functionSig, 0); } function scopeFunction( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, bool[] memory isScoped, @@ -510,7 +513,7 @@ library Permissions { ] = compressCompValue(paramType[i], compValue[i]); } emit ScopeFunction( - roleId, + badgeId, targetAddress, functionSig, isScoped, @@ -524,7 +527,7 @@ library Permissions { function scopeFunctionExecutionOptions( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, ExecutionOptions options @@ -539,7 +542,7 @@ library Permissions { ] = scopeConfig; emit ScopeFunctionExecutionOptions( - roleId, + badgeId, targetAddress, functionSig, options, @@ -549,7 +552,7 @@ library Permissions { function scopeParameter( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index, @@ -581,7 +584,7 @@ library Permissions { ] = compressCompValue(paramType, compValue); emit ScopeParameter( - roleId, + badgeId, targetAddress, functionSig, index, @@ -594,7 +597,7 @@ library Permissions { function scopeParameterAsOneOf( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index, @@ -635,7 +638,7 @@ library Permissions { } emit ScopeParameterAsOneOf( - roleId, + badgeId, targetAddress, functionSig, index, @@ -647,7 +650,7 @@ library Permissions { function unscopeParameter( Role storage role, - uint16 roleId, + uint256 badgeId, address targetAddress, bytes4 functionSig, uint256 index @@ -668,7 +671,7 @@ library Permissions { role.functions[key] = scopeConfig; emit UnscopeParameter( - roleId, + badgeId, targetAddress, functionSig, index, @@ -981,4 +984,13 @@ library Permissions { ? bytes32(compValue) : keccak256(compValue); } + + function getTransactionHash( + address to, + uint256 value, + bytes memory data, + Enum.Operation operation + ) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(to, value, data, operation)); + } } diff --git a/contracts/Roles.sol b/contracts/Roles.sol index 869e41e02..53fe15171 100644 --- a/contracts/Roles.sol +++ b/contracts/Roles.sol @@ -1,16 +1,16 @@ // SPDX-License-Identifier: LGPL-3.0-only pragma solidity ^0.8.6; -import "@gnosis.pm/zodiac/contracts/core/Modifier.sol"; +import "@gnosis.pm/zodiac/contracts/core/Module.sol"; import "./Permissions.sol"; +import "./IBadger.sol"; -contract Roles is Modifier { +contract Roles is Module { address public multisend; + IBadger public badger; - mapping(address => uint16) public defaultRoles; - mapping(uint16 => Role) internal roles; + mapping(uint256 => Role) internal badgeRoles; - event AssignRoles(address module, uint16[] roles, bool[] memberOf); event SetMultisendAddress(address multisendAddress); event RolesModSetup( address indexed initiator, @@ -18,7 +18,6 @@ contract Roles is Modifier { address indexed avatar, address target ); - event SetDefaultRole(address module, uint16 defaultRole); /// `setUpModules` has already been called error SetUpModulesAlreadyCalled(); @@ -38,35 +37,31 @@ contract Roles is Modifier { constructor( address _owner, address _avatar, - address _target + address _target, + address _badger ) { - bytes memory initParams = abi.encode(_owner, _avatar, _target); + bytes memory initParams = abi.encode(_owner, _avatar, _target, _badger); setUp(initParams); } - function setUp(bytes memory initParams) public override { - (address _owner, address _avatar, address _target) = abi.decode( - initParams, - (address, address, address) - ); + function setUp(bytes memory initParams) public override initializer { + ( + address _owner, + address _avatar, + address _target, + address _badger + ) = abi.decode(initParams, (address, address, address, address)); __Ownable_init(); avatar = _avatar; target = _target; + badger = IBadger(_badger); transferOwnership(_owner); - setupModules(); emit RolesModSetup(msg.sender, _owner, _avatar, _target); } - function setupModules() internal { - if (modules[SENTINEL_MODULES] != address(0)) { - revert SetUpModulesAlreadyCalled(); - } - modules[SENTINEL_MODULES] = SENTINEL_MODULES; - } - /// @dev Set the address of the expected multisend library /// @notice Only callable by owner. /// @param _multisend address of the multisend library contract @@ -77,15 +72,20 @@ contract Roles is Modifier { /// @dev Allows all calls made to an address. /// @notice Only callable by owner. - /// @param role Role to set for + /// @param badgeId Role to set for /// @param targetAddress Address to be allowed /// @param options defines whether or not delegate calls and/or eth can be sent to the target address. function allowTarget( - uint16 role, + uint256 badgeId, address targetAddress, ExecutionOptions options ) external onlyOwner { - Permissions.allowTarget(roles[role], role, targetAddress, options); + Permissions.allowTarget( + badgeRoles[badgeId], + badgeId, + targetAddress, + options + ); } /// @dev Disallows all calls made to an address. @@ -96,7 +96,7 @@ contract Roles is Modifier { external onlyOwner { - Permissions.revokeTarget(roles[role], role, targetAddress); + Permissions.revokeTarget(badgeRoles[role], role, targetAddress); } /// @dev Scopes calls to an address, limited to specific function signatures, and per function scoping rules. @@ -107,7 +107,7 @@ contract Roles is Modifier { external onlyOwner { - Permissions.scopeTarget(roles[role], role, targetAddress); + Permissions.scopeTarget(badgeRoles[role], role, targetAddress); } /// @dev Allows a specific function signature on a scoped target. @@ -123,7 +123,7 @@ contract Roles is Modifier { ExecutionOptions options ) external onlyOwner { Permissions.scopeAllowFunction( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -142,7 +142,7 @@ contract Roles is Modifier { bytes4 functionSig ) external onlyOwner { Permissions.scopeRevokeFunction( - roles[role], + badgeRoles[role], role, targetAddress, functionSig @@ -170,7 +170,7 @@ contract Roles is Modifier { ExecutionOptions options ) external onlyOwner { Permissions.scopeFunction( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -196,7 +196,7 @@ contract Roles is Modifier { ExecutionOptions options ) external onlyOwner { Permissions.scopeFunctionExecutionOptions( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -223,7 +223,7 @@ contract Roles is Modifier { bytes calldata compValue ) external onlyOwner { Permissions.scopeParameter( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -252,7 +252,7 @@ contract Roles is Modifier { bytes[] calldata compValues ) external onlyOwner { Permissions.scopeParameterAsOneOf( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -275,7 +275,7 @@ contract Roles is Modifier { uint8 paramIndex ) external onlyOwner { Permissions.unscopeParameter( - roles[role], + badgeRoles[role], role, targetAddress, functionSig, @@ -283,35 +283,6 @@ contract Roles is Modifier { ); } - /// @dev Assigns and revokes roles to a given module. - /// @param module Module on which to assign/revoke roles. - /// @param _roles Roles to assign/revoke. - /// @param memberOf Assign (true) or revoke (false) corresponding _roles. - function assignRoles( - address module, - uint16[] calldata _roles, - bool[] calldata memberOf - ) external onlyOwner { - if (_roles.length != memberOf.length) { - revert ArraysDifferentLength(); - } - for (uint16 i = 0; i < _roles.length; i++) { - roles[_roles[i]].members[module] = memberOf[i]; - } - if (!isModuleEnabled(module)) { - enableModule(module); - } - emit AssignRoles(module, _roles, memberOf); - } - - /// @dev Sets the default role used for a module if it calls execTransactionFromModule() or execTransactionFromModuleReturnData(). - /// @param module Address of the module on which to set default role. - /// @param role Role to be set as default. - function setDefaultRole(address module, uint16 role) external onlyOwner { - defaultRoles[module] = role; - emit SetDefaultRole(module, role); - } - /// @dev Passes a transaction to the modifier. /// @param to Destination address of module transaction /// @param value Ether value of module transaction @@ -322,16 +293,20 @@ contract Roles is Modifier { address to, uint256 value, bytes calldata data, - Enum.Operation operation - ) public override moduleOnly returns (bool success) { + Enum.Operation operation, + uint256 badgeId + ) public returns (bool success) { Permissions.check( - roles[defaultRoles[msg.sender]], + badgeRoles[badgeId], multisend, to, value, data, - operation + operation, + badger, + badgeId ); + return exec(to, value, data, operation); } @@ -345,62 +320,19 @@ contract Roles is Modifier { address to, uint256 value, bytes calldata data, - Enum.Operation operation - ) public override moduleOnly returns (bool, bytes memory) { + Enum.Operation operation, + uint256 badgeId + ) public returns (bool, bytes memory) { Permissions.check( - roles[defaultRoles[msg.sender]], + badgeRoles[badgeId], multisend, to, value, data, - operation + operation, + badger, + badgeId ); return execAndReturnData(to, value, data, operation); } - - /// @dev Passes a transaction to the modifier assuming the specified role. - /// @param to Destination address of module transaction - /// @param value Ether value of module transaction - /// @param data Data payload of module transaction - /// @param operation Operation type of module transaction - /// @param role Identifier of the role to assume for this transaction - /// @param shouldRevert Should the function revert on inner execution returning success false? - /// @notice Can only be called by enabled modules - function execTransactionWithRole( - address to, - uint256 value, - bytes calldata data, - Enum.Operation operation, - uint16 role, - bool shouldRevert - ) public moduleOnly returns (bool success) { - Permissions.check(roles[role], multisend, to, value, data, operation); - success = exec(to, value, data, operation); - if (shouldRevert && !success) { - revert ModuleTransactionFailed(); - } - } - - /// @dev Passes a transaction to the modifier assuming the specified role. Expects return data. - /// @param to Destination address of module transaction - /// @param value Ether value of module transaction - /// @param data Data payload of module transaction - /// @param operation Operation type of module transaction - /// @param role Identifier of the role to assume for this transaction - /// @param shouldRevert Should the function revert on inner execution returning success false? - /// @notice Can only be called by enabled modules - function execTransactionWithRoleReturnData( - address to, - uint256 value, - bytes calldata data, - Enum.Operation operation, - uint16 role, - bool shouldRevert - ) public moduleOnly returns (bool success, bytes memory returnData) { - Permissions.check(roles[role], multisend, to, value, data, operation); - (success, returnData) = execAndReturnData(to, value, data, operation); - if (shouldRevert && !success) { - revert ModuleTransactionFailed(); - } - } } diff --git a/src/deploy/deploy_module.ts b/src/deploy/deploy_module.ts index 0ea195a12..866b1c924 100644 --- a/src/deploy/deploy_module.ts +++ b/src/deploy/deploy_module.ts @@ -7,7 +7,7 @@ const deploy: DeployFunction = async function (hre: HardhatRuntimeEnvironment) { const { deployments, getNamedAccounts } = hre; const { deployer } = await getNamedAccounts(); const { deploy } = deployments; - const args = [FirstAddress, FirstAddress, FirstAddress]; + const args = [FirstAddress, FirstAddress, FirstAddress, FirstAddress]; const txCheck = await deploy("Permissions", { from: deployer, diff --git a/test/Clearance.spec.ts b/test/Clearance.spec.ts index 6cb4e0cef..f940bd5e3 100644 --- a/test/Clearance.spec.ts +++ b/test/Clearance.spec.ts @@ -10,7 +10,10 @@ describe("Clearance", async () => { const TestContract = await hre.ethers.getContractFactory("TestContract"); const testContract = await TestContract.deploy(); const testContractClone = await TestContract.deploy(); - return { Avatar, avatar, testContract, testContractClone }; + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + + return { Avatar, avatar, testContract, testContractClone, badger }; }); const setupRolesWithOwnerAndInvoker = deployments.createFixture(async () => { @@ -29,11 +32,10 @@ describe("Clearance", async () => { const modifier = await Modifier.deploy( owner.address, base.avatar.address, - base.avatar.address + base.avatar.address, + base.badger.address ); - await modifier.enableModule(invoker.address); - return { ...base, Modifier, @@ -49,89 +51,92 @@ describe("Clearance", async () => { const OPTIONS_BOTH = 2; it("allows and then disallows a target", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; const { data } = await testContract.populateTransaction.doNothing(); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - + await badger.mint(invoker.address, BADGE_ID, 1); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.be.revertedWith("TargetAddressNotAllowed()"); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.not.be.reverted; - await modifier.connect(owner).revokeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).revokeTarget(BADGE_ID, testContract.address); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); it("allowing a target does not allow other targets", async () => { - const { modifier, testContract, testContractClone, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); + const { + modifier, + testContract, + testContractClone, + owner, + invoker, + badger, + } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); const { data } = await testContract.populateTransaction.doNothing(); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.not.be.reverted; await expect( modifier .connect(invoker) - .execTransactionFromModule(testContractClone.address, 0, data, 0) + .execTransactionFromModule( + testContractClone.address, + 0, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); it("allows and then disallows a function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); + const BADGE_ID = 1; - const ROLE_ID = 0; - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -142,39 +147,44 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.not.be.reverted; await modifier .connect(owner) - .scopeRevokeFunction(ROLE_ID, testContract.address, SELECTOR); + .scopeRevokeFunction(BADGE_ID, testContract.address, SELECTOR); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.be.revertedWith("FunctionNotAllowed()"); }); + it("allowing function on a target does not allow same function on diff target", async () => { - const { modifier, testContract, testContractClone, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); + const { + modifier, + testContract, + testContractClone, + owner, + invoker, + badger, + } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -186,32 +196,37 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 0) + .execTransactionFromModule(testContract.address, 0, data, 0, BADGE_ID) ).to.not.be.reverted; // but fail on the clone await expect( modifier .connect(invoker) - .execTransactionFromModule(testContractClone.address, 0, data, 0) + .execTransactionFromModule( + testContractClone.address, + 0, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); + it("allowing a function tightens a previously allowed target", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); const { data: dataDoNothing } = await testContract.populateTransaction.doNothing(); @@ -221,15 +236,20 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.not.be.reverted; - - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -238,24 +258,33 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoNothing, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoNothing, + 0, + BADGE_ID + ) ).to.not.be.reverted; await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.be.revertedWith("FunctionNotAllowed()"); }); it("allowing a target loosens a previously allowed function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - - const ROLE_ID = 0; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + const BADGE_ID = 1; + await badger.mint(invoker.address, BADGE_ID, 1); const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") @@ -265,12 +294,12 @@ describe("Clearance", async () => { const { data: dataDoEvenLess } = await testContract.populateTransaction.doEvenLess(); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -279,34 +308,50 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoNothing, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoNothing, + 0, + BADGE_ID + ) ).to.not.be.reverted; await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.be.revertedWith("FunctionNotAllowed()"); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.emit(testContract, "DoEvenLess"); }); it("disallowing one function does not impact other function allowances", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + const BADGE_ID = 1; + await badger.mint(invoker.address, BADGE_ID, 1); const SEL_DONOTHING = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") @@ -319,12 +364,12 @@ describe("Clearance", async () => { const { data: dataDoEvenLess } = await testContract.populateTransaction.doEvenLess(); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SEL_DONOTHING, OPTIONS_NONE @@ -333,7 +378,7 @@ describe("Clearance", async () => { await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SEL_DOEVENLESS, OPTIONS_NONE @@ -342,29 +387,53 @@ describe("Clearance", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoNothing, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoNothing, + 0, + BADGE_ID + ) ).to.not.be.reverted; await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.not.be.reverted; await modifier .connect(owner) - .scopeRevokeFunction(ROLE_ID, testContract.address, SEL_DOEVENLESS); + .scopeRevokeFunction(BADGE_ID, testContract.address, SEL_DOEVENLESS); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoNothing, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoNothing, + 0, + BADGE_ID + ) ).to.not.be.reverted; await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataDoEvenLess, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataDoEvenLess, + 0, + BADGE_ID + ) ).to.be.revertedWith("FunctionNotAllowed"); }); }); diff --git a/test/Comparison.spec.ts b/test/Comparison.spec.ts index 23f93a78b..c7d472be8 100644 --- a/test/Comparison.spec.ts +++ b/test/Comparison.spec.ts @@ -11,6 +11,9 @@ describe("Comparison", async () => { const testContract = await TestContract.deploy(); const testContractClone = await TestContract.deploy(); + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + const [owner, invoker] = waffle.provider.getWallets(); const Permissions = await hre.ethers.getContractFactory("Permissions"); @@ -24,11 +27,10 @@ describe("Comparison", async () => { const modifier = await Modifier.deploy( owner.address, avatar.address, - avatar.address + avatar.address, + badger.address ); - await modifier.enableModule(invoker.address); - return { Avatar, avatar, @@ -38,6 +40,7 @@ describe("Comparison", async () => { modifier, owner, invoker, + badger, }; }); @@ -56,9 +59,9 @@ describe("Comparison", async () => { const TYPE_DYNAMIC32 = 2; it("scopeFunction throws on input length mistmatch", async () => { - const { modifier, testContract, owner } = await setup(); + const { modifier, testContract, owner, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithTwoMixedParams") ); @@ -67,7 +70,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true, false], @@ -82,7 +85,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true, false], @@ -97,7 +100,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true, false], @@ -112,7 +115,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true, false], @@ -125,10 +128,10 @@ describe("Comparison", async () => { }); it("enforces paramComp for scopeFunction", async () => { - const { modifier, testContract, owner } = await setup(); + const { modifier, testContract, owner, badger } = await setup(); const IS_SCOPED = true; - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -137,7 +140,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [!IS_SCOPED, IS_SCOPED, !IS_SCOPED], @@ -156,7 +159,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [!IS_SCOPED, IS_SCOPED, !IS_SCOPED], @@ -176,7 +179,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [!IS_SCOPED, IS_SCOPED, IS_SCOPED], @@ -196,7 +199,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [!IS_SCOPED, IS_SCOPED, IS_SCOPED], @@ -212,9 +215,9 @@ describe("Comparison", async () => { ).to.not.be.reverted; }); it("enforces paramComp for scopeParameter", async () => { - const { modifier, testContract, owner } = await setup(); + const { modifier, testContract, owner, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -223,7 +226,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -237,7 +240,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -251,7 +254,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -265,7 +268,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -279,7 +282,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -293,7 +296,7 @@ describe("Comparison", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -305,9 +308,9 @@ describe("Comparison", async () => { }); it("passes an eq comparison", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); + const BADGE_ID = 1; - const ROLE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); @@ -319,20 +322,23 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.fnWithSingleParam(a)).data, - 0 + 0, + BADGE_ID ); + await badger.mint(invoker.address, BADGE_ID, 1); + await modifier .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -345,9 +351,9 @@ describe("Comparison", async () => { await expect(invoke(123)).to.not.be.reverted; }); it("passes an eq comparison for dynamic", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithTwoMixedParams") ); @@ -360,20 +366,19 @@ describe("Comparison", async () => { 0, (await testContract.populateTransaction.fnWithTwoMixedParams(a, b)) .data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -382,16 +387,16 @@ describe("Comparison", async () => { ethers.utils.solidityPack(["string"], ["Some string"]) ); - await expect(invoke(false, "Some string")).to.not.be.reverted; + await expect(invoke(false, "Some string")).to.not.be.revertedWith("lel"); await expect(invoke(false, "Some other string")).to.be.revertedWith( "ParameterNotAllowed()" ); }); it("passes an eq comparison for dynamic - empty buffer", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("dynamic") ); @@ -403,20 +408,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.dynamic(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -430,9 +434,9 @@ describe("Comparison", async () => { }); it("passes an eq comparison for dynamic32", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("dynamicDynamic32") ); @@ -444,20 +448,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.dynamicDynamic32(a, b)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -486,9 +489,9 @@ describe("Comparison", async () => { }); it("passes an eq comparison for dynamic32 - empty array", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("dynamic32") ); @@ -500,20 +503,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.dynamic32(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -529,9 +531,9 @@ describe("Comparison", async () => { }); it("re-scopes an eq paramComp", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); @@ -543,20 +545,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.fnWithSingleParam(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -571,7 +572,7 @@ describe("Comparison", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -585,9 +586,9 @@ describe("Comparison", async () => { }); it("passes a oneOf comparison", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); @@ -599,20 +600,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.fnWithSingleParam(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -629,9 +629,9 @@ describe("Comparison", async () => { }); it("passes a oneOf comparison for dynamic", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithTwoMixedParams") ); @@ -644,20 +644,19 @@ describe("Comparison", async () => { 0, (await testContract.populateTransaction.fnWithTwoMixedParams(a, b)) .data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -679,9 +678,9 @@ describe("Comparison", async () => { }); it("passes a oneOf comparison for dynamic32", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("dynamicDynamic32") ); @@ -693,20 +692,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.dynamicDynamic32(a, b)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -741,9 +739,9 @@ describe("Comparison", async () => { }); it("re-scopes a oneOf comparison to simple paramComp", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); @@ -755,20 +753,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.fnWithSingleParam(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -788,7 +785,7 @@ describe("Comparison", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -802,9 +799,9 @@ describe("Comparison", async () => { }); it("should pass a gt/lt comparison", async () => { - const { modifier, testContract, owner, invoker } = await setup(); + const { modifier, testContract, owner, invoker, badger } = await setup(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); @@ -816,20 +813,19 @@ describe("Comparison", async () => { testContract.address, 0, (await testContract.populateTransaction.fnWithSingleParam(a)).data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // set it to true - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -845,7 +841,7 @@ describe("Comparison", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, diff --git a/test/EmitsEvent.spec.ts b/test/EmitsEvent.spec.ts index be41468fc..1bc551b30 100644 --- a/test/EmitsEvent.spec.ts +++ b/test/EmitsEvent.spec.ts @@ -24,6 +24,9 @@ describe.skip("EmitsEvent", async () => { const Avatar = await hre.ethers.getContractFactory("TestAvatar"); const avatar = await Avatar.deploy(); + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + const [owner] = waffle.provider.getWallets(); const Permissions = await hre.ethers.getContractFactory("Permissions"); @@ -37,7 +40,8 @@ describe.skip("EmitsEvent", async () => { const modifier = await Modifier.deploy( owner.address, avatar.address, - avatar.address + avatar.address, + badger.address ); return { @@ -45,6 +49,7 @@ describe.skip("EmitsEvent", async () => { avatar, modifier, owner, + badger, }; }); diff --git a/test/ExecutionOptions.spec.ts b/test/ExecutionOptions.spec.ts index a8cdd6dbb..3cc9eee55 100644 --- a/test/ExecutionOptions.spec.ts +++ b/test/ExecutionOptions.spec.ts @@ -7,7 +7,8 @@ const OPTIONS_SEND = 1; const OPTIONS_DELEGATECALL = 2; const OPTIONS_BOTH = 3; -const ROLE_ID = 0; +const BADGE_ID = 0; +const ONE_TOKEN = 1; describe("ExecutionOptions", async () => { const setup = deployments.createFixture(async () => { @@ -16,6 +17,8 @@ describe("ExecutionOptions", async () => { const avatar = await Avatar.deploy(); const TestContract = await hre.ethers.getContractFactory("TestContract"); const testContract = await TestContract.deploy(); + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); const [owner, invoker] = waffle.provider.getWallets(); @@ -30,14 +33,11 @@ describe("ExecutionOptions", async () => { const modifier = await Modifier.deploy( owner.address, avatar.address, - avatar.address + avatar.address, + badger.address ); - await modifier.enableModule(invoker.address); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, ONE_TOKEN); // fund avatar await invoker.sendTransaction({ @@ -53,6 +53,7 @@ describe("ExecutionOptions", async () => { modifier, owner, invoker, + badger, }; }); @@ -68,12 +69,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); @@ -84,12 +91,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); @@ -103,12 +116,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_SEND); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_SEND); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -121,12 +140,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_SEND); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_SEND); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveFallback") .withArgs(value); @@ -142,12 +167,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_DELEGATECALL); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_DELEGATECALL); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); it("ExecutionOptions.DELEGATECALL - FAILS sending ETH to fallback", async () => { @@ -157,12 +188,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_DELEGATECALL); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_DELEGATECALL); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); it("ExecutionOptions.BOTH - OK sending ETH to payable function", async () => { @@ -175,12 +212,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_BOTH); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_BOTH); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -196,12 +239,18 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_BOTH); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_BOTH); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -223,12 +272,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -237,7 +286,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); @@ -248,12 +303,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, "0x00000000", OPTIONS_NONE @@ -262,7 +317,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); @@ -280,12 +341,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_SEND @@ -294,7 +355,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -306,12 +373,12 @@ describe("ExecutionOptions", async () => { const value = ethers.utils.parseEther("1.123"); await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, "0x00000000", OPTIONS_SEND @@ -320,7 +387,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveFallback") .withArgs(value); @@ -342,7 +415,7 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_SEND @@ -351,7 +424,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); @@ -369,12 +448,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_DELEGATECALL @@ -383,7 +462,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); it("ExecutionOptions.DELEGATECALL - FAILS sending ETH to fallback", async () => { @@ -393,12 +478,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, "0x00000000", OPTIONS_DELEGATECALL @@ -407,7 +492,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed()"); }); @@ -425,12 +516,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_BOTH @@ -439,7 +530,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -451,12 +548,12 @@ describe("ExecutionOptions", async () => { const value = ethers.utils.parseEther("1.123"); await modifier .connect(owner) - .scopeTarget(ROLE_ID, testContract.address); + .scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, "0x00000000", OPTIONS_BOTH @@ -465,7 +562,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, "0x", 0) + .execTransactionFromModule( + testContract.address, + value, + "0x", + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveFallback") .withArgs(value); @@ -487,7 +590,7 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_BOTH @@ -496,7 +599,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); }); @@ -510,12 +619,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_DELEGATECALL); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_DELEGATECALL); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 1) + .execTransactionFromModule(testContract.address, 0, data, 1, BADGE_ID) ).to.not.be.reverted; }); it("target allowed - cannot delegatecall", async () => { @@ -525,12 +634,12 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 1) + .execTransactionFromModule(testContract.address, 0, data, 1, BADGE_ID) ).to.be.revertedWith("DelegateCallNotAllowed()"); }); it("target partially allowed - can delegatecall", async () => { @@ -542,12 +651,12 @@ describe("ExecutionOptions", async () => { const { data } = await testContract.populateTransaction.emitTheSender(); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_BOTH @@ -556,7 +665,7 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 1) + .execTransactionFromModule(testContract.address, 0, data, 1, BADGE_ID) ).not.to.be.reverted; }); @@ -569,12 +678,12 @@ describe("ExecutionOptions", async () => { const { data } = await testContract.populateTransaction.emitTheSender(); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -583,7 +692,7 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, data, 1) + .execTransactionFromModule(testContract.address, 0, data, 1, BADGE_ID) ).to.be.revertedWith("DelegateCallNotAllowed()"); }); }); @@ -600,12 +709,12 @@ describe("ExecutionOptions", async () => { const { data } = await testContract.populateTransaction.receiveEthAndDoNothing(); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_SEND @@ -614,7 +723,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ) .to.be.emit(testContract, "ReceiveEthAndDoNothing") .withArgs(value); @@ -622,7 +737,7 @@ describe("ExecutionOptions", async () => { await modifier .connect(owner) .scopeFunctionExecutionOptions( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -631,7 +746,13 @@ describe("ExecutionOptions", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, value, data, 0) + .execTransactionFromModule( + testContract.address, + value, + data, + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed"); }); }); diff --git a/test/FactoryFriendly.spec.ts b/test/FactoryFriendly.spec.ts index a788eec63..b6d6e6d64 100644 --- a/test/FactoryFriendly.spec.ts +++ b/test/FactoryFriendly.spec.ts @@ -8,12 +8,16 @@ const FirstAddress = "0x0000000000000000000000000000000000000001"; const saltNonce = "0xfa"; describe("Module works with factory", () => { - const paramsTypes = ["address", "address", "address"]; + const paramsTypes = ["address", "address", "address", "address"]; const baseSetup = deployments.createFixture(async () => { await deployments.fixture(); const Factory = await hre.ethers.getContractFactory("ModuleProxyFactory"); const factory = await Factory.deploy(); + + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + const Permissions = await hre.ethers.getContractFactory("Permissions"); const permissions = await Permissions.deploy(); const Modifier = await hre.ethers.getContractFactory("Roles", { @@ -25,18 +29,20 @@ describe("Module works with factory", () => { const masterCopy = await Modifier.deploy( FirstAddress, FirstAddress, - FirstAddress + FirstAddress, + badger.address ); - return { factory, masterCopy, Modifier }; + return { factory, masterCopy, Modifier, badger }; }); it("should throw because master copy is already initialized", async () => { - const { masterCopy } = await baseSetup(); + const { masterCopy, badger } = await baseSetup(); const encodedParams = new AbiCoder().encode(paramsTypes, [ AddressOne, AddressOne, AddressOne, + badger.address, ]); await expect(masterCopy.setUp(encodedParams)).to.be.revertedWith( @@ -45,9 +51,14 @@ describe("Module works with factory", () => { }); it("should deploy new roles module proxy", async () => { - const { factory, masterCopy, Modifier } = await baseSetup(); + const { factory, masterCopy, Modifier, badger } = await baseSetup(); const [avatar, owner, target] = await ethers.getSigners(); - const paramsValues = [owner.address, avatar.address, target.address]; + const paramsValues = [ + owner.address, + avatar.address, + target.address, + badger.address, + ]; const encodedParams = [new AbiCoder().encode(paramsTypes, paramsValues)]; const initParams = masterCopy.interface.encodeFunctionData( "setUp", diff --git a/test/OnlyOwner.spec.ts b/test/OnlyOwner.spec.ts index 6818117d0..387c988d1 100644 --- a/test/OnlyOwner.spec.ts +++ b/test/OnlyOwner.spec.ts @@ -25,14 +25,16 @@ describe("OnlyOwner", async () => { }, }); + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + const modifier = await Modifier.deploy( owner.address, base.avatar.address, - base.avatar.address + base.avatar.address, + badger.address ); - await modifier.enableModule(invoker.address); - return { ...base, Modifier, @@ -40,6 +42,7 @@ describe("OnlyOwner", async () => { owner, invoker, janeDoe, + badger, }; }); @@ -56,24 +59,24 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(invoker) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE) + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(janeDoe) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE) + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE) + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE) ).to.not.be.reverted; }); @@ -81,36 +84,36 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( - modifier.connect(invoker).scopeTarget(ROLE_ID, testContract.address) + modifier.connect(invoker).scopeTarget(BADGE_ID, testContract.address) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( - modifier.connect(janeDoe).scopeTarget(ROLE_ID, testContract.address) + modifier.connect(janeDoe).scopeTarget(BADGE_ID, testContract.address) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( - modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address) + modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address) ).to.not.be.reverted; }); it("onlyOwner for revokeTarget, simple invoker fails", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( - modifier.connect(invoker).revokeTarget(ROLE_ID, testContract.address) + modifier.connect(invoker).revokeTarget(BADGE_ID, testContract.address) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( - modifier.connect(janeDoe).revokeTarget(ROLE_ID, testContract.address) + modifier.connect(janeDoe).revokeTarget(BADGE_ID, testContract.address) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( - modifier.connect(owner).revokeTarget(ROLE_ID, testContract.address) + modifier.connect(owner).revokeTarget(BADGE_ID, testContract.address) ).to.not.be.reverted; }); @@ -118,7 +121,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -127,7 +130,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -138,7 +141,7 @@ describe("OnlyOwner", async () => { modifier .connect(janeDoe) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -149,7 +152,7 @@ describe("OnlyOwner", async () => { modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -160,7 +163,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -168,26 +171,26 @@ describe("OnlyOwner", async () => { await expect( modifier .connect(invoker) - .scopeRevokeFunction(ROLE_ID, testContract.address, SELECTOR) + .scopeRevokeFunction(BADGE_ID, testContract.address, SELECTOR) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(janeDoe) - .scopeRevokeFunction(ROLE_ID, testContract.address, SELECTOR) + .scopeRevokeFunction(BADGE_ID, testContract.address, SELECTOR) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(owner) - .scopeRevokeFunction(ROLE_ID, testContract.address, SELECTOR) + .scopeRevokeFunction(BADGE_ID, testContract.address, SELECTOR) ).to.not.be.reverted; }); it("onlyOwner for scopeFunction, simple invoker fails", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -196,7 +199,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [], @@ -211,7 +214,7 @@ describe("OnlyOwner", async () => { modifier .connect(janeDoe) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [], @@ -226,7 +229,7 @@ describe("OnlyOwner", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [], @@ -241,7 +244,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -250,7 +253,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeFunctionExecutionOptions( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -261,7 +264,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeFunctionExecutionOptions( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -272,7 +275,7 @@ describe("OnlyOwner", async () => { modifier .connect(owner) .scopeFunctionExecutionOptions( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -283,7 +286,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -292,7 +295,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -306,7 +309,7 @@ describe("OnlyOwner", async () => { modifier .connect(janeDoe) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -320,7 +323,7 @@ describe("OnlyOwner", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -334,7 +337,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -343,7 +346,7 @@ describe("OnlyOwner", async () => { modifier .connect(invoker) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -356,7 +359,7 @@ describe("OnlyOwner", async () => { modifier .connect(janeDoe) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -369,7 +372,7 @@ describe("OnlyOwner", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -382,7 +385,7 @@ describe("OnlyOwner", async () => { const { modifier, testContract, owner, invoker, janeDoe } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -390,19 +393,19 @@ describe("OnlyOwner", async () => { await expect( modifier .connect(invoker) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 0) + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 0) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(janeDoe) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 0) + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 0) ).to.be.revertedWith("Ownable: caller is not the owner"); await expect( modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 0) + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 0) ).to.not.be.reverted; }); }); diff --git a/test/PluckParamAndDecoding.spec.ts b/test/PluckParamAndDecoding.spec.ts index e961c7956..58b5e007c 100644 --- a/test/PluckParamAndDecoding.spec.ts +++ b/test/PluckParamAndDecoding.spec.ts @@ -17,7 +17,7 @@ const TYPE_DYNAMIC = 1; const TYPE_DYNAMIC32 = 2; describe("PluckParam - Decoding", async () => { - const ROLE_ID = 0; + const BADGE_ID = 0; const setup = deployments.createFixture(async () => { await deployments.fixture(); const Avatar = await hre.ethers.getContractFactory("TestAvatar"); @@ -38,19 +38,19 @@ describe("PluckParam - Decoding", async () => { }, }); + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + const modifier = await Modifier.deploy( owner.address, avatar.address, - avatar.address + avatar.address, + badger.address ); - await modifier.enableModule(invoker.address); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testPluckParam.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testPluckParam.address); return { testPluckParam, @@ -58,6 +58,7 @@ describe("PluckParam - Decoding", async () => { modifier, owner, invoker, + badger, }; }); @@ -71,7 +72,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true], @@ -99,13 +100,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "StaticDynamic"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -119,7 +132,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -150,13 +163,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "StaticDynamicDynamic32"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); it("static, dynamic32, dynamic - (uint32,bytes4[],string)", async () => { @@ -169,7 +194,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -200,13 +225,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "StaticDynamic32Dynamic"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -220,7 +257,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -251,13 +288,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "DynamicStaticDynamic32"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); it("dynamic, dynamic32, static - (string,uint32[],uint256)", async () => { @@ -270,7 +319,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -301,13 +350,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "DynamicDynamic32Static"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); it("dynamic32, static, dynamic - (address[],bytes2,bytes)", async () => { @@ -320,7 +381,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -351,13 +412,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "Dynamic32StaticDynamic"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); it("dynamic32, dynamic, static - (bytes2[],string,uint32)", async () => { @@ -370,7 +443,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -401,13 +474,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "Dynamic32DynamicStatic"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -421,7 +506,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true, true, true], @@ -450,13 +535,25 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.emit(testPluckParam, "UnsupportedFixedSizeAndDynamic"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -470,7 +567,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, [true], @@ -483,7 +580,13 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, SELECTOR, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + SELECTOR, + 0, + BADGE_ID + ) ).to.be.revertedWith("CalldataOutOfBounds()"); await expect( @@ -493,7 +596,8 @@ describe("PluckParam - Decoding", async () => { testPluckParam.address, 0, `${SELECTOR}aabbccdd`, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("CalldataOutOfBounds()"); }); @@ -508,7 +612,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 0, @@ -525,13 +629,13 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, data, 0) + .execTransactionFromModule(testPluckParam.address, 0, data, 0, BADGE_ID) ).to.emit(testPluckParam, "Static"); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 1, @@ -544,7 +648,7 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, data, 0) + .execTransactionFromModule(testPluckParam.address, 0, data, 0, BADGE_ID) ).to.be.revertedWith("CalldataOutOfBounds()"); }); @@ -562,7 +666,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 1, @@ -586,21 +690,39 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataShort, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataShort, + 0, + BADGE_ID + ) ).to.be.revertedWith("CalldataOutOfBounds()"); // just the selector await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, SELECTOR, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + SELECTOR, + 0, + BADGE_ID + ) ).to.be.revertedWith("CalldataOutOfBounds()"); // ok await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.not.be.reverted; }); @@ -614,7 +736,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 1, @@ -638,14 +760,26 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataBad, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataBad, + 0, + BADGE_ID + ) ).to.be.revertedWith("CalldataOutOfBounds()"); // ok await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.not.be.reverted; }); @@ -659,7 +793,7 @@ describe("PluckParam - Decoding", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 1, @@ -678,13 +812,19 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.not.be.reverted; await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testPluckParam.address, SELECTOR, 15, @@ -696,7 +836,13 @@ describe("PluckParam - Decoding", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testPluckParam.address, 0, dataGood, 0) + .execTransactionFromModule( + testPluckParam.address, + 0, + dataGood, + 0, + BADGE_ID + ) ).to.be.revertedWith("CalldataOutOfBounds()"); }); }); diff --git a/test/Roles.spec.ts b/test/Roles.spec.ts index 7129c2245..52b4eaefe 100644 --- a/test/Roles.spec.ts +++ b/test/Roles.spec.ts @@ -1,8 +1,8 @@ import { AddressOne } from "@gnosis.pm/safe-contracts"; import { expect } from "chai"; import hre, { deployments, waffle, ethers } from "hardhat"; - import "@nomiclabs/hardhat-ethers"; + import { buildContractCall, buildMultiSendSafeTx } from "./utils"; const ZeroAddress = "0x0000000000000000000000000000000000000000"; @@ -15,7 +15,10 @@ describe("RolesModifier", async () => { const avatar = await Avatar.deploy(); const TestContract = await hre.ethers.getContractFactory("TestContract"); const testContract = await TestContract.deploy(); - return { Avatar, avatar, testContract }; + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + + return { Avatar, avatar, testContract, badger }; }); const setupTestWithTestAvatar = deployments.createFixture(async () => { @@ -31,7 +34,8 @@ describe("RolesModifier", async () => { const modifier = await Modifier.deploy( base.avatar.address, base.avatar.address, - base.avatar.address + base.avatar.address, + base.badger.address ); return { ...base, Modifier, modifier }; }); @@ -52,11 +56,10 @@ describe("RolesModifier", async () => { const modifier = await Modifier.deploy( owner.address, base.avatar.address, - base.avatar.address + base.avatar.address, + base.badger.address ); - await modifier.enableModule(invoker.address); - return { ...base, Modifier, @@ -161,6 +164,7 @@ describe("RolesModifier", async () => { }); const modifier = await Modifier.deploy( + user1.address, user1.address, user1.address, user1.address @@ -172,128 +176,17 @@ describe("RolesModifier", async () => { }); }); - describe("disableModule()", async () => { - it("reverts if not authorized", async () => { - const { modifier } = await txSetup(); - await expect( - modifier.disableModule(FirstAddress, user1.address) - ).to.be.revertedWith("Ownable: caller is not the owner"); - }); - - it("reverts if module is null or sentinel", async () => { - const { avatar, modifier } = await txSetup(); - const disable = await modifier.populateTransaction.disableModule( - FirstAddress, - FirstAddress - ); - await expect( - avatar.exec(modifier.address, 0, disable.data) - ).to.be.revertedWith("Invalid module"); - }); - - it("reverts if module is not added ", async () => { - const { avatar, modifier } = await txSetup(); - const disable = await modifier.populateTransaction.disableModule( - ZeroAddress, - user1.address - ); - await expect( - avatar.exec(modifier.address, 0, disable.data) - ).to.be.revertedWith("Module already disabled"); - }); - - it("disables a module()", async () => { - const { avatar, modifier } = await txSetup(); - const enable = await modifier.populateTransaction.enableModule( - user1.address - ); - const disable = await modifier.populateTransaction.disableModule( - FirstAddress, - user1.address - ); - - await avatar.exec(modifier.address, 0, enable.data); - await expect(await modifier.isModuleEnabled(user1.address)).to.be.equals( - true - ); - await avatar.exec(modifier.address, 0, disable.data); - await expect(await modifier.isModuleEnabled(user1.address)).to.be.equals( - false - ); - }); - }); - - describe("enableModule()", async () => { - it("reverts if not authorized", async () => { - const { modifier } = await txSetup(); - await expect(modifier.enableModule(user1.address)).to.be.revertedWith( - "Ownable: caller is not the owner" - ); - }); - - it("reverts if module is already enabled", async () => { - const { avatar, modifier } = await txSetup(); - const enable = await modifier.populateTransaction.enableModule( - user1.address - ); - - await avatar.exec(modifier.address, 0, enable.data); - await expect( - avatar.exec(modifier.address, 0, enable.data) - ).to.be.revertedWith("Module already enabled"); - }); - - it("reverts if module is invalid ", async () => { - const { avatar, modifier } = await txSetup(); - const enable = await modifier.populateTransaction.enableModule( - FirstAddress - ); - - await expect( - avatar.exec(modifier.address, 0, enable.data) - ).to.be.revertedWith("Invalid module"); - }); - - it("enables a module", async () => { - const { avatar, modifier } = await txSetup(); - const enable = await modifier.populateTransaction.enableModule( - user1.address - ); - - await avatar.exec(modifier.address, 0, enable.data); - await expect(await modifier.isModuleEnabled(user1.address)).to.be.equals( - true - ); - await expect( - await modifier.getModulesPaginated(FirstAddress, 10) - ).to.be.deep.equal([[user1.address], FirstAddress]); - }); - }); - - describe("assignRoles()", () => { - it("should throw on length mismatch", async () => { - const { modifier, owner } = await setupRolesWithOwnerAndInvoker(); - await expect( - modifier.connect(owner).assignRoles(user1.address, [1, 2], [true]) - ).to.be.revertedWith("ArraysDifferentLength()"); - }); - it("reverts if not authorized", async () => { - const { modifier } = await txSetup(); - await expect( - modifier.assignRoles(user1.address, [1], [true]) - ).to.be.revertedWith("Ownable: caller is not the owner"); - }); - + describe("badges as access control criteria", () => { it("assigns roles to a module", async () => { - const ROLE_ID = 0; + const BADGE_ID = 0; - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); // blank allow all calls to testContract from role 0 await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // expect it to fail, before assigning role await expect( @@ -303,13 +196,12 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("NoMembership()"); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // expect it to succeed, after assigning role await expect( @@ -319,26 +211,25 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "DoNothing"); }); it("revokes roles to a module", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; // blank allow all calls to testContract from role 0 await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); //authorize - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // expect it to succeed, after assigning role await expect( @@ -348,14 +239,13 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "DoNothing"); //revoke - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [false]); + await badger.burn(invoker.address, BADGE_ID, 1); // expect it to fail, after revoking await expect( @@ -365,73 +255,43 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("NoMembership()"); }); - - it("it enables the module if necessary", async () => { - const { avatar, modifier } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); - - await expect(await modifier.isModuleEnabled(user1.address)).to.equal( - true - ); - - // it doesn't revert when assigning additional roles - const assignSecond = await modifier.populateTransaction.assignRoles( - user1.address, - [1, 2], - [true, true] - ); - await expect(avatar.exec(modifier.address, 0, assignSecond.data)).to.not - .be.reverted; - }); - - it("emits the AssignRoles event", async () => { - const { avatar, modifier } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - - await expect(avatar.exec(modifier.address, 0, assign.data)) - .to.emit(modifier, "AssignRoles") - .withArgs(user1.address, [1], [true]); - }); }); describe("execTransactionFromModule()", () => { it("reverts if data is set and is not at least 4 bytes", async () => { - const { modifier, testContract, invoker } = + const { modifier, testContract, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; - await modifier.assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, "0xab", 0) + .execTransactionFromModule( + testContract.address, + 0, + "0xab", + 0, + BADGE_ID + ) ).to.be.revertedWith("FunctionSignatureTooShort()"); }); it("reverts if called from module not assigned any role", async () => { - const { modifier, testContract, owner } = + const { modifier, testContract, owner, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); - + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); const mint = await testContract.populateTransaction.mint( user1.address, 99 @@ -442,33 +302,33 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) - ).to.be.revertedWith("Module not authorized"); + ).to.be.revertedWith("NoMembership()"); }); it("reverts if the call is not an allowed target", async () => { - const { avatar, modifier, testContract } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( + const { avatar, modifier, testContract, badger } = await txSetup(); + const BADGE_ID = 1; + + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, - [1], - [true] + BADGE_ID, + 1 ); - await avatar.exec(modifier.address, 0, assign.data); + + await avatar.exec(badger.address, 0, assign.data); const allowTargetAddress = await modifier.populateTransaction.allowTarget( - 1, + BADGE_ID, testContract.address, OPTIONS_NONE ); await avatar.exec(modifier.address, 0, allowTargetAddress.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - await avatar.exec(modifier.address, 0, defaultRole.data); - const mint = await testContract.populateTransaction.mint( user1.address, 99 @@ -476,33 +336,36 @@ describe("RolesModifier", async () => { const someOtherAddress = "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"; await expect( - modifier.execTransactionFromModule(someOtherAddress, 0, mint.data, 0) + modifier.execTransactionFromModule( + someOtherAddress, + 0, + mint.data, + 0, + BADGE_ID + ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); it("executes a call to an allowed target", async () => { - const { avatar, modifier, testContract } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( + const { avatar, modifier, testContract, badger } = await txSetup(); + const BADGE_ID = 1; + + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, - [1], - [true] + BADGE_ID, + 1 ); - await avatar.exec(modifier.address, 0, assign.data); + await avatar.exec(badger.address, 0, assign.data); const allowTargetAddress = await modifier.populateTransaction.allowTarget( - 1, + BADGE_ID, testContract.address, OPTIONS_NONE ); await avatar.exec(modifier.address, 0, allowTargetAddress.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - - await avatar.exec(modifier.address, 0, defaultRole.data); - const mint = await testContract.populateTransaction.mint( user1.address, 99 @@ -513,29 +376,35 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "Mint"); }); it("reverts if value parameter is not allowed", async () => { - const { avatar, modifier, testContract, encodedParam_1, encodedParam_2 } = - await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const { + avatar, + modifier, + testContract, + encodedParam_1, + encodedParam_2, + badger, + } = await txSetup(); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( - 1, + BADGE_ID, testContract.address ); await avatar.exec(modifier.address, 0, functionScoped.data); @@ -562,28 +431,32 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); }); it("executes a call with allowed value parameter", async () => { const user1 = (await hre.ethers.getSigners())[0]; + const BADGE_ID = 1; + const { + avatar, + modifier, + testContract, + encodedParam_1, + encodedParam_2, + badger, + } = await txSetup(); - const { avatar, modifier, testContract, encodedParam_1, encodedParam_2 } = - await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + await badger.transferOwnership(avatar.address); - const defaultRole = await modifier.populateTransaction.setDefaultRole( + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -613,7 +486,8 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "Mint"); }); @@ -630,20 +504,18 @@ describe("RolesModifier", async () => { encodedParam_7, encodedParam_8, encodedParam_9, + badger, } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - - await avatar.exec(modifier.address, 0, assign.data); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -694,7 +566,8 @@ describe("RolesModifier", async () => { testContract.address, 0, dynamic.data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -711,20 +584,19 @@ describe("RolesModifier", async () => { encodedParam_7, encodedParam_8, encodedParam_9, + badger, } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); + const BADGE_ID = 1; - await avatar.exec(modifier.address, 0, assign.data); + await badger.transferOwnership(avatar.address); - const defaultRole = await modifier.populateTransaction.setDefaultRole( + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -775,7 +647,8 @@ describe("RolesModifier", async () => { testContract.address, 0, dynamic.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "TestDynamic"); }); @@ -797,28 +670,27 @@ describe("RolesModifier", async () => { tx_1, tx_2, tx_3, + badger, } = await txSetup(); + const BADGE_ID = 1; + + await badger.transferOwnership(avatar.address); + const MultiSend = await hre.ethers.getContractFactory("MultiSend"); const multisend = await MultiSend.deploy(); - const assign = await modifier.populateTransaction.assignRoles( + const assign = await badger.populateTransaction.mint( user1.address, - [1], - [true] + BADGE_ID, + 1 ); - await avatar.exec(modifier.address, 0, assign.data); + await avatar.exec(badger.address, 0, assign.data); const multiSendTarget = await modifier.populateTransaction.setMultisend( multisend.address ); await avatar.exec(modifier.address, 0, multiSendTarget.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - await avatar.exec(modifier.address, 0, defaultRole.data); - const scopeTarget = await modifier.populateTransaction.scopeTarget( 1, testContract.address @@ -883,7 +755,8 @@ describe("RolesModifier", async () => { multisend.address, 0, multiTx.data, - 1 + 1, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); }); @@ -896,28 +769,27 @@ describe("RolesModifier", async () => { encodedParam_1, encodedParam_2, tx_1, + badger, } = await txSetup(); - const MultiSend = await hre.ethers.getContractFactory("MultiSend"); - const multisend = await MultiSend.deploy(); + const BADGE_ID = 1; - const assign = await modifier.populateTransaction.assignRoles( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, - [1], - [true] + BADGE_ID, + 1 ); - await avatar.exec(modifier.address, 0, assign.data); + await avatar.exec(badger.address, 0, assign.data); + + const MultiSend = await hre.ethers.getContractFactory("MultiSend"); + const multisend = await MultiSend.deploy(); const multiSendTarget = await modifier.populateTransaction.setMultisend( multisend.address ); await avatar.exec(modifier.address, 0, multiSendTarget.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - await avatar.exec(modifier.address, 0, defaultRole.data); - const functionScoped = await modifier.populateTransaction.scopeTarget( 1, testContract.address @@ -946,7 +818,8 @@ describe("RolesModifier", async () => { multisend.address, 0, multiTx.data, - 1 + 1, + BADGE_ID ) ).to.be.revertedWith("UnacceptableMultiSendOffset()"); }); @@ -968,28 +841,27 @@ describe("RolesModifier", async () => { tx_1, tx_2, tx_3, + badger, } = await txSetup(); - const MultiSend = await hre.ethers.getContractFactory("MultiSend"); - const multisend = await MultiSend.deploy(); + const BADGE_ID = 1; - const assign = await modifier.populateTransaction.assignRoles( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, - [1], - [true] + BADGE_ID, + 1 ); - await avatar.exec(modifier.address, 0, assign.data); + await avatar.exec(badger.address, 0, assign.data); + + const MultiSend = await hre.ethers.getContractFactory("MultiSend"); + const multisend = await MultiSend.deploy(); const multiSendTarget = await modifier.populateTransaction.setMultisend( multisend.address ); await avatar.exec(modifier.address, 0, multiSendTarget.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - await avatar.exec(modifier.address, 0, defaultRole.data); - const scopeTarget = await modifier.populateTransaction.scopeTarget( 1, testContract.address @@ -1047,26 +919,25 @@ describe("RolesModifier", async () => { multisend.address, 0, multiTx.data, - 1 + 1, + BADGE_ID ) ).to.emit(testContract, "TestDynamic"); }); it("reverts if value parameter is less than allowed", async () => { - const { avatar, modifier, testContract, encodedParam_1 } = + const { avatar, modifier, testContract, encodedParam_1, badger } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + await avatar.exec(badger.address, 0, assign.data); const scopeTarget = await modifier.populateTransaction.scopeTarget( 1, @@ -1101,26 +972,25 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterLessThanAllowed"); }); it("executes if value parameter is greater than allowed", async () => { - const { avatar, modifier, testContract, encodedParam_1 } = + const { avatar, modifier, testContract, encodedParam_1, badger } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -1155,26 +1025,25 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "Mint"); }); it("reverts if value parameter is greater than allowed", async () => { - const { avatar, modifier, testContract, encodedParam_1 } = + const { avatar, modifier, testContract, encodedParam_1, badger } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -1209,26 +1078,25 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterGreaterThanAllowed"); }); it("executes if value parameter is less than allowed", async () => { - const { avatar, modifier, testContract, encodedParam_1 } = + const { avatar, modifier, testContract, encodedParam_1, badger } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const BADGE_ID = 1; - const defaultRole = await modifier.populateTransaction.setDefaultRole( + await badger.transferOwnership(avatar.address); + + const assign = await badger.populateTransaction.mint( user1.address, + BADGE_ID, 1 ); - await avatar.exec(modifier.address, 0, defaultRole.data); + await avatar.exec(badger.address, 0, assign.data); const functionScoped = await modifier.populateTransaction.scopeTarget( 1, @@ -1263,7 +1131,8 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "Mint"); }); @@ -1272,9 +1141,10 @@ describe("RolesModifier", async () => { describe("execTransactionFromModuleReturnData()", () => { it("reverts if called from module not assigned any role", async () => { const { avatar, modifier, testContract } = await txSetup(); - const ROLE_ID = 0; + const BADGE_ID = 1; + const allowTargetAddress = await modifier.populateTransaction.allowTarget( - 1, + BADGE_ID, testContract.address, OPTIONS_NONE ); @@ -1290,19 +1160,21 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - ROLE_ID + 1, + BADGE_ID ) - ).to.be.revertedWith("Module not authorized"); + ).to.be.revertedWith("NoMembership()"); }); it("reverts if the call is not an allowed target", async () => { - const { avatar, modifier, testContract } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const { avatar, modifier, testContract, badger } = await txSetup(); + const BADGE_ID = 1; + + await badger.transferOwnership(avatar.address); + const assign = await badger + .connect(avatar.address) + .populateTransaction.mint(user1.address, 1, 1); + await avatar.exec(badger.address, 0, assign.data); const allowTargetAddress = await modifier.populateTransaction.allowTarget( 1, @@ -1311,12 +1183,6 @@ describe("RolesModifier", async () => { ); await avatar.exec(modifier.address, 0, allowTargetAddress.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - await avatar.exec(modifier.address, 0, defaultRole.data); - const mint = await testContract.populateTransaction.mint( user1.address, 99 @@ -1328,34 +1194,29 @@ describe("RolesModifier", async () => { someOtherAddress, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); it("executes a call to an allowed target", async () => { - const { avatar, modifier, testContract } = await txSetup(); - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [1], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); + const { avatar, modifier, testContract, badger } = await txSetup(); + const BADGE_ID = 1; + + await badger.transferOwnership(avatar.address); + const assign = await badger + .connect(avatar.address) + .populateTransaction.mint(user1.address, 1, 1); + await avatar.exec(badger.address, 0, assign.data); const allowTargetAddress = await modifier.populateTransaction.allowTarget( - 1, + BADGE_ID, testContract.address, OPTIONS_NONE ); await avatar.exec(modifier.address, 0, allowTargetAddress.data); - const defaultRole = await modifier.populateTransaction.setDefaultRole( - user1.address, - 1 - ); - - await avatar.exec(modifier.address, 0, defaultRole.data); - const mint = await testContract.populateTransaction.mint( user1.address, 99 @@ -1366,280 +1227,27 @@ describe("RolesModifier", async () => { testContract.address, 0, mint.data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "Mint"); }); }); - describe("execTransactionWithRole()", () => { - it("reverts if inner tx reverted and shouldRevert true", async () => { - const { modifier, testContract, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const ROLE_ID = 0; - const SHOULD_REVERT = true; - const fnThatReverts = - await testContract.populateTransaction.fnThatReverts(); + describe("setMultisend()", () => { + it("reverts if not authorized", async () => { + const { modifier } = await txSetup(); + await expect(modifier.setMultisend(AddressOne)).to.be.revertedWith( + "Ownable: caller is not the owner" + ); + }); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - - await modifier - .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); - - await expect( - modifier - .connect(invoker) - .execTransactionWithRole( - testContract.address, - 0, - fnThatReverts.data, - 0, - ROLE_ID, - SHOULD_REVERT - ) - ).to.be.revertedWith("ModuleTransactionFailed()"); - }); - it("does not revert if inner tx reverted and shouldRevert false", async () => { - const { modifier, testContract, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const ROLE_ID = 0; - const SHOULD_REVERT = true; - const fnThatReverts = - await testContract.populateTransaction.fnThatReverts(); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - - await modifier - .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); - - await expect( - modifier - .connect(invoker) - .execTransactionWithRole( - testContract.address, - 0, - fnThatReverts.data, - 0, - ROLE_ID, - !SHOULD_REVERT - ) - ).to.not.be.reverted; - }); - }); - - describe("execTransactionWithRoleReturnData()", () => { - it("reverts if called from module not assigned any role", async () => { - const { modifier, testContract, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const ROLE_ID = 1; - const SHOULD_REVERT = true; - - const mint = await testContract.populateTransaction.mint( - user1.address, - 99 - ); - - await expect( - modifier - .connect(invoker) - .execTransactionWithRoleReturnData( - testContract.address, - 0, - mint.data, - 0, - ROLE_ID, - !SHOULD_REVERT - ) - ).to.be.revertedWith("NoMembership()"); - }); - - it("reverts if inner tx reverted and shouldRevert true", async () => { - const { modifier, testContract, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const SHOULD_REVERT = true; - const ROLE_ID = 0; - const fnThatReverts = - await testContract.populateTransaction.fnThatReverts(); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - - await modifier - .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); - - await expect( - modifier - .connect(invoker) - .execTransactionWithRoleReturnData( - testContract.address, - 0, - fnThatReverts.data, - 0, - ROLE_ID, - SHOULD_REVERT - ) - ).to.be.revertedWith("ModuleTransactionFailed()"); - }); - - it("does not revert if inner tx reverted and shouldRevert false", async () => { - const { modifier, testContract, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const SHOULD_REVERT = true; - const ROLE_ID = 0; - const fnThatReverts = - await testContract.populateTransaction.fnThatReverts(); - - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - - await modifier - .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); - - await expect( - modifier - .connect(invoker) - .execTransactionWithRoleReturnData( - testContract.address, - 0, - fnThatReverts.data, - 0, - ROLE_ID, - !SHOULD_REVERT - ) - ).to.be.not.be.reverted; - }); - - it("executes a call with multisend tx", async () => { - const { - avatar, - modifier, - testContract, - encodedParam_1, - encodedParam_2, - encodedParam_3, - encodedParam_4, - encodedParam_5, - encodedParam_6, - encodedParam_7, - encodedParam_8, - encodedParam_9, - tx_1, - tx_2, - tx_3, - } = await txSetup(); - - const SHOULD_REVERT = true; - - const MultiSend = await hre.ethers.getContractFactory("MultiSend"); - const multisend = await MultiSend.deploy(); - - const ROLE_ID = 1; - - const assign = await modifier.populateTransaction.assignRoles( - user1.address, - [ROLE_ID], - [true] - ); - await avatar.exec(modifier.address, 0, assign.data); - - const multiSendTarget = await modifier.populateTransaction.setMultisend( - multisend.address - ); - await avatar.exec(modifier.address, 0, multiSendTarget.data); - - const scopeTarget = await modifier.populateTransaction.scopeTarget( - 1, - testContract.address - ); - await avatar.exec(modifier.address, 0, scopeTarget.data); - - const paramScoped = await modifier.populateTransaction.scopeFunction( - ROLE_ID, - testContract.address, - "0x40c10f19", - [true, true], - [TYPE_STATIC, TYPE_STATIC], - [0, 0], - [encodedParam_1, encodedParam_2], - OPTIONS_NONE - ); - await avatar.exec(modifier.address, 0, paramScoped.data); - - const paramScoped_2 = await modifier.populateTransaction.scopeFunction( - ROLE_ID, - testContract.address, - "0x273454bf", - [true, true, true, true, true, true, true], - [ - TYPE_DYNAMIC, - TYPE_STATIC, - TYPE_DYNAMIC, - TYPE_STATIC, - TYPE_STATIC, - TYPE_DYNAMIC, - TYPE_DYNAMIC, - ], - [0, 0, 0, 0, 0, 0, 0], - [ - encodedParam_3, - encodedParam_4, - encodedParam_5, - encodedParam_6, - encodedParam_7, - encodedParam_8, - encodedParam_9, - ], - OPTIONS_NONE - ); - await avatar.exec(modifier.address, 0, paramScoped_2.data); - - const multiTx = buildMultiSendSafeTx( - multisend, - [tx_1, tx_2, tx_3, tx_1, tx_2, tx_3], - 0 - ); - - await expect( - modifier.execTransactionWithRoleReturnData( - multisend.address, - 0, - multiTx.data, - 1, - ROLE_ID, - !SHOULD_REVERT - ) - ).to.emit(testContract, "TestDynamic"); - }); - }); - describe("setMultisend()", () => { - it("reverts if not authorized", async () => { - const { modifier } = await txSetup(); - await expect(modifier.setMultisend(AddressOne)).to.be.revertedWith( - "Ownable: caller is not the owner" - ); - }); - - it("sets multisend address to true", async () => { - const { avatar, modifier } = await txSetup(); - const tx = await modifier.populateTransaction.setMultisend(AddressOne); - await avatar.exec(modifier.address, 0, tx.data); - expect(await modifier.multisend()).to.be.equals(AddressOne); - }); + it("sets multisend address to true", async () => { + const { avatar, modifier } = await txSetup(); + const tx = await modifier.populateTransaction.setMultisend(AddressOne); + await avatar.exec(modifier.address, 0, tx.data); + expect(await modifier.multisend()).to.be.equals(AddressOne); + }); it("emits event with correct params", async () => { const { avatar, modifier } = await txSetup(); @@ -1659,11 +1267,10 @@ describe("RolesModifier", async () => { }); it("sets allowed address to true", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const SHOULD_REVERT = true; - const ROLE_ID = 1; + const BADGE_ID = 1; const doNothingArgs = [ testContract.address, @@ -1672,79 +1279,76 @@ describe("RolesModifier", async () => { 0, ]; - // assign a role to invoker - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - // expect to fail due to no permissions await expect( - modifier.connect(invoker).execTransactionFromModule(...doNothingArgs) + modifier + .connect(invoker) + .execTransactionFromModule(...doNothingArgs, BADGE_ID) ).to.be.revertedWith("NoMembership()"); // allow testContract address for role await expect( modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE) - ).to.not.be.reverted; + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE) + ).not.to.be.reverted; // expect to fail with default role await expect( - modifier.connect(invoker).execTransactionFromModule(...doNothingArgs) + modifier + .connect(invoker) + .execTransactionFromModule(...doNothingArgs, BADGE_ID) ).to.be.revertedWith("NoMembership()"); + // assign a role to invoker + await badger.mint(invoker.address, BADGE_ID, 1); + // should work with the configured role await expect( modifier .connect(invoker) - .execTransactionWithRole( - ...[...doNothingArgs, ROLE_ID, !SHOULD_REVERT] - ) + .execTransactionFromModule(...doNothingArgs, BADGE_ID) ).to.emit(testContract, "DoNothing"); }); it("sets allowed address to false", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); const SHOULD_REVERT = true; - const ROLE_ID = 1; + const BADGE_ID = 1; const execWithRoleArgs = [ testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), 0, - ROLE_ID, - !SHOULD_REVERT, + BADGE_ID, ]; // assign a role to invoker - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); // allow testContract address for role await expect( modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE) + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE) ); // this call should work await expect( - modifier.connect(invoker).execTransactionWithRole(...execWithRoleArgs) + modifier.connect(invoker).execTransactionFromModule(...execWithRoleArgs) ).to.emit(testContract, "DoNothing"); // Revoke access await expect( - modifier.connect(owner).revokeTarget(ROLE_ID, testContract.address) + modifier.connect(owner).revokeTarget(BADGE_ID, testContract.address) ).to.not.be.reverted; // fails after revoke await expect( - modifier.connect(invoker).execTransactionWithRole(...execWithRoleArgs) + modifier.connect(invoker).execTransactionFromModule(...execWithRoleArgs) ).to.be.revertedWith("TargetAddressNotAllowed()"); }); }); @@ -1758,13 +1362,11 @@ describe("RolesModifier", async () => { }); it("sets allowed address to true", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + const BADGE_ID = 1; + await badger.mint(invoker.address, BADGE_ID, 1); const execArgs = [ testContract.address, @@ -1776,17 +1378,19 @@ describe("RolesModifier", async () => { // allow calls (but not delegate) await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // still getting the delegateCallNotAllowed error await expect( - modifier.connect(invoker).execTransactionFromModule(...execArgs) + modifier + .connect(invoker) + .execTransactionFromModule(...execArgs, BADGE_ID) ).to.be.revertedWith("DelegateCallNotAllowed()"); // allow delegate calls to address await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_DELEGATECALL); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_DELEGATECALL); // ok await expect( @@ -1796,19 +1400,18 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 1 + 1, + BADGE_ID ) ).to.not.be.reverted; }); it("sets allowed address to false", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + const BADGE_ID = 1; + await badger.mint(invoker.address, BADGE_ID, 1); const execArgs = [ testContract.address, @@ -1819,7 +1422,7 @@ describe("RolesModifier", async () => { await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_DELEGATECALL); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_DELEGATECALL); // ok await expect( @@ -1829,18 +1432,21 @@ describe("RolesModifier", async () => { testContract.address, 0, testContract.interface.encodeFunctionData("doNothing()"), - 1 + 1, + BADGE_ID ) ).to.not.be.reverted; // revoke delegate calls to address await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // still getting the delegateCallNotAllowed error await expect( - modifier.connect(invoker).execTransactionFromModule(...execArgs) + modifier + .connect(invoker) + .execTransactionFromModule(...execArgs, BADGE_ID) ).to.be.revertedWith("DelegateCallNotAllowed()"); }); }); @@ -1863,10 +1469,10 @@ describe("RolesModifier", async () => { }); it("sets parameters scoped to true", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; const COMP_TYPE_EQ = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") @@ -1881,25 +1487,25 @@ describe("RolesModifier", async () => { 0, ]; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // works before making function parameter scoped await expect( - modifier.connect(invoker).execTransactionFromModule(...EXEC_ARGS(1)) + modifier + .connect(invoker) + .execTransactionFromModule(...EXEC_ARGS(1), BADGE_ID) ).to.not.be.reverted; - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true], @@ -1911,12 +1517,16 @@ describe("RolesModifier", async () => { // ngmi await expect( - modifier.connect(invoker).execTransactionFromModule(...EXEC_ARGS(1)) + modifier + .connect(invoker) + .execTransactionFromModule(...EXEC_ARGS(1), BADGE_ID) ).to.be.revertedWith("ParameterNotAllowed"); // gmi await expect( - modifier.connect(invoker).execTransactionFromModule(...EXEC_ARGS(2)) + modifier + .connect(invoker) + .execTransactionFromModule(...EXEC_ARGS(2), BADGE_ID) ).to.not.be.reverted; }); }); @@ -1924,34 +1534,40 @@ describe("RolesModifier", async () => { describe("allowTarget - canSend", () => { it("reverts if not authorized", async () => { const { modifier } = await txSetup(); + const BADGE_ID = 1; + await expect( - modifier.allowTarget(1, AddressOne, OPTIONS_SEND) + modifier.allowTarget(BADGE_ID, AddressOne, OPTIONS_SEND) ).to.be.revertedWith("Ownable: caller is not the owner"); }); it("sets send allowed to true", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); await expect( modifier .connect(invoker) - .execTransactionFromModuleReturnData(testContract.address, 1, "0x", 0) + .execTransactionFromModuleReturnData( + testContract.address, + 1, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed"); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_SEND); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_SEND); await expect( modifier @@ -1960,23 +1576,22 @@ describe("RolesModifier", async () => { testContract.address, 10000, "0x", - 0 + 0, + BADGE_ID ) ).to.not.be.reverted; }); it("sets send allowed to false", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + const BADGE_ID = 1; + await badger.mint(invoker.address, BADGE_ID, 1); await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_SEND); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_SEND); // should work with sendAllowed true await expect( @@ -1986,19 +1601,26 @@ describe("RolesModifier", async () => { testContract.address, 10000, "0x", - 0 + 0, + BADGE_ID ) ).to.not.be.reverted; await modifier .connect(owner) - .allowTarget(ROLE_ID, testContract.address, OPTIONS_NONE); + .allowTarget(BADGE_ID, testContract.address, OPTIONS_NONE); // should work with sendAllowed false await expect( modifier .connect(invoker) - .execTransactionFromModuleReturnData(testContract.address, 1, "0x", 0) + .execTransactionFromModuleReturnData( + testContract.address, + 1, + "0x", + 0, + BADGE_ID + ) ).to.be.revertedWith("SendNotAllowed"); }); }); @@ -2012,10 +1634,10 @@ describe("RolesModifier", async () => { }); it("toggles allowed function false -> true -> false", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("doNothing") ); @@ -2025,19 +1647,18 @@ describe("RolesModifier", async () => { 0, testContract.interface.encodeFunctionData("doNothing()"), 0, + BADGE_ID, ]; - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); // allow the function await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -2051,7 +1672,7 @@ describe("RolesModifier", async () => { // revoke the function await modifier .connect(owner) - .scopeRevokeFunction(ROLE_ID, testContract.address, SELECTOR); + .scopeRevokeFunction(BADGE_ID, testContract.address, SELECTOR); // ngmi again await expect( @@ -2059,79 +1680,4 @@ describe("RolesModifier", async () => { ).to.be.revertedWith("FunctionNotAllowed"); }); }); - - describe("setDefaultRole()", () => { - it("reverts if not authorized", async () => { - const { modifier } = await txSetup(); - await expect(modifier.setDefaultRole(AddressOne, 1)).to.be.revertedWith( - "Ownable: caller is not the owner" - ); - }); - - it("sets default role", async () => { - const { modifier, testContract, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const ROLE1 = 1; - const ROLE2 = 2; - - // grant roles 1 and 2 to invoker - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE1, ROLE2], [true, true]); - - // make ROLE2 the default for invoker - await modifier.connect(owner).setDefaultRole(invoker.address, ROLE2); - - // allow all calls to testContract from ROLE1 - await modifier - .connect(owner) - .allowTarget(ROLE1, testContract.address, OPTIONS_NONE); - - // expect it to fail - await expect( - modifier - .connect(invoker) - .execTransactionFromModule( - testContract.address, - 0, - testContract.interface.encodeFunctionData("doNothing()"), - 0 - ) - ).to.be.reverted; - - // make ROLE1 the default to invoker - await modifier.connect(owner).setDefaultRole(invoker.address, ROLE1); - - // gmi - await expect( - modifier - .connect(invoker) - .execTransactionFromModule( - testContract.address, - 0, - testContract.interface.encodeFunctionData("doNothing()"), - 0 - ) - ).to.emit(testContract, "DoNothing"); - }); - - it("emits event with correct params", async () => { - const { modifier, owner, invoker } = - await setupRolesWithOwnerAndInvoker(); - - const ROLE_ID = 21; - - // grant roles 1 and 2 to invoker - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); - - await expect( - modifier.connect(owner).setDefaultRole(invoker.address, ROLE_ID) - ) - .to.emit(modifier, "SetDefaultRole") - .withArgs(invoker.address, 21); - }); - }); }); diff --git a/test/Scoping.spec.ts b/test/Scoping.spec.ts index 0e7b7b5ea..1ff36a12e 100644 --- a/test/Scoping.spec.ts +++ b/test/Scoping.spec.ts @@ -27,7 +27,10 @@ describe("Scoping", async () => { const avatar = await Avatar.deploy(); const TestContract = await hre.ethers.getContractFactory("TestContract"); const testContract = await TestContract.deploy(); - return { Avatar, avatar, testContract }; + const Badger = await hre.ethers.getContractFactory("Badger"); + const badger = await Badger.deploy("ipfs://"); + + return { Avatar, avatar, testContract, badger }; }); const setupRolesWithOwnerAndInvoker = deployments.createFixture(async () => { @@ -46,11 +49,10 @@ describe("Scoping", async () => { const modifier = await Modifier.deploy( owner.address, base.avatar.address, - base.avatar.address + base.avatar.address, + base.badger.address ); - await modifier.enableModule(invoker.address); - return { ...base, Modifier, @@ -61,17 +63,15 @@ describe("Scoping", async () => { }); it("scoping one param should work", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 1; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); const { data: dataFail } = await testContract.populateTransaction.fnWithThreeParams(1, 2, 3); @@ -79,12 +79,12 @@ describe("Scoping", async () => { const { data: dataOk } = await testContract.populateTransaction.fnWithThreeParams(1, 4, 3); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -93,13 +93,19 @@ describe("Scoping", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataFail, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataFail, + 0, + BADGE_ID + ) ).to.not.be.reverted; await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -111,35 +117,39 @@ describe("Scoping", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataFail, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataFail, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataOk, 0) + .execTransactionFromModule(testContract.address, 0, dataOk, 0, BADGE_ID) ).to.not.be.reverted; }); it("unscoping one param should work", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -151,7 +161,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -169,48 +179,58 @@ describe("Scoping", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataFail, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataFail, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); // sanity check await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataOk, 0) + .execTransactionFromModule(testContract.address, 0, dataOk, 0, BADGE_ID) ).to.not.be.reverted; await modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 1); + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 1); // works after unscoping await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataFail, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataFail, + 0, + BADGE_ID + ) ).to.not.be.reverted; }); it("scoping one param should work after allow function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); // this call is supposed to be redudant. This test is checking that scoping one para after scoping all works await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -219,7 +239,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -237,7 +257,8 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); @@ -250,35 +271,34 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(7, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.not.be.reverted; }); it("scoping one param should work after scope function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); const { data: dataFail } = await testContract.populateTransaction.fnWithThreeParams(1, 2, 3); const { data: dataOk } = await testContract.populateTransaction.fnWithThreeParams(1, 7, 3); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [false, true, false], @@ -291,20 +311,26 @@ describe("Scoping", async () => { await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataFail, 0) + .execTransactionFromModule( + testContract.address, + 0, + dataFail, + 0, + BADGE_ID + ) ).to.be.revertedWith("ParameterNotAllowed()"); await expect( modifier .connect(invoker) - .execTransactionFromModule(testContract.address, 0, dataOk, 0) + .execTransactionFromModule(testContract.address, 0, dataOk, 0, BADGE_ID) ).to.not.be.reverted; // set last param also as scoped await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 2, @@ -323,7 +349,8 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 7, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); await expect( @@ -335,7 +362,8 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 8) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); await expect( @@ -347,30 +375,29 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 7, 8) ).data, - 0 + 0, + BADGE_ID ) ).to.not.be.reverted; }); it("function scoping all params off is equivalent to allowing function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -388,14 +415,15 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [false, false, false], @@ -414,30 +442,29 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "FnWithThreeParams"); }); it("function scoping all params off, including dynamic types, is equivalent to allow function", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithTwoMixedParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -455,14 +482,15 @@ describe("Scoping", async () => { "Hello World!" ) ).data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "FnWithTwoMixedParams"); await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [false, false], @@ -484,30 +512,29 @@ describe("Scoping", async () => { "Hello World!" ) ).data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "FnWithTwoMixedParams"); }); it("unscoping all params one by one is equivalent to allowFunction", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [true, true, false], @@ -523,7 +550,7 @@ describe("Scoping", async () => { await modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 0); + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 0); //if some params still scoped returned ParamNotAllowed await expect( @@ -535,13 +562,14 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); await modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 1); + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 1); //all params off -> FunctionNotAllowed await expect( @@ -553,29 +581,28 @@ describe("Scoping", async () => { ( await testContract.populateTransaction.fnWithThreeParams(1, 2, 3) ).data, - 0 + 0, + BADGE_ID ) ).to.be.emit(testContract, "FnWithThreeParams"); }); it("unscoping all params one by one, including dynamic types, is equivalent to allowFunction", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithTwoMixedParams") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -587,7 +614,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -609,14 +636,15 @@ describe("Scoping", async () => { "Hello World!" ) ).data, - 0 + 0, + BADGE_ID ) ).to.be.revertedWith("ParameterNotAllowed()"); // should work after we unscope first parameter await modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 0); + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 0); await expect( modifier @@ -630,14 +658,15 @@ describe("Scoping", async () => { "Hello World!" ) ).data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "FnWithTwoMixedParams"); // unscope second parameter, leaves no parameter scoped await modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 1); + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 1); // whole function should be not allowed await expect( @@ -652,28 +681,27 @@ describe("Scoping", async () => { "Something not previously allowed" ) ).data, - 0 + 0, + BADGE_ID ) ).to.emit(testContract, "FnWithTwoMixedParams"); }); it("update paramComp should work on already scoped parameter", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithSingleParam") ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeAllowFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, OPTIONS_NONE @@ -687,7 +715,8 @@ describe("Scoping", async () => { 0, (await testContract.populateTransaction.fnWithSingleParam(param)) .data, - 0 + 0, + BADGE_ID ); // sanity @@ -696,7 +725,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -714,7 +743,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -728,10 +757,10 @@ describe("Scoping", async () => { }); it("scoping a high parameter index, after a lower one should work", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") @@ -745,19 +774,18 @@ describe("Scoping", async () => { 0, (await testContract.populateTransaction.fnWithThreeParams(a, b, c)) .data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -771,7 +799,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 1, @@ -787,10 +815,10 @@ describe("Scoping", async () => { }); it("scoping a low parameter index, after a higher one should work", async () => { - const { modifier, testContract, owner, invoker } = + const { modifier, testContract, owner, invoker, badger } = await setupRolesWithOwnerAndInvoker(); - const ROLE_ID = 0; + const BADGE_ID = 0; const SELECTOR = testContract.interface.getSighash( testContract.interface.getFunction("fnWithThreeParams") @@ -804,19 +832,18 @@ describe("Scoping", async () => { 0, (await testContract.populateTransaction.fnWithThreeParams(a, b, c)) .data, - 0 + 0, + BADGE_ID ); - await modifier - .connect(owner) - .assignRoles(invoker.address, [ROLE_ID], [true]); + await badger.mint(invoker.address, BADGE_ID, 1); - await modifier.connect(owner).scopeTarget(ROLE_ID, testContract.address); + await modifier.connect(owner).scopeTarget(BADGE_ID, testContract.address); await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 2, @@ -830,7 +857,7 @@ describe("Scoping", async () => { await modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -854,12 +881,12 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, new Array(49).fill(false), @@ -874,7 +901,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, new Array(48).fill(false), @@ -894,13 +921,13 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 48, @@ -914,7 +941,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 47, @@ -933,12 +960,12 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 48, @@ -951,7 +978,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 47, @@ -969,17 +996,17 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 48) + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 48) ).to.be.revertedWith("ScopeMaxParametersExceeded()"); await expect( modifier .connect(owner) - .unscopeParameter(ROLE_ID, testContract.address, SELECTOR, 47) + .unscopeParameter(BADGE_ID, testContract.address, SELECTOR, 47) ).to.not.be.reverted; }); }); @@ -1000,14 +1027,14 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; const IS_SCOPED = true; await expect( modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [IS_SCOPED], @@ -1022,7 +1049,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [IS_SCOPED], @@ -1037,7 +1064,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [IS_SCOPED], @@ -1053,7 +1080,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeFunction( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, [IS_SCOPED, !IS_SCOPED], @@ -1076,12 +1103,12 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1095,7 +1122,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1109,7 +1136,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameter( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1128,12 +1155,12 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1149,7 +1176,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1165,7 +1192,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1183,12 +1210,12 @@ describe("Scoping", async () => { testContract.interface.getFunction("doNothing") ); - const ROLE_ID = 0; + const BADGE_ID = 0; await expect( modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1201,7 +1228,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0, @@ -1214,7 +1241,7 @@ describe("Scoping", async () => { modifier .connect(owner) .scopeParameterAsOneOf( - ROLE_ID, + BADGE_ID, testContract.address, SELECTOR, 0,