// File: contracts/lib/Context.sol
// From package @openzeppelin/contracts@2.4.0
pragma solidity 0.5.8;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// File: contracts/lib/Ownable.sol
// From package @openzeppelin/contracts@2.4.0
pragma solidity 0.5.8;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
_owner = _msgSender();
emit OwnershipTransferred(address(0), _owner);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(isOwner(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Returns true if the caller is the current owner.
*/
function isOwner() public view returns (bool) {
return _msgSender() == _owner;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public onlyOwner {
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
*/
function _transferOwnership(address newOwner) internal {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// File: contracts/lib/SafeMath.sol
// From package @openzeppelin/contracts@2.4.0
pragma solidity 0.5.8;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*
* _Available since v2.4.0._
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*
* _Available since v2.4.0._
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File: contracts/lib/lib.sol
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/*
Everest is using the dai contracts to mock the real dai that will be used.
This contract lives here: https://github.com/makerdao/dss/blob/master/src/lib.sol
Also we changed the pragma from 0.5.12 to ^0.5.8
*/
pragma solidity 0.5.8;
contract LibNote {
event LogNote(
bytes4 indexed sig,
address indexed usr,
bytes32 indexed arg1,
bytes32 indexed arg2,
bytes data
) anonymous;
modifier note {
_;
/* solium-disable-next-line security/no-inline-assembly*/
assembly {
// log an 'anonymous' event with a constant 6 words of calldata
// and four indexed topics: selector, caller, arg1 and arg2
let mark := msize // end of memory ensures zero
mstore(0x40, add(mark, 288)) // update free memory pointer
mstore(mark, 0x20) // bytes type data offset
mstore(add(mark, 0x20), 224) // bytes size (padded)
calldatacopy(add(mark, 0x40), 0, 224) // bytes payload
log4(mark, 288, // calldata
shl(224, shr(224, calldataload(0))), // msg.sig
caller, // msg.sender
calldataload(4), // arg1
calldataload(36) // arg2
)
}
}
}
// File: contracts/lib/dai.sol
// Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
/*
Everest is using the dai contracts to mock the real dai that will be used.
This contract lives here: https://github.com/makerdao/dss/blob/master/src/dai.sol
Also we changed the pragma from 0.5.12 to ^0.5.8
*/
pragma solidity 0.5.8;
contract Dai is LibNote {
// --- Auth ---
mapping (address => uint) public wards;
function rely(address guy) external note auth { wards[guy] = 1; }
function deny(address guy) external note auth { wards[guy] = 0; }
modifier auth {
require(wards[msg.sender] == 1, "Dai/not-authorized");
_;
}
// --- ERC20 Data ---
string public constant name = "Dai Stablecoin";
string public constant symbol = "DAI";
string public constant version = "1";
uint8 public constant decimals = 18;
uint256 public totalSupply;
mapping (address => uint) public balanceOf;
mapping (address => mapping (address => uint)) public allowance;
mapping (address => uint) public nonces;
event Approval(address indexed src, address indexed guy, uint wad);
event Transfer(address indexed src, address indexed dst, uint wad);
// --- Math ---
function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x);
}
function sub(uint x, uint y) internal pure returns (uint z) {
require((z = x - y) <= x);
}
// --- EIP712 niceties ---
bytes32 public DOMAIN_SEPARATOR;
// bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
constructor(uint256 chainId_) public {
wards[msg.sender] = 1;
DOMAIN_SEPARATOR = keccak256(abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256(bytes(version)),
chainId_,
address(this)
));
}
// --- Token ---
function transfer(address dst, uint wad) external returns (bool) {
return transferFrom(msg.sender, dst, wad);
}
function transferFrom(address src, address dst, uint wad)
public returns (bool)
{
require(balanceOf[src] >= wad, "Dai/insufficient-balance");
if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
}
balanceOf[src] = sub(balanceOf[src], wad);
balanceOf[dst] = add(balanceOf[dst], wad);
emit Transfer(src, dst, wad);
return true;
}
function mint(address usr, uint wad) external auth {
balanceOf[usr] = add(balanceOf[usr], wad);
totalSupply = add(totalSupply, wad);
emit Transfer(address(0), usr, wad);
}
function burn(address usr, uint wad) external {
require(balanceOf[usr] >= wad, "Dai/insufficient-balance");
if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance");
allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
}
balanceOf[usr] = sub(balanceOf[usr], wad);
totalSupply = sub(totalSupply, wad);
emit Transfer(usr, address(0), wad);
}
function approve(address usr, uint wad) external returns (bool) {
allowance[msg.sender][usr] = wad;
emit Approval(msg.sender, usr, wad);
return true;
}
// --- Alias ---
function push(address usr, uint wad) external {
transferFrom(msg.sender, usr, wad);
}
function pull(address usr, uint wad) external {
transferFrom(usr, msg.sender, wad);
}
function move(address src, address dst, uint wad) external {
transferFrom(src, dst, wad);
}
// --- Approve by signature ---
function permit(address holder, address spender, uint256 nonce, uint256 expiry,
bool allowed, uint8 v, bytes32 r, bytes32 s) external
{
bytes32 digest =
keccak256(abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH,
holder,
spender,
nonce,
expiry,
allowed))
));
require(holder != address(0), "Dai/invalid-address-0");
require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
require(expiry == 0 || now <= expiry, "Dai/permit-expired");
require(nonce == nonces[holder]++, "Dai/invalid-nonce");
uint wad = allowed ? uint(-1) : 0;
allowance[holder][spender] = wad;
emit Approval(holder, spender, wad);
}
}
// File: contracts/lib/AddressUtils.sol
// Taken from
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
pragma solidity 0.5.8;
/**
* @dev Collection of functions related to the address type
*/
library AddressUtils {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// According to EIP-1052, 0x0 is the value returned for not-yet created accounts
// and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
// for accounts without code, i.e. `keccak256('')`
bytes32 codehash;
bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
// solhint-disable-next-line no-inline-assembly
assembly { codehash := extcodehash(account) }
return (codehash != accountHash && codehash != 0x0);
}
}
// File: contracts/ReserveBank.sol
pragma solidity 0.5.8;
/* Note, in Everest V1, the Reserve Bank is not upgradeable.
* What will be done is when Everest V2 is deployed, all the tokens
* stored in the Reserve Bank will be transferred to the new Reserve Bank.
* The new Reverse Bank is likely to be upgradeable, and have more functionality.
* However, the ownership of ReserveBank can still be transferred by the Everest owner
*
* Also, when the switch over happens from V1 to V2, it is okay the empty the reserve bank right
* away. This is because all existing challenges will fail on V1, since Everest V1 will no
* longer be the owner of the Registry, and any challenge will not be able to withdraw
* from the Reserve Bank.
*/
contract ReserveBank is Ownable {
using SafeMath for uint256;
using AddressUtils for address;
Dai public token;
constructor(address _daiAddress) public {
require(_daiAddress.isContract(), "The address should be a contract");
token = Dai(_daiAddress);
}
/**
@dev Allow the owner of the contract (Everest) to withdraw the funds.
@param _receiver The address receiving the tokens
@param _amount The amount being withdrawn
@return True if successful
*/
function withdraw(address _receiver, uint256 _amount)
external
onlyOwner
returns (bool)
{
require(_receiver != address(0), "Receiver must not be 0 address");
return token.transfer(_receiver, _amount);
}
}
// File: contracts/Registry.sol
pragma solidity 0.5.8;
contract Registry is Ownable {
// ------
// STATE
// ------
struct Member {
uint256 challengeID;
uint256 memberStartTime; // Used for voting: voteWeight = sqrt(now - memberStartTime)
}
// Note, this address is used to map to the owner and delegates in the ERC-1056 registry
mapping(address => Member) public members;
// -----------------
// GETTER FUNCTIONS
// -----------------
/**
@dev Get the challenge ID of a Member. If no challenge exists it returns 0
@param _member The member being checked
@return The challengeID
*/
function getChallengeID(address _member) external view returns (uint256) {
require(_member != address(0), "Can't check 0 address");
Member memory member = members[_member];
return member.challengeID;
}
/**
@dev Get the start time of a Member. If no time exists it returns 0
@param _member The member being checked
@return The start time
*/
function getMemberStartTime(address _member) external view returns (uint256) {
require(_member != address(0), "Can't check 0 address");
Member memory member = members[_member];
return member.memberStartTime;
}
// -----------------
// SETTER FUNCTIONS
// -----------------
/**
@dev Set a member in the Registry. Only Everest can call this function.
@param _member The member being added
@return The start time of the member
*/
function setMember(address _member) external onlyOwner returns (uint256) {
require(_member != address(0), "Can't check 0 address");
Member memory member = Member({
challengeID: 0,
/* solium-disable-next-line security/no-block-members*/
memberStartTime: now
});
members[_member] = member;
/* solium-disable-next-line security/no-block-members*/
return now;
}
/**
@dev Edit the challengeID. Can be used to set a challenge or remove a
challenge for a member. Only Everest can call.
@param _member The member being checked
@param _newChallengeID The new challenge ID. Pass in 0 to remove a challenge.
*/
function editChallengeID(address _member, uint256 _newChallengeID) external onlyOwner {
require(_member != address(0), "Can't check 0 address");
Member storage member = members[_member];
member.challengeID = _newChallengeID;
}
/**
@dev Remove a member. Only Everest can call
@param _member The member being removed
*/
function deleteMember(address _member) external onlyOwner {
require(_member != address(0), "Can't check 0 address");
delete members[_member];
}
}
// File: contracts/lib/EthereumDIDRegistry.sol
/*
Original Author: https://github.com/uport-project/ethr-did-registry
Pragma has been changed for this document from what is deployed on mainnet.
This shouldn"t pose a problem, but it means a lot of syntax has been changed.
This contract is only used for testing. On mainnet, we will use the existing
DID registry: https://etherscan.io/address/0xdca7ef03e98e0dc2b855be647c39abe984fcf21b#code
This contract is also deployed on all testnets, which can be found here:
https://github.com/uport-project/ethr-did-registry
This contract is included in this repository for testing purposes on ganache. For deploying
to testnets or mainnet, it will never be included in the deploy script, since we will use the
deployed versions in the above link.
*/
pragma solidity 0.5.8;
contract EthereumDIDRegistry {
mapping(address => address) public owners;
mapping(address => mapping(bytes32 => mapping(address => uint256))) public delegates;
mapping(address => uint256) public changed;
mapping(address => uint256) public nonce;
modifier onlyOwner(address identity, address actor) {
require(actor == identityOwner(identity), "Caller must be the identity owner");
_;
}
event DIDOwnerChanged(address indexed identity, address owner, uint256 previousChange);
event DIDDelegateChanged(
address indexed identity,
bytes32 delegateType,
address delegate,
uint256 validTo,
uint256 previousChange
);
event DIDAttributeChanged(
address indexed identity,
bytes32 name,
bytes value,
uint256 validTo,
uint256 previousChange
);
function identityOwner(address identity) public view returns (address) {
address owner = owners[identity];
if (owner != address(0)) {
return owner;
}
return identity;
}
function checkSignature(address identity, uint8 sigV, bytes32 sigR, bytes32 sigS, bytes32 hash)
internal
returns (address)
{
address signer = ecrecover(hash, sigV, sigR, sigS);
require(signer == identityOwner(identity), "Signer must be the identity owner");
nonce[signer]++;
return signer;
}
function validDelegate(address identity, bytes32 delegateType, address delegate)
public
view
returns (bool)
{
uint256 validity = delegates[identity][keccak256(abi.encode(delegateType))][delegate];
/* solium-disable-next-line security/no-block-members*/
return (validity > now);
}
function changeOwner(address identity, address actor, address newOwner)
internal
onlyOwner(identity, actor)
{
owners[identity] = newOwner;
emit DIDOwnerChanged(identity, newOwner, changed[identity]);
changed[identity] = block.number;
}
function changeOwner(address identity, address newOwner) public {
changeOwner(identity, msg.sender, newOwner);
}
function changeOwnerSigned(
address identity,
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
address newOwner
) public {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
this,
nonce[identityOwner(identity)],
identity,
"changeOwner",
newOwner
)
);
changeOwner(identity, checkSignature(identity, sigV, sigR, sigS, hash), newOwner);
}
function addDelegate(
address identity,
address actor,
bytes32 delegateType,
address delegate,
uint256 validity
) internal onlyOwner(identity, actor) {
/* solium-disable-next-line security/no-block-members*/
delegates[identity][keccak256(abi.encode(delegateType))][delegate] = now + validity;
emit DIDDelegateChanged(
identity,
delegateType,
delegate,
/* solium-disable-next-line security/no-block-members*/
now + validity,
changed[identity]
);
changed[identity] = block.number;
}
function addDelegate(address identity, bytes32 delegateType, address delegate, uint256 validity)
public
{
addDelegate(identity, msg.sender, delegateType, delegate, validity);
}
function addDelegateSigned(
address identity,
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
bytes32 delegateType,
address delegate,
uint256 validity
) public {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
this,
nonce[identityOwner(identity)],
identity,
"addDelegate",
delegateType,
delegate,
validity
)
);
addDelegate(
identity,
checkSignature(identity, sigV, sigR, sigS, hash),
delegateType,
delegate,
validity
);
}
function revokeDelegate(address identity, address actor, bytes32 delegateType, address delegate)
internal
onlyOwner(identity, actor)
{
/* solium-disable-next-line security/no-block-members*/
delegates[identity][keccak256(abi.encode(delegateType))][delegate] = now;
/* solium-disable-next-line security/no-block-members*/
emit DIDDelegateChanged(identity, delegateType, delegate, now, changed[identity]);
changed[identity] = block.number;
}
function revokeDelegate(address identity, bytes32 delegateType, address delegate) public {
revokeDelegate(identity, msg.sender, delegateType, delegate);
}
function revokeDelegateSigned(
address identity,
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
bytes32 delegateType,
address delegate
) public {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
this,
nonce[identityOwner(identity)],
identity,
"revokeDelegate",
delegateType,
delegate
)
);
revokeDelegate(
identity,
checkSignature(identity, sigV, sigR, sigS, hash),
delegateType,
delegate
);
}
function setAttribute(
address identity,
address actor,
bytes32 name,
bytes memory value,
uint256 validity
) internal onlyOwner(identity, actor) {
/* solium-disable-next-line security/no-block-members*/
emit DIDAttributeChanged(identity, name, value, now + validity, changed[identity]);
changed[identity] = block.number;
}
function setAttribute(address identity, bytes32 name, bytes memory value, uint256 validity)
public
{
setAttribute(identity, msg.sender, name, value, validity);
}
function setAttributeSigned(
address identity,
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
bytes32 name,
bytes memory value,
uint256 validity
) public {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
this,
nonce[identityOwner(identity)],
identity,
"setAttribute",
name,
value,
validity
)
);
setAttribute(
identity,
checkSignature(identity, sigV, sigR, sigS, hash),
name,
value,
validity
);
}
function revokeAttribute(address identity, address actor, bytes32 name, bytes memory value)
internal
onlyOwner(identity, actor)
{
emit DIDAttributeChanged(identity, name, value, 0, changed[identity]);
changed[identity] = block.number;
}
function revokeAttribute(address identity, bytes32 name, bytes memory value) public {
revokeAttribute(identity, msg.sender, name, value);
}
function revokeAttributeSigned(
address identity,
uint8 sigV,
bytes32 sigR,
bytes32 sigS,
bytes32 name,
bytes memory value
) public {
bytes32 hash = keccak256(
abi.encodePacked(
bytes1(0x19),
bytes1(0),
this,
nonce[identityOwner(identity)],
identity,
"revokeAttribute",
name,
value
)
);
revokeAttribute(identity, checkSignature(identity, sigV, sigR, sigS, hash), name, value);
}
}
// File: contracts/abdk-libraries-solidity/ABDKMath64x64.sol
/*
* TheGraph is using this software as described in the README.md in this folder
* https://github.com/abdk-consulting/abdk-libraries-solidity/tree/939f0a264f2d07a9e2c7a3a020f0db2c0885dc01
*
* This library has been significantly reduced to only include the functions needed for Everest
* Please visit the library at the link above for more details
*/
/*
* ABDK Math 64.64 Smart Contract Library. Copyright © 2019 by ABDK Consulting.
* Author: Mikhail Vladimirov <mikhail.vladimirov@gmail.com>
*/
pragma solidity 0.5.8;
/**
* Smart contract library of mathematical functions operating with signed
* 64.64-bit fixed point numbers. Signed 64.64-bit fixed point number is
* basically a simple fraction whose numerator is signed 128-bit integer and
* denominator is 2^64. As long as denominator is always the same, there is no
* need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
* represented by int128 type holding only the numerator.
*/
library ABDKMath64x64 {
/**
* Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
* number. Revert on overflow.
*
* @param x unsigned 256-bit integer number
* @return signed 64.64-bit fixed point number
*/
function fromUInt (uint256 x) internal pure returns (int128) {
require (x <= 0x7FFFFFFFFFFFFFFF);
return int128 (x << 64);
}
/**
* Convert signed 64.64 fixed point number into unsigned 64-bit integer
* number rounding down. Revert on underflow.
*
* @param x signed 64.64-bit fixed point number
* @return unsigned 64-bit integer number
*/
function toUInt (int128 x) internal pure returns (uint64) {
require (x >= 0);
return uint64 (x >> 64);
}
/**
* Calculate sqrt (x) rounding down. Revert if x < 0.
*
* @param x signed 64.64-bit fixed point number
* @return signed 64.64-bit fixed point number
*/
function sqrt (int128 x) internal pure returns (int128) {
require (x >= 0);
return int128 (sqrtu (uint256 (x) << 64, 0x10000000000000000));
}
/**
* Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
* number.
*
* @param x unsigned 256-bit integer number
* @return unsigned 128-bit integer number
*/
function sqrtu (uint256 x, uint256 r) private pure returns (uint128) {
if (x == 0) return 0;
else {
require (r > 0);
while (true) {
uint256 rr = x / r;
if (r == rr || r + 1 == rr) return uint128 (r);
else if (r == rr + 1) return uint128 (rr);
r = r + rr + 1 >> 1;
}
}
}
}
// File: contracts/Everest.sol
/*
Everest is a DAO that is designed to curate a Registry of members.
This storage of the list is in Registry. The EthereumDIDRegistry is used to store data such
as attributes and delegates and transfer of ownership. The only storage in the Everest contract
is Challenges and Votes, which can be safely removed upon completion. This allows for Everest
to be an upgradeable contract, while Registry is the persistent storage.
The DAO is inspired by the Moloch DAO smart contracts https://github.com/MolochVentures/moloch
*/
pragma solidity 0.5.8;
contract Everest is Ownable {
using SafeMath for uint256;
using ABDKMath64x64 for uint256;
using ABDKMath64x64 for int128;
using AddressUtils for address;
// -----------------
// STATE
// -----------------
// Voting period length for a challenge (in unix seconds)
uint256 public votingPeriodDuration;
// Deposit that must be made in order to submit a challenge
uint256 public challengeDeposit;
// Application fee to become a member
uint256 public applicationFee;
// IPFS hash for off chain storage of the Everest Charter
bytes32 public charter;
// IPFS hash for off chain storage of the Everest Categories
bytes32 public categories;
// Challenge freeze that can prevent new challenges from being made
bool public challengesFrozen;
// Approved token contract reference (i.e. DAI)
Dai public approvedToken;
// Reserve bank contract reference
ReserveBank public reserveBank;
// ERC-1056 contract reference
EthereumDIDRegistry public erc1056Registry;
// Registry contract reference
Registry public registry;
// We pass in the bytes representation of the string 'everest'
// bytes("everest") = 0x65766572657374. Then add 50 zeros to the end. The bytes32 value
// is passed to the ERC-1056 registry, and hashed within the delegate functions
bytes32 constant delegateType = 0x6576657265737400000000000000000000000000000000000000000000000000;
mapping (uint256 => Challenge) public challenges;
// Challenge counter for challenge IDs. With upgrading the contract, the latest challengeID
// must be the last challengeID + 1 of the old version of Everest
uint256 public challengeCounter;
// -------
// EVENTS
// -------
// Event data on delegates, owner, and offChainData are emitted from the ERC-1056 registry
event NewMember(address indexed member, uint256 startTime, uint256 fee);
event MemberExited(address indexed member);
event CharterUpdated(bytes32 indexed data);
event CategoriesUpdated(bytes32 indexed data);
event Withdrawal(address indexed receiver, uint256 amount);
event VotingDurationUpdated(uint256 indexed duration);
event ChallengeDepositUpdated(uint256 indexed deposit);
event ApplicationFeeUpdated(uint256 indexed fee);
event ChallengesFrozen(bool isFrozen);
event EverestDeployed(
address owner,
address approvedToken,
uint256 votingPeriodDuration,
uint256 challengeDeposit,
uint256 applicationFee,
bytes32 charter,
bytes32 categories,
address didRegistry,
address reserveBank,
address registry,
uint256 startingChallengeID
);
event MemberChallenged(
address indexed member,
uint256 indexed challengeID,
address indexed challenger,
uint256 challengeEndTime,
bytes32 details
);
event SubmitVote(
uint256 indexed challengeID,
address indexed submitter, // i.e. msg.sender
address indexed votingMember,
VoteChoice voteChoice,
uint256 voteWeight
);
event ChallengeFailed(
address indexed member,
uint256 indexed challengeID,
uint256 yesVotes,
uint256 noVotes,
uint256 voterCount,
uint256 resolverReward
);
event ChallengeSucceeded(
address indexed member,
uint256 indexed challengeID,
uint256 yesVotes,
uint256 noVotes,
uint256 voterCount,
uint256 challengerReward,
uint256 resolverReward
);
// ------
// STATE
// ------
enum VoteChoice {
Null, // Same as not voting at all (i.e. 0 value)
Yes,
No
}
struct Challenge {
address challenger; // The member who submitted the challenge
address challengee; // The member being challenged
uint256 yesVotes; // The total weight of YES votes for this challenge
uint256 noVotes; // The total weight of NO votes for this challenge
uint256 voterCount; // Total count of voters participating in the challenge
uint256 endTime; // Ending time of the challenge
bytes32 details; // Challenge details - an IPFS hash, without Qm, to make bytes32
mapping (address => VoteChoice) voteChoiceByMember; // The choice by each member
mapping (address => uint256) voteWeightByMember; // The vote weight of each member
}
// ----------
// MODIFIERS
// ----------
/**
@dev Modifer that allows a function to be called by the owner or delegate of a
member.
@param _member Member interacting with everest
*/
modifier onlyMemberOwnerOrDelegate(address _member) {
require(
isMember(_member),
"onlyMemberOwnerOrDelegate - Address is not a Member"
);
address memberOwner = erc1056Registry.identityOwner(_member);
bool validDelegate = erc1056Registry.validDelegate(_member, delegateType, msg.sender);
require(
validDelegate || memberOwner == msg.sender,
"onlyMemberOwnerOrDelegate - Caller must be delegate or owner"
);
_;
}
/**
@dev Modifer that allows a function to be called by owner of a member.
Only the member can call (no delegate permissions)
@param _member Member interacting with everest
*/
modifier onlyMemberOwner(address _member) {
require(
isMember(_member),
"onlyMemberOwner - Address is not a member"
);
address memberOwner = erc1056Registry.identityOwner(_member);
require(
memberOwner == msg.sender,
"onlyMemberOwner - Caller must be the owner"
);
_;
}
// ----------
// FUNCTIONS
// ----------
constructor(
address _approvedToken,
uint256 _votingPeriodDuration,
uint256 _challengeDeposit,
uint256 _applicationFee,
bytes32 _charter,
bytes32 _categories,
address _DIDregistry,
address _reserveBank,
address _registry,
uint256 _startingChallengeID
) public {
require(_approvedToken.isContract(), "The _approvedToken address should be a contract");
require(_DIDregistry.isContract(), "The _DIDregistry address should be a contract");
require(_reserveBank.isContract(), "The _reserveBank address should be a contract");
require(_registry.isContract(), "The _registry address should be a contract");
require(_votingPeriodDuration > 0, "constructor - _votingPeriodDuration cannot be 0");
require(_challengeDeposit > 0, "constructor - _challengeDeposit cannot be 0");
require(_applicationFee > 0, "constructor - _applicationFee cannot be 0");
require(_startingChallengeID != 0, "constructor - _startingChallengeID cannot be 0");
approvedToken = Dai(_approvedToken);
votingPeriodDuration = _votingPeriodDuration;
challengeDeposit = _challengeDeposit;
applicationFee = _applicationFee;
charter = _charter;
categories = _categories;
erc1056Registry = EthereumDIDRegistry(_DIDregistry);
reserveBank = ReserveBank(_reserveBank);
registry = Registry(_registry);
challengeCounter = _startingChallengeID;
emit EverestDeployed(
msg.sender, // i.e owner
_approvedToken,
_votingPeriodDuration,
_challengeDeposit,
_applicationFee,
_charter,
_categories,
_DIDregistry,
_reserveBank,
_registry,
_startingChallengeID
);
}
// ---------------------
// ADD MEMBER FUNCTIONS
// ---------------------
/**
@dev Allows a user to add a member to the Registry and
add off chain data to the DID registry. The sig for
changeOwner() and setAttribute() are from _newMember
and for DAIS permit() it is the _owner.
[0] = setAttributeSigned() signature
[1] = changeOwnerSigned() signature
[2] = permit() signature
@param _newMember The address of the new member
@param _sigV V of sigs
@param _sigR R of sigs
@param _sigS S of sigs
@param _memberOwner Owner of the member (on the DID registry)
@param _offChainDataName Attribute name. Should be a string less than 32 bytes, converted
to bytes32. example: 'ProjectData' = 0x50726f6a65637444617461,
with zeros appended to make it 32 bytes
@param _offChainDataValue Attribute data stored offchain (IPFS)
@param _offChainDataValidity Length of time attribute data is valid (unix)
*/
function applySignedWithAttributeAndPermit(
address _newMember,
uint8[3] calldata _sigV,
bytes32[3] calldata _sigR,
bytes32[3] calldata _sigS,
address _memberOwner,
bytes32 _offChainDataName,
bytes calldata _offChainDataValue,
uint256 _offChainDataValidity
) external {
require(_newMember != address(0), "Member can't be 0 address");
require(_memberOwner != address(0), "Owner can't be 0 address");
applySignedWithAttributeAndPermitInternal(
_newMember,
_sigV,
_sigR,
_sigS,
_memberOwner,
_offChainDataName,
_offChainDataValue,
_offChainDataValidity
);
}
/// @dev Note that this internal function is created in order to avoid the
/// Solidity stack too deep error.
function applySignedWithAttributeAndPermitInternal(
address _newMember,
uint8[3] memory _sigV,
bytes32[3] memory _sigR,
bytes32[3] memory _sigS,
address _memberOwner,
bytes32 _offChainDataName,
bytes memory _offChainDataValue,
uint256 _offChainDataValidity
) internal {
// Approve Everest to transfer DAI on the owner's behalf
// Expiry = 0 is infinite. true is unlimited allowance
uint256 nonce = approvedToken.nonces(_memberOwner);
approvedToken.permit(_memberOwner, address(this), nonce, 0, true, _sigV[2], _sigR[2], _sigS[2]);
applySignedWithAttribute(
_newMember,
[_sigV[0], _sigV[1]],
[_sigR[0], _sigR[1]],
[_sigS[0], _sigS[1]],
_memberOwner,
_offChainDataName,
_offChainDataValue,
_offChainDataValidity
);
}
/**
@dev Functions the same as applySignedWithAttributeAndPermit(),
except without permit(). This function should be called by
any _owner that has already called permit() for Everest.
[0] = setAttributeSigned() signature
[1] = changeOwnerSigned() signature
@param _newMember The address of the new member
@param _sigV V of sigs
@param _sigR R of sigs
@param _sigS S of sigs
@param _memberOwner Owner of the member application
@param _offChainDataName Attribute name. Should be a string less than 32 bytes, converted
to bytes32. example: 'ProjectData' = 0x50726f6a65637444617461,
with zeros appended to make it 32 bytes
@param _offChainDataValue Attribute data stored offchain (IPFS)
@param _offChainDataValidity Length of time attribute data is valid
*/
function applySignedWithAttribute(
address _newMember,
uint8[2] memory _sigV,
bytes32[2] memory _sigR,
bytes32[2] memory _sigS,
address _memberOwner,
bytes32 _offChainDataName,
bytes memory _offChainDataValue,
uint256 _offChainDataValidity
) public {
require(_newMember != address(0), "Member can't be 0 address");
require(_memberOwner != address(0), "Owner can't be 0 address");
require(
registry.getMemberStartTime(_newMember) == 0,
"applySignedInternal - This member already exists"
);
uint256 startTime = registry.setMember(_newMember);
// This event should be emitted before changeOwnerSigned() is called. This way all events
// in the Ethereum DID registry can start to be considered within the bounds of the event
// event NewMember() and the end of membership with event MemberExit() or event
// ChallengeSucceeded()
emit NewMember(
_newMember,
startTime,
applicationFee
);
erc1056Registry.setAttributeSigned(
_newMember,
_sigV[0],
_sigR[0],
_sigS[0],
_offChainDataName,
_offChainDataValue,
_offChainDataValidity
);
erc1056Registry.changeOwnerSigned(_newMember, _sigV[1], _sigR[1], _sigS[1], _memberOwner);
// Transfers tokens from owner to the reserve bank
require(
approvedToken.transferFrom(_memberOwner, address(reserveBank), applicationFee),
"applySignedInternal - Token transfer failed"
);
}
/**
@dev Allow a member to voluntarily leave. Note that this does not
reset ownership or delegates in the ERC-1056 registry. This must be done by
calling the respective functions in the registry that handle those.
@param _member Member exiting the list
*/
function memberExit(
address _member
) external onlyMemberOwner(_member) {
require(_member != address(0), "Member can't be 0 address");
require(
!memberChallengeExists(_member),
"memberExit - Can't exit during ongoing challenge"
);
registry.deleteMember(_member);
emit MemberExited(_member);
}
// --------------------
// CHALLENGE FUNCTIONS
// --------------------
/**
@dev Starts a challenge on a member. Challenger deposits a fee.
@param _challenger The address of the member who is challenging another member
@param _challengee The address of the member being challenged
@param _details Extra details relevant to the challenge. (IPFS hash without Qm)
@return Challenge ID for the created challenge
*/
function challenge(
address _challenger,
address _challengee,
bytes32 _details
) external onlyMemberOwner(_challenger) returns (uint256 challengeID) {
require(_challenger != address(0), "Challenger can't be 0 address");
require(isMember(_challengee), "challenge - Challengee must exist");
require(
_challenger != _challengee,
"challenge - Can't challenge self"
);
require(challengesFrozen != true, "challenge - Cannot create challenge, frozen");
uint256 currentChallengeID = registry.getChallengeID(_challengee);
require(currentChallengeID == 0, "challenge - Existing challenge must be resolved first");
uint256 newChallengeID = challengeCounter;
Challenge memory newChallenge = Challenge({
challenger: _challenger,
challengee: _challengee,
// It is okay to start counts at 0 here. submitVote() is called at the end of the func
yesVotes: 0,
noVotes: 0,
voterCount: 0,
/* solium-disable-next-line security/no-block-members*/
endTime: now.add(votingPeriodDuration),
details: _details
});
challengeCounter = challengeCounter.add(1);
challenges[newChallengeID] = newChallenge;
// Updates member to store most recent challenge
registry.editChallengeID(_challengee, newChallengeID);
// Transfer tokens from challenger to reserve bank
require(
approvedToken.transferFrom(msg.sender, address(reserveBank), challengeDeposit),
"challenge - Token transfer failed"
);
emit MemberChallenged(
_challengee,
newChallengeID,
_challenger,
/* solium-disable-next-line security/no-block-members*/
now.add(votingPeriodDuration),
newChallenge.details
);
// Add challengers' vote into the challenge
submitVote(newChallengeID, VoteChoice.Yes, _challenger);
return newChallengeID;
}
/**
@dev Submit a vote. Owner or delegate can submit
@param _challengeID The challenge ID
@param _voteChoice The vote choice (yes or no)
@param _votingMember The member who is voting
*/
function submitVote(
uint256 _challengeID,
VoteChoice _voteChoice,
address _votingMember
) public onlyMemberOwnerOrDelegate(_votingMember) {
require(_votingMember != address(0), "Member can't be 0 address");
require(
_voteChoice == VoteChoice.Yes || _voteChoice == VoteChoice.No,
"submitVote - Vote must be either Yes or No"
);
Challenge storage storedChallenge = challenges[_challengeID];
require(
storedChallenge.endTime > 0,
"submitVote - Challenge does not exist"
);
require(
!hasVotingPeriodExpired(storedChallenge.endTime),
"submitVote - Challenge voting period has expired"
);
require(
storedChallenge.voteChoiceByMember[_votingMember] == VoteChoice.Null,
"submitVote - Member has already voted on this challenge"
);
require(
storedChallenge.challengee != _votingMember,
"submitVote - Member can't vote on their own challenge"
);
uint256 startTime = registry.getMemberStartTime(_votingMember);
// The lower the member start time (i.e. the older the member) the more vote weight
uint256 voteWeightSquared = storedChallenge.endTime.sub(startTime);
// Here we use ABDKMath64x64 to do the square root of the vote weight
// We have to covert it to a 64.64 fixed point number, do sqrt(), then convert it
// back to uint256. uint256 wraps the result of toUInt(), since it returns uint64
int128 sixtyFourBitFPInt = voteWeightSquared.fromUInt();
int128 voteWeightInt128 = sixtyFourBitFPInt.sqrt();
uint256 voteWeight = uint256(voteWeightInt128.toUInt());
// Store vote with _votingMember, not msg.sender, since a delegate can vote
storedChallenge.voteChoiceByMember[_votingMember] = _voteChoice;
storedChallenge.voteWeightByMember[_votingMember] = voteWeight;
storedChallenge.voterCount = storedChallenge.voterCount.add(1);
// Count vote
if (_voteChoice == VoteChoice.Yes) {
storedChallenge.yesVotes = storedChallenge.yesVotes.add(voteWeight);
} else if (_voteChoice == VoteChoice.No) {
storedChallenge.noVotes = storedChallenge.noVotes.add(voteWeight);
}
emit SubmitVote(_challengeID, msg.sender, _votingMember, _voteChoice, voteWeight);
}
/**
@dev Submit many votes from owner or delegate with multiple members they own
or are delegates of
@param _challengeID The challenge ID
@param _voteChoices The vote choices (yes or no)
@param _voters The members who are voting
*/
function submitVotes(
uint256 _challengeID,
VoteChoice[] calldata _voteChoices,
address[] calldata _voters
) external {
require(
_voteChoices.length == _voters.length,
"submitVotes - Arrays must be equal"
);
require(_voteChoices.length < 90, "submitVotes - Array should be < 90 to avoid going over the block gas limit");
for (uint256 i; i < _voteChoices.length; i++){
submitVote(_challengeID, _voteChoices[i], _voters[i]);
}
}
/**
@dev Resolve a challenge A successful challenge means the member is removed.
Anyone can call this function. They will be rewarded with 1/10 of the
challenge deposit.
@param _challengeID The challenge ID
*/
function resolveChallenge(uint256 _challengeID) external {
challengeCanBeResolved(_challengeID);
Challenge storage storedChallenge = challenges[_challengeID];
bool didPass = storedChallenge.yesVotes > storedChallenge.noVotes;
bool moreThanOneVote = storedChallenge.voterCount > 1;
// Challenge reward is 1/10th the challenge deposit. This allows incentivization to
// always resolve the challenge for the user that calls this function
uint256 challengeRewardDivisor = 10;
uint256 resolverReward = challengeDeposit.div(challengeRewardDivisor);
if (didPass && moreThanOneVote) {
address challengerOwner = erc1056Registry.identityOwner(storedChallenge.challenger);
// The amount includes the applicationFee, which is the reward for challenging a project
// and getting it successfully removed. Minus the resolver reward
uint256 challengerReward = challengeDeposit.add(applicationFee).sub(resolverReward);
require(
reserveBank.withdraw(challengerOwner, challengerReward),
"resolveChallenge - Rewarding challenger failed"
);
// Transfer resolver reward
require(
reserveBank.withdraw(msg.sender, resolverReward),
"resolveChallenge - Rewarding resolver failed"
);
registry.deleteMember(storedChallenge.challengee);
emit ChallengeSucceeded(
storedChallenge.challengee,
_challengeID,
storedChallenge.yesVotes,
storedChallenge.noVotes,
storedChallenge.voterCount,
challengerReward,
resolverReward
);
} else {
// Transfer resolver reward
require(
reserveBank.withdraw(msg.sender, resolverReward),
"resolveChallenge - Rewarding resolver failed"
);
// Remove challenge ID from the Member in the registry
registry.editChallengeID(storedChallenge.challengee, 0);
emit ChallengeFailed(
storedChallenge.challengee,
_challengeID,
storedChallenge.yesVotes,
storedChallenge.noVotes,
storedChallenge.voterCount,
resolverReward
);
}
// Delete challenge from Everest in either case
delete challenges[_challengeID];
}
// ------------------------
// EVEREST OWNER FUNCTIONS
// ------------------------
/**
@dev Allows the owner of everest to withdraw funds from the reserve bank.
@param _receiver The address receiving funds
@param _amount The amount of funds being withdrawn
@return True if withdrawal is successful
*/
function withdraw(address _receiver, uint256 _amount) external onlyOwner returns (bool) {
require(_receiver != address(0), "Receiver must not be 0 address");
require(_amount > 0, "Amount must be greater than 0");
emit Withdrawal(_receiver, _amount);
return reserveBank.withdraw(_receiver, _amount);
}
/**
@dev Allows the owner of Everest to transfer the ownership of ReserveBank
@param _newOwner The new owner
*/
function transferOwnershipReserveBank(address _newOwner) external onlyOwner {
reserveBank.transferOwnership(_newOwner);
}
/**
@dev Allows the owner of Everest to transfer the ownership of Registry
@param _newOwner The new owner
*/
function transferOwnershipRegistry(address _newOwner) external onlyOwner {
registry.transferOwnership(_newOwner);
}
/**
@dev Updates the charter for Everest
@param _newCharter The data that point to the new charter
*/
function updateCharter(bytes32 _newCharter) external onlyOwner {
charter = _newCharter;
emit CharterUpdated(charter);
}
/**
@dev Updates the categories for Everest
@param _newCategories The data that point to the new categories
*/
function updateCategories(bytes32 _newCategories) external onlyOwner {
categories = _newCategories;
emit CategoriesUpdated(categories);
}
/**
@dev Updates the voting duration for Everest
@param _newVotingDuration New voting duration in unix seconds
*/
function updateVotingPeriodDuration(uint256 _newVotingDuration) external onlyOwner {
votingPeriodDuration = _newVotingDuration;
emit VotingDurationUpdated(votingPeriodDuration);
}
/**
@dev Updates the challenge deposit required
@param _newDeposit The new value for the challenge deposit, with decimals (10^18)
*/
function updateChallengeDeposit(uint256 _newDeposit) external onlyOwner {
challengeDeposit = _newDeposit;
emit ChallengeDepositUpdated(challengeDeposit);
}
/**
@dev Updates the application fee for Everest
@param _newFee The new application fee, with decimals (10^18)
*/
function updateApplicationFee(uint256 _newFee) external onlyOwner {
applicationFee = _newFee;
emit ApplicationFeeUpdated(applicationFee);
}
/**
@dev Freezes the ability to create challenges
@param _isFrozen Pass in true if challenges are to be frozen
*/
function updateChallengeFreeze(bool _isFrozen) external onlyOwner {
challengesFrozen = _isFrozen;
emit ChallengesFrozen(challengesFrozen);
}
// -----------------
// GETTER FUNCTIONS
// -----------------
/**
@dev Returns true if a challenge vote period has finished
@param _endTime The starting period of the challenge
@return True if voting period has expired
*/
function hasVotingPeriodExpired(uint256 _endTime) private view returns (bool) {
/* solium-disable-next-line security/no-block-members*/
return now >= _endTime;
}
/**
@dev Returns true if the address is a member
@param _member The member name of the member whose status is to be examined
@return True is address is a member
*/
function isMember(address _member) public view returns (bool){
require(_member != address(0), "Member can't be 0 address");
uint256 startTime = registry.getMemberStartTime(_member);
if (startTime > 0){
return true;
}
return false;
}
/**
@dev Returns true if the member has an unresolved challenge. False if the challenge
does not exist.
@param _member The member that is being checked for a challenge.
@return True if a challenge exists on the member
*/
function memberChallengeExists(address _member) public view returns (bool) {
require(_member != address(0), "Member can't be 0 address");
uint256 challengeID = registry.getChallengeID(_member);
return (challengeID > 0);
}
/**
@dev Determines whether voting has concluded in a challenge for a given
member. Throws if challenge can't be resolved
@param _challengeID The challenge ID
*/
function challengeCanBeResolved(uint256 _challengeID) private view {
Challenge storage storedChallenge = challenges[_challengeID];
require(
challenges[_challengeID].endTime > 0,
"challengeCanBeResolved - Challenge does not exist or was completed"
);
require(
hasVotingPeriodExpired(storedChallenge.endTime),
"challengeCanBeResolved - Current challenge is not ready to be resolved"
);
}
}
{
"compilationTarget": {
"Everest.sol": "Everest"
},
"evmVersion": "petersburg",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"_newCharter","type":"bytes32"}],"name":"updateCharter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"reserveBank","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"applicationFee","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"challengeDeposit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"erc1056Registry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newDeposit","type":"uint256"}],"name":"updateChallengeDeposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnershipReserveBank","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newFee","type":"uint256"}],"name":"updateApplicationFee","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_member","type":"address"}],"name":"memberChallengeExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_challengeID","type":"uint256"},{"name":"_voteChoices","type":"uint8[]"},{"name":"_voters","type":"address[]"}],"name":"submitVotes","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_challengeID","type":"uint256"}],"name":"resolveChallenge","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"registry","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_challenger","type":"address"},{"name":"_challengee","type":"address"},{"name":"_details","type":"bytes32"}],"name":"challenge","outputs":[{"name":"challengeID","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_challengeID","type":"uint256"},{"name":"_voteChoice","type":"uint8"},{"name":"_votingMember","type":"address"}],"name":"submitVote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"challenges","outputs":[{"name":"challenger","type":"address"},{"name":"challengee","type":"address"},{"name":"yesVotes","type":"uint256"},{"name":"noVotes","type":"uint256"},{"name":"voterCount","type":"uint256"},{"name":"endTime","type":"uint256"},{"name":"details","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newVotingDuration","type":"uint256"}],"name":"updateVotingPeriodDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_member","type":"address"}],"name":"isMember","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"votingPeriodDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_member","type":"address"}],"name":"memberExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"approvedToken","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newMember","type":"address"},{"name":"_sigV","type":"uint8[3]"},{"name":"_sigR","type":"bytes32[3]"},{"name":"_sigS","type":"bytes32[3]"},{"name":"_memberOwner","type":"address"},{"name":"_offChainDataName","type":"bytes32"},{"name":"_offChainDataValue","type":"bytes"},{"name":"_offChainDataValidity","type":"uint256"}],"name":"applySignedWithAttributeAndPermit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"charter","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_isFrozen","type":"bool"}],"name":"updateChallengeFreeze","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newMember","type":"address"},{"name":"_sigV","type":"uint8[2]"},{"name":"_sigR","type":"bytes32[2]"},{"name":"_sigS","type":"bytes32[2]"},{"name":"_memberOwner","type":"address"},{"name":"_offChainDataName","type":"bytes32"},{"name":"_offChainDataValue","type":"bytes"},{"name":"_offChainDataValidity","type":"uint256"}],"name":"applySignedWithAttribute","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnershipRegistry","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_receiver","type":"address"},{"name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"challengeCounter","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newCategories","type":"bytes32"}],"name":"updateCategories","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"challengesFrozen","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"categories","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_approvedToken","type":"address"},{"name":"_votingPeriodDuration","type":"uint256"},{"name":"_challengeDeposit","type":"uint256"},{"name":"_applicationFee","type":"uint256"},{"name":"_charter","type":"bytes32"},{"name":"_categories","type":"bytes32"},{"name":"_DIDregistry","type":"address"},{"name":"_reserveBank","type":"address"},{"name":"_registry","type":"address"},{"name":"_startingChallengeID","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"member","type":"address"},{"indexed":false,"name":"startTime","type":"uint256"},{"indexed":false,"name":"fee","type":"uint256"}],"name":"NewMember","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"member","type":"address"}],"name":"MemberExited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"data","type":"bytes32"}],"name":"CharterUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"data","type":"bytes32"}],"name":"CategoriesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"receiver","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"duration","type":"uint256"}],"name":"VotingDurationUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"deposit","type":"uint256"}],"name":"ChallengeDepositUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"fee","type":"uint256"}],"name":"ApplicationFeeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"isFrozen","type":"bool"}],"name":"ChallengesFrozen","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"approvedToken","type":"address"},{"indexed":false,"name":"votingPeriodDuration","type":"uint256"},{"indexed":false,"name":"challengeDeposit","type":"uint256"},{"indexed":false,"name":"applicationFee","type":"uint256"},{"indexed":false,"name":"charter","type":"bytes32"},{"indexed":false,"name":"categories","type":"bytes32"},{"indexed":false,"name":"didRegistry","type":"address"},{"indexed":false,"name":"reserveBank","type":"address"},{"indexed":false,"name":"registry","type":"address"},{"indexed":false,"name":"startingChallengeID","type":"uint256"}],"name":"EverestDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"member","type":"address"},{"indexed":true,"name":"challengeID","type":"uint256"},{"indexed":true,"name":"challenger","type":"address"},{"indexed":false,"name":"challengeEndTime","type":"uint256"},{"indexed":false,"name":"details","type":"bytes32"}],"name":"MemberChallenged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"challengeID","type":"uint256"},{"indexed":true,"name":"submitter","type":"address"},{"indexed":true,"name":"votingMember","type":"address"},{"indexed":false,"name":"voteChoice","type":"uint8"},{"indexed":false,"name":"voteWeight","type":"uint256"}],"name":"SubmitVote","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"member","type":"address"},{"indexed":true,"name":"challengeID","type":"uint256"},{"indexed":false,"name":"yesVotes","type":"uint256"},{"indexed":false,"name":"noVotes","type":"uint256"},{"indexed":false,"name":"voterCount","type":"uint256"},{"indexed":false,"name":"resolverReward","type":"uint256"}],"name":"ChallengeFailed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"member","type":"address"},{"indexed":true,"name":"challengeID","type":"uint256"},{"indexed":false,"name":"yesVotes","type":"uint256"},{"indexed":false,"name":"noVotes","type":"uint256"},{"indexed":false,"name":"voterCount","type":"uint256"},{"indexed":false,"name":"challengerReward","type":"uint256"},{"indexed":false,"name":"resolverReward","type":"uint256"}],"name":"ChallengeSucceeded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]