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

chore: add script to deploy token voting modules #74

Merged
merged 8 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,14 @@ run-script script_name flags='' sig='' args='':
-vvvv {{flags}}
mv _test test

run-deploy-voting-module-script flags: (run-script 'DeployLlamaTokenVotingModule' flags '--sig "run(address,string)"' '$SCRIPT_DEPLOYER_ADDRESS "tokenVotingModuleConfig.json"')

dry-run-deploy: (run-script 'DeployLlamaTokenVotingFactory')

deploy: (run-script 'DeployLlamaTokenVotingFactory' '--broadcast --verify --build-info --build-info-path build_info')

dry-run-deploy-voting-module: (run-deploy-voting-module-script '')

deploy-voting-module: (run-deploy-voting-module-script '--broadcast --verify')

verify: (run-script 'DeployLlamaTokenVotingFactory' '--verify --resume')
52 changes: 52 additions & 0 deletions script/DeployLlamaTokenVotingModule.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {Script, stdJson} from "forge-std/Script.sol";

import {DeployUtils} from "script/DeployUtils.sol";

import {ILlamaCore} from "src/interfaces/ILlamaCore.sol";
import {CasterConfig, LlamaTokenVotingConfig} from "src/lib/Structs.sol";
import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol";
import {LlamaTokenActionCreator} from "src/token-voting/LlamaTokenActionCreator.sol";
import {LlamaTokenCaster} from "src/token-voting/LlamaTokenCaster.sol";
import {LlamaTokenVotingFactory} from "src/token-voting/LlamaTokenVotingFactory.sol";
import {DeployUtils} from "script/DeployUtils.sol";

contract DeployLlamaTokenVotingModule is Script {
using stdJson for string;

function run(address deployer, string memory configFile) public {
string memory jsonInput = DeployUtils.readScriptInput(configFile);

LlamaTokenVotingFactory factory = LlamaTokenVotingFactory(jsonInput.readAddress(".factory"));

DeployUtils.print(string.concat("Deploying Llama token voting module to chain:", vm.toString(block.chainid)));

CasterConfig memory casterConfig = CasterConfig(
abi.decode(jsonInput.parseRaw(".casterConfig.voteQuorumPct"), (uint16)),
abi.decode(jsonInput.parseRaw(".casterConfig.vetoQuorumPct"), (uint16)),
abi.decode(jsonInput.parseRaw(".casterConfig.delayPeriodPct"), (uint16)),
abi.decode(jsonInput.parseRaw(".casterConfig.castingPeriodPct"), (uint16)),
abi.decode(jsonInput.parseRaw(".casterConfig.submissionPeriodPct"), (uint16))
);

LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
ILlamaCore(jsonInput.readAddress(".llamaCore")),
ILlamaTokenAdapter(jsonInput.readAddress(".tokenAdapterLogic")),
DeployUtils.readTokenAdapter(jsonInput),
abi.decode(jsonInput.parseRaw(".nonce"), (uint256)),
abi.decode(jsonInput.parseRaw(".actionCreatorRole"), (uint8)),
abi.decode(jsonInput.parseRaw(".casterRole"), (uint8)),
abi.decode(jsonInput.parseRaw(".creationThreshold"), (uint256)),
casterConfig
);

vm.broadcast(deployer);
(LlamaTokenActionCreator actionCreator, LlamaTokenCaster caster) = factory.deploy(config);

DeployUtils.print("Successfully deployed a new Llama token voting module");
DeployUtils.print(string.concat(" LlamaTokenActionCreator: ", vm.toString(address(actionCreator))));
DeployUtils.print(string.concat(" LlamaTokenCaster: ", vm.toString(address(caster))));
}
}
21 changes: 20 additions & 1 deletion script/DeployUtils.sol
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.23;

import {console2} from "forge-std/Script.sol";
import {VmSafe} from "forge-std/Vm.sol";
import {console2, stdJson} from "forge-std/Script.sol";

import {LlamaTokenAdapterVotesTimestamp} from "src/token-voting/token-adapters/LlamaTokenAdapterVotesTimestamp.sol";

library DeployUtils {
using stdJson for string;

address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
VmSafe internal constant VM = VmSafe(VM_ADDRESS);

function readScriptInput(string memory filename) internal view returns (string memory) {
string memory inputDir = string.concat(VM.projectRoot(), "/script/input/");
string memory chainDir = string.concat(VM.toString(block.chainid), "/");
return VM.readFile(string.concat(inputDir, chainDir, filename));
}

function print(string memory message) internal view {
// Avoid getting flooded with logs during tests. Note that fork tests will show logs with this
// approach, because there's currently no way to tell which environment we're in, e.g. script
// or test. This is being tracked in https://github.com/foundry-rs/foundry/issues/2900.
if (block.chainid != 31_337) console2.log(message);
}

function readTokenAdapter(string memory jsonInput) internal pure returns (bytes memory) {
address tokenAddress = jsonInput.readAddress(".tokenAddress");
return abi.encode(LlamaTokenAdapterVotesTimestamp.Config(tokenAddress));
}
}
18 changes: 18 additions & 0 deletions script/input/11155111/tokenVotingModuleConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"comment": "This is an example token voting module deployment on Sepolia.",
"factory": "0x2997f4D6899DC91dE9Ae0FcD98b49CA88b8Fc85e",
"llamaCore": "0xc68046794327490F953EA15522367FFBA0b64f86",
"tokenAdapterLogic": "0x88D63b8c5F8C3e95743F1d26Df8aDd0669614278",
"tokenAddress": "0xf44d44a54440F22e5DC5adb7efA3233645f04007",
"nonce": 0,
"actionCreatorRole": 0,
"casterRole": 0,
"creationThreshold": 10000e18,
"casterConfig": {
"voteQuorumPct": 2000,
"vetoQuorumPct": 1000,
"delayPeriodPct": 2500,
"castingPeriodPct": 5000,
"submissionPeriodPct": 2500
}
}
14 changes: 14 additions & 0 deletions src/lib/Structs.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
pragma solidity ^0.8.23;

import {ILlamaAccount} from "src/interfaces/ILlamaAccount.sol";
import {ILlamaCore} from "src/interfaces/ILlamaCore.sol";
import {ILlamaActionGuard} from "src/interfaces/ILlamaActionGuard.sol";
import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol";
import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol";
import {RoleDescription} from "src/lib/UDVTs.sol";

/// @dev Data required to create an action.
Expand Down Expand Up @@ -34,6 +36,18 @@ struct Action {
uint96 totalDisapprovals; // The total quantity of policyholder disapprovals.
}

/// @dev Configuration of a new Llama token voting module.
struct LlamaTokenVotingConfig {
ILlamaCore llamaCore; // The address of the Llama core.
ILlamaTokenAdapter tokenAdapterLogic; // The logic contract of the token adapter.
bytes adapterConfig; // The configuration of the token adapter.
uint256 nonce; // The nonce to be used in the salt of the deterministic deployment.
uint8 actionCreatorRole; // The role required by the `LlamaTokenActionCreator` to create an action.
uint8 casterRole; // The role required by the `LlamaTokenCaster` to cast approvals and disapprovals.
uint256 creationThreshold; // The number of tokens required to create an action.
CasterConfig casterConfig; // The quorum and period data for the `LlamaTokenCaster`.
}

/// @dev Quorum and period data for token voting caster contracts.
struct CasterConfig {
uint16 voteQuorumPct;
Expand Down
2 changes: 1 addition & 1 deletion src/token-voting/LlamaTokenActionCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ contract LlamaTokenActionCreator is Initializable {
_disableInitializers();
}

/// @notice Initializes a new `LlamaERC20TokenActionCreator` clone.
/// @notice Initializes a new `LlamaTokenActionCreator` clone.
/// @dev This function is called by the `deploy` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _llamaCore The `LlamaCore` contract for this Llama instance.
Expand Down
2 changes: 1 addition & 1 deletion src/token-voting/LlamaTokenCaster.sol
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ contract LlamaTokenCaster is Initializable {
_disableInitializers();
}

/// @notice Initializes a new `LlamaERC20TokenCaster` clone.
/// @notice Initializes a new `LlamaTokenCaster` clone.
/// @dev This function is called by the `deploy` function in the `LlamaTokenVotingFactory` contract.
/// The `initializer` modifier ensures that this function can be invoked at most once.
/// @param _llamaCore The `LlamaCore` contract for this Llama instance.
Expand Down
18 changes: 1 addition & 17 deletions src/token-voting/LlamaTokenVotingFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.23;
import {Clones} from "@openzeppelin/proxy/Clones.sol";

import {ILlamaCore} from "src/interfaces/ILlamaCore.sol";
import {CasterConfig} from "src/lib/Structs.sol";
import {CasterConfig, LlamaTokenVotingConfig} from "src/lib/Structs.sol";
import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol";
import {LlamaTokenActionCreator} from "src/token-voting/LlamaTokenActionCreator.sol";
import {LlamaTokenCaster} from "src/token-voting/LlamaTokenCaster.sol";
Expand All @@ -13,22 +13,6 @@ import {LlamaTokenCaster} from "src/token-voting/LlamaTokenCaster.sol";
/// @author Llama ([email protected])
/// @notice This contract enables Llama instances to deploy a token voting module.
contract LlamaTokenVotingFactory {
// =========================
// ======== Structs ========
// =========================

/// @dev Configuration of a new Llama token voting module.
struct LlamaTokenVotingConfig {
ILlamaCore llamaCore; // The address of the Llama core.
ILlamaTokenAdapter tokenAdapterLogic; // The logic contract of the token adapter.
bytes adapterConfig; // The configuration of the token adapter.
uint256 nonce; // The nonce to be used in the salt of the deterministic deployment.
uint8 actionCreatorRole; // The role required by the `LlamaTokenActionCreator` to create an action.
uint8 casterRole; // The role required by the `LlamaTokenCaster` to cast approvals and disapprovals.
uint256 creationThreshold; // The number of tokens required to create an action.
CasterConfig casterConfig; // The quorum and period data for the `LlamaTokenCaster`.
}

// ========================
// ======== Errors ========
// ========================
Expand Down
3 changes: 2 additions & 1 deletion src/token-voting/interfaces/ILlamaTokenAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ interface ILlamaTokenAdapter {
function clock() external view returns (uint48 timepoint);

/// @notice Reverts if the token's CLOCK_MODE changes from what's in the adapter or if the clock() function doesn't
/// return the correct timepoint based on CLOCK_MODE.
function checkIfInconsistentClock() external view;

/// @notice Converts a timestamp to timepoint units.
Expand All @@ -34,9 +33,11 @@ interface ILlamaTokenAdapter {
/// @notice Get the voting balance of a token holder at a specified past timepoint.
/// @param account The token holder's address.
/// @param timepoint The timepoint at which to get the voting balance.
/// @return The number of votes the account had at timepoint.
function getPastVotes(address account, uint48 timepoint) external view returns (uint256);

/// @notice Get the total supply of a token at a specified past timepoint.
/// @param timepoint The timepoint at which to get the total supply.
/// @return The total supply of the token at timepoint.
function getPastTotalSupply(uint48 timepoint) external view returns (uint256);
}
12 changes: 6 additions & 6 deletions test/token-voting/LlamaTokenVotingFactory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {Clones} from "@openzeppelin/proxy/Clones.sol";

import {LlamaTokenVotingTestSetup} from "test/token-voting/LlamaTokenVotingTestSetup.sol";

import {ActionInfo, CasterConfig} from "src/lib/Structs.sol";
import {ActionInfo, LlamaTokenVotingConfig} from "src/lib/Structs.sol";
import {ILlamaCore} from "src/interfaces/ILlamaCore.sol";
import {ILlamaPolicy} from "src/interfaces/ILlamaPolicy.sol";
import {ILlamaTokenAdapter} from "src/token-voting/interfaces/ILlamaTokenAdapter.sol";
Expand Down Expand Up @@ -82,7 +82,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest {

function test_CanDeployERC20TokenVotingModule() public {
bytes memory adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc20VotesToken)));
LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down Expand Up @@ -159,7 +159,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest {

function test_CanDeployERC721TokenVotingModule() public {
bytes memory adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc721VotesToken)));
LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down Expand Up @@ -285,7 +285,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest {
block.chainid
);

LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down Expand Up @@ -317,7 +317,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest {
/////////////////////

bytes memory adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc20VotesToken)));
LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down Expand Up @@ -380,7 +380,7 @@ contract DeployTokenVotingModule is LlamaTokenVotingFactoryTest {
//////////////////////

adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc20VotesToken)));
config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down
7 changes: 3 additions & 4 deletions test/token-voting/LlamaTokenVotingTestSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import {LlamaPeripheryTestSetup} from "test/LlamaPeripheryTestSetup.sol";

import {DeployLlamaTokenVotingFactory} from "script/DeployLlamaTokenVotingFactory.s.sol";

import {Action, ActionInfo, CasterConfig} from "src/lib/Structs.sol";
import {Action, ActionInfo, CasterConfig, LlamaTokenVotingConfig} from "src/lib/Structs.sol";
import {ILlamaPolicy} from "src/interfaces/ILlamaPolicy.sol";
import {ILlamaRelativeStrategyBase} from "src/interfaces/ILlamaRelativeStrategyBase.sol";
import {ILlamaStrategy} from "src/interfaces/ILlamaStrategy.sol";
import {RoleDescription} from "src/lib/UDVTs.sol";
import {LlamaTokenAdapterVotesTimestamp} from "src/token-voting/token-adapters/LlamaTokenAdapterVotesTimestamp.sol";
import {LlamaTokenVotingFactory} from "src/token-voting/LlamaTokenVotingFactory.sol";
import {LlamaTokenActionCreator} from "src/token-voting/LlamaTokenActionCreator.sol";
import {LlamaTokenCaster} from "src/token-voting/LlamaTokenCaster.sol";

Expand Down Expand Up @@ -109,7 +108,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV

function _deployERC20TokenVotingModuleAndSetRole() internal returns (LlamaTokenActionCreator, LlamaTokenCaster) {
bytes memory adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc20VotesToken)));
LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down Expand Up @@ -138,7 +137,7 @@ contract LlamaTokenVotingTestSetup is LlamaPeripheryTestSetup, DeployLlamaTokenV

function _deployERC721TokenVotingModuleAndSetRole() internal returns (LlamaTokenActionCreator, LlamaTokenCaster) {
bytes memory adapterConfig = abi.encode(LlamaTokenAdapterVotesTimestamp.Config(address(erc721VotesToken)));
LlamaTokenVotingFactory.LlamaTokenVotingConfig memory config = LlamaTokenVotingFactory.LlamaTokenVotingConfig(
LlamaTokenVotingConfig memory config = LlamaTokenVotingConfig(
CORE,
llamaTokenAdapterTimestampLogic,
adapterConfig,
Expand Down
Loading