// File: LibBaseAuth.sol



// SPDX-License-Identifier: MIT
pragma solidity =0.7.4;

import "LibRoles.sol";
import "LibIERC20.sol";


/**
 * @dev Base auth.
 */
contract BaseAuth {
    using Roles for Roles.Role;

    Roles.Role private _agents;

    event AgentAdded(address indexed account);
    event AgentRemoved(address indexed account);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor ()
    {
        _agents.add(msg.sender);
        emit AgentAdded(msg.sender);
    }

    /**
     * @dev Throws if called by account which is not an agent.
     */
    modifier onlyAgent() {
        require(isAgent(msg.sender), "AgentRole: caller does not have the Agent role");
        _;
    }

    /**
     * @dev Rescue compatible ERC20 Token
     *
     * Can only be called by an agent.
     */
    function rescueToken(
        address tokenAddr,
        address recipient,
        uint256 amount
    )
        external
        onlyAgent
    {
        IERC20 _token = IERC20(tokenAddr);
        require(recipient != address(0), "Rescue: recipient is the zero address");
        uint256 balance = _token.balanceOf(address(this));

        require(balance >= amount, "Rescue: amount exceeds balance");
        _token.transfer(recipient, amount);
    }

    /**
     * @dev Withdraw Ether
     *
     * Can only be called by an agent.
     */
    function withdrawEther(
        address payable recipient,
        uint256 amount
    )
        external
        onlyAgent
    {
        require(recipient != address(0), "Withdraw: recipient is the zero address");
        uint256 balance = address(this).balance;
        require(balance >= amount, "Withdraw: amount exceeds balance");
        recipient.transfer(amount);
    }

    /**
     * @dev Returns true if the `account` has the Agent role.
     */
    function isAgent(address account)
        public
        view
        returns (bool)
    {
        return _agents.has(account);
    }

    /**
     * @dev Give an `account` access to the Agent role.
     *
     * Can only be called by an agent.
     */
    function addAgent(address account)
        public
        onlyAgent
    {
        _agents.add(account);
        emit AgentAdded(account);
    }

    /**
     * @dev Remove an `account` access from the Agent role.
     *
     * Can only be called by an agent.
     */
    function removeAgent(address account)
        public
        onlyAgent
    {
        _agents.remove(account);
        emit AgentRemoved(account);
    }
}


// File: LibIERC20.sol



// SPDX-License-Identifier: MIT
pragma solidity =0.7.4;


/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    function name() external view returns (string memory);
    function symbol() external view returns (string memory);
    function decimals() external view returns (uint8);
    function totalSupply() external view returns (uint256);
    function allowance(address owner, address spender) external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Approval(address indexed owner, address indexed spender, uint256 value);
    event Transfer(address indexed from, address indexed to, uint256 value);
}

// File: LibIVokenAudit.sol



// SPDX-License-Identifier: MIT
pragma solidity =0.7.4;

interface IVokenAudit {
    function getAccount(address account) external view
        returns (
            uint72 wei_purchased,
            uint72 wei_rewarded,
            uint72 wei_audit,
            uint16 txs_in,
            uint16 txs_out
        );
}

// File: LibRoles.sol



// SPDX-License-Identifier: MIT
pragma solidity =0.7.4;


/**
 * @dev Library for managing addresses assigned to a Role.
 */
library Roles {
    struct Role
    {
        mapping (address => bool) bearer;
    }

    /**
     * @dev Give an account access to this role.
     */
    function add(
        Role storage role,
        address account
    )
        internal
    {
        require(!has(role, account), "Roles: account already has role");
        role.bearer[account] = true;
    }

    /**
     * @dev Remove an account's access to this role.
     */
    function remove(
        Role storage role,
        address account
    )
        internal
    {
        require(has(role, account), "Roles: account does not have role");
        role.bearer[account] = false;
    }

    /**
     * @dev Check if an account has this role.
     *
     * @return bool
     */
    function has(
        Role storage role,
        address account
    )
        internal
        view
        returns (bool)
    {
        require(account != address(0), "Roles: account is the zero address");
        return role.bearer[account];
    }
}

// File: Voken2Audit.sol



// SPDX-License-Identifier: MIT
pragma solidity =0.7.4;

import "LibBaseAuth.sol";
import "LibIVokenAudit.sol";


/**
 * @dev Voken2.0 Audit
 */
contract Voken2Audit is BaseAuth, IVokenAudit {
    struct Account {
        uint72 wei_purchased;
        uint72 wei_rewarded;
        uint72 wei_audit;
        uint16 txs_in;
        uint16 txs_out;
    }

    mapping (address => Account) _accounts;

    function setAccounts(
        address[] memory accounts,
        uint72[] memory wei_purchased,
        uint72[] memory wei_rewarded,
        uint72[] memory wei_audit,
        uint16[] memory txs_in,
        uint16[] memory txs_out
    )
        external
        onlyAgent
    {
        for (uint8 i = 0; i < accounts.length; i++) {
            _accounts[accounts[i]] = Account(wei_purchased[i], wei_rewarded[i], wei_audit[i], txs_in[i], txs_out[i]);
        }
    }

    function removeAccounts(address[] memory accounts)
        external
        onlyAgent
    {
        for (uint8 i = 0; i < accounts.length; i++) {
            delete _accounts[accounts[i]];
        }
        
    }

    function getAccount(address account)
        public
        override
        view
        returns (uint72 wei_purchased, uint72 wei_rewarded, uint72 wei_audit, uint16 txs_in, uint16 txs_out)
    {
        wei_purchased = _accounts[account].wei_purchased;
        wei_rewarded = _accounts[account].wei_rewarded;
        wei_audit = _accounts[account].wei_audit;
        txs_in = _accounts[account].txs_in;
        txs_out = _accounts[account].txs_out;
    }
}