pragma solidity 0.4.25;
// File: contracts/LinkedListLib.sol
/**
* @title LinkedListLib
* @author Darryl Morris (o0ragman0o) and Modular.network
*
* This utility library was forked from https://github.com/o0ragman0o/LibCLL
* into the Modular-Network ethereum-libraries repo at https://github.com/Modular-Network/ethereum-libraries
* It has been updated to add additional functionality and be more compatible with solidity 0.4.18
* coding patterns.
*
* version 1.1.1
* Copyright (c) 2017 Modular Inc.
* The MIT License (MIT)
* https://github.com/Modular-network/ethereum-libraries/blob/master/LICENSE
*
* The LinkedListLib provides functionality for implementing data indexing using
* a circlular linked list
*
* Modular provides smart contract services and security reviews for contract
* deployments in addition to working on open source projects in the Ethereum
* community. Our purpose is to test, document, and deploy reusable code onto the
* blockchain and improve both security and usability. We also educate non-profits,
* schools, and other community members about the application of blockchain
* technology. For further information: modular.network
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
library LinkedListLib {
uint256 constant NULL = 0;
uint256 constant HEAD = 0;
bool constant PREV = false;
bool constant NEXT = true;
struct LinkedList{
mapping (uint256 => mapping (bool => uint256)) list;
}
/// @dev returns true if the list exists
/// @param self stored linked list from contract
function listExists(LinkedList storage self)
public
view returns (bool)
{
// if the head nodes previous or next pointers both point to itself, then there are no items in the list
if (self.list[HEAD][PREV] != HEAD || self.list[HEAD][NEXT] != HEAD) {
return true;
} else {
return false;
}
}
/// @dev returns true if the node exists
/// @param self stored linked list from contract
/// @param _node a node to search for
function nodeExists(LinkedList storage self, uint256 _node)
public
view returns (bool)
{
if (self.list[_node][PREV] == HEAD && self.list[_node][NEXT] == HEAD) {
if (self.list[HEAD][NEXT] == _node) {
return true;
} else {
return false;
}
} else {
return true;
}
}
/// @dev Returns the number of elements in the list
/// @param self stored linked list from contract
function sizeOf(LinkedList storage self) public view returns (uint256 numElements) {
bool exists;
uint256 i;
(exists,i) = getAdjacent(self, HEAD, NEXT);
while (i != HEAD) {
(exists,i) = getAdjacent(self, i, NEXT);
numElements++;
}
return;
}
/// @dev Returns the links of a node as a tuple
/// @param self stored linked list from contract
/// @param _node id of the node to get
function getNode(LinkedList storage self, uint256 _node)
public view returns (bool,uint256,uint256)
{
if (!nodeExists(self,_node)) {
return (false,0,0);
} else {
return (true,self.list[_node][PREV], self.list[_node][NEXT]);
}
}
/// @dev Returns the link of a node `_node` in direction `_direction`.
/// @param self stored linked list from contract
/// @param _node id of the node to step from
/// @param _direction direction to step in
function getAdjacent(LinkedList storage self, uint256 _node, bool _direction)
public view returns (bool,uint256)
{
if (!nodeExists(self,_node)) {
return (false,0);
} else {
return (true,self.list[_node][_direction]);
}
}
/// @dev Can be used before `insert` to build an ordered list
/// @param self stored linked list from contract
/// @param _node an existing node to search from, e.g. HEAD.
/// @param _value value to seek
/// @param _direction direction to seek in
// @return next first node beyond '_node' in direction `_direction`
function getSortedSpot(LinkedList storage self, uint256 _node, uint256 _value, bool _direction)
public view returns (uint256)
{
if (sizeOf(self) == 0) { return 0; }
require((_node == 0) || nodeExists(self,_node));
bool exists;
uint256 next;
(exists,next) = getAdjacent(self, _node, _direction);
while ((next != 0) && (_value != next) && ((_value < next) != _direction)) next = self.list[next][_direction];
return next;
}
/// @dev Creates a bidirectional link between two nodes on direction `_direction`
/// @param self stored linked list from contract
/// @param _node first node for linking
/// @param _link node to link to in the _direction
function createLink(LinkedList storage self, uint256 _node, uint256 _link, bool _direction) private {
self.list[_link][!_direction] = _node;
self.list[_node][_direction] = _link;
}
/// @dev Insert node `_new` beside existing node `_node` in direction `_direction`.
/// @param self stored linked list from contract
/// @param _node existing node
/// @param _new new node to insert
/// @param _direction direction to insert node in
function insert(LinkedList storage self, uint256 _node, uint256 _new, bool _direction) internal returns (bool) {
if(!nodeExists(self,_new) && nodeExists(self,_node)) {
uint256 c = self.list[_node][_direction];
createLink(self, _node, _new, _direction);
createLink(self, _new, c, _direction);
return true;
} else {
return false;
}
}
/// @dev removes an entry from the linked list
/// @param self stored linked list from contract
/// @param _node node to remove from the list
function remove(LinkedList storage self, uint256 _node) internal returns (uint256) {
if ((_node == NULL) || (!nodeExists(self,_node))) { return 0; }
createLink(self, self.list[_node][PREV], self.list[_node][NEXT], NEXT);
delete self.list[_node][PREV];
delete self.list[_node][NEXT];
return _node;
}
/// @dev pushes an enrty to the head of the linked list
/// @param self stored linked list from contract
/// @param _node new entry to push to the head
/// @param _direction push to the head (NEXT) or tail (PREV)
function push(LinkedList storage self, uint256 _node, bool _direction) internal {
insert(self, HEAD, _node, _direction);
}
/// @dev pops the first entry from the linked list
/// @param self stored linked list from contract
/// @param _direction pop from the head (NEXT) or the tail (PREV)
function pop(LinkedList storage self, bool _direction) internal returns (uint256) {
bool exists;
uint256 adj;
(exists,adj) = getAdjacent(self, HEAD, _direction);
return remove(self, adj);
}
}
// File: openzeppelin-solidity/contracts/math/SafeMath.sol
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (a == 0) {
return 0;
}
c = a * b;
assert(c / a == b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return a / b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
assert(b <= a);
return a - b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = a + b;
assert(c >= a);
return c;
}
}
// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
// File: openzeppelin-solidity/contracts/ownership/rbac/Roles.sol
/**
* @title Roles
* @author Francisco Giordano (@frangio)
* @dev Library for managing addresses assigned to a Role.
* See RBAC.sol for example usage.
*/
library Roles {
struct Role {
mapping (address => bool) bearer;
}
/**
* @dev give an address access to this role
*/
function add(Role storage role, address addr)
internal
{
role.bearer[addr] = true;
}
/**
* @dev remove an address' access to this role
*/
function remove(Role storage role, address addr)
internal
{
role.bearer[addr] = false;
}
/**
* @dev check if an address has this role
* // reverts
*/
function check(Role storage role, address addr)
view
internal
{
require(has(role, addr));
}
/**
* @dev check if an address has this role
* @return bool
*/
function has(Role storage role, address addr)
view
internal
returns (bool)
{
return role.bearer[addr];
}
}
// File: openzeppelin-solidity/contracts/ownership/rbac/RBAC.sol
/**
* @title RBAC (Role-Based Access Control)
* @author Matt Condon (@Shrugs)
* @dev Stores and provides setters and getters for roles and addresses.
* @dev Supports unlimited numbers of roles and addresses.
* @dev See //contracts/mocks/RBACMock.sol for an example of usage.
* This RBAC method uses strings to key roles. It may be beneficial
* for you to write your own implementation of this interface using Enums or similar.
* It's also recommended that you define constants in the contract, like ROLE_ADMIN below,
* to avoid typos.
*/
contract RBAC {
using Roles for Roles.Role;
mapping (string => Roles.Role) private roles;
event RoleAdded(address addr, string roleName);
event RoleRemoved(address addr, string roleName);
/**
* @dev reverts if addr does not have role
* @param addr address
* @param roleName the name of the role
* // reverts
*/
function checkRole(address addr, string roleName)
view
public
{
roles[roleName].check(addr);
}
/**
* @dev determine if addr has role
* @param addr address
* @param roleName the name of the role
* @return bool
*/
function hasRole(address addr, string roleName)
view
public
returns (bool)
{
return roles[roleName].has(addr);
}
/**
* @dev add a role to an address
* @param addr address
* @param roleName the name of the role
*/
function addRole(address addr, string roleName)
internal
{
roles[roleName].add(addr);
emit RoleAdded(addr, roleName);
}
/**
* @dev remove a role from an address
* @param addr address
* @param roleName the name of the role
*/
function removeRole(address addr, string roleName)
internal
{
roles[roleName].remove(addr);
emit RoleRemoved(addr, roleName);
}
/**
* @dev modifier to scope access to a single role (uses msg.sender as addr)
* @param roleName the name of the role
* // reverts
*/
modifier onlyRole(string roleName)
{
checkRole(msg.sender, roleName);
_;
}
/**
* @dev modifier to scope access to a set of roles (uses msg.sender as addr)
* @param roleNames the names of the roles to scope access to
* // reverts
*
* @TODO - when solidity supports dynamic arrays as arguments to modifiers, provide this
* see: https://github.com/ethereum/solidity/issues/2467
*/
// modifier onlyRoles(string[] roleNames) {
// bool hasAnyRole = false;
// for (uint8 i = 0; i < roleNames.length; i++) {
// if (hasRole(msg.sender, roleNames[i])) {
// hasAnyRole = true;
// break;
// }
// }
// require(hasAnyRole);
// _;
// }
}
// File: openzeppelin-solidity/contracts/ownership/Whitelist.sol
/**
* @title Whitelist
* @dev The Whitelist contract has a whitelist of addresses, and provides basic authorization control functions.
* @dev This simplifies the implementation of "user permissions".
*/
contract Whitelist is Ownable, RBAC {
event WhitelistedAddressAdded(address addr);
event WhitelistedAddressRemoved(address addr);
string public constant ROLE_WHITELISTED = "whitelist";
/**
* @dev Throws if called by any account that's not whitelisted.
*/
modifier onlyWhitelisted() {
checkRole(msg.sender, ROLE_WHITELISTED);
_;
}
/**
* @dev add an address to the whitelist
* @param addr address
* @return true if the address was added to the whitelist, false if the address was already in the whitelist
*/
function addAddressToWhitelist(address addr)
onlyOwner
public
{
addRole(addr, ROLE_WHITELISTED);
emit WhitelistedAddressAdded(addr);
}
/**
* @dev getter to determine if address is in whitelist
*/
function whitelist(address addr)
public
view
returns (bool)
{
return hasRole(addr, ROLE_WHITELISTED);
}
/**
* @dev add addresses to the whitelist
* @param addrs addresses
* @return true if at least one address was added to the whitelist,
* false if all addresses were already in the whitelist
*/
function addAddressesToWhitelist(address[] addrs)
onlyOwner
public
{
for (uint256 i = 0; i < addrs.length; i++) {
addAddressToWhitelist(addrs[i]);
}
}
/**
* @dev remove an address from the whitelist
* @param addr address
* @return true if the address was removed from the whitelist,
* false if the address wasn't in the whitelist in the first place
*/
function removeAddressFromWhitelist(address addr)
onlyOwner
public
{
removeRole(addr, ROLE_WHITELISTED);
emit WhitelistedAddressRemoved(addr);
}
/**
* @dev remove addresses from the whitelist
* @param addrs addresses
* @return true if at least one address was removed from the whitelist,
* false if all addresses weren't in the whitelist in the first place
*/
function removeAddressesFromWhitelist(address[] addrs)
onlyOwner
public
{
for (uint256 i = 0; i < addrs.length; i++) {
removeAddressFromWhitelist(addrs[i]);
}
}
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20Basic.sol
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract ERC20Basic {
function totalSupply() public view returns (uint256);
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
// File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract ERC20 is ERC20Basic {
function allowance(address owner, address spender)
public view returns (uint256);
function transferFrom(address from, address to, uint256 value)
public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);
}
// File: openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
function safeTransfer(ERC20Basic token, address to, uint256 value) internal {
require(token.transfer(to, value));
}
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 value
)
internal
{
require(token.transferFrom(from, to, value));
}
function safeApprove(ERC20 token, address spender, uint256 value) internal {
require(token.approve(spender, value));
}
}
// File: contracts/token_escrow/TokenEscrow.sol
/**
* NOTE: All contracts in this directory were taken from a non-master branch of openzeppelin-solidity.
* This contract was modified to be a whitelist.
* Commit: ed451a8688d1fa7c927b27cec299a9726667d9b1
*/
pragma solidity ^0.4.24;
/**
* @title TokenEscrow
* @dev Holds tokens destinated to a payee until they withdraw them.
* The contract that uses the TokenEscrow as its payment method
* should be its owner, and provide public methods redirecting
* to the TokenEscrow's deposit and withdraw.
* Moreover, the TokenEscrow should also be allowed to transfer
* tokens from the payer to itself.
*/
contract TokenEscrow is Ownable, Whitelist {
using SafeMath for uint256;
using SafeERC20 for ERC20;
event Deposited(address indexed payee, uint256 tokenAmount);
event Withdrawn(address indexed payee, uint256 tokenAmount);
mapping(address => uint256) public deposits;
ERC20 public token;
constructor (ERC20 _token) public {
require(_token != address(0));
token = _token;
}
function depositsOf(address _payee) public view returns (uint256) {
return deposits[_payee];
}
/**
* @dev Puts in escrow a certain amount of tokens as credit to be withdrawn.
* @param _payee The destination address of the tokens.
* @param _amount The amount of tokens to deposit in escrow.
*/
function deposit(address _payee, uint256 _amount) public onlyWhitelisted {
deposits[_payee] = deposits[_payee].add(_amount);
token.safeTransferFrom(msg.sender, address(this), _amount);
emit Deposited(_payee, _amount);
}
/**
* @dev Withdraw accumulated tokens for a payee.
* @param _payee The address whose tokens will be withdrawn and transferred to.
*/
function withdraw(address _payee) public onlyWhitelisted {
uint256 payment = deposits[_payee];
assert(token.balanceOf(address(this)) >= payment);
deposits[_payee] = 0;
token.safeTransfer(_payee, payment);
emit Withdrawn(_payee, payment);
}
}
// File: contracts/token_escrow/ConditionalTokenEscrow.sol
/**
* NOTE: All contracts in this directory were taken from a non-master branch of openzeppelin-solidity.
* Commit: ed451a8688d1fa7c927b27cec299a9726667d9b1
*/
pragma solidity ^0.4.24;
/**
* @title ConditionalTokenEscrow
* @dev Base abstract escrow to only allow withdrawal of tokens
* if a condition is met.
*/
contract ConditionalTokenEscrow is TokenEscrow {
/**
* @dev Returns whether an address is allowed to withdraw their tokens.
* To be implemented by derived contracts.
* @param _payee The destination address of the tokens.
*/
function withdrawalAllowed(address _payee) public view returns (bool);
function withdraw(address _payee) public {
require(withdrawalAllowed(_payee));
super.withdraw(_payee);
}
}
// File: contracts/QuantstampAuditTokenEscrow.sol
contract QuantstampAuditTokenEscrow is ConditionalTokenEscrow {
// the escrow maintains the list of staked addresses
using LinkedListLib for LinkedListLib.LinkedList;
// constants used by LinkedListLib
uint256 constant internal NULL = 0;
uint256 constant internal HEAD = 0;
bool constant internal PREV = false;
bool constant internal NEXT = true;
// maintain the number of staked nodes
// saves gas cost over needing to call stakedNodesList.sizeOf()
uint256 public stakedNodesCount = 0;
// the minimum amount of wei-QSP that must be staked in order to be a node
uint256 public minAuditStake = 10000 * (10 ** 18);
// if true, the payee cannot currently withdraw their funds
mapping(address => bool) public lockedFunds;
// if funds are locked, they may be retrieved after this block
// if funds are unlocked, the number should be ignored
mapping(address => uint256) public unlockBlockNumber;
// staked audit nodes -- needed to inquire about audit node statistics, such as min price
// this list contains all nodes that have *ANY* stake, however when getNextStakedNode is called,
// it skips nodes that do not meet the minimum stake.
// the reason for this approach is that if the owner lowers the minAuditStake,
// we must be aware of any node with a stake.
LinkedListLib.LinkedList internal stakedNodesList;
event Slashed(address addr, uint256 amount);
event StakedNodeAdded(address addr);
event StakedNodeRemoved(address addr);
// the constructor of TokenEscrow requires an ERC20, not an address
constructor(address tokenAddress) public TokenEscrow(ERC20(tokenAddress)) {} // solhint-disable no-empty-blocks
/**
* @dev Puts in escrow a certain amount of tokens as credit to be withdrawn.
* Overrides the function in TokenEscrow.sol to add the payee to the staked list.
* @param _payee The destination address of the tokens.
* @param _amount The amount of tokens to deposit in escrow.
*/
function deposit(address _payee, uint256 _amount) public onlyWhitelisted {
super.deposit(_payee, _amount);
if (_amount > 0) {
// fails gracefully if the node already exists
addNodeToStakedList(_payee);
}
}
/**
* @dev Withdraw accumulated tokens for a payee.
* Overrides the function in TokenEscrow.sol to remove the payee from the staked list.
* @param _payee The address whose tokens will be withdrawn and transferred to.
*/
function withdraw(address _payee) public onlyWhitelisted {
super.withdraw(_payee);
removeNodeFromStakedList(_payee);
}
/**
* @dev Sets the minimum stake to a new value.
* @param _value The new value. _value must be greater than zero in order for the linked list to be maintained correctly.
*/
function setMinAuditStake(uint256 _value) public onlyOwner {
require(_value > 0);
minAuditStake = _value;
}
/**
* @dev Returns true if the sender staked enough.
* @param addr The address to check.
*/
function hasEnoughStake(address addr) public view returns(bool) {
return depositsOf(addr) >= minAuditStake;
}
/**
* @dev Overrides ConditionalTokenEscrow function. If true, funds may be withdrawn.
* @param _payee The address that wants to withdraw funds.
*/
function withdrawalAllowed(address _payee) public view returns (bool) {
return !lockedFunds[_payee] || unlockBlockNumber[_payee] < block.number;
}
/**
* @dev Prevents the payee from withdrawing funds.
* @param _payee The address that will be locked.
*/
function lockFunds(address _payee, uint256 _unlockBlockNumber) public onlyWhitelisted returns (bool) {
lockedFunds[_payee] = true;
unlockBlockNumber[_payee] = _unlockBlockNumber;
return true;
}
/**
* @dev Slash a percentage of the stake of an address.
* The percentage is taken from the minAuditStake, not the total stake of the address.
* The caller of this function receives the slashed QSP.
* If the current stake does not cover the slash amount, the full stake is taken.
*
* @param addr The address that will be slashed.
* @param percentage The percent of the minAuditStake that should be slashed.
*/
function slash(address addr, uint256 percentage) public onlyWhitelisted returns (uint256) {
require(0 <= percentage && percentage <= 100);
uint256 slashAmount = getSlashAmount(percentage);
uint256 balance = depositsOf(addr);
if (balance < slashAmount) {
slashAmount = balance;
}
// subtract from the deposits amount of the addr
deposits[addr] = deposits[addr].sub(slashAmount);
emit Slashed(addr, slashAmount);
// if the deposits of the address are now zero, remove from the list
if (depositsOf(addr) == 0) {
removeNodeFromStakedList(addr);
}
// transfer the slashAmount to the police contract
token.safeTransfer(msg.sender, slashAmount);
return slashAmount;
}
/**
* @dev Returns the slash amount for a given percentage.
* @param percentage The percent of the minAuditStake that should be slashed.
*/
function getSlashAmount(uint256 percentage) public view returns (uint256) {
return (minAuditStake.mul(percentage)).div(100);
}
/**
* @dev Given a staked address, returns the next address from the list that meets the minAuditStake.
* @param addr The staked address.
* @return The next address in the list.
*/
function getNextStakedNode(address addr) public view returns(address) {
bool exists;
uint256 next;
(exists, next) = stakedNodesList.getAdjacent(uint256(addr), NEXT);
// only return addresses that meet the minAuditStake
while (exists && next != HEAD && !hasEnoughStake(address(next))) {
(exists, next) = stakedNodesList.getAdjacent(next, NEXT);
}
return address(next);
}
/**
* @dev Adds an address to the stakedNodesList.
* @param addr The address to be added to the list.
* @return true if the address was added to the list.
*/
function addNodeToStakedList(address addr) internal returns(bool success) {
if (stakedNodesList.insert(HEAD, uint256(addr), PREV)) {
stakedNodesCount++;
emit StakedNodeAdded(addr);
success = true;
}
}
/**
* @dev Removes an address from the stakedNodesList.
* @param addr The address to be removed from the list.
* @return true if the address was removed from the list.
*/
function removeNodeFromStakedList(address addr) internal returns(bool success) {
if (stakedNodesList.remove(uint256(addr)) != 0) {
stakedNodesCount--;
emit StakedNodeRemoved(addr);
success = true;
}
}
}
{
"compilationTarget": {
"QuantstampAuditTokenEscrow.sol": "QuantstampAuditTokenEscrow"
},
"evmVersion": "byzantium",
"libraries": {},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"percentage","type":"uint256"}],"name":"slash","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"},{"name":"roleName","type":"string"}],"name":"checkRole","outputs":[],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_payee","type":"address"},{"name":"_unlockBlockNumber","type":"uint256"}],"name":"lockFunds","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ROLE_WHITELISTED","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"unlockBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"},{"name":"roleName","type":"string"}],"name":"hasRole","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addrs","type":"address[]"}],"name":"removeAddressesFromWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"removeAddressFromWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"percentage","type":"uint256"}],"name":"getSlashAmount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_payee","type":"address"},{"name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_payee","type":"address"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_payee","type":"address"}],"name":"withdrawalAllowed","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"hasEnoughStake","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"addAddressToWhitelist","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":"addr","type":"address"}],"name":"whitelist","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_value","type":"uint256"}],"name":"setMinAuditStake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"lockedFunds","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"addr","type":"address"}],"name":"getNextStakedNode","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minAuditStake","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakedNodesCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"addrs","type":"address[]"}],"name":"addAddressesToWhitelist","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_payee","type":"address"}],"name":"depositsOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"token","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"deposits","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"tokenAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"},{"indexed":false,"name":"amount","type":"uint256"}],"name":"Slashed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"}],"name":"StakedNodeAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"}],"name":"StakedNodeRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"payee","type":"address"},{"indexed":false,"name":"tokenAmount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"payee","type":"address"},{"indexed":false,"name":"tokenAmount","type":"uint256"}],"name":"Withdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"}],"name":"WhitelistedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"}],"name":"WhitelistedAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"},{"indexed":false,"name":"roleName","type":"string"}],"name":"RoleAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"addr","type":"address"},{"indexed":false,"name":"roleName","type":"string"}],"name":"RoleRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"}],"name":"OwnershipRenounced","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"previousOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"}]