Skip to content

Commit

Permalink
Optimistic WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed May 15, 2024
1 parent 1059c68 commit c61a28f
Show file tree
Hide file tree
Showing 9 changed files with 486 additions and 872 deletions.
19 changes: 15 additions & 4 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {PluginSetupProcessor} from "@aragon/osx/framework/plugin/setup/PluginSet
import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";
import {DAO} from "@aragon/osx/core/dao/DAO.sol";
import {createERC1967Proxy} from "@aragon/osx/utils/Proxy.sol";
import {ITaikoEssentialContract} from "../src/interfaces/ITaikoEssentialContract.sol";

contract Deploy is Script {
DAO immutable daoImplementation;
Expand All @@ -32,6 +33,8 @@ contract Deploy is Script {
address immutable tokenAddress;
address[] multisigMembers;

address immutable taikoL1;
address immutable taikoBridge;
uint64 immutable minStdProposalDelay; // Minimum delay of proposals on the optimistic voting plugin
uint16 immutable minStdApprovals;
uint16 immutable minEmergencyApprovals;
Expand All @@ -48,6 +51,8 @@ contract Deploy is Script {
pluginSetupProcessor = PluginSetupProcessor(vm.envAddress("PLUGIN_SETUP_PROCESSOR"));
pluginRepoFactory = vm.envAddress("PLUGIN_REPO_FACTORY");
tokenAddress = vm.envAddress("TOKEN_ADDRESS");
taikoL1 = vm.envAddress("TAIKO_L1_ADDRESS");
taikoBridge = vm.envAddress("TAIKO_BRIDGE_ADDRESS");

minStdProposalDelay = uint64(vm.envUint("MIN_STD_PROPOSAL_DELAY"));
minStdApprovals = uint16(vm.envUint("MIN_STD_APPROVALS"));
Expand Down Expand Up @@ -221,9 +226,8 @@ contract Deploy is Script {
{
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings memory votingSettings = OptimisticTokenVotingPlugin
.OptimisticGovernanceSettings(
200000, // minVetoRatio - 20%
0, // minDuration (the condition will enforce it)
0 // minProposerVotingPower
200_000, // minVetoRatio - 20%
0 // minDuration (the condition will enforce it)
);

OptimisticTokenVotingPluginSetup.TokenSettings memory tokenSettings =
Expand All @@ -233,7 +237,14 @@ contract Deploy is Script {
GovernanceERC20.MintSettings(new address[](0), new uint256[](0));

settingsData = pluginSetup.encodeInstallationParams(
votingSettings, tokenSettings, mintSettings, minStdProposalDelay, stdProposer, emergencyProposer
votingSettings,
tokenSettings,
mintSettings,
ITaikoEssentialContract(taikoL1),
taikoBridge,
minStdProposalDelay,
stdProposer,
emergencyProposer
);
}

Expand Down
2 changes: 1 addition & 1 deletion script/_alternate_deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ contract Deploy is Script {
) public view returns (DAOFactory.PluginSettings[] memory pluginSettings) {
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings
memory votingSettings = OptimisticTokenVotingPlugin
.OptimisticGovernanceSettings(200000, 60 * 60 * 24 * 6, 0);
.OptimisticGovernanceSettings(200000, 60 * 60 * 24 * 6);
OptimisticTokenVotingPluginSetup.TokenSettings
memory tokenSettings = OptimisticTokenVotingPluginSetup
.TokenSettings(tokenAddress, "", "");
Expand Down
2 changes: 1 addition & 1 deletion src/OptimisticTokenVotingPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {ProposalUpgradeable} from "@aragon/osx/core/plugin/proposal/ProposalUpgr
import {PluginUUPSUpgradeable} from "@aragon/osx/core/plugin/PluginUUPSUpgradeable.sol";
import {RATIO_BASE, _applyRatioCeiled, RatioOutOfBounds} from "@aragon/osx/plugins/utils/Ratio.sol";
import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";
import {IEssentialContract as ITaikoEssentialContract} from "./interfaces/ITaikoEssentialContract.sol";
import {ITaikoEssentialContract} from "./interfaces/ITaikoEssentialContract.sol";
// import {EssentialContract as TaikoEssentialContract} from "@taikoxyz/taiko-mono/common/EssentialContract.sol";

uint64 constant L2_AGGREGATION_PERIOD = 3 days;
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/ITaikoEssentialContract.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

interface IEssentialContract {
interface ITaikoEssentialContract {
/// @notice Pauses the contract.
function pause() external;

Expand Down
126 changes: 50 additions & 76 deletions src/setup/OptimisticTokenVotingPluginSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {GovernanceWrappedERC20} from "@aragon/osx/token/ERC20/governance/Governa
import {IGovernanceWrappedERC20} from "@aragon/osx/token/ERC20/governance/IGovernanceWrappedERC20.sol";
import {OptimisticTokenVotingPlugin} from "../OptimisticTokenVotingPlugin.sol";
import {StandardProposalCondition} from "../conditions/StandardProposalCondition.sol";
import {ITaikoEssentialContract} from "../interfaces/ITaikoEssentialContract.sol";
// import {EssentialContract as TaikoEssentialContract} from "@taikoxyz/taiko-mono/common/EssentialContract.sol";

/// @title OptimisticTokenVotingPluginSetup
/// @author Aragon Association - 2022-2023
Expand All @@ -28,8 +30,7 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
using ERC165Checker for address;

/// @notice The address of the `OptimisticTokenVotingPlugin` base contract.
OptimisticTokenVotingPlugin
private immutable optimisticTokenVotingPluginBase;
OptimisticTokenVotingPlugin private immutable optimisticTokenVotingPluginBase;

/// @notice The address of the `GovernanceERC20` base contract.
address public immutable governanceERC20Base;
Expand Down Expand Up @@ -62,31 +63,26 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
/// @notice The contract constructor deploying the plugin implementation contract and receiving the governance token base contracts to clone from.
/// @param _governanceERC20Base The base `GovernanceERC20` contract to create clones from.
/// @param _governanceWrappedERC20Base The base `GovernanceWrappedERC20` contract to create clones from.
constructor(
GovernanceERC20 _governanceERC20Base,
GovernanceWrappedERC20 _governanceWrappedERC20Base
) {
constructor(GovernanceERC20 _governanceERC20Base, GovernanceWrappedERC20 _governanceWrappedERC20Base) {
optimisticTokenVotingPluginBase = new OptimisticTokenVotingPlugin();
governanceERC20Base = address(_governanceERC20Base);
governanceWrappedERC20Base = address(_governanceWrappedERC20Base);
}

/// @inheritdoc IPluginSetup
function prepareInstallation(
address _dao,
bytes calldata _installParameters
)
function prepareInstallation(address _dao, bytes calldata _installParameters)
external
returns (address plugin, PreparedSetupData memory preparedSetupData)
{
// Decode `_installParameters` to extract the params needed for deploying and initializing `OptimisticTokenVoting` plugin,
// and the required helpers
(
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings
memory votingSettings,
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings memory votingSettings,
TokenSettings memory tokenSettings,
// only used for GovernanceERC20 (when token is not passed)
GovernanceERC20.MintSettings memory mintSettings,
ITaikoEssentialContract _taikoL1,
address _taikoBridge,
uint64 stdProposalMinDelay,
address stdProposer,
address emergencyProposer
Expand All @@ -113,30 +109,23 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
// If token supports none of them
// it's simply ERC20 which gets checked by _isERC20
// Currently, not a satisfiable check.
(!supportedIds[0] && !supportedIds[1] && !supportedIds[2]) ||
(!supportedIds[0] && !supportedIds[1] && !supportedIds[2])
// If token supports IERC20, but neither
// IVotes nor IGovernanceWrappedERC20, it needs wrapping.
(supportedIds[0] && !supportedIds[1] && !supportedIds[2])
|| (supportedIds[0] && !supportedIds[1] && !supportedIds[2])
) {
token = governanceWrappedERC20Base.clone();
// User already has a token. We need to wrap it in
// GovernanceWrappedERC20 in order to make the token
// include governance functionality.
GovernanceWrappedERC20(token).initialize(
IERC20Upgradeable(tokenSettings.addr),
tokenSettings.name,
tokenSettings.symbol
IERC20Upgradeable(tokenSettings.addr), tokenSettings.name, tokenSettings.symbol
);
}
} else {
// Clone a `GovernanceERC20`.
token = governanceERC20Base.clone();
GovernanceERC20(token).initialize(
IDAO(_dao),
tokenSettings.name,
tokenSettings.symbol,
mintSettings
);
GovernanceERC20(token).initialize(IDAO(_dao), tokenSettings.name, tokenSettings.symbol, mintSettings);
}

helpers[0] = token;
Expand All @@ -146,15 +135,13 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
address(optimisticTokenVotingPluginBase),
abi.encodeCall(
OptimisticTokenVotingPlugin.initialize,
(IDAO(_dao), votingSettings, IVotesUpgradeable(token))
(IDAO(_dao), votingSettings, IVotesUpgradeable(token), _taikoL1, _taikoBridge)
)
);

// Prepare permissions
PermissionLib.MultiTargetPermission[]
memory permissions = new PermissionLib.MultiTargetPermission[](
tokenSettings.addr != address(0) ? 5 : 6
);
PermissionLib.MultiTargetPermission[] memory permissions =
new PermissionLib.MultiTargetPermission[](tokenSettings.addr != address(0) ? 5 : 6);

// Request the permissions to be granted

Expand All @@ -164,8 +151,7 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
where: plugin,
who: _dao,
condition: PermissionLib.NO_CONDITION,
permissionId: optimisticTokenVotingPluginBase
.UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID()
});

// The DAO can upgrade the plugin implementation
Expand All @@ -174,8 +160,7 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
where: plugin,
who: _dao,
condition: PermissionLib.NO_CONDITION,
permissionId: optimisticTokenVotingPluginBase
.UPGRADE_PLUGIN_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.UPGRADE_PLUGIN_PERMISSION_ID()
});

// The plugin can make the DAO execute actions
Expand All @@ -188,28 +173,24 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
});
{
// Deploy the Std proposal condition
StandardProposalCondition stdProposalCondition = new StandardProposalCondition(
address(_dao),
stdProposalMinDelay
);
StandardProposalCondition stdProposalCondition =
new StandardProposalCondition(address(_dao), stdProposalMinDelay);

// Proposer plugins can create proposals
permissions[3] = PermissionLib.MultiTargetPermission({
operation: PermissionLib.Operation.Grant,
where: plugin,
who: stdProposer,
condition: address(stdProposalCondition),
permissionId: optimisticTokenVotingPluginBase
.PROPOSER_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.PROPOSER_PERMISSION_ID()
});
}
permissions[4] = PermissionLib.MultiTargetPermission({
operation: PermissionLib.Operation.Grant,
where: plugin,
who: emergencyProposer,
condition: PermissionLib.NO_CONDITION,
permissionId: optimisticTokenVotingPluginBase
.PROPOSER_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.PROPOSER_PERMISSION_ID()
});

if (tokenSettings.addr == address(0x0)) {
Expand All @@ -228,10 +209,7 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
}

/// @inheritdoc IPluginSetup
function prepareUninstallation(
address _dao,
SetupPayload calldata _payload
)
function prepareUninstallation(address _dao, SetupPayload calldata _payload)
external
view
returns (PermissionLib.MultiTargetPermission[] memory permissions)
Expand All @@ -248,31 +226,25 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {

bool[] memory supportedIds = _getTokenInterfaceIds(token);

bool isGovernanceERC20 = supportedIds[0] &&
supportedIds[1] &&
!supportedIds[2];
bool isGovernanceERC20 = supportedIds[0] && supportedIds[1] && !supportedIds[2];

permissions = new PermissionLib.MultiTargetPermission[](
isGovernanceERC20 ? 4 : 3
);
permissions = new PermissionLib.MultiTargetPermission[](isGovernanceERC20 ? 4 : 3);

// Set permissions to be Revoked.
permissions[0] = PermissionLib.MultiTargetPermission({
operation: PermissionLib.Operation.Revoke,
where: _payload.plugin,
who: _dao,
condition: PermissionLib.NO_CONDITION,
permissionId: optimisticTokenVotingPluginBase
.UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID()
});

permissions[1] = PermissionLib.MultiTargetPermission({
operation: PermissionLib.Operation.Revoke,
where: _payload.plugin,
who: _dao,
condition: PermissionLib.NO_CONDITION,
permissionId: optimisticTokenVotingPluginBase
.UPGRADE_PLUGIN_PERMISSION_ID()
permissionId: optimisticTokenVotingPluginBase.UPGRADE_PLUGIN_PERMISSION_ID()
});

permissions[2] = PermissionLib.MultiTargetPermission({
Expand Down Expand Up @@ -306,38 +278,39 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {

/// @notice Encodes the given installation parameters into a byte array
function encodeInstallationParams(
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings
calldata _votingSettings,
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings calldata _votingSettings,
TokenSettings calldata _tokenSettings,
// only used for GovernanceERC20 (when a token is not passed)
GovernanceERC20.MintSettings calldata _mintSettings,
ITaikoEssentialContract _taikoL1,
address _taikoBridge,
uint64 _stdProposalMinDelay,
address _stdProposer,
address _emergencyProposer
) external pure returns (bytes memory) {
return
abi.encode(
_votingSettings,
_tokenSettings,
_mintSettings,
_stdProposalMinDelay,
_stdProposer,
_emergencyProposer
);
return abi.encode(
_votingSettings,
_tokenSettings,
_mintSettings,
_taikoL1,
_taikoBridge,
_stdProposalMinDelay,
_stdProposer,
_emergencyProposer
);
}

/// @notice Decodes the given byte array into the original installation parameters
function decodeInstallationParams(
bytes memory _data
)
function decodeInstallationParams(bytes memory _data)
public
pure
returns (
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings
memory votingSettings,
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings memory votingSettings,
TokenSettings memory tokenSettings,
// only used for GovernanceERC20 (when token is not passed)
GovernanceERC20.MintSettings memory mintSettings,
ITaikoEssentialContract _taikoL1,
address _taikoBridge,
uint64 _stdProposalMinDelay,
address _stdProposer,
address _emergencyProposer
Expand All @@ -347,6 +320,8 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
votingSettings,
tokenSettings,
mintSettings,
_taikoL1,
_taikoBridge,
_stdProposalMinDelay,
_stdProposer,
_emergencyProposer
Expand All @@ -356,6 +331,8 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
OptimisticTokenVotingPlugin.OptimisticGovernanceSettings,
TokenSettings,
GovernanceERC20.MintSettings,
ITaikoEssentialContract,
address,
uint64,
address,
address
Expand All @@ -366,9 +343,7 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
/// @notice Retrieves the interface identifiers supported by the token contract.
/// @dev It is crucial to verify if the provided token address represents a valid contract before using the below.
/// @param token The token address
function _getTokenInterfaceIds(
address token
) private view returns (bool[] memory) {
function _getTokenInterfaceIds(address token) private view returns (bool[] memory) {
bytes4[] memory interfaceIds = new bytes4[](3);
interfaceIds[0] = type(IERC20Upgradeable).interfaceId;
interfaceIds[1] = type(IVotesUpgradeable).interfaceId;
Expand All @@ -380,9 +355,8 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
/// @dev It's important to first check whether token is a contract prior to this call.
/// @param token The token address
function _isERC20(address token) private view returns (bool) {
(bool success, bytes memory data) = token.staticcall(
abi.encodeCall(IERC20Upgradeable.balanceOf, (address(this)))
);
(bool success, bytes memory data) =
token.staticcall(abi.encodeCall(IERC20Upgradeable.balanceOf, (address(this))));
return success && data.length == 0x20;
}
}
Loading

0 comments on commit c61a28f

Please sign in to comment.