Contract Source Code:
File 1 of 1 : Governor
pragma solidity 0.5.11;
/*
* Origin Protocol
* https://originprotocol.com
*
* Released under the MIT license
* https://github.com/OriginProtocol
*
* Copyright 2019 Origin Protocol, Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// File: origin-dollar/contracts/interfaces/ITimelock.sol
interface ITimelock {
function delay() external view returns (uint256);
function GRACE_PERIOD() external view returns (uint256);
function acceptAdmin() external;
function queuedTransactions(bytes32 hash) external view returns (bool);
function queueTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external returns (bytes32);
function cancelTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external;
function executeTransaction(
address target,
uint256 value,
string calldata signature,
bytes calldata data,
uint256 eta
) external payable returns (bytes memory);
}
// File: origin-dollar/contracts/governance/Governor.sol
pragma solidity ^0.5.11;
pragma experimental ABIEncoderV2;
// Modeled off of Compound's Governor Alpha
// https://github.com/compound-finance/compound-protocol/blob/master/contracts/Governance/GovernorAlpha.sol
contract Governor {
/// @notice The address of the Timelock
ITimelock public timelock;
/// @notice The address of the Governor Guardian
address public guardian;
/// @notice The total number of proposals
uint256 public proposalCount;
struct Proposal {
/// @notice Unique id for looking up a proposal
uint256 id;
/// @notice Creator of the proposal
address proposer;
/// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds
uint256 eta;
/// @notice the ordered list of target addresses for calls to be made
address[] targets;
/// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made
uint256[] values;
/// @notice The ordered list of function signatures to be called
string[] signatures;
/// @notice The ordered list of calldata to be passed to each call
bytes[] calldatas;
/// @notice Flag marking whether the proposal has been executed
bool executed;
}
/// @notice The official record of all proposals ever proposed
mapping(uint256 => Proposal) public proposals;
/// @notice An event emitted when a new proposal is created
event ProposalCreated(
uint256 id,
address proposer,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
string description
);
/// @notice An event emitted when a proposal has been queued in the Timelock
event ProposalQueued(uint256 id, uint256 eta);
/// @notice An event emitted when a proposal has been executed in the Timelock
event ProposalExecuted(uint256 id);
uint256 public constant MAX_OPERATIONS = 16;
/// @notice Possible states that a proposal may be in
enum ProposalState { Pending, Queued, Expired, Executed }
constructor(address timelock_, address guardian_) public {
timelock = ITimelock(timelock_);
guardian = guardian_;
}
function propose(
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas,
string memory description
) public returns (uint256) {
// allow anyone to propose for now, since only guardian can queue the transaction it should be harmless, you just need to pay the gas
require(
targets.length == values.length &&
targets.length == signatures.length &&
targets.length == calldatas.length,
"Governor::propose: proposal function information arity mismatch"
);
require(targets.length != 0, "Governor::propose: must provide actions");
require(
targets.length <= MAX_OPERATIONS,
"Governor::propose: too many actions"
);
proposalCount++;
Proposal memory newProposal = Proposal({
id: proposalCount,
proposer: msg.sender,
eta: 0,
targets: targets,
values: values,
signatures: signatures,
calldatas: calldatas,
executed: false
});
proposals[newProposal.id] = newProposal;
emit ProposalCreated(
newProposal.id,
msg.sender,
targets,
values,
signatures,
calldatas,
description
);
return newProposal.id;
}
function queue(uint256 proposalId) public {
require(
msg.sender == guardian,
"Governor::queue: sender must be gov guardian"
);
require(
state(proposalId) == ProposalState.Pending,
"Governor::queue: proposal can only be queued if it is pending"
);
Proposal storage proposal = proposals[proposalId];
proposal.eta = add256(block.timestamp, timelock.delay());
for (uint256 i = 0; i < proposal.targets.length; i++) {
_queueOrRevert(
proposal.targets[i],
proposal.values[i],
proposal.signatures[i],
proposal.calldatas[i],
proposal.eta
);
}
emit ProposalQueued(proposal.id, proposal.eta);
}
function state(uint256 proposalId) public view returns (ProposalState) {
require(
proposalCount >= proposalId && proposalId > 0,
"Governor::state: invalid proposal id"
);
Proposal storage proposal = proposals[proposalId];
if (proposal.executed) {
return ProposalState.Executed;
} else if (proposal.eta == 0) {
return ProposalState.Pending;
} else if (
block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())
) {
return ProposalState.Expired;
} else {
return ProposalState.Queued;
}
}
function _queueOrRevert(
address target,
uint256 value,
string memory signature,
bytes memory data,
uint256 eta
) internal {
require(
!timelock.queuedTransactions(
keccak256(abi.encode(target, value, signature, data, eta))
),
"Governor::_queueOrRevert: proposal action already queued at eta"
);
timelock.queueTransaction(target, value, signature, data, eta);
}
function execute(uint256 proposalId) public payable {
require(
state(proposalId) == ProposalState.Queued,
"Governor::execute: proposal can only be executed if it is queued"
);
Proposal storage proposal = proposals[proposalId];
proposal.executed = true;
for (uint256 i = 0; i < proposal.targets.length; i++) {
timelock.executeTransaction.value(proposal.values[i])(
proposal.targets[i],
proposal.values[i],
proposal.signatures[i],
proposal.calldatas[i],
proposal.eta
);
}
emit ProposalExecuted(proposalId);
}
function getActions(uint256 proposalId)
public
view
returns (
address[] memory targets,
uint256[] memory values,
string[] memory signatures,
bytes[] memory calldatas
)
{
Proposal storage p = proposals[proposalId];
return (p.targets, p.values, p.signatures, p.calldatas);
}
function __acceptAdmin() public {
require(
msg.sender == guardian,
"Governor::__acceptAdmin: sender must be gov guardian"
);
timelock.acceptAdmin();
}
function __queueSetTimelockPendingAdmin(
address newPendingAdmin,
uint256 eta
) public {
require(
msg.sender == guardian,
"Governor::__queueSetTimelockPendingAdmin: sender must be gov guardian"
);
timelock.queueTransaction(
address(timelock),
0,
"setPendingAdmin(address)",
abi.encode(newPendingAdmin),
eta
);
}
function __executeSetTimelockPendingAdmin(
address newPendingAdmin,
uint256 eta
) public {
require(
msg.sender == guardian,
"Governor::__executeSetTimelockPendingAdmin: sender must be gov guardian"
);
timelock.executeTransaction(
address(timelock),
0,
"setPendingAdmin(address)",
abi.encode(newPendingAdmin),
eta
);
}
function add256(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "addition overflow");
return c;
}
function sub256(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "subtraction underflow");
return a - b;
}
}