diff --git a/src/token-voting/LlamaTokenVotingFactory.sol b/src/token-voting/LlamaTokenVotingFactory.sol index cc703db..7ab8054 100644 --- a/src/token-voting/LlamaTokenVotingFactory.sol +++ b/src/token-voting/LlamaTokenVotingFactory.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.23; import {Clones} from "@openzeppelin/proxy/Clones.sol"; import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; -import {ILlamaExecutor} from "src/interfaces/ILlamaExecutor.sol"; import {ERC20TokenholderActionCreator} from "src/token-voting/ERC20TokenholderActionCreator.sol"; import {ERC20TokenholderCaster} from "src/token-voting/ERC20TokenholderCaster.sol"; import {ERC20Votes} from "@openzeppelin/token/ERC20/extensions/ERC20Votes.sol"; @@ -67,6 +66,7 @@ contract LlamaTokenVotingFactory { ///@param minDisapprovalPct The minimum percentage of tokens required to disapprove an action (set to 0 if not /// deploying caster). function deployTokenVotingModule( + ILlamaCore llamaCore, address token, bool isERC20, uint8 actionCreatorRole, @@ -75,17 +75,20 @@ contract LlamaTokenVotingFactory { uint256 minApprovalPct, uint256 minDisapprovalPct ) external returns (address actionCreator, address caster) { - ILlamaCore core = ILlamaCore(ILlamaExecutor(msg.sender).LLAMA_CORE()); if (isERC20) { - actionCreator = - address(_deployERC20TokenholderActionCreator(ERC20Votes(token), core, actionCreatorRole, creationThreshold)); - caster = - address(_deployERC20TokenholderCaster(ERC20Votes(token), core, casterRole, minApprovalPct, minDisapprovalPct)); + actionCreator = address( + _deployERC20TokenholderActionCreator(ERC20Votes(token), llamaCore, actionCreatorRole, creationThreshold) + ); + caster = address( + _deployERC20TokenholderCaster(ERC20Votes(token), llamaCore, casterRole, minApprovalPct, minDisapprovalPct) + ); } else { - actionCreator = - address(_deployERC721TokenholderActionCreator(ERC721Votes(token), core, actionCreatorRole, creationThreshold)); - caster = - address(_deployERC721TokenholderCaster(ERC721Votes(token), core, casterRole, minApprovalPct, minDisapprovalPct)); + actionCreator = address( + _deployERC721TokenholderActionCreator(ERC721Votes(token), llamaCore, actionCreatorRole, creationThreshold) + ); + caster = address( + _deployERC721TokenholderCaster(ERC721Votes(token), llamaCore, casterRole, minApprovalPct, minDisapprovalPct) + ); } } diff --git a/test/token-voting/LlamaTokenVotingFactory.t.sol b/test/token-voting/LlamaTokenVotingFactory.t.sol index 75a6811..619b95d 100644 --- a/test/token-voting/LlamaTokenVotingFactory.t.sol +++ b/test/token-voting/LlamaTokenVotingFactory.t.sol @@ -89,6 +89,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { // Set up action to call `deployTokenVotingModule` with the ERC20 token. bytes memory data = abi.encodeWithSelector( LlamaTokenVotingFactory.deployTokenVotingModule.selector, + CORE, address(erc20VotesToken), true, tokenVotingActionCreatorRole, @@ -141,6 +142,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { // Set up action to call `deployTokenVotingModule` with the ERC721 token. bytes memory data = abi.encodeWithSelector( LlamaTokenVotingFactory.deployTokenVotingModule.selector, + CORE, address(erc721VotesToken), false, tokenVotingActionCreatorRole, @@ -188,4 +190,56 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest { assertEq(erc721TokenholderCaster.minApprovalPct(), ERC721_MIN_APPROVAL_PCT); assertEq(erc721TokenholderCaster.minDisapprovalPct(), ERC721_MIN_DISAPPROVAL_PCT); } + + function test_CanBeDeployedByAnyone(address randomCaller) public { + vm.assume(randomCaller != address(0)); + vm.deal(randomCaller, 1 ether); + + ERC20TokenholderActionCreator erc20TokenholderActionCreator = ERC20TokenholderActionCreator( + Clones.predictDeterministicAddress( + address(erc20TokenholderActionCreatorLogic), + keccak256(abi.encodePacked(address(erc20VotesToken), randomCaller)), // salt + address(tokenVotingFactory) // deployer + ) + ); + + ERC20TokenholderCaster erc20TokenholderCaster = ERC20TokenholderCaster( + Clones.predictDeterministicAddress( + address(erc20TokenholderCasterLogic), + keccak256(abi.encodePacked(address(erc20VotesToken), randomCaller)), // salt + address(tokenVotingFactory) // deployer + ) + ); + + vm.expectEmit(); + emit ActionThresholdSet(ERC20_CREATION_THRESHOLD); + vm.expectEmit(); + emit ERC20TokenholderActionCreatorCreated(address(erc20TokenholderActionCreator), address(erc20VotesToken)); + vm.expectEmit(); + emit ERC20TokenholderCasterCreated( + address(erc20TokenholderCaster), address(erc20VotesToken), ERC20_MIN_APPROVAL_PCT, ERC20_MIN_DISAPPROVAL_PCT + ); + + vm.prank(randomCaller); + tokenVotingFactory.deployTokenVotingModule( + CORE, + address(erc20VotesToken), + true, + tokenVotingActionCreatorRole, + tokenVotingCasterRole, + ERC20_CREATION_THRESHOLD, + ERC20_MIN_APPROVAL_PCT, + ERC20_MIN_DISAPPROVAL_PCT + ); + + assertEq(address(erc20TokenholderActionCreator.token()), address(erc20VotesToken)); + assertEq(address(erc20TokenholderActionCreator.llamaCore()), address(CORE)); + assertEq(erc20TokenholderActionCreator.role(), tokenVotingActionCreatorRole); + assertEq(erc20TokenholderActionCreator.creationThreshold(), ERC20_CREATION_THRESHOLD); + assertEq(address(erc20TokenholderCaster.token()), address(erc20VotesToken)); + assertEq(address(erc20TokenholderCaster.llamaCore()), address(CORE)); + assertEq(erc20TokenholderCaster.role(), tokenVotingCasterRole); + assertEq(erc20TokenholderCaster.minApprovalPct(), ERC20_MIN_APPROVAL_PCT); + assertEq(erc20TokenholderCaster.minDisapprovalPct(), ERC20_MIN_DISAPPROVAL_PCT); + } } diff --git a/test/token-voting/LlamaTokenVotingTestSetup.sol b/test/token-voting/LlamaTokenVotingTestSetup.sol index ae0cf7c..27b6c90 100644 --- a/test/token-voting/LlamaTokenVotingTestSetup.sol +++ b/test/token-voting/LlamaTokenVotingTestSetup.sol @@ -96,6 +96,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV vm.startPrank(address(EXECUTOR)); // Deploy Token Voting Module (address erc20TokenholderActionCreator, address erc20TokenholderCaster) = tokenVotingFactory.deployTokenVotingModule( + CORE, address(erc20VotesToken), true, tokenVotingActionCreatorRole, @@ -123,6 +124,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV // Deploy Token Voting Module (address erc721TokenholderActionCreator, address erc721TokenholderCaster) = tokenVotingFactory .deployTokenVotingModule( + CORE, address(erc721VotesToken), false, tokenVotingActionCreatorRole,