Contract source code
pragma solidity ^0.5.3;
contract Context {
constructor () internal { }
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this;
return msg.data;
}
}
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view returns (address) {
return _owner;
}
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
library SafeMath {
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
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;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
uint256 c = a / b;
return c;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
contract Initializable {
bool public initialized;
modifier initializer() {
require(!initialized, "contract already initialized");
initialized = true;
_;
}
}
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);
}
interface IAccounts {
function isAccount(address) external view returns (bool);
function voteSignerToAccount(address) external view returns (address);
function validatorSignerToAccount(address) external view returns (address);
function attestationSignerToAccount(address) external view returns (address);
function signerToAccount(address) external view returns (address);
function getAttestationSigner(address) external view returns (address);
function getValidatorSigner(address) external view returns (address);
function getVoteSigner(address) external view returns (address);
function hasAuthorizedVoteSigner(address) external view returns (bool);
function hasAuthorizedValidatorSigner(address) external view returns (bool);
function hasAuthorizedAttestationSigner(address) external view returns (bool);
function setAccountDataEncryptionKey(bytes calldata) external;
function setMetadataURL(string calldata) external;
function setName(string calldata) external;
function setWalletAddress(address, uint8, bytes32, bytes32) external;
function setAccount(string calldata, bytes calldata, address, uint8, bytes32, bytes32) external;
function getDataEncryptionKey(address) external view returns (bytes memory);
function getWalletAddress(address) external view returns (address);
function getMetadataURL(address) external view returns (string memory);
function batchGetMetadataURL(address[] calldata)
external
view
returns (uint256[] memory, bytes memory);
function getName(address) external view returns (string memory);
function authorizeVoteSigner(address, uint8, bytes32, bytes32) external;
function authorizeValidatorSigner(address, uint8, bytes32, bytes32) external;
function authorizeValidatorSignerWithPublicKey(address, uint8, bytes32, bytes32, bytes calldata)
external;
function authorizeValidatorSignerWithKeys(
address,
uint8,
bytes32,
bytes32,
bytes calldata,
bytes calldata,
bytes calldata
) external;
function authorizeAttestationSigner(address, uint8, bytes32, bytes32) external;
function createAccount() external returns (bool);
}
interface IFeeCurrencyWhitelist {
function addToken(address) external;
function getWhitelist() external view returns (address[] memory);
}
interface IFreezer {
function isFrozen(address) external view returns (bool);
}
interface IRegistry {
function setAddressFor(string calldata, address) external;
function getAddressForOrDie(bytes32) external view returns (address);
function getAddressFor(bytes32) external view returns (address);
function isOneOf(bytes32[] calldata, address) external view returns (bool);
}
interface IElection {
function getTotalVotes() external view returns (uint256);
function getActiveVotes() external view returns (uint256);
function getTotalVotesByAccount(address) external view returns (uint256);
function markGroupIneligible(address) external;
function markGroupEligible(address, address, address) external;
function electValidatorSigners() external view returns (address[] memory);
function vote(address, uint256, address, address) external returns (bool);
function activate(address) external returns (bool);
function revokeActive(address, uint256, address, address, uint256) external returns (bool);
function revokeAllActive(address, address, address, uint256) external returns (bool);
function revokePending(address, uint256, address, address, uint256) external returns (bool);
function forceDecrementVotes(
address,
uint256,
address[] calldata,
address[] calldata,
uint256[] calldata
) external returns (uint256);
}
interface IGovernance {
function isVoting(address) external view returns (bool);
}
interface ILockedGold {
function incrementNonvotingAccountBalance(address, uint256) external;
function decrementNonvotingAccountBalance(address, uint256) external;
function getAccountTotalLockedGold(address) external view returns (uint256);
function getTotalLockedGold() external view returns (uint256);
function getPendingWithdrawals(address)
external
view
returns (uint256[] memory, uint256[] memory);
function getTotalPendingWithdrawals(address) external view returns (uint256);
function lock() external payable;
function unlock(uint256) external;
function relock(uint256, uint256) external;
function withdraw(uint256) external;
function slash(
address account,
uint256 penalty,
address reporter,
uint256 reward,
address[] calldata lessers,
address[] calldata greaters,
uint256[] calldata indices
) external;
function isSlasher(address) external view returns (bool);
}
interface IValidators {
function getAccountLockedGoldRequirement(address) external view returns (uint256);
function meetsAccountLockedGoldRequirements(address) external view returns (bool);
function getGroupNumMembers(address) external view returns (uint256);
function getGroupsNumMembers(address[] calldata) external view returns (uint256[] memory);
function getNumRegisteredValidators() external view returns (uint256);
function getTopGroupValidators(address, uint256) external view returns (address[] memory);
function updateEcdsaPublicKey(address, address, bytes calldata) external returns (bool);
function updatePublicKeys(address, address, bytes calldata, bytes calldata, bytes calldata)
external
returns (bool);
function isValidator(address) external view returns (bool);
function isValidatorGroup(address) external view returns (bool);
function calculateGroupEpochScore(uint256[] calldata uptimes) external view returns (uint256);
function groupMembershipInEpoch(address account, uint256 epochNumber, uint256 index)
external
view
returns (address);
function halveSlashingMultiplier(address group) external;
function forceDeaffiliateIfValidator(address validator) external;
function getValidatorGroupSlashingMultiplier(address) external view returns (uint256);
function affiliate(address group) external returns (bool);
}
interface IRandom {
function revealAndCommit(bytes32, bytes32, address) external;
function randomnessBlockRetentionWindow() external view returns (uint256);
function random() external view returns (bytes32);
function getBlockRandomness(uint256) external view returns (bytes32);
}
interface IAttestations {
function setAttestationRequestFee(address, uint256) external;
function request(bytes32, uint256, address) external;
function selectIssuers(bytes32) external;
function complete(bytes32, uint8, bytes32, bytes32) external;
function revoke(bytes32, uint256) external;
function withdraw(address) external;
function setAttestationExpiryBlocks(uint256) external;
function getMaxAttestations() external view returns (uint256);
function getUnselectedRequest(bytes32, address) external view returns (uint32, uint32, address);
function getAttestationRequestFee(address) external view returns (uint256);
function lookupAccountsForIdentifier(bytes32) external view returns (address[] memory);
function getAttestationStats(bytes32, address) external view returns (uint32, uint32);
function getAttestationState(bytes32, address, address)
external
view
returns (uint8, uint32, address);
function getCompletableAttestations(bytes32, address)
external
view
returns (uint32[] memory, address[] memory, uint256[] memory, bytes memory);
}
interface IExchange {
function exchange(uint256, uint256, bool) external returns (uint256);
function setUpdateFrequency(uint256) external;
function getBuyTokenAmount(uint256, bool) external view returns (uint256);
function getSellTokenAmount(uint256, bool) external view returns (uint256);
function getBuyAndSellBuckets(bool) external view returns (uint256, uint256);
}
interface IReserve {
function setTobinTaxStalenessThreshold(uint256) external;
function addToken(address) external returns (bool);
function removeToken(address, uint256) external returns (bool);
function transferGold(address payable, uint256) external returns (bool);
function transferExchangeGold(address payable, uint256) external returns (bool);
function getReserveGoldBalance() external view returns (uint256);
function getUnfrozenReserveGoldBalance() external view returns (uint256);
function getOrComputeTobinTax() external returns (uint256, uint256);
function getTokens() external view returns (address[] memory);
function getReserveRatio() external view returns (uint256);
}
interface ISortedOracles {
function addOracle(address, address) external;
function removeOracle(address, address, uint256) external;
function report(address, uint256, address, address) external;
function removeExpiredReports(address, uint256) external;
function isOldestReportExpired(address token) external view returns (bool, address);
function numRates(address) external view returns (uint256);
function medianRate(address) external view returns (uint256, uint256);
function numTimestamps(address) external view returns (uint256);
function medianTimestamp(address) external view returns (uint256);
}
interface IStableToken {
function mint(address, uint256) external returns (bool);
function burn(uint256) external returns (bool);
function setInflationParameters(uint256, uint256) external;
function valueToUnits(uint256) external view returns (uint256);
function unitsToValue(uint256) external view returns (uint256);
function getInflationParameters() external view returns (uint256, uint256, uint256, uint256);
function balanceOf(address) external view returns (uint256);
}
contract UsingRegistry is Ownable {
event RegistrySet(address indexed registryAddress);
bytes32 constant ACCOUNTS_REGISTRY_ID = keccak256(abi.encodePacked("Accounts"));
bytes32 constant ATTESTATIONS_REGISTRY_ID = keccak256(abi.encodePacked("Attestations"));
bytes32 constant DOWNTIME_SLASHER_REGISTRY_ID = keccak256(abi.encodePacked("DowntimeSlasher"));
bytes32 constant DOUBLE_SIGNING_SLASHER_REGISTRY_ID = keccak256(
abi.encodePacked("DoubleSigningSlasher")
);
bytes32 constant ELECTION_REGISTRY_ID = keccak256(abi.encodePacked("Election"));
bytes32 constant EXCHANGE_REGISTRY_ID = keccak256(abi.encodePacked("Exchange"));
bytes32 constant FEE_CURRENCY_WHITELIST_REGISTRY_ID = keccak256(
abi.encodePacked("FeeCurrencyWhitelist")
);
bytes32 constant FREEZER_REGISTRY_ID = keccak256(abi.encodePacked("Freezer"));
bytes32 constant GOLD_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("GoldToken"));
bytes32 constant GOVERNANCE_REGISTRY_ID = keccak256(abi.encodePacked("Governance"));
bytes32 constant GOVERNANCE_SLASHER_REGISTRY_ID = keccak256(
abi.encodePacked("GovernanceSlasher")
);
bytes32 constant LOCKED_GOLD_REGISTRY_ID = keccak256(abi.encodePacked("LockedGold"));
bytes32 constant RESERVE_REGISTRY_ID = keccak256(abi.encodePacked("Reserve"));
bytes32 constant RANDOM_REGISTRY_ID = keccak256(abi.encodePacked("Random"));
bytes32 constant SORTED_ORACLES_REGISTRY_ID = keccak256(abi.encodePacked("SortedOracles"));
bytes32 constant STABLE_TOKEN_REGISTRY_ID = keccak256(abi.encodePacked("StableToken"));
bytes32 constant VALIDATORS_REGISTRY_ID = keccak256(abi.encodePacked("Validators"));
IRegistry public registry;
modifier onlyRegisteredContract(bytes32 identifierHash) {
require(registry.getAddressForOrDie(identifierHash) == msg.sender, "only registered contract");
_;
}
modifier onlyRegisteredContracts(bytes32[] memory identifierHashes) {
require(registry.isOneOf(identifierHashes, msg.sender), "only registered contracts");
_;
}
function setRegistry(address registryAddress) public onlyOwner {
require(registryAddress != address(0), "Cannot register the null address");
registry = IRegistry(registryAddress);
emit RegistrySet(registryAddress);
}
function getAccounts() internal view returns (IAccounts) {
return IAccounts(registry.getAddressForOrDie(ACCOUNTS_REGISTRY_ID));
}
function getAttestations() internal view returns (IAttestations) {
return IAttestations(registry.getAddressForOrDie(ATTESTATIONS_REGISTRY_ID));
}
function getElection() internal view returns (IElection) {
return IElection(registry.getAddressForOrDie(ELECTION_REGISTRY_ID));
}
function getExchange() internal view returns (IExchange) {
return IExchange(registry.getAddressForOrDie(EXCHANGE_REGISTRY_ID));
}
function getFeeCurrencyWhitelistRegistry() internal view returns (IFeeCurrencyWhitelist) {
return IFeeCurrencyWhitelist(registry.getAddressForOrDie(FEE_CURRENCY_WHITELIST_REGISTRY_ID));
}
function getFreezer() internal view returns (IFreezer) {
return IFreezer(registry.getAddressForOrDie(FREEZER_REGISTRY_ID));
}
function getGoldToken() internal view returns (IERC20) {
return IERC20(registry.getAddressForOrDie(GOLD_TOKEN_REGISTRY_ID));
}
function getGovernance() internal view returns (IGovernance) {
return IGovernance(registry.getAddressForOrDie(GOVERNANCE_REGISTRY_ID));
}
function getLockedGold() internal view returns (ILockedGold) {
return ILockedGold(registry.getAddressForOrDie(LOCKED_GOLD_REGISTRY_ID));
}
function getRandom() internal view returns (IRandom) {
return IRandom(registry.getAddressForOrDie(RANDOM_REGISTRY_ID));
}
function getReserve() internal view returns (IReserve) {
return IReserve(registry.getAddressForOrDie(RESERVE_REGISTRY_ID));
}
function getSortedOracles() internal view returns (ISortedOracles) {
return ISortedOracles(registry.getAddressForOrDie(SORTED_ORACLES_REGISTRY_ID));
}
function getStableToken() internal view returns (IStableToken) {
return IStableToken(registry.getAddressForOrDie(STABLE_TOKEN_REGISTRY_ID));
}
function getValidators() internal view returns (IValidators) {
return IValidators(registry.getAddressForOrDie(VALIDATORS_REGISTRY_ID));
}
}
contract GovernanceSlasher is Ownable, Initializable, UsingRegistry {
using SafeMath for uint256;
mapping(address => uint256) slashed;
event SlashingApproved(address indexed account, uint256 amount);
event GovernanceSlashPerformed(address indexed account, uint256 amount);
function initialize(address registryAddress) external initializer {
_transferOwnership(msg.sender);
setRegistry(registryAddress);
}
function approveSlashing(address account, uint256 penalty) external onlyOwner {
slashed[account] = slashed[account].add(penalty);
emit SlashingApproved(account, penalty);
}
function getApprovedSlashing(address account) external view returns (uint256) {
return slashed[account];
}
function slash(
address account,
address[] calldata electionLessers,
address[] calldata electionGreaters,
uint256[] calldata electionIndices
) external returns (bool) {
uint256 penalty = slashed[account];
require(penalty > 0, "No penalty given by governance");
slashed[account] = 0;
getLockedGold().slash(
account,
penalty,
address(0),
0,
electionLessers,
electionGreaters,
electionIndices
);
emit GovernanceSlashPerformed(account, penalty);
return true;
}
}
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"initialized","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"approveSlashing","inputs":[{"type":"address","name":"account"},{"type":"uint256","name":"penalty"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"registry","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"isOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setRegistry","inputs":[{"type":"address","name":"registryAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"registryAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[{"type":"bool","name":""}],"name":"slash","inputs":[{"type":"address","name":"account"},{"type":"address[]","name":"electionLessers"},{"type":"address[]","name":"electionGreaters"},{"type":"uint256[]","name":"electionIndices"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"getApprovedSlashing","inputs":[{"type":"address","name":"account"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner"}],"constant":false},{"type":"event","name":"SlashingApproved","inputs":[{"type":"address","name":"account","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"GovernanceSlashPerformed","inputs":[{"type":"address","name":"account","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"RegistrySet","inputs":[{"type":"address","name":"registryAddress","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]