EthereumEthereum
0x2b...044d
OMNIS-BIT

OMNIS-BIT

OMNIS

代币
市值
$1.00
 
价格
2%
此合同的源代码已经过验证!
合同元数据
编译器
0.5.9+commit.e560f70d
语言
Solidity
合同源代码
文件 1 的 1:OMNIS.sol
pragma solidity 0.5.9;
/**
 _____                   __  __      ______      ____                 ____       ______      ______
/\  __`\     /'\_/`\    /\ \/\ \    /\__  _\    /\  _`\              /\  _`\    /\__  _\    /\__  _\
\ \ \/\ \   /\      \   \ \ `\\ \   \/_/\ \/    \ \,\L\_\            \ \ \L\ \  \/_/\ \/    \/_/\ \/
 \ \ \ \ \  \ \ \__\ \   \ \ , ` \     \ \ \     \/_\__ \    _______  \ \  _ <'    \ \ \       \ \ \
  \ \ \_\ \  \ \ \_/\ \   \ \ \`\ \     \_\ \__    /\ \L\ \ /\______\  \ \ \L\ \    \_\ \__     \ \ \
   \ \_____\  \ \_\\ \_\   \ \_\ \_\    /\_____\   \ `\____\\/______/   \ \____/    /\_____\     \ \_\
    \/_____/   \/_/ \/_/    \/_/\/_/    \/_____/    \/_____/             \/___/     \/_____/      \/_/

    WEBSITE: www.omnis-bit.com
    Email: support@omnis-bit.com
    *If you need support please contact us*

    This contract's staking features are based on the code provided at
    https://github.com/PoSToken/PoSToken

    SafeMath Library provided by OpenZeppelin
    https://github.com/OpenZeppelin/openzeppelin-solidity
    
    Audited by Callisto Security Audit Department, 
    link: https://github.com/EthereumCommonwealth/Auditing/issues/344#issuecomment-530542757
    No mitigation applied on contract for approve/transferFrom ERC20 issue https://github.com/ethereum/EIPs/issues/738
    404,436,690,827,884 lines corrected according to the audit
   *losing stake reward after token transfer is part of staking logic*

    Official Social Networks:
    Telegram Channel: https://t.me/OMNISOFFICIAL
    Telegram Chat: https://t.me/OmnisBitOfficial
    Medium: https://medium.com/@OMNIS
    Twitter: https://twitter.com/OmnisBit
    Facebook: https://www.facebook.com/OMNISBITPAGE/
    Instagram: https://www.instagram.com/omnisbit/?st=JQO8XM3Z&sh=0870a6f5
    Reddit: https://www.reddit.com/user/OMNISBIT
  
 */

/**
 * @title SafeMath
 * @dev Unsigned math operations with safety checks that revert on error.
 */
library SafeMath {
    /**
     * @dev Multiplies two unsigned integers, reverts on 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-solidity/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
     */
    function div(uint256 a, uint256 b) internal pure returns(uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
     */
    function sub(uint256 a, uint256 b) internal pure returns(uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Adds two unsigned integers, reverts on overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns(uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
     * reverts when dividing by zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns(uint256) {
        require(b != 0, "SafeMath: modulo by zero");
        return a % b;
    }
}

/**
 * @title Admined
 * @dev The Admined contract has an owner address, can set administrators,
 * and provides authorization control functions. These features can be used in other contracts
 * through interfacing, so external contracts can check main contract admin levels
 */
contract Admined {
    address public owner; //named owner for etherscan compatibility
    mapping(address => uint256) public level;

    /**
     * @dev The Admined constructor sets the original `owner` of the contract to the sender
     * account and assing high level privileges.
     */
    constructor() public {
        owner = msg.sender;
        level[owner] = 3;
        emit OwnerSet(owner);
        emit LevelSet(owner, level[owner]);
    }

    /**
     * @dev Throws if called by any account with lower level than minLvl.
     * @param _minLvl Minimum level to use the function
     */
    modifier onlyAdmin(uint256 _minLvl) {
        require(level[msg.sender] >= _minLvl, 'You do not have privileges for this transaction');
        _;
    }

    /**
     * @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 onlyAdmin(3) {
        require(newOwner != address(0), 'Address cannot be zero');

        owner = newOwner;
        level[owner] = 3;

        emit OwnerSet(owner);
        emit LevelSet(owner, level[owner]);

        level[msg.sender] = 0;
        emit LevelSet(msg.sender, level[msg.sender]);
    }

    /**
     * @dev Allows the assignment of new privileges to a new address.
     * @param userAddress The address to transfer ownership to.
     * @param lvl Lvl to assign.
     */
    function setLevel(address userAddress, uint256 lvl) public onlyAdmin(2) {
        require(userAddress != address(0), 'Address cannot be zero');
        require(lvl < level[msg.sender], 'You do not have privileges for this level assignment');
        require(level[msg.sender] > level[userAddress], 'You do not have privileges for this level change');

        level[userAddress] = lvl;
        emit LevelSet(userAddress, level[userAddress]);
    }

    event LevelSet(address indexed user, uint256 lvl);
    event OwnerSet(address indexed user);

}

/**
 * @title ERC20Basic
 * @dev Simpler version of ERC20 interface
 * @dev see https://github.com/ethereum/EIPs/issues/179
 */
contract ERC20Basic {
    uint256 public totalSupply;

    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);
}

/**
 * @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);
}

contract StakerToken {
    uint256 public stakeStartTime;
    uint256 public stakeMinAge;
    uint256 public stakeMaxAge;

    function claimStake() public returns(bool);

    function coinAge() public view returns(uint256);

    function annualInterest() public view returns(uint256);
}

contract OMNIS is ERC20, StakerToken, Admined {
    using SafeMath
    for uint256;
    ///////////////////////////////////////////////////////////////////
    //TOKEN RELATED
    string public name = "OMNIS-BIT";
    string public symbol = "OMNIS";
    string public version = "v4";
    uint8 public decimals = 18;

    uint public totalSupply;
    uint public maxTotalSupply;
    uint public totalInitialSupply;

    mapping(address => uint256) balances;
    mapping(address => mapping(address => uint256)) allowed;
    //TOKEN SECTION END
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //AIRDROP RELATED
    struct Airdrop {
        uint value;
        bool claimed;
    }

    address public airdropWallet;

    mapping(address => Airdrop) public airdrops; //One airdrop at a time allowed
    //AIRDROP SECTION END
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //ESCROW RELATED
    enum PaymentStatus {
        Requested,
        Rejected,
        Pending,
        Completed,
        Refunded
    }

    struct Payment {
        address provider;
        address customer;
        uint value;
        string comment;
        PaymentStatus status;
        bool refundApproved;
    }

    uint escrowCounter;
    uint public escrowFeePercent = 2; //initially set to 0.2%
    bool public escrowEnabled = true;

    /**
     * @dev Throws if escrow is disabled.
     */
    modifier escrowIsEnabled() {
        require(escrowEnabled == true, 'Escrow is Disabled');
        _;
    }

    mapping(uint => Payment) public payments;
    address public collectionAddress;
    //ESCROW SECTION END
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //STAKING RELATED
    struct transferInStruct {
        uint128 amount;
        uint64 time;
    }

    uint public chainStartTime;
    uint public chainStartBlockNumber;
    uint public stakeStartTime;
    uint public stakeMinAge = 3 days;
    uint public stakeMaxAge = 90 days;

    mapping(address => bool) public userFreeze;

    // mapping(address => transferInStruct[]) transferIns;

    mapping(address => uint) staked;
    mapping(address => transferInStruct) lastTransfer;


    modifier canPoSclaimStake() {
        require(totalSupply < maxTotalSupply, 'Max supply reached');
        _;
    }
    //STAKING SECTION END
    ///////////////////////////////////////////////////////////////////

    /**
     * @dev Throws if any frozen is applied.
     * @param _holderWallet Address of the actual token holder
     */
    modifier notFrozen(address _holderWallet) {
        require(userFreeze[_holderWallet] == false, 'Balance frozen by the user');
        _;
    }

    ///////////////////////////////////////////////////////////////////
    //EVENTS
    event ClaimStake(address indexed _address, uint _reward);
    event NewCollectionWallet(address newWallet);

    event ClaimDrop(address indexed user, uint value);
    event NewAirdropWallet(address newWallet);

    event GlobalFreeze(bool status);

    event EscrowLock(bool status);
    event NewFeeRate(uint newFee);
    event PaymentCreation(
        uint indexed orderId,
        address indexed provider,
        address indexed customer,
        uint value,
        string description
    );
    event PaymentUpdate(
        uint indexed orderId,
        address indexed provider,
        address indexed customer,
        uint value,
        PaymentStatus status
    );
    event PaymentRefundApprove(
        uint indexed orderId,
        address indexed provider,
        address indexed customer,
        bool status
    );
    ///////////////////////////////////////////////////////////////////

    constructor() public {

        maxTotalSupply = 1000000000 * 10 ** 18; //MAX SUPPLY EVER
        totalInitialSupply = 820000000 * 10 ** 18; //INITIAL SUPPLY
        chainStartTime = now; //Deployment Time
        chainStartBlockNumber = block.number; //Deployment Block
        totalSupply = totalInitialSupply;
        collectionAddress = msg.sender; //Initially fees collection wallet to creator
        airdropWallet = msg.sender; //Initially airdrop wallet to creator
        balances[msg.sender] = totalInitialSupply;

        emit Transfer(address(0), msg.sender, totalInitialSupply);
    }

    /**
     * @dev setCollectionWallet
     * @dev Allow an admin from level 3 to set the Escrow Service Fee Wallet
     * @param _newWallet The new fee wallet
     */
    function setCollectionWallet(address _newWallet) public onlyAdmin(3) {
        require(_newWallet != address(0), 'Address cannot be zero');
        collectionAddress = _newWallet;
        emit NewCollectionWallet(collectionAddress);
    }

    /**
     * @dev setAirDropWallet
     * @dev Allow an admin from level 3 to set the Airdrop Service Wallet
     * @param _newWallet The new Airdrop wallet
     */
    function setAirDropWallet(address _newWallet) public onlyAdmin(3) {
        require(_newWallet != address(0), 'Address cannot be zero');
        airdropWallet = _newWallet;
        emit NewAirdropWallet(airdropWallet);
    }

    ///////////////////////////////////////////////////////////////////
    //ERC20 FUNCTIONS
    function transfer(address _to, uint256 _value) public notFrozen(msg.sender) returns(bool) {
        require(_to != address(0), 'Address cannot be zero');
        require(_to != address(this), 'Address cannot be this contract');

        if (msg.sender == _to) return claimStake();

        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);

        //STAKING RELATED//////////////////////////////////////////////
        if (staked[msg.sender] != 0) staked[msg.sender] = 0;
        uint64 _now = uint64(now);
        lastTransfer[msg.sender] = transferInStruct(uint128(balances[msg.sender]), _now);

        if (uint(lastTransfer[_to].time) != 0) {
            uint nCoinSeconds = now.sub(uint(lastTransfer[_to].time));
            if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
            staked[_to] = staked[_to].add(uint(lastTransfer[_to].amount).mul(nCoinSeconds.div(1 days)));
        }
        lastTransfer[_to] = transferInStruct(uint128(balances[_to]), _now);
        ///////////////////////////////////////////////////////////////

        return true;
    }

    function balanceOf(address _owner) public view returns(uint256 balance) {
        return balances[_owner];
    }

    function transferFrom(address _from, address _to, uint256 _value) public notFrozen(_from) returns(bool) {
        require(_to != address(0), 'Address cannot be zero');

        uint256 _allowance = allowed[_from][msg.sender];
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        allowed[_from][msg.sender] = _allowance.sub(_value);
        emit Transfer(_from, _to, _value);

        //STAKING RELATED//////////////////////////////////////////////
        if (staked[_from] != 0) staked[_from] = 0;
        uint64 _now = uint64(now);
        lastTransfer[_from] = transferInStruct(uint128(balances[_from]), _now);

        if (_from != _to) { //Prevent double stake

            if (uint(lastTransfer[_to].time) != 0) {
                uint nCoinSeconds = now.sub(uint(lastTransfer[_to].time));
                if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
                staked[_to] = staked[_to].add(uint(lastTransfer[_to].amount).mul(nCoinSeconds.div(1 days)));
            }

            lastTransfer[_to] = transferInStruct(uint128(balances[_to]), _now);
        }
        ///////////////////////////////////////////////////////////////

        return true;
    }

    function approve(address _spender, uint256 _value) public returns(bool) {
        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);

        return true;
    }

    function allowance(address _owner, address _spender) public view returns(uint256 remaining) {
        return allowed[_owner][_spender];
    }
    //ERC20 SECTION END
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //STAKING FUNCTIONS
    /**
     * @dev claimStake
     * @dev Allow any user to claim stake earned
     */
    function claimStake() public canPoSclaimStake returns(bool) {
        if (balances[msg.sender] <= 0) return false;

        uint reward = getProofOfStakeReward(msg.sender);

        if (totalSupply.add(reward) > maxTotalSupply) {
            reward = maxTotalSupply.sub(totalSupply);
        }

        if (reward <= 0) return false;

        totalSupply = totalSupply.add(reward);
        balances[msg.sender] = balances[msg.sender].add(reward);

        //STAKING RELATED//////////////////////////////////////////////
        uint64 _now = uint64(now);
        staked[msg.sender] = 0;
        lastTransfer[msg.sender] = transferInStruct(uint128(balances[msg.sender]), _now);
        ///////////////////////////////////////////////////////////////

        emit Transfer(address(0), msg.sender, reward);
        emit ClaimStake(msg.sender, reward);
        return true;
    }

    /**
     * @dev getBlockNumber
     * @dev Returns the block number since deployment
     */
    function getBlockNumber() public view returns(uint blockNumber) {
        blockNumber = block.number.sub(chainStartBlockNumber);
    }

    /**
     * @dev coinAge
     * @dev Returns the coinage for the callers account
     */
    function coinAge() public view returns(uint myCoinAge) {
        myCoinAge = getCoinAge(msg.sender, now);
    }

    /**
     * @dev annualInterest
     * @dev Returns the current interest rate
     */
    function annualInterest() public view returns(uint interest) {
        uint _now = now;
        // If all periods are finished but not max supply is reached,
        // a default small interest rate is left until max supply
        // get reached
        interest = (1 * 1e15); //fallback interest
        if ((_now.sub(stakeStartTime)).div(365 days) == 0) {
            interest = (106 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 1) {
            interest = (49 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 2) {
            interest = (24 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 3) {
            interest = (13 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 4) {
            interest = (11 * 1e15);
        }
    }

    /**
     * @dev getProofOfStakeReward
     * @dev Returns the current stake of a wallet
     * @param _address is the user wallet
     */
    function getProofOfStakeReward(address _address) public view returns(uint) {
        require((now >= stakeStartTime) && (stakeStartTime > 0), 'Staking is not yet enabled');

        uint _now = now;
        uint _coinAge = getCoinAge(_address, _now);
        if (_coinAge <= 0) return 0;

        // If all periods are finished but not max supply is reached,
        // a default small interest rate is left until max supply
        // get reached
        uint interest = (1 * 1e15); //fallback interest

        if ((_now.sub(stakeStartTime)).div(365 days) == 0) {
            interest = (106 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 1) {
            interest = (49 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 2) {
            interest = (24 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 3) {
            interest = (13 * 1e15);
        } else if ((_now.sub(stakeStartTime)).div(365 days) == 4) {
            interest = (11 * 1e15);
        }

        return (_coinAge * interest).div(365 * (10 ** uint256(decimals)));
    }

    function getCoinAge(address _address, uint _now) internal view returns(uint _coinAge) {
        _coinAge = staked[_address];
        if (uint(lastTransfer[_address].time) != 0) {
            uint nCoinSeconds = _now.sub(uint(lastTransfer[_address].time));
            if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
            _coinAge = _coinAge.add(uint(lastTransfer[_address].amount).mul(nCoinSeconds.div(1 days)));
        }
    }

    /**
     * @dev setStakeStartTime
     * @dev Used by the owner to define the staking period start
     * @param timestamp time in UNIX format
     */
    function setStakeStartTime(uint timestamp) public onlyAdmin(3) {
        require((stakeStartTime <= 0) && (timestamp >= chainStartTime), 'Wrong time set');
        stakeStartTime = timestamp;
    }
    //STACKING SECTION END
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //UTILITY FUNCTIONS
    /**
     * @dev batchTransfer
     * @dev Used by the owner to deliver several transfers at the same time (Airdrop)
     * @param _recipients Array of addresses
     * @param _values Array of values
     */
    function batchTransfer(
        address[] calldata _recipients,
        uint[] calldata _values
    )
    external
    onlyAdmin(1)
    returns(bool) {
        //Check data sizes
        require(_recipients.length > 0 && _recipients.length == _values.length, 'Addresses and Values have wrong sizes');
        //Total value calc
        uint total = 0;
        for (uint i = 0; i < _values.length; i++) {
            total = total.add(_values[i]);
        }
        //Sender must hold funds
        require(total <= balances[msg.sender], 'Not enough funds for the transaction');
        //Make transfers
        uint64 _now = uint64(now);
        for (uint j = 0; j < _recipients.length; j++) {
            balances[_recipients[j]] = balances[_recipients[j]].add(_values[j]);
            //STAKING RELATED//////////////////////////////////////////////
            if (uint(lastTransfer[_recipients[j]].time) != 0) {
                uint nCoinSeconds = now.sub(uint(lastTransfer[_recipients[j]].time));
                if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
                staked[_recipients[j]] = staked[_recipients[j]].add(uint(lastTransfer[_recipients[j]].amount).mul(nCoinSeconds.div(1 days)));
            }
            lastTransfer[_recipients[j]] = transferInStruct(uint128(_values[j]), _now);
            ///////////////////////////////////////////////////////////////
            emit Transfer(msg.sender, _recipients[j], _values[j]);
        }
        //Reduce all balance on a single transaction from sender
        balances[msg.sender] = balances[msg.sender].sub(total);
        //STAKING RELATED//////////////////////////////////////////////
        if (staked[msg.sender] != 0) staked[msg.sender] = 0;
        lastTransfer[msg.sender] = transferInStruct(uint128(balances[msg.sender]), _now);
        ///////////////////////////////////////////////////////////////
        return true;
    }

    /**
     * @dev dropSet
     * @dev Used by the owner to set several self-claiming drops at the same time (Airdrop)
     * @param _recipients Array of addresses
     * @param _values Array of values1
     */
    function dropSet(
        address[] calldata _recipients,
        uint[] calldata _values
    )
    external
    onlyAdmin(1)
    returns(bool) {
        //Check data sizes
        require(_recipients.length > 0 && _recipients.length == _values.length, 'Addresses and Values have wrong sizes');

        for (uint j = 0; j < _recipients.length; j++) {
            //Store user drop info
            airdrops[_recipients[j]].value = _values[j];
            airdrops[_recipients[j]].claimed = false;
        }

        return true;
    }

    /**
     * @dev claimAirdrop
     * @dev Allow any user with a drop set to claim it
     */
    function claimAirdrop() external returns(bool) {
        //Check if not claimed
        require(airdrops[msg.sender].claimed == false, 'Airdrop already claimed');
        require(airdrops[msg.sender].value != 0, 'No airdrop value to claim');

        //Original value
        uint _value = airdrops[msg.sender].value;

        //Set as Claimed
        airdrops[msg.sender].claimed = true;
        //Clear value
        airdrops[msg.sender].value = 0;

        //Tokens are on airdropWallet
        address _from = airdropWallet;
        //Tokens goes to costumer
        address _to = msg.sender;
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);

        emit Transfer(_from, _to, _value);
        emit ClaimDrop(_to, _value);

        //STAKING RELATED//////////////////////////////////////////////
        if (staked[_from] != 0) staked[_from] = 0;
        uint64 _now = uint64(now);
        lastTransfer[_from] = transferInStruct(uint128(balances[_from]), _now);

        if (_from != _to) { //Prevent double stake

            if (uint(lastTransfer[_to].time) != 0) {
                uint nCoinSeconds = now.sub(uint(lastTransfer[_to].time));
                if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
                staked[_to] = staked[_to].add(uint(lastTransfer[_to].amount).mul(nCoinSeconds.div(1 days)));
            }
            lastTransfer[_to] = transferInStruct(uint128(balances[_to]), _now);
        }
        ///////////////////////////////////////////////////////////////

        return true;

    }

    /**
     * @dev userFreezeBalance
     * @dev Allow a user to safe Lock/Unlock it's balance
     * @param _lock Lock Status to set
     */
    function userFreezeBalance(bool _lock) public returns(bool) {
        userFreeze[msg.sender] = _lock;
        return userFreeze[msg.sender];
    }

    //UTILITY SECTION ENDS
    ///////////////////////////////////////////////////////////////////

    ///////////////////////////////////////////////////////////////////
    //ESCROW FUNCTIONS
    /**
     * @dev createPaymentRequest
     * @dev Allow an user to request start a Escrow process
     * @param _customer Counterpart that will receive payment on success
     * @param _value Amount to be escrowed
     * @param _description Description
     */
    function createPaymentRequest(
        address _customer,
        uint _value,
        string calldata _description
    )
    external
    escrowIsEnabled()
    notFrozen(msg.sender)
    returns(uint) {

        require(_customer != address(0), 'Address cannot be zero');
        require(_value > 0, 'Value cannot be zero');

        payments[escrowCounter] = Payment(msg.sender, _customer, _value, _description, PaymentStatus.Requested, false);
        emit PaymentCreation(escrowCounter, msg.sender, _customer, _value, _description);

        escrowCounter = escrowCounter.add(1);
        return escrowCounter - 1;

    }

    /**
     * @dev answerPaymentRequest
     * @dev Allow a user to answer to a Escrow process
     * @param _orderId the request ticket number
     * @param _answer request answer
     */
    function answerPaymentRequest(uint _orderId, bool _answer) external returns(bool) {
        //Get Payment Handler
        Payment storage payment = payments[_orderId];

        require(payment.status == PaymentStatus.Requested, 'Ticket wrong status, expected "Requested"');
        require(payment.customer == msg.sender, 'You are not allowed to manage this ticket');

        if (_answer == true) {

            address _to = address(this);

            balances[payment.provider] = balances[payment.provider].sub(payment.value);
            balances[_to] = balances[_to].add(payment.value);
            emit Transfer(payment.provider, _to, payment.value);

            //STAKING RELATED//////////////////////////////////////////////
            if (staked[payment.provider] != 0) staked[payment.provider] = 0;
            uint64 _now = uint64(now);
            lastTransfer[payment.provider] = transferInStruct(uint128(balances[payment.provider]), _now);
            ///////////////////////////////////////////////////////////////

            payments[_orderId].status = PaymentStatus.Pending;

            emit PaymentUpdate(_orderId, payment.provider, payment.customer, payment.value, PaymentStatus.Pending);

        } else {

            payments[_orderId].status = PaymentStatus.Rejected;

            emit PaymentUpdate(_orderId, payment.provider, payment.customer, payment.value, PaymentStatus.Rejected);

        }

        return true;
    }


    /**
     * @dev release
     * @dev Allow a provider or admin user to release a payment
     * @param _orderId Ticket number of the escrow service
     */
    function release(uint _orderId) external returns(bool) {
        //Get Payment Handler
        Payment storage payment = payments[_orderId];
        //Only if pending
        require(payment.status == PaymentStatus.Pending, 'Ticket wrong status, expected "Pending"');
        //Only owner or token provider
        require(level[msg.sender] >= 2 || msg.sender == payment.provider, 'You are not allowed to manage this ticket');
        //Tokens are on contract
        address _from = address(this);
        //Tokens goes to costumer
        address _to = payment.customer;
        //Original value
        uint _value = payment.value;
        //Fee calculation
        uint _fee = _value.mul(escrowFeePercent).div(1000);
        //Value less fees
        _value = _value.sub(_fee);
        //Costumer transfer
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(_from, _to, _value);
        //collectionAddress fee recolection
        balances[_from] = balances[_from].sub(_fee);
        balances[collectionAddress] = balances[collectionAddress].add(_fee);
        emit Transfer(_from, collectionAddress, _fee);

        //STAKING RELATED//////////////////////////////////////////////
        if (staked[_from] != 0) staked[_from] = 0;
        uint64 _now = uint64(now);
        lastTransfer[_from] = transferInStruct(uint128(balances[_from]), _now);

        if (_from != _to) { //Prevent double stake

            if (uint(lastTransfer[_to].time) != 0) {
                uint nCoinSeconds = now.sub(uint(lastTransfer[_to].time));
                if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
                staked[_to] = staked[_to].add(uint(lastTransfer[_to].amount).mul(nCoinSeconds.div(1 days)));
            }
            lastTransfer[_to] = transferInStruct(uint128(balances[_to]), _now);
        }

        if (uint(lastTransfer[collectionAddress].time) != 0) {
            uint nCoinSeconds = now.sub(uint(lastTransfer[collectionAddress].time));
            if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
            staked[collectionAddress] = staked[collectionAddress].add(uint(lastTransfer[collectionAddress].amount).mul(nCoinSeconds.div(1 days)));
        }
        lastTransfer[collectionAddress] = transferInStruct(uint128(_fee), _now);
        ///////////////////////////////////////////////////////////////


        //Payment Escrow Completed
        payment.status = PaymentStatus.Completed;
        //Emit Event
        emit PaymentUpdate(_orderId, payment.provider, payment.customer, payment.value, payment.status);

        return true;
    }

    /**
     * @dev refund
     * @dev Allow a user to refund a payment
     * @param _orderId Ticket number of the escrow service
     */
    function refund(uint _orderId) external returns(bool) {
        //Get Payment Handler
        Payment storage payment = payments[_orderId];
        //Only if pending
        require(payment.status == PaymentStatus.Pending, 'Ticket wrong status, expected "Pending"');
        //Only if refund was approved
        require(payment.refundApproved, 'Refund has not been approved yet');
        //Only owner or token provider
        require(level[msg.sender] >= 2 || msg.sender == payment.provider, 'You are not allowed to manage this ticket');
        //Tokens are on contract
        address _from = address(this);
        //Tokens go back to provider
        address _to = payment.provider;
        //Original value
        uint _value = payment.value;
        //Provider transfer
        balances[_from] = balances[_from].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(_from, _to, _value);
        
        //STAKING RELATED//////////////////////////////////////////////
        if (staked[_from] != 0) staked[_from] = 0;
        uint64 _now = uint64(now);
        lastTransfer[_from] = transferInStruct(uint128(balances[_from]), _now);

        if (_from != _to) { //Prevent double stake

            if (uint(lastTransfer[_to].time) != 0) {
                uint nCoinSeconds = now.sub(uint(lastTransfer[_to].time));
                if (nCoinSeconds > stakeMaxAge) nCoinSeconds = stakeMaxAge;
                staked[_to] = staked[_to].add(uint(lastTransfer[_to].amount).mul(nCoinSeconds.div(1 days)));
            }
            lastTransfer[_to] = transferInStruct(uint128(balances[_to]), _now);
        }
        ///////////////////////////////////////////////////////////////
        
        //Payment Escrow Refunded
        payment.status = PaymentStatus.Refunded;
        //Emit Event
        emit PaymentUpdate(_orderId, payment.provider, payment.customer, payment.value, payment.status);

        return true;
    }

    /**
     * @dev approveRefund
     * @dev Allow a user to approve a refund
     * @param _orderId Ticket number of the escrow service
     */
    function approveRefund(uint _orderId) external returns(bool) {
        //Get Payment Handler
        Payment storage payment = payments[_orderId];
        //Only if pending
        require(payment.status == PaymentStatus.Pending, 'Ticket wrong status, expected "Pending"');
        //Only owner or costumer
        require(level[msg.sender] >= 2 || msg.sender == payment.customer, 'You are not allowed to manage this ticket');
        //Approve Refund
        payment.refundApproved = true;

        emit PaymentRefundApprove(_orderId, payment.provider, payment.customer, payment.refundApproved);

        return true;
    }

    /**
     * @dev escrowLockSet
     * @dev Allow the owner to lock the escrow feature
     * @param _lock lock indicator
     */
    function escrowLockSet(bool _lock) external onlyAdmin(3) returns(bool) {
        escrowEnabled = _lock;
        emit EscrowLock(escrowEnabled);
        return true;
    }

    //ESCROW SECTION END
    ///////////////////////////////////////////////////////////////////
}
设置
{
  "compilationTarget": {
    "OMNIS.sol": "OMNIS"
  },
  "evmVersion": "petersburg",
  "libraries": {},
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": []
}
ABI
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_address","type":"address"}],"name":"getProofOfStakeReward","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newWallet","type":"address"}],"name":"setAirDropWallet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"coinAge","outputs":[{"name":"myCoinAge","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"}],"name":"refund","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"maxTotalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"escrowFeePercent","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"}],"name":"approveRefund","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"}],"name":"release","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_lock","type":"bool"}],"name":"escrowLockSet","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getBlockNumber","outputs":[{"name":"blockNumber","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"userFreeze","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"chainStartTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimAirdrop","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"collectionAddress","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"userAddress","type":"address"},{"name":"lvl","type":"uint256"}],"name":"setLevel","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"stakeStartTime","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_orderId","type":"uint256"},{"name":"_answer","type":"bool"}],"name":"answerPaymentRequest","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"payments","outputs":[{"name":"provider","type":"address"},{"name":"customer","type":"address"},{"name":"value","type":"uint256"},{"name":"comment","type":"string"},{"name":"status","type":"uint8"},{"name":"refundApproved","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_values","type":"uint256[]"}],"name":"batchTransfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_recipients","type":"address[]"},{"name":"_values","type":"uint256[]"}],"name":"dropSet","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"airdrops","outputs":[{"name":"value","type":"uint256"},{"name":"claimed","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalInitialSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"airdropWallet","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_lock","type":"bool"}],"name":"userFreezeBalance","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"annualInterest","outputs":[{"name":"interest","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakeMinAge","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"timestamp","type":"uint256"}],"name":"setStakeStartTime","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"chainStartBlockNumber","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"level","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"escrowEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"stakeMaxAge","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimStake","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_customer","type":"address"},{"name":"_value","type":"uint256"},{"name":"_description","type":"string"}],"name":"createPaymentRequest","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_newWallet","type":"address"}],"name":"setCollectionWallet","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_address","type":"address"},{"indexed":false,"name":"_reward","type":"uint256"}],"name":"ClaimStake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newWallet","type":"address"}],"name":"NewCollectionWallet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"ClaimDrop","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newWallet","type":"address"}],"name":"NewAirdropWallet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"status","type":"bool"}],"name":"GlobalFreeze","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"status","type":"bool"}],"name":"EscrowLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"newFee","type":"uint256"}],"name":"NewFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderId","type":"uint256"},{"indexed":true,"name":"provider","type":"address"},{"indexed":true,"name":"customer","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"description","type":"string"}],"name":"PaymentCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderId","type":"uint256"},{"indexed":true,"name":"provider","type":"address"},{"indexed":true,"name":"customer","type":"address"},{"indexed":false,"name":"value","type":"uint256"},{"indexed":false,"name":"status","type":"uint8"}],"name":"PaymentUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"orderId","type":"uint256"},{"indexed":true,"name":"provider","type":"address"},{"indexed":true,"name":"customer","type":"address"},{"indexed":false,"name":"status","type":"bool"}],"name":"PaymentRefundApprove","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"},{"indexed":false,"name":"lvl","type":"uint256"}],"name":"LevelSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"user","type":"address"}],"name":"OwnerSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"spender","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":true,"name":"to","type":"address"},{"indexed":false,"name":"value","type":"uint256"}],"name":"Transfer","type":"event"}]