/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
import "../interface/RocketStorageInterface.sol";
/// @title Base settings / modifiers for each contract in Rocket Pool
/// @author David Rugendyke
abstract contract RocketBase {
// Calculate using this as the base
uint256 constant calcBase = 1 ether;
// Version of the contract
uint8 public version;
// The main storage contract where primary persistant storage is maintained
RocketStorageInterface rocketStorage = RocketStorageInterface(address(0));
/*** Modifiers **********************************************************/
/**
* @dev Throws if called by any sender that doesn't match a Rocket Pool network contract
*/
modifier onlyLatestNetworkContract() {
require(getBool(keccak256(abi.encodePacked("contract.exists", msg.sender))), "Invalid or outdated network contract");
_;
}
/**
* @dev Throws if called by any sender that doesn't match one of the supplied contract or is the latest version of that contract
*/
modifier onlyLatestContract(string memory _contractName, address _contractAddress) {
require(_contractAddress == getAddress(keccak256(abi.encodePacked("contract.address", _contractName))), "Invalid or outdated contract");
_;
}
/**
* @dev Throws if called by any sender that isn't a registered node
*/
modifier onlyRegisteredNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
_;
}
/**
* @dev Throws if called by any sender that isn't a trusted node DAO member
*/
modifier onlyTrustedNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("dao.trustednodes.", "member", _nodeAddress))), "Invalid trusted node");
_;
}
/**
* @dev Throws if called by any sender that isn't a registered minipool
*/
modifier onlyRegisteredMinipool(address _minipoolAddress) {
require(getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress))), "Invalid minipool");
_;
}
/**
* @dev Throws if called by any account other than a guardian account (temporary account allowed access to settings before DAO is fully enabled)
*/
modifier onlyGuardian() {
require(msg.sender == rocketStorage.getGuardian(), "Account is not a temporary guardian");
_;
}
/*** Methods **********************************************************/
/// @dev Set the main Rocket Storage address
constructor(RocketStorageInterface _rocketStorageAddress) {
// Update the contract address
rocketStorage = RocketStorageInterface(_rocketStorageAddress);
}
/// @dev Get the address of a network contract by name
function getContractAddress(string memory _contractName) internal view returns (address) {
// Get the current contract address
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
// Check it
require(contractAddress != address(0x0), "Contract not found");
// Return
return contractAddress;
}
/// @dev Get the address of a network contract by name (returns address(0x0) instead of reverting if contract does not exist)
function getContractAddressUnsafe(string memory _contractName) internal view returns (address) {
// Get the current contract address
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
// Return
return contractAddress;
}
/// @dev Get the name of a network contract by address
function getContractName(address _contractAddress) internal view returns (string memory) {
// Get the contract name
string memory contractName = getString(keccak256(abi.encodePacked("contract.name", _contractAddress)));
// Check it
require(bytes(contractName).length > 0, "Contract not found");
// Return
return contractName;
}
/// @dev Get revert error message from a .call method
function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
// If the _res length is less than 68, then the transaction failed silently (without a revert message)
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
// Slice the sighash.
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string)); // All that remains is the revert string
}
/*** Rocket Storage Methods ****************************************/
// Note: Unused helpers have been removed to keep contract sizes down
/// @dev Storage get methods
function getAddress(bytes32 _key) internal view returns (address) { return rocketStorage.getAddress(_key); }
function getUint(bytes32 _key) internal view returns (uint) { return rocketStorage.getUint(_key); }
function getString(bytes32 _key) internal view returns (string memory) { return rocketStorage.getString(_key); }
function getBytes(bytes32 _key) internal view returns (bytes memory) { return rocketStorage.getBytes(_key); }
function getBool(bytes32 _key) internal view returns (bool) { return rocketStorage.getBool(_key); }
function getInt(bytes32 _key) internal view returns (int) { return rocketStorage.getInt(_key); }
function getBytes32(bytes32 _key) internal view returns (bytes32) { return rocketStorage.getBytes32(_key); }
/// @dev Storage set methods
function setAddress(bytes32 _key, address _value) internal { rocketStorage.setAddress(_key, _value); }
function setUint(bytes32 _key, uint _value) internal { rocketStorage.setUint(_key, _value); }
function setString(bytes32 _key, string memory _value) internal { rocketStorage.setString(_key, _value); }
function setBytes(bytes32 _key, bytes memory _value) internal { rocketStorage.setBytes(_key, _value); }
function setBool(bytes32 _key, bool _value) internal { rocketStorage.setBool(_key, _value); }
function setInt(bytes32 _key, int _value) internal { rocketStorage.setInt(_key, _value); }
function setBytes32(bytes32 _key, bytes32 _value) internal { rocketStorage.setBytes32(_key, _value); }
/// @dev Storage delete methods
function deleteAddress(bytes32 _key) internal { rocketStorage.deleteAddress(_key); }
function deleteUint(bytes32 _key) internal { rocketStorage.deleteUint(_key); }
function deleteString(bytes32 _key) internal { rocketStorage.deleteString(_key); }
function deleteBytes(bytes32 _key) internal { rocketStorage.deleteBytes(_key); }
function deleteBool(bytes32 _key) internal { rocketStorage.deleteBool(_key); }
function deleteInt(bytes32 _key) internal { rocketStorage.deleteInt(_key); }
function deleteBytes32(bytes32 _key) internal { rocketStorage.deleteBytes32(_key); }
/// @dev Storage arithmetic methods
function addUint(bytes32 _key, uint256 _amount) internal { rocketStorage.addUint(_key, _amount); }
function subUint(bytes32 _key, uint256 _amount) internal { rocketStorage.subUint(_key, _amount); }
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity 0.7.6;
// SPDX-License-Identifier: GPL-3.0-only
import "../RocketBase.sol";
import "../../interface/dao/RocketDAOProposalInterface.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
// A DAO proposal
contract RocketDAOProposal is RocketBase, RocketDAOProposalInterface {
using SafeMath for uint;
// Events
event ProposalAdded(address indexed proposer, string indexed proposalDAO, uint256 indexed proposalID, bytes payload, uint256 time);
event ProposalVoted(uint256 indexed proposalID, address indexed voter, bool indexed supported, uint256 time);
event ProposalExecuted(uint256 indexed proposalID, address indexed executor, uint256 time);
event ProposalCancelled(uint256 indexed proposalID, address indexed canceller, uint256 time);
// The namespace for any data stored in the trusted node DAO (do not change)
string constant private daoProposalNameSpace = "dao.proposal.";
// Only allow the DAO contract to access
modifier onlyDAOContract(string memory _daoName) {
// Load contracts
require(keccak256(abi.encodePacked(getContractName(msg.sender))) == keccak256(abi.encodePacked(_daoName)), "Sender is not the required DAO contract");
_;
}
// Construct
constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
// Version
version = 2;
}
/*** Proposals ****************/
// Get the current total proposals
function getTotal() override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "total")));
}
// Get the DAO that this proposal belongs too
function getDAO(uint256 _proposalID) override public view returns (string memory) {
return getString(keccak256(abi.encodePacked(daoProposalNameSpace, "dao", _proposalID)));
}
// Get the member who proposed
function getProposer(uint256 _proposalID) override public view returns (address) {
return getAddress(keccak256(abi.encodePacked(daoProposalNameSpace, "proposer", _proposalID)));
}
// Get the proposal message
function getMessage(uint256 _proposalID) override external view returns (string memory) {
return getString(keccak256(abi.encodePacked(daoProposalNameSpace, "message", _proposalID)));
}
// Get the start block of this proposal
function getStart(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "start", _proposalID)));
}
// Get the end block of this proposal
function getEnd(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "end", _proposalID)));
}
// The block where the proposal expires and can no longer be executed if it is successful
function getExpires(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "expires", _proposalID)));
}
// Get the created status of this proposal
function getCreated(uint256 _proposalID) override external view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "created", _proposalID)));
}
// Get the votes count for this proposal
function getVotesFor(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.for", _proposalID)));
}
// Get the votes count against this proposal
function getVotesAgainst(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.against", _proposalID)));
}
// How many votes are required for the proposal to succeed
function getVotesRequired(uint256 _proposalID) override public view returns (uint256) {
return getUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.required", _proposalID)));
}
// Get the cancelled status of this proposal
function getCancelled(uint256 _proposalID) override public view returns (bool) {
return getBool(keccak256(abi.encodePacked(daoProposalNameSpace, "cancelled", _proposalID)));
}
// Get the executed status of this proposal
function getExecuted(uint256 _proposalID) override public view returns (bool) {
return getBool(keccak256(abi.encodePacked(daoProposalNameSpace, "executed", _proposalID)));
}
// Get the votes against count of this proposal
function getPayload(uint256 _proposalID) override public view returns (bytes memory) {
return getBytes(keccak256(abi.encodePacked(daoProposalNameSpace, "payload", _proposalID)));
}
// Returns true if this proposal has already been voted on by a member
function getReceiptHasVoted(uint256 _proposalID, address _nodeAddress) override public view returns (bool) {
return getBool(keccak256(abi.encodePacked(daoProposalNameSpace, "receipt.hasVoted", _proposalID, _nodeAddress)));
}
// Returns true if this proposal was supported by this member
function getReceiptSupported(uint256 _proposalID, address _nodeAddress) override external view returns (bool) {
return getBool(keccak256(abi.encodePacked(daoProposalNameSpace, "receipt.supported", _proposalID, _nodeAddress)));
}
// Return the state of the specified proposal
// A successful proposal can be executed immediately
function getState(uint256 _proposalID) override public view returns (ProposalState) {
// Check the proposal ID is legit
require(getTotal() >= _proposalID && _proposalID > 0, "Invalid proposal ID");
// Get the amount of votes for and against
uint256 votesFor = getVotesFor(_proposalID);
uint256 votesAgainst = getVotesAgainst(_proposalID);
// Now return the state of the current proposal
if (getCancelled(_proposalID)) {
// Cancelled by the proposer?
return ProposalState.Cancelled;
// Has it been executed?
} else if (getExecuted(_proposalID)) {
return ProposalState.Executed;
// Is the proposal pending? Eg. waiting to be voted on
} else if (block.timestamp < getStart(_proposalID)) {
return ProposalState.Pending;
// Vote was successful, is now awaiting execution
} else if (votesFor >= getVotesRequired(_proposalID) && block.timestamp < getExpires(_proposalID)) {
return ProposalState.Succeeded;
// The proposal is active and can be voted on
} else if (block.timestamp < getEnd(_proposalID)) {
return ProposalState.Active;
// Check the votes, was it defeated?
} else if (votesFor <= votesAgainst || votesFor < getVotesRequired(_proposalID)) {
return ProposalState.Defeated;
} else {
// Was it successful, but has now expired? and cannot be executed anymore?
return ProposalState.Expired;
}
}
// Add a proposal to the an RP DAO, immeditately becomes active
// Calldata is passed as the payload to execute upon passing the proposal
function add(address _member, string memory _dao, string memory _message, uint256 _startTime, uint256 _duration, uint256 _expires, uint256 _votesRequired, bytes memory _payload) override external onlyDAOContract(_dao) returns (uint256) {
// Basic checks
require(_startTime > block.timestamp, "Proposal start time must be in the future");
require(_duration > 0, "Proposal cannot have a duration of 0");
require(_expires > 0, "Proposal cannot have a execution expiration of 0");
require(_votesRequired > 0, "Proposal cannot have a 0 votes required to be successful");
// Set the end block
uint256 endTime = _startTime.add(_duration);
// Set the expires block
uint256 expires = endTime.add(_expires);
// Get the proposal ID
uint256 proposalID = getTotal().add(1);
// The data structure for a proposal
setAddress(keccak256(abi.encodePacked(daoProposalNameSpace, "proposer", proposalID)), _member); // Which member is making the proposal
setString(keccak256(abi.encodePacked(daoProposalNameSpace, "dao", proposalID)), _dao); // The DAO the proposal relates too
setString(keccak256(abi.encodePacked(daoProposalNameSpace, "message", proposalID)), _message); // A general message that can be included with the proposal
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "start", proposalID)), _startTime); // The time the proposal becomes active for voting on
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "end", proposalID)), endTime); // The time the proposal where voting ends
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "expires", proposalID)), expires); // The time when the proposal expires and can no longer be executed if it is successful
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "created", proposalID)), block.timestamp); // The time the proposal was created at
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.for", proposalID)), 0); // Votes for this proposal
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.against", proposalID)), 0); // Votes against this proposal
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.required", proposalID)), _votesRequired); // How many votes are required for the proposal to pass
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "cancelled", proposalID)), false); // The proposer can cancel this proposal, but only before it passes
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "executed", proposalID)), false); // Has this proposals calldata been executed?
setBytes(keccak256(abi.encodePacked(daoProposalNameSpace, "payload", proposalID)), _payload); // A calldata payload to execute after it is successful
// Update the total proposals
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "total")), proposalID);
// Log it
emit ProposalAdded(_member, _dao, proposalID, _payload, block.timestamp);
// Done
return proposalID;
}
// Voting for or against a proposal
function vote(address _member, uint256 _votes, uint256 _proposalID, bool _support) override external onlyDAOContract(getDAO(_proposalID)) {
// Successful proposals can be executed immediately, add this as a check for people who are still trying to vote after it has passed
require(getState(_proposalID) != ProposalState.Succeeded, "Proposal has passed, voting is complete and the proposal can now be executed");
// Check the proposal is in a state that can be voted on
require(getState(_proposalID) == ProposalState.Active, "Voting is not active for this proposal");
// Has this member already voted on this proposal?
require(!getReceiptHasVoted(_proposalID, _member), "Member has already voted on proposal");
// Add votes to proposal
if(_support) {
addUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.for", _proposalID)), _votes);
}else{
addUint(keccak256(abi.encodePacked(daoProposalNameSpace, "votes.against", _proposalID)), _votes);
}
// Record the vote receipt now
setUint(keccak256(abi.encodePacked(daoProposalNameSpace, "receipt.votes", _proposalID, _member)), _votes);
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "receipt.hasVoted", _proposalID, _member)), true);
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "receipt.supported", _proposalID, _member)), _support);
// Log it
emit ProposalVoted(_proposalID, _member, _support, block.timestamp);
}
// Execute a proposal if it has passed
function execute(uint256 _proposalID) override external {
// Firstly make sure this proposal has passed
require(getState(_proposalID) == ProposalState.Succeeded, "Proposal has not succeeded, has expired or has already been executed");
// Set as executed now before running payload
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "executed", _proposalID)), true);
// Ok all good, lets run the payload on the dao contract that the proposal relates too, it should execute one of the methods on this contract
(bool success, bytes memory response) = getContractAddress(getDAO(_proposalID)).call(getPayload(_proposalID));
// Was there an error?
require(success, getRevertMsg(response));
// Log it
emit ProposalExecuted(_proposalID, tx.origin, block.timestamp);
}
// Cancel a proposal, can be cancelled by the original proposer only if it hasn't been executed yet
function cancel(address _member, uint256 _proposalID) override external onlyDAOContract(getDAO(_proposalID)) {
// Firstly make sure this proposal can be cancelled
require(getState(_proposalID) == ProposalState.Pending || getState(_proposalID) == ProposalState.Active, "Proposal can only be cancelled if pending or active");
// Only allow the proposer to cancel
require(getProposer(_proposalID) == _member, "Proposal can only be cancelled by the proposer");
// Set as cancelled now
setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "cancelled", _proposalID)), true);
// Log it
emit ProposalCancelled(_proposalID, _member, block.timestamp);
}
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
interface RocketDAOProposalInterface {
// Possible states that a proposal may be in
enum ProposalState {
Pending,
Active,
Cancelled,
Defeated,
Succeeded,
Expired,
Executed
}
function getTotal() external view returns (uint256);
function getDAO(uint256 _proposalID) external view returns (string memory);
function getProposer(uint256 _proposalID) external view returns (address);
function getMessage(uint256 _proposalID) external view returns (string memory);
function getStart(uint256 _proposalID) external view returns (uint256);
function getEnd(uint256 _proposalID) external view returns (uint256);
function getExpires(uint256 _proposalID) external view returns (uint256);
function getCreated(uint256 _proposalID) external view returns (uint256);
function getVotesFor(uint256 _proposalID) external view returns (uint256);
function getVotesAgainst(uint256 _proposalID) external view returns (uint256);
function getVotesRequired(uint256 _proposalID) external view returns (uint256);
function getCancelled(uint256 _proposalID) external view returns (bool);
function getExecuted(uint256 _proposalID) external view returns (bool);
function getPayload(uint256 _proposalID) external view returns (bytes memory);
function getReceiptHasVoted(uint256 _proposalID, address _nodeAddress) external view returns (bool);
function getReceiptSupported(uint256 _proposalID, address _nodeAddress) external view returns (bool);
function getState(uint256 _proposalID) external view returns (ProposalState);
function add(address _member, string memory _dao, string memory _message, uint256 _startBlock, uint256 _durationBlocks, uint256 _expiresBlocks, uint256 _votesRequired, bytes memory _payload) external returns (uint256);
function vote(address _member, uint256 _votes, uint256 _proposalID, bool _support) external;
function cancel(address _member, uint256 _proposalID) external;
function execute(uint256 _proposalID) external;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
interface RocketStorageInterface {
// Deploy status
function getDeployedStatus() external view returns (bool);
// Guardian
function getGuardian() external view returns(address);
function setGuardian(address _newAddress) external;
function confirmGuardian() external;
// Getters
function getAddress(bytes32 _key) external view returns (address);
function getUint(bytes32 _key) external view returns (uint);
function getString(bytes32 _key) external view returns (string memory);
function getBytes(bytes32 _key) external view returns (bytes memory);
function getBool(bytes32 _key) external view returns (bool);
function getInt(bytes32 _key) external view returns (int);
function getBytes32(bytes32 _key) external view returns (bytes32);
// Setters
function setAddress(bytes32 _key, address _value) external;
function setUint(bytes32 _key, uint _value) external;
function setString(bytes32 _key, string calldata _value) external;
function setBytes(bytes32 _key, bytes calldata _value) external;
function setBool(bytes32 _key, bool _value) external;
function setInt(bytes32 _key, int _value) external;
function setBytes32(bytes32 _key, bytes32 _value) external;
// Deleters
function deleteAddress(bytes32 _key) external;
function deleteUint(bytes32 _key) external;
function deleteString(bytes32 _key) external;
function deleteBytes(bytes32 _key) external;
function deleteBool(bytes32 _key) external;
function deleteInt(bytes32 _key) external;
function deleteBytes32(bytes32 _key) external;
// Arithmetic
function addUint(bytes32 _key, uint256 _amount) external;
function subUint(bytes32 _key, uint256 _amount) external;
// Protected storage
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
function confirmWithdrawalAddress(address _nodeAddress) external;
}
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @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, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, 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 (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
/**
* @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) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
/**
* @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) {
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, reverting 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) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting 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) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* 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);
return a - b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* 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) {
require(b > 0, errorMessage);
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* 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;
}
}
{
"compilationTarget": {
"contracts/contract/dao/RocketDAOProposal.sol": "RocketDAOProposal"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 15000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract RocketStorageInterface","name":"_rocketStorageAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":true,"internalType":"string","name":"proposalDAO","type":"string"},{"indexed":true,"internalType":"uint256","name":"proposalID","type":"uint256"},{"indexed":false,"internalType":"bytes","name":"payload","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ProposalAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalID","type":"uint256"},{"indexed":true,"internalType":"address","name":"canceller","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ProposalCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalID","type":"uint256"},{"indexed":true,"internalType":"address","name":"executor","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalID","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":true,"internalType":"bool","name":"supported","type":"bool"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ProposalVoted","type":"event"},{"inputs":[{"internalType":"address","name":"_member","type":"address"},{"internalType":"string","name":"_dao","type":"string"},{"internalType":"string","name":"_message","type":"string"},{"internalType":"uint256","name":"_startTime","type":"uint256"},{"internalType":"uint256","name":"_duration","type":"uint256"},{"internalType":"uint256","name":"_expires","type":"uint256"},{"internalType":"uint256","name":"_votesRequired","type":"uint256"},{"internalType":"bytes","name":"_payload","type":"bytes"}],"name":"add","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"},{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"cancel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getCancelled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getCreated","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getDAO","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getEnd","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getExpires","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getMessage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getPayload","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getProposer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"},{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getReceiptHasVoted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"},{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getReceiptSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getStart","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getState","outputs":[{"internalType":"enum RocketDAOProposalInterface.ProposalState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getVotesAgainst","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getVotesFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_proposalID","type":"uint256"}],"name":"getVotesRequired","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_member","type":"address"},{"internalType":"uint256","name":"_votes","type":"uint256"},{"internalType":"uint256","name":"_proposalID","type":"uint256"},{"internalType":"bool","name":"_support","type":"bool"}],"name":"vote","outputs":[],"stateMutability":"nonpayable","type":"function"}]