Skip to content

Commit

Permalink
Optimistic plugin creation WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
brickpop committed May 13, 2024
1 parent cf46d1f commit a62d90e
Showing 1 changed file with 50 additions and 10 deletions.
60 changes: 50 additions & 10 deletions src/OptimisticTokenVotingPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import {RATIO_BASE, _applyRatioCeiled, RatioOutOfBounds} from "@aragon/osx/plugi
import {IDAO} from "@aragon/osx/core/dao/IDAO.sol";
import {EssentialContract as TaikoEssentialContract} from "@taikoxyz/taiko-mono/common/EssentialContract.sol";

uint64 constant L2_AGGREGATION_PERIOD = 3 days;

/// @title OptimisticTokenVotingPlugin
/// @author Aragon Association - 2023-2024
/// @notice The abstract implementation of optimistic majority plugins.
Expand Down Expand Up @@ -46,26 +48,28 @@ contract OptimisticTokenVotingPlugin is
/// @param vetoVoters The voters who have vetoed.
/// @param actions The actions to be executed when the proposal passes.
/// @param allowFailureMap A bitmap allowing the proposal to succeed, even if individual actions might revert. If the bit at index `i` is 1, the proposal succeeds even if the `i`th action reverts. A failure map value of 0 requires every action to not revert.
/// @param aggregatedL2Balance The amount of balance that has been registered from the L2.
struct Proposal {
bool executed;
ProposalParameters parameters;
uint256 vetoTally;
mapping(address => bool) vetoVoters;
IDAO.Action[] actions;
uint256 allowFailureMap;
uint256 aggregatedL2Balance;
}

/// @notice A container for the proposal parameters at the time of proposal creation.
/// @param startDate The start date of the proposal vote.
/// @param endDate The end date of the proposal vote.
/// @param snapshotTimestamp The number of the block prior to the proposal creation.
/// @param minVetoVotingPower The minimum voting power needed to defeat the proposal.
/// @param minVetoRatio The minimum veto ratio needed to defeat the proposal, as a fraction of 1_000_000.
/// @param taikoL1PausedOnCreation Whether the Taiko L1 was paused when the proposal was created.
struct ProposalParameters {
uint64 startDate;
uint64 endDate;
uint64 snapshotTimestamp;
uint256 minVetoVotingPower;
uint32 minVetoRatio;
bool taikoL1PausedOnCreation;
}

Expand All @@ -84,13 +88,13 @@ contract OptimisticTokenVotingPlugin is
IVotesUpgradeable public votingToken;

/// @notice The address of the L2 token bridge, to determine the L2 balance bridged to the L2 on proposal creation.
address taikoBridge;
address public taikoBridge;

/// @notice The struct storing the governance settings.
OptimisticGovernanceSettings public governanceSettings;

/// @notice Taiko L1 contract to check for paused() status when a proposal is created.
TaikoEssentialContract taikoL1;
TaikoEssentialContract public taikoL1;

/// @notice A mapping between proposal IDs and proposal information.
mapping(uint256 => Proposal) internal proposals;
Expand Down Expand Up @@ -141,13 +145,18 @@ contract OptimisticTokenVotingPlugin is
/// @param _dao The IDAO interface of the associated DAO.
/// @param _governanceSettings The vetoing settings.
/// @param _token The [ERC-20](https://eips.ethereum.org/EIPS/eip-20) token used for voting.
function initialize(IDAO _dao, OptimisticGovernanceSettings calldata _governanceSettings, IVotesUpgradeable _token)
external
initializer
{
function initialize(
IDAO _dao,
OptimisticGovernanceSettings calldata _governanceSettings,
IVotesUpgradeable _token,
TaikoEssentialContract _taikoL1,
address _taikoBridge
) external initializer {
__PluginUUPSUpgradeable_init(_dao);

votingToken = _token;
taikoL1 = _taikoL1;
taikoBridge = _taikoBridge;

_updateOptimisticGovernanceSettings(_governanceSettings);
emit MembershipContractAnnounced({definingContract: address(_token)});
Expand Down Expand Up @@ -221,6 +230,10 @@ contract OptimisticTokenVotingPlugin is
else if (!_isProposalEnded(proposal_)) {
return false;
}
// Check if L2 bridged vetoes are still possible
else if (_canReceiveL2Vetoes(_proposalId)) {
return false;
}
// Check that not enough voters have vetoed the proposal
else if (isMinVetoRatioReached(_proposalId)) {
return false;
Expand All @@ -232,8 +245,14 @@ contract OptimisticTokenVotingPlugin is
/// @inheritdoc IOptimisticTokenVoting
function isMinVetoRatioReached(uint256 _proposalId) public view virtual returns (bool) {
Proposal storage proposal_ = proposals[_proposalId];
uint256 totalVotingPower_ = totalVotingPower(proposal_.snapshotTimestamp);
if (_isOnlyL1(proposal_)) {
// L2 tokens won't be fully accountable. Subtracting the bridged supply to compute relative to L1 only.
totalVotingPower_ -= votingToken.balanceOf(taikoBridge);
}

return proposal_.vetoTally >= proposal_.parameters.minVetoVotingPower;
uint256 _minVetoPower = _applyRatioCeiled(totalVotingPower_, proposal_.parameters.minVetoRatio);
return proposal_.vetoTally >= _minVetoPower;
}

/// @inheritdoc IOptimisticTokenVoting
Expand Down Expand Up @@ -318,7 +337,7 @@ contract OptimisticTokenVotingPlugin is
proposal_.parameters.startDate = _startDate;
proposal_.parameters.endDate = _endDate;
proposal_.parameters.snapshotTimestamp = snapshotTimestamp.toUint64();
proposal_.parameters.minVetoVotingPower = _applyRatioCeiled(totalVotingPower_, minVetoRatio());
proposal_.parameters.minVetoRatio = minVetoRatio();
proposal_.parameters.taikoL1PausedOnCreation = isTaikoL1Paused;

// Save gas
Expand Down Expand Up @@ -475,6 +494,27 @@ contract OptimisticTokenVotingPlugin is
return currentTime >= proposal_.parameters.endDate;
}

/// @notice Determines whether the proposal is considered L1 only or not
/// @param _proposalId The proposal ID
function _isOnlyL1(Proposal storage proposal_) internal pure returns (bool) {
if (proposal_.parameters.taikoL1PausedOnCreation) {
return true;
} else if (!_canReceiveL2Vetoes(proposal_)) {
return proposal_.aggregatedL2Balance == 0;
}
return false;
}

/// @notice Internal function to check if a proposal may still receive L2 vetoes.
/// @param proposal_ The proposal struct.
/// @return True if the proposal may still receive L2 bridged votes, false otherwise.
function _canReceiveL2Vetoes(Proposal storage proposal_) internal view virtual returns (bool) {
uint64 currentTime = block.timestamp.toUint64();

return currentTime >= proposal_.parameters.startDate
&& currentTime < proposal_.parameters.endDate + L2_AGGREGATION_PERIOD;
}

/// @notice Validates and returns the proposal vote dates.
/// @param _start The start date of the proposal vote. If 0, the current timestamp is used and the vote starts immediately.
/// @param _end The end date of the proposal vote. If 0, `_start + minDuration` is used.
Expand Down

0 comments on commit a62d90e

Please sign in to comment.