Contract Address Details

0x6C76489E86e1f9a1C3F51064b3f4F6435e3Ba6Bd

Contract Name
OrderStorage
Creator
0x195582–c8d801 at 0xc1f296–14ed35
Balance
0 ROSE
Tokens
Fetching tokens...
Transactions
42 Transactions
Transfers
0 Transfers
Gas Used
25,709,448
Last Balance Update
7994248
Contract name:
OrderStorage




Optimization enabled
true
Compiler version
v0.8.11+commit.d7f03943




Optimization runs
200
EVM Version
default




Verified at
2022-06-19 09:57:55.026803Z

Constructor Arguments

pragma solidity ^0.8.0;

abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// File: @openzeppelin/contracts/access/Ownable.sol

// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)

pragma solidity ^0.8.0;

/**
 * @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.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * 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.
 */
abstract 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() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        require(owner() == _msgSender(), "Ownable: caller is not the 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 virtual onlyOwner {
        _transferOwnership(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 virtual onlyOwner {
        require(
            newOwner != address(0),
            "Ownable: new owner is the zero address"
        );
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

contract UserStorage is Ownable {
    struct User {
        address userAddr; 
        string avatar; 
        string email;  
        uint isOnline; 
        uint userFlag; 
        uint256 credit; 
        uint regTime; 
        TradeStats tradeStats; 
        MorgageStats morgageStats; 
    }
    struct TradeStats {
        uint256 tradeTotal;
        uint256 restTotal; 
    }
    struct MorgageStats {
        uint256 mortgage; 
        uint256 freezeMortgage; 
        uint256 relieveMortgage; 
        uint256 inviteUserCount; 
        uint256 inviteUserReward; 
        uint applyRelieveTime; 
        uint handleRelieveTime; 
    }
    mapping (address => User) public users;
    mapping (address => uint256) public userIndex;
    User[] public userList; 
    event addUser(address _userAddr);
    event updateUser(string _avatar, string _email, uint _isOnline);
	address _restCAddr;
	address _orderCAddr;
	address _recordCAddr;
	address _appealCAddr;
	modifier onlyAuthFromAddr() {
		require(_restCAddr != address(0), 'Invalid address call rest');
		require(_orderCAddr != address(0), 'Invalid address call order');
		require(_recordCAddr != address(0), 'Invalid address call record');
		require(_appealCAddr != address(0), 'Invalid address call appeal');
		_;
	}
	function authFromContract(address _fromRest, address _fromOrder, address _fromRecord, address _fromAppeal) external onlyOwner {
		_restCAddr = _fromRest;
		_orderCAddr = _fromOrder;
		_recordCAddr = _fromRecord;
		_appealCAddr = _fromAppeal;
	}
    modifier onlyMemberOf() {
        require(users[msg.sender].userAddr != address(0), 'has no permission');
        _;
    }
    function _insert(address _addr) internal {
		require(_addr != address(0), "UserStorage: addr null is not allowed");
		require(users[_addr].userAddr == address(0), "UserStorage: current User exist");
		TradeStats memory tradeStats = TradeStats({tradeTotal:0, restTotal:0});
        MorgageStats memory morgageStats = MorgageStats({mortgage:0, freezeMortgage:0, relieveMortgage: 0, inviteUserCount:0, inviteUserReward:0, applyRelieveTime:0, handleRelieveTime:0});
 		User memory u = User({userAddr:_addr, avatar: '', email:'',
        isOnline:1, userFlag:0, credit:0, regTime:block.timestamp,tradeStats:tradeStats, morgageStats:morgageStats});
        users[_addr] = u;
		userList.push(u);
		userIndex[_addr] = userList.length -1;
		emit addUser(_addr);
	}
	function _updateInfo(address _addr, string memory _avatar, string memory _email, uint _isOnline) internal {
		require(_addr != address(0), "UserStorage: _addr null is not allowed");
		require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
		User memory u = users[_addr];
		if(bytes(_avatar).length != 0){
			u.avatar = _avatar;
		}
		if(bytes(_email).length != 0){
			u.email = _email;
		}
		if(_isOnline != uint(0)){
			u.isOnline = _isOnline;
		}
		users[_addr] = u;
		userList[userIndex[_addr]] = u;
	}
	function _updateTradeStats(address _addr, TradeStats memory _tradeStats, uint _credit) internal {
		require(_addr != address(0), "UserStorage: _addr null is not allowed");
		require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
		User memory u = users[_addr];
		u.credit = _credit;
		u.tradeStats.tradeTotal = _tradeStats.tradeTotal;
		u.tradeStats.restTotal = _tradeStats.restTotal;
		users[_addr] = u;
		userList[userIndex[_addr]] = u;
	}
	function _updateMorgageStats(address _addr, MorgageStats memory _morgageStats) internal {
		require(_addr != address(0), "UserStorage: _addr null is not allowed");
		require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
		User memory u = users[_addr];
		u.morgageStats.mortgage = _morgageStats.mortgage;
		u.morgageStats.freezeMortgage = _morgageStats.freezeMortgage;
		u.morgageStats.relieveMortgage = _morgageStats.relieveMortgage;
		u.morgageStats.inviteUserCount = _morgageStats.inviteUserCount;
		u.morgageStats.inviteUserReward = _morgageStats.inviteUserReward;
		u.morgageStats.applyRelieveTime = _morgageStats.applyRelieveTime;
		u.morgageStats.handleRelieveTime = _morgageStats.handleRelieveTime;
		users[_addr] = u;
		userList[userIndex[_addr]] = u;
	}
    function _search(address _addr) internal view returns(User memory user) {
		require(_addr != address(0), "UserStorage: _addr null is not allowed");
		require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
		User memory a = users[_addr];
		return a;
	}
	function register() external {
		require(!isMemberOf(), 'has registed');
		_insert(msg.sender);
	}
    function isMemberOf() public view returns (bool) {
        return (users[msg.sender].userAddr != address(0));
    }
	function updateInfo(string memory _avatar, string memory _email, uint _isOnline) onlyMemberOf external {
		_updateInfo(msg.sender, _avatar, _email, _isOnline);
		emit updateUser(_avatar, _email, _isOnline);
	}
	function updateTradeStats(address _addr, TradeStats memory _tradeStats, uint _credit) onlyAuthFromAddr public {
	    require(msg.sender == _restCAddr || msg.sender == _orderCAddr || msg.sender == _appealCAddr || msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
		_updateTradeStats(_addr, _tradeStats, _credit);
	}
	function updateMorgageStats(address _addr, MorgageStats memory _morgageStats) onlyAuthFromAddr public {
		require(msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
		_updateMorgageStats(_addr, _morgageStats);
	}
	function updateUserRole(address _addr, uint _userFlag) onlyAuthFromAddr public {
	    require(msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
	    require(_addr != address(0), "UserStorage: _addr null is not allowed");
		require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
		require(_userFlag<=3, 'UserStorage: Invalid userFlag 3');
		User memory u = users[_addr];
		u.userFlag = _userFlag;
	    users[_addr] = u;
		userList[userIndex[_addr]] = u;
	}
	function searchUser(address _addr) external view returns(User memory user) {
		return _search(_addr);
	}
	function searchUserList() external view returns(User[] memory) {
		return userList;
	}
}


abstract contract ReentrancyGuardRest {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;
    constructor() {
        _status = _NOT_ENTERED;
    }
    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}
library CountersRest {
    struct Counter {
        uint256 _value; 
    }
    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }
    function increment(Counter storage counter) internal {
        {
            if (counter._value == 0) {
				counter._value = 10000;
			}
            counter._value += 1;
        }
    }
    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        {
            counter._value = value - 1;
        }
    }
}
contract RestStorage is Ownable,ReentrancyGuardRest {
    using CountersRest for CountersRest.Counter;
    RecordInterface private _recordStorage;
    UserInterface private _userStorage;
    address recordAddress;
    struct Rest {
        address userAddr; 
        uint restNo; 
        uint restType; 
        string coinType; 
        string currencyType; 
        uint restCount; 
        uint price; 
        uint[] payType; 
        uint restStatus; 
        RestDetail restDetail; 
    }
    struct RestDetail {
        uint finishCount; 
        uint remainderCount; 
        uint limitAmountFrom; 
        uint limitAmountTo; 
        uint limitMinCredit; 
        uint limitMinMortgage; 
        string restRemark; 
        uint restTime; 
        uint updateTime; 
        uint restFee;
        string restHash;
    }
    CountersRest.Counter private _restNoCounter;
    mapping (uint => Rest) private rests;
    mapping (uint => uint) private restIndex;
    Rest[] private restList; 
	mapping(address=>mapping(uint=>uint)) restFrozenTotal;
    event RestAdd(uint _restNo, uint _restType, string  _coinType, string  _currencyType, uint _restCount, uint _price, uint[] _payType,RestDetail _restDetail);
    event RestUpdate(uint _restNo, string _coinType, string _currencyType, uint _restCount, uint _price,uint[] _payType, RestDetail _restDetail);
	address _orderCAddr;
	modifier onlyAuthFromAddr() {
        require(_orderCAddr == msg.sender, 'Invalid contract address');
		_;
	}
	function authFromContract(address _recordAddr, address _userAddr, address _orderAddr) external onlyOwner {
		_orderCAddr = _orderAddr;
        _recordStorage = RecordInterface(_recordAddr);
        _userStorage = UserInterface(_userAddr);
        recordAddress = _recordAddr;
        _restNoCounter.increment();
	}
    modifier onlyRestOwner(uint _restNo) {
		require(rests[_restNo].userAddr == msg.sender, "rest address not exist");
        _;
    }
     function _checkParam(uint _restType, string memory _coinType, string memory _currencyType, 
                        uint _restCount, uint _price, uint[] memory _payType) pure internal {
        require(_restType != uint(0), "RestStorage: restType null is not allowed");
        require(bytes(_coinType).length != 0, "RestStorage: coinType null is not allowed");
        require(bytes(_currencyType).length != 0, "RestStorage: currencyType null is not allowed");
        require(_restCount != uint(0), "RestStorage: restCount null is not allowed");
        require(_price != uint(0), "RestStorage: price null is not allowed");
        require(_payType.length != 0, "RestStorage: payType null is not allowed");
	}
    function _insert(uint _restType, string memory _coinType, string memory _currencyType, 
    uint _restCount, uint _price, uint[] memory _payType, RestDetail memory _restDetail) internal nonReentrant returns(uint){
		_checkParam(_restType, _coinType, _currencyType, _restCount, _price, _payType);
		uint _restNo = _restNoCounter.current();
        require(rests[_restNo].restNo == uint(0), "rest exist");
		_restDetail.finishCount = 0;
		_restDetail.remainderCount = _restCount;
		_restDetail.restTime = block.timestamp;
		_restDetail.updateTime = 0;
        if(_restDetail.limitAmountTo > SafeMath.mul(_restCount, _price) || _restDetail.limitAmountTo == 0) {
            _restDetail.limitAmountTo = SafeMath.mul(_restCount, _price);
        }
 		Rest memory r = Rest({userAddr: msg.sender, restNo: _restNo, restType:_restType,
         coinType:_coinType, currencyType:_currencyType,
        restCount:_restCount, price:_price,
        payType:_payType, restStatus:1, restDetail: _restDetail});
        rests[_restNo] = r;
		restList.push(r);
		restIndex[_restNo] = restList.length-1;
        _restNoCounter.increment();
		emit RestAdd(_restNo, _restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
		return _restNo;
	}
    function _updateInfo(uint _restNo, string memory _coinType, string memory _currencyType, 
    uint _addCount, uint _price, uint[] memory _payType, RestDetail memory _restDetail) internal {
		require(_restNo != uint(0), 'Invalid restNo');
		Rest memory r = rests[_restNo];
		r.restStatus = 1;
		if(bytes(_coinType).length != 0){
			r.coinType = _coinType;
		}
		if(bytes(_currencyType).length != 0){
			r.currencyType = _currencyType;
		}
		if(_price != uint(0)){
			r.price = _price;
		}
        if(_addCount != uint(0)){
			r.restCount += _addCount;
            r.restDetail.remainderCount += _addCount;
            r.restDetail.limitAmountTo = SafeMath.mul(r.restDetail.remainderCount, r.price);
		}
        if(_payType.length != 0){
			r.payType = _payType;
		}
        if(_restDetail.limitAmountFrom != uint(0)){
            if(_restDetail.limitAmountFrom > r.restDetail.limitAmountTo) {
                _restDetail.limitAmountFrom = r.restDetail.limitAmountTo;
            }
            r.restDetail.limitAmountFrom = _restDetail.limitAmountFrom;
		}
        if(_restDetail.limitMinCredit != uint(0)){
			r.restDetail.limitMinCredit = _restDetail.limitMinCredit;
		}
        if(_restDetail.limitMinMortgage != uint(0)){
			r.restDetail.limitMinMortgage = _restDetail.limitMinMortgage;
		}
        if(bytes(_restDetail.restRemark).length != 0){
			r.restDetail.restRemark = _restDetail.restRemark;
		}
		if(_restDetail.restFee != uint(0)){
			r.restDetail.restFee = _restDetail.restFee;
		}
        r.restDetail.updateTime = block.timestamp;
		rests[_restNo] = r;
        restList[restIndex[_restNo]] = r;
        emit RestUpdate(_restNo, _coinType, _currencyType, r.restCount, _price, _payType, _restDetail);
	}
	function addBuyRest(uint _restType, string memory _coinType, string memory _currencyType, 
    uint _restCount, uint _price, uint[] memory _payType,RestDetail memory _restDetail) external {
        require(_restType == 1, "must buy rest" );
        UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
        bool _openTrade = _recordStorage.getOpenTrade();
        require(_openTrade || _user.userFlag == 3, "invalid user" );
        _insert(_restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
	}
	function _addSell(uint _restType, string memory _coinType, string memory _currencyType, 
    uint _restCount, uint _restFee, uint _price, uint[] memory _payType,RestDetail memory _restDetail) internal {
	    require(_restType == 2, "must sell rest" );
        require(_restCount > 0, "restCount error");
        UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
        bool _openTrade = _recordStorage.getOpenTrade();
        require(_openTrade || _user.userFlag == 3, "invalid user" );
        _recordStorage.addRecord(msg.sender, '', _coinType, _restCount, 2, 1, 2);
        uint _needSub = SafeMath.add(_restCount, _restFee);
        TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(_coinType);
		_tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
        uint _newRestNo = _insert(_restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
        restFrozenTotal[msg.sender][_newRestNo] = _restCount;
	}
	function addSellRest(uint _restType, string memory _coinType, string memory _currencyType, 
    uint _restCount,uint _restFee, uint _price, uint[] memory _payType,RestDetail memory _restDetail) external {
        _addSell(_restType, _coinType, _currencyType, _restCount,_restFee,_price, _payType, _restDetail);
	}
	function getRestFrozenTotal(address _addr, uint _restNo) public view returns(uint) {
	    return restFrozenTotal[_addr][_restNo];
	}
	function cancelBuyRest(uint _restNo) external onlyRestOwner(_restNo) {
        require(rests[_restNo].restStatus == 1, "can't change this rest");
        require(rests[_restNo].restType == 1, "Invalid rest type");
        require(rests[_restNo].restDetail.finishCount < rests[_restNo].restCount, "this rest has finished");
        Rest memory r = rests[_restNo];
        r.restStatus = 4;
        r.restDetail.updateTime = block.timestamp;
        rests[_restNo] = r;
        restList[restIndex[_restNo]] = r;
    }
    function _cancelSell(uint _restNo) onlyRestOwner(_restNo) internal {
        require(rests[_restNo].restStatus == 1, "can't cancel this rest");
        require(rests[_restNo].restType == 2, "Invalid rest type");
        require(rests[_restNo].restDetail.finishCount < rests[_restNo].restCount, "this rest has finished");
        require(restFrozenTotal[msg.sender][_restNo] > 0, "rest has finished");
        uint _frozenTotal = _recordStorage.getFrozenTotal(msg.sender, rests[_restNo].coinType);
        require(_frozenTotal >= restFrozenTotal[msg.sender][_restNo], "can't cancel this rest");
        uint remainHoldCoin = restFrozenTotal[msg.sender][_restNo];
        Rest memory r = rests[_restNo];
        r.restStatus = 4;
        if (remainHoldCoin < rests[_restNo].restCount) {
            r.restStatus = 5;
        }
        r.restDetail.remainderCount = 0;
        r.restDetail.updateTime = block.timestamp;
        rests[_restNo] = r;
        restList[restIndex[_restNo]] = r;
        restFrozenTotal[msg.sender][_restNo] = 0;
        _recordStorage.addAvailableTotal(msg.sender, rests[_restNo].coinType, remainHoldCoin);
    }
    function cancelSellRest(uint _restNo) external{
        _cancelSell(_restNo);
    }
    function startOrStop(uint _restNo, uint _restStatus) external onlyRestOwner(_restNo){
        require(_restStatus == 1 || _restStatus == 3, "Invalid rest status");
        Rest memory r = rests[_restNo];
        require(r.restStatus == 1 || r.restStatus == 3, "Invalid rest status,opt error");
        r.restStatus = _restStatus;
        r.restDetail.updateTime = block.timestamp;
        rests[_restNo] = r;
        restList[restIndex[_restNo]] = r;
    }
	function updateInfo(uint _restNo, string memory _coinType, string memory _currencyType, 
    uint _addCount, uint _restFee, uint _price,uint[] memory _payType, RestDetail memory _restDetail) external onlyRestOwner(_restNo){
		require(_restNo != uint(0), 'Invalid restNo');
		Rest memory _rest = rests[_restNo];
		require(_rest.restNo != uint(0), 'rest not exist');
		if (_rest.restType == 2) {
            _recordStorage.addRecord(msg.sender, '', _coinType, _addCount, 2, 1, 2);
            uint _needSub = SafeMath.add(_addCount, _restFee);
            TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(_coinType);
            _tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
            restFrozenTotal[msg.sender][_restNo] += _addCount;
		}
        _updateInfo(_restNo, _coinType, _currencyType, _addCount, _price, _payType, _restDetail);
	}
    function updateRestFinishCount(uint _restNo, uint _finishCount) onlyAuthFromAddr external {
        Rest memory _rest = rests[_restNo];
        require(_rest.restDetail.remainderCount >= _finishCount, "RestStorage:finish count error");
        if (_rest.restType == 2) {
            restFrozenTotal[_rest.userAddr][_restNo] = SafeMath.sub(restFrozenTotal[_rest.userAddr][_restNo], _finishCount);
        }
        _rest.restDetail.finishCount = SafeMath.add(_rest.restDetail.finishCount, _finishCount);
        _rest.restDetail.remainderCount = SafeMath.sub(_rest.restDetail.remainderCount, _finishCount);
        _rest.restDetail.limitAmountTo = SafeMath.mul(_rest.price, _rest.restDetail.remainderCount);
        if (_rest.restDetail.remainderCount == 0) {
            _rest.restStatus = 2;
        }
        _rest.restDetail.updateTime = block.timestamp;
		rests[_restNo] = _rest;
        restList[restIndex[_restNo]] = _rest;
    }
    function addRestRemainCount(uint _restNo, uint _remainCount) onlyAuthFromAddr public {
        Rest memory _rest = rests[_restNo];
        require(_remainCount > 0 && _rest.restDetail.finishCount >= _remainCount, "count error");
        if (_rest.restType == 2) {
            restFrozenTotal[_rest.userAddr][_restNo] = SafeMath.add(restFrozenTotal[_rest.userAddr][_restNo], _remainCount);
        }
        _rest.restDetail.finishCount = SafeMath.sub(_rest.restDetail.finishCount, _remainCount);
        _rest.restDetail.remainderCount = SafeMath.add(_rest.restDetail.remainderCount, _remainCount);
        _rest.restDetail.limitAmountTo = SafeMath.mul(_rest.price, _rest.restDetail.remainderCount);
        _rest.restDetail.limitAmountFrom = _rest.restDetail.limitAmountFrom > _rest.restDetail.limitAmountTo ? _rest.restDetail.limitAmountTo : _rest.restDetail.limitAmountFrom;
        _rest.restStatus = 1;
        _rest.restDetail.updateTime = block.timestamp;
		rests[_restNo] = _rest;
        restList[restIndex[_restNo]] = _rest;
    }
	function searchRest(uint _restNo) external view returns(Rest memory rest) {
	    require(_restNo != uint(0), "restNo null is not allowed");
		Rest memory r = rests[_restNo];
		return r;
	}
	function searchRestList() external view returns(Rest[] memory) {
        return restList;
	}
}


abstract contract ReentrancyGuardOrder {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;
    uint256 private _status;
    constructor() {
        _status = _NOT_ENTERED;
    }
    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
        _status = _ENTERED;
        _;
        _status = _NOT_ENTERED;
    }
}
library CountersOrder {
    struct Counter {
        uint256 _value;
    }
    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }
    function increment(Counter storage counter) internal {
        {
            if (counter._value == 0) {
                counter._value = 10000;
            }
            counter._value += 1;
        }
    }
    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        {
            counter._value = value - 1;
        }
    }
}
contract OrderStorage is Ownable, ReentrancyGuardOrder {
    using CountersOrder for CountersOrder.Counter;
    RestStorage private _restStorage;
    RecordInterface private _recordStorage;
    UserInterface private _userStorage;
    AppealInterface private _appealS;
    address recordAddress;
    struct Order {
        address userAddr;
        uint256 orderNo;
        uint256 restNo;
        uint256 coinCount;
        uint256 orderAmount;
        uint256 payType;
        string currencyType;
        uint256 orderType;
        uint256 orderStatus;
        OrderDetail orderDetail;
    }
    struct OrderDetail {
        address buyerAddr;
        address sellerAddr;
        string coinType;
        uint256 price;
        uint256 tradeTime;
        uint256 updateTime;
        string tradeHash;
        uint256 tradeFee;
    }
    CountersOrder.Counter private _orderNoCounter;
    mapping(uint256 => Order) private orders;
    mapping(uint256 => uint256) private orderIndex;
    Order[] private orderList;
    mapping(address => mapping(uint256 => uint256)) orderFrozenTotal;
    uint256 cancelOrderTime = 30;
    function setCancelOrderTime(uint256 _count) public onlyOwner {
        cancelOrderTime = _count;
    }
    function getCancelOrderTime() public view returns (uint256) {
        return cancelOrderTime;
    }
    uint256 canWithdrawHours = 24;
    function setCanWithdrawHours(uint256 _count) public onlyOwner {
        canWithdrawHours = _count;
    }
    function getCanWithdrawHours() public view returns (uint256) {
        return canWithdrawHours;
    }
    event OrderAdd(
        uint256 _orderNo,
        uint256 _restNo,
        uint256 _coinCount,
        uint256 _tradeFee,
        uint256 _orderAmount,
        uint256 _payType,
        uint256 _orderType,
        address _buyerAddr,
        address _sellerAddr
    );
    event OrderPaidMoney(uint256 _orderNo);
    event OrderConfirmCollect(uint256 _orderNo);
    event OrderCancel(uint256 _orderNo);
    event OrderUpdateStatus(uint256 _orderNo, uint256 _orderStatus);
    function authFromContract(
        address _recordAddr,
        address _restAddr,
        address _userAddr,
        address _appealAddr
    ) external onlyOwner {
        _recordStorage = RecordInterface(_recordAddr);
        _restStorage = RestStorage(_restAddr);
        _userStorage = UserInterface(_userAddr);
        recordAddress = _recordAddr;
        _appealS = AppealInterface(_appealAddr);
        _orderNoCounter.increment();
    }
    modifier onlyBuyer(uint256 _orderNo) {
        require(_orderNo != uint256(0), "orderNo null");
        require(
            orders[_orderNo].orderDetail.buyerAddr == msg.sender,
            "only buyer"
        );
        _;
    }
    modifier onlySeller(uint256 _orderNo) {
        require(_orderNo != uint256(0), "orderNo null");
        require(
            orders[_orderNo].orderDetail.sellerAddr == msg.sender,
            "only seller"
        );
        _;
    }
    modifier onlyBuyerOrSeller(uint256 _orderNo) {
        require(_orderNo != uint256(0), "orderNo null");
        require(
            orders[_orderNo].orderDetail.sellerAddr == msg.sender ||
                orders[_orderNo].orderDetail.buyerAddr == msg.sender,
            "Only buyer or seller"
        );
        _;
    }
    function _checkParam(
        uint256 _restNo,
        uint256 _coinCount,
        uint256 _orderAmount,
        uint256 _payType
    ) internal pure {
        require(_restNo != uint256(0), "restNo null");
        require(_coinCount > 0, "coinCount null");
        require(_orderAmount > 0, "orderAmount null");
        require(_payType != uint256(0), "payType null");
    }
    function _insert(
        uint256 _restNo,
        uint256 _coinCount,
        uint256 _tradeFee,
        uint256 _orderAmount,
        uint256 _payType,
        uint256 _orderType,
        address _buyerAddr,
        address _sellerAddr
    ) internal nonReentrant returns (uint256 restNo) {
        _checkParam(_restNo, _coinCount, _orderAmount, _payType);
        RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
        require(_rest.userAddr != address(0), "rest not exist");
        OrderDetail memory _orderDetail = OrderDetail({
            buyerAddr: _buyerAddr,
            sellerAddr: _sellerAddr,
            coinType: _rest.coinType,
            price: _rest.price,
            tradeTime: block.timestamp,
            updateTime: 0,
            tradeHash: "",
            tradeFee: _tradeFee
        });
        uint256 _orderNo = _orderNoCounter.current();
        require(orders[_orderNo].orderNo == uint256(0), "order exist");
        Order memory order = Order({
            userAddr: msg.sender,
            orderNo: _orderNo,
            restNo: _restNo,
            coinCount: _coinCount,
            orderAmount: _orderAmount,
            payType: _payType,
            currencyType: _rest.currencyType,
            orderType: _orderType,
            orderStatus: 1,
            orderDetail: _orderDetail
        });
        orders[_orderNo] = order;
        orderList.push(order);
        orderIndex[_orderNo] = orderList.length - 1;
        if (_orderType == 2) {
            orderFrozenTotal[msg.sender][_orderNo] = _coinCount;
        } else if (_orderType == 1) {
            orderFrozenTotal[_rest.userAddr][_orderNo] = _coinCount;
        }
        _orderNoCounter.increment();
        emit OrderAdd(
            _orderNo,
            _restNo,
            _coinCount,
            _tradeFee,
            _orderAmount,
            _payType,
            _orderType,
            _buyerAddr,
            _sellerAddr
        );
        return _orderNo;
    }
    function addBuyOrder(
        uint256 _restNo,
        uint256 _coinCount,
        uint256 _orderAmount,
        uint256 _payType
    ) external {
        RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
        require(_rest.userAddr != msg.sender, "rest not exist");
        require(_rest.restType == 2, "sell rest not exist");
        require(_coinCount > 0 && _orderAmount > 0, "coin count error");
        require(_rest.restStatus == 1, "rest status error");
        UserStorage.User memory _currentUser = _userStorage.searchUser(
            msg.sender
        );
        require(
            _currentUser.userFlag != 1 && _currentUser.userFlag != 2,
            "invalid user"
        );
        uint256 _restFrozen = _restStorage.getRestFrozenTotal(
            _rest.userAddr,
            _restNo
        );
        require(_restFrozen >= _coinCount, "coin not enough");
        uint256 _amo = SafeMath.mul(_rest.price, _coinCount);
        require(
            _amo >= _rest.restDetail.limitAmountFrom &&
                _amo <= _rest.restDetail.limitAmountTo,
            "amount error"
        );
        require(
            _currentUser.credit >= _rest.restDetail.limitMinCredit,
            "credit error"
        );
        require(
            _currentUser.morgageStats.mortgage >=
                _rest.restDetail.limitMinMortgage,
            "mortgage error"
        );
        _restStorage.updateRestFinishCount(_restNo, _coinCount);
        _insert(
            _restNo,
            _coinCount,
            0,
            _orderAmount,
            _payType,
            1,
            msg.sender,
            _rest.userAddr
        );
    }
    function addSellOrder(
        uint256 _restNo,
        uint256 _coinCount,
        uint256 _tradeFee,
        uint256 _orderAmount,
        uint256 _payType
    ) external {
        RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
        require(_rest.userAddr != msg.sender, "rest not exist");
        require(_rest.restType == 1, "buy rest not exist");
        require(_coinCount > 0, "coin count error");
        require(_orderAmount > 0, "orderAmount error");
        require(_rest.restStatus == 1, "rest status error");
        uint256 _amo = SafeMath.mul(_rest.price, _coinCount);
        require(
            _amo >= _rest.restDetail.limitAmountFrom &&
                _amo <= _rest.restDetail.limitAmountTo,
            "amount error"
        );
        UserStorage.User memory _currentUser = _userStorage.searchUser(
            msg.sender
        );
        require(
            _currentUser.userFlag != 1 && _currentUser.userFlag != 2,
            "invalid user"
        );
        require(
            _currentUser.credit >= _rest.restDetail.limitMinCredit,
            "credit error"
        );
        require(
            _currentUser.morgageStats.mortgage >=
                _rest.restDetail.limitMinMortgage,
            "mortgage error"
        );
        uint256 _needSub = SafeMath.add(_coinCount, _tradeFee);
        _restStorage.updateRestFinishCount(_restNo, _coinCount);
        _insert(
            _restNo,
            _coinCount,
            _tradeFee,
            _orderAmount,
            _payType,
            2,
            _rest.userAddr,
            msg.sender
        );
        TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(
            _rest.coinType
        );
        _tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
        _recordStorage.addRecord(
            msg.sender,
            "",
            _rest.coinType,
            _coinCount,
            2,
            1,
            2
        );
    }
    function setPaidMoney(uint256 _orderNo)
        external
        onlyBuyer(_orderNo)
        returns (bool)
    {
        _updateOrderStatus(_orderNo, 2);
        emit OrderPaidMoney(_orderNo);
        return true;
    }
    function confirmCollect(uint256 _orderNo) external onlySeller(_orderNo) {
        require(_orderNo != uint256(0), "orderNo null");
        Order memory _order = orders[_orderNo];
        require(_order.orderStatus == 2, "Invalid order status");
        require(
            _order.orderDetail.buyerAddr != address(0),
            "Invalid buyer address"
        );
        require(
            orderFrozenTotal[msg.sender][_orderNo] >= _order.coinCount,
            "coin not enough"
        );
        _updateOrderStatus(_orderNo, 3);
        orderFrozenTotal[msg.sender][_orderNo] = 0;
        uint256 _rc = _recordStorage.getTradeCredit();
        UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
        uint256 _credit = _user.credit + _rc;
        UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
        _tradeStats.tradeTotal += 1;
        _userStorage.updateTradeStats(msg.sender, _tradeStats, _credit);
        UserStorage.User memory _user2 = _userStorage.searchUser(
            _order.orderDetail.buyerAddr
        );
        uint256 _credit2 = _user2.credit + _rc;
        UserStorage.TradeStats memory _tradeStats2 = _user2.tradeStats;
        _tradeStats2.tradeTotal += 1;
        _userStorage.updateTradeStats(
            _order.orderDetail.buyerAddr,
            _tradeStats2,
            _credit2
        );
        _recordStorage.subFrozenTotal(_orderNo, _order.orderDetail.buyerAddr);
        emit OrderConfirmCollect(_orderNo);
    }
    function cancelOrder(uint256 _orderNo)
        external
        onlyBuyerOrSeller(_orderNo)
        returns (bool)
    {
        Order memory _order = orders[_orderNo];
        require(_order.orderNo != uint256(0), "current Order not exist");
        require(_order.orderStatus == 1, "Can't cancel order");
        if (_order.orderDetail.sellerAddr == msg.sender) {
            require(
                _order.orderDetail.tradeTime + cancelOrderTime * 1 minutes <
                    block.timestamp,
                "limit"
            );
        }
        RestStorage.Rest memory _rest = _restStorage.searchRest(_order.restNo);
        if (_rest.restStatus == 4 || _rest.restStatus == 5) {
            orderFrozenTotal[_order.orderDetail.sellerAddr][_orderNo] = 0;
            _recordStorage.addAvailableTotal(
                _order.orderDetail.sellerAddr,
                _order.orderDetail.coinType,
                _order.coinCount
            );
        } else {
            if (_order.orderType == 2) {
                orderFrozenTotal[_order.orderDetail.sellerAddr][_orderNo] = 0;
                _recordStorage.addAvailableTotal(
                    _order.orderDetail.sellerAddr,
                    _order.orderDetail.coinType,
                    _order.coinCount
                );
            }
            _restStorage.addRestRemainCount(_order.restNo, _order.coinCount);
        }
        _updateOrderStatus(_orderNo, 4);
        emit OrderCancel(_orderNo);
        return true;
    }
    function takeCoin(uint256 _o) external onlyBuyerOrSeller(_o) {
        AppealStorage.Appeal memory _appeal = _appealS.searchAppeal(_o);
        require(
            block.timestamp - _appeal.detail.witnessHandleTime >
                canWithdrawHours * 1 hours,
            "time error"
        );
        address _win;
        if (_appeal.user == _appeal.buyer) {
            if (_appeal.status == 2) {
                _win = _appeal.buyer;
            } else if (_appeal.status == 3) {
                _win = _appeal.seller;
            }
        } else {
            if (_appeal.status == 2) {
                _win = _appeal.seller;
            } else if (_appeal.status == 3) {
                _win = _appeal.buyer;
            }
        }
        require(_win == msg.sender, "opt error");
        _updateOrderStatus(_o, 5);
        orderFrozenTotal[_appeal.seller][_o] = 0;
        _recordStorage.subFrozenTotal(_o, msg.sender);
    }
    function _updateOrderStatus(uint256 _orderNo, uint256 _orderStatus)
        internal
        onlyBuyerOrSeller(_orderNo)
    {
        Order memory order = orders[_orderNo];
        require(order.orderNo != uint256(0), "current Order not exist");
        require(_orderStatus >= 1 && _orderStatus <= 5, "Invalid order status");
        if (_orderStatus == 2 && order.orderStatus != 1) {
            revert("Invalid order status 2");
        }
        if (_orderStatus == 3 && order.orderStatus != 2) {
            revert("Invalid order status 3");
        }
        if (_orderStatus == 4 && order.orderStatus != 1) {
            revert("Invalid order status 4");
        }
        if (
            _orderStatus == 5 &&
            order.orderStatus != 1 &&
            order.orderStatus != 2
        ) {
            revert("Invalid order status 5");
        }
        if (_orderStatus == 2) {
            require(
                order.orderDetail.buyerAddr == msg.sender,
                "only buyer call"
            );
        }
        if (_orderStatus == 3) {
            require(
                order.orderDetail.sellerAddr == msg.sender,
                "only seller call"
            );
        }
        order.orderStatus = _orderStatus;
        order.orderDetail.updateTime = block.timestamp;
        orders[_orderNo] = order;
        orderList[orderIndex[_orderNo]] = order;
        emit OrderUpdateStatus(_orderNo, _orderStatus);
    }
    function searchOrder(uint256 _orderNo)
        external
        view
        returns (Order memory order)
    {
        require(_orderNo != uint256(0), "orderNo null");
        require(
            orders[_orderNo].orderNo != uint256(0),
            "current Order not exist"
        );
        Order memory o = orders[_orderNo];
        return o;
    }
    function searchOrderList() external view returns (Order[] memory) {
        return orderList;
    }
    function searchListByRest(uint256 _restNo)
        external
        view
        returns (Order[] memory)
    {
        Order[] memory resultList = new Order[](orderList.length);
        for (uint256 i = 0; i < orderList.length; i++) {
            Order memory _order = orderList[i];
            if (_order.restNo == _restNo) {
                resultList[i] = _order;
            }
        }
        return resultList;
    }
}


library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            // 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 (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b)
        internal
        pure
        returns (bool, uint256)
    {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @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) {
        return a + b;
    }

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

    /**
     * @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) {
        return a * b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator.
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting 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 a % b;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b <= a, errorMessage);
            return a - b;
        }
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting 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.
     */
    function div(
        uint256 a,
        uint256 b,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a / b;
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * 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,
        string memory errorMessage
    ) internal pure returns (uint256) {
        unchecked {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
}

contract AppealStorage {
    OrderInterface private _oSt;
    RecordInterface private _rSt;
    UserInterface private _uSt;
    address recAddr;

    struct Appeal {
        address user;
        uint256 appealNo;
        uint256 orderNo;
        address witness;
        address buyer;
        address seller;
        uint256 mortgage;
        uint256 status;
        uint256 appealTime;
        uint256 witTakeTime;
        uint256 obTakeTime;
        AppealDetail detail;
    }

    struct AppealDetail {
        address finalAppealAddr;
        uint256 updateTime;
        string witnessReason;
        uint256 witnessAppealStatus;
        string observerReason;
        uint256 witnessHandleTime;
        uint256 observerHandleTime;
        address observerAddr;
        uint256 witnessHandleReward;
        uint256 observerHandleReward;
        uint256 witnessHandleCredit;
        uint256 observerHandleCredit;
        uint256 witReward;
        uint256 witSub;
        uint256 witCreditR;
        uint256 witCreditS;
    }

    mapping(uint256 => Appeal) public appeals;
    mapping(uint256 => uint256) public appealIndex;

    Appeal[] public appealList;

    event addAppeal(uint256 _appealNo, uint256 _orderNo);

    constructor(
        address _r,
        address _o,
        address _u
    ) {
        _rSt = RecordInterface(_r);
        _oSt = OrderInterface(_o);
        _uSt = UserInterface(_u);
        recAddr = _r;
    }

    modifier onlyWit(uint256 _o) {
        Appeal memory _al = appeals[_o];
        require(_al.witness == msg.sender);
        require(_al.buyer != msg.sender && _al.seller != msg.sender);
        _;
    }

    modifier onlyOb(uint256 _o) {
        Appeal memory _al = appeals[_o];
        require(_al.detail.observerAddr == msg.sender);
        require(_al.buyer != msg.sender && _al.seller != msg.sender);
        _;
    }

    modifier onlyBOS(uint256 _o) {
        OrderStorage.Order memory _r = _oSt.searchOrder(_o);
        require(
            _r.orderDetail.sellerAddr == msg.sender ||
                _r.orderDetail.buyerAddr == msg.sender
        );
        _;
    }

    function _insert(uint256 _o, uint256 _count) internal {
        OrderStorage.Order memory _or = _oSt.searchOrder(_o);

        require(appeals[_o].appealNo == uint256(0));

        AppealDetail memory _detail = AppealDetail({
            finalAppealAddr: address(0),
            updateTime: uint256(0),
            witnessReason: "",
            observerReason: "",
            witnessAppealStatus: 0,
            witnessHandleTime: uint256(0),
            observerHandleTime: uint256(0),
            observerAddr: address(0),
            witnessHandleReward: 0,
            observerHandleReward: 0,
            witnessHandleCredit: 0,
            observerHandleCredit: 0,
            witReward: 0,
            witSub: 0,
            witCreditR: 0,
            witCreditS: 0
        });

        uint256 _appealNo = block.timestamp;

        Appeal memory _appeal = Appeal({
            user: msg.sender,
            appealNo: _appealNo,
            orderNo: _o,
            witness: address(0),
            buyer: _or.orderDetail.buyerAddr,
            seller: _or.orderDetail.sellerAddr,
            mortgage: _count,
            status: 1,
            appealTime: block.timestamp,
            witTakeTime: 0,
            obTakeTime: 0,
            detail: _detail
        });

        appeals[_o] = _appeal;

        appealList.push(_appeal);
        appealIndex[_o] = appealList.length - 1;

        chanT(_or.orderDetail.sellerAddr, _or.orderDetail.buyerAddr, 1, 0);

        emit addAppeal(_appealNo, _o);
    }

    function chanT(
        address _seller,
        address _buyer,
        uint256 _t,
        uint256 _r
    ) internal {
        uint256 _tc = _rSt.getTradeCredit();
        uint256 _rs = _rSt.getSubTCredit();

        UserStorage.User memory _user = _uSt.searchUser(_seller);
        UserStorage.TradeStats memory _tr = _user.tradeStats;

        UserStorage.User memory _user2 = _uSt.searchUser(_buyer);
        UserStorage.TradeStats memory _tr2 = _user2.tradeStats;
        uint256 _c2 = _user2.credit;

        uint256 _c = _user.credit;
        if (_t == 1) {
            _tr.tradeTotal = _tr.tradeTotal > 0 ? (_tr.tradeTotal - 1) : 0;
            _tr2.tradeTotal = _tr2.tradeTotal > 0 ? (_tr2.tradeTotal - 1) : 0;

            _c = (_c >= _tc) ? (_c - _tc) : 0;

            _c2 = (_c2 >= _tc) ? (_c2 - _tc) : 0;
        } else if (_t == 2) {
            _tr.tradeTotal += 1;
            _tr2.tradeTotal += 1;

            if (_r == 1) {
                _c += _tc;
                _c2 = (_c2 >= _rs) ? (_c2 - _rs) : 0;
            } else if (_r == 2) {
                _c2 += _tc;
                _c = (_c >= _rs) ? (_c - _rs) : 0;
            }
        }

        _uSt.updateTradeStats(_seller, _tr, _c);
        _uSt.updateTradeStats(_buyer, _tr2, _c2);
    }

    function applyAppeal(uint256 _o) external onlyBOS(_o) {
        uint256 _fee = _rSt.getAppealFee();
        _insert(_o, _fee);

        TokenTransfer _tokenTransfer = _rSt.getERC20Address("wROSE");
        _tokenTransfer.transferFrom(msg.sender, recAddr, _fee);
    }

    function takeWit(uint256 _o) external {
        Appeal memory _al = appeals[_o];

        require(_al.buyer != msg.sender && _al.seller != msg.sender);

        require(_al.witness == address(0));
        require(_al.status == 1);

        bool _f = witOrOb(1);
        require(_f);

        _al.witness = msg.sender;
        _al.witTakeTime = block.timestamp;

        appeals[_o] = _al;
        appealList[appealIndex[_o]] = _al;
    }

    function takeOb(uint256 _o) external {
        Appeal memory _al = appeals[_o];

        require(_al.buyer != msg.sender && _al.seller != msg.sender);

        require(_al.status == 4 || _al.status == 5);
        require(_al.detail.observerAddr == address(0));

        bool _f = witOrOb(2);
        require(_f);

        _al.detail.observerAddr = msg.sender;
        _al.obTakeTime = block.timestamp;

        appeals[_o] = _al;
        appealList[appealIndex[_o]] = _al;
    }

    function changeHandler(uint256 _o, uint256 _type) external onlyBOS(_o) {
        Appeal memory _al = appeals[_o];

        if (_type == 1) {
            require(_al.status == 1);
            require(_al.witness != address(0));
            require(block.timestamp - _al.witTakeTime > 24 hours);

            _al.witness = address(0);
            _al.witTakeTime = 0;
        } else if (_type == 2) {
            require(_al.status == 4 || _al.status == 5);
            require(_al.detail.observerAddr != address(0));
            require(block.timestamp - _al.obTakeTime > 24 hours);

            _al.detail.observerAddr = address(0);
            _al.obTakeTime = 0;
        }

        appeals[_o] = _al;
        appealList[appealIndex[_o]] = _al;
    }

    function witOrOb(uint256 _f) internal view returns (bool) {
        UserStorage.User memory _u = _uSt.searchUser(msg.sender);
        if (_u.userFlag == _f) {
            return true;
        }
        return false;
    }

    function applyFinal(uint256 _o) external onlyBOS(_o) {
        Appeal memory _al = appeals[_o];

        require(_al.status == 2 || _al.status == 3);

        require(block.timestamp - _al.detail.witnessHandleTime <= 24 hours);

        chanT(_al.seller, _al.buyer, 1, 0);

        uint256 _fee = _rSt.getAppealFeeFinal();

        TokenTransfer _tokenTransfer = _rSt.getERC20Address("wROSE");
        _tokenTransfer.transferFrom(msg.sender, recAddr, _fee);

        if (_al.status == 2) {
            _al.status = 4;
        } else if (_al.status == 3) {
            _al.status = 5;
        }
        _al.detail.finalAppealAddr = msg.sender;
        _al.detail.updateTime = block.timestamp;
        appeals[_o] = _al;
        appealList[appealIndex[_o]] = _al;
    }

    function witnessOpt(
        uint256 _o,
        string memory _r,
        uint256 _s
    ) external onlyWit(_o) {
        require(_s == 2 || _s == 3);
        Appeal memory _al = appeals[_o];

        require(_al.status == 1);
        uint256 _fee = _rSt.getAppealFee();
        uint256 _rcedit = _rSt.getWitnessHandleCredit();

        _al.status = _s;
        _al.detail.witnessAppealStatus = _s;
        _al.detail.witnessReason = _r;
        _al.detail.witnessHandleTime = block.timestamp;
        _al.detail.witnessHandleReward = _fee;
        _al.detail.witnessHandleCredit = _rcedit;
        _al.detail.witReward = _fee;
        _al.detail.witCreditR = _rcedit;

        _al.detail.updateTime = block.timestamp;
        appeals[_o] = _al;
        appealList[appealIndex[_o]] = _al;

        if (_s == 2) {
            if (_al.user == _al.buyer) {
                _rSt.subAvaAppeal(_al.seller, _al.buyer, _al, _fee, 1, 0);
                chanT(_al.seller, _al.buyer, 2, 2);
            } else if (_al.user == _al.seller) {
                _rSt.subAvaAppeal(_al.buyer, _al.seller, _al, _fee, 1, 0);

                chanT(_al.seller, _al.buyer, 2, 1);
            }
        }

        if (_s == 3) {
            if (_al.user == _al.buyer) {
                _rSt.subAvaAppeal(_al.buyer, _al.seller, _al, _fee, 1, 1);
                chanT(_al.seller, _al.buyer, 2, 1);
            } else if (_al.user == _al.seller) {
                _rSt.subAvaAppeal(_al.seller, _al.buyer, _al, _fee, 1, 1);
                chanT(_al.seller, _al.buyer, 2, 2);
            }
        }
    }

    function observerOpt(
        uint256 _o,
        string memory _r,
        uint256 _s
    ) external onlyOb(_o) {
        require(_s == 6 || _s == 7);
        Appeal memory _appeal = appeals[_o];

        require(_appeal.status == 4 || _appeal.status == 5);
        uint256 _fee = _rSt.getAppealFeeFinal();
        uint256 _rcedit = _rSt.getObserverHandleCredit();

        _appeal.status = _s;
        _appeal.detail.observerReason = _r;
        _appeal.detail.observerHandleTime = block.timestamp;
        _appeal.detail.observerHandleReward = _fee;
        _appeal.detail.observerHandleCredit = _rcedit;

        uint256 _subWC = _rSt.getSubWitCredit();
        uint256 _subWF = _rSt.getSubWitFee();

        if (_s == 6) {
            if (_appeal.user == _appeal.buyer) {
                _rSt.subAvaAppeal(
                    _appeal.seller,
                    _appeal.buyer,
                    _appeal,
                    _fee,
                    2,
                    0
                );

                chanT(_appeal.seller, _appeal.buyer, 2, 2);
                _rSt.subFrozenTotal(_o, _appeal.buyer);
            } else if (_appeal.user == _appeal.seller) {
                _rSt.subAvaAppeal(
                    _appeal.buyer,
                    _appeal.seller,
                    _appeal,
                    _fee,
                    2,
                    0
                );

                chanT(_appeal.seller, _appeal.buyer, 2, 1);
                _rSt.subFrozenTotal(_o, _appeal.seller);
            }
            if (_appeal.detail.witnessAppealStatus == 3) {
                _appeal.detail.witSub = _subWF;
                _appeal.detail.witCreditS = _subWC;

                if (_appeal.detail.witnessHandleCredit >= _subWC) {
                    _appeal.detail.witnessHandleCredit = SafeMath.sub(
                        _appeal.detail.witnessHandleCredit,
                        _subWC
                    );
                } else {
                    _appeal.detail.witnessHandleCredit = 0;
                }
                _rSt.subWitnessAvailable(_appeal.witness);
            }
        }

        if (_s == 7) {
            if (_appeal.user == _appeal.buyer) {
                _rSt.subAvaAppeal(
                    _appeal.buyer,
                    _appeal.seller,
                    _appeal,
                    _fee,
                    2,
                    1
                );
                chanT(_appeal.seller, _appeal.buyer, 2, 1);
                _rSt.subFrozenTotal(_o, _appeal.seller);
            } else if (_appeal.user == _appeal.seller) {
                _rSt.subAvaAppeal(
                    _appeal.seller,
                    _appeal.buyer,
                    _appeal,
                    _fee,
                    2,
                    1
                );
                chanT(_appeal.seller, _appeal.buyer, 2, 2);
                _rSt.subFrozenTotal(_o, _appeal.buyer);
            }
            if (_appeal.detail.witnessAppealStatus == 2) {
                _appeal.detail.witSub = _subWF;
                _appeal.detail.witCreditS = _subWC;

                if (_appeal.detail.witnessHandleCredit >= _subWC) {
                    _appeal.detail.witnessHandleCredit = SafeMath.sub(
                        _appeal.detail.witnessHandleCredit,
                        _subWC
                    );
                } else {
                    _appeal.detail.witnessHandleCredit = 0;
                }
                _rSt.subWitnessAvailable(_appeal.witness);
            }
        }

        _appeal.detail.updateTime = block.timestamp;
        appeals[_o] = _appeal;
        appealList[appealIndex[_o]] = _appeal;
    }

    function searchAppeal(uint256 _o)
        external
        view
        returns (Appeal memory appeal)
    {
        return appeals[_o];
    }

    function searchAppealList() external view returns (Appeal[] memory) {
        return appealList;
    }
}





interface RecordInterface {
    function getErcBalance(string memory _coinType, address _addr)
        external
        returns (uint256);
    function getAvailableTotal(address _addr, string memory _coinType)
        external
        returns (uint256);
    function getFrozenTotal(address _addr, string memory _coinType)
        external
        returns (uint256);
    function addAvailableTotal(
        address _addr,
        string memory _coinType,
        uint256 remainHoldCoin
    ) external;
    function subAvaAppeal(
        address _from,
        address _to,
        AppealStorage.Appeal memory _al,
        uint256 _amt,
        uint256 _type,
        uint256 _self
    ) external;
    function subWitnessAvailable(address _addr) external;
    function getERC20Address(string memory _coinType)
        external
        returns (TokenTransfer);
    function subFrozenTotal(uint256 _orderNo, address _addr) external;
    function addRecord(
        address _addr,
        string memory _tradeHash,
        string memory _coinType,
        uint256 _hostCount,
        uint256 _hostStatus,
        uint256 _hostType,
        uint256 _hostDirection
    ) external;
    function getAppealFee() external view returns (uint256);
    function getAppealFeeFinal() external view returns (uint256);
    function getWitnessHandleReward() external view returns (uint256);
    function getObserverHandleReward() external view returns (uint256);
    function getWitnessHandleCredit() external view returns (uint256);
    function getObserverHandleCredit() external view returns (uint256);
    function getSubWitCredit() external view returns (uint256);
    function getOpenTrade() external view returns (bool);
    function getTradeCredit() external view returns (uint256);
    function getSubTCredit() external view returns (uint256);
    function getSubWitFee() external view returns (uint256);
}
interface RestInterface {
    function searchRest(uint256 _restNo)
        external
        returns (RestStorage.Rest memory rest);
    function getRestFrozenTotal(address _addr, uint256 _restNo)
        external
        returns (uint256);
    function updateRestFinishCount(uint256 _restNo, uint256 _coinCount)
        external
        returns (uint256);
    function addRestRemainCount(uint256 _restNo, uint256 _remainCount)
        external
        returns (uint256);
}
interface OrderInterface {
    function searchOrder(uint256 _orderNo)
        external
        returns (OrderStorage.Order memory order);
}
interface UserInterface {
    function searchUser(address _addr)
        external
        view
        returns (UserStorage.User memory user);
    function searchWitnessList(uint256 _userFlag)
        external
        returns (UserStorage.User[] memory userList);
    function updateTradeStats(
        address _addr,
        UserStorage.TradeStats memory _tradeStats,
        uint256 _credit
    ) external;
    function updateMorgageStats(
        address _addr,
        UserStorage.MorgageStats memory _morgageStats
    ) external;
    function updateUserRole(address _addr, uint256 _userFlag) external;
}
interface AppealInterface {
    function searchAppeal(uint256 _o)
        external
        view
        returns (AppealStorage.Appeal memory appeal);
}


abstract contract ReentrancyGuardRecord {
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    modifier nonReentrant() {
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        _status = _ENTERED;

        _;

        _status = _NOT_ENTERED;
    }
}

library CountersRecord {
    struct Counter {
        uint256 _value;
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        {
            if (counter._value == 0) {
                counter._value = 10000;
            }
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        {
            counter._value = value - 1;
        }
    }
}

interface TokenTransfer {
    function transfer(address recipient, uint256 amount) external;

    function balanceOf(address account) external view returns (uint256);

    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external;

    function allowance(address _owner, address _spender)
        external
        view
        returns (uint256 remaining);
}

contract RecordStorage is Ownable, ReentrancyGuardRecord {
    using CountersRecord for CountersRecord.Counter;

    string constant P_COIN = 'wROSE';

    mapping(string => address) coinTypeMaping;
    uint256 merchantNeedCount = 100 * (10**18);
	uint256 witnessNeedCount =  1000 * (10**18);
	uint256 congressNeedCount = 10000 * (10**18);
	uint256 appealFee = 100 * (10**18);
	uint256 appealFeeFinal = 1000 * (10**18);
	uint256 canWithdrawToTime = 28;
	uint256 subWitFee = 100 * (10**18);
	uint256 subWitCredit = 10;
	uint256 witnessHandleReward = 100 * (10**18);
	uint256 observerHandleReward = 1000 * (10**18);
	uint256 witnessHandleCredit = 1;
	uint256 observerHandleCredit = 1;
	bool openTrade = false;
	uint256 tradeCredit = 1;
	uint256 subTCredit = 10;

    mapping(address => uint256) witnessFlag;
    mapping(address => uint256) congressFlag;

    function setWitnessFlag(address _addr, uint256 _flag) external onlyOwner {
        witnessFlag[_addr] = _flag;
        if (_flag == 1) {
            uint256 _amt = availableTotal[_addr][P_COIN];
            require(_amt >= witnessNeedCount, "coin not enough");
            _userStorage.updateUserRole(_addr, 1);
        } else {
            _userStorage.updateUserRole(_addr, 0);
        }
    }

    function getWitnessFlag(address _addr) public view returns (uint256) {
        return witnessFlag[_addr];
    }

    function setCongressFlag(address _addr, uint256 _flag) external onlyOwner {
        congressFlag[_addr] = _flag;
        if (_flag == 1) {
            uint256 _amt = availableTotal[_addr][P_COIN];
            require(_amt >= congressNeedCount, "coin not enough");
            _userStorage.updateUserRole(_addr, 2);
        } else {
            _userStorage.updateUserRole(_addr, 0);
        }
    }

    function getCongressFlag(address _addr) public view returns (uint256) {
        return congressFlag[_addr];
    }

    function setCoinTypeMapping(
        string calldata _coinType,
        address _coinTypeAddr
    ) external onlyOwner {
        coinTypeMaping[_coinType] = _coinTypeAddr;
    }

    function getCoinTypeMapping(string calldata _coinType)
        public
        view
        returns (address)
    {
        return coinTypeMaping[_coinType];
    }

    function setMerchantNeedCount(uint256 _count) external onlyOwner {
        merchantNeedCount = _count;
    }

    function getMerchantNeedCount() public view returns (uint256) {
        return merchantNeedCount;
    }

    function setWitnessNeedCount(uint256 _count) external onlyOwner {
        witnessNeedCount = _count;
    }

    function getWitnessNeedCount() public view returns (uint256) {
        return witnessNeedCount;
    }

    function setCongressNeedCount(uint256 _count) external onlyOwner {
        congressNeedCount = _count;
    }

    function getCongressNeedCount() public view returns (uint256) {
        return congressNeedCount;
    }

    function setAppealFee(uint256 _count) external onlyOwner {
        appealFee = _count;
    }

    function getAppealFee() public view returns (uint256) {
        return appealFee;
    }

    function setAppealFeeFinal(uint256 _count) external onlyOwner {
        appealFeeFinal = _count;
    }

    function getAppealFeeFinal() public view returns (uint256) {
        return appealFeeFinal;
    }

    function setCanWithdrawToTime(uint256 _days) external onlyOwner {
        canWithdrawToTime = _days;
    }

    function getCanWithdrawToTime() public view returns (uint256) {
        return canWithdrawToTime;
    }

    function setSubWitFee(uint256 _c) external onlyOwner {
        subWitFee = _c;
    }

    function getSubWitFee() public view returns (uint256) {
        return subWitFee;
    }

    function setSubWitCredit(uint256 _c) external onlyOwner {
        subWitCredit = _c;
    }

    function getSubWitCredit() public view returns (uint256) {
        return subWitCredit;
    }

    function setWitnessHandleReward(uint256 _c) external onlyOwner {
        witnessHandleReward = _c;
    }

    function getWitnessHandleReward() public view returns (uint256) {
        return witnessHandleReward;
    }

    function setObserverHandleReward(uint256 _c) external onlyOwner {
        observerHandleReward = _c;
    }

    function getObserverHandleReward() public view returns (uint256) {
        return observerHandleReward;
    }

    function setWitnessHandleCredit(uint256 _c) external onlyOwner {
        witnessHandleCredit = _c;
    }

    function getWitnessHandleCredit() public view returns (uint256) {
        return witnessHandleCredit;
    }

    function setObserverHandleCredit(uint256 _c) external onlyOwner {
        observerHandleCredit = _c;
    }

    function getObserverHandleCredit() public view returns (uint256) {
        return observerHandleCredit;
    }

    function setOpenTrade(bool _c) external onlyOwner {
        openTrade = _c;
    }

    function getOpenTrade() public view returns (bool) {
        return openTrade;
    }

    function setTradeCredit(uint256 _c) external onlyOwner {
        tradeCredit = _c;
    }

    function getTradeCredit() public view returns (uint256) {
        return tradeCredit;
    }

    function setSubTCredit(uint256 _c) external onlyOwner {
        subTCredit = _c;
    }

    function getSubTCredit() public view returns (uint256) {
        return subTCredit;
    }

    function punishPerson(
        address _from,
        address _to,
        uint256 _count
    ) external onlyOwner {
        require(_from != address(0) && _to != address(0));
        UserStorage.User memory _user = _userStorage.searchUser(_from);
        require(_user.userFlag == 1 || _user.userFlag == 2, "can't punish");

        uint256 _ava = availableTotal[_from][P_COIN];
        uint256 _toavailab = availableTotal[_to][P_COIN];
        if (_ava >= _count) {
            availableTotal[_from][P_COIN] = SafeMath.sub(_ava, _count);
            availableTotal[_to][P_COIN] = SafeMath.add(_toavailab, _count);
        } else {
            availableTotal[_from][P_COIN] = 0;

            uint256 _draing = withdrawingTotal[_from][P_COIN];
            if (SafeMath.add(_ava, _draing) >= _count) {
                withdrawingTotal[_from][P_COIN] = SafeMath.sub(
                    _draing,
                    SafeMath.sub(_count, _ava)
                );
                availableTotal[_to][P_COIN] = SafeMath.add(_toavailab, _count);
            } else {
                withdrawingTotal[_from][P_COIN] = 0;
                availableTotal[_to][P_COIN] = SafeMath.add(
                    _toavailab,
                    SafeMath.add(_ava, _draing)
                );
            }
        }
        chanRole(_from);
        chanRole(_to);
    }

    UserInterface private _userStorage;
    OrderInterface private _orderStorage;
    struct Record {
        uint256 recordNo;
        address userAddr;
        string tradeHash;
        string coinType;
        uint256 hostCount;
        uint256 hostStatus;
        uint256 hostType;
        uint256 hostDirection;
        uint256 hostTime;
        uint256 updateTime;
    }

    CountersRecord.Counter private _recordNoCounter;
    mapping(uint256 => Record) public records;
    mapping(uint256 => uint256) public recordIndex;

    Record[] public recordList;

    mapping(address => mapping(string => uint256)) public availableTotal;

    mapping(address => mapping(string => uint256)) public frozenTotal;

    mapping(address => mapping(string => uint256)) public unfrozenTotal;

    mapping(address => uint256) lastWithdrawTime;

    mapping(address => mapping(uint256 => uint256)) lastWithdrawAmount;

    mapping(address => mapping(string => uint256)) public withdrawingTotal;

    mapping(address => mapping(uint256 => uint256)) orderSubFrozenList;

    constructor(
        address _usdtAddress,
        address _usdcAddress,
        address _coinAddress
    ) {
        coinTypeMaping["USDT"] = _usdtAddress;
        coinTypeMaping["USDC"] = _usdcAddress;
        coinTypeMaping[P_COIN] = _coinAddress;
        _recordNoCounter.increment();
    }

    function getERC20Address(string memory _coinType)
        public
        view
        returns (TokenTransfer)
    {
        address _remoteAddr = coinTypeMaping[_coinType];
        require(_remoteAddr != address(0));

        TokenTransfer _tokenTransfer = TokenTransfer(_remoteAddr);
        return _tokenTransfer;
    }

    event RecordAdd(
        uint256 _recordNo,
        address _addr,
        string _tradeHash,
        string _coinType,
        uint256 _hostCount,
        uint256 _hostStatus,
        uint256 _hostType,
        uint256 _hostDirection
    );
    event RecordApplyUnfrozen(address _addr, uint256 _amt);
    event UnfrozenTotalTransfer(
        address _addr,
        string _coinType,
        uint256 _lastAmount
    );
    event RecordUpdate(
        address _addr,
        uint256 _recordNo,
        string _hash,
        uint256 _hostStatus
    );

    address _userAddr;
    address _restCAddr;
    address _orderCAddr;
    address _appealCAddr;

    modifier onlyAuthFromAddr() {
        require(_userAddr != address(0), "Invalid address call user");
        require(_restCAddr != address(0), "Invalid address call rest");
        require(_orderCAddr != address(0), "Invalid address call order");
        require(_appealCAddr != address(0), "Invalid address call appeal");
        _;
    }

    function authFromContract(
        address _fromUser,
        address _fromRest,
        address _fromOrder,
        address _fromAppeal
    ) external onlyOwner {
        _userAddr = _fromUser;
        _restCAddr = _fromRest;
        _orderCAddr = _fromOrder;
        _appealCAddr = _fromAppeal;
        _userStorage = UserInterface(_userAddr);
        _orderStorage = OrderInterface(_orderCAddr);
    }

    function _insert(
        address _addr,
        string memory _tradeHash,
        string memory _coinType,
        uint256 _hostCount,
        uint256 _hostStatus,
        uint256 _hostType,
        uint256 _hostDirection
    ) internal nonReentrant returns (uint256 recordNo) {
        require(_addr != address(0), "address null");
        require(bytes(_coinType).length != 0, "coinType null");
        require(_hostCount != uint256(0), "hostCount null");
        require(_hostType != uint256(0), "hostType null");
        require(_hostDirection != uint256(0), "hostDirection null");

        uint256 _recordNo = _recordNoCounter.current();
        require(records[_recordNo].recordNo == uint256(0), "order exist");

        Record memory _record = Record({
            recordNo: _recordNo,
            userAddr: _addr,
            tradeHash: _tradeHash,
            coinType: _coinType,
            hostCount: _hostCount,
            hostStatus: _hostStatus,
            hostType: _hostType,
            hostDirection: _hostDirection,
            hostTime: block.timestamp,
            updateTime: 0
        });

        records[_recordNo] = _record;

        recordList.push(_record);
        recordIndex[_recordNo] = recordList.length - 1;

        _recordNoCounter.increment();
        emit RecordAdd(
            _recordNo,
            _addr,
            _tradeHash,
            _coinType,
            _hostCount,
            _hostStatus,
            _hostType,
            _hostDirection
        );
        return _recordNo;
    }

    function tokenEscrow(string memory _coinType, uint256 _amt) external {
        require(_amt > 0, "invalid");
        require(
            availableTotal[msg.sender][_coinType] + _amt >
                availableTotal[msg.sender][_coinType],
            "Invalid transfer amount"
        );

        availableTotal[msg.sender][_coinType] = SafeMath.add(
            availableTotal[msg.sender][_coinType],
            _amt
        );

        uint256 _hostType = 1;
        if (
            keccak256(abi.encodePacked(_coinType)) ==
            keccak256(abi.encodePacked(P_COIN))
        ) {
            _hostType = 2;
            UserStorage.User memory _user = _userStorage.searchUser(msg.sender);

            _changeUserMorgageStats(
                msg.sender,
                availableTotal[msg.sender][_coinType]
            );

            if (
                _user.userFlag == 0 &&
                availableTotal[msg.sender][_coinType] >= merchantNeedCount
            ) {
                _userStorage.updateUserRole(msg.sender, 3);
            }
        }
        _insert(msg.sender, "", _coinType, _amt, 2, _hostType, 1);

        TokenTransfer _tokenTransfer = getERC20Address(_coinType);
        _tokenTransfer.transferFrom(msg.sender, address(this), _amt);
    }

    function addRecord(
        address _addr,
        string memory _tradeHash,
        string memory _coinType,
        uint256 _hostCount,
        uint256 _hostStatus,
        uint256 _hostType,
        uint256 _hostDirection
    ) public onlyAuthFromAddr {
        require(
            msg.sender == _restCAddr || msg.sender == _orderCAddr,
            "RedocrdStorage:Invalid from contract address"
        );

        frozenTotal[_addr][_coinType] = SafeMath.add(
            frozenTotal[_addr][_coinType],
            _hostCount
        );
        _insert(
            _addr,
            _tradeHash,
            _coinType,
            _hostCount,
            _hostStatus,
            _hostType,
            _hostDirection
        );
    }

    function addAvailableTotal(
        address _addr,
        string memory _coinType,
        uint256 _amt
    ) public onlyAuthFromAddr {
        require(
            msg.sender == _restCAddr || msg.sender == _orderCAddr,
            "Invalid address"
        );
        require(_amt > 0, "invalid");
        uint256 _aBalance = getErcBalance(_coinType, address(this));
        require(_aBalance >= _amt, "not enough");
        require(frozenTotal[_addr][_coinType] >= _amt, "insufficient");
        require(
            SafeMath.sub(frozenTotal[_addr][_coinType], _amt) <=
                frozenTotal[_addr][_coinType],
            "Invalid amount"
        );
        frozenTotal[_addr][_coinType] = SafeMath.sub(
            frozenTotal[_addr][_coinType],
            _amt
        );

        TokenTransfer _tokenTransfer = getERC20Address(_coinType);
        _tokenTransfer.transfer(_addr, _amt);
    }

    function getAvailableTotal(address _addr, string memory _coinType)
        public
        view
        returns (uint256)
    {
        return availableTotal[_addr][_coinType];
    }

    function subFrozenTotal(uint256 _orderNo, address _addr)
        public
        onlyAuthFromAddr
    {
        require(
            msg.sender == _orderCAddr || msg.sender == _appealCAddr,
            "Invalid call"
        );
        OrderStorage.Order memory _order = _orderStorage.searchOrder(_orderNo);
        require(_order.orderNo != uint256(0), "not exist");
        address _seller = _order.orderDetail.sellerAddr;
        string memory _coinType = _order.orderDetail.coinType;

        uint256 _subAmount = orderSubFrozenList[_seller][_orderNo];
        require(_subAmount == 0);

        uint256 _frozen = frozenTotal[_seller][_coinType];
        uint256 _orderCount = _order.coinCount;
        require(_frozen >= _orderCount);
        require(SafeMath.sub(_frozen, _orderCount) <= _frozen);

        frozenTotal[_seller][_coinType] = SafeMath.sub(_frozen, _orderCount);
        orderSubFrozenList[_seller][_orderNo] = _orderCount;

        TokenTransfer _tokenTransfer = getERC20Address(_coinType);
        _tokenTransfer.transfer(_addr, _orderCount);
    }

    function subAvaAppeal(
        address _from,
        address _to,
        AppealStorage.Appeal memory _al,
        uint256 _amt,
        uint256 _t,
        uint256 _self
    ) public onlyAuthFromAddr {
        require(msg.sender == _appealCAddr, "Invalid call");

        uint256 _available = getAvailableTotal(_from, P_COIN);
        uint256 _need = 0;
        address _opt = _t == 1 ? _al.witness : _al.detail.observerAddr;
        if (_available >= _amt) {
            _need = _amt;
        } else {
            _need = _available;
        }

        if (
            (_t == 1 && _self == 0) ||
            (_t == 2 && _al.detail.finalAppealAddr != _from)
        ) {
            availableTotal[_from][P_COIN] = SafeMath.sub(
                availableTotal[_from][P_COIN],
                _need
            );
            availableTotal[_to][P_COIN] = SafeMath.add(
                availableTotal[_to][P_COIN],
                _need
            );
            _changeUserMorgageStats(_from, availableTotal[_from][P_COIN]);
            _changeUserMorgageStats(_to, availableTotal[_to][P_COIN]);
        }

        availableTotal[_opt][P_COIN] = SafeMath.add(
            availableTotal[_opt][P_COIN],
            _amt
        );
        _changeUserMorgageStats(_opt, availableTotal[_opt][P_COIN]);
        chanRole(_from);
        chanRole(_to);
        chanRole(_opt);

        UserStorage.User memory _user = _userStorage.searchUser(_opt);
        if (_t == 1) {
            _user.credit = _user.credit + witnessHandleCredit;
        } else if (_t == 2) {
            _user.credit = _user.credit + observerHandleCredit;
        }
        UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
        _userStorage.updateTradeStats(_opt, _tradeStats, _user.credit);
    }

    function _changeUserMorgageStats(address _addr, uint256 _amt) internal {
        UserStorage.User memory _user = _userStorage.searchUser(_addr);
        UserStorage.MorgageStats memory _morgageStats = _user.morgageStats;
        _morgageStats.mortgage = _amt;
        _userStorage.updateMorgageStats(_addr, _morgageStats);
    }

    function subWitnessAvailable(address _addr) public onlyAuthFromAddr {
        require(msg.sender == _appealCAddr, "Invalid call");
        require(_addr != address(0), "address null");
        uint256 _availableTotal = availableTotal[_addr][P_COIN];
        uint256 _need = 0;
        uint256 subFromDraing = 0;
        if (_availableTotal >= subWitFee) {
            _need = subWitFee;
            availableTotal[_addr][P_COIN] = SafeMath.sub(
                _availableTotal,
                _need
            );
        } else {
            availableTotal[_addr][P_COIN] = 0;

            uint256 _draing = withdrawingTotal[_addr][P_COIN];
            if (SafeMath.add(_availableTotal, _draing) >= subWitFee) {
                _need = subWitFee;
                subFromDraing = SafeMath.sub(subWitFee, _availableTotal);
                withdrawingTotal[_addr][P_COIN] = SafeMath.sub(
                    _draing,
                    subFromDraing
                );
            } else {
                _need = SafeMath.add(_draing, _availableTotal);
                withdrawingTotal[_addr][P_COIN] = 0;
            }
        }
        chanRole(_addr);

        UserStorage.User memory _user = _userStorage.searchUser(_addr);
        _user.credit = _user.credit >= subWitCredit
            ? (_user.credit - subWitCredit)
            : 0;
        UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
        _userStorage.updateTradeStats(_addr, _tradeStats, _user.credit);

        TokenTransfer _tokenTransfer = getERC20Address(P_COIN);
        _tokenTransfer.transfer(owner(), _need);
    }

    function getFrozenTotal(address _addr, string memory _coinType)
        public
        view
        returns (uint256)
    {
        return frozenTotal[_addr][_coinType];
    }

    function applyUnfrozen(uint256 _amt) external returns (uint256) {
        require(_amt > 0);
        require(availableTotal[msg.sender][P_COIN] >= _amt, "Invalid amount");
        require(
            SafeMath.sub(availableTotal[msg.sender][P_COIN], _amt) <
                availableTotal[msg.sender][P_COIN],
            "Invalid amount 2"
        );

        lastWithdrawTime[msg.sender] = block.timestamp;
        lastWithdrawAmount[msg.sender][lastWithdrawTime[msg.sender]] = _amt;
        availableTotal[msg.sender][P_COIN] = SafeMath.sub(
            availableTotal[msg.sender][P_COIN],
            _amt
        );
        withdrawingTotal[msg.sender][P_COIN] = SafeMath.add(
            withdrawingTotal[msg.sender][P_COIN],
            _amt
        );

        chanRole(msg.sender);

        _insert(msg.sender, "", P_COIN, _amt, 3, 3, 2);

        emit RecordApplyUnfrozen(msg.sender, _amt);

        return getAvailableTotal(msg.sender, P_COIN);
    }

    function chanRole(address _addr) internal {
        uint256 _avail = availableTotal[_addr][P_COIN];

        UserStorage.User memory _user = _userStorage.searchUser(_addr);

        _changeUserMorgageStats(_addr, _avail);

        if (
            _user.userFlag == 2 &&
            _avail < congressNeedCount &&
            _avail >= merchantNeedCount
        ) {
            _userStorage.updateUserRole(_addr, 3);
        }

        if (
            _user.userFlag == 1 &&
            _avail < witnessNeedCount &&
            _avail >= merchantNeedCount
        ) {
            _userStorage.updateUserRole(_addr, 3);
        }

        if (_user.userFlag == 0 && _avail >= merchantNeedCount) {
            _userStorage.updateUserRole(_addr, 3);
        }

        if (_avail < merchantNeedCount) {
            _userStorage.updateUserRole(_addr, 0);
        }
    }

    function unApplyUnfrozen(address _addr) external onlyOwner {
        uint256 _drawing = withdrawingTotal[_addr][P_COIN];
        require(_drawing > 0, "sufficient");
        withdrawingTotal[_addr][P_COIN] = 0;
        availableTotal[_addr][P_COIN] = SafeMath.add(
            availableTotal[_addr][P_COIN],
            _drawing
        );
        chanRole(_addr);
    }

    function applyWithdraw(uint256 _recordNo) public {
        Record memory _record = records[_recordNo];

        require(_record.recordNo != uint256(0), "record not exist");
        require(_record.userAddr == msg.sender, "record user not exist");

        require(_record.hostStatus == 3, "status error");

        require(
            withdrawingTotal[msg.sender][P_COIN] >= _record.hostCount,
            "sufficient"
        );

        require(
            block.timestamp >= (_record.hostTime + canWithdrawToTime * 1 days),
            "can't withdraw"
        );

        withdrawingTotal[msg.sender][P_COIN] = SafeMath.sub(
            withdrawingTotal[msg.sender][P_COIN],
            _record.hostCount
        );
        unfrozenTotal[msg.sender][P_COIN] = SafeMath.add(
            unfrozenTotal[msg.sender][P_COIN],
            _record.hostCount
        );

        _record.hostStatus = 4;
        _record.updateTime = block.timestamp;
        records[_recordNo] = _record;
        recordList[recordIndex[_recordNo]] = _record;
        emit RecordUpdate(msg.sender, _recordNo, _record.tradeHash, 4);

        TokenTransfer _tokenTransfer = getERC20Address(P_COIN);
        _tokenTransfer.transfer(msg.sender, _record.hostCount);
    }

    function unfrozenTotalSearch(address _addr, string memory _coinType)
        public
        view
        returns (uint256)
    {
        require(_addr != address(0), "user address is null");

        return unfrozenTotal[_addr][_coinType];
    }

    function getUnfrozenTotal(address _addr, string memory _coinType)
        external
        view
        returns (uint256)
    {
        return unfrozenTotal[_addr][_coinType];
    }

    function getWithdrawingTotal(address _addr, string memory _coinType)
        public
        view
        returns (uint256)
    {
        return withdrawingTotal[_addr][_coinType];
    }

    function getErcBalance(string memory _coinType, address _addr)
        public
        view
        returns (uint256)
    {
        TokenTransfer _tokenTransfer = getERC20Address(_coinType);
        return _tokenTransfer.balanceOf(_addr);
    }

    function _updateInfo(
        address _addr,
        uint256 _recordNo,
        string memory _hash,
        uint256 _hostStatus
    ) internal returns (bool) {
        Record storage _record = records[_recordNo];
        require(_record.userAddr == _addr);
        require(_hostStatus == 1 || _hostStatus == 2, "invalid status");

        if (_hostStatus != uint256(0)) {
            _record.hostStatus = _hostStatus;
        }
        if (bytes(_hash).length != 0) {
            _record.tradeHash = _hash;
        }

        _record.updateTime = block.timestamp;

        emit RecordUpdate(_addr, _recordNo, _hash, _hostStatus);
        return true;
    }

    function updateInfo(
        address _addr,
        uint256 _recordNo,
        string memory _hash,
        uint256 _hostStatus
    ) external returns (bool) {
        return _updateInfo(_addr, _recordNo, _hash, _hostStatus);
    }

    function searchRecord(uint256 _recordNo)
        external
        view
        returns (Record memory record)
    {
        return records[_recordNo];
    }

    function searchRecordList() external view returns (Record[] memory) {
        return recordList;
    }
}

              

Contract source code

pragma solidity ^0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}
// File: @openzeppelin/contracts/access/Ownable.sol
// OpenZeppelin Contracts v4.4.0 (access/Ownable.sol)
pragma solidity ^0.8.0;
/**
* @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.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* 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.
*/
abstract 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() {
_transferOwnership(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the 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 virtual onlyOwner {
_transferOwnership(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 virtual onlyOwner {
require(
newOwner != address(0),
"Ownable: new owner is the zero address"
);
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}
contract UserStorage is Ownable {
struct User {
address userAddr;
string avatar;
string email;
uint isOnline;
uint userFlag;
uint256 credit;
uint regTime;
TradeStats tradeStats;
MorgageStats morgageStats;
}
struct TradeStats {
uint256 tradeTotal;
uint256 restTotal;
}
struct MorgageStats {
uint256 mortgage;
uint256 freezeMortgage;
uint256 relieveMortgage;
uint256 inviteUserCount;
uint256 inviteUserReward;
uint applyRelieveTime;
uint handleRelieveTime;
}
mapping (address => User) public users;
mapping (address => uint256) public userIndex;
User[] public userList;
event addUser(address _userAddr);
event updateUser(string _avatar, string _email, uint _isOnline);
address _restCAddr;
address _orderCAddr;
address _recordCAddr;
address _appealCAddr;
modifier onlyAuthFromAddr() {
require(_restCAddr != address(0), 'Invalid address call rest');
require(_orderCAddr != address(0), 'Invalid address call order');
require(_recordCAddr != address(0), 'Invalid address call record');
require(_appealCAddr != address(0), 'Invalid address call appeal');
_;
}
function authFromContract(address _fromRest, address _fromOrder, address _fromRecord, address _fromAppeal) external onlyOwner {
_restCAddr = _fromRest;
_orderCAddr = _fromOrder;
_recordCAddr = _fromRecord;
_appealCAddr = _fromAppeal;
}
modifier onlyMemberOf() {
require(users[msg.sender].userAddr != address(0), 'has no permission');
_;
}
function _insert(address _addr) internal {
require(_addr != address(0), "UserStorage: addr null is not allowed");
require(users[_addr].userAddr == address(0), "UserStorage: current User exist");
TradeStats memory tradeStats = TradeStats({tradeTotal:0, restTotal:0});
MorgageStats memory morgageStats = MorgageStats({mortgage:0, freezeMortgage:0, relieveMortgage: 0, inviteUserCount:0, inviteUserReward:0, applyRelieveTime:0, handleRelieveTime:0});
User memory u = User({userAddr:_addr, avatar: '', email:'',
isOnline:1, userFlag:0, credit:0, regTime:block.timestamp,tradeStats:tradeStats, morgageStats:morgageStats});
users[_addr] = u;
userList.push(u);
userIndex[_addr] = userList.length -1;
emit addUser(_addr);
}
function _updateInfo(address _addr, string memory _avatar, string memory _email, uint _isOnline) internal {
require(_addr != address(0), "UserStorage: _addr null is not allowed");
require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
User memory u = users[_addr];
if(bytes(_avatar).length != 0){
u.avatar = _avatar;
}
if(bytes(_email).length != 0){
u.email = _email;
}
if(_isOnline != uint(0)){
u.isOnline = _isOnline;
}
users[_addr] = u;
userList[userIndex[_addr]] = u;
}
function _updateTradeStats(address _addr, TradeStats memory _tradeStats, uint _credit) internal {
require(_addr != address(0), "UserStorage: _addr null is not allowed");
require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
User memory u = users[_addr];
u.credit = _credit;
u.tradeStats.tradeTotal = _tradeStats.tradeTotal;
u.tradeStats.restTotal = _tradeStats.restTotal;
users[_addr] = u;
userList[userIndex[_addr]] = u;
}
function _updateMorgageStats(address _addr, MorgageStats memory _morgageStats) internal {
require(_addr != address(0), "UserStorage: _addr null is not allowed");
require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
User memory u = users[_addr];
u.morgageStats.mortgage = _morgageStats.mortgage;
u.morgageStats.freezeMortgage = _morgageStats.freezeMortgage;
u.morgageStats.relieveMortgage = _morgageStats.relieveMortgage;
u.morgageStats.inviteUserCount = _morgageStats.inviteUserCount;
u.morgageStats.inviteUserReward = _morgageStats.inviteUserReward;
u.morgageStats.applyRelieveTime = _morgageStats.applyRelieveTime;
u.morgageStats.handleRelieveTime = _morgageStats.handleRelieveTime;
users[_addr] = u;
userList[userIndex[_addr]] = u;
}
function _search(address _addr) internal view returns(User memory user) {
require(_addr != address(0), "UserStorage: _addr null is not allowed");
require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
User memory a = users[_addr];
return a;
}
function register() external {
require(!isMemberOf(), 'has registed');
_insert(msg.sender);
}
function isMemberOf() public view returns (bool) {
return (users[msg.sender].userAddr != address(0));
}
function updateInfo(string memory _avatar, string memory _email, uint _isOnline) onlyMemberOf external {
_updateInfo(msg.sender, _avatar, _email, _isOnline);
emit updateUser(_avatar, _email, _isOnline);
}
function updateTradeStats(address _addr, TradeStats memory _tradeStats, uint _credit) onlyAuthFromAddr public {
require(msg.sender == _restCAddr || msg.sender == _orderCAddr || msg.sender == _appealCAddr || msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
_updateTradeStats(_addr, _tradeStats, _credit);
}
function updateMorgageStats(address _addr, MorgageStats memory _morgageStats) onlyAuthFromAddr public {
require(msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
_updateMorgageStats(_addr, _morgageStats);
}
function updateUserRole(address _addr, uint _userFlag) onlyAuthFromAddr public {
require(msg.sender == _recordCAddr, 'UserStorage:Invalid from contract address');
require(_addr != address(0), "UserStorage: _addr null is not allowed");
require(users[_addr].userAddr != address(0), "UserStorage: current User not exist");
require(_userFlag<=3, 'UserStorage: Invalid userFlag 3');
User memory u = users[_addr];
u.userFlag = _userFlag;
users[_addr] = u;
userList[userIndex[_addr]] = u;
}
function searchUser(address _addr) external view returns(User memory user) {
return _search(_addr);
}
function searchUserList() external view returns(User[] memory) {
return userList;
}
}
abstract contract ReentrancyGuardRest {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
library CountersRest {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
{
if (counter._value == 0) {
counter._value = 10000;
}
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
{
counter._value = value - 1;
}
}
}
contract RestStorage is Ownable,ReentrancyGuardRest {
using CountersRest for CountersRest.Counter;
RecordInterface private _recordStorage;
UserInterface private _userStorage;
address recordAddress;
struct Rest {
address userAddr;
uint restNo;
uint restType;
string coinType;
string currencyType;
uint restCount;
uint price;
uint[] payType;
uint restStatus;
RestDetail restDetail;
}
struct RestDetail {
uint finishCount;
uint remainderCount;
uint limitAmountFrom;
uint limitAmountTo;
uint limitMinCredit;
uint limitMinMortgage;
string restRemark;
uint restTime;
uint updateTime;
uint restFee;
string restHash;
}
CountersRest.Counter private _restNoCounter;
mapping (uint => Rest) private rests;
mapping (uint => uint) private restIndex;
Rest[] private restList;
mapping(address=>mapping(uint=>uint)) restFrozenTotal;
event RestAdd(uint _restNo, uint _restType, string _coinType, string _currencyType, uint _restCount, uint _price, uint[] _payType,RestDetail _restDetail);
event RestUpdate(uint _restNo, string _coinType, string _currencyType, uint _restCount, uint _price,uint[] _payType, RestDetail _restDetail);
address _orderCAddr;
modifier onlyAuthFromAddr() {
require(_orderCAddr == msg.sender, 'Invalid contract address');
_;
}
function authFromContract(address _recordAddr, address _userAddr, address _orderAddr) external onlyOwner {
_orderCAddr = _orderAddr;
_recordStorage = RecordInterface(_recordAddr);
_userStorage = UserInterface(_userAddr);
recordAddress = _recordAddr;
_restNoCounter.increment();
}
modifier onlyRestOwner(uint _restNo) {
require(rests[_restNo].userAddr == msg.sender, "rest address not exist");
_;
}
function _checkParam(uint _restType, string memory _coinType, string memory _currencyType,
uint _restCount, uint _price, uint[] memory _payType) pure internal {
require(_restType != uint(0), "RestStorage: restType null is not allowed");
require(bytes(_coinType).length != 0, "RestStorage: coinType null is not allowed");
require(bytes(_currencyType).length != 0, "RestStorage: currencyType null is not allowed");
require(_restCount != uint(0), "RestStorage: restCount null is not allowed");
require(_price != uint(0), "RestStorage: price null is not allowed");
require(_payType.length != 0, "RestStorage: payType null is not allowed");
}
function _insert(uint _restType, string memory _coinType, string memory _currencyType,
uint _restCount, uint _price, uint[] memory _payType, RestDetail memory _restDetail) internal nonReentrant returns(uint){
_checkParam(_restType, _coinType, _currencyType, _restCount, _price, _payType);
uint _restNo = _restNoCounter.current();
require(rests[_restNo].restNo == uint(0), "rest exist");
_restDetail.finishCount = 0;
_restDetail.remainderCount = _restCount;
_restDetail.restTime = block.timestamp;
_restDetail.updateTime = 0;
if(_restDetail.limitAmountTo > SafeMath.mul(_restCount, _price) || _restDetail.limitAmountTo == 0) {
_restDetail.limitAmountTo = SafeMath.mul(_restCount, _price);
}
Rest memory r = Rest({userAddr: msg.sender, restNo: _restNo, restType:_restType,
coinType:_coinType, currencyType:_currencyType,
restCount:_restCount, price:_price,
payType:_payType, restStatus:1, restDetail: _restDetail});
rests[_restNo] = r;
restList.push(r);
restIndex[_restNo] = restList.length-1;
_restNoCounter.increment();
emit RestAdd(_restNo, _restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
return _restNo;
}
function _updateInfo(uint _restNo, string memory _coinType, string memory _currencyType,
uint _addCount, uint _price, uint[] memory _payType, RestDetail memory _restDetail) internal {
require(_restNo != uint(0), 'Invalid restNo');
Rest memory r = rests[_restNo];
r.restStatus = 1;
if(bytes(_coinType).length != 0){
r.coinType = _coinType;
}
if(bytes(_currencyType).length != 0){
r.currencyType = _currencyType;
}
if(_price != uint(0)){
r.price = _price;
}
if(_addCount != uint(0)){
r.restCount += _addCount;
r.restDetail.remainderCount += _addCount;
r.restDetail.limitAmountTo = SafeMath.mul(r.restDetail.remainderCount, r.price);
}
if(_payType.length != 0){
r.payType = _payType;
}
if(_restDetail.limitAmountFrom != uint(0)){
if(_restDetail.limitAmountFrom > r.restDetail.limitAmountTo) {
_restDetail.limitAmountFrom = r.restDetail.limitAmountTo;
}
r.restDetail.limitAmountFrom = _restDetail.limitAmountFrom;
}
if(_restDetail.limitMinCredit != uint(0)){
r.restDetail.limitMinCredit = _restDetail.limitMinCredit;
}
if(_restDetail.limitMinMortgage != uint(0)){
r.restDetail.limitMinMortgage = _restDetail.limitMinMortgage;
}
if(bytes(_restDetail.restRemark).length != 0){
r.restDetail.restRemark = _restDetail.restRemark;
}
if(_restDetail.restFee != uint(0)){
r.restDetail.restFee = _restDetail.restFee;
}
r.restDetail.updateTime = block.timestamp;
rests[_restNo] = r;
restList[restIndex[_restNo]] = r;
emit RestUpdate(_restNo, _coinType, _currencyType, r.restCount, _price, _payType, _restDetail);
}
function addBuyRest(uint _restType, string memory _coinType, string memory _currencyType,
uint _restCount, uint _price, uint[] memory _payType,RestDetail memory _restDetail) external {
require(_restType == 1, "must buy rest" );
UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
bool _openTrade = _recordStorage.getOpenTrade();
require(_openTrade || _user.userFlag == 3, "invalid user" );
_insert(_restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
}
function _addSell(uint _restType, string memory _coinType, string memory _currencyType,
uint _restCount, uint _restFee, uint _price, uint[] memory _payType,RestDetail memory _restDetail) internal {
require(_restType == 2, "must sell rest" );
require(_restCount > 0, "restCount error");
UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
bool _openTrade = _recordStorage.getOpenTrade();
require(_openTrade || _user.userFlag == 3, "invalid user" );
_recordStorage.addRecord(msg.sender, '', _coinType, _restCount, 2, 1, 2);
uint _needSub = SafeMath.add(_restCount, _restFee);
TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(_coinType);
_tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
uint _newRestNo = _insert(_restType, _coinType, _currencyType, _restCount, _price, _payType, _restDetail);
restFrozenTotal[msg.sender][_newRestNo] = _restCount;
}
function addSellRest(uint _restType, string memory _coinType, string memory _currencyType,
uint _restCount,uint _restFee, uint _price, uint[] memory _payType,RestDetail memory _restDetail) external {
_addSell(_restType, _coinType, _currencyType, _restCount,_restFee,_price, _payType, _restDetail);
}
function getRestFrozenTotal(address _addr, uint _restNo) public view returns(uint) {
return restFrozenTotal[_addr][_restNo];
}
function cancelBuyRest(uint _restNo) external onlyRestOwner(_restNo) {
require(rests[_restNo].restStatus == 1, "can't change this rest");
require(rests[_restNo].restType == 1, "Invalid rest type");
require(rests[_restNo].restDetail.finishCount < rests[_restNo].restCount, "this rest has finished");
Rest memory r = rests[_restNo];
r.restStatus = 4;
r.restDetail.updateTime = block.timestamp;
rests[_restNo] = r;
restList[restIndex[_restNo]] = r;
}
function _cancelSell(uint _restNo) onlyRestOwner(_restNo) internal {
require(rests[_restNo].restStatus == 1, "can't cancel this rest");
require(rests[_restNo].restType == 2, "Invalid rest type");
require(rests[_restNo].restDetail.finishCount < rests[_restNo].restCount, "this rest has finished");
require(restFrozenTotal[msg.sender][_restNo] > 0, "rest has finished");
uint _frozenTotal = _recordStorage.getFrozenTotal(msg.sender, rests[_restNo].coinType);
require(_frozenTotal >= restFrozenTotal[msg.sender][_restNo], "can't cancel this rest");
uint remainHoldCoin = restFrozenTotal[msg.sender][_restNo];
Rest memory r = rests[_restNo];
r.restStatus = 4;
if (remainHoldCoin < rests[_restNo].restCount) {
r.restStatus = 5;
}
r.restDetail.remainderCount = 0;
r.restDetail.updateTime = block.timestamp;
rests[_restNo] = r;
restList[restIndex[_restNo]] = r;
restFrozenTotal[msg.sender][_restNo] = 0;
_recordStorage.addAvailableTotal(msg.sender, rests[_restNo].coinType, remainHoldCoin);
}
function cancelSellRest(uint _restNo) external{
_cancelSell(_restNo);
}
function startOrStop(uint _restNo, uint _restStatus) external onlyRestOwner(_restNo){
require(_restStatus == 1 || _restStatus == 3, "Invalid rest status");
Rest memory r = rests[_restNo];
require(r.restStatus == 1 || r.restStatus == 3, "Invalid rest status,opt error");
r.restStatus = _restStatus;
r.restDetail.updateTime = block.timestamp;
rests[_restNo] = r;
restList[restIndex[_restNo]] = r;
}
function updateInfo(uint _restNo, string memory _coinType, string memory _currencyType,
uint _addCount, uint _restFee, uint _price,uint[] memory _payType, RestDetail memory _restDetail) external onlyRestOwner(_restNo){
require(_restNo != uint(0), 'Invalid restNo');
Rest memory _rest = rests[_restNo];
require(_rest.restNo != uint(0), 'rest not exist');
if (_rest.restType == 2) {
_recordStorage.addRecord(msg.sender, '', _coinType, _addCount, 2, 1, 2);
uint _needSub = SafeMath.add(_addCount, _restFee);
TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(_coinType);
_tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
restFrozenTotal[msg.sender][_restNo] += _addCount;
}
_updateInfo(_restNo, _coinType, _currencyType, _addCount, _price, _payType, _restDetail);
}
function updateRestFinishCount(uint _restNo, uint _finishCount) onlyAuthFromAddr external {
Rest memory _rest = rests[_restNo];
require(_rest.restDetail.remainderCount >= _finishCount, "RestStorage:finish count error");
if (_rest.restType == 2) {
restFrozenTotal[_rest.userAddr][_restNo] = SafeMath.sub(restFrozenTotal[_rest.userAddr][_restNo], _finishCount);
}
_rest.restDetail.finishCount = SafeMath.add(_rest.restDetail.finishCount, _finishCount);
_rest.restDetail.remainderCount = SafeMath.sub(_rest.restDetail.remainderCount, _finishCount);
_rest.restDetail.limitAmountTo = SafeMath.mul(_rest.price, _rest.restDetail.remainderCount);
if (_rest.restDetail.remainderCount == 0) {
_rest.restStatus = 2;
}
_rest.restDetail.updateTime = block.timestamp;
rests[_restNo] = _rest;
restList[restIndex[_restNo]] = _rest;
}
function addRestRemainCount(uint _restNo, uint _remainCount) onlyAuthFromAddr public {
Rest memory _rest = rests[_restNo];
require(_remainCount > 0 && _rest.restDetail.finishCount >= _remainCount, "count error");
if (_rest.restType == 2) {
restFrozenTotal[_rest.userAddr][_restNo] = SafeMath.add(restFrozenTotal[_rest.userAddr][_restNo], _remainCount);
}
_rest.restDetail.finishCount = SafeMath.sub(_rest.restDetail.finishCount, _remainCount);
_rest.restDetail.remainderCount = SafeMath.add(_rest.restDetail.remainderCount, _remainCount);
_rest.restDetail.limitAmountTo = SafeMath.mul(_rest.price, _rest.restDetail.remainderCount);
_rest.restDetail.limitAmountFrom = _rest.restDetail.limitAmountFrom > _rest.restDetail.limitAmountTo ? _rest.restDetail.limitAmountTo : _rest.restDetail.limitAmountFrom;
_rest.restStatus = 1;
_rest.restDetail.updateTime = block.timestamp;
rests[_restNo] = _rest;
restList[restIndex[_restNo]] = _rest;
}
function searchRest(uint _restNo) external view returns(Rest memory rest) {
require(_restNo != uint(0), "restNo null is not allowed");
Rest memory r = rests[_restNo];
return r;
}
function searchRestList() external view returns(Rest[] memory) {
return restList;
}
}
abstract contract ReentrancyGuardOrder {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
library CountersOrder {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
{
if (counter._value == 0) {
counter._value = 10000;
}
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
{
counter._value = value - 1;
}
}
}
contract OrderStorage is Ownable, ReentrancyGuardOrder {
using CountersOrder for CountersOrder.Counter;
RestStorage private _restStorage;
RecordInterface private _recordStorage;
UserInterface private _userStorage;
AppealInterface private _appealS;
address recordAddress;
struct Order {
address userAddr;
uint256 orderNo;
uint256 restNo;
uint256 coinCount;
uint256 orderAmount;
uint256 payType;
string currencyType;
uint256 orderType;
uint256 orderStatus;
OrderDetail orderDetail;
}
struct OrderDetail {
address buyerAddr;
address sellerAddr;
string coinType;
uint256 price;
uint256 tradeTime;
uint256 updateTime;
string tradeHash;
uint256 tradeFee;
}
CountersOrder.Counter private _orderNoCounter;
mapping(uint256 => Order) private orders;
mapping(uint256 => uint256) private orderIndex;
Order[] private orderList;
mapping(address => mapping(uint256 => uint256)) orderFrozenTotal;
uint256 cancelOrderTime = 30;
function setCancelOrderTime(uint256 _count) public onlyOwner {
cancelOrderTime = _count;
}
function getCancelOrderTime() public view returns (uint256) {
return cancelOrderTime;
}
uint256 canWithdrawHours = 24;
function setCanWithdrawHours(uint256 _count) public onlyOwner {
canWithdrawHours = _count;
}
function getCanWithdrawHours() public view returns (uint256) {
return canWithdrawHours;
}
event OrderAdd(
uint256 _orderNo,
uint256 _restNo,
uint256 _coinCount,
uint256 _tradeFee,
uint256 _orderAmount,
uint256 _payType,
uint256 _orderType,
address _buyerAddr,
address _sellerAddr
);
event OrderPaidMoney(uint256 _orderNo);
event OrderConfirmCollect(uint256 _orderNo);
event OrderCancel(uint256 _orderNo);
event OrderUpdateStatus(uint256 _orderNo, uint256 _orderStatus);
function authFromContract(
address _recordAddr,
address _restAddr,
address _userAddr,
address _appealAddr
) external onlyOwner {
_recordStorage = RecordInterface(_recordAddr);
_restStorage = RestStorage(_restAddr);
_userStorage = UserInterface(_userAddr);
recordAddress = _recordAddr;
_appealS = AppealInterface(_appealAddr);
_orderNoCounter.increment();
}
modifier onlyBuyer(uint256 _orderNo) {
require(_orderNo != uint256(0), "orderNo null");
require(
orders[_orderNo].orderDetail.buyerAddr == msg.sender,
"only buyer"
);
_;
}
modifier onlySeller(uint256 _orderNo) {
require(_orderNo != uint256(0), "orderNo null");
require(
orders[_orderNo].orderDetail.sellerAddr == msg.sender,
"only seller"
);
_;
}
modifier onlyBuyerOrSeller(uint256 _orderNo) {
require(_orderNo != uint256(0), "orderNo null");
require(
orders[_orderNo].orderDetail.sellerAddr == msg.sender ||
orders[_orderNo].orderDetail.buyerAddr == msg.sender,
"Only buyer or seller"
);
_;
}
function _checkParam(
uint256 _restNo,
uint256 _coinCount,
uint256 _orderAmount,
uint256 _payType
) internal pure {
require(_restNo != uint256(0), "restNo null");
require(_coinCount > 0, "coinCount null");
require(_orderAmount > 0, "orderAmount null");
require(_payType != uint256(0), "payType null");
}
function _insert(
uint256 _restNo,
uint256 _coinCount,
uint256 _tradeFee,
uint256 _orderAmount,
uint256 _payType,
uint256 _orderType,
address _buyerAddr,
address _sellerAddr
) internal nonReentrant returns (uint256 restNo) {
_checkParam(_restNo, _coinCount, _orderAmount, _payType);
RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
require(_rest.userAddr != address(0), "rest not exist");
OrderDetail memory _orderDetail = OrderDetail({
buyerAddr: _buyerAddr,
sellerAddr: _sellerAddr,
coinType: _rest.coinType,
price: _rest.price,
tradeTime: block.timestamp,
updateTime: 0,
tradeHash: "",
tradeFee: _tradeFee
});
uint256 _orderNo = _orderNoCounter.current();
require(orders[_orderNo].orderNo == uint256(0), "order exist");
Order memory order = Order({
userAddr: msg.sender,
orderNo: _orderNo,
restNo: _restNo,
coinCount: _coinCount,
orderAmount: _orderAmount,
payType: _payType,
currencyType: _rest.currencyType,
orderType: _orderType,
orderStatus: 1,
orderDetail: _orderDetail
});
orders[_orderNo] = order;
orderList.push(order);
orderIndex[_orderNo] = orderList.length - 1;
if (_orderType == 2) {
orderFrozenTotal[msg.sender][_orderNo] = _coinCount;
} else if (_orderType == 1) {
orderFrozenTotal[_rest.userAddr][_orderNo] = _coinCount;
}
_orderNoCounter.increment();
emit OrderAdd(
_orderNo,
_restNo,
_coinCount,
_tradeFee,
_orderAmount,
_payType,
_orderType,
_buyerAddr,
_sellerAddr
);
return _orderNo;
}
function addBuyOrder(
uint256 _restNo,
uint256 _coinCount,
uint256 _orderAmount,
uint256 _payType
) external {
RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
require(_rest.userAddr != msg.sender, "rest not exist");
require(_rest.restType == 2, "sell rest not exist");
require(_coinCount > 0 && _orderAmount > 0, "coin count error");
require(_rest.restStatus == 1, "rest status error");
UserStorage.User memory _currentUser = _userStorage.searchUser(
msg.sender
);
require(
_currentUser.userFlag != 1 && _currentUser.userFlag != 2,
"invalid user"
);
uint256 _restFrozen = _restStorage.getRestFrozenTotal(
_rest.userAddr,
_restNo
);
require(_restFrozen >= _coinCount, "coin not enough");
uint256 _amo = SafeMath.mul(_rest.price, _coinCount);
require(
_amo >= _rest.restDetail.limitAmountFrom &&
_amo <= _rest.restDetail.limitAmountTo,
"amount error"
);
require(
_currentUser.credit >= _rest.restDetail.limitMinCredit,
"credit error"
);
require(
_currentUser.morgageStats.mortgage >=
_rest.restDetail.limitMinMortgage,
"mortgage error"
);
_restStorage.updateRestFinishCount(_restNo, _coinCount);
_insert(
_restNo,
_coinCount,
0,
_orderAmount,
_payType,
1,
msg.sender,
_rest.userAddr
);
}
function addSellOrder(
uint256 _restNo,
uint256 _coinCount,
uint256 _tradeFee,
uint256 _orderAmount,
uint256 _payType
) external {
RestStorage.Rest memory _rest = _restStorage.searchRest(_restNo);
require(_rest.userAddr != msg.sender, "rest not exist");
require(_rest.restType == 1, "buy rest not exist");
require(_coinCount > 0, "coin count error");
require(_orderAmount > 0, "orderAmount error");
require(_rest.restStatus == 1, "rest status error");
uint256 _amo = SafeMath.mul(_rest.price, _coinCount);
require(
_amo >= _rest.restDetail.limitAmountFrom &&
_amo <= _rest.restDetail.limitAmountTo,
"amount error"
);
UserStorage.User memory _currentUser = _userStorage.searchUser(
msg.sender
);
require(
_currentUser.userFlag != 1 && _currentUser.userFlag != 2,
"invalid user"
);
require(
_currentUser.credit >= _rest.restDetail.limitMinCredit,
"credit error"
);
require(
_currentUser.morgageStats.mortgage >=
_rest.restDetail.limitMinMortgage,
"mortgage error"
);
uint256 _needSub = SafeMath.add(_coinCount, _tradeFee);
_restStorage.updateRestFinishCount(_restNo, _coinCount);
_insert(
_restNo,
_coinCount,
_tradeFee,
_orderAmount,
_payType,
2,
_rest.userAddr,
msg.sender
);
TokenTransfer _tokenTransfer = _recordStorage.getERC20Address(
_rest.coinType
);
_tokenTransfer.transferFrom(msg.sender, recordAddress, _needSub);
_recordStorage.addRecord(
msg.sender,
"",
_rest.coinType,
_coinCount,
2,
1,
2
);
}
function setPaidMoney(uint256 _orderNo)
external
onlyBuyer(_orderNo)
returns (bool)
{
_updateOrderStatus(_orderNo, 2);
emit OrderPaidMoney(_orderNo);
return true;
}
function confirmCollect(uint256 _orderNo) external onlySeller(_orderNo) {
require(_orderNo != uint256(0), "orderNo null");
Order memory _order = orders[_orderNo];
require(_order.orderStatus == 2, "Invalid order status");
require(
_order.orderDetail.buyerAddr != address(0),
"Invalid buyer address"
);
require(
orderFrozenTotal[msg.sender][_orderNo] >= _order.coinCount,
"coin not enough"
);
_updateOrderStatus(_orderNo, 3);
orderFrozenTotal[msg.sender][_orderNo] = 0;
uint256 _rc = _recordStorage.getTradeCredit();
UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
uint256 _credit = _user.credit + _rc;
UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
_tradeStats.tradeTotal += 1;
_userStorage.updateTradeStats(msg.sender, _tradeStats, _credit);
UserStorage.User memory _user2 = _userStorage.searchUser(
_order.orderDetail.buyerAddr
);
uint256 _credit2 = _user2.credit + _rc;
UserStorage.TradeStats memory _tradeStats2 = _user2.tradeStats;
_tradeStats2.tradeTotal += 1;
_userStorage.updateTradeStats(
_order.orderDetail.buyerAddr,
_tradeStats2,
_credit2
);
_recordStorage.subFrozenTotal(_orderNo, _order.orderDetail.buyerAddr);
emit OrderConfirmCollect(_orderNo);
}
function cancelOrder(uint256 _orderNo)
external
onlyBuyerOrSeller(_orderNo)
returns (bool)
{
Order memory _order = orders[_orderNo];
require(_order.orderNo != uint256(0), "current Order not exist");
require(_order.orderStatus == 1, "Can't cancel order");
if (_order.orderDetail.sellerAddr == msg.sender) {
require(
_order.orderDetail.tradeTime + cancelOrderTime * 1 minutes <
block.timestamp,
"limit"
);
}
RestStorage.Rest memory _rest = _restStorage.searchRest(_order.restNo);
if (_rest.restStatus == 4 || _rest.restStatus == 5) {
orderFrozenTotal[_order.orderDetail.sellerAddr][_orderNo] = 0;
_recordStorage.addAvailableTotal(
_order.orderDetail.sellerAddr,
_order.orderDetail.coinType,
_order.coinCount
);
} else {
if (_order.orderType == 2) {
orderFrozenTotal[_order.orderDetail.sellerAddr][_orderNo] = 0;
_recordStorage.addAvailableTotal(
_order.orderDetail.sellerAddr,
_order.orderDetail.coinType,
_order.coinCount
);
}
_restStorage.addRestRemainCount(_order.restNo, _order.coinCount);
}
_updateOrderStatus(_orderNo, 4);
emit OrderCancel(_orderNo);
return true;
}
function takeCoin(uint256 _o) external onlyBuyerOrSeller(_o) {
AppealStorage.Appeal memory _appeal = _appealS.searchAppeal(_o);
require(
block.timestamp - _appeal.detail.witnessHandleTime >
canWithdrawHours * 1 hours,
"time error"
);
address _win;
if (_appeal.user == _appeal.buyer) {
if (_appeal.status == 2) {
_win = _appeal.buyer;
} else if (_appeal.status == 3) {
_win = _appeal.seller;
}
} else {
if (_appeal.status == 2) {
_win = _appeal.seller;
} else if (_appeal.status == 3) {
_win = _appeal.buyer;
}
}
require(_win == msg.sender, "opt error");
_updateOrderStatus(_o, 5);
orderFrozenTotal[_appeal.seller][_o] = 0;
_recordStorage.subFrozenTotal(_o, msg.sender);
}
function _updateOrderStatus(uint256 _orderNo, uint256 _orderStatus)
internal
onlyBuyerOrSeller(_orderNo)
{
Order memory order = orders[_orderNo];
require(order.orderNo != uint256(0), "current Order not exist");
require(_orderStatus >= 1 && _orderStatus <= 5, "Invalid order status");
if (_orderStatus == 2 && order.orderStatus != 1) {
revert("Invalid order status 2");
}
if (_orderStatus == 3 && order.orderStatus != 2) {
revert("Invalid order status 3");
}
if (_orderStatus == 4 && order.orderStatus != 1) {
revert("Invalid order status 4");
}
if (
_orderStatus == 5 &&
order.orderStatus != 1 &&
order.orderStatus != 2
) {
revert("Invalid order status 5");
}
if (_orderStatus == 2) {
require(
order.orderDetail.buyerAddr == msg.sender,
"only buyer call"
);
}
if (_orderStatus == 3) {
require(
order.orderDetail.sellerAddr == msg.sender,
"only seller call"
);
}
order.orderStatus = _orderStatus;
order.orderDetail.updateTime = block.timestamp;
orders[_orderNo] = order;
orderList[orderIndex[_orderNo]] = order;
emit OrderUpdateStatus(_orderNo, _orderStatus);
}
function searchOrder(uint256 _orderNo)
external
view
returns (Order memory order)
{
require(_orderNo != uint256(0), "orderNo null");
require(
orders[_orderNo].orderNo != uint256(0),
"current Order not exist"
);
Order memory o = orders[_orderNo];
return o;
}
function searchOrderList() external view returns (Order[] memory) {
return orderList;
}
function searchListByRest(uint256 _restNo)
external
view
returns (Order[] memory)
{
Order[] memory resultList = new Order[](orderList.length);
for (uint256 i = 0; i < orderList.length; i++) {
Order memory _order = orderList[i];
if (_order.restNo == _restNo) {
resultList[i] = _order;
}
}
return resultList;
}
}
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
// 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 (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b)
internal
pure
returns (bool, uint256)
{
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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) {
return a + b;
}
/**
* @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 a - b;
}
/**
* @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) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting 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 a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting 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.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* 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,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}
contract AppealStorage {
OrderInterface private _oSt;
RecordInterface private _rSt;
UserInterface private _uSt;
address recAddr;
struct Appeal {
address user;
uint256 appealNo;
uint256 orderNo;
address witness;
address buyer;
address seller;
uint256 mortgage;
uint256 status;
uint256 appealTime;
uint256 witTakeTime;
uint256 obTakeTime;
AppealDetail detail;
}
struct AppealDetail {
address finalAppealAddr;
uint256 updateTime;
string witnessReason;
uint256 witnessAppealStatus;
string observerReason;
uint256 witnessHandleTime;
uint256 observerHandleTime;
address observerAddr;
uint256 witnessHandleReward;
uint256 observerHandleReward;
uint256 witnessHandleCredit;
uint256 observerHandleCredit;
uint256 witReward;
uint256 witSub;
uint256 witCreditR;
uint256 witCreditS;
}
mapping(uint256 => Appeal) public appeals;
mapping(uint256 => uint256) public appealIndex;
Appeal[] public appealList;
event addAppeal(uint256 _appealNo, uint256 _orderNo);
constructor(
address _r,
address _o,
address _u
) {
_rSt = RecordInterface(_r);
_oSt = OrderInterface(_o);
_uSt = UserInterface(_u);
recAddr = _r;
}
modifier onlyWit(uint256 _o) {
Appeal memory _al = appeals[_o];
require(_al.witness == msg.sender);
require(_al.buyer != msg.sender && _al.seller != msg.sender);
_;
}
modifier onlyOb(uint256 _o) {
Appeal memory _al = appeals[_o];
require(_al.detail.observerAddr == msg.sender);
require(_al.buyer != msg.sender && _al.seller != msg.sender);
_;
}
modifier onlyBOS(uint256 _o) {
OrderStorage.Order memory _r = _oSt.searchOrder(_o);
require(
_r.orderDetail.sellerAddr == msg.sender ||
_r.orderDetail.buyerAddr == msg.sender
);
_;
}
function _insert(uint256 _o, uint256 _count) internal {
OrderStorage.Order memory _or = _oSt.searchOrder(_o);
require(appeals[_o].appealNo == uint256(0));
AppealDetail memory _detail = AppealDetail({
finalAppealAddr: address(0),
updateTime: uint256(0),
witnessReason: "",
observerReason: "",
witnessAppealStatus: 0,
witnessHandleTime: uint256(0),
observerHandleTime: uint256(0),
observerAddr: address(0),
witnessHandleReward: 0,
observerHandleReward: 0,
witnessHandleCredit: 0,
observerHandleCredit: 0,
witReward: 0,
witSub: 0,
witCreditR: 0,
witCreditS: 0
});
uint256 _appealNo = block.timestamp;
Appeal memory _appeal = Appeal({
user: msg.sender,
appealNo: _appealNo,
orderNo: _o,
witness: address(0),
buyer: _or.orderDetail.buyerAddr,
seller: _or.orderDetail.sellerAddr,
mortgage: _count,
status: 1,
appealTime: block.timestamp,
witTakeTime: 0,
obTakeTime: 0,
detail: _detail
});
appeals[_o] = _appeal;
appealList.push(_appeal);
appealIndex[_o] = appealList.length - 1;
chanT(_or.orderDetail.sellerAddr, _or.orderDetail.buyerAddr, 1, 0);
emit addAppeal(_appealNo, _o);
}
function chanT(
address _seller,
address _buyer,
uint256 _t,
uint256 _r
) internal {
uint256 _tc = _rSt.getTradeCredit();
uint256 _rs = _rSt.getSubTCredit();
UserStorage.User memory _user = _uSt.searchUser(_seller);
UserStorage.TradeStats memory _tr = _user.tradeStats;
UserStorage.User memory _user2 = _uSt.searchUser(_buyer);
UserStorage.TradeStats memory _tr2 = _user2.tradeStats;
uint256 _c2 = _user2.credit;
uint256 _c = _user.credit;
if (_t == 1) {
_tr.tradeTotal = _tr.tradeTotal > 0 ? (_tr.tradeTotal - 1) : 0;
_tr2.tradeTotal = _tr2.tradeTotal > 0 ? (_tr2.tradeTotal - 1) : 0;
_c = (_c >= _tc) ? (_c - _tc) : 0;
_c2 = (_c2 >= _tc) ? (_c2 - _tc) : 0;
} else if (_t == 2) {
_tr.tradeTotal += 1;
_tr2.tradeTotal += 1;
if (_r == 1) {
_c += _tc;
_c2 = (_c2 >= _rs) ? (_c2 - _rs) : 0;
} else if (_r == 2) {
_c2 += _tc;
_c = (_c >= _rs) ? (_c - _rs) : 0;
}
}
_uSt.updateTradeStats(_seller, _tr, _c);
_uSt.updateTradeStats(_buyer, _tr2, _c2);
}
function applyAppeal(uint256 _o) external onlyBOS(_o) {
uint256 _fee = _rSt.getAppealFee();
_insert(_o, _fee);
TokenTransfer _tokenTransfer = _rSt.getERC20Address("wROSE");
_tokenTransfer.transferFrom(msg.sender, recAddr, _fee);
}
function takeWit(uint256 _o) external {
Appeal memory _al = appeals[_o];
require(_al.buyer != msg.sender && _al.seller != msg.sender);
require(_al.witness == address(0));
require(_al.status == 1);
bool _f = witOrOb(1);
require(_f);
_al.witness = msg.sender;
_al.witTakeTime = block.timestamp;
appeals[_o] = _al;
appealList[appealIndex[_o]] = _al;
}
function takeOb(uint256 _o) external {
Appeal memory _al = appeals[_o];
require(_al.buyer != msg.sender && _al.seller != msg.sender);
require(_al.status == 4 || _al.status == 5);
require(_al.detail.observerAddr == address(0));
bool _f = witOrOb(2);
require(_f);
_al.detail.observerAddr = msg.sender;
_al.obTakeTime = block.timestamp;
appeals[_o] = _al;
appealList[appealIndex[_o]] = _al;
}
function changeHandler(uint256 _o, uint256 _type) external onlyBOS(_o) {
Appeal memory _al = appeals[_o];
if (_type == 1) {
require(_al.status == 1);
require(_al.witness != address(0));
require(block.timestamp - _al.witTakeTime > 24 hours);
_al.witness = address(0);
_al.witTakeTime = 0;
} else if (_type == 2) {
require(_al.status == 4 || _al.status == 5);
require(_al.detail.observerAddr != address(0));
require(block.timestamp - _al.obTakeTime > 24 hours);
_al.detail.observerAddr = address(0);
_al.obTakeTime = 0;
}
appeals[_o] = _al;
appealList[appealIndex[_o]] = _al;
}
function witOrOb(uint256 _f) internal view returns (bool) {
UserStorage.User memory _u = _uSt.searchUser(msg.sender);
if (_u.userFlag == _f) {
return true;
}
return false;
}
function applyFinal(uint256 _o) external onlyBOS(_o) {
Appeal memory _al = appeals[_o];
require(_al.status == 2 || _al.status == 3);
require(block.timestamp - _al.detail.witnessHandleTime <= 24 hours);
chanT(_al.seller, _al.buyer, 1, 0);
uint256 _fee = _rSt.getAppealFeeFinal();
TokenTransfer _tokenTransfer = _rSt.getERC20Address("wROSE");
_tokenTransfer.transferFrom(msg.sender, recAddr, _fee);
if (_al.status == 2) {
_al.status = 4;
} else if (_al.status == 3) {
_al.status = 5;
}
_al.detail.finalAppealAddr = msg.sender;
_al.detail.updateTime = block.timestamp;
appeals[_o] = _al;
appealList[appealIndex[_o]] = _al;
}
function witnessOpt(
uint256 _o,
string memory _r,
uint256 _s
) external onlyWit(_o) {
require(_s == 2 || _s == 3);
Appeal memory _al = appeals[_o];
require(_al.status == 1);
uint256 _fee = _rSt.getAppealFee();
uint256 _rcedit = _rSt.getWitnessHandleCredit();
_al.status = _s;
_al.detail.witnessAppealStatus = _s;
_al.detail.witnessReason = _r;
_al.detail.witnessHandleTime = block.timestamp;
_al.detail.witnessHandleReward = _fee;
_al.detail.witnessHandleCredit = _rcedit;
_al.detail.witReward = _fee;
_al.detail.witCreditR = _rcedit;
_al.detail.updateTime = block.timestamp;
appeals[_o] = _al;
appealList[appealIndex[_o]] = _al;
if (_s == 2) {
if (_al.user == _al.buyer) {
_rSt.subAvaAppeal(_al.seller, _al.buyer, _al, _fee, 1, 0);
chanT(_al.seller, _al.buyer, 2, 2);
} else if (_al.user == _al.seller) {
_rSt.subAvaAppeal(_al.buyer, _al.seller, _al, _fee, 1, 0);
chanT(_al.seller, _al.buyer, 2, 1);
}
}
if (_s == 3) {
if (_al.user == _al.buyer) {
_rSt.subAvaAppeal(_al.buyer, _al.seller, _al, _fee, 1, 1);
chanT(_al.seller, _al.buyer, 2, 1);
} else if (_al.user == _al.seller) {
_rSt.subAvaAppeal(_al.seller, _al.buyer, _al, _fee, 1, 1);
chanT(_al.seller, _al.buyer, 2, 2);
}
}
}
function observerOpt(
uint256 _o,
string memory _r,
uint256 _s
) external onlyOb(_o) {
require(_s == 6 || _s == 7);
Appeal memory _appeal = appeals[_o];
require(_appeal.status == 4 || _appeal.status == 5);
uint256 _fee = _rSt.getAppealFeeFinal();
uint256 _rcedit = _rSt.getObserverHandleCredit();
_appeal.status = _s;
_appeal.detail.observerReason = _r;
_appeal.detail.observerHandleTime = block.timestamp;
_appeal.detail.observerHandleReward = _fee;
_appeal.detail.observerHandleCredit = _rcedit;
uint256 _subWC = _rSt.getSubWitCredit();
uint256 _subWF = _rSt.getSubWitFee();
if (_s == 6) {
if (_appeal.user == _appeal.buyer) {
_rSt.subAvaAppeal(
_appeal.seller,
_appeal.buyer,
_appeal,
_fee,
2,
0
);
chanT(_appeal.seller, _appeal.buyer, 2, 2);
_rSt.subFrozenTotal(_o, _appeal.buyer);
} else if (_appeal.user == _appeal.seller) {
_rSt.subAvaAppeal(
_appeal.buyer,
_appeal.seller,
_appeal,
_fee,
2,
0
);
chanT(_appeal.seller, _appeal.buyer, 2, 1);
_rSt.subFrozenTotal(_o, _appeal.seller);
}
if (_appeal.detail.witnessAppealStatus == 3) {
_appeal.detail.witSub = _subWF;
_appeal.detail.witCreditS = _subWC;
if (_appeal.detail.witnessHandleCredit >= _subWC) {
_appeal.detail.witnessHandleCredit = SafeMath.sub(
_appeal.detail.witnessHandleCredit,
_subWC
);
} else {
_appeal.detail.witnessHandleCredit = 0;
}
_rSt.subWitnessAvailable(_appeal.witness);
}
}
if (_s == 7) {
if (_appeal.user == _appeal.buyer) {
_rSt.subAvaAppeal(
_appeal.buyer,
_appeal.seller,
_appeal,
_fee,
2,
1
);
chanT(_appeal.seller, _appeal.buyer, 2, 1);
_rSt.subFrozenTotal(_o, _appeal.seller);
} else if (_appeal.user == _appeal.seller) {
_rSt.subAvaAppeal(
_appeal.seller,
_appeal.buyer,
_appeal,
_fee,
2,
1
);
chanT(_appeal.seller, _appeal.buyer, 2, 2);
_rSt.subFrozenTotal(_o, _appeal.buyer);
}
if (_appeal.detail.witnessAppealStatus == 2) {
_appeal.detail.witSub = _subWF;
_appeal.detail.witCreditS = _subWC;
if (_appeal.detail.witnessHandleCredit >= _subWC) {
_appeal.detail.witnessHandleCredit = SafeMath.sub(
_appeal.detail.witnessHandleCredit,
_subWC
);
} else {
_appeal.detail.witnessHandleCredit = 0;
}
_rSt.subWitnessAvailable(_appeal.witness);
}
}
_appeal.detail.updateTime = block.timestamp;
appeals[_o] = _appeal;
appealList[appealIndex[_o]] = _appeal;
}
function searchAppeal(uint256 _o)
external
view
returns (Appeal memory appeal)
{
return appeals[_o];
}
function searchAppealList() external view returns (Appeal[] memory) {
return appealList;
}
}
interface RecordInterface {
function getErcBalance(string memory _coinType, address _addr)
external
returns (uint256);
function getAvailableTotal(address _addr, string memory _coinType)
external
returns (uint256);
function getFrozenTotal(address _addr, string memory _coinType)
external
returns (uint256);
function addAvailableTotal(
address _addr,
string memory _coinType,
uint256 remainHoldCoin
) external;
function subAvaAppeal(
address _from,
address _to,
AppealStorage.Appeal memory _al,
uint256 _amt,
uint256 _type,
uint256 _self
) external;
function subWitnessAvailable(address _addr) external;
function getERC20Address(string memory _coinType)
external
returns (TokenTransfer);
function subFrozenTotal(uint256 _orderNo, address _addr) external;
function addRecord(
address _addr,
string memory _tradeHash,
string memory _coinType,
uint256 _hostCount,
uint256 _hostStatus,
uint256 _hostType,
uint256 _hostDirection
) external;
function getAppealFee() external view returns (uint256);
function getAppealFeeFinal() external view returns (uint256);
function getWitnessHandleReward() external view returns (uint256);
function getObserverHandleReward() external view returns (uint256);
function getWitnessHandleCredit() external view returns (uint256);
function getObserverHandleCredit() external view returns (uint256);
function getSubWitCredit() external view returns (uint256);
function getOpenTrade() external view returns (bool);
function getTradeCredit() external view returns (uint256);
function getSubTCredit() external view returns (uint256);
function getSubWitFee() external view returns (uint256);
}
interface RestInterface {
function searchRest(uint256 _restNo)
external
returns (RestStorage.Rest memory rest);
function getRestFrozenTotal(address _addr, uint256 _restNo)
external
returns (uint256);
function updateRestFinishCount(uint256 _restNo, uint256 _coinCount)
external
returns (uint256);
function addRestRemainCount(uint256 _restNo, uint256 _remainCount)
external
returns (uint256);
}
interface OrderInterface {
function searchOrder(uint256 _orderNo)
external
returns (OrderStorage.Order memory order);
}
interface UserInterface {
function searchUser(address _addr)
external
view
returns (UserStorage.User memory user);
function searchWitnessList(uint256 _userFlag)
external
returns (UserStorage.User[] memory userList);
function updateTradeStats(
address _addr,
UserStorage.TradeStats memory _tradeStats,
uint256 _credit
) external;
function updateMorgageStats(
address _addr,
UserStorage.MorgageStats memory _morgageStats
) external;
function updateUserRole(address _addr, uint256 _userFlag) external;
}
interface AppealInterface {
function searchAppeal(uint256 _o)
external
view
returns (AppealStorage.Appeal memory appeal);
}
abstract contract ReentrancyGuardRecord {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
_;
_status = _NOT_ENTERED;
}
}
library CountersRecord {
struct Counter {
uint256 _value;
}
function current(Counter storage counter) internal view returns (uint256) {
return counter._value;
}
function increment(Counter storage counter) internal {
{
if (counter._value == 0) {
counter._value = 10000;
}
counter._value += 1;
}
}
function decrement(Counter storage counter) internal {
uint256 value = counter._value;
require(value > 0, "Counter: decrement overflow");
{
counter._value = value - 1;
}
}
}
interface TokenTransfer {
function transfer(address recipient, uint256 amount) external;
function balanceOf(address account) external view returns (uint256);
function transferFrom(
address sender,
address recipient,
uint256 amount
) external;
function allowance(address _owner, address _spender)
external
view
returns (uint256 remaining);
}
contract RecordStorage is Ownable, ReentrancyGuardRecord {
using CountersRecord for CountersRecord.Counter;
string constant P_COIN = 'wROSE';
mapping(string => address) coinTypeMaping;
uint256 merchantNeedCount = 100 * (10**18);
uint256 witnessNeedCount = 1000 * (10**18);
uint256 congressNeedCount = 10000 * (10**18);
uint256 appealFee = 100 * (10**18);
uint256 appealFeeFinal = 1000 * (10**18);
uint256 canWithdrawToTime = 28;
uint256 subWitFee = 100 * (10**18);
uint256 subWitCredit = 10;
uint256 witnessHandleReward = 100 * (10**18);
uint256 observerHandleReward = 1000 * (10**18);
uint256 witnessHandleCredit = 1;
uint256 observerHandleCredit = 1;
bool openTrade = false;
uint256 tradeCredit = 1;
uint256 subTCredit = 10;
mapping(address => uint256) witnessFlag;
mapping(address => uint256) congressFlag;
function setWitnessFlag(address _addr, uint256 _flag) external onlyOwner {
witnessFlag[_addr] = _flag;
if (_flag == 1) {
uint256 _amt = availableTotal[_addr][P_COIN];
require(_amt >= witnessNeedCount, "coin not enough");
_userStorage.updateUserRole(_addr, 1);
} else {
_userStorage.updateUserRole(_addr, 0);
}
}
function getWitnessFlag(address _addr) public view returns (uint256) {
return witnessFlag[_addr];
}
function setCongressFlag(address _addr, uint256 _flag) external onlyOwner {
congressFlag[_addr] = _flag;
if (_flag == 1) {
uint256 _amt = availableTotal[_addr][P_COIN];
require(_amt >= congressNeedCount, "coin not enough");
_userStorage.updateUserRole(_addr, 2);
} else {
_userStorage.updateUserRole(_addr, 0);
}
}
function getCongressFlag(address _addr) public view returns (uint256) {
return congressFlag[_addr];
}
function setCoinTypeMapping(
string calldata _coinType,
address _coinTypeAddr
) external onlyOwner {
coinTypeMaping[_coinType] = _coinTypeAddr;
}
function getCoinTypeMapping(string calldata _coinType)
public
view
returns (address)
{
return coinTypeMaping[_coinType];
}
function setMerchantNeedCount(uint256 _count) external onlyOwner {
merchantNeedCount = _count;
}
function getMerchantNeedCount() public view returns (uint256) {
return merchantNeedCount;
}
function setWitnessNeedCount(uint256 _count) external onlyOwner {
witnessNeedCount = _count;
}
function getWitnessNeedCount() public view returns (uint256) {
return witnessNeedCount;
}
function setCongressNeedCount(uint256 _count) external onlyOwner {
congressNeedCount = _count;
}
function getCongressNeedCount() public view returns (uint256) {
return congressNeedCount;
}
function setAppealFee(uint256 _count) external onlyOwner {
appealFee = _count;
}
function getAppealFee() public view returns (uint256) {
return appealFee;
}
function setAppealFeeFinal(uint256 _count) external onlyOwner {
appealFeeFinal = _count;
}
function getAppealFeeFinal() public view returns (uint256) {
return appealFeeFinal;
}
function setCanWithdrawToTime(uint256 _days) external onlyOwner {
canWithdrawToTime = _days;
}
function getCanWithdrawToTime() public view returns (uint256) {
return canWithdrawToTime;
}
function setSubWitFee(uint256 _c) external onlyOwner {
subWitFee = _c;
}
function getSubWitFee() public view returns (uint256) {
return subWitFee;
}
function setSubWitCredit(uint256 _c) external onlyOwner {
subWitCredit = _c;
}
function getSubWitCredit() public view returns (uint256) {
return subWitCredit;
}
function setWitnessHandleReward(uint256 _c) external onlyOwner {
witnessHandleReward = _c;
}
function getWitnessHandleReward() public view returns (uint256) {
return witnessHandleReward;
}
function setObserverHandleReward(uint256 _c) external onlyOwner {
observerHandleReward = _c;
}
function getObserverHandleReward() public view returns (uint256) {
return observerHandleReward;
}
function setWitnessHandleCredit(uint256 _c) external onlyOwner {
witnessHandleCredit = _c;
}
function getWitnessHandleCredit() public view returns (uint256) {
return witnessHandleCredit;
}
function setObserverHandleCredit(uint256 _c) external onlyOwner {
observerHandleCredit = _c;
}
function getObserverHandleCredit() public view returns (uint256) {
return observerHandleCredit;
}
function setOpenTrade(bool _c) external onlyOwner {
openTrade = _c;
}
function getOpenTrade() public view returns (bool) {
return openTrade;
}
function setTradeCredit(uint256 _c) external onlyOwner {
tradeCredit = _c;
}
function getTradeCredit() public view returns (uint256) {
return tradeCredit;
}
function setSubTCredit(uint256 _c) external onlyOwner {
subTCredit = _c;
}
function getSubTCredit() public view returns (uint256) {
return subTCredit;
}
function punishPerson(
address _from,
address _to,
uint256 _count
) external onlyOwner {
require(_from != address(0) && _to != address(0));
UserStorage.User memory _user = _userStorage.searchUser(_from);
require(_user.userFlag == 1 || _user.userFlag == 2, "can't punish");
uint256 _ava = availableTotal[_from][P_COIN];
uint256 _toavailab = availableTotal[_to][P_COIN];
if (_ava >= _count) {
availableTotal[_from][P_COIN] = SafeMath.sub(_ava, _count);
availableTotal[_to][P_COIN] = SafeMath.add(_toavailab, _count);
} else {
availableTotal[_from][P_COIN] = 0;
uint256 _draing = withdrawingTotal[_from][P_COIN];
if (SafeMath.add(_ava, _draing) >= _count) {
withdrawingTotal[_from][P_COIN] = SafeMath.sub(
_draing,
SafeMath.sub(_count, _ava)
);
availableTotal[_to][P_COIN] = SafeMath.add(_toavailab, _count);
} else {
withdrawingTotal[_from][P_COIN] = 0;
availableTotal[_to][P_COIN] = SafeMath.add(
_toavailab,
SafeMath.add(_ava, _draing)
);
}
}
chanRole(_from);
chanRole(_to);
}
UserInterface private _userStorage;
OrderInterface private _orderStorage;
struct Record {
uint256 recordNo;
address userAddr;
string tradeHash;
string coinType;
uint256 hostCount;
uint256 hostStatus;
uint256 hostType;
uint256 hostDirection;
uint256 hostTime;
uint256 updateTime;
}
CountersRecord.Counter private _recordNoCounter;
mapping(uint256 => Record) public records;
mapping(uint256 => uint256) public recordIndex;
Record[] public recordList;
mapping(address => mapping(string => uint256)) public availableTotal;
mapping(address => mapping(string => uint256)) public frozenTotal;
mapping(address => mapping(string => uint256)) public unfrozenTotal;
mapping(address => uint256) lastWithdrawTime;
mapping(address => mapping(uint256 => uint256)) lastWithdrawAmount;
mapping(address => mapping(string => uint256)) public withdrawingTotal;
mapping(address => mapping(uint256 => uint256)) orderSubFrozenList;
constructor(
address _usdtAddress,
address _usdcAddress,
address _coinAddress
) {
coinTypeMaping["USDT"] = _usdtAddress;
coinTypeMaping["USDC"] = _usdcAddress;
coinTypeMaping[P_COIN] = _coinAddress;
_recordNoCounter.increment();
}
function getERC20Address(string memory _coinType)
public
view
returns (TokenTransfer)
{
address _remoteAddr = coinTypeMaping[_coinType];
require(_remoteAddr != address(0));
TokenTransfer _tokenTransfer = TokenTransfer(_remoteAddr);
return _tokenTransfer;
}
event RecordAdd(
uint256 _recordNo,
address _addr,
string _tradeHash,
string _coinType,
uint256 _hostCount,
uint256 _hostStatus,
uint256 _hostType,
uint256 _hostDirection
);
event RecordApplyUnfrozen(address _addr, uint256 _amt);
event UnfrozenTotalTransfer(
address _addr,
string _coinType,
uint256 _lastAmount
);
event RecordUpdate(
address _addr,
uint256 _recordNo,
string _hash,
uint256 _hostStatus
);
address _userAddr;
address _restCAddr;
address _orderCAddr;
address _appealCAddr;
modifier onlyAuthFromAddr() {
require(_userAddr != address(0), "Invalid address call user");
require(_restCAddr != address(0), "Invalid address call rest");
require(_orderCAddr != address(0), "Invalid address call order");
require(_appealCAddr != address(0), "Invalid address call appeal");
_;
}
function authFromContract(
address _fromUser,
address _fromRest,
address _fromOrder,
address _fromAppeal
) external onlyOwner {
_userAddr = _fromUser;
_restCAddr = _fromRest;
_orderCAddr = _fromOrder;
_appealCAddr = _fromAppeal;
_userStorage = UserInterface(_userAddr);
_orderStorage = OrderInterface(_orderCAddr);
}
function _insert(
address _addr,
string memory _tradeHash,
string memory _coinType,
uint256 _hostCount,
uint256 _hostStatus,
uint256 _hostType,
uint256 _hostDirection
) internal nonReentrant returns (uint256 recordNo) {
require(_addr != address(0), "address null");
require(bytes(_coinType).length != 0, "coinType null");
require(_hostCount != uint256(0), "hostCount null");
require(_hostType != uint256(0), "hostType null");
require(_hostDirection != uint256(0), "hostDirection null");
uint256 _recordNo = _recordNoCounter.current();
require(records[_recordNo].recordNo == uint256(0), "order exist");
Record memory _record = Record({
recordNo: _recordNo,
userAddr: _addr,
tradeHash: _tradeHash,
coinType: _coinType,
hostCount: _hostCount,
hostStatus: _hostStatus,
hostType: _hostType,
hostDirection: _hostDirection,
hostTime: block.timestamp,
updateTime: 0
});
records[_recordNo] = _record;
recordList.push(_record);
recordIndex[_recordNo] = recordList.length - 1;
_recordNoCounter.increment();
emit RecordAdd(
_recordNo,
_addr,
_tradeHash,
_coinType,
_hostCount,
_hostStatus,
_hostType,
_hostDirection
);
return _recordNo;
}
function tokenEscrow(string memory _coinType, uint256 _amt) external {
require(_amt > 0, "invalid");
require(
availableTotal[msg.sender][_coinType] + _amt >
availableTotal[msg.sender][_coinType],
"Invalid transfer amount"
);
availableTotal[msg.sender][_coinType] = SafeMath.add(
availableTotal[msg.sender][_coinType],
_amt
);
uint256 _hostType = 1;
if (
keccak256(abi.encodePacked(_coinType)) ==
keccak256(abi.encodePacked(P_COIN))
) {
_hostType = 2;
UserStorage.User memory _user = _userStorage.searchUser(msg.sender);
_changeUserMorgageStats(
msg.sender,
availableTotal[msg.sender][_coinType]
);
if (
_user.userFlag == 0 &&
availableTotal[msg.sender][_coinType] >= merchantNeedCount
) {
_userStorage.updateUserRole(msg.sender, 3);
}
}
_insert(msg.sender, "", _coinType, _amt, 2, _hostType, 1);
TokenTransfer _tokenTransfer = getERC20Address(_coinType);
_tokenTransfer.transferFrom(msg.sender, address(this), _amt);
}
function addRecord(
address _addr,
string memory _tradeHash,
string memory _coinType,
uint256 _hostCount,
uint256 _hostStatus,
uint256 _hostType,
uint256 _hostDirection
) public onlyAuthFromAddr {
require(
msg.sender == _restCAddr || msg.sender == _orderCAddr,
"RedocrdStorage:Invalid from contract address"
);
frozenTotal[_addr][_coinType] = SafeMath.add(
frozenTotal[_addr][_coinType],
_hostCount
);
_insert(
_addr,
_tradeHash,
_coinType,
_hostCount,
_hostStatus,
_hostType,
_hostDirection
);
}
function addAvailableTotal(
address _addr,
string memory _coinType,
uint256 _amt
) public onlyAuthFromAddr {
require(
msg.sender == _restCAddr || msg.sender == _orderCAddr,
"Invalid address"
);
require(_amt > 0, "invalid");
uint256 _aBalance = getErcBalance(_coinType, address(this));
require(_aBalance >= _amt, "not enough");
require(frozenTotal[_addr][_coinType] >= _amt, "insufficient");
require(
SafeMath.sub(frozenTotal[_addr][_coinType], _amt) <=
frozenTotal[_addr][_coinType],
"Invalid amount"
);
frozenTotal[_addr][_coinType] = SafeMath.sub(
frozenTotal[_addr][_coinType],
_amt
);
TokenTransfer _tokenTransfer = getERC20Address(_coinType);
_tokenTransfer.transfer(_addr, _amt);
}
function getAvailableTotal(address _addr, string memory _coinType)
public
view
returns (uint256)
{
return availableTotal[_addr][_coinType];
}
function subFrozenTotal(uint256 _orderNo, address _addr)
public
onlyAuthFromAddr
{
require(
msg.sender == _orderCAddr || msg.sender == _appealCAddr,
"Invalid call"
);
OrderStorage.Order memory _order = _orderStorage.searchOrder(_orderNo);
require(_order.orderNo != uint256(0), "not exist");
address _seller = _order.orderDetail.sellerAddr;
string memory _coinType = _order.orderDetail.coinType;
uint256 _subAmount = orderSubFrozenList[_seller][_orderNo];
require(_subAmount == 0);
uint256 _frozen = frozenTotal[_seller][_coinType];
uint256 _orderCount = _order.coinCount;
require(_frozen >= _orderCount);
require(SafeMath.sub(_frozen, _orderCount) <= _frozen);
frozenTotal[_seller][_coinType] = SafeMath.sub(_frozen, _orderCount);
orderSubFrozenList[_seller][_orderNo] = _orderCount;
TokenTransfer _tokenTransfer = getERC20Address(_coinType);
_tokenTransfer.transfer(_addr, _orderCount);
}
function subAvaAppeal(
address _from,
address _to,
AppealStorage.Appeal memory _al,
uint256 _amt,
uint256 _t,
uint256 _self
) public onlyAuthFromAddr {
require(msg.sender == _appealCAddr, "Invalid call");
uint256 _available = getAvailableTotal(_from, P_COIN);
uint256 _need = 0;
address _opt = _t == 1 ? _al.witness : _al.detail.observerAddr;
if (_available >= _amt) {
_need = _amt;
} else {
_need = _available;
}
if (
(_t == 1 && _self == 0) ||
(_t == 2 && _al.detail.finalAppealAddr != _from)
) {
availableTotal[_from][P_COIN] = SafeMath.sub(
availableTotal[_from][P_COIN],
_need
);
availableTotal[_to][P_COIN] = SafeMath.add(
availableTotal[_to][P_COIN],
_need
);
_changeUserMorgageStats(_from, availableTotal[_from][P_COIN]);
_changeUserMorgageStats(_to, availableTotal[_to][P_COIN]);
}
availableTotal[_opt][P_COIN] = SafeMath.add(
availableTotal[_opt][P_COIN],
_amt
);
_changeUserMorgageStats(_opt, availableTotal[_opt][P_COIN]);
chanRole(_from);
chanRole(_to);
chanRole(_opt);
UserStorage.User memory _user = _userStorage.searchUser(_opt);
if (_t == 1) {
_user.credit = _user.credit + witnessHandleCredit;
} else if (_t == 2) {
_user.credit = _user.credit + observerHandleCredit;
}
UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
_userStorage.updateTradeStats(_opt, _tradeStats, _user.credit);
}
function _changeUserMorgageStats(address _addr, uint256 _amt) internal {
UserStorage.User memory _user = _userStorage.searchUser(_addr);
UserStorage.MorgageStats memory _morgageStats = _user.morgageStats;
_morgageStats.mortgage = _amt;
_userStorage.updateMorgageStats(_addr, _morgageStats);
}
function subWitnessAvailable(address _addr) public onlyAuthFromAddr {
require(msg.sender == _appealCAddr, "Invalid call");
require(_addr != address(0), "address null");
uint256 _availableTotal = availableTotal[_addr][P_COIN];
uint256 _need = 0;
uint256 subFromDraing = 0;
if (_availableTotal >= subWitFee) {
_need = subWitFee;
availableTotal[_addr][P_COIN] = SafeMath.sub(
_availableTotal,
_need
);
} else {
availableTotal[_addr][P_COIN] = 0;
uint256 _draing = withdrawingTotal[_addr][P_COIN];
if (SafeMath.add(_availableTotal, _draing) >= subWitFee) {
_need = subWitFee;
subFromDraing = SafeMath.sub(subWitFee, _availableTotal);
withdrawingTotal[_addr][P_COIN] = SafeMath.sub(
_draing,
subFromDraing
);
} else {
_need = SafeMath.add(_draing, _availableTotal);
withdrawingTotal[_addr][P_COIN] = 0;
}
}
chanRole(_addr);
UserStorage.User memory _user = _userStorage.searchUser(_addr);
_user.credit = _user.credit >= subWitCredit
? (_user.credit - subWitCredit)
: 0;
UserStorage.TradeStats memory _tradeStats = _user.tradeStats;
_userStorage.updateTradeStats(_addr, _tradeStats, _user.credit);
TokenTransfer _tokenTransfer = getERC20Address(P_COIN);
_tokenTransfer.transfer(owner(), _need);
}
function getFrozenTotal(address _addr, string memory _coinType)
public
view
returns (uint256)
{
return frozenTotal[_addr][_coinType];
}
function applyUnfrozen(uint256 _amt) external returns (uint256) {
require(_amt > 0);
require(availableTotal[msg.sender][P_COIN] >= _amt, "Invalid amount");
require(
SafeMath.sub(availableTotal[msg.sender][P_COIN], _amt) <
availableTotal[msg.sender][P_COIN],
"Invalid amount 2"
);
lastWithdrawTime[msg.sender] = block.timestamp;
lastWithdrawAmount[msg.sender][lastWithdrawTime[msg.sender]] = _amt;
availableTotal[msg.sender][P_COIN] = SafeMath.sub(
availableTotal[msg.sender][P_COIN],
_amt
);
withdrawingTotal[msg.sender][P_COIN] = SafeMath.add(
withdrawingTotal[msg.sender][P_COIN],
_amt
);
chanRole(msg.sender);
_insert(msg.sender, "", P_COIN, _amt, 3, 3, 2);
emit RecordApplyUnfrozen(msg.sender, _amt);
return getAvailableTotal(msg.sender, P_COIN);
}
function chanRole(address _addr) internal {
uint256 _avail = availableTotal[_addr][P_COIN];
UserStorage.User memory _user = _userStorage.searchUser(_addr);
_changeUserMorgageStats(_addr, _avail);
if (
_user.userFlag == 2 &&
_avail < congressNeedCount &&
_avail >= merchantNeedCount
) {
_userStorage.updateUserRole(_addr, 3);
}
if (
_user.userFlag == 1 &&
_avail < witnessNeedCount &&
_avail >= merchantNeedCount
) {
_userStorage.updateUserRole(_addr, 3);
}
if (_user.userFlag == 0 && _avail >= merchantNeedCount) {
_userStorage.updateUserRole(_addr, 3);
}
if (_avail < merchantNeedCount) {
_userStorage.updateUserRole(_addr, 0);
}
}
function unApplyUnfrozen(address _addr) external onlyOwner {
uint256 _drawing = withdrawingTotal[_addr][P_COIN];
require(_drawing > 0, "sufficient");
withdrawingTotal[_addr][P_COIN] = 0;
availableTotal[_addr][P_COIN] = SafeMath.add(
availableTotal[_addr][P_COIN],
_drawing
);
chanRole(_addr);
}
function applyWithdraw(uint256 _recordNo) public {
Record memory _record = records[_recordNo];
require(_record.recordNo != uint256(0), "record not exist");
require(_record.userAddr == msg.sender, "record user not exist");
require(_record.hostStatus == 3, "status error");
require(
withdrawingTotal[msg.sender][P_COIN] >= _record.hostCount,
"sufficient"
);
require(
block.timestamp >= (_record.hostTime + canWithdrawToTime * 1 days),
"can't withdraw"
);
withdrawingTotal[msg.sender][P_COIN] = SafeMath.sub(
withdrawingTotal[msg.sender][P_COIN],
_record.hostCount
);
unfrozenTotal[msg.sender][P_COIN] = SafeMath.add(
unfrozenTotal[msg.sender][P_COIN],
_record.hostCount
);
_record.hostStatus = 4;
_record.updateTime = block.timestamp;
records[_recordNo] = _record;
recordList[recordIndex[_recordNo]] = _record;
emit RecordUpdate(msg.sender, _recordNo, _record.tradeHash, 4);
TokenTransfer _tokenTransfer = getERC20Address(P_COIN);
_tokenTransfer.transfer(msg.sender, _record.hostCount);
}
function unfrozenTotalSearch(address _addr, string memory _coinType)
public
view
returns (uint256)
{
require(_addr != address(0), "user address is null");
return unfrozenTotal[_addr][_coinType];
}
function getUnfrozenTotal(address _addr, string memory _coinType)
external
view
returns (uint256)
{
return unfrozenTotal[_addr][_coinType];
}
function getWithdrawingTotal(address _addr, string memory _coinType)
public
view
returns (uint256)
{
return withdrawingTotal[_addr][_coinType];
}
function getErcBalance(string memory _coinType, address _addr)
public
view
returns (uint256)
{
TokenTransfer _tokenTransfer = getERC20Address(_coinType);
return _tokenTransfer.balanceOf(_addr);
}
function _updateInfo(
address _addr,
uint256 _recordNo,
string memory _hash,
uint256 _hostStatus
) internal returns (bool) {
Record storage _record = records[_recordNo];
require(_record.userAddr == _addr);
require(_hostStatus == 1 || _hostStatus == 2, "invalid status");
if (_hostStatus != uint256(0)) {
_record.hostStatus = _hostStatus;
}
if (bytes(_hash).length != 0) {
_record.tradeHash = _hash;
}
_record.updateTime = block.timestamp;
emit RecordUpdate(_addr, _recordNo, _hash, _hostStatus);
return true;
}
function updateInfo(
address _addr,
uint256 _recordNo,
string memory _hash,
uint256 _hostStatus
) external returns (bool) {
return _updateInfo(_addr, _recordNo, _hash, _hostStatus);
}
function searchRecord(uint256 _recordNo)
external
view
returns (Record memory record)
{
return records[_recordNo];
}
function searchRecordList() external view returns (Record[] memory) {
return recordList;
}
}

Contract ABI

[{"type":"event","name":"OrderAdd","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256","indexed":false},{"type":"uint256","name":"_restNo","internalType":"uint256","indexed":false},{"type":"uint256","name":"_coinCount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_tradeFee","internalType":"uint256","indexed":false},{"type":"uint256","name":"_orderAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"_payType","internalType":"uint256","indexed":false},{"type":"uint256","name":"_orderType","internalType":"uint256","indexed":false},{"type":"address","name":"_buyerAddr","internalType":"address","indexed":false},{"type":"address","name":"_sellerAddr","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OrderCancel","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OrderConfirmCollect","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OrderPaidMoney","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OrderUpdateStatus","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256","indexed":false},{"type":"uint256","name":"_orderStatus","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addBuyOrder","inputs":[{"type":"uint256","name":"_restNo","internalType":"uint256"},{"type":"uint256","name":"_coinCount","internalType":"uint256"},{"type":"uint256","name":"_orderAmount","internalType":"uint256"},{"type":"uint256","name":"_payType","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"addSellOrder","inputs":[{"type":"uint256","name":"_restNo","internalType":"uint256"},{"type":"uint256","name":"_coinCount","internalType":"uint256"},{"type":"uint256","name":"_tradeFee","internalType":"uint256"},{"type":"uint256","name":"_orderAmount","internalType":"uint256"},{"type":"uint256","name":"_payType","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"authFromContract","inputs":[{"type":"address","name":"_recordAddr","internalType":"address"},{"type":"address","name":"_restAddr","internalType":"address"},{"type":"address","name":"_userAddr","internalType":"address"},{"type":"address","name":"_appealAddr","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"cancelOrder","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"confirmCollect","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCanWithdrawHours","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getCancelOrderTime","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct OrderStorage.Order[]","components":[{"type":"address","name":"userAddr","internalType":"address"},{"type":"uint256","name":"orderNo","internalType":"uint256"},{"type":"uint256","name":"restNo","internalType":"uint256"},{"type":"uint256","name":"coinCount","internalType":"uint256"},{"type":"uint256","name":"orderAmount","internalType":"uint256"},{"type":"uint256","name":"payType","internalType":"uint256"},{"type":"string","name":"currencyType","internalType":"string"},{"type":"uint256","name":"orderType","internalType":"uint256"},{"type":"uint256","name":"orderStatus","internalType":"uint256"},{"type":"tuple","name":"orderDetail","internalType":"struct OrderStorage.OrderDetail","components":[{"type":"address","name":"buyerAddr","internalType":"address"},{"type":"address","name":"sellerAddr","internalType":"address"},{"type":"string","name":"coinType","internalType":"string"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"tradeTime","internalType":"uint256"},{"type":"uint256","name":"updateTime","internalType":"uint256"},{"type":"string","name":"tradeHash","internalType":"string"},{"type":"uint256","name":"tradeFee","internalType":"uint256"}]}]}],"name":"searchListByRest","inputs":[{"type":"uint256","name":"_restNo","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple","name":"order","internalType":"struct OrderStorage.Order","components":[{"type":"address","name":"userAddr","internalType":"address"},{"type":"uint256","name":"orderNo","internalType":"uint256"},{"type":"uint256","name":"restNo","internalType":"uint256"},{"type":"uint256","name":"coinCount","internalType":"uint256"},{"type":"uint256","name":"orderAmount","internalType":"uint256"},{"type":"uint256","name":"payType","internalType":"uint256"},{"type":"string","name":"currencyType","internalType":"string"},{"type":"uint256","name":"orderType","internalType":"uint256"},{"type":"uint256","name":"orderStatus","internalType":"uint256"},{"type":"tuple","name":"orderDetail","internalType":"struct OrderStorage.OrderDetail","components":[{"type":"address","name":"buyerAddr","internalType":"address"},{"type":"address","name":"sellerAddr","internalType":"address"},{"type":"string","name":"coinType","internalType":"string"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"tradeTime","internalType":"uint256"},{"type":"uint256","name":"updateTime","internalType":"uint256"},{"type":"string","name":"tradeHash","internalType":"string"},{"type":"uint256","name":"tradeFee","internalType":"uint256"}]}]}],"name":"searchOrder","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"tuple[]","name":"","internalType":"struct OrderStorage.Order[]","components":[{"type":"address","name":"userAddr","internalType":"address"},{"type":"uint256","name":"orderNo","internalType":"uint256"},{"type":"uint256","name":"restNo","internalType":"uint256"},{"type":"uint256","name":"coinCount","internalType":"uint256"},{"type":"uint256","name":"orderAmount","internalType":"uint256"},{"type":"uint256","name":"payType","internalType":"uint256"},{"type":"string","name":"currencyType","internalType":"string"},{"type":"uint256","name":"orderType","internalType":"uint256"},{"type":"uint256","name":"orderStatus","internalType":"uint256"},{"type":"tuple","name":"orderDetail","internalType":"struct OrderStorage.OrderDetail","components":[{"type":"address","name":"buyerAddr","internalType":"address"},{"type":"address","name":"sellerAddr","internalType":"address"},{"type":"string","name":"coinType","internalType":"string"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"tradeTime","internalType":"uint256"},{"type":"uint256","name":"updateTime","internalType":"uint256"},{"type":"string","name":"tradeHash","internalType":"string"},{"type":"uint256","name":"tradeFee","internalType":"uint256"}]}]}],"name":"searchOrderList","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCanWithdrawHours","inputs":[{"type":"uint256","name":"_count","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCancelOrderTime","inputs":[{"type":"uint256","name":"_count","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setPaidMoney","inputs":[{"type":"uint256","name":"_orderNo","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"takeCoin","inputs":[{"type":"uint256","name":"_o","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]}]
            

Contract Creation Code

0x6080604052601e600c556018600d553480156200001b57600080fd5b50620000273362000031565b6001805562000081565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6148a280620000916000396000f3fe608060405234801561001057600080fd5b506004361061010b5760003560e01c80637318be66116100a2578063923cce5e11610071578063923cce5e146101fe5780639a80e66c14610211578063c57666be14610224578063e72e411414610244578063f2fde38b1461025757600080fd5b80637318be66146101c0578063889d8ff4146101d35780638c2d1a3a146101db5780638da5cb5b146101e357600080fd5b8063514fcac7116100de578063514fcac71461017f57806357ce6486146101925780636cf75b5e146101a5578063715018a6146101b857600080fd5b80630f5dccc4146101105780631168bbe41461013857806321e1474b146101585780634fe188ad1461016a575b600080fd5b61012361011e366004613b46565b61026a565b60405190151581526020015b60405180910390f35b61014b610146366004613b46565b610332565b60405161012f9190613cd2565b600d545b60405190815260200161012f565b61017d610178366004613b46565b6106a3565b005b61012361018d366004613b46565b6106d2565b61017d6101a0366004613b46565b610d69565b61017d6101b3366004613b46565b61151d565b61017d61154c565b61017d6101ce366004613d49565b611582565b61014b611610565b600c5461015c565b6000546040516001600160a01b03909116815260200161012f565b61017d61020c366004613b46565b6118ea565b61017d61021f366004613da5565b611b95565b610237610232366004613b46565b612111565b60405161012f9190613de0565b61017d610252366004613df3565b6123ff565b61017d610265366004613e25565b61289d565b600081806102935760405162461bcd60e51b815260040161028a90613e42565b60405180910390fd5b6000818152600860205260409020600901546001600160a01b031633146102e95760405162461bcd60e51b815260206004820152600a60248201526937b7363c90313abcb2b960b11b604482015260640161028a565b6102f4836002612938565b6040518381527f6992e0bea484754da7aaaf68b0918cd87ec1ddbda5a503f902f0b2cd0aa668709060200160405180910390a1600191505b50919050565b600a546060906000906001600160401b0381111561035257610352613e68565b60405190808252806020026020018201604052801561038b57816020015b6103786139fa565b8152602001906001900390816103705790505b50905060005b600a5481101561069c576000600a82815481106103b0576103b0613e7e565b9060005260206000209060110201604051806101400160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201805461043b90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461046790613e94565b80156104b45780601f10610489576101008083540402835291602001916104b4565b820191906000526020600020905b81548152906001019060200180831161049757829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b8501805460609095019491939284019161051c90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461054890613e94565b80156105955780601f1061056a57610100808354040283529160200191610595565b820191906000526020600020905b81548152906001019060200180831161057857829003601f168201915b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820180546105cc90613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546105f890613e94565b80156106455780601f1061061a57610100808354040283529160200191610645565b820191906000526020600020905b81548152906001019060200180831161062857829003601f168201915b505050505081526020016007820154815250508152505090508481604001511415610689578083838151811061067d5761067d613e7e565b60200260200101819052505b508061069481613edf565b915050610391565b5092915050565b6000546001600160a01b031633146106cd5760405162461bcd60e51b815260040161028a90613efa565b600c55565b600081806106f25760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061073357506000818152600860205260409020600901546001600160a01b031633145b61074f5760405162461bcd60e51b815260040161028a90613f2f565b600083815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c0840191906107c190613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546107ed90613e94565b801561083a5780601f1061080f5761010080835404028352916020019161083a565b820191906000526020600020905b81548152906001019060200180831161081d57829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b850180546060909501949193928401916108a290613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546108ce90613e94565b801561091b5780601f106108f05761010080835404028352916020019161091b565b820191906000526020600020905b8154815290600101906020018083116108fe57829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461095290613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461097e90613e94565b80156109cb5780601f106109a0576101008083540402835291602001916109cb565b820191906000526020600020905b8154815290600101906020018083116109ae57829003601f168201915b50505050508152602001600782015481525050815250509050600081602001511415610a095760405162461bcd60e51b815260040161028a90613f5d565b806101000151600114610a535760405162461bcd60e51b815260206004820152601260248201527121b0b713ba1031b0b731b2b61037b93232b960711b604482015260640161028a565b610120810151602001516001600160a01b0316331415610ac65742600c54603c610a7d9190613f94565b82610120015160800151610a919190613fb3565b10610ac65760405162461bcd60e51b81526020600482015260056024820152641b1a5b5a5d60da1b604482015260640161028a565b6002546040828101519051630129ad5160e01b815260048101919091526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015610b16573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3e9190810190614278565b905080610100015160041480610b5957508061010001516005145b15610c0057610120820180516020908101516001600160a01b039081166000908152600b835260408082208a835284528082209190915560035493519283015192810151606087015191516332f02e1d60e01b815294909216936332f02e1d93610bc99390929091600401614399565b600060405180830381600087803b158015610be357600080fd5b505af1158015610bf7573d6000803e3d6000fd5b50505050610d20565b8160e0015160021415610cab57610120820180516020908101516001600160a01b039081166000908152600b835260408082208a835284528082209190915560035493519283015192810151606087015191516332f02e1d60e01b815294909216936332f02e1d93610c789390929091600401614399565b600060405180830381600087803b158015610c9257600080fd5b505af1158015610ca6573d6000803e3d6000fd5b505050505b60025460408084015160608501519151632b9db5df60e11b81526001600160a01b039093169263573b6bbe92610ced9291600401918252602082015260400190565b600060405180830381600087803b158015610d0757600080fd5b505af1158015610d1b573d6000803e3d6000fd5b505050505b610d2b856004612938565b6040518581527fab15e9f4d651ec7d8276a842911d7028683655a4e1d043a54a623c2d36f3b18f9060200160405180910390a1506001949350505050565b8080610d875760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b03163314610dde5760405162461bcd60e51b815260206004820152600b60248201526a37b7363c9039b2b63632b960a91b604482015260640161028a565b81610dfb5760405162461bcd60e51b815260040161028a90613e42565b600082815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c084019190610e6d90613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054610e9990613e94565b8015610ee65780601f10610ebb57610100808354040283529160200191610ee6565b820191906000526020600020905b815481529060010190602001808311610ec957829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b85018054606090950194919392840191610f4e90613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7a90613e94565b8015610fc75780601f10610f9c57610100808354040283529160200191610fc7565b820191906000526020600020905b815481529060010190602001808311610faa57829003601f168201915b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682018054610ffe90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461102a90613e94565b80156110775780601f1061104c57610100808354040283529160200191611077565b820191906000526020600020905b81548152906001019060200180831161105a57829003601f168201915b505050505081526020016007820154815250508152505090508061010001516002146110dc5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206f726465722073746174757360601b604482015260640161028a565b610120810151516001600160a01b03166111305760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206275796572206164647265737360581b604482015260640161028a565b6060810151336000908152600b6020908152604080832087845290915290205410156111905760405162461bcd60e51b815260206004820152600f60248201526e0c6ded2dc40dcdee840cadcdeeaced608b1b604482015260640161028a565b61119b836003612938565b336000908152600b6020908152604080832086845282528083208390556003548151635c7cee6360e01b815291516001600160a01b0390911692635c7cee6392600480820193918290030181865afa1580156111fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121f91906143cd565b60048054604051639bd7417f60e01b815233928101929092529192506000916001600160a01b031690639bd7417f90602401600060405180830381865afa15801561126e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261129691908101906144b7565b90506000828260a001516112aa9190613fb3565b60e083015180519192509060019082906112c5908390613fb3565b905250600480546040516316a1e96960e31b815233928101929092528251602483015260208301516044830152606482018490526001600160a01b03169063b50f4b4890608401600060405180830381600087803b15801561132657600080fd5b505af115801561133a573d6000803e3d6000fd5b50506004805461012089015151604051639bd7417f60e01b81526001600160a01b039182169381019390935260009450169150639bd7417f90602401600060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bb91908101906144b7565b90506000858260a001516113cf9190613fb3565b60e083015180519192509060019082906113ea908390613fb3565b905250600480546101208a0151516040516316a1e96960e31b81526001600160a01b0391821693810193909352835160248401526020840151604484015260648301859052169063b50f4b4890608401600060405180830381600087803b15801561145457600080fd5b505af1158015611468573d6000803e3d6000fd5b50506003546101208b0151516040516301b7257760e41b8152600481018f90526001600160a01b03918216602482015291169250631b7257709150604401600060405180830381600087803b1580156114c057600080fd5b505af11580156114d4573d6000803e3d6000fd5b505050507f2977e4c43592a10bfbebdbacff1dd75f525cfc12644428d2f0bc595572d0e1c88a60405161150991815260200190565b60405180910390a150505050505050505050565b6000546001600160a01b031633146115475760405162461bcd60e51b815260040161028a90613efa565b600d55565b6000546001600160a01b031633146115765760405162461bcd60e51b815260040161028a90613efa565b61158060006131da565b565b6000546001600160a01b031633146115ac5760405162461bcd60e51b815260040161028a90613efa565b600380546001600160a01b03199081166001600160a01b0387811691821790935560028054831687851617905560048054831686851617905560068054831690911790556005805490911691831691909117905561160a600761322a565b50505050565b6060600a805480602002602001604051908101604052809291908181526020016000905b828210156118e157600084815260209081902060408051610140810182526011860290920180546001600160a01b031683526001810154938301939093526002830154908201526003820154606082015260048201546080820152600582015460a082015260068201805491929160c0840191906116b190613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546116dd90613e94565b801561172a5780601f106116ff5761010080835404028352916020019161172a565b820191906000526020600020905b81548152906001019060200180831161170d57829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b8501805460609095019491939284019161179290613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546117be90613e94565b801561180b5780601f106117e05761010080835404028352916020019161180b565b820191906000526020600020905b8154815290600101906020018083116117ee57829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461184290613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461186e90613e94565b80156118bb5780601f10611890576101008083540402835291602001916118bb565b820191906000526020600020905b81548152906001019060200180831161189e57829003601f168201915b505050505081526020016007820154815250508152505081526020019060010190611634565b50505050905090565b80806119085760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061194957506000818152600860205260409020600901546001600160a01b031633145b6119655760405162461bcd60e51b815260040161028a90613f2f565b6005546040516339ccd25f60e01b8152600481018490526000916001600160a01b0316906339ccd25f90602401600060405180830381865afa1580156119af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119d791908101906146ba565b9050600d54610e106119e99190613f94565b61016082015160a001516119fd90426147a7565b11611a375760405162461bcd60e51b815260206004820152600a6024820152693a34b6b29032b93937b960b11b604482015260640161028a565b600081608001516001600160a01b031682600001516001600160a01b03161415611a8c578160e0015160021415611a7357506080810151611ab8565b8160e0015160031415611a87575060a08101515b611ab8565b8160e0015160021415611aa4575060a0810151611ab8565b8160e0015160031415611ab8575060808101515b6001600160a01b0381163314611afc5760405162461bcd60e51b815260206004820152600960248201526837b83a1032b93937b960b91b604482015260640161028a565b611b07846005612938565b60a08201516001600160a01b039081166000908152600b602090815260408083208884529091528082209190915560035490516301b7257760e41b815260048101879052336024820152911690631b72577090604401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b5050505050505050565b600254604051630129ad5160e01b8152600481018790526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c079190810190614278565b80519091506001600160a01b0316331415611c345760405162461bcd60e51b815260040161028a906147be565b8060400151600114611c7d5760405162461bcd60e51b8152602060048201526012602482015271189d5e481c995cdd081b9bdd08195e1a5cdd60721b604482015260640161028a565b60008511611cc05760405162461bcd60e51b815260206004820152601060248201526f31b7b4b71031b7bab73a1032b93937b960811b604482015260640161028a565b60008311611d045760405162461bcd60e51b815260206004820152601160248201527037b93232b920b6b7bab73a1032b93937b960791b604482015260640161028a565b806101000151600114611d4d5760405162461bcd60e51b81526020600482015260116024820152703932b9ba1039ba30ba3ab99032b93937b960791b604482015260640161028a565b6000611d5d8260c0015187613253565b9050816101200151604001518110158015611d815750816101200151606001518111155b611dbc5760405162461bcd60e51b815260206004820152600c60248201526b30b6b7bab73a1032b93937b960a11b604482015260640161028a565b60048054604051639bd7417f60e01b815233928101929092526000916001600160a01b0390911690639bd7417f90602401600060405180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e3291908101906144b7565b90508060800151600114158015611e4e57508060800151600214155b611e895760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640161028a565b826101200151608001518160a001511015611ed55760405162461bcd60e51b815260206004820152600c60248201526b31b932b234ba1032b93937b960a11b604482015260640161028a565b61012083015160a00151610100820151511015611f255760405162461bcd60e51b815260206004820152600e60248201526d36b7b93a33b0b3b29032b93937b960911b604482015260640161028a565b6000611f318888613266565b600254604051633e4a8eed60e21b8152600481018c9052602481018b90529192506001600160a01b03169063f92a3bb490604401600060405180830381600087803b158015611f7f57600080fd5b505af1158015611f93573d6000803e3d6000fd5b50505050611fac898989898960028a6000015133613272565b506003546060850151604051630bc67f9b60e01b81526000926001600160a01b031691630bc67f9b91611fe291906004016147e6565b6020604051808303816000875af1158015612001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202591906147f9565b6006546040516323b872dd60e01b81523360048201526001600160a01b039182166024820152604481018590529192508216906323b872dd90606401600060405180830381600087803b15801561207b57600080fd5b505af115801561208f573d6000803e3d6000fd5b50506003546060880151604051634e23ea9760e01b81526001600160a01b039092169350634e23ea9792506120d3913391908e906002906001908290600401614816565b600060405180830381600087803b1580156120ed57600080fd5b505af1158015612101573d6000803e3d6000fd5b5050505050505050505050505050565b6121196139fa565b816121365760405162461bcd60e51b815260040161028a90613e42565b6000828152600860205260409020600101546121645760405162461bcd60e51b815260040161028a90613f5d565b600082815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c0840191906121d690613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461220290613e94565b801561224f5780601f106122245761010080835404028352916020019161224f565b820191906000526020600020905b81548152906001019060200180831161223257829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b850180546060909501949193928401916122b790613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546122e390613e94565b80156123305780601f1061230557610100808354040283529160200191612330565b820191906000526020600020905b81548152906001019060200180831161231357829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461236790613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461239390613e94565b80156123e05780601f106123b5576101008083540402835291602001916123e0565b820191906000526020600020905b8154815290600101906020018083116123c357829003601f168201915b5050509183525050600791909101546020909101529052509392505050565b600254604051630129ad5160e01b8152600481018690526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015612449573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124719190810190614278565b80519091506001600160a01b031633141561249e5760405162461bcd60e51b815260040161028a906147be565b80604001516002146124e85760405162461bcd60e51b81526020600482015260136024820152721cd95b1b081c995cdd081b9bdd08195e1a5cdd606a1b604482015260640161028a565b6000841180156124f85750600083115b6125375760405162461bcd60e51b815260206004820152601060248201526f31b7b4b71031b7bab73a1032b93937b960811b604482015260640161028a565b8061010001516001146125805760405162461bcd60e51b81526020600482015260116024820152703932b9ba1039ba30ba3ab99032b93937b960791b604482015260640161028a565b60048054604051639bd7417f60e01b815233928101929092526000916001600160a01b0390911690639bd7417f90602401600060405180830381865afa1580156125ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125f691908101906144b7565b9050806080015160011415801561261257508060800151600214155b61264d5760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640161028a565b600254825160405163e9a5f96d60e01b81526001600160a01b03918216600482015260248101899052600092919091169063e9a5f96d90604401602060405180830381865afa1580156126a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c891906143cd565b90508581101561270c5760405162461bcd60e51b815260206004820152600f60248201526e0c6ded2dc40dcdee840cadcdeeaced608b1b604482015260640161028a565b600061271c8460c0015188613253565b90508361012001516040015181101580156127405750836101200151606001518111155b61277b5760405162461bcd60e51b815260206004820152600c60248201526b30b6b7bab73a1032b93937b960a11b604482015260640161028a565b836101200151608001518360a0015110156127c75760405162461bcd60e51b815260206004820152600c60248201526b31b932b234ba1032b93937b960a11b604482015260640161028a565b61012084015160a001516101008401515110156128175760405162461bcd60e51b815260206004820152600e60248201526d36b7b93a33b0b3b29032b93937b960911b604482015260640161028a565b600254604051633e4a8eed60e21b8152600481018a9052602481018990526001600160a01b039091169063f92a3bb490604401600060405180830381600087803b15801561286457600080fd5b505af1158015612878573d6000803e3d6000fd5b505050506128928888600089896001338b60000151613272565b505050505050505050565b6000546001600160a01b031633146128c75760405162461bcd60e51b815260040161028a90613efa565b6001600160a01b03811661292c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161028a565b612935816131da565b50565b81806129565760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061299757506000818152600860205260409020600901546001600160a01b031633145b6129b35760405162461bcd60e51b815260040161028a90613f2f565b600083815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c084019190612a2590613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612a5190613e94565b8015612a9e5780601f10612a7357610100808354040283529160200191612a9e565b820191906000526020600020905b815481529060010190602001808311612a8157829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b85018054606090950194919392840191612b0690613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612b3290613e94565b8015612b7f5780601f10612b5457610100808354040283529160200191612b7f565b820191906000526020600020905b815481529060010190602001808311612b6257829003601f168201915b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682018054612bb690613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612be290613e94565b8015612c2f5780601f10612c0457610100808354040283529160200191612c2f565b820191906000526020600020905b815481529060010190602001808311612c1257829003601f168201915b50505050508152602001600782015481525050815250509050600081602001511415612c6d5760405162461bcd60e51b815260040161028a90613f5d565b60018310158015612c7f575060058311155b612cc25760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206f726465722073746174757360601b604482015260640161028a565b826002148015612cd85750806101000151600114155b15612d1e5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21037b93232b91039ba30ba3ab9901960511b604482015260640161028a565b826003148015612d345750806101000151600214155b15612d7a5760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7264657220737461747573203360501b604482015260640161028a565b826004148015612d905750806101000151600114155b15612dd65760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a59081bdc99195c881cdd185d1d5cc80d60521b604482015260640161028a565b826005148015612dec5750806101000151600114155b8015612dfe5750806101000151600214155b15612e445760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7264657220737461747573203560501b604482015260640161028a565b8260021415612e9d57610120810151516001600160a01b03163314612e9d5760405162461bcd60e51b815260206004820152600f60248201526e1bdb9b1e48189d5e595c8818d85b1b608a1b604482015260640161028a565b8260031415612efa57610120810151602001516001600160a01b03163314612efa5760405162461bcd60e51b815260206004820152601060248201526f1bdb9b1e481cd95b1b195c8818d85b1b60821b604482015260640161028a565b61010081018390526101208101514260a091820152600085815260086020908152604091829020845181546001600160a01b0319166001600160a01b03909116178155818501516001820155918401516002830155606084015160038301556080840151600483015591830151600582015560c083015180518493612f86926006850192910190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a870180549093169416939093179055604083015180519192612ff692600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c08201518051613030916006840191602090910190613aad565b5060e091909101516007909101555050600084815260096020526040902054600a8054839290811061306457613064613e7e565b600091825260209182902083516011929092020180546001600160a01b0319166001600160a01b0390921691909117815582820151600182015560408301516002820155606083015160038201556080830151600482015560a0830151600582015560c0830151805191926130e192600685019290910190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a87018054909316941693909317905560408301518051919261315192600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c0820151805161318b916006840191602090910190613aad565b5060e09190910151600790910155505060408051858152602081018590527f5bd27be5765507f933e2cb48522d35ec14e011f43ce75c17041898e6ed37d859910160405180910390a150505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80546132365761271081555b600181600001600082825461324b9190613fb3565b909155505050565b600061325f8284613f94565b9392505050565b600061325f8284613fb3565b6000600260015414156132c75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161028a565b60026001556132d8898988886138ff565b600254604051630129ad5160e01b8152600481018b90526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015613322573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261334a9190810190614278565b80519091506001600160a01b03166133745760405162461bcd60e51b815260040161028a906147be565b6000604051806101000160405280866001600160a01b03168152602001856001600160a01b03168152602001836060015181526020018360c001518152602001428152602001600081526020016040518060200160405280600081525081526020018a815250905060006133e760075490565b600081815260086020526040902060010154909150156134375760405162461bcd60e51b815260206004820152600b60248201526a1bdc99195c88195e1a5cdd60aa1b604482015260640161028a565b6000604051806101400160405280336001600160a01b031681526020018381526020018e81526020018d81526020018b81526020018a81526020018560800151815260200189815260200160018152602001848152509050806008600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601908051906020019061351e929190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a87018054909316941693909317905560408301518051919261358e92600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c082015180516135c8916006840191602090910190613aad565b5060e091909101516007909101555050600a805460018101825560009190915281517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601190920291820180546001600160a01b0319166001600160a01b039092169190911781556020808401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a984015560408401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2aa84015560608401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ab84015560808401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ac84015560a08401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ad84015560c084015180518594613737937fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ae909101920190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a8701805490931694169390931790556040830151805191926137a792600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c082015180516137e1916006840191602090910190613aad565b5060e091909101516007909101555050600a54613800906001906147a7565b600083815260096020526040902055600288141561383a57336000908152600b6020908152604080832085845290915290208c905561386b565b876001141561386b5783516001600160a01b03166000908152600b6020908152604080832085845290915290208c90555b613875600761322a565b60408051838152602081018f90529081018d9052606081018c9052608081018b905260a081018a905260c081018990526001600160a01b0380891660e083015287166101008201527f65c63bce967237d9b3fd7a8cd7f6a75e6f9d4196256f87fc332a42a71081e05c906101200160405180910390a150600180559b9a5050505050505050505050565b8361393a5760405162461bcd60e51b815260206004820152600b60248201526a1c995cdd139bc81b9d5b1b60aa1b604482015260640161028a565b6000831161397b5760405162461bcd60e51b815260206004820152600e60248201526d18dbda5b90dbdd5b9d081b9d5b1b60921b604482015260640161028a565b600082116139be5760405162461bcd60e51b815260206004820152601060248201526f1bdc99195c905b5bdd5b9d081b9d5b1b60821b604482015260640161028a565b8061160a5760405162461bcd60e51b815260206004820152600c60248201526b1c185e551e5c19481b9d5b1b60a21b604482015260640161028a565b60405180610140016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016000815260200160008152602001613aa860405180610100016040528060006001600160a01b0316815260200160006001600160a01b031681526020016060815260200160008152602001600081526020016000815260200160608152602001600081525090565b905290565b828054613ab990613e94565b90600052602060002090601f016020900481019282613adb5760008555613b21565b82601f10613af457805160ff1916838001178555613b21565b82800160010185558215613b21579182015b82811115613b21578251825591602001919060010190613b06565b50613b2d929150613b31565b5090565b5b80821115613b2d5760008155600101613b32565b600060208284031215613b5857600080fd5b5035919050565b60005b83811015613b7a578181015183820152602001613b62565b8381111561160a5750506000910152565b60008151808452613ba3816020860160208601613b5f565b601f01601f19169290920160200192915050565b600061010060018060a01b03808451168552806020850151166020860152506040830151816040860152613bed82860182613b8b565b915050606083015160608501526080830151608085015260a083015160a085015260c083015184820360c0860152613c258282613b8b565b91505060e083015160e08501528091505092915050565b80516001600160a01b0316825260006101406020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c08301518160c0860152613c9782860182613b8b565b91505060e083015160e08501526101008084015181860152506101208084015185830382870152613cc88382613bb7565b9695505050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613d2757603f19888603018452613d15858351613c3c565b94509285019290850190600101613cf9565b5092979650505050505050565b6001600160a01b038116811461293557600080fd5b60008060008060808587031215613d5f57600080fd5b8435613d6a81613d34565b93506020850135613d7a81613d34565b92506040850135613d8a81613d34565b91506060850135613d9a81613d34565b939692955090935050565b600080600080600060a08688031215613dbd57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60208152600061325f6020830184613c3c565b60008060008060808587031215613e0957600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215613e3757600080fd5b813561325f81613d34565b6020808252600c908201526b1bdc99195c939bc81b9d5b1b60a21b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600181811c90821680613ea857607f821691505b6020821081141561032c57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ef357613ef3613ec9565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526014908201527327b7363c90313abcb2b91037b91039b2b63632b960611b604082015260600190565b60208082526017908201527f63757272656e74204f72646572206e6f74206578697374000000000000000000604082015260600190565b6000816000190483118215151615613fae57613fae613ec9565b500290565b60008219821115613fc657613fc6613ec9565b500190565b60405161016081016001600160401b0381118282101715613fee57613fee613e68565b60405290565b60405161014081016001600160401b0381118282101715613fee57613fee613e68565b60405161012081016001600160401b0381118282101715613fee57613fee613e68565b60405161020081016001600160401b0381118282101715613fee57613fee613e68565b60405161018081016001600160401b0381118282101715613fee57613fee613e68565b604051601f8201601f191681016001600160401b03811182821017156140a8576140a8613e68565b604052919050565b80516140bb81613d34565b919050565b600082601f8301126140d157600080fd5b81516001600160401b038111156140ea576140ea613e68565b6140fd601f8201601f1916602001614080565b81815284602083860101111561411257600080fd5b614123826020830160208701613b5f565b949350505050565b600082601f83011261413c57600080fd5b815160206001600160401b0382111561415757614157613e68565b8160051b614166828201614080565b928352848101820192828101908785111561418057600080fd5b83870192505b8483101561419f57825182529183019190830190614186565b979650505050505050565b600061016082840312156141bd57600080fd5b6141c5613fcb565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c08201516001600160401b038082111561421757600080fd5b614223858386016140c0565b60c084015260e0848101519084015261010080850151908401526101208085015190840152610140808501519092508181111561425f57600080fd5b61426b868287016140c0565b8385015250505092915050565b60006020828403121561428a57600080fd5b81516001600160401b03808211156142a157600080fd5b9083019061014082860312156142b657600080fd5b6142be613ff4565b6142c7836140b0565b815260208301516020820152604083015160408201526060830151828111156142ef57600080fd5b6142fb878286016140c0565b60608301525060808301518281111561431357600080fd5b61431f878286016140c0565b60808301525060a083015160a082015260c083015160c082015260e08301518281111561434b57600080fd5b6143578782860161412b565b60e0830152506101008381015190820152610120808401518381111561437c57600080fd5b614388888287016141aa565b918301919091525095945050505050565b6001600160a01b03841681526060602082018190526000906143bd90830185613b8b565b9050826040830152949350505050565b6000602082840312156143df57600080fd5b5051919050565b6000604082840312156143f857600080fd5b604051604081018181106001600160401b038211171561441a5761441a613e68565b604052825181526020928301519281019290925250919050565b600060e0828403121561444657600080fd5b60405160e081018181106001600160401b038211171561446857614468613e68565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201525092915050565b6000602082840312156144c957600080fd5b81516001600160401b03808211156144e057600080fd5b9083019061020082860312156144f557600080fd5b6144fd614017565b614506836140b0565b815260208301518281111561451a57600080fd5b614526878286016140c0565b60208301525060408301518281111561453e57600080fd5b61454a878286016140c0565b604083015250606083015160608201526080830151608082015260a083015160a082015260c083015160c08201526145858660e085016143e6565b60e0820152614598866101208501614434565b61010082015295945050505050565b600061020082840312156145ba57600080fd5b6145c261403a565b90506145cd826140b0565b81526020820151602082015260408201516001600160401b03808211156145f357600080fd5b6145ff858386016140c0565b604084015260608401516060840152608084015191508082111561462257600080fd5b5061462f848285016140c0565b60808301525060a082015160a082015260c082015160c082015261465560e083016140b0565b60e0820152610100828101519082015261012080830151908201526101408083015190820152610160808301519082015261018080830151908201526101a080830151908201526101c080830151908201526101e09182015191810191909152919050565b6000602082840312156146cc57600080fd5b81516001600160401b03808211156146e357600080fd5b9083019061018082860312156146f857600080fd5b61470061405d565b614709836140b0565b8152602083015160208201526040830151604082015261472b606084016140b0565b606082015261473c608084016140b0565b608082015261474d60a084016140b0565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401518381111561479b57600080fd5b614388888287016145a7565b6000828210156147b9576147b9613ec9565b500390565b6020808252600e908201526d1c995cdd081b9bdd08195e1a5cdd60921b604082015260600190565b60208152600061325f6020830184613b8b565b60006020828403121561480b57600080fd5b815161325f81613d34565b60018060a01b038716815260e06020820152600060e0820152600061010080604084015261484681840189613b8b565b9150508560608301528460808301528360a08301528260c083015297965050505050505056fea2646970667358221220a7b6bb5fcbf52c2c2bdee2099a06a514cca8d07adb5e92f6d5cc800f977a652164736f6c634300080b0033

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061010b5760003560e01c80637318be66116100a2578063923cce5e11610071578063923cce5e146101fe5780639a80e66c14610211578063c57666be14610224578063e72e411414610244578063f2fde38b1461025757600080fd5b80637318be66146101c0578063889d8ff4146101d35780638c2d1a3a146101db5780638da5cb5b146101e357600080fd5b8063514fcac7116100de578063514fcac71461017f57806357ce6486146101925780636cf75b5e146101a5578063715018a6146101b857600080fd5b80630f5dccc4146101105780631168bbe41461013857806321e1474b146101585780634fe188ad1461016a575b600080fd5b61012361011e366004613b46565b61026a565b60405190151581526020015b60405180910390f35b61014b610146366004613b46565b610332565b60405161012f9190613cd2565b600d545b60405190815260200161012f565b61017d610178366004613b46565b6106a3565b005b61012361018d366004613b46565b6106d2565b61017d6101a0366004613b46565b610d69565b61017d6101b3366004613b46565b61151d565b61017d61154c565b61017d6101ce366004613d49565b611582565b61014b611610565b600c5461015c565b6000546040516001600160a01b03909116815260200161012f565b61017d61020c366004613b46565b6118ea565b61017d61021f366004613da5565b611b95565b610237610232366004613b46565b612111565b60405161012f9190613de0565b61017d610252366004613df3565b6123ff565b61017d610265366004613e25565b61289d565b600081806102935760405162461bcd60e51b815260040161028a90613e42565b60405180910390fd5b6000818152600860205260409020600901546001600160a01b031633146102e95760405162461bcd60e51b815260206004820152600a60248201526937b7363c90313abcb2b960b11b604482015260640161028a565b6102f4836002612938565b6040518381527f6992e0bea484754da7aaaf68b0918cd87ec1ddbda5a503f902f0b2cd0aa668709060200160405180910390a1600191505b50919050565b600a546060906000906001600160401b0381111561035257610352613e68565b60405190808252806020026020018201604052801561038b57816020015b6103786139fa565b8152602001906001900390816103705790505b50905060005b600a5481101561069c576000600a82815481106103b0576103b0613e7e565b9060005260206000209060110201604051806101400160405290816000820160009054906101000a90046001600160a01b03166001600160a01b03166001600160a01b03168152602001600182015481526020016002820154815260200160038201548152602001600482015481526020016005820154815260200160068201805461043b90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461046790613e94565b80156104b45780601f10610489576101008083540402835291602001916104b4565b820191906000526020600020905b81548152906001019060200180831161049757829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b8501805460609095019491939284019161051c90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461054890613e94565b80156105955780601f1061056a57610100808354040283529160200191610595565b820191906000526020600020905b81548152906001019060200180831161057857829003601f168201915b505050505081526020016003820154815260200160048201548152602001600582015481526020016006820180546105cc90613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546105f890613e94565b80156106455780601f1061061a57610100808354040283529160200191610645565b820191906000526020600020905b81548152906001019060200180831161062857829003601f168201915b505050505081526020016007820154815250508152505090508481604001511415610689578083838151811061067d5761067d613e7e565b60200260200101819052505b508061069481613edf565b915050610391565b5092915050565b6000546001600160a01b031633146106cd5760405162461bcd60e51b815260040161028a90613efa565b600c55565b600081806106f25760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061073357506000818152600860205260409020600901546001600160a01b031633145b61074f5760405162461bcd60e51b815260040161028a90613f2f565b600083815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c0840191906107c190613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546107ed90613e94565b801561083a5780601f1061080f5761010080835404028352916020019161083a565b820191906000526020600020905b81548152906001019060200180831161081d57829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b850180546060909501949193928401916108a290613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546108ce90613e94565b801561091b5780601f106108f05761010080835404028352916020019161091b565b820191906000526020600020905b8154815290600101906020018083116108fe57829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461095290613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461097e90613e94565b80156109cb5780601f106109a0576101008083540402835291602001916109cb565b820191906000526020600020905b8154815290600101906020018083116109ae57829003601f168201915b50505050508152602001600782015481525050815250509050600081602001511415610a095760405162461bcd60e51b815260040161028a90613f5d565b806101000151600114610a535760405162461bcd60e51b815260206004820152601260248201527121b0b713ba1031b0b731b2b61037b93232b960711b604482015260640161028a565b610120810151602001516001600160a01b0316331415610ac65742600c54603c610a7d9190613f94565b82610120015160800151610a919190613fb3565b10610ac65760405162461bcd60e51b81526020600482015260056024820152641b1a5b5a5d60da1b604482015260640161028a565b6002546040828101519051630129ad5160e01b815260048101919091526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015610b16573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610b3e9190810190614278565b905080610100015160041480610b5957508061010001516005145b15610c0057610120820180516020908101516001600160a01b039081166000908152600b835260408082208a835284528082209190915560035493519283015192810151606087015191516332f02e1d60e01b815294909216936332f02e1d93610bc99390929091600401614399565b600060405180830381600087803b158015610be357600080fd5b505af1158015610bf7573d6000803e3d6000fd5b50505050610d20565b8160e0015160021415610cab57610120820180516020908101516001600160a01b039081166000908152600b835260408082208a835284528082209190915560035493519283015192810151606087015191516332f02e1d60e01b815294909216936332f02e1d93610c789390929091600401614399565b600060405180830381600087803b158015610c9257600080fd5b505af1158015610ca6573d6000803e3d6000fd5b505050505b60025460408084015160608501519151632b9db5df60e11b81526001600160a01b039093169263573b6bbe92610ced9291600401918252602082015260400190565b600060405180830381600087803b158015610d0757600080fd5b505af1158015610d1b573d6000803e3d6000fd5b505050505b610d2b856004612938565b6040518581527fab15e9f4d651ec7d8276a842911d7028683655a4e1d043a54a623c2d36f3b18f9060200160405180910390a1506001949350505050565b8080610d875760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b03163314610dde5760405162461bcd60e51b815260206004820152600b60248201526a37b7363c9039b2b63632b960a91b604482015260640161028a565b81610dfb5760405162461bcd60e51b815260040161028a90613e42565b600082815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c084019190610e6d90613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054610e9990613e94565b8015610ee65780601f10610ebb57610100808354040283529160200191610ee6565b820191906000526020600020905b815481529060010190602001808311610ec957829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b85018054606090950194919392840191610f4e90613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054610f7a90613e94565b8015610fc75780601f10610f9c57610100808354040283529160200191610fc7565b820191906000526020600020905b815481529060010190602001808311610faa57829003601f168201915b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682018054610ffe90613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461102a90613e94565b80156110775780601f1061104c57610100808354040283529160200191611077565b820191906000526020600020905b81548152906001019060200180831161105a57829003601f168201915b505050505081526020016007820154815250508152505090508061010001516002146110dc5760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206f726465722073746174757360601b604482015260640161028a565b610120810151516001600160a01b03166111305760405162461bcd60e51b8152602060048201526015602482015274496e76616c6964206275796572206164647265737360581b604482015260640161028a565b6060810151336000908152600b6020908152604080832087845290915290205410156111905760405162461bcd60e51b815260206004820152600f60248201526e0c6ded2dc40dcdee840cadcdeeaced608b1b604482015260640161028a565b61119b836003612938565b336000908152600b6020908152604080832086845282528083208390556003548151635c7cee6360e01b815291516001600160a01b0390911692635c7cee6392600480820193918290030181865afa1580156111fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061121f91906143cd565b60048054604051639bd7417f60e01b815233928101929092529192506000916001600160a01b031690639bd7417f90602401600060405180830381865afa15801561126e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261129691908101906144b7565b90506000828260a001516112aa9190613fb3565b60e083015180519192509060019082906112c5908390613fb3565b905250600480546040516316a1e96960e31b815233928101929092528251602483015260208301516044830152606482018490526001600160a01b03169063b50f4b4890608401600060405180830381600087803b15801561132657600080fd5b505af115801561133a573d6000803e3d6000fd5b50506004805461012089015151604051639bd7417f60e01b81526001600160a01b039182169381019390935260009450169150639bd7417f90602401600060405180830381865afa158015611393573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526113bb91908101906144b7565b90506000858260a001516113cf9190613fb3565b60e083015180519192509060019082906113ea908390613fb3565b905250600480546101208a0151516040516316a1e96960e31b81526001600160a01b0391821693810193909352835160248401526020840151604484015260648301859052169063b50f4b4890608401600060405180830381600087803b15801561145457600080fd5b505af1158015611468573d6000803e3d6000fd5b50506003546101208b0151516040516301b7257760e41b8152600481018f90526001600160a01b03918216602482015291169250631b7257709150604401600060405180830381600087803b1580156114c057600080fd5b505af11580156114d4573d6000803e3d6000fd5b505050507f2977e4c43592a10bfbebdbacff1dd75f525cfc12644428d2f0bc595572d0e1c88a60405161150991815260200190565b60405180910390a150505050505050505050565b6000546001600160a01b031633146115475760405162461bcd60e51b815260040161028a90613efa565b600d55565b6000546001600160a01b031633146115765760405162461bcd60e51b815260040161028a90613efa565b61158060006131da565b565b6000546001600160a01b031633146115ac5760405162461bcd60e51b815260040161028a90613efa565b600380546001600160a01b03199081166001600160a01b0387811691821790935560028054831687851617905560048054831686851617905560068054831690911790556005805490911691831691909117905561160a600761322a565b50505050565b6060600a805480602002602001604051908101604052809291908181526020016000905b828210156118e157600084815260209081902060408051610140810182526011860290920180546001600160a01b031683526001810154938301939093526002830154908201526003820154606082015260048201546080820152600582015460a082015260068201805491929160c0840191906116b190613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546116dd90613e94565b801561172a5780601f106116ff5761010080835404028352916020019161172a565b820191906000526020600020905b81548152906001019060200180831161170d57829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b8501805460609095019491939284019161179290613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546117be90613e94565b801561180b5780601f106117e05761010080835404028352916020019161180b565b820191906000526020600020905b8154815290600101906020018083116117ee57829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461184290613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461186e90613e94565b80156118bb5780601f10611890576101008083540402835291602001916118bb565b820191906000526020600020905b81548152906001019060200180831161189e57829003601f168201915b505050505081526020016007820154815250508152505081526020019060010190611634565b50505050905090565b80806119085760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061194957506000818152600860205260409020600901546001600160a01b031633145b6119655760405162461bcd60e51b815260040161028a90613f2f565b6005546040516339ccd25f60e01b8152600481018490526000916001600160a01b0316906339ccd25f90602401600060405180830381865afa1580156119af573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119d791908101906146ba565b9050600d54610e106119e99190613f94565b61016082015160a001516119fd90426147a7565b11611a375760405162461bcd60e51b815260206004820152600a6024820152693a34b6b29032b93937b960b11b604482015260640161028a565b600081608001516001600160a01b031682600001516001600160a01b03161415611a8c578160e0015160021415611a7357506080810151611ab8565b8160e0015160031415611a87575060a08101515b611ab8565b8160e0015160021415611aa4575060a0810151611ab8565b8160e0015160031415611ab8575060808101515b6001600160a01b0381163314611afc5760405162461bcd60e51b815260206004820152600960248201526837b83a1032b93937b960b91b604482015260640161028a565b611b07846005612938565b60a08201516001600160a01b039081166000908152600b602090815260408083208884529091528082209190915560035490516301b7257760e41b815260048101879052336024820152911690631b72577090604401600060405180830381600087803b158015611b7757600080fd5b505af1158015611b8b573d6000803e3d6000fd5b5050505050505050565b600254604051630129ad5160e01b8152600481018790526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015611bdf573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611c079190810190614278565b80519091506001600160a01b0316331415611c345760405162461bcd60e51b815260040161028a906147be565b8060400151600114611c7d5760405162461bcd60e51b8152602060048201526012602482015271189d5e481c995cdd081b9bdd08195e1a5cdd60721b604482015260640161028a565b60008511611cc05760405162461bcd60e51b815260206004820152601060248201526f31b7b4b71031b7bab73a1032b93937b960811b604482015260640161028a565b60008311611d045760405162461bcd60e51b815260206004820152601160248201527037b93232b920b6b7bab73a1032b93937b960791b604482015260640161028a565b806101000151600114611d4d5760405162461bcd60e51b81526020600482015260116024820152703932b9ba1039ba30ba3ab99032b93937b960791b604482015260640161028a565b6000611d5d8260c0015187613253565b9050816101200151604001518110158015611d815750816101200151606001518111155b611dbc5760405162461bcd60e51b815260206004820152600c60248201526b30b6b7bab73a1032b93937b960a11b604482015260640161028a565b60048054604051639bd7417f60e01b815233928101929092526000916001600160a01b0390911690639bd7417f90602401600060405180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611e3291908101906144b7565b90508060800151600114158015611e4e57508060800151600214155b611e895760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640161028a565b826101200151608001518160a001511015611ed55760405162461bcd60e51b815260206004820152600c60248201526b31b932b234ba1032b93937b960a11b604482015260640161028a565b61012083015160a00151610100820151511015611f255760405162461bcd60e51b815260206004820152600e60248201526d36b7b93a33b0b3b29032b93937b960911b604482015260640161028a565b6000611f318888613266565b600254604051633e4a8eed60e21b8152600481018c9052602481018b90529192506001600160a01b03169063f92a3bb490604401600060405180830381600087803b158015611f7f57600080fd5b505af1158015611f93573d6000803e3d6000fd5b50505050611fac898989898960028a6000015133613272565b506003546060850151604051630bc67f9b60e01b81526000926001600160a01b031691630bc67f9b91611fe291906004016147e6565b6020604051808303816000875af1158015612001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061202591906147f9565b6006546040516323b872dd60e01b81523360048201526001600160a01b039182166024820152604481018590529192508216906323b872dd90606401600060405180830381600087803b15801561207b57600080fd5b505af115801561208f573d6000803e3d6000fd5b50506003546060880151604051634e23ea9760e01b81526001600160a01b039092169350634e23ea9792506120d3913391908e906002906001908290600401614816565b600060405180830381600087803b1580156120ed57600080fd5b505af1158015612101573d6000803e3d6000fd5b5050505050505050505050505050565b6121196139fa565b816121365760405162461bcd60e51b815260040161028a90613e42565b6000828152600860205260409020600101546121645760405162461bcd60e51b815260040161028a90613f5d565b600082815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c0840191906121d690613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461220290613e94565b801561224f5780601f106122245761010080835404028352916020019161224f565b820191906000526020600020905b81548152906001019060200180831161223257829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b850180546060909501949193928401916122b790613e94565b80601f01602080910402602001604051908101604052809291908181526020018280546122e390613e94565b80156123305780601f1061230557610100808354040283529160200191612330565b820191906000526020600020905b81548152906001019060200180831161231357829003601f168201915b5050505050815260200160038201548152602001600482015481526020016005820154815260200160068201805461236790613e94565b80601f016020809104026020016040519081016040528092919081815260200182805461239390613e94565b80156123e05780601f106123b5576101008083540402835291602001916123e0565b820191906000526020600020905b8154815290600101906020018083116123c357829003601f168201915b5050509183525050600791909101546020909101529052509392505050565b600254604051630129ad5160e01b8152600481018690526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015612449573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526124719190810190614278565b80519091506001600160a01b031633141561249e5760405162461bcd60e51b815260040161028a906147be565b80604001516002146124e85760405162461bcd60e51b81526020600482015260136024820152721cd95b1b081c995cdd081b9bdd08195e1a5cdd606a1b604482015260640161028a565b6000841180156124f85750600083115b6125375760405162461bcd60e51b815260206004820152601060248201526f31b7b4b71031b7bab73a1032b93937b960811b604482015260640161028a565b8061010001516001146125805760405162461bcd60e51b81526020600482015260116024820152703932b9ba1039ba30ba3ab99032b93937b960791b604482015260640161028a565b60048054604051639bd7417f60e01b815233928101929092526000916001600160a01b0390911690639bd7417f90602401600060405180830381865afa1580156125ce573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526125f691908101906144b7565b9050806080015160011415801561261257508060800151600214155b61264d5760405162461bcd60e51b815260206004820152600c60248201526b34b73b30b634b2103ab9b2b960a11b604482015260640161028a565b600254825160405163e9a5f96d60e01b81526001600160a01b03918216600482015260248101899052600092919091169063e9a5f96d90604401602060405180830381865afa1580156126a4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126c891906143cd565b90508581101561270c5760405162461bcd60e51b815260206004820152600f60248201526e0c6ded2dc40dcdee840cadcdeeaced608b1b604482015260640161028a565b600061271c8460c0015188613253565b90508361012001516040015181101580156127405750836101200151606001518111155b61277b5760405162461bcd60e51b815260206004820152600c60248201526b30b6b7bab73a1032b93937b960a11b604482015260640161028a565b836101200151608001518360a0015110156127c75760405162461bcd60e51b815260206004820152600c60248201526b31b932b234ba1032b93937b960a11b604482015260640161028a565b61012084015160a001516101008401515110156128175760405162461bcd60e51b815260206004820152600e60248201526d36b7b93a33b0b3b29032b93937b960911b604482015260640161028a565b600254604051633e4a8eed60e21b8152600481018a9052602481018990526001600160a01b039091169063f92a3bb490604401600060405180830381600087803b15801561286457600080fd5b505af1158015612878573d6000803e3d6000fd5b505050506128928888600089896001338b60000151613272565b505050505050505050565b6000546001600160a01b031633146128c75760405162461bcd60e51b815260040161028a90613efa565b6001600160a01b03811661292c5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b606482015260840161028a565b612935816131da565b50565b81806129565760405162461bcd60e51b815260040161028a90613e42565b6000818152600860205260409020600a01546001600160a01b031633148061299757506000818152600860205260409020600901546001600160a01b031633145b6129b35760405162461bcd60e51b815260040161028a90613f2f565b600083815260086020908152604080832081516101408101835281546001600160a01b031681526001820154938101939093526002810154918301919091526003810154606083015260048101546080830152600581015460a083015260068101805460c084019190612a2590613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612a5190613e94565b8015612a9e5780601f10612a7357610100808354040283529160200191612a9e565b820191906000526020600020905b815481529060010190602001808311612a8157829003601f168201915b5050509183525050600782015460208083019190915260088301546040808401919091528051610100810182526009850180546001600160a01b039081168352600a8701541693820193909352600b85018054606090950194919392840191612b0690613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612b3290613e94565b8015612b7f5780601f10612b5457610100808354040283529160200191612b7f565b820191906000526020600020905b815481529060010190602001808311612b6257829003601f168201915b50505050508152602001600382015481526020016004820154815260200160058201548152602001600682018054612bb690613e94565b80601f0160208091040260200160405190810160405280929190818152602001828054612be290613e94565b8015612c2f5780601f10612c0457610100808354040283529160200191612c2f565b820191906000526020600020905b815481529060010190602001808311612c1257829003601f168201915b50505050508152602001600782015481525050815250509050600081602001511415612c6d5760405162461bcd60e51b815260040161028a90613f5d565b60018310158015612c7f575060058311155b612cc25760405162461bcd60e51b8152602060048201526014602482015273496e76616c6964206f726465722073746174757360601b604482015260640161028a565b826002148015612cd85750806101000151600114155b15612d1e5760405162461bcd60e51b815260206004820152601660248201527524b73b30b634b21037b93232b91039ba30ba3ab9901960511b604482015260640161028a565b826003148015612d345750806101000151600214155b15612d7a5760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7264657220737461747573203360501b604482015260640161028a565b826004148015612d905750806101000151600114155b15612dd65760405162461bcd60e51b8152602060048201526016602482015275125b9d985b1a59081bdc99195c881cdd185d1d5cc80d60521b604482015260640161028a565b826005148015612dec5750806101000151600114155b8015612dfe5750806101000151600214155b15612e445760405162461bcd60e51b8152602060048201526016602482015275496e76616c6964206f7264657220737461747573203560501b604482015260640161028a565b8260021415612e9d57610120810151516001600160a01b03163314612e9d5760405162461bcd60e51b815260206004820152600f60248201526e1bdb9b1e48189d5e595c8818d85b1b608a1b604482015260640161028a565b8260031415612efa57610120810151602001516001600160a01b03163314612efa5760405162461bcd60e51b815260206004820152601060248201526f1bdb9b1e481cd95b1b195c8818d85b1b60821b604482015260640161028a565b61010081018390526101208101514260a091820152600085815260086020908152604091829020845181546001600160a01b0319166001600160a01b03909116178155818501516001820155918401516002830155606084015160038301556080840151600483015591830151600582015560c083015180518493612f86926006850192910190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a870180549093169416939093179055604083015180519192612ff692600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c08201518051613030916006840191602090910190613aad565b5060e091909101516007909101555050600084815260096020526040902054600a8054839290811061306457613064613e7e565b600091825260209182902083516011929092020180546001600160a01b0319166001600160a01b0390921691909117815582820151600182015560408301516002820155606083015160038201556080830151600482015560a0830151600582015560c0830151805191926130e192600685019290910190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a87018054909316941693909317905560408301518051919261315192600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c0820151805161318b916006840191602090910190613aad565b5060e09190910151600790910155505060408051858152602081018590527f5bd27be5765507f933e2cb48522d35ec14e011f43ce75c17041898e6ed37d859910160405180910390a150505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80546132365761271081555b600181600001600082825461324b9190613fb3565b909155505050565b600061325f8284613f94565b9392505050565b600061325f8284613fb3565b6000600260015414156132c75760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161028a565b60026001556132d8898988886138ff565b600254604051630129ad5160e01b8152600481018b90526000916001600160a01b031690630129ad5190602401600060405180830381865afa158015613322573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261334a9190810190614278565b80519091506001600160a01b03166133745760405162461bcd60e51b815260040161028a906147be565b6000604051806101000160405280866001600160a01b03168152602001856001600160a01b03168152602001836060015181526020018360c001518152602001428152602001600081526020016040518060200160405280600081525081526020018a815250905060006133e760075490565b600081815260086020526040902060010154909150156134375760405162461bcd60e51b815260206004820152600b60248201526a1bdc99195c88195e1a5cdd60aa1b604482015260640161028a565b6000604051806101400160405280336001600160a01b031681526020018381526020018e81526020018d81526020018b81526020018a81526020018560800151815260200189815260200160018152602001848152509050806008600084815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506020820151816001015560408201518160020155606082015181600301556080820151816004015560a0820151816005015560c082015181600601908051906020019061351e929190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a87018054909316941693909317905560408301518051919261358e92600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c082015180516135c8916006840191602090910190613aad565b5060e091909101516007909101555050600a805460018101825560009190915281517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a8601190920291820180546001600160a01b0319166001600160a01b039092169190911781556020808401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a984015560408401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2aa84015560608401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ab84015560808401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ac84015560a08401517fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ad84015560c084015180518594613737937fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2ae909101920190613aad565b5060e08201516007820155610100820151600882015561012082015180516009830180546001600160a01b03199081166001600160a01b03938416178255602080850151600a8701805490931694169390931790556040830151805191926137a792600b87019290910190613aad565b50606082015160038201556080820151600482015560a0820151600582015560c082015180516137e1916006840191602090910190613aad565b5060e091909101516007909101555050600a54613800906001906147a7565b600083815260096020526040902055600288141561383a57336000908152600b6020908152604080832085845290915290208c905561386b565b876001141561386b5783516001600160a01b03166000908152600b6020908152604080832085845290915290208c90555b613875600761322a565b60408051838152602081018f90529081018d9052606081018c9052608081018b905260a081018a905260c081018990526001600160a01b0380891660e083015287166101008201527f65c63bce967237d9b3fd7a8cd7f6a75e6f9d4196256f87fc332a42a71081e05c906101200160405180910390a150600180559b9a5050505050505050505050565b8361393a5760405162461bcd60e51b815260206004820152600b60248201526a1c995cdd139bc81b9d5b1b60aa1b604482015260640161028a565b6000831161397b5760405162461bcd60e51b815260206004820152600e60248201526d18dbda5b90dbdd5b9d081b9d5b1b60921b604482015260640161028a565b600082116139be5760405162461bcd60e51b815260206004820152601060248201526f1bdc99195c905b5bdd5b9d081b9d5b1b60821b604482015260640161028a565b8061160a5760405162461bcd60e51b815260206004820152600c60248201526b1c185e551e5c19481b9d5b1b60a21b604482015260640161028a565b60405180610140016040528060006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001606081526020016000815260200160008152602001613aa860405180610100016040528060006001600160a01b0316815260200160006001600160a01b031681526020016060815260200160008152602001600081526020016000815260200160608152602001600081525090565b905290565b828054613ab990613e94565b90600052602060002090601f016020900481019282613adb5760008555613b21565b82601f10613af457805160ff1916838001178555613b21565b82800160010185558215613b21579182015b82811115613b21578251825591602001919060010190613b06565b50613b2d929150613b31565b5090565b5b80821115613b2d5760008155600101613b32565b600060208284031215613b5857600080fd5b5035919050565b60005b83811015613b7a578181015183820152602001613b62565b8381111561160a5750506000910152565b60008151808452613ba3816020860160208601613b5f565b601f01601f19169290920160200192915050565b600061010060018060a01b03808451168552806020850151166020860152506040830151816040860152613bed82860182613b8b565b915050606083015160608501526080830151608085015260a083015160a085015260c083015184820360c0860152613c258282613b8b565b91505060e083015160e08501528091505092915050565b80516001600160a01b0316825260006101406020830151602085015260408301516040850152606083015160608501526080830151608085015260a083015160a085015260c08301518160c0860152613c9782860182613b8b565b91505060e083015160e08501526101008084015181860152506101208084015185830382870152613cc88382613bb7565b9695505050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b82811015613d2757603f19888603018452613d15858351613c3c565b94509285019290850190600101613cf9565b5092979650505050505050565b6001600160a01b038116811461293557600080fd5b60008060008060808587031215613d5f57600080fd5b8435613d6a81613d34565b93506020850135613d7a81613d34565b92506040850135613d8a81613d34565b91506060850135613d9a81613d34565b939692955090935050565b600080600080600060a08688031215613dbd57600080fd5b505083359560208501359550604085013594606081013594506080013592509050565b60208152600061325f6020830184613c3c565b60008060008060808587031215613e0957600080fd5b5050823594602084013594506040840135936060013592509050565b600060208284031215613e3757600080fd5b813561325f81613d34565b6020808252600c908201526b1bdc99195c939bc81b9d5b1b60a21b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b600181811c90821680613ea857607f821691505b6020821081141561032c57634e487b7160e01b600052602260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415613ef357613ef3613ec9565b5060010190565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b60208082526014908201527327b7363c90313abcb2b91037b91039b2b63632b960611b604082015260600190565b60208082526017908201527f63757272656e74204f72646572206e6f74206578697374000000000000000000604082015260600190565b6000816000190483118215151615613fae57613fae613ec9565b500290565b60008219821115613fc657613fc6613ec9565b500190565b60405161016081016001600160401b0381118282101715613fee57613fee613e68565b60405290565b60405161014081016001600160401b0381118282101715613fee57613fee613e68565b60405161012081016001600160401b0381118282101715613fee57613fee613e68565b60405161020081016001600160401b0381118282101715613fee57613fee613e68565b60405161018081016001600160401b0381118282101715613fee57613fee613e68565b604051601f8201601f191681016001600160401b03811182821017156140a8576140a8613e68565b604052919050565b80516140bb81613d34565b919050565b600082601f8301126140d157600080fd5b81516001600160401b038111156140ea576140ea613e68565b6140fd601f8201601f1916602001614080565b81815284602083860101111561411257600080fd5b614123826020830160208701613b5f565b949350505050565b600082601f83011261413c57600080fd5b815160206001600160401b0382111561415757614157613e68565b8160051b614166828201614080565b928352848101820192828101908785111561418057600080fd5b83870192505b8483101561419f57825182529183019190830190614186565b979650505050505050565b600061016082840312156141bd57600080fd5b6141c5613fcb565b9050815181526020820151602082015260408201516040820152606082015160608201526080820151608082015260a082015160a082015260c08201516001600160401b038082111561421757600080fd5b614223858386016140c0565b60c084015260e0848101519084015261010080850151908401526101208085015190840152610140808501519092508181111561425f57600080fd5b61426b868287016140c0565b8385015250505092915050565b60006020828403121561428a57600080fd5b81516001600160401b03808211156142a157600080fd5b9083019061014082860312156142b657600080fd5b6142be613ff4565b6142c7836140b0565b815260208301516020820152604083015160408201526060830151828111156142ef57600080fd5b6142fb878286016140c0565b60608301525060808301518281111561431357600080fd5b61431f878286016140c0565b60808301525060a083015160a082015260c083015160c082015260e08301518281111561434b57600080fd5b6143578782860161412b565b60e0830152506101008381015190820152610120808401518381111561437c57600080fd5b614388888287016141aa565b918301919091525095945050505050565b6001600160a01b03841681526060602082018190526000906143bd90830185613b8b565b9050826040830152949350505050565b6000602082840312156143df57600080fd5b5051919050565b6000604082840312156143f857600080fd5b604051604081018181106001600160401b038211171561441a5761441a613e68565b604052825181526020928301519281019290925250919050565b600060e0828403121561444657600080fd5b60405160e081018181106001600160401b038211171561446857614468613e68565b8060405250809150825181526020830151602082015260408301516040820152606083015160608201526080830151608082015260a083015160a082015260c083015160c08201525092915050565b6000602082840312156144c957600080fd5b81516001600160401b03808211156144e057600080fd5b9083019061020082860312156144f557600080fd5b6144fd614017565b614506836140b0565b815260208301518281111561451a57600080fd5b614526878286016140c0565b60208301525060408301518281111561453e57600080fd5b61454a878286016140c0565b604083015250606083015160608201526080830151608082015260a083015160a082015260c083015160c08201526145858660e085016143e6565b60e0820152614598866101208501614434565b61010082015295945050505050565b600061020082840312156145ba57600080fd5b6145c261403a565b90506145cd826140b0565b81526020820151602082015260408201516001600160401b03808211156145f357600080fd5b6145ff858386016140c0565b604084015260608401516060840152608084015191508082111561462257600080fd5b5061462f848285016140c0565b60808301525060a082015160a082015260c082015160c082015261465560e083016140b0565b60e0820152610100828101519082015261012080830151908201526101408083015190820152610160808301519082015261018080830151908201526101a080830151908201526101c080830151908201526101e09182015191810191909152919050565b6000602082840312156146cc57600080fd5b81516001600160401b03808211156146e357600080fd5b9083019061018082860312156146f857600080fd5b61470061405d565b614709836140b0565b8152602083015160208201526040830151604082015261472b606084016140b0565b606082015261473c608084016140b0565b608082015261474d60a084016140b0565b60a082015260c0838101519082015260e08084015190820152610100808401519082015261012080840151908201526101408084015190820152610160808401518381111561479b57600080fd5b614388888287016145a7565b6000828210156147b9576147b9613ec9565b500390565b6020808252600e908201526d1c995cdd081b9bdd08195e1a5cdd60921b604082015260600190565b60208152600061325f6020830184613b8b565b60006020828403121561480b57600080fd5b815161325f81613d34565b60018060a01b038716815260e06020820152600060e0820152600061010080604084015261484681840189613b8b565b9150508560608301528460808301528360a08301528260c083015297965050505050505056fea2646970667358221220a7b6bb5fcbf52c2c2bdee2099a06a514cca8d07adb5e92f6d5cc800f977a652164736f6c634300080b0033