From 805bf2f746e38f678f18e4f0b41f1d829ebdc2ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8r=E2=88=82=C2=A1?= Date: Wed, 29 Nov 2023 20:47:48 +0100 Subject: [PATCH] Updates member access condition tests --- .../src/MemberAccessExecuteCondition.sol | 38 +- .../member-access-execute-condition.ts | 724 +++++++++--------- 2 files changed, 391 insertions(+), 371 deletions(-) diff --git a/packages/contracts/src/MemberAccessExecuteCondition.sol b/packages/contracts/src/MemberAccessExecuteCondition.sol index d3ebdae..417cb2a 100644 --- a/packages/contracts/src/MemberAccessExecuteCondition.sol +++ b/packages/contracts/src/MemberAccessExecuteCondition.sol @@ -19,13 +19,26 @@ contract MemberAccessExecuteCondition is PermissionCondition { } function getSelector(bytes memory _data) public pure returns (bytes4 selector) { - // Slices are only supported for bytes calldata + // Slices are only supported for bytes calldata, not bytes memory // Bytes memory requires an assembly block assembly { selector := mload(add(_data, 32)) } } + function decodeGrantRevokeCalldata( + bytes memory _data + ) public pure returns (bytes4 sig, address who, address where, bytes32 permissionId) { + // Slicing is only supported for bytes calldata, not bytes memory + // Bytes memory requires an assembly block + assembly { + sig := mload(add(_data, 32)) + who := mload(add(_data, 36)) + where := mload(add(_data, 68)) + permissionId := mload(add(_data, 100)) + } + } + /// @notice Checks whether the current action wants to grant membership on the predefined address function isGranted( address _where, @@ -35,8 +48,8 @@ contract MemberAccessExecuteCondition is PermissionCondition { ) external view returns (bool) { (_where, _who, _permissionId); - bytes4 _requestedFuncSig = getSelector(_data); - if (_requestedFuncSig != IDAO.execute.selector) { + // Is execute()? + if (getSelector(_data) != IDAO.execute.selector) { return false; } @@ -47,19 +60,20 @@ contract MemberAccessExecuteCondition is PermissionCondition { // Check actions if (_actions.length != 1) return false; - _requestedFuncSig = getSelector(_actions[0].data); + + // Decode the call being requested (both have the same parameters) + ( + bytes4 _requestedSelector, + address _requestedWhere, + , + bytes32 _requestedPermission + ) = decodeGrantRevokeCalldata(_actions[0].data); if ( - _requestedFuncSig != PermissionManager.grant.selector && - _requestedFuncSig != PermissionManager.revoke.selector + _requestedSelector != PermissionManager.grant.selector && + _requestedSelector != PermissionManager.revoke.selector ) return false; - // Decode the call being requested (both have the same parameters) - (, address _requestedWhere, , bytes32 _requestedPermission) = abi.decode( - _actions[0].data, - (bytes4 /*funcSig*/, address /*where*/, address /*who*/, bytes32 /*perm*/) - ); - if (_requestedWhere != targetContract) return false; else if (_requestedPermission != MEMBER_PERMISSION_ID) return false; diff --git a/packages/contracts/test/unit-testing/member-access-execute-condition.ts b/packages/contracts/test/unit-testing/member-access-execute-condition.ts index 9dd5fcb..6fb9a8b 100644 --- a/packages/contracts/test/unit-testing/member-access-execute-condition.ts +++ b/packages/contracts/test/unit-testing/member-access-execute-condition.ts @@ -1,6 +1,7 @@ import { DAO, DAO__factory, + IDAO, MemberAccessExecuteCondition, MemberAccessExecuteCondition__factory, } from '../../typechain'; @@ -22,6 +23,8 @@ import {toUtf8Bytes} from 'ethers/lib/utils'; import {ethers} from 'hardhat'; const SOME_CONTRACT_ADDRESS = '0x' + '1234567890'.repeat(4); +const ONE_BYTES32 = + '0x0000000000000000000000000000000000000000000000000000000000000001'; describe('Member Access Condition', function () { let alice: SignerWithAddress; @@ -40,380 +43,383 @@ describe('Member Access Condition', function () { memberAccessExecuteCondition = await factory.deploy(SOME_CONTRACT_ADDRESS); }); - it('Should only accept granting and revoking', async () => { - // Valid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + describe('Executing grant/revoke MEMBER_PERMISSION_ID on a certain contract', () => { + const daoInterface = DAO__factory.createInterface(); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + it('Should only allow executing grant and revoke', async () => { + const actions: IDAO.ActionStruct[] = [ + {to: dao.address, value: 0, data: '0x'}, + ]; - // Invalid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('setDaoURI', [ - // call - hexlify(toUtf8Bytes('ipfs://')), - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('setMetadata', [ - // call - hexlify(toUtf8Bytes('ipfs://')), - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData( - 'setSignatureValidator', - [ - // call - ADDRESS_ONE, - ] + // Valid grant + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) ) - ) - ).to.eq(false); - }); + ).to.eq(true); - it('Should only allow MEMBER_PERMISSION_ID', async () => { - // Valid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + // Valid revoke + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(true); - // Invalid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - EDITOR_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - EDITOR_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - ROOT_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - ROOT_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - DEPLOYER_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - DEPLOYER_PERMISSION_ID, - ]) - ) - ).to.eq(false); - }); + // Invalid + actions[0].data = daoInterface.encodeFunctionData('setDaoURI', [ + hexlify(toUtf8Bytes('ipfs://')), + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); - it('Should only allow to target the intended plugin contract', async () => { - // Valid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + // Invalid + actions[0].data = daoInterface.encodeFunctionData('setMetadata', [ + hexlify(toUtf8Bytes('ipfs://')), + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); - // Invalid - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - ADDRESS_TWO, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - ADDRESS_TWO, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(false); + // Invalid + actions[0].data = daoInterface.encodeFunctionData( + 'setSignatureValidator', + [ADDRESS_ONE] + ); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + }); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - dao.address, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(false); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - dao.address, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(false); - }); + it('Should only allow MEMBER_PERMISSION_ID', async () => { + const actions: IDAO.ActionStruct[] = [ + {to: dao.address, value: 0, data: '0x'}, + ]; - it("Should allow granting to whatever 'who' address", async () => { - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - alice.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - alice.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + // Valid grant + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(true); - // Bob - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - bob.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - bob.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + // Valid revoke + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(true); - // Carol - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call - SOME_CONTRACT_ADDRESS, - carol.address, - MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + // Invalid + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + EDITOR_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + EDITOR_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + // Invalid + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + ROOT_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + ROOT_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + // Invalid + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + DEPLOYER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + DEPLOYER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + }); + + it('Should only allow to target the intended plugin contract', async () => { + const actions: IDAO.ActionStruct[] = [ + {to: dao.address, value: 0, data: '0x'}, + ]; + + // Valid grant + actions[0].data = daoInterface.encodeFunctionData('grant', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(true); + + // Valid revoke + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(true); + + // Invalid + actions[0].data = daoInterface.encodeFunctionData('grant', [ + ADDRESS_TWO, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); - // Any - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('grant', [ - // call + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + ADDRESS_TWO, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + // Invalid + actions[0].data = daoInterface.encodeFunctionData('grant', [ + dao.address, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + + actions[0].data = daoInterface.encodeFunctionData('revoke', [ + dao.address, + carol.address, + MEMBER_PERMISSION_ID, + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ONE_BYTES32, actions, 0]) + ) + ).to.eq(false); + }); + + it("Should allow granting to whatever 'who' address", async () => { + const actions: IDAO.ActionStruct[] = [ + {to: dao.address, value: 0, data: '0x'}, + ]; + for (const grantedToAddress of [ + SOME_CONTRACT_ADDRESS, + bob.address, + dao.address, + ADDRESS_ONE, + ]) { + // Valid grant + actions[0].data = daoInterface.encodeFunctionData('grant', [ SOME_CONTRACT_ADDRESS, - ADDRESS_ZERO, + grantedToAddress, MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); - expect( - await memberAccessExecuteCondition.isGranted( - ADDRESS_ONE, // where (used) - ADDRESS_TWO, // who (used) - EXECUTE_PERMISSION_ID, // permission (used) - DAO__factory.createInterface().encodeFunctionData('revoke', [ - // call + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ + ONE_BYTES32, + actions, + 0, + ]) + ) + ).to.eq(true); + + // Valid revoke + actions[0].data = daoInterface.encodeFunctionData('revoke', [ SOME_CONTRACT_ADDRESS, - ADDRESS_ZERO, + grantedToAddress, MEMBER_PERMISSION_ID, - ]) - ) - ).to.eq(true); + ]); + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + daoInterface.encodeFunctionData('execute', [ + ONE_BYTES32, + actions, + 0, + ]) + ) + ).to.eq(true); + } + }); + }); + + describe('Direct grant and revoke are not allowed', () => { + it('Should reject granting and revoking directly', async () => { + // Valid + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + DAO__factory.createInterface().encodeFunctionData('grant', [ + // call + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]) + ) + ).to.eq(false); + + expect( + await memberAccessExecuteCondition.isGranted( + ADDRESS_ONE, // where (used) + ADDRESS_TWO, // who (used) + EXECUTE_PERMISSION_ID, // permission (used) + DAO__factory.createInterface().encodeFunctionData('revoke', [ + // call + SOME_CONTRACT_ADDRESS, + carol.address, + MEMBER_PERMISSION_ID, + ]) + ) + ).to.eq(false); + }); }); });