From 5e2653b7b34f607d05889df5fc85f4b3a11bd6b7 Mon Sep 17 00:00:00 2001 From: Austin Green Date: Tue, 5 Dec 2023 14:57:45 -0500 Subject: [PATCH] conflicts --- src/llama-scripts/LlamaBaseScript.sol | 23 ---- src/llama-scripts/LlamaSingleUseScript.sol | 27 ----- .../ERC721TokenholderActionCreator.sol | 3 +- src/token-voting/LlamaTokenVotingFactory.sol | 108 ++---------------- src/token-voting/TokenholderActionCreator.sol | 8 +- src/token-voting/TokenholderCaster.sol | 6 +- 6 files changed, 18 insertions(+), 157 deletions(-) delete mode 100644 src/llama-scripts/LlamaBaseScript.sol delete mode 100644 src/llama-scripts/LlamaSingleUseScript.sol diff --git a/src/llama-scripts/LlamaBaseScript.sol b/src/llama-scripts/LlamaBaseScript.sol deleted file mode 100644 index 6e33630..0000000 --- a/src/llama-scripts/LlamaBaseScript.sol +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -/// @dev This script is a template for creating new scripts, and should not be used directly. -abstract contract LlamaBaseScript { - /// @dev Thrown if you try to CALL a function that has the `onlyDelegatecall` modifier. - error OnlyDelegateCall(); - - /// @dev Add this to your script's methods to ensure the script can only be used via delegatecall, and not a regular - /// call. - modifier onlyDelegateCall() { - if (address(this) == SELF) revert OnlyDelegateCall(); - _; - } - - /// @dev Address of the script contract. We save it off because during a delegatecall `address(this)` refers to the - /// caller's address, not this script's address. - address internal immutable SELF; - - constructor() { - SELF = address(this); - } -} diff --git a/src/llama-scripts/LlamaSingleUseScript.sol b/src/llama-scripts/LlamaSingleUseScript.sol deleted file mode 100644 index 0f28d49..0000000 --- a/src/llama-scripts/LlamaSingleUseScript.sol +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import {LlamaBaseScript} from "src/llama-scripts/LlamaBaseScript.sol"; -import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; -import {ILlamaExecutor} from "src/interfaces/ILlamaExecutor.sol"; - -/// @dev This script is a template for creating new scripts, and should not be used directly. -/// @dev This script is meant to be delegatecalled by the executor contract, with the script leveraging the -/// `unauthorizeAfterRun` modifier to ensure it can only be used once. -abstract contract LlamaSingleUseScript is LlamaBaseScript { - /// @dev Add this to your script's methods to unauthorize itself after it has been run once. Any subsequent calls will - /// fail unless the script is reauthorized. Best if used in tandem with the `onlyDelegateCall` from `BaseScript.sol`. - modifier unauthorizeAfterRun() { - _; - ILlamaCore core = ILlamaCore(EXECUTOR.LLAMA_CORE()); - core.setScriptAuthorization(SELF, false); - } - - /// @dev Address of the executor contract. We save it off in order to access the setScriptAuthorization method in - /// `LlamaCore`. - ILlamaExecutor internal immutable EXECUTOR; - - constructor(ILlamaExecutor executor) { - EXECUTOR = executor; - } -} diff --git a/src/token-voting/ERC721TokenholderActionCreator.sol b/src/token-voting/ERC721TokenholderActionCreator.sol index 7be92ce..0836ad8 100644 --- a/src/token-voting/ERC721TokenholderActionCreator.sol +++ b/src/token-voting/ERC721TokenholderActionCreator.sol @@ -17,10 +17,11 @@ contract ERC721TokenholderActionCreator is TokenholderActionCreator { TokenholderActionCreator(llamaCore, _creationThreshold) { TOKEN = token; + if (!TOKEN.supportsInterface(type(IERC721).interfaceId)) revert InvalidTokenAddress(); + uint256 totalSupply = TOKEN.getPastTotalSupply(block.timestamp - 1); if (totalSupply == 0) revert InvalidTokenAddress(); if (_creationThreshold > totalSupply) revert InvalidCreationThreshold(); - if (!TOKEN.supportsInterface(type(IERC721).interfaceId)) revert InvalidTokenAddress(); } function _getPastVotes(address account, uint256 timestamp) internal view virtual override returns (uint256) { diff --git a/src/token-voting/LlamaTokenVotingFactory.sol b/src/token-voting/LlamaTokenVotingFactory.sol index e539f0d..45a1a3e 100644 --- a/src/token-voting/LlamaTokenVotingFactory.sol +++ b/src/token-voting/LlamaTokenVotingFactory.sol @@ -2,21 +2,18 @@ pragma solidity ^0.8.23; import {ILlamaCore} from "src/interfaces/ILlamaCore.sol"; -import {ILlamaPolicy} from "src/interfaces/ILlamaPolicy.sol"; import {ILlamaExecutor} from "src/interfaces/ILlamaExecutor.sol"; -import {RoleDescription} from "src/lib/UDVTs.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"; import {ERC721TokenholderActionCreator} from "src/token-voting/ERC721TokenholderActionCreator.sol"; import {ERC721TokenholderCaster} from "src/token-voting/ERC721TokenholderCaster.sol"; import {ERC721Votes} from "@openzeppelin/token/ERC721/extensions/ERC721Votes.sol"; -import {LlamaBaseScript} from "src/llama-scripts/LlamaBaseScript.sol"; /// @title LlamaTokenVotingFactory /// @author Llama (devsdosomething@llama.xyz) /// @notice This contract lets llama instances deploy a token voting module in a single llama action. -contract LlamaTokenVotingFactory is LlamaBaseScript { +contract LlamaTokenVotingFactory { error NoModulesDeployed(); event ERC20TokenholderActionCreatorCreated(address actionCreator, address indexed token); @@ -34,8 +31,6 @@ contract LlamaTokenVotingFactory is LlamaBaseScript { /// a script. ///@param token The address of the token to be used for voting. ///@param isERC20 Whether the token is an ERC20 or ERC721. - ///@param deployActionCreator Whether to deploy the action creator. - ///@param deployCaster Whether to deploy the caster. ///@param creationThreshold The number of tokens required to create an action (set to 0 if not deploying action /// creator). ///@param minApprovalPct The minimum percentage of tokens required to approve an action (set to 0 if not deploying @@ -45,73 +40,17 @@ contract LlamaTokenVotingFactory is LlamaBaseScript { function deployTokenVotingModule( address token, bool isERC20, - bool deployActionCreator, - bool deployCaster, uint256 creationThreshold, uint256 minApprovalPct, uint256 minDisapprovalPct - ) public returns (address, address) { - return _deployTokenVotingModule( - ILlamaExecutor(msg.sender), - token, - isERC20, - deployActionCreator, - deployCaster, - creationThreshold, - minApprovalPct, - minDisapprovalPct - ); - } - - ///@notice A llama script that deploys a token voting module and inittializes/issues roles to the token voting action - /// creator and caster in a single function so it can be deployed in a single llama action. - ///@dev This contract must be authorized as a script in the core contract before it can be used (invoke the - /// `LlamaCore::setScriptAuthorization` function to authorize). - ///@dev This method CAN NOT be used in tandem with `deployTokenVotingModule`. You must use one or the other due to - /// this method requring the contract to be authorized as a script. - ///@param token The address of the token to be used for voting. - ///@param isERC20 Whether the token is an ERC20 or ERC721. - ///@param deployActionCreator Whether to deploy the action creator. - ///@param deployCaster Whether to deploy the caster. - ///@param creationThreshold The number of tokens required to create an action (set to 0 if not deploying action - /// creator). - ///@param minApprovalPct The minimum percentage of tokens required to approve an action (set to 0 if not deploying - /// caster). - ///@param minDisapprovalPct The minimum percentage of tokens required to disapprove an action (set to 0 if not - /// deploying caster). - function delegateCallDeployTokenVotingModuleWithRoles( - address token, - bool isERC20, - bool deployActionCreator, - bool deployCaster, - uint256 creationThreshold, - uint256 minApprovalPct, - uint256 minDisapprovalPct - ) public onlyDelegateCall { - (address actionCreator, address caster) = _deployTokenVotingModule( - ILlamaExecutor(address(this)), - token, - isERC20, - deployActionCreator, - deployCaster, - creationThreshold, - minApprovalPct, - minDisapprovalPct - ); - - ILlamaExecutor executor = ILlamaExecutor(address(this)); - ILlamaCore core = ILlamaCore(executor.LLAMA_CORE()); - ILlamaPolicy policy = ILlamaPolicy(core.policy()); - uint8 numRoles = policy.numRoles(); - string memory name; - isERC20 ? name = ERC20Votes(token).name() : name = ERC721Votes(token).name(); - if (actionCreator != address(0)) { - policy.initializeRole(RoleDescription.wrap(bytes32(abi.encodePacked("Action Creator Role: ", name)))); - policy.setRoleHolder(numRoles + 1, actionCreator, 1, type(uint64).max); - } - if (caster != address(0)) { - policy.initializeRole(RoleDescription.wrap(bytes32(abi.encodePacked("Caster Role: ", name)))); - policy.setRoleHolder(actionCreator == address(0) ? numRoles + 1 : numRoles + 2, caster, 1, type(uint64).max); + ) external returns (address actionCreator, address caster) { + ILlamaCore core = ILlamaCore(ILlamaExecutor(executor).LLAMA_CORE()); + if (isERC20) { + actionCreator = address(_deployERC20TokenholderActionCreator(ERC20Votes(token), core, creationThreshold)); + caster = address(_deployERC20TokenholderCaster(ERC20Votes(token), core, 0, minApprovalPct, minDisapprovalPct)); + } else { + actionCreator = address(_deployERC721TokenholderActionCreator(ERC721Votes(token), core, creationThreshold)); + caster = address(_deployERC721TokenholderCaster(ERC721Votes(token), core, 0, minApprovalPct, minDisapprovalPct)); } } @@ -119,35 +58,6 @@ contract LlamaTokenVotingFactory is LlamaBaseScript { // ======== Internal Functions ======== // ==================================== - function _deployTokenVotingModule( - ILlamaExecutor executor, - address token, - bool isERC20, - bool deployActionCreator, - bool deployCaster, - uint256 creationThreshold, - uint256 minApprovalPct, - uint256 minDisapprovalPct - ) internal returns (address actionCreator, address caster) { - if (!deployActionCreator && !deployCaster) revert NoModulesDeployed(); - ILlamaCore core = ILlamaCore(executor.LLAMA_CORE()); - if (isERC20) { - if (deployActionCreator) { - actionCreator = address(_deployERC20TokenholderActionCreator(ERC20Votes(token), core, creationThreshold)); - } - if (deployCaster) { - caster = address(_deployERC20TokenholderCaster(ERC20Votes(token), core, 0, minApprovalPct, minDisapprovalPct)); - } - } else { - if (deployActionCreator) { - actionCreator = address(_deployERC721TokenholderActionCreator(ERC721Votes(token), core, creationThreshold)); - } - if (deployCaster) { - caster = address(_deployERC721TokenholderCaster(ERC721Votes(token), core, 0, minApprovalPct, minDisapprovalPct)); - } - } - } - function _deployERC20TokenholderActionCreator(ERC20Votes token, ILlamaCore llamaCore, uint256 creationThreshold) internal returns (ERC20TokenholderActionCreator actionCreator) diff --git a/src/token-voting/TokenholderActionCreator.sol b/src/token-voting/TokenholderActionCreator.sol index 705aee1..c89637a 100644 --- a/src/token-voting/TokenholderActionCreator.sol +++ b/src/token-voting/TokenholderActionCreator.sol @@ -10,10 +10,10 @@ import {LlamaUtils} from "src/lib/LlamaUtils.sol"; /// @author Llama (devsdosomething@llama.xyz) /// @notice This contract lets holders of a given governance token create actions if they have /// sufficient token balance. -/// @dev This contract can be deployed by anyone, but to actually be able to create an action it -/// will need to hold a Policy from the specified `LlamaCore` instance. That policy encodes what -/// actions this contract is allowed to create, and attempting to create an action that is not -/// allowed by the policy will result in a revert. +/// @dev This contract is deployed by `LlamaTokenVotingFactory`. Anyone can deploy this contract using the factory, but +/// it must hold a Policy from the specified `LlamaCore` instance to actually be able to create an action. The +/// instance's policy encodes what actions this contract is allowed to create, and attempting to create an action that +/// is not allowed by the policy will result in a revert. abstract contract TokenholderActionCreator { /// @notice The core contract for this Llama instance. ILlamaCore public immutable LLAMA_CORE; diff --git a/src/token-voting/TokenholderCaster.sol b/src/token-voting/TokenholderCaster.sol index 56557eb..0009243 100644 --- a/src/token-voting/TokenholderCaster.sol +++ b/src/token-voting/TokenholderCaster.sol @@ -12,9 +12,9 @@ import {ILlamaRelativeStrategyBase} from "src/interfaces/ILlamaRelativeStrategyB /// @author Llama (devsdosomething@llama.xyz) /// @notice This contract lets holders of a given governance token cast approvals and disapprovals /// on created actions. -/// @dev This contract can be deployed by anyone, but to actually be able to cast on an action it -/// will need to hold the appropriate Policy from the specified `LlamaCore` instance. This contract -/// does not verify that it holds the correct policy when voting, and relies on `LlamaCore` to +/// @dev This contract is deployed by `LlamaTokenVotingFactory`. Anyone can deploy this contract using the factory, but +/// it must hold a Policy from the specified `LlamaCore` instance to actually be able to cast on an action. This +/// contract does not verify that it holds the correct policy when voting and relies on `LlamaCore` to /// verify that during submission. abstract contract TokenholderCaster { // =========================