Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename Governor OZ to OZ Governor #7

Merged
merged 3 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
10 changes: 5 additions & 5 deletions addresses/Addresses.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,31 +81,31 @@
"addr": "0xF1608e08314B546CA2dDC1E4c247ed2ac753a82b",
"chainId": 11155111,
"isContract": true,
"name": "GOVERNOR_OZ"
"name": "OZ_GOVERNOR"
},
{
"addr": "0xD21a3b1b572F7C38b5e3ff841d1D2903e1B03695",
"chainId": 11155111,
"isContract": true,
"name": "GOVERNOR_OZ_TIMELOCK"
"name": "OZ_GOVERNOR_TIMELOCK"
},
{
"addr": "0xDefA8533981bb799bb2bC42a6078d5fE8327a822",
"chainId": 11155111,
"isContract": true,
"name": "GOVERNOR_OZ_GOVERNANCE_TOKEN"
"name": "OZ_GOVERNOR_GOVERNANCE_TOKEN"
},
{
"addr": "0x6fFA4aDB1df78f0Cc127d9BdA946C9E4eBF07C90",
"chainId": 11155111,
"isContract": true,
"name": "GOVERNOR_OZ_VAULT"
"name": "OZ_GOVERNOR_VAULT"
},
{
"addr": "0x948B7026411CBB9Ef39dB330B31C735b3D06359b",
"chainId": 11155111,
"isContract": true,
"name": "GOVERNOR_OZ_VAULT_TOKEN"
"name": "OZ_GOVERNOR_VAULT_TOKEN"
},
{
"addr": "0xE6841D92B0C345144506576eC13ECf5103aC7f49",
Expand Down
2 changes: 1 addition & 1 deletion lib/forge-proposal-simulator
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this up to date on the latest version?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is currently on the docs branch as the name of GovernorOZProposal has been updated to OZGovernorProposal on FPS. Once docs PR gets merged there I will update this to the main branch. @ElliotFriedman

Submodule forge-proposal-simulator updated 43 files
+1 −1 .github/workflows/ci.yml
+11 −2 .husky/.pre-commit.sh
+3 −2 README.md
+18 −18 addresses/Addresses.json
+11 −23 docs/README.md
+8 −7 docs/SUMMARY.md
+10 −79 docs/actions/print-calldata.md
+1 −21 docs/assets/diagram.svg
+0 −5 docs/fundamentals/compatibility.md
+0 −44 docs/fundamentals/getting-set-up.md
+668 −0 docs/guides/customizing-proposal.md
+258 −160 docs/guides/governor-bravo-proposal.md
+67 −26 docs/guides/introduction.md
+172 −141 docs/guides/multisig-proposal.md
+396 −0 docs/guides/oz-governor-proposal.md
+161 −132 docs/guides/timelock-proposal.md
+202 −0 docs/mainnet-examples/ArbitrumTimelock.md
+136 −0 docs/mainnet-examples/CompoundGovernorBravo.md
+142 −0 docs/mainnet-examples/ENSOzGovernor.md
+145 −0 docs/mainnet-examples/OptimismMultisig.md
+6 −27 docs/overview/architecture/README.md
+22 −22 docs/overview/architecture/addresses.md
+0 −11 docs/overview/architecture/external-functions.md
+0 −24 docs/overview/architecture/internal-functions.md
+459 −0 docs/overview/architecture/proposal-functions.md
+10 −24 docs/overview/use-cases.md
+69 −85 docs/testing/integration-tests.md
+18 −20 docs/type-check/example.md
+20 −25 docs/type-check/introduction.md
+1 −1 docs/type-check/type-check.md
+2 −2 mocks/MockBravoProposal.sol
+0 −1 mocks/MockDuplicatedActionProposal.sol
+4 −3 mocks/MockMultisigProposal.sol
+71 −0 mocks/MockOZGovernorProposal.sol
+5 −7 mocks/MockTimelockProposal.sol
+66 −0 run-proposal.sh
+43 −43 src/proposals/OZGovernorProposal.sol
+0 −2 src/proposals/Proposal.sol
+2 −0 test/BravoProposal.t.sol
+2 −0 test/DuplicatedAction.t.sol
+129 −0 test/GovernorOZProposal.t.sol
+2 −0 test/MultisigProposal.t.sol
+2 −0 test/TimelockProposal.t.sol
48 changes: 24 additions & 24 deletions script/DeployGovernorOz.s.sol → script/DeployOZGovernor.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ import {MultisigProposal} from "@forge-proposal-simulator/src/proposals/Multisig
import {TimelockController} from "@openzeppelin/governance/TimelockController.sol";

import {MockERC20Votes} from "src/mocks/governor-oz/MockERC20Votes.sol";
import {MockGovernorOz} from "src/mocks/governor-oz/MockGovernorOz.sol";
import {MockOZGovernor} from "src/mocks/governor-oz/MockOZGovernor.sol";

/// @notice Governor OZ deployment contract
/// DO_PRINT=false DO_BUILD=false DO_DEPLOY=true DO_VALIDATE=true forge script script/DeployGovernorOZ.s.sol:DeployGovernorOZ --fork-url sepolia -vvvvv
contract DeployGovernorOZ is MultisigProposal {
/// @notice OZ Governor deployment contract
/// DO_PRINT=false DO_BUILD=false DO_DEPLOY=true DO_VALIDATE=true forge script script/DeployOZGovernor.s.sol:DeployOZGovernor --fork-url sepolia -vvvvv
contract DeployOZGovernor is MultisigProposal {
function name() public pure override returns (string memory) {
return "GOVERNOR_OZ_DEPLOY";
return "OZ_GOVERNOR_DEPLOY";
}

function description() public pure override returns (string memory) {
return "Deploy Governor OZ contract";
return "Deploy OZ Governor contract";
}

function deploy() public override {
// Get proposer and executor addresses
address dev = addresses.getAddress("DEPLOYER_EOA");

if (!addresses.isAddressSet("GOVERNOR_OZ_TIMELOCK")) {
if (!addresses.isAddressSet("OZ_GOVERNOR_TIMELOCK")) {
// Create arrays of addresses to pass to the TimelockController constructor
address[] memory proposers = new address[](1);
proposers[0] = dev;
Expand All @@ -33,33 +33,33 @@ contract DeployGovernorOZ is MultisigProposal {
// Deploy a new TimelockController
TimelockController timelock = new TimelockController(60, proposers, executors, dev);

// Add GOVERNOR_OZ_TIMELOCK address
addresses.addAddress("GOVERNOR_OZ_TIMELOCK", address(timelock), true);
// Add OZ_GOVERNOR_TIMELOCK address
addresses.addAddress("OZ_GOVERNOR_TIMELOCK", address(timelock), true);
}

if (!addresses.isAddressSet("GOVERNOR_OZ_GOVERNANCE_TOKEN")) {
if (!addresses.isAddressSet("OZ_GOVERNOR_GOVERNANCE_TOKEN")) {
// Deploy the governance token
MockERC20Votes govToken = new MockERC20Votes("Governance Token", "GOV");

govToken.mint(dev, 1e21);

// Add GOVERNOR_OZ_GOVERNANCE_TOKEN address
addresses.addAddress("GOVERNOR_OZ_GOVERNANCE_TOKEN", address(govToken), true);
// Add OZ_GOVERNOR_GOVERNANCE_TOKEN address
addresses.addAddress("OZ_GOVERNOR_GOVERNANCE_TOKEN", address(govToken), true);
}

if (!addresses.isAddressSet("GOVERNOR_OZ")) {
// Deploy MockGovernorOz
MockGovernorOz governor = new MockGovernorOz(
MockERC20Votes(addresses.getAddress("GOVERNOR_OZ_GOVERNANCE_TOKEN")), // governance token
TimelockController(payable(addresses.getAddress("GOVERNOR_OZ_TIMELOCK"))) // timelock
if (!addresses.isAddressSet("OZ_GOVERNOR")) {
// Deploy MockOZGovernor
MockOZGovernor governor = new MockOZGovernor(
MockERC20Votes(addresses.getAddress("OZ_GOVERNOR_GOVERNANCE_TOKEN")), // governance token
TimelockController(payable(addresses.getAddress("OZ_GOVERNOR_TIMELOCK"))) // timelock
);

// Add GOVERNOR_OZ address
addresses.addAddress("GOVERNOR_OZ", address(governor), true);
// Add OZ_GOVERNOR address
addresses.addAddress("OZ_GOVERNOR", address(governor), true);
}

// add propose and execute role for governor
TimelockController(payable(addresses.getAddress("GOVERNOR_OZ_TIMELOCK"))).grantRole(keccak256("PROPOSER_ROLE"), addresses.getAddress("GOVERNOR_OZ"));
TimelockController(payable(addresses.getAddress("OZ_GOVERNOR_TIMELOCK"))).grantRole(keccak256("PROPOSER_ROLE"), addresses.getAddress("OZ_GOVERNOR"));

addresses.printJSONChanges();
}
Expand All @@ -71,14 +71,14 @@ contract DeployGovernorOZ is MultisigProposal {
}

function validate() public view override {
MockERC20Votes govToken = MockERC20Votes(addresses.getAddress("GOVERNOR_OZ_GOVERNANCE_TOKEN"));
MockERC20Votes govToken = MockERC20Votes(addresses.getAddress("OZ_GOVERNOR_GOVERNANCE_TOKEN"));

// ensure governance token is minted to deployer address
assertEq(govToken.balanceOf(addresses.getAddress("DEPLOYER_EOA")), 1e21);

TimelockController timelock = TimelockController(payable(addresses.getAddress("GOVERNOR_OZ_TIMELOCK")));
TimelockController timelock = TimelockController(payable(addresses.getAddress("OZ_GOVERNOR_TIMELOCK")));

// ensure governor oz has been granted proposer role on timelock
assertTrue(timelock.hasRole(keccak256("PROPOSER_ROLE"), addresses.getAddress("GOVERNOR_OZ")));
// ensure OZ Governor has been granted proposer role on timelock
assertTrue(timelock.hasRole(keccak256("PROPOSER_ROLE"), addresses.getAddress("OZ_GOVERNOR")));
}
}
2 changes: 1 addition & 1 deletion script/DeployTimelock.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ contract DeployTimelock is MultisigProposal {
// Get proposer and executor addresses
address dev = addresses.getAddress("DEPLOYER_EOA");

if (!addresses.isAddressSet("GOVERNOR_OZ_GOVERNANCE_TOKEN")) {
if (!addresses.isAddressSet("OZ_GOVERNOR_GOVERNANCE_TOKEN")) {
// Create arrays of addresses to pass to the TimelockController constructor
address[] memory proposers = new address[](1);
proposers[0] = dev;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {GovernorCountingSimple} from "@openzeppelin/governance/extensions/Govern
import {GovernorVotesQuorumFraction} from "@openzeppelin/governance/extensions/GovernorVotesQuorumFraction.sol";
import {GovernorTimelockControl, TimelockController} from "@openzeppelin/governance/extensions/GovernorTimelockControl.sol";

contract MockGovernorOz is
contract MockOZGovernor is
Governor,
GovernorCountingSimple,
GovernorVotes,
Expand Down
6 changes: 3 additions & 3 deletions src/proposals/arbitrum/ArbitrumProposal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ pragma solidity ^0.8.0;
import {Vm} from "@forge-std/Vm.sol";
import {console} from "@forge-std/console.sol";

import {GovernorOZProposal} from "@forge-proposal-simulator/src/proposals/GovernorOZProposal.sol";
import {OZGovernorProposal} from "@forge-proposal-simulator/src/proposals/OZGovernorProposal.sol";
import {ITimelockController} from "@forge-proposal-simulator/src/interface/ITimelockController.sol";
import {Address} from "@forge-proposal-simulator/utils/Address.sol";

import {MockArbSys} from "src/mocks/arbitrum/MockArbSys.sol";
import {MockArbOutbox} from "src/mocks/arbitrum/MockArbOutbox.sol";

abstract contract ArbitrumProposal is GovernorOZProposal {
abstract contract ArbitrumProposal is OZGovernorProposal {
using Address for address;

/// @notice the target address on L1 Timelock when it's a L2 proposal
Expand Down Expand Up @@ -166,7 +166,7 @@ abstract contract ArbitrumProposal is GovernorOZProposal {
arguments[0] = callData;
}

/// @notice override the GovernorOZProposal simulate function to handle
/// @notice override the OZGovernorProposal simulate function to handle
/// the proposal L1 settlement
function simulate() public override {
// First part of Arbitrum Governance proposal path follows the OZ
Expand Down
6 changes: 3 additions & 3 deletions src/proposals/arbitrum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Based on the Arbitrum governance documentation, the proposal creation process is
## Proposal Creation Examples Using FPS

We have developed an [ArbitrumProposal.sol](./ArbitrumProposal.sol) contract
that extends the FPS GovernorOZProposal to showcase the this tool capabilities. FPS
that extends the FPS OZGovernorProposal to showcase the this tool capabilities. FPS
allows the creation of declarative proposals that undergo not only code review
but also integration tests simulating the entire proposal lifecycle. This
includes L2 submission, L1 settlement, and execution on L1 if is the case, or on
Expand Down Expand Up @@ -73,7 +73,7 @@ L2 if the target is an L2 contract.
- `getProposalActions`: function used to generate the actions for the
proposal. In this case, it generates a single action to call the ArbSys
precompiled contract. This is a utility function that is used by other
functions like `simulate` and GovernorOzProposal `getCalldata`.
functions like `simulate` and OZGovernorProposal `getCalldata`.
- `simulate`: this function is used to simulate the proposal lifecycle from
scheduling to execution. The first part of the simulation follows the standard OZ Governor proposal path by calling `super.simulate()`. FPS leverages Foundry to simulate proposing, voting, queuing on the L2 timelock, and finally executing. Once the proposal is executed by the L2 Timelock, ArbitrumProposal simulates the L1 settlement by calling the L1 Timelock using the Bridge as the sender to schedule the proposal. Finally, the proposal is executed on L1 and if the target is an L2 contract, the calldata is retrievable from the logs and it's executed on L2, which can be either Arbitrum One or Arbitrum Nova.

Expand All @@ -96,7 +96,7 @@ We have developed two examples to illustrate how an Arbitrum proposal can be cre
changes.
- `getCalldata`: function used to generate the calldata for submitting the
proposal. It's not necessary to override this function, as it's already
implemented in the GovernorOzProposal contract.
implemented in the OZGovernorProposal contract.

When running a proposal through the `forge script`, FPS calls all the functions described above in the following order: `deploy`, `build`, `simulate`, `validate`, and `getCalldata` to ensure the proposal is valid and can be submitted to the Governor. The calldata is printed to the console, and the contracts deployed in the `deploy` function can be broadcasted to the network if needed.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {GovernorOZProposal} from "@forge-proposal-simulator/src/proposals/GovernorOZProposal.sol";
import {OZGovernorProposal} from "@forge-proposal-simulator/src/proposals/OZGovernorProposal.sol";
import {Addresses} from "@forge-proposal-simulator/addresses/Addresses.sol";

import {Vault} from "src/mocks/vault/Vault.sol";
import {Token} from "src/mocks/vault/Token.sol";

contract GovernorOZProposal_01 is GovernorOZProposal {
contract OZGovernorProposal_01 is OZGovernorProposal {
function name() public pure override returns (string memory) {
return "GOVERNOR_OZ_PROPOSAL";
return "OZ_GOVERNOR_PROPOSAL";
}

function description() public pure override returns (string memory) {
return "Governor oz proposal mock 1";
return "OZ Governor proposal mock 1";
}

function run() public override {
Expand All @@ -25,23 +25,23 @@ contract GovernorOZProposal_01 is GovernorOZProposal {
)
);

setGovernor(addresses.getAddress("GOVERNOR_OZ"));
setGovernor(addresses.getAddress("OZ_GOVERNOR"));

super.run();
}

function deploy() public override {
address owner = addresses.getAddress("GOVERNOR_OZ_TIMELOCK");
if (!addresses.isAddressSet("GOVERNOR_OZ_VAULT")) {
Vault governorOZVault = new Vault();
address owner = addresses.getAddress("OZ_GOVERNOR_TIMELOCK");
if (!addresses.isAddressSet("OZ_GOVERNOR_VAULT")) {
Vault OZGovernorVault = new Vault();

addresses.addAddress("GOVERNOR_OZ_VAULT", address(governorOZVault), true);
governorOZVault.transferOwnership(owner);
addresses.addAddress("OZ_GOVERNOR_VAULT", address(OZGovernorVault), true);
OZGovernorVault.transferOwnership(owner);
}

if (!addresses.isAddressSet("GOVERNOR_OZ_VAULT_TOKEN")) {
if (!addresses.isAddressSet("OZ_GOVERNOR_VAULT_TOKEN")) {
Token token = new Token();
addresses.addAddress("GOVERNOR_OZ_VAULT_TOKEN", address(token), true);
addresses.addAddress("OZ_GOVERNOR_VAULT_TOKEN", address(token), true);
token.transferOwnership(owner);

// During forge script execution, the deployer of the contracts is
Expand All @@ -57,44 +57,44 @@ contract GovernorOZProposal_01 is GovernorOZProposal {
function build()
public
override
buildModifier(addresses.getAddress("GOVERNOR_OZ_TIMELOCK"))
buildModifier(addresses.getAddress("OZ_GOVERNOR_TIMELOCK"))
{
/// STATICCALL -- not recorded for the run stage
address governorOZVault = addresses.getAddress("GOVERNOR_OZ_VAULT");
address token = addresses.getAddress("GOVERNOR_OZ_VAULT_TOKEN");
address OZGovernorVault = addresses.getAddress("OZ_GOVERNOR_VAULT");
address token = addresses.getAddress("OZ_GOVERNOR_VAULT_TOKEN");
uint256 balance = Token(token).balanceOf(
addresses.getAddress("GOVERNOR_OZ_TIMELOCK")
addresses.getAddress("OZ_GOVERNOR_TIMELOCK")
);

/// CALLS -- mutative and recorded
Vault(governorOZVault).whitelistToken(token, true);
Token(token).approve(governorOZVault, balance);
Vault(governorOZVault).deposit(token, balance);
Vault(OZGovernorVault).whitelistToken(token, true);
Token(token).approve(OZGovernorVault, balance);
Vault(OZGovernorVault).deposit(token, balance);
}

function validate() public view override {
Vault governorOZVault = Vault(addresses.getAddress("GOVERNOR_OZ_VAULT"));
Token token = Token(addresses.getAddress("GOVERNOR_OZ_VAULT_TOKEN"));
Vault OZGovernorVault = Vault(addresses.getAddress("OZ_GOVERNOR_VAULT"));
Token token = Token(addresses.getAddress("OZ_GOVERNOR_VAULT_TOKEN"));

address timelock = addresses.getAddress("GOVERNOR_OZ_TIMELOCK");
address timelock = addresses.getAddress("OZ_GOVERNOR_TIMELOCK");

uint256 balance = token.balanceOf(address(governorOZVault));
(uint256 amount, ) = governorOZVault.deposits(
uint256 balance = token.balanceOf(address(OZGovernorVault));
(uint256 amount, ) = OZGovernorVault.deposits(
address(token),
address(timelock)
);
assertEq(amount, balance);

assertTrue(governorOZVault.tokenWhitelist(address(token)));
assertTrue(OZGovernorVault.tokenWhitelist(address(token)));

assertEq(token.balanceOf(address(governorOZVault)), token.totalSupply());
assertEq(token.balanceOf(address(OZGovernorVault)), token.totalSupply());

assertEq(token.totalSupply(), 10_000_000e18);

assertEq(token.owner(), address(timelock));

assertEq(governorOZVault.owner(), address(timelock));
assertEq(OZGovernorVault.owner(), address(timelock));

assertFalse(governorOZVault.paused());
assertFalse(OZGovernorVault.paused());
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity ^0.8.0;

import {GovernorOZProposal} from "@forge-proposal-simulator/src/proposals/GovernorOZProposal.sol";
import {OZGovernorProposal} from "@forge-proposal-simulator/src/proposals/OZGovernorProposal.sol";
import {Addresses} from "@forge-proposal-simulator/addresses/Addresses.sol";

import {Vault} from "src/mocks/vault/Vault.sol";
import {Token} from "src/mocks/vault/Token.sol";

contract GovernorOZProposal_02 is GovernorOZProposal {
contract OZGovernorProposal_02 is OZGovernorProposal {
function name() public pure override returns (string memory) {
return "GOVERNOR_OZ_PROPOSAL_02";
return "OZ_GOVERNOR_PROPOSAL_02";
}

function description() public pure override returns (string memory) {
return "Governor oz proposal mock 2";
return "OZ Governor proposal mock 2";
}

function run() public override {
Expand All @@ -25,36 +25,36 @@ contract GovernorOZProposal_02 is GovernorOZProposal {
)
);

setGovernor(addresses.getAddress("GOVERNOR_OZ"));
setGovernor(addresses.getAddress("OZ_GOVERNOR"));

super.run();
}

function build()
public
override
buildModifier(addresses.getAddress("GOVERNOR_OZ_TIMELOCK"))
buildModifier(addresses.getAddress("OZ_GOVERNOR_TIMELOCK"))
{
/// STATICCALL -- not recorded for the run stage
address timelock = addresses.getAddress("GOVERNOR_OZ_TIMELOCK");
Vault governorOZVault = Vault(addresses.getAddress("GOVERNOR_OZ_VAULT"));
address token = addresses.getAddress("GOVERNOR_OZ_VAULT_TOKEN");
(uint256 amount, ) = governorOZVault.deposits(address(token), timelock);
address timelock = addresses.getAddress("OZ_GOVERNOR_TIMELOCK");
Vault OZGovernorVault = Vault(addresses.getAddress("OZ_GOVERNOR_VAULT"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

naming: OZGovernorVault -> ozGovernorVault

address token = addresses.getAddress("OZ_GOVERNOR_VAULT_TOKEN");
(uint256 amount, ) = OZGovernorVault.deposits(address(token), timelock);

/// CALLS -- mutative and recorded
governorOZVault.withdraw(token, payable(timelock), amount);
OZGovernorVault.withdraw(token, payable(timelock), amount);
}

function validate() public view override {
Vault governorOZVault = Vault(addresses.getAddress("GOVERNOR_OZ_VAULT"));
Token token = Token(addresses.getAddress("GOVERNOR_OZ_VAULT_TOKEN"));
Vault OZGovernorVault = Vault(addresses.getAddress("OZ_GOVERNOR_VAULT"));
Token token = Token(addresses.getAddress("OZ_GOVERNOR_VAULT_TOKEN"));

address timelock = addresses.getAddress("GOVERNOR_OZ_TIMELOCK");
address timelock = addresses.getAddress("OZ_GOVERNOR_TIMELOCK");

uint256 balance = token.balanceOf(address(governorOZVault));
uint256 balance = token.balanceOf(address(OZGovernorVault));
assertEq(balance, 0);

(uint256 amount, ) = governorOZVault.deposits(
(uint256 amount, ) = OZGovernorVault.deposits(
address(token),
address(timelock)
);
Expand Down
Loading
Loading