Skip to content

Commit

Permalink
using underlying token total supply
Browse files Browse the repository at this point in the history
  • Loading branch information
hujw77 committed Aug 7, 2024
1 parent 65c8274 commit c395b49
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 20 deletions.
76 changes: 59 additions & 17 deletions src/plugins/optimistic-token-voting/OptimisticTokenVotingPlugin.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

pragma solidity 0.8.17;

import {
IERC5805Upgradeable,
IVotesUpgradeable
} from "@openzeppelin/contracts-upgradeable/interfaces/IERC5805Upgradeable.sol";
import {IERC6372Upgradeable} from "@openzeppelin/contracts-upgradeable/interfaces/IERC6372Upgradeable.sol";
import {ERC165Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol";
import {IERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/IERC20Upgradeable.sol";
import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {SafeCastUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/math/SafeCastUpgradeable.sol";
import {IVotesUpgradeable} from "@openzeppelin/contracts-upgradeable/governance/utils/IVotesUpgradeable.sol";
import {IMembership} from "@aragon/osx/core/plugin/membership/IMembership.sol";
import {IOptimisticTokenVoting} from "./IOptimisticTokenVoting.sol";

Expand All @@ -24,6 +28,7 @@ import {RATIO_BASE, RatioOutOfBounds} from "@aragon/osx/plugins/utils/Ratio.sol"
contract OptimisticTokenVotingPlugin is
IOptimisticTokenVoting,
IMembership,
IERC6372Upgradeable,
Initializable,
ERC165Upgradeable,
PluginUUPSUpgradeable,
Expand Down Expand Up @@ -61,11 +66,13 @@ contract OptimisticTokenVotingPlugin is
/// @param startDate The start date of the proposal vote.
/// @param endDate The end date of the proposal vote.
/// @param snapshotBlock The number of the block prior to the proposal creation.
/// @param snapshotTimepoint The timepoint to the proposal creation.
/// @param minVetoVotingPower The minimum voting power needed to defeat the proposal.
struct ProposalParameters {
uint64 startDate;
uint64 endDate;
uint64 snapshotBlock;
uint48 snapshotTimepoint;
uint256 minVetoVotingPower;
}

Expand All @@ -81,14 +88,17 @@ contract OptimisticTokenVotingPlugin is
this.initialize.selector ^ this.getProposal.selector ^ this.updateOptimisticGovernanceSettings.selector;

/// @notice An [OpenZeppelin `Votes`](https://docs.openzeppelin.com/contracts/4.x/api/governance#Votes) compatible contract referencing the token being used for voting.
IVotesUpgradeable private votingToken;
IERC5805Upgradeable private votingToken;

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

/// @notice A mapping between proposal IDs and proposal information.
mapping(uint256 => Proposal) internal proposals;

/// @notice Total supply of underlying token in voting token.
uint256 public underlyingTotalSupply;

/// @notice Emitted when the vetoing settings are updated.
/// @param minVetoRatio The support threshold value.
/// @param minDuration The minimum duration of the proposal vote in seconds.
Expand Down Expand Up @@ -136,13 +146,17 @@ 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,
uint256 _underlyingTotalSupply
) external initializer {
__PluginUUPSUpgradeable_init(_dao);

votingToken = _token;
votingToken = IERC5805Upgradeable(address(_token));

underlyingTotalSupply = _underlyingTotalSupply;

_updateOptimisticGovernanceSettings(_governanceSettings);
emit MembershipContractAnnounced({definingContract: address(_token)});
Expand All @@ -169,8 +183,28 @@ contract OptimisticTokenVotingPlugin is
}

/// @inheritdoc IOptimisticTokenVoting
function totalVotingPower(uint256 _blockNumber) public view returns (uint256) {
return votingToken.getPastTotalSupply(_blockNumber);
function totalVotingPower(uint256) public view returns (uint256) {
return underlyingTotalSupply;
}

/// @dev Clock (as specified in EIP-6372) is set to match the token's clock. Fallback to block numbers if the token
/// does not implement EIP-6372.
function clock() public view virtual override returns (uint48) {
try votingToken.clock() returns (uint48 timepoint) {
return timepoint;
} catch {
return block.number.toUint48();
}
}

/// @dev Machine-readable description of the clock as specified in EIP-6372.
/// solhint-disable-next-line func-name-mixedcase
function CLOCK_MODE() public view virtual override returns (string memory) {
try votingToken.CLOCK_MODE() returns (string memory clockmode) {
return clockmode;
} catch {
return "mode=blocknumber&from=default";
}
}

/// @inheritdoc IMembership
Expand Down Expand Up @@ -199,7 +233,7 @@ contract OptimisticTokenVotingPlugin is
}

// The voter has no voting power.
if (votingToken.getPastVotes(_voter, proposal_.parameters.snapshotBlock) == 0) {
if (votingToken.getPastVotes(_voter, proposal_.parameters.snapshotTimepoint) == 0) {
return false;
}

Expand Down Expand Up @@ -302,12 +336,9 @@ contract OptimisticTokenVotingPlugin is
}
}

uint256 snapshotBlock;
unchecked {
snapshotBlock = block.number - 1; // The snapshot block must be mined already to protect the transaction against backrunning transactions causing census changes.
}
uint48 snapshotTimepoint = clock() - 1; // The snapshot timepoint must be mined already to protect the transaction against backrunning transactions causing census changes.

uint256 totalVotingPower_ = totalVotingPower(snapshotBlock);
uint256 totalVotingPower_ = totalVotingPower(snapshotTimepoint);

if (totalVotingPower_ == 0) {
revert NoVotingPower();
Expand All @@ -329,7 +360,8 @@ contract OptimisticTokenVotingPlugin is

proposal_.parameters.startDate = _startDate;
proposal_.parameters.endDate = _endDate;
proposal_.parameters.snapshotBlock = snapshotBlock.toUint64();
proposal_.parameters.snapshotBlock = (block.number - 1).toUint64();
proposal_.parameters.snapshotTimepoint = snapshotTimepoint;
proposal_.parameters.minVetoVotingPower = _applyRatioCeiled(totalVotingPower_, minVetoRatio());

// Save gas
Expand All @@ -356,7 +388,7 @@ contract OptimisticTokenVotingPlugin is
Proposal storage proposal_ = proposals[_proposalId];

// This could re-enter, though we can assume the governance token is not malicious
uint256 votingPower = votingToken.getPastVotes(_voter, proposal_.parameters.snapshotBlock);
uint256 votingPower = votingToken.getPastVotes(_voter, proposal_.parameters.snapshotTimepoint);

// Not checking if the voter already voted, since canVeto() above already did

Expand All @@ -378,6 +410,16 @@ contract OptimisticTokenVotingPlugin is
_executeProposal(dao(), _proposalId, proposals[_proposalId].actions, proposals[_proposalId].allowFailureMap);
}

/// @notice Updates the total supply of underlying token in voting token.
/// @param _underlyingTotalSupply The new total supply of underlying token in voting token.
function updateUnderlyingTotalSupply(uint256 _underlyingTotalSupply)
external
virtual
auth(UPDATE_OPTIMISTIC_GOVERNANCE_SETTINGS_PERMISSION_ID)
{
underlyingTotalSupply = _underlyingTotalSupply;
}

/// @notice Updates the governance settings.
/// @param _governanceSettings The new governance settings.
function updateOptimisticGovernanceSettings(OptimisticGovernanceSettings calldata _governanceSettings)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {

/// @notice The token settings struct.
/// @param addr The voting token contract address.
/// @param underlyingTotalSupply Total supply of underlying token in voting token.
struct TokenSettings {
address addr;
uint256 underlyingTotalSupply;
}

/// @notice Thrown if token address is passed which is not a token.
Expand Down Expand Up @@ -96,7 +98,8 @@ contract OptimisticTokenVotingPluginSetup is PluginSetup {
plugin = createERC1967Proxy(
address(optimisticTokenVotingPluginBase),
abi.encodeCall(
OptimisticTokenVotingPlugin.initialize, (IDAO(_dao), votingSettings, IVotesUpgradeable(token))
OptimisticTokenVotingPlugin.initialize,
(IDAO(_dao), votingSettings, IVotesUpgradeable(token), tokenSettings.underlyingTotalSupply)
)
);

Expand Down
8 changes: 7 additions & 1 deletion src/plugins/optimistic-token-voting/build-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@
"internalType": "address",
"name": "token",
"type": "address",
"description": "The token address. If this is `address(0)`, a new `GovernanceERC20` token is deployed. If not, the existing token is wrapped as an `GovernanceWrappedERC20`."
"description": "The voting token address."
},
{
"internalType": "uint256",
"name": "underlyingTotalSupply",
"type": "uint256",
"description": "Total supply of underlying token in voting token."
}
],
"internalType": "struct OptimisticTokenVotingPluginSetup.TokenSettings",
Expand Down
7 changes: 6 additions & 1 deletion src/plugins/token-voting/TokenVotingSetup.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@ contract TokenVotingSetup is PluginSetup {

/// @notice The token settings struct.
/// @param addr The voting token contract address.
/// @param underlyingTotalSupply Total supply of underlying token in voting token.
struct TokenSettings {
address addr;
uint256 underlyingTotalSupply;
}

/// @notice Thrown if token address is passed which is not a token.
Expand Down Expand Up @@ -91,7 +93,10 @@ contract TokenVotingSetup is PluginSetup {
// Prepare and deploy plugin proxy.
plugin = createERC1967Proxy(
address(tokenVotingBase),
abi.encodeWithSelector(TokenVoting.initialize.selector, _dao, votingSettings, token)
abi.encodeCall(
TokenVoting.initialize,
(IDAO(_dao), votingSettings, IVotesUpgradeable(token), tokenSettings.underlyingTotalSupply)
)
);

// Prepare permissions
Expand Down
6 changes: 6 additions & 0 deletions src/plugins/token-voting/build-metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
"type": "address",
"description": "The voting token contract address."
},
{
"internalType": "uint256",
"name": "underlyingTotalSupply",
"type": "uint256",
"description": "Total supply of underlying token in voting token."
}
],
"internalType": "struct TokenVotingSetup.TokenSettings",
"name": "tokenSettings",
Expand Down

0 comments on commit c395b49

Please sign in to comment.