Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into theo/language
Browse files Browse the repository at this point in the history
  • Loading branch information
dd0sxx committed Dec 9, 2023
2 parents a553161 + 51c1890 commit cd6962b
Show file tree
Hide file tree
Showing 17 changed files with 1,729 additions and 2,034 deletions.
40 changes: 20 additions & 20 deletions script/DeployLlamaTokenVotingFactory.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ pragma solidity 0.8.23;
import {Script} from "forge-std/Script.sol";

import {DeployUtils} from "script/DeployUtils.sol";
import {ERC20TokenHolderActionCreator} from "src/token-voting/ERC20TokenHolderActionCreator.sol";
import {ERC20TokenHolderCaster} from "src/token-voting/ERC20TokenHolderCaster.sol";
import {ERC721TokenHolderActionCreator} from "src/token-voting/ERC721TokenHolderActionCreator.sol";
import {ERC721TokenHolderCaster} from "src/token-voting/ERC721TokenHolderCaster.sol";
import {ERC20TokenholderActionCreator} from "src/token-voting/ERC20TokenholderActionCreator.sol";
import {ERC20TokenholderCaster} from "src/token-voting/ERC20TokenholderCaster.sol";
import {ERC721TokenholderActionCreator} from "src/token-voting/ERC721TokenholderActionCreator.sol";
import {ERC721TokenholderCaster} from "src/token-voting/ERC721TokenholderCaster.sol";
import {LlamaTokenVotingFactory} from "src/token-voting/LlamaTokenVotingFactory.sol";

contract DeployLlamaTokenVotingFactory is Script {
// Logic contracts.
ERC20TokenHolderActionCreator erc20TokenHolderActionCreatorLogic;
ERC20TokenHolderCaster erc20TokenHolderCasterLogic;
ERC721TokenHolderActionCreator erc721TokenHolderActionCreatorLogic;
ERC721TokenHolderCaster erc721TokenHolderCasterLogic;
ERC20TokenholderActionCreator erc20TokenholderActionCreatorLogic;
ERC20TokenholderCaster erc20TokenholderCasterLogic;
ERC721TokenholderActionCreator erc721TokenholderActionCreatorLogic;
ERC721TokenholderCaster erc721TokenholderCasterLogic;

// Factory contracts.
LlamaTokenVotingFactory tokenVotingFactory;
Expand All @@ -26,37 +26,37 @@ contract DeployLlamaTokenVotingFactory is Script {
);

vm.broadcast();
erc20TokenHolderActionCreatorLogic = new ERC20TokenHolderActionCreator();
erc20TokenholderActionCreatorLogic = new ERC20TokenholderActionCreator();
DeployUtils.print(
string.concat(" ERC20TokenHolderActionCreatorLogic: ", vm.toString(address(erc20TokenHolderActionCreatorLogic)))
string.concat(" ERC20TokenholderActionCreatorLogic: ", vm.toString(address(erc20TokenholderActionCreatorLogic)))
);

vm.broadcast();
erc20TokenHolderCasterLogic = new ERC20TokenHolderCaster();
erc20TokenholderCasterLogic = new ERC20TokenholderCaster();
DeployUtils.print(
string.concat(" ERC20TokenHolderCasterLogic: ", vm.toString(address(erc20TokenHolderCasterLogic)))
string.concat(" ERC20TokenholderCasterLogic: ", vm.toString(address(erc20TokenholderCasterLogic)))
);

vm.broadcast();
erc721TokenHolderActionCreatorLogic = new ERC721TokenHolderActionCreator();
erc721TokenholderActionCreatorLogic = new ERC721TokenholderActionCreator();
DeployUtils.print(
string.concat(
" ERC721TokenHolderActionCreatorLogic: ", vm.toString(address(erc721TokenHolderActionCreatorLogic))
" ERC721TokenholderActionCreatorLogic: ", vm.toString(address(erc721TokenholderActionCreatorLogic))
)
);

vm.broadcast();
erc721TokenHolderCasterLogic = new ERC721TokenHolderCaster();
erc721TokenholderCasterLogic = new ERC721TokenholderCaster();
DeployUtils.print(
string.concat(" ERC721TokenHolderCasterLogic: ", vm.toString(address(erc721TokenHolderCasterLogic)))
string.concat(" ERC721TokenholderCasterLogic: ", vm.toString(address(erc721TokenholderCasterLogic)))
);

vm.broadcast();
tokenVotingFactory = new LlamaTokenVotingFactory(
erc20TokenHolderActionCreatorLogic,
erc20TokenHolderCasterLogic,
erc721TokenHolderActionCreatorLogic,
erc721TokenHolderCasterLogic
erc20TokenholderActionCreatorLogic,
erc20TokenholderCasterLogic,
erc721TokenholderActionCreatorLogic,
erc721TokenholderCasterLogic
);
DeployUtils.print(string.concat(" LlamaTokenVotingFactory: ", vm.toString(address(tokenVotingFactory))));
}
Expand Down
12 changes: 8 additions & 4 deletions src/token-voting/ERC20TokenholderActionCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {ERC20Votes} from "@openzeppelin/token/ERC20/extensions/ERC20Votes.sol";
/// @author Llama ([email protected])
/// @notice This contract lets holders of a specified `ERC20Votes` token create actions on a llama instance if their
/// token balance is greater than or equal to the creation threshold.
contract ERC20TokenHolderActionCreator is TokenHolderActionCreator {
contract ERC20TokenholderActionCreator is TokenholderActionCreator {
ERC20Votes public token;

/// @dev This contract is deployed as a minimal proxy from the factory's `deployTokenVotingModule` function. The
Expand All @@ -18,16 +18,20 @@ contract ERC20TokenHolderActionCreator is TokenHolderActionCreator {
_disableInitializers();
}

/// @notice Initializes a new `ERC20TokenHolderActionCreator` clone.
/// @notice Initializes a new `ERC20TokenholderActionCreator` clone.
/// @dev This function is called by the `deployTokenVotingModule` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _token The ERC20 token to be used for voting.
/// @param _llamaCore The `LlamaCore` contract for this Llama instance.
/// @param _role The role used by this contract to cast approvals and disapprovals.
/// @param _creationThreshold The default number of tokens required to create an action. This must
/// be in the same decimals as the token. For example, if the token has 18 decimals and you want a
/// creation threshold of 1000 tokens, pass in 1000e18.
function initialize(ERC20Votes _token, ILlamaCore _llamaCore, uint256 _creationThreshold) external initializer {
__initializeTokenHolderActionCreatorMinimalProxy(_llamaCore, _creationThreshold);
function initialize(ERC20Votes _token, ILlamaCore _llamaCore, uint8 _role, uint256 _creationThreshold)
external
initializer
{
__initializeTokenholderActionCreatorMinimalProxy(_llamaCore, _role, _creationThreshold);
token = _token;
uint256 totalSupply = token.totalSupply();
if (totalSupply == 0) revert InvalidTokenAddress();
Expand Down
6 changes: 3 additions & 3 deletions src/token-voting/ERC20TokenholderCaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {ERC20Votes} from "@openzeppelin/token/ERC20/extensions/ERC20Votes.sol";
/// @author Llama ([email protected])
/// @notice This contract lets holders of a given governance ERC20Votes token cast approvals and disapprovals
/// on created actions.
contract ERC20TokenHolderCaster is TokenHolderCaster {
contract ERC20TokenholderCaster is TokenholderCaster {
ERC20Votes public token;

/// @dev This contract is deployed as a minimal proxy from the factory's `deployTokenVotingModule` function. The
Expand All @@ -18,7 +18,7 @@ contract ERC20TokenHolderCaster is TokenHolderCaster {
_disableInitializers();
}

/// @notice Initializes a new `ERC20TokenHolderCaster` clone.
/// @notice Initializes a new `ERC20TokenholderCaster` clone.
/// @dev This function is called by the `deployTokenVotingModule` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _token The ERC20 token to be used for voting.
Expand All @@ -33,7 +33,7 @@ contract ERC20TokenHolderCaster is TokenHolderCaster {
uint256 _minApprovalPct,
uint256 _minDisapprovalPct
) external initializer {
__initializeTokenHolderCasterMinimalProxy(_llamaCore, _role, _minApprovalPct, _minDisapprovalPct);
__initializeTokenholderCasterMinimalProxy(_llamaCore, _role, _minApprovalPct, _minDisapprovalPct);
token = _token;
uint256 totalSupply = token.totalSupply();
if (totalSupply == 0) revert InvalidTokenAddress();
Expand Down
12 changes: 8 additions & 4 deletions src/token-voting/ERC721TokenholderActionCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {IERC721} from "@openzeppelin/token/ERC721/IERC721.sol";
/// @author Llama ([email protected])
/// @notice This contract lets holders of a given governance ERC721Votes token create actions on the llama instance if
/// they hold enough tokens.
contract ERC721TokenHolderActionCreator is TokenHolderActionCreator {
contract ERC721TokenholderActionCreator is TokenholderActionCreator {
ERC721Votes public token;

/// @dev This contract is deployed as a minimal proxy from the factory's `deployTokenVotingModule` function. The
Expand All @@ -19,16 +19,20 @@ contract ERC721TokenHolderActionCreator is TokenHolderActionCreator {
_disableInitializers();
}

/// @notice Initializes a new `ERC721TokenHolderActionCreator` clone.
/// @notice Initializes a new `ERC721TokenholderActionCreator` clone.
/// @dev This function is called by the `deployTokenVotingModule` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _token The ERC721 token to be used for voting.
/// @param _llamaCore The `LlamaCore` contract for this Llama instance.
/// @param _role The role used by this contract to cast approvals and disapprovals.
/// @param _creationThreshold The default number of tokens required to create an action. This must
/// be in the same decimals as the token. For example, if the token has 18 decimals and you want a
/// creation threshold of 1000 tokens, pass in 1000e18.
function initialize(ERC721Votes _token, ILlamaCore _llamaCore, uint256 _creationThreshold) external initializer {
__initializeTokenHolderActionCreatorMinimalProxy(_llamaCore, _creationThreshold);
function initialize(ERC721Votes _token, ILlamaCore _llamaCore, uint8 _role, uint256 _creationThreshold)
external
initializer
{
__initializeTokenholderActionCreatorMinimalProxy(_llamaCore, _role, _creationThreshold);
token = _token;
if (!token.supportsInterface(type(IERC721).interfaceId)) revert InvalidTokenAddress();
uint256 totalSupply = token.getPastTotalSupply(block.timestamp - 1);
Expand Down
21 changes: 9 additions & 12 deletions src/token-voting/ERC721TokenholderCaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {IERC721} from "@openzeppelin/token/ERC721/IERC721.sol";
/// @author Llama ([email protected])
/// @notice This contract lets holders of a given governance ERC721Votes token cast approvals and disapprovals
/// on created actions.
contract ERC721TokenHolderCaster is TokenHolderCaster {
contract ERC721TokenholderCaster is TokenholderCaster {
ERC721Votes public token;

/// @dev This contract is deployed as a minimal proxy from the factory's `deployTokenVotingModule` function. The
Expand All @@ -19,22 +19,19 @@ contract ERC721TokenHolderCaster is TokenHolderCaster {
_disableInitializers();
}

/// @notice Initializes a new `ERC721TokenHolderCaster` clone.
/// @notice Initializes a new `ERC721TokenholderCaster` clone.
/// @dev This function is called by the `deployTokenVotingModule` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _token The ERC721 token to be used for voting.
/// @param _llamaCore The `LlamaCore` contract for this Llama instance.
/// @param _role The role used by this contract to cast approvals and disapprovals.
/// @param _minApprovalPct The minimum % of approvals required to submit approvals to `LlamaCore`.
/// @param _minDisapprovalPct The minimum % of disapprovals required to submit disapprovals to `LlamaCore`.
function initialize(
ERC721Votes _token,
ILlamaCore _llamaCore,
uint8 _role,
uint256 _minApprovalPct,
uint256 _minDisapprovalPct
) external initializer {
__initializeTokenHolderCasterMinimalProxy(_llamaCore, _role, _minApprovalPct, _minDisapprovalPct);
/// @param _voteQuorum The minimum % of approvals required to submit approvals to `LlamaCore`.
/// @param _vetoQuorum The minimum % of disapprovals required to submit disapprovals to `LlamaCore`.
function initialize(ERC721Votes _token, ILlamaCore _llamaCore, uint8 _role, uint256 _voteQuorum, uint256 _vetoQuorum)
external
initializer
{
__initializeTokenholderCasterMinimalProxy(_llamaCore, _role, _voteQuorum, _vetoQuorum);
token = _token;
if (!token.supportsInterface(type(IERC721).interfaceId)) revert InvalidTokenAddress();
}
Expand Down
70 changes: 51 additions & 19 deletions src/token-voting/LlamaTokenVotingFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,39 @@ contract LlamaTokenVotingFactory {
ERC721_TOKENHOLDER_CASTER_LOGIC = erc721TokenHolderCasterLogic;
}

/// @notice The ERC20 Tokenholder Action Creator (logic) contract.
ERC20TokenholderActionCreator public immutable ERC20_TOKENHOLDER_ACTION_CREATOR_LOGIC;

/// @notice The ERC20 Tokenholder Caster (logic) contract.
ERC20TokenholderCaster public immutable ERC20_TOKENHOLDER_CASTER_LOGIC;

/// @notice The ERC721 Tokenholder Action Creator (logic) contract.
ERC721TokenholderActionCreator public immutable ERC721_TOKENHOLDER_ACTION_CREATOR_LOGIC;

/// @notice The ERC721 Tokenholder Caster (logic) contract.
ERC721TokenholderCaster public immutable ERC721_TOKENHOLDER_CASTER_LOGIC;

/// @dev Set the logic contracts used to deploy Token Voting modules.
constructor(
ERC20TokenholderActionCreator erc20TokenholderActionCreatorLogic,
ERC20TokenholderCaster erc20TokenholderCasterLogic,
ERC721TokenholderActionCreator erc721TokenholderActionCreatorLogic,
ERC721TokenholderCaster erc721TokenholderCasterLogic
) {
ERC20_TOKENHOLDER_ACTION_CREATOR_LOGIC = erc20TokenholderActionCreatorLogic;
ERC20_TOKENHOLDER_CASTER_LOGIC = erc20TokenholderCasterLogic;
ERC721_TOKENHOLDER_ACTION_CREATOR_LOGIC = erc721TokenholderActionCreatorLogic;
ERC721_TOKENHOLDER_CASTER_LOGIC = erc721TokenholderCasterLogic;
}

///@notice Deploys a token voting module in a single function so it can be deployed in a single llama action.
///@dev This method CAN NOT be used in tandem with `delegateCallDeployTokenVotingModuleWithRoles`. You must use one or
/// the other due to the delegateCallDeployTokenVotingModuleWithRoles 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 actionCreatorRole The role required by the TokenholderActionCreator to create an action.
///@param casterRole The role required by the TokenholderCaster to cast approvals and disapprovals.
///@param creationThreshold The number of tokens required to create an action (set to 0 if not deploying action
/// creator).
///@param voteQuorum The minimum percentage of tokens required to approve an action (set to 0 if not deploying
Expand All @@ -63,47 +90,52 @@ contract LlamaTokenVotingFactory {
ILlamaCore llamaCore,
address token,
bool isERC20,
uint8 actionCreatorRole,
uint8 casterRole,
uint256 creationThreshold,
uint256 voteQuorum,
uint256 vetoQuorum
) external returns (address actionCreator, address caster) {
if (isERC20) {
actionCreator = address(_deployERC20TokenHolderActionCreator(ERC20Votes(token), llamaCore, creationThreshold));
caster = address(_deployERC20TokenHolderCaster(ERC20Votes(token), llamaCore, 0, voteQuorum, vetoQuorum));
actionCreator = address(_deployERC20TokenholderActionCreator(ERC20Votes(token), llamaCore, actionCreatorRole, creationThreshold));
caster = address(_deployERC20TokenholderCaster(ERC20Votes(token), llamaCore, casterRole, voteQuorum, vetoQuorum));
} else {
actionCreator = address(_deployERC721TokenHolderActionCreator(ERC721Votes(token), llamaCore, creationThreshold));
caster = address(_deployERC721TokenHolderCaster(ERC721Votes(token), llamaCore, 0, voteQuorum, vetoQuorum));
}
actionCreator = address(_deployERC721TokenholderActionCreator(ERC721Votes(token), llamaCore, actionCreatorRole, creationThreshold));
caster = address(_deployERC721TokenholderCaster(ERC721Votes(token), llamaCore, casterRole, voteQuorum, vetoQuorum));
}

// ====================================
// ======== Internal Functions ========
// ====================================

function _deployERC20TokenHolderActionCreator(ERC20Votes token, ILlamaCore llamaCore, uint256 creationThreshold)
internal
returns (ERC20TokenHolderActionCreator actionCreator)
{
actionCreator = ERC20TokenHolderActionCreator(
function _deployERC20TokenholderActionCreator(
ERC20Votes token,
ILlamaCore llamaCore,
uint8 role,
uint256 creationThreshold
) internal returns (ERC20TokenholderActionCreator actionCreator) {
actionCreator = ERC20TokenholderActionCreator(
Clones.cloneDeterministic(
address(ERC20_TOKENHOLDER_ACTION_CREATOR_LOGIC), keccak256(abi.encodePacked(address(token), msg.sender))
)
);
actionCreator.initialize(token, llamaCore, creationThreshold);
emit ERC20TokenHolderActionCreatorCreated(address(actionCreator), address(token));
actionCreator.initialize(token, llamaCore, role, creationThreshold);
emit ERC20TokenholderActionCreatorCreated(address(actionCreator), address(token));
}

function _deployERC721TokenHolderActionCreator(ERC721Votes token, ILlamaCore llamaCore, uint256 creationThreshold)
internal
returns (ERC721TokenHolderActionCreator actionCreator)
{
actionCreator = ERC721TokenHolderActionCreator(
function _deployERC721TokenholderActionCreator(
ERC721Votes token,
ILlamaCore llamaCore,
uint8 role,
uint256 creationThreshold
) internal returns (ERC721TokenholderActionCreator actionCreator) {
actionCreator = ERC721TokenholderActionCreator(
Clones.cloneDeterministic(
address(ERC721_TOKENHOLDER_ACTION_CREATOR_LOGIC), keccak256(abi.encodePacked(address(token), msg.sender))
)
);
actionCreator.initialize(token, llamaCore, creationThreshold);
emit ERC721TokenHolderActionCreatorCreated(address(actionCreator), address(token));
actionCreator.initialize(token, llamaCore, role, creationThreshold);
emit ERC721TokenholderActionCreatorCreated(address(actionCreator), address(token));
}

function _deployERC20TokenHolderCaster(
Expand Down
Loading

0 comments on commit cd6962b

Please sign in to comment.