diff generated with contract downloaded from etherscan at: Wed Sep 21 12:27:08 PM CEST 2022
index 01c891e..a36db1c 100644
--- a/./etherscan/Executor/Executor.sol
+++ b/./src/contracts/Executor.sol
@@ -1,752 +1,134 @@
-// SPDX-License-Identifier: agpl-3.0
-pragma solidity 0.7.5;
-pragma abicoder v2;
+// SPDX-License-Identifier: MIT
+pragma solidity ^0.8.8;
-/**
- * @dev Wrappers over Solidity's arithmetic operations with added overflow
- * checks.
- *
- * Arithmetic operations in Solidity wrap on overflow. This can easily result
- * in bugs, because programmers usually assume that an overflow raises an
- * error, which is the standard behavior in high level programming languages.
- * `SafeMath` restores this intuition by reverting the transaction when an
- * operation overflows.
- *
- * Using this library instead of the unchecked operations eliminates an entire
- * class of bugs, so it's recommended to use it always.
- */
-library SafeMath {
- /**
- * @dev Returns the addition of two unsigned integers, reverting on
- * overflow.
- *
- * Counterpart to Solidity's `+` operator.
- *
- * Requirements:
- * - Addition cannot overflow.
- */
- function add(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a + b;
- require(c >= a, 'SafeMath: addition overflow');
-
- return c;
- }
-
- /**
- * @dev Returns the subtraction of two unsigned integers, reverting on
- * overflow (when the result is negative).
- *
- * Counterpart to Solidity's `-` operator.
- *
- * Requirements:
- * - Subtraction cannot overflow.
- */
- function sub(uint256 a, uint256 b) internal pure returns (uint256) {
- return sub(a, b, 'SafeMath: subtraction overflow');
- }
-
- /**
- * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
- * overflow (when the result is negative).
- *
- * Counterpart to Solidity's `-` operator.
- *
- * Requirements:
- * - Subtraction cannot overflow.
- */
- function sub(
- uint256 a,
- uint256 b,
- string memory errorMessage
- ) internal pure returns (uint256) {
- require(b <= a, errorMessage);
- uint256 c = a - b;
-
- return c;
- }
-
- /**
- * @dev Returns the multiplication of two unsigned integers, reverting on
- * overflow.
- *
- * Counterpart to Solidity's `*` operator.
- *
- * Requirements:
- * - Multiplication cannot overflow.
- */
- function mul(uint256 a, uint256 b) internal pure returns (uint256) {
- // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
- // benefit is lost if 'b' is also tested.
- // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
- if (a == 0) {
- return 0;
- }
-
- uint256 c = a * b;
- require(c / a == b, 'SafeMath: multiplication overflow');
-
- return c;
- }
-
- /**
- * @dev Returns the integer division of two unsigned integers. Reverts on
- * division by zero. The result is rounded towards zero.
- *
- * Counterpart to Solidity's `/` operator. Note: this function uses a
- * `revert` opcode (which leaves remaining gas untouched) while Solidity
- * uses an invalid opcode to revert (consuming all remaining gas).
- *
- * Requirements:
- * - The divisor cannot be zero.
- */
- function div(uint256 a, uint256 b) internal pure returns (uint256) {
- return div(a, b, 'SafeMath: division by zero');
- }
-
- /**
- * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
- * division by zero. The result is rounded towards zero.
- *
- * Counterpart to Solidity's `/` operator. Note: this function uses a
- * `revert` opcode (which leaves remaining gas untouched) while Solidity
- * uses an invalid opcode to revert (consuming all remaining gas).
- *
- * Requirements:
- * - The divisor cannot be zero.
- */
- function div(
- uint256 a,
- uint256 b,
- string memory errorMessage
- ) internal pure returns (uint256) {
- // Solidity only automatically asserts when dividing by 0
- require(b > 0, errorMessage);
- uint256 c = a / b;
- // assert(a == b * c + a % b); // There is no case in which this doesn't hold
-
- return c;
- }
-
- /**
- * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
- * Reverts when dividing by zero.
- *
- * Counterpart to Solidity's `%` operator. This function uses a `revert`
- * opcode (which leaves remaining gas untouched) while Solidity uses an
- * invalid opcode to revert (consuming all remaining gas).
- *
- * Requirements:
- * - The divisor cannot be zero.
- */
- function mod(uint256 a, uint256 b) internal pure returns (uint256) {
- return mod(a, b, 'SafeMath: modulo by zero');
- }
-
- /**
- * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
- * Reverts with custom message when dividing by zero.
- *
- * Counterpart to Solidity's `%` operator. This function uses a `revert`
- * opcode (which leaves remaining gas untouched) while Solidity uses an
- * invalid opcode to revert (consuming all remaining gas).
- *
- * Requirements:
- * - The divisor cannot be zero.
- */
- function mod(
- uint256 a,
- uint256 b,
- string memory errorMessage
- ) internal pure returns (uint256) {
- require(b != 0, errorMessage);
- return a % b;
- }
-}
-
-interface IGovernanceStrategy {
- /**
- * @dev Returns the Proposition Power of a user at a specific block number.
- * @param user Address of the user.
- * @param blockNumber Blocknumber at which to fetch Proposition Power
- * @return Power number
- **/
- function getPropositionPowerAt(address user, uint256 blockNumber) external view returns (uint256);
-
- /**
- * @dev Returns the total supply of Outstanding Proposition Tokens
- * @param blockNumber Blocknumber at which to evaluate
- * @return total supply at blockNumber
- **/
- function getTotalPropositionSupplyAt(uint256 blockNumber) external view returns (uint256);
-
- /**
- * @dev Returns the total supply of Outstanding Voting Tokens
- * @param blockNumber Blocknumber at which to evaluate
- * @return total supply at blockNumber
- **/
- function getTotalVotingSupplyAt(uint256 blockNumber) external view returns (uint256);
-
- /**
- * @dev Returns the Vote Power of a user at a specific block number.
- * @param user Address of the user.
- * @param blockNumber Blocknumber at which to fetch Vote Power
- * @return Vote number
- **/
- function getVotingPowerAt(address user, uint256 blockNumber) external view returns (uint256);
-}
-
-interface IAaveGovernanceV2 {
- enum ProposalState {Pending, Canceled, Active, Failed, Succeeded, Queued, Expired, Executed}
-
- struct Vote {
- bool support;
- uint248 votingPower;
- }
-
- struct Proposal {
- uint256 id;
- address creator;
- IExecutorWithTimelock executor;
- address[] targets;
- uint256[] values;
- string[] signatures;
- bytes[] calldatas;
- bool[] withDelegatecalls;
- uint256 startBlock;
- uint256 endBlock;
- uint256 executionTime;
- uint256 forVotes;
- uint256 againstVotes;
- bool executed;
- bool canceled;
- address strategy;
- bytes32 ipfsHash;
- mapping(address => Vote) votes;
- }
-
- struct ProposalWithoutVotes {
- uint256 id;
- address creator;
- IExecutorWithTimelock executor;
- address[] targets;
- uint256[] values;
- string[] signatures;
- bytes[] calldatas;
- bool[] withDelegatecalls;
- uint256 startBlock;
- uint256 endBlock;
- uint256 executionTime;
- uint256 forVotes;
- uint256 againstVotes;
- bool executed;
- bool canceled;
- address strategy;
- bytes32 ipfsHash;
- }
-
- /**
- * @dev emitted when a new proposal is created
- * @param id Id of the proposal
- * @param creator address of the creator
- * @param executor The ExecutorWithTimelock contract that will execute the proposal
- * @param targets list of contracts called by proposal's associated transactions
- * @param values list of value in wei for each propoposal's associated transaction
- * @param signatures list of function signatures (can be empty) to be used when created the callData
- * @param calldatas list of calldatas: if associated signature empty, calldata ready, else calldata is arguments
- * @param withDelegatecalls boolean, true = transaction delegatecalls the taget, else calls the target
- * @param startBlock block number when vote starts
- * @param endBlock block number when vote ends
- * @param strategy address of the governanceStrategy contract
- * @param ipfsHash IPFS hash of the proposal
- **/
- event ProposalCreated(
- uint256 id,
- address indexed creator,
- IExecutorWithTimelock indexed executor,
- address[] targets,
- uint256[] values,
- string[] signatures,
- bytes[] calldatas,
- bool[] withDelegatecalls,
- uint256 startBlock,
- uint256 endBlock,
- address strategy,
- bytes32 ipfsHash
- );
-
- /**
- * @dev emitted when a proposal is canceled
- * @param id Id of the proposal
- **/
- event ProposalCanceled(uint256 id);
-
- /**
- * @dev emitted when a proposal is queued
- * @param id Id of the proposal
- * @param executionTime time when proposal underlying transactions can be executed
- * @param initiatorQueueing address of the initiator of the queuing transaction
- **/
- event ProposalQueued(uint256 id, uint256 executionTime, address indexed initiatorQueueing);
- /**
- * @dev emitted when a proposal is executed
- * @param id Id of the proposal
- * @param initiatorExecution address of the initiator of the execution transaction
- **/
- event ProposalExecuted(uint256 id, address indexed initiatorExecution);
- /**
- * @dev emitted when a vote is registered
- * @param id Id of the proposal
- * @param voter address of the voter
- * @param support boolean, true = vote for, false = vote against
- * @param votingPower Power of the voter/vote
- **/
- event VoteEmitted(uint256 id, address indexed voter, bool support, uint256 votingPower);
-
- event GovernanceStrategyChanged(address indexed newStrategy, address indexed initiatorChange);
-
- event VotingDelayChanged(uint256 newVotingDelay, address indexed initiatorChange);
-
- event ExecutorAuthorized(address executor);
-
- event ExecutorUnauthorized(address executor);
-
- /**
- * @dev Creates a Proposal (needs Proposition Power of creator > Threshold)
- * @param executor The ExecutorWithTimelock contract that will execute the proposal
- * @param targets list of contracts called by proposal's associated transactions
- * @param values list of value in wei for each propoposal's associated transaction
- * @param signatures list of function signatures (can be empty) to be used when created the callData
- * @param calldatas list of calldatas: if associated signature empty, calldata ready, else calldata is arguments
- * @param withDelegatecalls if true, transaction delegatecalls the taget, else calls the target
- * @param ipfsHash IPFS hash of the proposal
- **/
- function create(
- IExecutorWithTimelock executor,
- address[] memory targets,
- uint256[] memory values,
- string[] memory signatures,
- bytes[] memory calldatas,
- bool[] memory withDelegatecalls,
- bytes32 ipfsHash
- ) external returns (uint256);
-
- /**
- * @dev Cancels a Proposal,
- * either at anytime by guardian
- * or when proposal is Pending/Active and threshold no longer reached
- * @param proposalId id of the proposal
- **/
- function cancel(uint256 proposalId) external;
-
- /**
- * @dev Queue the proposal (If Proposal Succeeded)
- * @param proposalId id of the proposal to queue
- **/
- function queue(uint256 proposalId) external;
-
- /**
- * @dev Execute the proposal (If Proposal Queued)
- * @param proposalId id of the proposal to execute
- **/
- function execute(uint256 proposalId) external payable;
-
- /**
- * @dev Function allowing msg.sender to vote for/against a proposal
- * @param proposalId id of the proposal
- * @param support boolean, true = vote for, false = vote against
- **/
- function submitVote(uint256 proposalId, bool support) external;
-
- /**
- * @dev Function to register the vote of user that has voted offchain via signature
- * @param proposalId id of the proposal
- * @param support boolean, true = vote for, false = vote against
- * @param v v part of the voter signature
- * @param r r part of the voter signature
- * @param s s part of the voter signature
- **/
- function submitVoteBySignature(
- uint256 proposalId,
- bool support,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) external;
-
- /**
- * @dev Set new GovernanceStrategy
- * Note: owner should be a timelocked executor, so needs to make a proposal
- * @param governanceStrategy new Address of the GovernanceStrategy contract
- **/
- function setGovernanceStrategy(address governanceStrategy) external;
-
- /**
- * @dev Set new Voting Delay (delay before a newly created proposal can be voted on)
- * Note: owner should be a timelocked executor, so needs to make a proposal
- * @param votingDelay new voting delay in seconds
- **/
- function setVotingDelay(uint256 votingDelay) external;
-
- /**
- * @dev Add new addresses to the list of authorized executors
- * @param executors list of new addresses to be authorized executors
- **/
- function authorizeExecutors(address[] memory executors) external;
-
- /**
- * @dev Remove addresses to the list of authorized executors
- * @param executors list of addresses to be removed as authorized executors
- **/
- function unauthorizeExecutors(address[] memory executors) external;
-
- /**
- * @dev Let the guardian abdicate from its priviledged rights
- **/
- function __abdicate() external;
-
- /**
- * @dev Getter of the current GovernanceStrategy address
- * @return The address of the current GovernanceStrategy contracts
- **/
- function getGovernanceStrategy() external view returns (address);
-
- /**
- * @dev Getter of the current Voting Delay (delay before a created proposal can be voted on)
- * Different from the voting duration
- * @return The voting delay in seconds
- **/
- function getVotingDelay() external view returns (uint256);
-
- /**
- * @dev Returns whether an address is an authorized executor
- * @param executor address to evaluate as authorized executor
- * @return true if authorized
- **/
- function isExecutorAuthorized(address executor) external view returns (bool);
-
- /**
- * @dev Getter the address of the guardian, that can mainly cancel proposals
- * @return The address of the guardian
- **/
- function getGuardian() external view returns (address);
-
- /**
- * @dev Getter of the proposal count (the current number of proposals ever created)
- * @return the proposal count
- **/
- function getProposalsCount() external view returns (uint256);
-
- /**
- * @dev Getter of a proposal by id
- * @param proposalId id of the proposal to get
- * @return the proposal as ProposalWithoutVotes memory object
- **/
- function getProposalById(uint256 proposalId) external view returns (ProposalWithoutVotes memory);
-
- /**
- * @dev Getter of the Vote of a voter about a proposal
- * Note: Vote is a struct: ({bool support, uint248 votingPower})
- * @param proposalId id of the proposal
- * @param voter address of the voter
- * @return The associated Vote memory object
- **/
- function getVoteOnProposal(uint256 proposalId, address voter) external view returns (Vote memory);
-
- /**
- * @dev Get the current state of a proposal
- * @param proposalId id of the proposal
- * @return The current state if the proposal
- **/
- function getProposalState(uint256 proposalId) external view returns (ProposalState);
-}
-
-
-interface IExecutorWithTimelock {
- /**
- * @dev emitted when a new pending admin is set
- * @param newPendingAdmin address of the new pending admin
- **/
- event NewPendingAdmin(address newPendingAdmin);
-
- /**
- * @dev emitted when a new admin is set
- * @param newAdmin address of the new admin
- **/
- event NewAdmin(address newAdmin);
-
- /**
- * @dev emitted when a new delay (between queueing and execution) is set
- * @param delay new delay
- **/
- event NewDelay(uint256 delay);
-
- /**
- * @dev emitted when a new (trans)action is Queued.
- * @param actionHash hash of the action
- * @param target address of the targeted contract
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- **/
- event QueuedAction(
- bytes32 actionHash,
- address indexed target,
- uint256 value,
- string signature,
- bytes data,
- uint256 executionTime,
- bool withDelegatecall
- );
-
- /**
- * @dev emitted when an action is Cancelled
- * @param actionHash hash of the action
- * @param target address of the targeted contract
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- **/
- event CancelledAction(
- bytes32 actionHash,
- address indexed target,
- uint256 value,
- string signature,
- bytes data,
- uint256 executionTime,
- bool withDelegatecall
- );
-
- /**
- * @dev emitted when an action is Cancelled
- * @param actionHash hash of the action
- * @param target address of the targeted contract
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- * @param resultData the actual callData used on the target
- **/
- event ExecutedAction(
- bytes32 actionHash,
- address indexed target,
- uint256 value,
- string signature,
- bytes data,
- uint256 executionTime,
- bool withDelegatecall,
- bytes resultData
- );
- /**
- * @dev Getter of the current admin address (should be governance)
- * @return The address of the current admin
- **/
- function getAdmin() external view returns (address);
- /**
- * @dev Getter of the current pending admin address
- * @return The address of the pending admin
- **/
- function getPendingAdmin() external view returns (address);
- /**
- * @dev Getter of the delay between queuing and execution
- * @return The delay in seconds
- **/
- function getDelay() external view returns (uint256);
- /**
- * @dev Returns whether an action (via actionHash) is queued
- * @param actionHash hash of the action to be checked
- * keccak256(abi.encode(target, value, signature, data, executionTime, withDelegatecall))
- * @return true if underlying action of actionHash is queued
- **/
- function isActionQueued(bytes32 actionHash) external view returns (bool);
- /**
- * @dev Checks whether a proposal is over its grace period
- * @param governance Governance contract
- * @param proposalId Id of the proposal against which to test
- * @return true of proposal is over grace period
- **/
- function isProposalOverGracePeriod(IAaveGovernanceV2 governance, uint256 proposalId)
- external
- view
- returns (bool);
- /**
- * @dev Getter of grace period constant
- * @return grace period in seconds
- **/
- function GRACE_PERIOD() external view returns (uint256);
- /**
- * @dev Getter of minimum delay constant
- * @return minimum delay in seconds
- **/
- function MINIMUM_DELAY() external view returns (uint256);
- /**
- * @dev Getter of maximum delay constant
- * @return maximum delay in seconds
- **/
- function MAXIMUM_DELAY() external view returns (uint256);
- /**
- * @dev Function, called by Governance, that queue a transaction, returns action hash
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- **/
- function queueTransaction(
- address target,
- uint256 value,
- string memory signature,
- bytes memory data,
- uint256 executionTime,
- bool withDelegatecall
- ) external returns (bytes32);
- /**
- * @dev Function, called by Governance, that cancels a transaction, returns the callData executed
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- **/
- function executeTransaction(
- address target,
- uint256 value,
- string memory signature,
- bytes memory data,
- uint256 executionTime,
- bool withDelegatecall
- ) external payable returns (bytes memory);
- /**
- * @dev Function, called by Governance, that cancels a transaction, returns action hash
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- **/
- function cancelTransaction(
- address target,
- uint256 value,
- string memory signature,
- bytes memory data,
- uint256 executionTime,
- bool withDelegatecall
- ) external returns (bytes32);
-}
+import {IGovernanceStrategy} from './interfaces/IGovernanceStrategy.sol';
+import {IAaveGovernanceV2} from './interfaces/IAaveGovernanceV2.sol';
+import {IExecutor} from './interfaces/IExecutor.sol';
/**
- * @title Time Locked Executor Contract, inherited by Aave Governance Executors
- * @dev Contract that can queue, execute, cancel transactions voted by Governance
- * Queued transactions can be executed after a delay and until
- * Grace period is not over.
- * @author Aave
+ * @title Executor
+ * @author BGD Labs
+ * @notice Time Locked, Validator, Executor Contract that:
+ * - Validates Proposal creations/ cancellation
+ * - Validates Vote Quorum and Vote success on proposal
+ * - Allows queueing, execution and cancellation of proposals' transactions.
**/
-contract ExecutorWithTimelock is IExecutorWithTimelock {
- using SafeMath for uint256;
-
- uint256 public immutable override GRACE_PERIOD;
- uint256 public immutable override MINIMUM_DELAY;
- uint256 public immutable override MAXIMUM_DELAY;
-
+contract Executor is IExecutor {
address private _admin;
address private _pendingAdmin;
uint256 private _delay;
+ // uppercase is kept even not being constant/immutables,
+ // in order to keep interface compatibility with a previous version of the Executor
+ uint256 public PROPOSITION_THRESHOLD;
+ uint256 public VOTING_DURATION;
+ uint256 public VOTE_DIFFERENTIAL;
+ uint256 public MINIMUM_QUORUM;
+
mapping(bytes32 => bool) private _queuedTransactions;
+ uint256 public immutable GRACE_PERIOD;
+ uint256 public immutable MINIMUM_DELAY;
+ uint256 public immutable MAXIMUM_DELAY;
+ uint256 public constant ONE_HUNDRED_WITH_PRECISION = 10000; // Equivalent to 100%, but scaled for precision
+
/**
* @dev Constructor
* @param admin admin address, that can call the main functions, (Governance)
- * @param delay minimum time between queueing and execution of proposal
- * @param gracePeriod time after `delay` while a proposal can be executed
+ * @param delay minimum time between queueing and execution of proposal, in seconds
+ * @param gracePeriod time after `delay` while a proposal can be executed, in seconds
* @param minimumDelay lower threshold of `delay`, in seconds
- * @param maximumDelay upper threhold of `delay`, in seconds
+ * @param maximumDelay upper threshold of `delay`, in seconds
+ * @param propositionThreshold minimum percentage of supply needed to submit a proposal
+ * - In ONE_HUNDRED_WITH_PRECISION units
+ * @param voteDuration duration in blocks of the voting period
+ * @param voteDifferential percentage of supply that `for` votes need to be over `against`
+ * in order for the proposal to pass
+ * - In ONE_HUNDRED_WITH_PRECISION units
+ * @param minimumQuorum minimum percentage of the supply in FOR-voting-power need for a proposal to pass
+ * - In ONE_HUNDRED_WITH_PRECISION units
**/
constructor(
address admin,
uint256 delay,
uint256 gracePeriod,
uint256 minimumDelay,
- uint256 maximumDelay
- ) {
+ uint256 maximumDelay,
+ uint256 propositionThreshold,
+ uint256 voteDuration,
+ uint256 voteDifferential,
+ uint256 minimumQuorum
+ )
+ {
require(delay >= minimumDelay, 'DELAY_SHORTER_THAN_MINIMUM');
require(delay <= maximumDelay, 'DELAY_LONGER_THAN_MAXIMUM');
_delay = delay;
_admin = admin;
+ require(gracePeriod > 0, 'GRACE_PERIOD_LESS_THAN_0');
GRACE_PERIOD = gracePeriod;
+
MINIMUM_DELAY = minimumDelay;
MAXIMUM_DELAY = maximumDelay;
emit NewDelay(delay);
emit NewAdmin(admin);
+
+ _updateVotingDuration(voteDuration);
+ _updateVoteDifferential(voteDifferential);
+ _updateMinimumQuorum(minimumQuorum);
+ _updatePropositionThreshold(propositionThreshold);
}
+ /**
+ * -------------------------------------------------------------
+ * --------------- IExecutorWithTimelock -----------------------
+ * @dev logic for queue, execute, cancel transactions voted by Governance
+ * Queued transactions can be executed after a delay and until
+ * Grace period is not over.
+ * -------------------------------------------------------------
+ */
+
modifier onlyAdmin() {
require(msg.sender == _admin, 'ONLY_BY_ADMIN');
_;
}
- modifier onlyTimelock() {
- require(msg.sender == address(this), 'ONLY_BY_THIS_TIMELOCK');
+ modifier onlyPendingAdmin() {
+ require(msg.sender == _pendingAdmin, 'ONLY_BY_PENDING_ADMIN');
_;
}
- modifier onlyPendingAdmin() {
- require(msg.sender == _pendingAdmin, 'ONLY_BY_PENDING_ADMIN');
+ modifier onlyExecutor {
+ require(msg.sender == address(this), 'CALLER_NOT_EXECUTOR');
_;
}
- /**
- * @dev Set the delay
- * @param delay delay between queue and execution of proposal
- **/
- function setDelay(uint256 delay) public onlyTimelock {
+ /// @inheritdoc IExecutor
+ function setDelay(uint256 delay) external onlyExecutor {
_validateDelay(delay);
_delay = delay;
emit NewDelay(delay);
}
- /**
- * @dev Function enabling pending admin to become admin
- **/
- function acceptAdmin() public onlyPendingAdmin {
+ /// @inheritdoc IExecutor
+ function acceptAdmin() external onlyPendingAdmin {
_admin = msg.sender;
_pendingAdmin = address(0);
emit NewAdmin(msg.sender);
}
- /**
- * @dev Setting a new pending admin (that can then become admin)
- * Can only be called by this executor (i.e via proposal)
- * @param newPendingAdmin address of the new admin
- **/
- function setPendingAdmin(address newPendingAdmin) public onlyTimelock {
+ /// @inheritdoc IExecutor
+ function setPendingAdmin(address newPendingAdmin) external onlyExecutor {
_pendingAdmin = newPendingAdmin;
emit NewPendingAdmin(newPendingAdmin);
}
- /**
- * @dev Function, called by Governance, that queue a transaction, returns action hash
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- * @return the action Hash
- **/
+ /// @inheritdoc IExecutor
function queueTransaction(
address target,
uint256 value,
@@ -754,8 +136,8 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
bytes memory data,
uint256 executionTime,
bool withDelegatecall
- ) public override onlyAdmin returns (bytes32) {
- require(executionTime >= block.timestamp.add(_delay), 'EXECUTION_TIME_UNDERESTIMATED');
+ ) external onlyAdmin returns (bytes32) {
+ require(executionTime >= block.timestamp + _delay, 'EXECUTION_TIME_UNDERESTIMATED');
bytes32 actionHash = keccak256(
abi.encode(target, value, signature, data, executionTime, withDelegatecall)
@@ -766,16 +148,7 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
return actionHash;
}
- /**
- * @dev Function, called by Governance, that cancels a transaction, returns action hash
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- * @return the action Hash of the canceled tx
- **/
+ /// @inheritdoc IExecutor
function cancelTransaction(
address target,
uint256 value,
@@ -783,7 +156,7 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
bytes memory data,
uint256 executionTime,
bool withDelegatecall
- ) public override onlyAdmin returns (bytes32) {
+ ) external onlyAdmin returns (bytes32) {
bytes32 actionHash = keccak256(
abi.encode(target, value, signature, data, executionTime, withDelegatecall)
);
@@ -801,16 +174,7 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
return actionHash;
}
- /**
- * @dev Function, called by Governance, that cancels a transaction, returns the callData executed
- * @param target smart contract target
- * @param value wei value of the transaction
- * @param signature function signature of the transaction
- * @param data function arguments of the transaction or callData if signature empty
- * @param executionTime time at which to execute the transaction
- * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
- * @return the callData executed as memory bytes
- **/
+ /// @inheritdoc IExecutor
function executeTransaction(
address target,
uint256 value,
@@ -818,13 +182,13 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
bytes memory data,
uint256 executionTime,
bool withDelegatecall
- ) public payable override onlyAdmin returns (bytes memory) {
+ ) external payable onlyAdmin returns (bytes memory) {
bytes32 actionHash = keccak256(
abi.encode(target, value, signature, data, executionTime, withDelegatecall)
);
require(_queuedTransactions[actionHash], 'ACTION_NOT_QUEUED');
require(block.timestamp >= executionTime, 'TIMELOCK_NOT_FINISHED');
- require(block.timestamp <= executionTime.add(GRACE_PERIOD), 'GRACE_PERIOD_FINISHED');
+ require(block.timestamp <= executionTime + GRACE_PERIOD, 'GRACE_PERIOD_FINISHED');
_queuedTransactions[actionHash] = false;
@@ -863,273 +227,92 @@ contract ExecutorWithTimelock is IExecutorWithTimelock {
return resultData;
}
- /**
- * @dev Getter of the current admin address (should be governance)
- * @return The address of the current admin
- **/
- function getAdmin() external view override returns (address) {
+ /// @inheritdoc IExecutor
+ function getAdmin() external view returns (address) {
return _admin;
}
- /**
- * @dev Getter of the current pending admin address
- * @return The address of the pending admin
- **/
- function getPendingAdmin() external view override returns (address) {
+ /// @inheritdoc IExecutor
+ function getPendingAdmin() external view returns (address) {
return _pendingAdmin;
}
- /**
- * @dev Getter of the delay between queuing and execution
- * @return The delay in seconds
- **/
- function getDelay() external view override returns (uint256) {
+ /// @inheritdoc IExecutor
+ function getDelay() external view returns (uint256) {
return _delay;
}
- /**
- * @dev Returns whether an action (via actionHash) is queued
- * @param actionHash hash of the action to be checked
- * keccak256(abi.encode(target, value, signature, data, executionTime, withDelegatecall))
- * @return true if underlying action of actionHash is queued
- **/
- function isActionQueued(bytes32 actionHash) external view override returns (bool) {
+ /// @inheritdoc IExecutor
+ function isActionQueued(bytes32 actionHash) external view returns (bool) {
return _queuedTransactions[actionHash];
}
- /**
- * @dev Checks whether a proposal is over its grace period
- * @param governance Governance contract
- * @param proposalId Id of the proposal against which to test
- * @return true of proposal is over grace period
- **/
+ /// @inheritdoc IExecutor
function isProposalOverGracePeriod(IAaveGovernanceV2 governance, uint256 proposalId)
external
view
- override
returns (bool)
{
IAaveGovernanceV2.ProposalWithoutVotes memory proposal = governance.getProposalById(proposalId);
- return (block.timestamp > proposal.executionTime.add(GRACE_PERIOD));
- }
-
- function _validateDelay(uint256 delay) internal view {
- require(delay >= MINIMUM_DELAY, 'DELAY_SHORTER_THAN_MINIMUM');
- require(delay <= MAXIMUM_DELAY, 'DELAY_LONGER_THAN_MAXIMUM');
+ return (block.timestamp > proposal.executionTime + GRACE_PERIOD);
}
receive() external payable {}
-}
-
-interface IProposalValidator {
- /**
- * @dev Called to validate a proposal (e.g when creating new proposal in Governance)
- * @param governance Governance Contract
- * @param user Address of the proposal creator
- * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
- * @return boolean, true if can be created
- **/
- function validateCreatorOfProposal(
- IAaveGovernanceV2 governance,
- address user,
- uint256 blockNumber
- ) external view returns (bool);
-
- /**
- * @dev Called to validate the cancellation of a proposal
- * @param governance Governance Contract
- * @param user Address of the proposal creator
- * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
- * @return boolean, true if can be cancelled
- **/
- function validateProposalCancellation(
- IAaveGovernanceV2 governance,
- address user,
- uint256 blockNumber
- ) external view returns (bool);
-
- /**
- * @dev Returns whether a user has enough Proposition Power to make a proposal.
- * @param governance Governance Contract
- * @param user Address of the user to be challenged.
- * @param blockNumber Block Number against which to make the challenge.
- * @return true if user has enough power
- **/
- function isPropositionPowerEnough(
- IAaveGovernanceV2 governance,
- address user,
- uint256 blockNumber
- ) external view returns (bool);
-
- /**
- * @dev Returns the minimum Proposition Power needed to create a proposition.
- * @param governance Governance Contract
- * @param blockNumber Blocknumber at which to evaluate
- * @return minimum Proposition Power needed
- **/
- function getMinimumPropositionPowerNeeded(IAaveGovernanceV2 governance, uint256 blockNumber)
- external
- view
- returns (uint256);
-
- /**
- * @dev Returns whether a proposal passed or not
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to set
- * @return true if proposal passed
- **/
- function isProposalPassed(IAaveGovernanceV2 governance, uint256 proposalId)
- external
- view
- returns (bool);
-
- /**
- * @dev Check whether a proposal has reached quorum, ie has enough FOR-voting-power
- * Here quorum is not to understand as number of votes reached, but number of for-votes reached
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to verify
- * @return voting power needed for a proposal to pass
- **/
- function isQuorumValid(IAaveGovernanceV2 governance, uint256 proposalId)
- external
- view
- returns (bool);
-
- /**
- * @dev Check whether a proposal has enough extra FOR-votes than AGAINST-votes
- * FOR VOTES - AGAINST VOTES > VOTE_DIFFERENTIAL * voting supply
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to verify
- * @return true if enough For-Votes
- **/
- function isVoteDifferentialValid(IAaveGovernanceV2 governance, uint256 proposalId)
- external
- view
- returns (bool);
-
- /**
- * @dev Calculates the minimum amount of Voting Power needed for a proposal to Pass
- * @param votingSupply Total number of oustanding voting tokens
- * @return voting power needed for a proposal to pass
- **/
- function getMinimumVotingPowerNeeded(uint256 votingSupply) external view returns (uint256);
-
- /**
- * @dev Get proposition threshold constant value
- * @return the proposition threshold value (100 <=> 1%)
- **/
- function PROPOSITION_THRESHOLD() external view returns (uint256);
-
- /**
- * @dev Get voting duration constant value
- * @return the voting duration value in seconds
- **/
- function VOTING_DURATION() external view returns (uint256);
-
- /**
- * @dev Get the vote differential threshold constant value
- * to compare with % of for votes/total supply - % of against votes/total supply
- * @return the vote differential threshold value (100 <=> 1%)
- **/
- function VOTE_DIFFERENTIAL() external view returns (uint256);
/**
- * @dev Get quorum threshold constant value
- * to compare with % of for votes/total supply
- * @return the quorum threshold value (100 <=> 1%)
- **/
- function MINIMUM_QUORUM() external view returns (uint256);
+ * --------------------------------------------------------
+ * ---------- Proposal Validation -------------------------
+ * @dev Validates/Invalidations propositions state modifications.
+ * Proposition Power functions: Validates proposition creations/ cancellation
+ * Voting Power functions: Validates success of propositions.
+ * --------------------------------------------------------
+ */
- /**
- * @dev precision helper: 100% = 10000
- * @return one hundred percents with our chosen precision
- **/
- function ONE_HUNDRED_WITH_PRECISION() external view returns (uint256);
-}
+ /// @inheritdoc IExecutor
+ function updateVotingDuration(uint256 votingDuration) external onlyExecutor {
+ _updateVotingDuration(votingDuration);
+ }
-/**
- * @title Proposal Validator Contract, inherited by Aave Governance Executors
- * @dev Validates/Invalidations propositions state modifications.
- * Proposition Power functions: Validates proposition creations/ cancellation
- * Voting Power functions: Validates success of propositions.
- * @author Aave
- **/
-contract ProposalValidator is IProposalValidator {
- using SafeMath for uint256;
+ /// @inheritdoc IExecutor
+ function updateVoteDifferential(uint256 voteDifferential) external onlyExecutor {
+ _updateVoteDifferential(voteDifferential);
+ }
- uint256 public immutable override PROPOSITION_THRESHOLD;
- uint256 public immutable override VOTING_DURATION;
- uint256 public immutable override VOTE_DIFFERENTIAL;
- uint256 public immutable override MINIMUM_QUORUM;
- uint256 public constant override ONE_HUNDRED_WITH_PRECISION = 10000; // Equivalent to 100%, but scaled for precision
+ /// @inheritdoc IExecutor
+ function updateMinimumQuorum(uint256 minimumQuorum) external onlyExecutor {
+ _updateMinimumQuorum(minimumQuorum);
+ }
- /**
- * @dev Constructor
- * @param propositionThreshold minimum percentage of supply needed to submit a proposal
- * - In ONE_HUNDRED_WITH_PRECISION units
- * @param votingDuration duration in blocks of the voting period
- * @param voteDifferential percentage of supply that `for` votes need to be over `against`
- * in order for the proposal to pass
- * - In ONE_HUNDRED_WITH_PRECISION units
- * @param minimumQuorum minimum percentage of the supply in FOR-voting-power need for a proposal to pass
- * - In ONE_HUNDRED_WITH_PRECISION units
- **/
- constructor(
- uint256 propositionThreshold,
- uint256 votingDuration,
- uint256 voteDifferential,
- uint256 minimumQuorum
- ) {
- PROPOSITION_THRESHOLD = propositionThreshold;
- VOTING_DURATION = votingDuration;
- VOTE_DIFFERENTIAL = voteDifferential;
- MINIMUM_QUORUM = minimumQuorum;
+ /// @inheritdoc IExecutor
+ function updatePropositionThreshold(uint256 propositionThreshold) external onlyExecutor {
+ _updatePropositionThreshold(propositionThreshold);
}
- /**
- * @dev Called to validate a proposal (e.g when creating new proposal in Governance)
- * @param governance Governance Contract
- * @param user Address of the proposal creator
- * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
- * @return boolean, true if can be created
- **/
+ /// @inheritdoc IExecutor
function validateCreatorOfProposal(
IAaveGovernanceV2 governance,
address user,
uint256 blockNumber
- ) external view override returns (bool) {
+ ) external view returns (bool) {
return isPropositionPowerEnough(governance, user, blockNumber);
}
- /**
- * @dev Called to validate the cancellation of a proposal
- * Needs to creator to have lost proposition power threashold
- * @param governance Governance Contract
- * @param user Address of the proposal creator
- * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
- * @return boolean, true if can be cancelled
- **/
+ /// @inheritdoc IExecutor
function validateProposalCancellation(
IAaveGovernanceV2 governance,
address user,
uint256 blockNumber
- ) external view override returns (bool) {
+ ) external view returns (bool) {
return !isPropositionPowerEnough(governance, user, blockNumber);
}
- /**
- * @dev Returns whether a user has enough Proposition Power to make a proposal.
- * @param governance Governance Contract
- * @param user Address of the user to be challenged.
- * @param blockNumber Block Number against which to make the challenge.
- * @return true if user has enough power
- **/
+ /// @inheritdoc IExecutor
function isPropositionPowerEnough(
IAaveGovernanceV2 governance,
address user,
uint256 blockNumber
- ) public view override returns (bool) {
+ ) public view returns (bool) {
IGovernanceStrategy currentGovernanceStrategy = IGovernanceStrategy(
governance.getGovernanceStrategy()
);
@@ -1138,16 +321,10 @@ contract ProposalValidator is IProposalValidator {
getMinimumPropositionPowerNeeded(governance, blockNumber);
}
- /**
- * @dev Returns the minimum Proposition Power needed to create a proposition.
- * @param governance Governance Contract
- * @param blockNumber Blocknumber at which to evaluate
- * @return minimum Proposition Power needed
- **/
+ /// @inheritdoc IExecutor
function getMinimumPropositionPowerNeeded(IAaveGovernanceV2 governance, uint256 blockNumber)
public
view
- override
returns (uint256)
{
IGovernanceStrategy currentGovernanceStrategy = IGovernanceStrategy(
@@ -1156,51 +333,33 @@ contract ProposalValidator is IProposalValidator {
return
currentGovernanceStrategy
.getTotalPropositionSupplyAt(blockNumber)
- .mul(PROPOSITION_THRESHOLD)
- .div(ONE_HUNDRED_WITH_PRECISION);
+ * PROPOSITION_THRESHOLD
+ / ONE_HUNDRED_WITH_PRECISION;
}
- /**
- * @dev Returns whether a proposal passed or not
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to set
- * @return true if proposal passed
- **/
+ /// @inheritdoc IExecutor
function isProposalPassed(IAaveGovernanceV2 governance, uint256 proposalId)
external
view
- override
returns (bool)
{
return (isQuorumValid(governance, proposalId) &&
isVoteDifferentialValid(governance, proposalId));
}
- /**
- * @dev Calculates the minimum amount of Voting Power needed for a proposal to Pass
- * @param votingSupply Total number of oustanding voting tokens
- * @return voting power needed for a proposal to pass
- **/
+ /// @inheritdoc IExecutor
function getMinimumVotingPowerNeeded(uint256 votingSupply)
public
view
- override
returns (uint256)
{
- return votingSupply.mul(MINIMUM_QUORUM).div(ONE_HUNDRED_WITH_PRECISION);
+ return votingSupply * MINIMUM_QUORUM / ONE_HUNDRED_WITH_PRECISION;
}
- /**
- * @dev Check whether a proposal has reached quorum, ie has enough FOR-voting-power
- * Here quorum is not to understand as number of votes reached, but number of for-votes reached
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to verify
- * @return voting power needed for a proposal to pass
- **/
+ /// @inheritdoc IExecutor
function isQuorumValid(IAaveGovernanceV2 governance, uint256 proposalId)
public
view
- override
returns (bool)
{
IAaveGovernanceV2.ProposalWithoutVotes memory proposal = governance.getProposalById(proposalId);
@@ -1211,17 +370,10 @@ contract ProposalValidator is IProposalValidator {
return proposal.forVotes >= getMinimumVotingPowerNeeded(votingSupply);
}
- /**
- * @dev Check whether a proposal has enough extra FOR-votes than AGAINST-votes
- * FOR VOTES - AGAINST VOTES > VOTE_DIFFERENTIAL * voting supply
- * @param governance Governance Contract
- * @param proposalId Id of the proposal to verify
- * @return true if enough For-Votes
- **/
+ /// @inheritdoc IExecutor
function isVoteDifferentialValid(IAaveGovernanceV2 governance, uint256 proposalId)
public
view
- override
returns (bool)
{
IAaveGovernanceV2.ProposalWithoutVotes memory proposal = governance.getProposalById(proposalId);
@@ -1229,34 +381,45 @@ contract ProposalValidator is IProposalValidator {
proposal.startBlock
);
- return (proposal.forVotes.mul(ONE_HUNDRED_WITH_PRECISION).div(votingSupply) >
- proposal.againstVotes.mul(ONE_HUNDRED_WITH_PRECISION).div(votingSupply).add(
- VOTE_DIFFERENTIAL
- ));
+ return (proposal.forVotes * ONE_HUNDRED_WITH_PRECISION / votingSupply) >
+ ((proposal.againstVotes * ONE_HUNDRED_WITH_PRECISION / votingSupply) +
+ VOTE_DIFFERENTIAL);
}
-}
-/**
- * @title Time Locked, Validator, Executor Contract
- * @dev Contract
- * - Validate Proposal creations/ cancellation
- * - Validate Vote Quorum and Vote success on proposal
- * - Queue, Execute, Cancel, successful proposals' transactions.
- * @author Aave
- **/
-contract Executor is ExecutorWithTimelock, ProposalValidator {
- constructor(
- address admin,
- uint256 delay,
- uint256 gracePeriod,
- uint256 minimumDelay,
- uint256 maximumDelay,
- uint256 propositionThreshold,
- uint256 voteDuration,
- uint256 voteDifferential,
- uint256 minimumQuorum
- )
- ExecutorWithTimelock(admin, delay, gracePeriod, minimumDelay, maximumDelay)
- ProposalValidator(propositionThreshold, voteDuration, voteDifferential, minimumQuorum)
- {}
+ /// updates voting duration
+ function _updateVotingDuration(uint256 votingDuration) internal {
+ require(votingDuration > 0, 'VOTING_DURATION_CAN_NOT_BE_0');
+ VOTING_DURATION = votingDuration;
+ emit VotingDurationUpdated(votingDuration);
+ }
+
+ /// updates vote differential
+ function _updateVoteDifferential(uint256 voteDifferential) internal {
+ require(voteDifferential <= ONE_HUNDRED_WITH_PRECISION, 'VOTE_DIFFERENTIAL_CAN_NOT_BE_GREATER_THAN_100%');
+ require(voteDifferential > 0, 'VOTE_DIFFERENTIAL_CAN_NOT_BE_LESS_THAN_0');
+ VOTE_DIFFERENTIAL = voteDifferential;
+ emit VoteDifferentialUpdated(voteDifferential);
+ }
+
+ /// updates minimum quorum
+ function _updateMinimumQuorum(uint256 minimumQuorum) internal {
+ require(minimumQuorum <= ONE_HUNDRED_WITH_PRECISION, 'MINIMUM_QUORUM_CAN_NOT_BE_GREATER_THAN_100%');
+ require(minimumQuorum > 0, 'MINIMUM_QUORUM_CAN_NOT_BE_LESS_THAN_0');
+ MINIMUM_QUORUM = minimumQuorum;
+ emit MinimumQuorumUpdated(minimumQuorum);
+ }
+
+ /// updates proposition threshold
+ function _updatePropositionThreshold(uint256 propositionThreshold) internal {
+ require(propositionThreshold <= ONE_HUNDRED_WITH_PRECISION, 'PROPOSITION_THRESHOLD_CAN_NOT_BE_GREATER_THAN_100%');
+ require(propositionThreshold > 0, 'PROPOSITION_THRESHOLD_CAN_NOT_BE_LESS_THAN_0');
+ PROPOSITION_THRESHOLD = propositionThreshold;
+ emit PropositionThresholdUpdated(propositionThreshold);
+ }
+
+ /// validates that a delay is correct
+ function _validateDelay(uint256 delay) internal view {
+ require(delay >= MINIMUM_DELAY, 'DELAY_SHORTER_THAN_MINIMUM');
+ require(delay <= MAXIMUM_DELAY, 'DELAY_LONGER_THAN_MAXIMUM');
+ }
}
\ No newline at end of file