文件 1 的 9:Address.sol
pragma solidity ^0.8.0;
library Address {
function isContract(address account) internal view returns (bool) {
uint256 size;
assembly { size := extcodesize(account) }
return size > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}
文件 2 的 9:Context.sol
pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
this;
return msg.data;
}
}
文件 3 的 9:Delegator.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
contract Delegator is Ownable {
mapping(
address => mapping(
address => mapping(bytes4 => bool)
)
) public permissions;
event GrantPermission(address indexed caller, address indexed contractAddress, bytes4 indexed selector);
event RevokePermission(address indexed caller, address indexed contractAddress, bytes4 indexed selector);
constructor(address _admin) {
Ownable.transferOwnership(_admin);
}
function setPermission(
address _caller,
address _contract,
bytes4 _selector,
bool _permission
) public onlyOwner {
if (permissions[_caller][_contract][_selector] != _permission) {
permissions[_caller][_contract][_selector] = _permission;
if (_permission) {
emit GrantPermission(_caller, _contract, _selector);
} else {
emit RevokePermission(_caller, _contract, _selector);
}
}
}
function checkPermission(address _caller, address _contract, bytes4 _selector) public view returns (bool) {
return (
_caller == Ownable.owner()
|| permissions[_caller][_contract][_selector]
|| permissions[_caller][_contract][0x0]
|| permissions[_caller][address(0)][_selector]
|| permissions[_caller][address(0)][0x0]
);
}
function callContract(address _contract, bytes calldata _data, uint256 _value) public returns (bool success, bytes memory returnData) {
bytes4 selector = bytes4(_data);
if (_contract == address(this)) {
if (selector == this.setPermission.selector) {
(
address caller,
address calledContract,
bytes4 _permissionSelector,
bool permission
) = abi.decode(abi.encodePacked(_data[4:]), (address, address, bytes4, bool));
setPermission(caller, calledContract, _permissionSelector, permission);
bytes memory empty;
return (true, empty);
} else if (selector == this.transferOwnership.selector) {
(
address newOwner
) = abi.decode(abi.encodePacked(_data[4:]), (address));
Ownable.transferOwnership(newOwner);
bytes memory empty;
return (true, empty);
} else if (selector == this.renounceOwnership.selector) {
Ownable.renounceOwnership();
bytes memory empty;
return (true, empty);
} else {
bytes memory empty;
return (false, empty);
}
}
require(checkPermission(msg.sender, _contract, selector), "Delegator: Caller doesn't have permission");
return _contract.call{value: _value}(_data);
}
}
文件 4 的 9:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
文件 5 的 9:Math.sol
pragma solidity ^0.8.0;
library Math {
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a >= b ? a : b;
}
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
function average(uint256 a, uint256 b) internal pure returns (uint256) {
return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
}
}
文件 6 的 9:Ownable.sol
pragma solidity ^0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 7 的 9:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 8 的 9:Staking.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import { Math } from "@openzeppelin/contracts/utils/math/Math.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract Staking {
using SafeERC20 for IERC20;
uint256 public constant STAKE_LOCKTIME = 30 days;
uint256 public constant SNAPSHOT_INTERVAL = 1 days;
IERC20 public stakingToken;
uint256 public immutable DEPLOY_TIME = block.timestamp;
event Stake(address indexed account, uint256 indexed stakeID, uint256 amount);
event Unlock(address indexed account, uint256 indexed stakeID);
event Claim(address indexed account, uint256 indexed stakeID);
event Delegate(address indexed owner, address indexed _from, address indexed to, uint256 stakeID, uint256 amount);
uint256 public totalStaked = 0;
struct GlobalsSnapshot {
uint256 interval;
uint256 totalVotingPower;
uint256 totalStaked;
}
GlobalsSnapshot[] private globalsSnapshots;
struct StakeStruct {
address delegate;
uint256 amount;
uint256 staketime;
uint256 locktime;
uint256 claimedTime;
}
mapping(address => StakeStruct[]) public stakes;
mapping(address => uint256) public votingPower;
struct AccountSnapshot {
uint256 interval;
uint256 votingPower;
}
mapping(address => AccountSnapshot[]) private accountSnapshots;
constructor(IERC20 _stakingToken) {
stakingToken = _stakingToken;
votingPower[address(0)] = type(uint256).max;
}
function totalVotingPower() public view returns (uint256) {
return ~votingPower[address(0)];
}
function stakesLength(address _account) external view returns (uint256) {
return stakes[_account].length;
}
function intervalAtTime(uint256 _time) public view returns (uint256) {
require(_time >= DEPLOY_TIME, "Staking: Requested time is before contract was deployed");
return (_time - DEPLOY_TIME) / SNAPSHOT_INTERVAL;
}
function currentInterval() public view returns (uint256) {
return intervalAtTime(block.timestamp);
}
function latestGlobalsSnapshotInterval() public view returns (uint256) {
if (globalsSnapshots.length > 0) {
return globalsSnapshots[globalsSnapshots.length - 1].interval;
} else {
return 0;
}
}
function latestAccountSnapshotInterval(address _account) public view returns (uint256) {
if (accountSnapshots[_account].length > 0) {
return accountSnapshots[_account][accountSnapshots[_account].length - 1].interval;
} else {
return 0;
}
}
function accountSnapshotLength(address _account) external view returns (uint256) {
return accountSnapshots[_account].length;
}
function globalsSnapshotLength() external view returns (uint256) {
return globalsSnapshots.length;
}
function globalsSnapshot(uint256 _index) external view returns (GlobalsSnapshot memory) {
return globalsSnapshots[_index];
}
function accountSnapshot(address _account, uint256 _index) external view returns (AccountSnapshot memory) {
return accountSnapshots[_account][_index];
}
function snapshot(address _account) internal {
uint256 _currentInterval = currentInterval();
if(latestGlobalsSnapshotInterval() < _currentInterval) {
globalsSnapshots.push(GlobalsSnapshot(
_currentInterval,
totalVotingPower(),
totalStaked
));
}
if(_account != address(0) && latestAccountSnapshotInterval(_account) < _currentInterval) {
accountSnapshots[_account].push(AccountSnapshot(
_currentInterval,
votingPower[_account]
));
}
}
function moveVotingPower(address _from, address _to, uint256 _amount) internal {
votingPower[_from] -= _amount;
votingPower[_to] += _amount;
}
function delegate(uint256 _stakeID, address _to) public {
StakeStruct storage _stake = stakes[msg.sender][_stakeID];
require(
_stake.staketime != 0,
"Staking: Stake doesn't exist"
);
require(
_stake.locktime == 0,
"Staking: Stake unlocked"
);
require(
_to != address(0),
"Staking: Can't delegate to 0 address"
);
if (_stake.delegate != _to) {
snapshot(_stake.delegate);
snapshot(_to);
moveVotingPower(
_stake.delegate,
_to,
_stake.amount
);
emit Delegate(msg.sender, _stake.delegate, _to, _stakeID, _stake.amount);
_stake.delegate = _to;
}
}
function undelegate(uint256 _stakeID) external {
delegate(_stakeID, msg.sender);
}
function globalsSnapshotAtSearch(uint256 _interval) internal view returns (GlobalsSnapshot memory) {
require(_interval <= currentInterval(), "Staking: Interval out of bounds");
uint256 index;
uint256 low = 0;
uint256 high = globalsSnapshots.length;
while (low < high) {
uint256 mid = Math.average(low, high);
if (globalsSnapshots[mid].interval > _interval) {
high = mid;
} else {
low = mid + 1;
}
}
if (low > 0 && globalsSnapshots[low - 1].interval == _interval) {
return globalsSnapshots[low - 1];
} else {
index = low;
}
if (index == globalsSnapshots.length) {
return GlobalsSnapshot(
_interval,
totalVotingPower(),
totalStaked
);
} else {
return globalsSnapshots[index];
}
}
function globalsSnapshotAt(uint256 _interval, uint256 _hint) external view returns (GlobalsSnapshot memory) {
require(_interval <= currentInterval(), "Staking: Interval out of bounds");
if (
_hint <= globalsSnapshots.length
&& (_hint == 0 || globalsSnapshots[_hint - 1].interval < _interval)
&& (_hint == globalsSnapshots.length || globalsSnapshots[_hint].interval >= _interval)
) {
if (_hint < globalsSnapshots.length)
return globalsSnapshots[_hint];
else
return GlobalsSnapshot (_interval, totalVotingPower(), totalStaked);
} else return globalsSnapshotAtSearch (_interval);
}
function accountSnapshotAtSearch(address _account, uint256 _interval) internal view returns (AccountSnapshot memory) {
require(_interval <= currentInterval(), "Staking: Interval out of bounds");
AccountSnapshot[] storage snapshots = accountSnapshots[_account];
uint256 index;
uint256 low = 0;
uint256 high = snapshots.length;
while (low < high) {
uint256 mid = Math.average(low, high);
if (snapshots[mid].interval > _interval) {
high = mid;
} else {
low = mid + 1;
}
}
if (low > 0 && snapshots[low - 1].interval == _interval) {
return snapshots[low - 1];
} else {
index = low;
}
if (index == snapshots.length) {
return AccountSnapshot(
_interval,
votingPower[_account]
);
} else {
return snapshots[index];
}
}
function accountSnapshotAt(address _account, uint256 _interval, uint256 _hint) external view returns (AccountSnapshot memory) {
require(_interval <= currentInterval(), "Staking: Interval out of bounds");
AccountSnapshot[] storage snapshots = accountSnapshots[_account];
if (
_hint <= snapshots.length
&& (_hint == 0 || snapshots[_hint - 1].interval < _interval)
&& (_hint == snapshots.length || snapshots[_hint].interval >= _interval)
) {
if (_hint < snapshots.length)
return snapshots[_hint];
else
return AccountSnapshot(_interval, votingPower[_account]);
} else return accountSnapshotAtSearch(_account, _interval);
}
function stake(uint256 _amount) public returns (uint256) {
require(_amount > 0, "Staking: Amount not set");
snapshot(msg.sender);
uint256 stakeID = stakes[msg.sender].length;
stakes[msg.sender].push(StakeStruct(
msg.sender,
_amount,
block.timestamp,
0,
0
));
totalStaked += _amount;
moveVotingPower(
address(0),
msg.sender,
_amount
);
stakingToken.safeTransferFrom(msg.sender, address(this), _amount);
emit Stake(msg.sender, stakeID, _amount);
return stakeID;
}
function unlock(uint256 _stakeID) public {
require(
stakes[msg.sender][_stakeID].staketime != 0,
"Staking: Stake doesn't exist"
);
require(
stakes[msg.sender][_stakeID].locktime == 0,
"Staking: Stake already unlocked"
);
snapshot(msg.sender);
stakes[msg.sender][_stakeID].locktime = block.timestamp + STAKE_LOCKTIME;
moveVotingPower(
stakes[msg.sender][_stakeID].delegate,
address(0),
stakes[msg.sender][_stakeID].amount
);
emit Unlock(msg.sender, _stakeID);
}
function claim(uint256 _stakeID) public {
require(
stakes[msg.sender][_stakeID].locktime != 0
&& stakes[msg.sender][_stakeID].locktime < block.timestamp,
"Staking: Stake not unlocked"
);
require(
stakes[msg.sender][_stakeID].claimedTime == 0,
"Staking: Stake already claimed"
);
snapshot(msg.sender);
stakes[msg.sender][_stakeID].claimedTime = block.timestamp;
totalStaked -= stakes[msg.sender][_stakeID].amount;
stakingToken.safeTransfer(
msg.sender,
stakes[msg.sender][_stakeID].amount
);
emit Claim(msg.sender, _stakeID);
}
}
文件 9 的 9:Voting.sol
pragma solidity ^0.8.0;
pragma abicoder v2;
import { Staking } from "./Staking.sol";
import { Delegator } from "./Delegator.sol";
contract Voting {
uint256 public constant SPONSOR_WINDOW = 30 days;
uint256 public constant VOTING_START_OFFSET = 2 days;
uint256 public constant VOTING_YAY_END_OFFSET = 5 days;
uint256 public constant VOTING_NAY_END_OFFSET = 6 days;
uint256 public constant EXECUTION_START_OFFSET = 7 days;
uint256 public constant EXECUTION_END_OFFSET = 14 days;
uint256 public constant QUORUM = 4000000e18;
uint256 public constant PROPOSAL_SPONSOR_THRESHOLD = 1000000e18;
event Proposal(uint256 indexed id, address indexed proposer);
event Sponsorship(uint256 indexed id, address indexed sponsor, uint256 amount);
event SponsorshipRevocation(uint256 indexed id, address indexed sponsor, uint256 amount);
event VoteCall(uint256 indexed id);
event VoteCast(uint256 indexed id, address indexed voter, bool affirmative, uint256 votes);
event Execution(uint256 indexed id);
struct Call {
address callContract;
bytes data;
uint256 value;
}
struct ProposalStruct {
address proposer;
string proposalDocument;
Call[] actions;
uint256 publishTime;
uint256 voteCallTime;
uint256 sponsorship;
mapping(address => uint256) sponsors;
bool executed;
mapping(address => uint256) voted;
uint256 yayVotes;
uint256 nayVotes;
uint256 sponsorInterval;
uint256 votingInterval;
}
ProposalStruct[] public proposals;
Staking public immutable STAKING_CONTRACT;
Delegator public immutable DELEGATOR_CONTRACT;
constructor(Staking _stakingContract, Delegator _delegator) {
STAKING_CONTRACT = _stakingContract;
DELEGATOR_CONTRACT = _delegator;
}
function proposalsLength() external view returns (uint256) {
return proposals.length;
}
function getActions(uint256 _id) external view returns (Call[] memory) {
return proposals[_id].actions;
}
function getSponsored(uint256 _id, address _account) external view returns (uint256) {
return proposals[_id].sponsors[_account];
}
function createProposal(string calldata _proposalDocument, Call[] calldata _actions) external returns (uint256) {
require(_actions.length > 0, "Voting: No actions specified");
uint256 proposalID = proposals.length;
ProposalStruct storage proposal = proposals.push();
proposal.proposer = msg.sender;
proposal.proposalDocument = _proposalDocument;
proposal.publishTime = block.timestamp;
proposal.sponsorInterval = STAKING_CONTRACT.currentInterval();
for (uint256 i = 0; i < _actions.length; i++) {
proposal.actions.push(Call(
_actions[i].callContract,
_actions[i].data,
_actions[i].value
));
}
emit Proposal(proposalID, msg.sender);
return proposalID;
}
function sponsorProposal(uint256 _id, uint256 _amount, uint256 _hint) external {
ProposalStruct storage proposal = proposals[_id];
require(proposal.voteCallTime == 0, "Voting: Gone to vote");
require(block.timestamp < proposal.publishTime + SPONSOR_WINDOW, "Voting: Sponsoring window passed");
Staking.AccountSnapshot memory snapshot = STAKING_CONTRACT.accountSnapshotAt(
msg.sender,
proposal.sponsorInterval,
_hint
);
require(proposal.sponsors[msg.sender] + _amount <= snapshot.votingPower, "Voting: Not enough voting power");
proposal.sponsors[msg.sender] += _amount;
proposal.sponsorship += _amount;
emit Sponsorship(_id, msg.sender, _amount);
}
function unsponsorProposal(uint256 _id, uint256 _amount) external {
ProposalStruct storage proposal = proposals[_id];
require(proposal.voteCallTime == 0, "Voting: Gone to vote");
require(block.timestamp < proposal.publishTime + SPONSOR_WINDOW, "Voting: Sponsoring window passed");
require(_amount <= proposal.sponsors[msg.sender], "Voting: Amount greater than sponsored");
proposal.sponsors[msg.sender] -= _amount;
proposal.sponsorship -= _amount;
emit SponsorshipRevocation(_id, msg.sender, _amount);
}
function callVote(uint256 _id) external {
ProposalStruct storage proposal = proposals[_id];
require(block.timestamp < proposal.publishTime + SPONSOR_WINDOW, "Voting: Sponsoring window passed");
require(proposal.voteCallTime == 0, "Voting: Proposal already gone to vote");
require(proposal.sponsorship >= PROPOSAL_SPONSOR_THRESHOLD, "Voting: Sponsor threshold not met");
proposal.voteCallTime = block.timestamp;
proposal.votingInterval = STAKING_CONTRACT.currentInterval();
emit VoteCall(_id);
}
function vote(uint256 _id, uint256 _amount, bool _affirmative, uint256 _hint) external {
ProposalStruct storage proposal = proposals[_id];
require(proposal.voteCallTime > 0, "Voting: Vote hasn't been called for this proposal");
require(block.timestamp > proposal.voteCallTime + VOTING_START_OFFSET, "Voting: Voting window hasn't opened");
if(_affirmative) {
require(block.timestamp < proposal.voteCallTime + VOTING_YAY_END_OFFSET, "Voting: Affirmative voting window has closed");
} else {
require(block.timestamp < proposal.voteCallTime + VOTING_NAY_END_OFFSET, "Voting: Negative voting window has closed");
}
Staking.AccountSnapshot memory snapshot = STAKING_CONTRACT.accountSnapshotAt(
msg.sender,
proposal.votingInterval,
_hint
);
require(proposal.voted[msg.sender] + _amount <= snapshot.votingPower, "Voting: Not enough voting power to cast this vote");
proposal.voted[msg.sender] += _amount;
if (_affirmative) {
proposal.yayVotes += _amount;
} else {
proposal.nayVotes += _amount;
}
emit VoteCast(_id, msg.sender, _affirmative, _amount);
}
function executeProposal(uint256 _id) external {
ProposalStruct storage proposal = proposals[_id];
require(proposal.voteCallTime > 0, "Voting: Vote hasn't been called for this proposal");
require(proposal.yayVotes + proposal.nayVotes >= QUORUM, "Voting: Quorum hasn't been reached");
require(proposal.yayVotes > proposal.nayVotes, "Voting: Proposal hasn't passed vote");
require(block.timestamp > proposal.voteCallTime + EXECUTION_START_OFFSET, "Voting: Execution window hasn't opened");
require(block.timestamp < proposal.voteCallTime + EXECUTION_END_OFFSET, "Voting: Execution window has closed");
require(!proposal.executed, "Voting: Proposal has already been executed");
proposal.executed = true;
Call[] storage actions = proposal.actions;
for (uint256 i = 0; i < actions.length; i++) {
(bool successful, bytes memory returnData) = DELEGATOR_CONTRACT.callContract(
actions[i].callContract,
actions[i].data,
actions[i].value
);
if (!successful) {
bytes memory revertData = abi.encode(i, returnData);
assembly {
revert (add (32, revertData), mload (revertData))
}
}
}
emit Execution(_id);
}
}
{
"compilationTarget": {
"contracts/governance/Voting.sol": "Voting"
},
"evmVersion": "berlin",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 1600
},
"remappings": []
}
[{"inputs":[{"internalType":"contract Staking","name":"_stakingContract","type":"address"},{"internalType":"contract Delegator","name":"_delegator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Execution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"}],"name":"Proposal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Sponsorship","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"sponsor","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"SponsorshipRevocation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"VoteCall","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"bool","name":"affirmative","type":"bool"},{"indexed":false,"internalType":"uint256","name":"votes","type":"uint256"}],"name":"VoteCast","type":"event"},{"inputs":[],"name":"DELEGATOR_CONTRACT","outputs":[{"internalType":"contract Delegator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTION_END_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EXECUTION_START_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROPOSAL_SPONSOR_THRESHOLD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUORUM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPONSOR_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKING_CONTRACT","outputs":[{"internalType":"contract Staking","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTING_NAY_END_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTING_START_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VOTING_YAY_END_OFFSET","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"callVote","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_proposalDocument","type":"string"},{"components":[{"internalType":"address","name":"callContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Voting.Call[]","name":"_actions","type":"tuple[]"}],"name":"createProposal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"executeProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"getActions","outputs":[{"components":[{"internalType":"address","name":"callContract","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"internalType":"struct Voting.Call[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"address","name":"_account","type":"address"}],"name":"getSponsored","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"proposals","outputs":[{"internalType":"address","name":"proposer","type":"address"},{"internalType":"string","name":"proposalDocument","type":"string"},{"internalType":"uint256","name":"publishTime","type":"uint256"},{"internalType":"uint256","name":"voteCallTime","type":"uint256"},{"internalType":"uint256","name":"sponsorship","type":"uint256"},{"internalType":"bool","name":"executed","type":"bool"},{"internalType":"uint256","name":"yayVotes","type":"uint256"},{"internalType":"uint256","name":"nayVotes","type":"uint256"},{"internalType":"uint256","name":"sponsorInterval","type":"uint256"},{"internalType":"uint256","name":"votingInterval","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalsLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"sponsorProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unsponsorProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_affirmative","type":"bool"},{"internalType":"uint256","name":"_hint","type":"uint256"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]