false
false
5713000

Contract Address Details

0xeA0C753D391761bBDb090AC93102A4d1BdCbEE2b

Contract Name
TokenManagerDelegateV2
Creator
0xdb1388–e98779 at 0x1bd42a–0650af
Implementation
0x0000000000000000000000000000000000000000
Balance
0 PUNDIAI
Tokens
Fetching tokens...
Transactions
0 Transactions
Transfers
0 Transfers
Gas Used
Fetching gas used...
Last Balance Update
22424957
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
TokenManagerDelegateV2




Optimization enabled
true
Compiler version
v0.4.26+commit.4563c3fc




Optimization runs
200
Verified at
2023-04-20T02:12:54.636931Z

contracts/tokenManager/TokenManagerDelegateV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;
pragma experimental ABIEncoderV2;

import "../interfaces/IWrappedNFT721.sol";
import "../interfaces/IWrappedNFT1155.sol";
import "../interfaces/IMappingToken.sol";
import "./MappingToken.sol";
import "./TokenManagerDelegate.sol";
import "../components/Proxy.sol";

contract TokenManagerDelegateV2 is TokenManagerDelegate, Proxy {

    /************************************************************
     **
     ** STATE VARIABLES
     **
     ************************************************************/
    address public operator;

    /// tokenPairID => type; type: 0 is ERC20, 1 is ERC721, ...
    enum TokenCrossType {ERC20, ERC721, ERC1155}
    mapping(uint => uint8) public mapTokenPairType;


    /************************************************************
     **
     ** EVENTS
     **
     ************************************************************/
     event SetOperator(address indexed oldOperator, address indexed newOperator);
     event SetTokenPairType(uint indexed tokenPairId, uint indexed tokenPairType);

    /**
     *
     * MODIFIERS
     *
     */

    modifier onlyOperator() {
        require(msg.sender == operator, "not operator");
        _;
    }

    /************************************************************
     **
     ** MANIPULATIONS
     **
     ************************************************************/
    function setTokenPairTypes(uint[] tokenPairIds, uint8[] tokenPairTypes)
        external
        onlyOperator
    {
       require(tokenPairIds.length == tokenPairTypes.length, "length mismatch");
       for(uint idx = 0; idx < tokenPairIds.length; ++idx) {
          mapTokenPairType[tokenPairIds[idx]] = tokenPairTypes[idx];
          emit SetTokenPairType(tokenPairIds[idx], tokenPairTypes[idx]);
       }
    }

    function setOperator(address account)
        external
        onlyOwner
    {
       emit SetOperator(operator, account);
       operator = account;
    }

    //*****************************************************************************
    //*****************************************************************************
    // ERC1155
    //*****************************************************************************
    //*****************************************************************************
    function mintNFT(
        uint    tokenCrossType,
        address tokenAddress,
        address to,
        uint[]  tokenIDs,
        uint[]  values,
        bytes   data
    )
        public
        onlyAdmin
    {
        if(tokenCrossType == uint(TokenCrossType.ERC721)) {
            IWrappedNFT721(tokenAddress).mintBatch(to, tokenIDs, data);
        }
        else if(tokenCrossType == uint(TokenCrossType.ERC1155)) {
            IWrappedNFT1155(tokenAddress).mintBatch(to, tokenIDs, values, data);
        }
        else {
            require(false, "Invalid NFT type");
        }
    }

    function burnNFT(
        uint    tokenCrossType,
        address tokenAddress,
        address from,
        uint[]  tokenIDs,
        uint[]  values
    )
        public
        onlyAdmin
    {
        if(tokenCrossType == uint(TokenCrossType.ERC721)) {
            IWrappedNFT721(tokenAddress).burnBatch(from, tokenIDs);
        }
        else if(tokenCrossType == uint(TokenCrossType.ERC1155)) {
            IWrappedNFT1155(tokenAddress).burnBatch(from, tokenIDs, values);
        }
        else {
            require(false, "Invalid NFT type");
        }
    }
}
        

openzeppelin-eth/contracts/token/ERC721/IERC721Enumerable.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./IERC721.sol";


/**
 * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721Enumerable is Initializable, IERC721 {
  function totalSupply() public view returns (uint256);
  function tokenOfOwnerByIndex(
    address owner,
    uint256 index
  )
    public
    view
    returns (uint256 tokenId);

  function tokenByIndex(uint256 index) public view returns (uint256);
}
          

contracts/storemanGroupAdmin/IncentiveLib.sol

pragma solidity ^0.4.24;
import "./StoremanType.sol";
import "../interfaces/IPosLib.sol";
import "../interfaces/IMetric.sol";
import "../interfaces/IListGroup.sol";
import "./StoremanUtil.sol";

library IncentiveLib {
    using Deposit for Deposit.Records;
    using SafeMath for uint;
    uint public constant DIVISOR = 10000;

    event incentiveEvent(bytes32 indexed groupId, address indexed wkAddr, bool indexed finished, uint from, uint end);
    event selectedEvent(bytes32 indexed groupId, uint indexed count, address[] members);
    function getChainTypeCo(StoremanType.StoremanData storage data, uint chain1, uint chain2) public view returns(uint co){
        if(chain1 < chain2) {
            co = data.chainTypeCo[chain1][chain2];
        } else {
            co = data.chainTypeCo[chain2][chain1];
        }
        if(co == 0){
            return data.conf.chainTypeCoDefault;
        }
        return co;
    }

    function getGroupIncentive(address groupListAddr, StoremanType.StoremanGroup storage group, uint day,StoremanType.StoremanData storage data) private view returns (uint) {
        uint chainTypeCo = getChainTypeCo(data,group.chain1, group.chain2);
        uint totalDeposit = IListGroup(groupListAddr).getTotalDeposit(day);
        if(totalDeposit == 0){
            bytes32[] memory groupIds = IListGroup(groupListAddr).getActiveGroupIds(day);
            for(uint i=0; i<groupIds.length; i++){
                totalDeposit = totalDeposit.add(data.groups[groupIds[i]].deposit.getValueById(day));
            }
            require(totalDeposit != 0, "internal error");
            IListGroup(groupListAddr).setTotalDeposit(day, totalDeposit);
        }
        return IPosLib(data.posLib).getMinIncentive(group.deposit.getLastValue(),day, totalDeposit).mul(chainTypeCo).div(DIVISOR);
    }

    function calIncentive(uint groupIncentive, uint groupWeight, uint weight) private returns (uint) {
        return groupIncentive.mul(weight).div(groupWeight);
    }
    function checkMetric(IMetric metric, bytes32 groupId, uint day, uint index) private returns (bool) {
        if(index == 0) {
            return true; // leader is always OK.
        }
        uint[] memory counts = metric.getPrdInctMetric(groupId, day, day);
        uint leadCount = counts[0];
        if(leadCount < 6) {
            return true;
        }
        uint nodeCount = counts[index];
        if(nodeCount >= leadCount/2){
            return true;
        }
        return false;
    }
    function rotateSkGroup(address posLib, StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage group) public {
        if(sk.incentivedDay+1 == StoremanUtil.getDaybyTime(posLib, group.workTime+group.totalTime) && group.status == StoremanType.GroupStatus.dismissed) {
            if(sk.nextGroupId != bytes32(0x00)) {
                sk.groupId = sk.nextGroupId;
                sk.nextGroupId = bytes32(0x00);
            } else {
                // if  whitelist, set groupId = 0
                if(sk.isWhite){
                    sk.groupId = bytes32(0x00);
                }
            }
        }
    }
    function calFromEndDay(address posLib, StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage group) private returns(uint,uint) {
        uint fromDay = StoremanUtil.getDaybyTime(posLib, group.workTime);
        if (fromDay <= sk.incentivedDay){
            fromDay = sk.incentivedDay + 1;
        }
        uint endDay = now;
        if (endDay > group.workTime + group.totalTime) {
            endDay = group.workTime + group.totalTime;
        }
        endDay = StoremanUtil.getDaybyTime(posLib, endDay);
        return (fromDay, endDay);
    }

    function checkPartQuited(address listGroupAddr, StoremanType.Candidate storage sk, address pnAddr) private view returns(bool){
        bytes32 QuitGroupId;
        bytes32 QuitNextGroupId;
        (QuitGroupId,QuitNextGroupId) = IListGroup(listGroupAddr).getPartQuitGroupId(sk.wkAddr, pnAddr);
        StoremanType.Delegator storage pn = sk.partners[pnAddr];
        if(pn.quited && QuitGroupId != sk.groupId && QuitNextGroupId != sk.groupId){
            return true;
        }
        return false;
    }
    function checkDelegateQuited(address listGroupAddr, StoremanType.Candidate storage sk, address deAddr) private view returns(bool){
        bytes32 QuitGroupId;
        bytes32 QuitNextGroupId;
        (QuitGroupId,QuitNextGroupId) = IListGroup(listGroupAddr).getDelegateQuitGroupId(sk.wkAddr, deAddr);
        StoremanType.Delegator storage de = sk.delegators[deAddr];
        if(de.quited && QuitGroupId != sk.groupId && QuitNextGroupId != sk.groupId){
            return true;
        }
        return false;
    }
    function incentiveNode(uint day, StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage group,StoremanType.StoremanData storage data, address listGroupAddr) public {
        sk.incentive[day] = calIncentive(group.groupIncentive[day], group.depositWeight.getValueById(day), StoremanUtil.calSkWeight(data.conf.standaloneWeight,sk.deposit.getValueById(day)));
        sk.incentive[0] =  sk.incentive[0].add(sk.incentive[day]);
        data.totalReward = data.totalReward.add(sk.incentive[day]);
        for(uint m=0; m<sk.partnerCount; m++){
            if(checkPartQuited(listGroupAddr, sk, sk.partMap[m])){
                continue;
            }
            
            uint partnerWeight = StoremanUtil.calSkWeight(data.conf.standaloneWeight, sk.partners[sk.partMap[m]].deposit.getValueById(day));
            uint partnerReward = calIncentive(group.groupIncentive[day], group.depositWeight.getValueById(day), partnerWeight);
            sk.incentive[day] = sk.incentive[day].add(partnerReward);
            sk.incentive[0] = sk.incentive[0].add(partnerReward);
            data.totalReward = data.totalReward.add(partnerReward);
        }
    }
    function incentiveDelegator(uint day, StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage group,StoremanType.StoremanData storage data, address listGroupAddr) public {
        address deAddr = sk.delegatorMap[sk.incentivedDelegator];
        if(checkDelegateQuited(listGroupAddr, sk, deAddr)){
            sk.incentivedDelegator++;
            return;            
        }

        uint incs = calIncentive(group.groupIncentive[day], group.depositWeight.getValueById(day), sk.delegators[deAddr].deposit.getValueById(day));
        uint incSk = incs.mul(group.delegateFee).div(DIVISOR);
        uint incDe = incs.sub(incSk);
        sk.delegators[deAddr].incentive[day] = sk.delegators[deAddr].incentive[day].add(incDe);
        sk.delegators[deAddr].incentive[0] = sk.delegators[deAddr].incentive[0].add(incDe);
        sk.incentive[day] = sk.incentive[day].add(incSk);
        sk.incentive[0] = sk.incentive[0].add(incSk);
        data.totalReward = data.totalReward.add(incs);
        sk.incentivedDelegator++;
    }

    /*
    @dev The logic of incentive
    1) get the incentive by day and groupID.
    If the incentive array by day haven't got from low level, the tx will try to get it.
    so the one who first incentive will spend more gas.
    2) calculate the sk incentive every days.
    3) calculate the delegator every days one by one.
     */    
    function incentiveCandidator(StoremanType.StoremanData storage data, address wkAddr,  address metricAddr, address listGroupAddr) public {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.StoremanGroup storage group = data.groups[sk.groupId];
        require(group.status >= StoremanType.GroupStatus.ready, "not ready");
        uint fromDay; uint endDay;
        uint reservedGas = 2500000;
        (fromDay, endDay) = calFromEndDay(data.posLib, sk, group);

        uint day;
        uint idx = 0;
        for (; idx < group.selectedCount; idx++) {
            address addr = group.selectedNode[idx];
            if (addr == sk.wkAddr) {
                break;
            }
        }
        require(idx < group.selectedCount, "not selected");

        for (day = fromDay; day < endDay; day++) {
            if (msg.gas < reservedGas ) { // check the gas. because calculate delegator incentive need more gas left.
                emit incentiveEvent(sk.groupId, wkAddr, false, fromDay, day);
                return;
            }
            if (group.groupIncentive[day] == 0) {
                group.groupIncentive[day] = getGroupIncentive(listGroupAddr, group, day, data);
            }

            if(checkMetric(IMetric(metricAddr), sk.groupId, day, idx)){
                if(0 == sk.incentive[day]) {
                    incentiveNode(day, sk,group,data, listGroupAddr);
                }
                while (sk.incentivedDelegator < sk.delegatorCount) {
                    if (msg.gas < reservedGas ) {
                        emit incentiveEvent(sk.groupId, wkAddr, false, fromDay, 0);
                        return;
                    }
                    incentiveDelegator(day, sk,group,data,listGroupAddr);
                }
            }
            sk.incentivedDay = day;
            rotateSkGroup(data.posLib, sk, group);
            sk.incentivedDelegator = 0;
        }
        emit incentiveEvent(sk.groupId, wkAddr, true, fromDay, endDay-1);
    }

    function setGroupDeposit(StoremanType.StoremanData storage data,StoremanType.StoremanGroup storage group) public {
        uint day = StoremanUtil.getDaybyTime(data.posLib, group.workTime);
        uint groupDeposit = 0;
        uint groupDepositWeight = 0;
        for(uint i = 0; i<group.memberCountDesign; i++){
            StoremanType.Candidate storage sk = data.candidates[0][group.selectedNode[i]];
            groupDeposit = groupDeposit.add(sk.deposit.getLastValue().add(sk.partnerDeposit).add(sk.delegateDeposit));
            groupDepositWeight = groupDepositWeight.add(StoremanUtil.calSkWeight(data.conf.standaloneWeight,sk.deposit.getLastValue().add(sk.partnerDeposit)).add(sk.delegateDeposit));
        }
        Deposit.Record memory deposit = Deposit.Record(day, groupDeposit);
        Deposit.Record memory depositWeight = Deposit.Record(day, groupDepositWeight);
        group.deposit.clean();
        group.depositWeight.clean();
        group.deposit.addRecord(deposit);
        group.depositWeight.addRecord(depositWeight);
        return;        
    }
    function cleanSmNode(StoremanType.Candidate storage skt, bytes32 groupId){
        if(skt.isWhite){
            if(skt.groupId == groupId){
                skt.groupId = bytes32(0x00);
            }else if(skt.nextGroupId == groupId){
                skt.nextGroupId = bytes32(0x00);
            }
        }        
    }

    function toSelect(StoremanType.StoremanData storage data,bytes32 groupId) public {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(group.status == StoremanType.GroupStatus.curveSeted,"Wrong status");
        require(now > group.registerTime + group.registerDuration, "Wrong time");
        if(group.memberCount < group.memberCountDesign){
            group.status = StoremanType.GroupStatus.failed;
            for(uint k=0; k<group.whiteCountAll; k++){
                StoremanType.Candidate storage skt = data.candidates[0][group.whiteMap[k]];
                cleanSmNode(skt, groupId);
            }
            return;
        }
        address[] memory members = new address[](group.memberCountDesign);
        for(uint i = 0; i<group.memberCountDesign; i++){
            members[i] = group.selectedNode[i];
        }

        emit selectedEvent(groupId, group.memberCountDesign, members);
        group.status = StoremanType.GroupStatus.selected;
        setGroupDeposit(data,group);
        return;
    }
}
          

contracts/interfaces/ITokenManager.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface ITokenManager {
    function getTokenPairInfo(uint id) external view
      returns (uint origChainID, bytes tokenOrigAccount, uint shadowChainID, bytes tokenShadowAccount);

    function getTokenPairInfoSlim(uint id) external view
      returns (uint origChainID, bytes tokenOrigAccount, uint shadowChainID);

    function getAncestorInfo(uint id) external view
      returns (bytes account, string name, string symbol, uint8 decimals, uint chainId);

    function mintToken(address tokenAddress, address to, uint value) external;

    function burnToken(address tokenAddress, address from, uint value) external;

    function mapTokenPairType(uint tokenPairID) external view
      returns (uint8 tokenPairType);

    // erc1155
    function mintNFT(uint tokenCrossType, address tokenAddress, address to, uint[] ids, uint[] values, bytes data) public;
    function burnNFT(uint tokenCrossType, address tokenAddress, address from, uint[] ids, uint[] values) public;
}
          

contracts/gpk/GpkProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

import "../components/Admin.sol";
import "./GpkStorage.sol";
import "../components/Proxy.sol";

contract GpkProxy is GpkStorage, Admin, Proxy {
    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for setting or upgrading GpkDelegate address by owner
    /// @param impl                       GpkDelegate contract address
    function upgradeTo(address impl) external onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/crossApproach/lib/HTLCDebtLib.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

// import "./HTLCTxLib.sol";
import "./CrossTypes.sol";

library HTLCDebtLib {
    // using SafeMath for uint;
    // using HTLCTxLib for HTLCTxLib.Data;

    /**
     *
     * STRUCTURES
     *
     */

    /// @notice struct of debt and asset parameters
    struct DebtAssetParams {
        bytes32 uniqueID;               /// hash of HTLC random number
        bytes32 srcSmgID;               /// ID of source storeman group
        bytes32 destSmgID;              /// ID of destination storeman group
    }

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                     event of storeman asset transfer
    /// @param uniqueID                random number
    /// @param srcSmgID             ID of source storeman group
    /// @param destSmgID            ID of destination storeman group
    event TransferAssetLogger(bytes32 indexed uniqueID, bytes32 indexed srcSmgID, bytes32 indexed destSmgID);

    /// @notice                     event of storeman debt receive
    /// @param uniqueID                random number
    /// @param srcSmgID             ID of source storeman group
    /// @param destSmgID            ID of destination storeman group
    event ReceiveDebtLogger(bytes32 indexed uniqueID, bytes32 indexed srcSmgID, bytes32 indexed destSmgID);

    /**
     *
     * MANIPULATIONS
     *
     */

    /// @notice                     transfer asset
    /// @param  storageData         Cross storage data
    /// @param  params              parameters of storeman debt lock
    function transferAsset(CrossTypes.Data storage storageData, DebtAssetParams memory params)
        public
    {
        if (address(storageData.quota) != address(0)) {
            storageData.quota.transferAsset(params.srcSmgID, params.destSmgID);
        }
        emit TransferAssetLogger(params.uniqueID, params.srcSmgID, params.destSmgID);
    }

    /// @notice                     receive debt
    /// @param  storageData         Cross storage data
    /// @param  params              parameters of storeman debt lock
    function receiveDebt(CrossTypes.Data storage storageData, DebtAssetParams memory params)
        public
    {
        if (address(storageData.quota) != address(0)) {
            storageData.quota.receiveDebt(params.srcSmgID, params.destSmgID);
        }
        emit ReceiveDebtLogger(params.uniqueID, params.srcSmgID, params.destSmgID);
    }
}
          

contracts/lib/PosLib.sol

pragma solidity ^0.4.24;
import 'openzeppelin-eth/contracts/math/SafeMath.sol';


library PosLib {

    using SafeMath for uint;
    uint public constant DIVISOR = 10000;
    address constant PRECOMPILE_CONTRACT_ADDR = 0x268;


    function getEpochId(uint256 blockTime) public view returns (uint256) {
        bytes32 functionSelector = keccak256("getEpochId(uint256)");

        (uint256 result, bool success) = callWith32BytesReturnsUint256(
            0x262,
            functionSelector,
            bytes32(blockTime)
        );

        require(success, "ASSEMBLY_CALL getEpochId failed");

        return result;
    }

    function callWith32BytesReturnsUint256(
        address to,
        bytes32 functionSelector,
        bytes32 param1
    ) private view returns (uint256 result, bool success) {
        assembly {
            let freePtr := mload(0x40)

            mstore(freePtr, functionSelector)
            mstore(add(freePtr, 4), param1)

            // call ERC20 Token contract transfer function
            success := staticcall(gas, to, freePtr, 36, freePtr, 32)

            result := mload(freePtr)
        }
    }


    function getPosAvgReturn(uint256 targetSecond)  public view returns(uint256 result,bool success) {
      // bytes32 functionSelector = keccak256("getPosAvgReturn(uint256)");
       bytes32 functionSelector = 0x94fee72400000000000000000000000000000000000000000000000000000000;
       address to = PRECOMPILE_CONTRACT_ADDR;

       assembly {
            let freePtr := mload(0x40)
            mstore(freePtr, functionSelector)
            mstore(add(freePtr, 4), targetSecond)

            // call ERC20 Token contract transfer function
            success := staticcall(gas, to, freePtr,36, freePtr, 32)
            result := mload(freePtr)
        }
    }


    function testGetHardCap ()  public view returns(uint256,bool) {
        return getHardCap(now - 3600 * 24);
    }


    function getHardCap (uint256 time) public view returns(uint256,bool) {
       bytes32 functionSelector = 0x8b19e7b700000000000000000000000000000000000000000000000000000000;
       address to = PRECOMPILE_CONTRACT_ADDR;
       uint256 posReturn=0;
       bool    success;
       assembly {
            let freePtr := mload(0x40)
            mstore(freePtr, functionSelector)
            mstore(add(freePtr, 4), time)
            success := staticcall(gas, to, freePtr,36, freePtr, 32)
            posReturn := mload(freePtr)
        }

        return (posReturn,success);

    }


    //  function getMinIncentive1 ()  public view returns(uint256,uint256) {
    //      return (getMinIncentive(100000 ether,now - 86400 * 4),0);
    //  }


    //  function getMinIncentive2 ()  public view returns(uint256,uint256) {
    //      return (getMinIncentive(10000000 ether,now - 86400 * 4),0);
    //  }

    function getMinIncentive (uint256 smgDeposit,uint256 day, uint256 totalDeposit) public view returns(uint256) {
        uint256 p1;
        bool    success;
        uint targetSecond = day.mul(3600*24);
        (p1,success) = getPosAvgReturn(targetSecond);
        if(!success) {
            return 0;
        }
        uint256 p1Return = smgDeposit.mul(p1).div(DIVISOR).div(365);

        uint256 hardcap;
        (hardcap,success) = getHardCap(targetSecond);
        if(!success) {
            return 0;
        }

        uint256 hardcapReturn = hardcap.mul(1 ether).div(DIVISOR).mul(smgDeposit).div(totalDeposit);

        return hardcapReturn<=p1Return?hardcapReturn:p1Return;
    }


}
          

contracts/crossApproach/CrossStorage.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "../components/BasicStorage.sol";
import "./lib/CrossTypes.sol";
import "./lib/HTLCTxLib.sol";
import "./lib/RapidityTxLib.sol";

contract CrossStorage is BasicStorage {
    using HTLCTxLib for HTLCTxLib.Data;
    using RapidityTxLib for RapidityTxLib.Data;

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    CrossTypes.Data internal storageData;

    /// @notice locked time(in seconds)
    uint public lockedTime = uint(3600*36);

    /// @notice Since storeman group admin receiver address may be changed, system should make sure the new address
    /// @notice can be used, and the old address can not be used. The solution is add timestamp.
    /// @notice unit: second
    uint public smgFeeReceiverTimeout = uint(10*60);

    enum GroupStatus { none, initial, curveSeted, failed, selected, ready, unregistered, dismissed }

}
          

openzeppelin-eth/contracts/utils/Address.sol

pragma solidity ^0.4.24;


/**
 * Utility library of inline functions on addresses
 */
library Address {

  /**
   * Returns whether the target address is a contract
   * @dev This function will return false if invoked during the constructor of a contract,
   * as the code is not actually created until after the constructor finishes.
   * @param account address of the account to check
   * @return whether the target address is a contract
   */
  function isContract(address account) internal view returns (bool) {
    uint256 size;
    // XXX Currently there is no better way to check if there is a contract in an address
    // than to check the size of the code at that address.
    // See https://ethereum.stackexchange.com/a/14016/36603
    // for more details about how this works.
    // TODO Check this again before the Serenity release, because all addresses will be
    // contracts then.
    // solium-disable-next-line security/no-inline-assembly
    assembly { size := extcodesize(account) }
    return size > 0;
  }
}
          

contracts/crossApproach/lib/NFTLibV1.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "../../interfaces/IERC1155.sol";
import 'openzeppelin-eth/contracts/token/ERC721/IERC721.sol';
import "./RapidityTxLib.sol";
import "./CrossTypesV1.sol";
import "../../interfaces/ITokenManager.sol";

library NFTLibV1 {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    enum TokenCrossType {ERC20, ERC721, ERC1155}

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapidityUserLockNFTParams {
        bytes32                 smgID;                  /// ID of storeman group which user has selected
        uint                    tokenPairID;            /// token pair id on cross chain
        uint[]                  tokenIDs;               /// NFT token Ids
        uint[]                  tokenValues;            /// NFT token values
        uint                    currentChainID;         /// current chain ID
        uint                    tokenPairContractFee;   /// fee of token pair
        bytes                   destUserAccount;        /// account of shadow chain, used to receive token
        address                 smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapiditySmgMintNFTParams {
        bytes32                 uniqueID;               /// Rapidity random number
        bytes32                 smgID;                  /// ID of storeman group which user has selected
        uint                    tokenPairID;            /// token pair id on cross chain
        uint[]                  tokenIDs;               /// NFT token Ids
        uint[]                  tokenValues;            /// NFT token values
        bytes                   extData;                /// storeman data
        address                 destTokenAccount;       /// shadow token account
        address                 destUserAccount;        /// account of shadow chain, used to receive token
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapidityUserBurnNFTParams {
        bytes32                 smgID;                  /// ID of storeman group which user has selected
        uint                    tokenPairID;            /// token pair id on cross chain
        uint[]                  tokenIDs;               /// NFT token Ids
        uint[]                  tokenValues;            /// NFT token values
        uint                    currentChainID;         /// current chain ID
        uint                    tokenPairContractFee;   /// fee of token pair
        address                 srcTokenAccount;        /// shadow token account
        bytes                   destUserAccount;        /// account of token destination chain, used to receive token
        address                 smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapiditySmgReleaseNFTParams {
        bytes32                 uniqueID;               /// Rapidity random number
        bytes32                 smgID;                  /// ID of storeman group which user has selected
        uint                    tokenPairID;            /// token pair id on cross chain
        uint[]                  tokenIDs;               /// NFT token Ids
        uint[]                  tokenValues;            /// NFT token values
        address                 destTokenAccount;       /// original token/coin account
        address                 destUserAccount;        /// account of token original chain, used to receive token
    }

    event UserLockNFT(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, string[] keys, bytes[] values);

    event UserBurnNFT(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, string[] keys, bytes[] values);

    event SmgMintNFT(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    event SmgReleaseNFT(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    function getTokenScAddrAndContractFee(CrossTypesV1.Data storage storageData, uint tokenPairID, uint tokenPairContractFee, uint currentChainID, uint batchLength)
        public
        view
        returns (address, uint)
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint contractFee = tokenPairContractFee;
        address tokenScAddr;
        if (currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);
        } else if (currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(toTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        if (contractFee > 0) {
            contractFee = contractFee.mul(9 + batchLength).div(10);
        }
        return (tokenScAddr, contractFee);
    }

    /// @notice                         mintBridge, user lock token on token original chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user mint lock token on token original chain
    function userLockNFT(CrossTypesV1.Data storage storageData, RapidityUserLockNFTParams memory params)
        public
    {
        address tokenScAddr;
        uint contractFee;
        (tokenScAddr, contractFee) = getTokenScAddrAndContractFee(storageData, params.tokenPairID, params.tokenPairContractFee, params.currentChainID, params.tokenIDs.length);

        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        uint left = (msg.value).sub(contractFee);

        uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
        if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
            for(uint idx = 0; idx < params.tokenIDs.length; ++idx) {
                IERC721(tokenScAddr).safeTransferFrom(msg.sender, address(this), params.tokenIDs[idx], "");
            }
        } else if(tokenCrossType == uint8(TokenCrossType.ERC1155)) {
            IERC1155(tokenScAddr).safeBatchTransferFrom(msg.sender, address(this), params.tokenIDs, params.tokenValues, "");
        }
        else{
            require(false, "Invalid NFT type");
        }

        if (left != 0) {
            (msg.sender).transfer(left);
        }

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);

        keys[0] = "tokenIDs:uint256[]";
        values[0] = abi.encode(params.tokenIDs);

        keys[1] = "tokenValues:uint256[]";
        values[1] = abi.encode(params.tokenValues);

        keys[2] = "userAccount:bytes";
        values[2] = params.destUserAccount;

        keys[3] = "contractFee:uint256";
        values[3] = abi.encodePacked(contractFee);

        emit UserLockNFT(params.smgID, params.tokenPairID, tokenScAddr, keys, values);
    }

    /// @notice                         burnBridge, user lock token on token original chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user burn lock token on token original chain
    function userBurnNFT(CrossTypesV1.Data storage storageData, RapidityUserBurnNFTParams memory params)
        public
    {
        address tokenScAddr;
        uint contractFee;
        (tokenScAddr, contractFee) = getTokenScAddrAndContractFee(storageData, params.tokenPairID, params.tokenPairContractFee, params.currentChainID, params.tokenIDs.length);

        ITokenManager tokenManager = storageData.tokenManager;
        uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
        require((tokenCrossType == uint8(TokenCrossType.ERC721) || tokenCrossType == uint8(TokenCrossType.ERC1155)), "Invalid NFT type");
        ITokenManager(tokenManager).burnNFT(uint(tokenCrossType), tokenScAddr, msg.sender, params.tokenIDs, params.tokenValues);

        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        uint left = (msg.value).sub(contractFee);
        if (left != 0) {
            (msg.sender).transfer(left);
        }

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);

        keys[0] = "tokenIDs:uint256[]";
        values[0] = abi.encode(params.tokenIDs);

        keys[1] = "tokenValues:uint256[]";
        values[1] = abi.encode(params.tokenValues);

        keys[2] = "userAccount:bytes";
        values[2] = params.destUserAccount;

        keys[3] = "contractFee:uint256";
        values[3] = abi.encodePacked(contractFee);
        emit UserBurnNFT(params.smgID, params.tokenPairID, tokenScAddr, keys, values);
    }

    /// @notice                         mintBridge, storeman mint lock token on token shadow chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman mint lock token on token shadow chain
    function smgMintNFT(CrossTypesV1.Data storage storageData, RapiditySmgMintNFTParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        ITokenManager tokenManager = storageData.tokenManager;
        uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
        require((tokenCrossType == uint8(TokenCrossType.ERC721) || tokenCrossType == uint8(TokenCrossType.ERC1155)), "Invalid NFT type");
        ITokenManager(tokenManager).mintNFT(uint(tokenCrossType), params.destTokenAccount, params.destUserAccount, params.tokenIDs, params.tokenValues, params.extData);

        string[] memory keys = new string[](5);
        bytes[] memory values = new bytes[](5);

        keys[0] = "tokenIDs:uint256[]";
        values[0] = abi.encode(params.tokenIDs);

        keys[1] = "tokenValues:uint256[]";
        values[1] = abi.encode(params.tokenValues);

        keys[2] = "tokenAccount:address";
        values[2] = abi.encodePacked(params.destTokenAccount);

        keys[3] = "userAccount:address";
        values[3] = abi.encodePacked(params.destUserAccount);

        keys[4] = "extData:bytes";
        values[4] = params.extData;

        emit SmgMintNFT(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
    }

    /// @notice                         burnBridge, storeman burn lock token on token shadow chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman burn lock token on token shadow chain
    function smgReleaseNFT(CrossTypesV1.Data storage storageData, RapiditySmgReleaseNFTParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
        if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
            for(uint idx = 0; idx < params.tokenIDs.length; ++idx) {
                IERC721(params.destTokenAccount).safeTransferFrom(address(this), params.destUserAccount, params.tokenIDs[idx], "");
            }
        }
        else if(tokenCrossType == uint8(TokenCrossType.ERC1155)) {
            IERC1155(params.destTokenAccount).safeBatchTransferFrom(address(this), params.destUserAccount, params.tokenIDs, params.tokenValues, "");
        }
        else {
            require(false, "Invalid NFT type");
        }

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);

        keys[0] = "tokenIDs:uint256[]";
        values[0] = abi.encode(params.tokenIDs);

        keys[1] = "tokenValues:uint256[]";
        values[1] = abi.encode(params.tokenValues);

        keys[2] = "tokenAccount:address";
        values[2] = abi.encodePacked(params.destTokenAccount);

        keys[3] = "userAccount:address";
        values[3] = abi.encodePacked(params.destUserAccount);

        emit SmgReleaseNFT(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
    }
}
          

contracts/schnorr/SignatureVerifier.sol

pragma solidity ^0.4.24;

import "../components/Halt.sol";
import "../interfaces/ISignatureVerifier.sol";

/// @dev for multi curves contract call.
interface IBaseSignVerifier {
    function verify(
        bytes32 signature,
        bytes32 groupKeyX,
        bytes32 groupKeyY,
        bytes32 randomPointX,
        bytes32 randomPointY,
        bytes32 message
    ) external returns (bool);
}

contract SignatureVerifier is Halt {

    /// @dev a map from a uint256 curveId to it's verifier contract address.
    mapping(uint256 => address) public verifierMap;

    /// @dev verify is used for check signature.
    function verify(
        uint256 curveId,
        bytes32 signature,
        bytes32 groupKeyX,
        bytes32 groupKeyY,
        bytes32 randomPointX,
        bytes32 randomPointY,
        bytes32 message
    ) external returns (bool) {
        require(verifierMap[curveId] != address(0), "curveId not correct");
        IBaseSignVerifier verifier = IBaseSignVerifier(verifierMap[curveId]);
        return verifier.verify(signature, groupKeyX, groupKeyY, randomPointX, randomPointY, message);
    }

    function register(uint256 curveId, address verifierAddress) external onlyOwner {
        verifierMap[curveId] = verifierAddress;
    }
}
          

contracts/metric/lib/MetricLib.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "./MetricTypes.sol";
import "../../lib/CommonTool.sol";
import "../../interfaces/IPosLib.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../interfaces/ICurve.sol";

library MetricLib {
    using SafeMath for uint;

    /// @notice                         function for write slash of R stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param rslshData                slash data of R stage
    /// @param smCount                  total number of store man
    function writeRSlsh(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, MetricTypes.RSlshData memory rslshData, uint8 smCount)
    internal
    returns (bool, uint8)
    {
        require(metricData.mapRSlsh[grpId][hashX][rslshData.sndrIndex].polyDataPln.polyData.length == 0,"Duplicate RSlsh");

        require(rslshData.sndrIndex <= smCount, "invalid send index");
        require(rslshData.rcvrIndex <= smCount, "invalid receiver index");

        require(rslshData.polyCMData.polyCM.length != 0, "polyCM is empty");
        require(rslshData.polyDataPln.polyData.length != 0, "polyData is empty");

        require(rslshData.becauseSndr, "R because sender is not true");

        uint8 smIndex;
        //smIndex = rslshData.becauseSndr ? rslshData.sndrIndex : rslshData.rcvrIndex;

        smIndex = rslshData.sndrIndex;

        metricData.mapRSlsh[grpId][hashX][smIndex] = rslshData;


        if (checkRProof(metricData, grpId, hashX, smIndex)) {
            metricData.mapSlshCount[grpId][getEpochId(metricData)][smIndex] = metricData.mapSlshCount[grpId][getEpochId(metricData)][smIndex].add(uint(1));
            return (true, smIndex);
        } else {
            delete metricData.mapRSlsh[grpId][hashX][smIndex];
            return (false, smIndex);
        }

    }


    /// @notice                         check proof of R stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkRProof(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        bool bSig = checkRSig(metricData, grpId, hashX, smIndex);
        bool bContent = checkRContent(metricData, grpId, hashX, smIndex);
        return getChkResult(bSig, bContent);
    }
    /// @notice                         check signature of proof in R stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkRSig(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        bytes32 h;
        bytes memory senderPk;

        MetricTypes.RSlshData rslshData = metricData.mapRSlsh[grpId][hashX][smIndex];
        // build h
        h = sha256(rslshData.polyDataPln.polyData);
        // build senderpk
        senderPk = getPkBytesByInx(metricData, grpId, rslshData.sndrIndex);
        return ckSig(metricData,h, rslshData.polyDataPln.polyDataR, rslshData.polyDataPln.polyDataS, senderPk);
    }
    /// @notice                         check content of proof in R stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkRContent(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        uint256 xLeft;
        uint256 yLeft;

        uint256 xRight;
        uint256 yRight;
        bool success;

        bytes memory sij;
        bytes memory rcvrPk;
        MetricTypes.RSlshData memory rslshData = metricData.mapRSlsh[grpId][hashX][smIndex];
        sij = rslshData.polyDataPln.polyData;
        rcvrPk = getPkBytesByInx(metricData, grpId, rslshData.rcvrIndex);

        // left point compute by CMG  polyCM:= 64*n
        address curveAddr;
        curveAddr = IConfig(metricData.config).getCurve(uint8(rslshData.curveType));
        (xLeft, yLeft, success) = ICurve(curveAddr).calPolyCommit(rslshData.polyCMData.polyCM, rcvrPk);
        require(success, 'calPolyCommit fail');

        // right point s[i][i]*G
        uint256 uintSij = CommonTool.bytes2uint(sij, 0, uint16(sij.length));
        (xRight, yRight, success) = ICurve(curveAddr).mulG(uintSij);

        require(success, 'mulG fail');
        return ICurve(curveAddr).equalPt(xLeft,yLeft,xRight,yRight);
    }

    function getChkResult(bool bSig, bool bContent)
    internal
    pure
    returns (bool)
    {
        return !bSig || !bContent;
    }
    /// @notice                         function for write slash of S stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param sslshData                slash data of S stage
    /// @param smCount                  total number of store man
    function writeSSlsh(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, MetricTypes.SSlshData sslshData, uint8 smCount)
    public
    returns (bool, uint8)
    {
        require(metricData.mapSSlsh[grpId][hashX][sslshData.sndrIndex].polyDataPln.polyData.length == 0,"Duplicate SSlsh");

        require(sslshData.sndrIndex <= smCount, "invalid send index");
        require(sslshData.rcvrIndex <= smCount, "invalid receiver index");

        require(sslshData.m.length != 0, "m is empty");
        require(sslshData.rpkShare.length != 0, "rpkShare is empty");
        require(sslshData.gpkShare.length != 0, "gpkShare is empty");
        require(sslshData.polyDataPln.polyData.length != 0, "polyData is empty");

        require(sslshData.becauseSndr, "S because sender is not true");

        uint8 smIndex;
        //smIndex = sslshData.becauseSndr ? sslshData.sndrIndex : sslshData.rcvrIndex;
        smIndex =  sslshData.sndrIndex;
        metricData.mapSSlsh[grpId][hashX][smIndex] = sslshData;

        if (checkSProof(metricData, grpId, hashX, smIndex)) {
            metricData.mapSlshCount[grpId][getEpochId(metricData)][smIndex] = metricData.mapSlshCount[grpId][getEpochId(metricData)][smIndex].add(uint(1));
            return (true, smIndex);
        } else {
            delete metricData.mapSSlsh[grpId][hashX][smIndex];

            return (false, smIndex);
        }
    }

    /// @notice                         check proof of S stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkSProof(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        bool bSig = checkSSig(metricData, grpId, hashX, smIndex);
        bool bContent = checkSContent(metricData, grpId, hashX, smIndex);
        return getChkResult(bSig, bContent);
    }
    /// @notice                         check signature of proof in S stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkSSig(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        bytes32 h;
        bytes memory senderPk;

        MetricTypes.SSlshData sslshData = metricData.mapSSlsh[grpId][hashX][smIndex];
        // build h
        h = sha256(sslshData.polyDataPln.polyData);
        // build senderpk
        senderPk = getPkBytesByInx(metricData, grpId, sslshData.sndrIndex);

        return ckSig(metricData, h, sslshData.polyDataPln.polyDataR, sslshData.polyDataPln.polyDataS, senderPk);
    }

    function ckSig(MetricTypes.MetricStorageData storage metricData, bytes32 hash, bytes32 r, bytes32 s, bytes pk)
    internal
    returns (bool){
        address curveAddr;
        curveAddr = IConfig(metricData.config).getCurve(uint8(CommonTool.CurveType.SK));
        return ICurve(curveAddr).checkSig(hash, r, s, pk);
    }

    /// @notice                         check content of proof in S stage
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function checkSContent(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, bytes32 hashX, uint8 smIndex)
    internal
    returns (bool)
    {
        bool success;
        uint xLeft;
        uint yLeft;

        uint xRight;
        uint yRight;

        uint mgpkX;
        uint mgpkY;

        MetricTypes.SSlshData memory sslshData = metricData.mapSSlsh[grpId][hashX][smIndex];
        // s*G
        address curveAddr;
        curveAddr = IConfig(metricData.config).getCurve(uint8(sslshData.curveType));

        uint16 ployDataLen = uint16(sslshData.polyDataPln.polyData.length);
        (xRight, yRight, success) = ICurve(curveAddr).mulG(CommonTool.bytes2uint(sslshData.polyDataPln.polyData, 0,ployDataLen));
        require(success, 'mulG fail');

        // rpkShare + m * gpkShare
        (mgpkX, mgpkY, success) = ICurve(curveAddr).mulPk(CommonTool.bytes2uint(sslshData.m, 0, uint16(sslshData.m.length)),
            CommonTool.bytes2uint(sslshData.gpkShare, 0, 32),
            CommonTool.bytes2uint(sslshData.gpkShare, 32, 32));
        require(success, 'mulPk fail');

        (xLeft, yLeft, success) = ICurve(curveAddr).add(CommonTool.bytes2uint(sslshData.rpkShare, 0, 32),
            CommonTool.bytes2uint(sslshData.rpkShare, 32, 32),
            mgpkX,
            mgpkY);
        require(success, 'add fail');
        return ICurve(curveAddr).equalPt(xLeft,yLeft,yLeft,yRight);
    }
    /// @notice                         get public key bytes by stor eman index
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param smIndex                  index of store man
    function getPkBytesByInx(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, uint8 smIndex)
    internal
    view
    returns (bytes)
    {
        bytes memory smPk;
        (, smPk,) = (IStoremanGroup)(metricData.smg).getSelectedSmInfo(grpId, uint(smIndex));
        return smPk;
    }
    /// @notice                         get epoch id by now time stamp
    /// @param metricData               self parameter for lib function
    function getEpochId(MetricTypes.MetricStorageData storage metricData)
    internal
    view
    returns (uint)
    {
        return IPosLib(metricData.posLib).getEpochId(now);
    }
    /// @notice                         get total number of store man in special group
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    function getSMCount(MetricTypes.MetricStorageData storage metricData, bytes32 grpId)
    public
    view
    returns (uint8)
    {
        IStoremanGroup smgTemp = IStoremanGroup(metricData.smg);
        return uint8(smgTemp.getSelectedSmNumber(grpId));
    }
    /// @notice                         get leader address of the group
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    function getLeader(MetricTypes.MetricStorageData storage metricData, bytes32 grpId)
    public
    view
    returns (address)
    {
        address leader;
        IStoremanGroup smgTemp = IStoremanGroup(metricData.smg);
        (leader,,) = smgTemp.getSelectedSmInfo(grpId, uint(0));
        return leader;
    }

    /// @notice                         get work address of the group
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param smIndex                  sm index
    function getWkAddr(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, uint smIndex)
    public
    view
    returns (address)
    {
        address wkAddr;
        IStoremanGroup smgTemp = IStoremanGroup(metricData.smg);
        (wkAddr,,) = smgTemp.getSelectedSmInfo(grpId, smIndex);
        return wkAddr;
    }

    /// @notice                         record sm slash
    /// @param metricData               self parameter for lib function
    /// @param grpId                    group id
    /// @param smIndex                  sm index
    function recordSmSlash(MetricTypes.MetricStorageData storage metricData, bytes32 grpId, uint smIndex)
    public
    view
    {
        address wkAddr;
        IStoremanGroup smgTemp = IStoremanGroup(metricData.smg);
        wkAddr = getWkAddr(metricData, grpId, smIndex);
        smgTemp.recordSmSlash(wkAddr);
    }
}
          

openzeppelin-eth/contracts/token/ERC721/ERC721Metadata.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./ERC721.sol";
import "./IERC721Metadata.sol";
import "../../introspection/ERC165.sol";


contract ERC721Metadata is Initializable, ERC165, ERC721, IERC721Metadata {
  // Token name
  string internal _name;

  // Token symbol
  string internal _symbol;

  // Optional mapping for token URIs
  mapping(uint256 => string) private _tokenURIs;

  bytes4 private constant InterfaceId_ERC721Metadata = 0x5b5e139f;
  /**
   * 0x5b5e139f ===
   *   bytes4(keccak256('name()')) ^
   *   bytes4(keccak256('symbol()')) ^
   *   bytes4(keccak256('tokenURI(uint256)'))
   */

  /**
   * @dev Constructor function
   */
  function initialize(string name, string symbol) public initializer {
    require(ERC721._hasBeenInitialized());

    _name = name;
    _symbol = symbol;

    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(InterfaceId_ERC721Metadata);
  }

  function _hasBeenInitialized() internal view returns (bool) {
    return supportsInterface(InterfaceId_ERC721Metadata);
  }

  /**
   * @dev Gets the token name
   * @return string representing the token name
   */
  function name() external view returns (string) {
    return _name;
  }

  /**
   * @dev Gets the token symbol
   * @return string representing the token symbol
   */
  function symbol() external view returns (string) {
    return _symbol;
  }

  /**
   * @dev Returns an URI for a given token ID
   * Throws if the token ID does not exist. May return an empty string.
   * @param tokenId uint256 ID of the token to query
   */
  function tokenURI(uint256 tokenId) public view returns (string) {
    require(_exists(tokenId));
    return _tokenURIs[tokenId];
  }

  /**
   * @dev Internal function to set the token URI for a given token
   * Reverts if the token ID does not exist
   * @param tokenId uint256 ID of the token to set its URI
   * @param uri string URI to assign
   */
  function _setTokenURI(uint256 tokenId, string uri) internal {
    require(_exists(tokenId));
    _tokenURIs[tokenId] = uri;
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param owner owner of the token to burn
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    super._burn(owner, tokenId);

    // Clear metadata (if any)
    if (bytes(_tokenURIs[tokenId]).length != 0) {
      delete _tokenURIs[tokenId];
    }
  }

  uint256[50] private ______gap;
}
          

contracts/interfaces/IPosLib.sol

pragma solidity 0.4.26;

interface IPosLib {
    function getEpochId(uint256 blockTime) external view returns (uint256);

    function getMinIncentive(uint256 smgDeposit, uint256 day, uint256 totalDeposit) external view returns (uint256);
}
          

contracts/metric/lib/MetricTypes.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../../interfaces/IConfig.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../lib/CommonTool.sol";

library MetricTypes {
    enum SlshReason {CM, R, RNK, S, SNK}

    struct PolyCMData {
        bytes polyCM;
        bytes32 polyCMR;
        bytes32 polyCMS;
    }

    struct PolyDataPln {
        bytes polyData;
        bytes32 polyDataR;
        bytes32 polyDataS;
    }

    struct RSlshData {
        PolyCMData polyCMData;
        PolyDataPln polyDataPln;
        uint8 sndrIndex;
        uint8 rcvrIndex;
        bool becauseSndr;
        CommonTool.CurveType curveType;
    }

    struct SSlshData {
        PolyDataPln polyDataPln;
        bytes m;          // hash(R|| hash(M))
        bytes rpkShare;
        bytes gpkShare;
        uint8 sndrIndex;
        uint8 rcvrIndex;
        bool becauseSndr;
        CommonTool.CurveType curveType;
    }

    struct InctData {
        uint256 smIndexes;
    }

    struct RNWData {
        uint256 smIndexes;
    }

    struct SNWData {
        uint256 smIndexes;
    }


    struct MetricStorageData {

        /** Incentive data **/
        /// groupId -> hashx -> InctData
        mapping(bytes32 => mapping(bytes32 => InctData)) mapInct;

        /** R slsh data **/
        // groupId -> hashx -> smIndex -> RSlshData
        mapping(bytes32 => mapping(bytes32 => mapping(uint8 => RSlshData))) mapRSlsh;

        /** R No Working data **/
        // groupId -> hashx -> RNWData
        mapping(bytes32 => mapping(bytes32 => RNWData)) mapRNW;

        /** S slsh data **/
        // groupId -> hashx -> smIndex -> SSlshData
        mapping(bytes32 => mapping(bytes32 => mapping(uint8 => SSlshData))) mapSSlsh;

        /** S No Working data **/
        // groupId -> hashx -> SNWData
        mapping(bytes32 => mapping(bytes32 => SNWData)) mapSNW;

        /** slsh count statistics **/
        /// grpId -> epochId -> smIndex -> slsh count
        mapping(bytes32 => mapping(uint256 => mapping(uint8 => uint256))) mapSlshCount;

        /** incentive count statistics **/
        /// grpId -> epochId -> smIndex -> incentive count
        mapping(bytes32 => mapping(uint256 => mapping(uint8 => uint256))) mapInctCount;

        /// config instance address
        address config;

        /// smg instance address
        address smg;

        /// posLib address
        address posLib;
    }

}
          

contracts/schnorr/Secp256k1.sol

pragma solidity ^0.4.24;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';

contract Secp256k1 {
    using SafeMath for uint256;

    uint256 constant gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798;
    uint256 constant gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8;
    uint256 constant n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
    uint256 constant a = 0;
    uint256 constant b = 7;

    function getGx() public pure returns (uint256) {
        return gx;
    }

    function getGy() public pure returns (uint256) {
        return gy;
    }

    function ecadd(
        uint256 x1,
        uint256 y1,
        uint256 x2,
        uint256 y2
    ) public view returns (uint256 retx, uint256 rety) {
        address to = 0X42;
        assembly {
            let freePtr := mload(0x40)
            mstore(add(freePtr, 0), x1)
            mstore(add(freePtr, 32), y1)
            mstore(add(freePtr, 64), x2)
            mstore(add(freePtr, 96), y2)

            if iszero(staticcall(gas, to, freePtr, 132, freePtr, 64)) {
                revert(0, 0)
            }

            retx := mload(freePtr)
            rety := mload(add(freePtr, 32))
        }
    }

    function ecmul(
        uint256 xPk,
        uint256 yPk,
        uint256 scalar
    ) public view returns (uint256 x, uint256 y) {
        address to = 0x43;
        assembly {
            let freePtr := mload(0x40)
            mstore(add(freePtr, 0), scalar)
            mstore(add(freePtr, 32), xPk)
            mstore(add(freePtr, 64), yPk)

            if iszero(staticcall(gas, to, freePtr, 96, freePtr, 64)) {
                revert(0,0)
            }

            x := mload(freePtr)
            y := mload(add(freePtr, 32))
        }
    }
}
          

contracts/tokenManager/WanToken.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

import '../components/StandardToken.sol';
import '../components/Owned.sol';

contract WanToken is StandardToken, Owned {
    using SafeMath for uint;

    /****************************************************************************
     **
     ** MODIFIERS
     **
     ****************************************************************************/
    modifier onlyMeaningfulValue(uint value) {
        require(value > 0, "Value is null");
        _;
    }

    /****************************************************************************
     **
     ** EVENTS
     **
     ****************************************************************************/
    /// @notice Logger for token mint
    /// @dev Logger for token mint
    /// @param account Whom these token will be minted to
    /// @param value Amount of ETH/WETH to be minted
    /// @param totalSupply Total amount of WETH after token mint
    event TokenMintedLogger(
        address indexed account,
        uint indexed value,
        uint indexed totalSupply
    );

    /// @notice Logger for token burn
    /// @dev Logger for token burn
    /// @param account Initiator address
    /// @param value Amount of WETH to be burnt
    /// @param totalSupply Total amount of WETH after token burn
    event TokenBurntLogger(
        address indexed account,
        uint indexed value,
        uint indexed totalSupply
    );

    ///@notice Initialize the TokenManager address
    ///@dev Initialize the TokenManager address
    ///@param tokenName The token name to be used
    ///@param tokenSymbol The token symbol to be used
    ///@param tokenDecimal The token decimals to be used
    constructor(string tokenName, string tokenSymbol, uint8 tokenDecimal)
        public
    {
        name = tokenName;
        symbol = tokenSymbol;
        decimals = tokenDecimal;
    }

    /****************************************************************************
     **
     ** MANIPULATIONS
     **
     ****************************************************************************/

    /// @notice Create token
    /// @dev Create token
    /// @param account Address will receive token
    /// @param value Amount of token to be minted
    function mint(address account, uint value)
        external
        onlyOwner
        onlyMeaningfulValue(value)
    {
        require(account != address(0), "Account is null");

        balances[account] = balances[account].add(value);
        totalSupply = totalSupply.add(value);

        emit TokenMintedLogger(account, value, totalSupply);
    }

    /// @notice Burn token
    /// @dev Burn token
    /// @param account Address of whose token will be burnt
    /// @param value Amount of token to be burnt
    function burn(address account, uint value)
        external
        onlyOwner
        onlyMeaningfulValue(value)
    {
        balances[account] = balances[account].sub(value);
        totalSupply = totalSupply.sub(value);

        emit TokenBurntLogger(account, value, totalSupply);
    }

}
          

contracts/quota/QuotaStorage.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "../components/BasicStorage.sol";

contract QuotaStorage is BasicStorage {

    /// @dev Math operations with safety checks
    using SafeMath for uint;

    struct Quota {
        /// amount of original token to be received, equals to amount of WAN token to be minted
        uint debt_receivable;
        /// amount of WAN token to be burnt
        uint debt_payable;
        /// amount of original token has been exchanged to the wanchain
        uint _debt;
        /// amount of original token to be received, equals to amount of WAN token to be minted
        uint asset_receivable;
        /// amount of WAN token to be burnt
        uint asset_payable;
        /// amount of original token has been exchanged to the wanchain
        uint _asset;
        /// data is active
        bool _active;
    }

    /// @dev the denominator of deposit rate value
    uint public constant DENOMINATOR = 10000;

    /// @dev mapping: tokenId => storemanPk => Quota
    mapping(uint => mapping(bytes32 => Quota)) quotaMap;

    /// @dev mapping: storemanPk => tokenIndex => tokenId, tokenIndex:0,1,2,3...
    mapping(bytes32 => mapping(uint => uint)) storemanTokensMap;

    /// @dev mapping: storemanPk => token count
    mapping(bytes32 => uint) storemanTokenCountMap;

    /// @dev mapping: htlcAddress => exist
    mapping(address => bool) public htlcGroupMap;

    /// @dev save deposit oracle address (storeman admin or oracle)
    address public depositOracleAddress;

    /// @dev save price oracle address
    address public priceOracleAddress;

    /// @dev deposit rate use for deposit amount calculate
    uint public depositRate;

    /// @dev deposit token's symbol
    string public depositTokenSymbol;

    /// @dev token manger contract address
    address public tokenManagerAddress;

    /// @dev oracle address for check other chain's debt clean
    address public debtOracleAddress;

    /// @dev limit the minimize value of fast cross chain
    uint public fastCrossMinValue;

    modifier onlyHtlc() {
        require(htlcGroupMap[msg.sender], "Not in HTLC group");
        _;
    }
}
          

contracts/lib/CommonTool.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

library CommonTool {

    enum CurveType  {SK, BN}

    address constant PRECOMPILE_CONTRACT_ADDR = 0x268;

    function bytes2uint(bytes source, uint16 offset, uint16 length)
    public
    pure
    returns(uint)
    {
        uint number = 0;
        for (uint i = 0; i < length; i++) {
            number = number + uint8(source[i + offset]) * (2 ** (8 * (length - (i + 1))));
        }
        return number;
    }

    function bytesToBytes32(bytes memory source) pure public returns (bytes32 result) {
        assembly {
            result := mload(add(source, 32))
        }
    }

    function cmpBytes(bytes b1, bytes b2)
    public
    pure
    returns(bool)
    {
        uint len1 = b1.length;
        uint len2 = b2.length; // maybe has padding
        if (len2 >= len1) {
            for (uint i = 0; i < len2; i++) {
                if (i < len1) {
                    if (b1[i] != b2[i]) {
                        return false;
                    }
                } else if (b2[i] != 0x0) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    function enc(bytes32 rbpri, bytes32 iv, uint256 mes, bytes pub)
    public
    view
    returns(bytes, bool success)
    {
        bytes32 functionSelector = 0xa1ecea4b00000000000000000000000000000000000000000000000000000000;
        address to = PRECOMPILE_CONTRACT_ADDR;
        bytes memory cc = new bytes(6*32);
        assembly {
            let freePtr := mload(0x40)
            mstore(freePtr, functionSelector)
            mstore(add(freePtr, 4), rbpri)
            mstore(add(freePtr, 36), iv)
            mstore(add(freePtr, 68), mes)
            mstore(add(freePtr, 100), mload(add(pub, 32)))
            mstore(add(freePtr, 132), mload(add(pub, 64)))

        // call ERC20 Token contract transfer function
            success := staticcall(gas,to, freePtr, 164, freePtr, 1024)

            let loopCnt := 0
            loop:
            jumpi(loopend, eq(loopCnt, 6))
            mstore(add(cc,mul(add(loopCnt,1),32)),mload(add(freePtr,mul(loopCnt,32))))
            loopCnt := add(loopCnt, 1)
            jump(loop)
            loopend:
        }
        return (cc,success);
    }
}
          

contracts/gpk/GpkDelegate.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "../components/Admin.sol";
import "./GpkStorage.sol";
import "./lib/GpkLib.sol";

contract GpkDelegate is GpkStorage, Admin {
    using SafeMath for uint;

    /**
     *
     * EVENTS
     *
     */

    /// @notice                           event for storeman submit poly commit
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    /// @param curveIndex                 signature curve index
    /// @param storeman                   storeman address
    event SetPolyCommitLogger(bytes32 indexed groupId, uint16 indexed round, uint8 indexed curveIndex, address storeman);

    /// @notice                           event for storeman submit encoded sij
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    /// @param curveIndex                 signature curve index
    /// @param src                        src storeman address
    /// @param dest                       dest storeman address
    event SetEncSijLogger(bytes32 indexed groupId, uint16 indexed round, uint8 indexed curveIndex, address src, address dest);

    /// @notice                           event for storeman submit result of checking encSij
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    /// @param curveIndex                 signature curve index
    /// @param src                        src storeman address
    /// @param dest                       dest storeman address
    /// @param isValid                    whether encSij is valid
    event SetCheckStatusLogger(bytes32 indexed groupId, uint16 indexed round, uint8 indexed curveIndex, address src, address dest, bool isValid);

    /// @notice                           event for storeman reveal sij
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    /// @param curveIndex                 signature curve index
    /// @param src                        src storeman address
    /// @param dest                       dest storeman address
    event RevealSijLogger(bytes32 indexed groupId, uint16 indexed round, uint8 indexed curveIndex, address src, address dest);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for set smg contract address
    /// @param cfgAddr                    cfg contract address
    /// @param smgAddr                    smg contract address
    function setDependence(address cfgAddr, address smgAddr)
        external
        onlyOwner
    {
        require(cfgAddr != address(0), "Invalid cfg");
        cfg = cfgAddr;
              
        require(smgAddr != address(0), "Invalid smg");
        smg = smgAddr;
    }

    /// @notice                           function for set period
    /// @param groupId                    group id
    /// @param ployCommitPeriod           ployCommit period
    /// @param defaultPeriod              default period
    /// @param negotiatePeriod            negotiate period
    function setPeriod(bytes32 groupId, uint32 ployCommitPeriod, uint32 defaultPeriod, uint32 negotiatePeriod)
        external
        onlyAdmin
    {
        GpkTypes.Group storage group = groupMap[groupId];
        group.ployCommitPeriod = ployCommitPeriod;
        group.defaultPeriod = defaultPeriod;
        group.negotiatePeriod = negotiatePeriod;
    }


    /// @notice                           function for storeman submit poly commit
    /// @param groupId                    storeman group id
    /// @param roundIndex                 group negotiate round
    /// @param curveIndex                 singnature curve index
    /// @param polyCommit                 poly commit list (17 order in x0,y0,x1,y1... format)
    function setPolyCommit(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, bytes polyCommit)
        external
    {
        require(polyCommit.length > 0, "Invalid polyCommit");

        GpkTypes.Group storage group = groupMap[groupId];
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        if (group.smNumber == 0) {
            // init group when the first node submit to start every round
            GpkLib.initGroup(groupId, group, cfg, smg);
        }
        if (round.statusTime == 0) {
            round.statusTime = now;
        }
        checkValid(group, roundIndex, curveIndex, GpkTypes.GpkStatus.PolyCommit, true, false, address(0));
        require(round.srcMap[msg.sender].polyCommit.length == 0, "Duplicate");
        round.srcMap[msg.sender].polyCommit = polyCommit;
        round.polyCommitCount++;
        GpkLib.updateGpk(round, polyCommit);
        GpkLib.updateGpkShare(group, round, polyCommit);
        if (round.polyCommitCount >= group.smNumber) {
            round.status = GpkTypes.GpkStatus.Negotiate;
            round.statusTime = now;
        }

        emit SetPolyCommitLogger(groupId, roundIndex, curveIndex, msg.sender);
    }

    /// @notice                           function for report storeman submit poly commit timeout
    /// @param groupId                    storeman group id
    /// @param curveIndex                 singnature curve index
    function polyCommitTimeout(bytes32 groupId, uint8 curveIndex)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, group.round, curveIndex, GpkTypes.GpkStatus.PolyCommit, false, false, address(0));
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        uint32 timeout = (group.round == 0) ? group.ployCommitPeriod : group.defaultPeriod;
        require(now.sub(round.statusTime) > timeout, "Not late");
        uint slashCount = 0;
        for (uint i = 0; (i < group.smNumber) && (slashCount + round.polyCommitCount < group.smNumber); i++) {
            address src = group.addrMap[i];
            if (round.srcMap[src].polyCommit.length == 0) {
                GpkLib.slash(group, curveIndex, GpkTypes.SlashType.PolyCommitTimeout, src, address(0), false, smg);
                slashCount++;
            }
        }
        GpkLib.slashMulti(group, curveIndex, smg);
    }

    /// @notice                           function for src storeman submit encSij
    /// @param groupId                    storeman group id
    /// @param roundIndex                 group negotiate round
    /// @param curveIndex                 singnature curve index
    /// @param dest                       dest storeman address
    /// @param encSij                     encSij
    function setEncSij(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, address dest, bytes encSij)
        external
    {
        require(encSij.length > 0, "Invalid encSij"); // ephemPublicKey(65) + iv(16) + mac(32) + ciphertext(48)
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, roundIndex, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, dest);
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        GpkTypes.Dest storage d = round.srcMap[msg.sender].destMap[dest];
        require(d.encSij.length == 0, "Duplicate");
        d.encSij = encSij;
        d.setTime = now;
        emit SetEncSijLogger(groupId, roundIndex, curveIndex, msg.sender, dest);
    }

    /// @notice                           function for dest storeman set check status for encSij
    /// @param groupId                    storeman group id
    /// @param roundIndex                 group negotiate round
    /// @param curveIndex                 singnature curve index
    /// @param src                        src storeman address
    /// @param isValid                    whether encSij is valid
    function setCheckStatus(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, address src, bool isValid)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, roundIndex, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, src);
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        GpkTypes.Src storage s = round.srcMap[src];
        GpkTypes.Dest storage d = s.destMap[msg.sender];
        require(d.encSij.length != 0, "Not ready");
        require(d.checkStatus == GpkTypes.CheckStatus.Init, "Duplicate");

        d.checkTime = now;
        emit SetCheckStatusLogger(groupId, roundIndex, curveIndex, src, msg.sender, isValid);

        if (isValid) {
            d.checkStatus = GpkTypes.CheckStatus.Valid;
            s.checkValidCount++;
            round.checkValidCount++;
            if (round.checkValidCount >= group.smNumber ** 2) {
                round.status = GpkTypes.GpkStatus.Complete;
                round.statusTime = now;
                GpkLib.tryComplete(group, smg);
            }
        } else {
            d.checkStatus = GpkTypes.CheckStatus.Invalid;
        }
    }

    /// @notice                           function for report src storeman submit encSij timeout
    /// @param groupId                    storeman group id
    /// @param curveIndex                 singnature curve index
    /// @param src                        src storeman address
    function encSijTimeout(bytes32 groupId, uint8 curveIndex, address src)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, group.round, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, src);
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        GpkTypes.Dest storage d = round.srcMap[src].destMap[msg.sender];
        require(d.encSij.length == 0, "Outdated");
        require(now.sub(round.statusTime) > group.defaultPeriod, "Not late");
        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.EncSijTimout, src, msg.sender, true, smg);
    }

    /// @notice                           function for src storeman reveal sij
    /// @param groupId                    storeman group id
    /// @param roundIndex                 group negotiate round
    /// @param curveIndex                 singnature curve index
    /// @param dest                       dest storeman address
    /// @param sij                        sij
    /// @param ephemPrivateKey            ecies ephemPrivateKey
    function revealSij(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, address dest, uint sij, uint ephemPrivateKey)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, roundIndex, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, dest);
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        GpkTypes.Src storage src = round.srcMap[msg.sender];
        GpkTypes.Dest storage d = src.destMap[dest];
        require(d.checkStatus == GpkTypes.CheckStatus.Invalid, "Not need");
        d.sij = sij;
        d.ephemPrivateKey = ephemPrivateKey;
        emit RevealSijLogger(groupId, roundIndex, curveIndex, msg.sender, dest);
        if (GpkLib.verifySij(d, group.pkMap[dest], src.polyCommit, round.curve)) {
          GpkLib.slash(group, curveIndex, GpkTypes.SlashType.CheckInvalid, dest, msg.sender, true, smg);
        } else {
          GpkLib.slash(group, curveIndex, GpkTypes.SlashType.SijInvalid, msg.sender, dest, true, smg);
        }
    }

    /// @notice                           function for report dest storeman check Sij timeout
    /// @param groupId                    storeman group id
    /// @param curveIndex                 singnature curve index
    /// @param dest                       dest storeman address
    function checkSijTimeout(bytes32 groupId, uint8 curveIndex, address dest)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, group.round, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, dest);
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        GpkTypes.Dest storage d = round.srcMap[msg.sender].destMap[dest];
        require(d.checkStatus == GpkTypes.CheckStatus.Init, "Checked");
        require(d.encSij.length != 0, "Not ready");
        require(now.sub(d.setTime) > group.defaultPeriod, "Not late");
        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.CheckTimeout, dest, msg.sender, true, smg);
    }

    /// @notice                           function for report srcPk submit sij timeout
    /// @param groupId                    storeman group id
    /// @param curveIndex                 singnature curve index
    /// @param src                        src storeman address
    function SijTimeout(bytes32 groupId, uint8 curveIndex, address src)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, group.round, curveIndex, GpkTypes.GpkStatus.Negotiate, true, true, src);
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        GpkTypes.Dest storage d = round.srcMap[src].destMap[msg.sender];
        require(d.checkStatus == GpkTypes.CheckStatus.Invalid, "Not need");
        require(now.sub(d.checkTime) > group.defaultPeriod, "Not late");
        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.SijTimeout, src, msg.sender, true, smg);
    }

    /// @notice                           function for terminate protocol
    /// @param groupId                    storeman group id
    /// @param curveIndex                 singnature curve index
    function terminate(bytes32 groupId, uint8 curveIndex)
        external
    {
        GpkTypes.Group storage group = groupMap[groupId];
        checkValid(group, group.round, curveIndex, GpkTypes.GpkStatus.Negotiate, false, false, address(0));
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        require(now.sub(round.statusTime) > group.negotiatePeriod, "Not late");
        for (uint i = 0; i < group.smNumber; i++) {
            address src = group.addrMap[i];
            uint slashPair = uint(group.smNumber).sub(uint(round.srcMap[src].checkValidCount));
            for (uint j = 0; (j < group.smNumber) && (slashPair > 0); j++) {
                address dest = group.addrMap[j];
                GpkTypes.Dest storage d = round.srcMap[src].destMap[dest];
                if (d.checkStatus != GpkTypes.CheckStatus.Valid) {
                    if (d.encSij.length == 0) {
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.EncSijTimout, src, dest, false, smg);
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.Connive, dest, src, false, smg);
                    } else if (d.checkStatus == GpkTypes.CheckStatus.Init) {
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.Connive, src, dest, false, smg);
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.CheckTimeout, dest, src, false, smg);
                    } else { // GpkTypes.CheckStatus.Invalid
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.SijTimeout, src, dest, false, smg);
                        GpkLib.slash(group, curveIndex, GpkTypes.SlashType.Connive, dest, src, false, smg);
                    }
                    slashPair--;
                }
            }
        }
        GpkLib.slashMulti(group, curveIndex, smg);
    }

    /// @notice                           function for check paras
    /// @param group                      group
    /// @param roundIndex                 group negotiate round
    /// @param curveIndex                 singnature curve index
    /// @param status                     check group status
    /// @param checkSender                whether check msg.sender
    /// @param checkStoreman              whether check storeman
    /// @param storeman                   storeman address
    function checkValid(GpkTypes.Group storage group, uint16 roundIndex, uint8 curveIndex, GpkTypes.GpkStatus status, bool checkSender, bool checkStoreman, address storeman)
        private
        view
    {
        require(roundIndex == group.round, "Invalid round"); // must be current round
        require(curveIndex <= 1, "Invalid curve"); // curve only can be 0 or 1
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        require((round.status == status) && (round.statusTime > 0), "Invalid status");
        if (checkSender) {
            require(group.pkMap[msg.sender].length > 0, "Invalid sender");
        }
        if (checkStoreman) {
            require(group.pkMap[storeman].length > 0, "Invalid storeman");
        }
    }

    function getGroupInfo(bytes32 groupId, int32 roundIndex)
        external
        view
        returns(uint16 queriedRound, address curve1, uint8 curve1Status, uint curve1StatusTime, address curve2, uint8 curve2Status, uint curve2StatusTime)
    {
        GpkTypes.Group storage group = groupMap[groupId];
        queriedRound = (roundIndex >= 0)? uint16(roundIndex) : group.round;
        GpkTypes.Round storage round1 = group.roundMap[queriedRound][0];
        GpkTypes.Round storage round2 = group.roundMap[queriedRound][1];
        return (queriedRound, round1.curve, uint8(round1.status), round1.statusTime, round2.curve, uint8(round2.status), round2.statusTime);
    }

    function getPolyCommit(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, address src)
        external
        view
        returns(bytes polyCommit)
    {
        GpkTypes.Group storage group = groupMap[groupId];
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        return round.srcMap[src].polyCommit;
    }

    function getSijInfo(bytes32 groupId, uint16 roundIndex, uint8 curveIndex, address src, address dest)
        external
        view
        returns(bytes encSij, uint8 checkStatus, uint setTime, uint checkTime, uint sij, uint ephemPrivateKey)
    {
        GpkTypes.Group storage group = groupMap[groupId];
        GpkTypes.Round storage round = group.roundMap[roundIndex][curveIndex];
        GpkTypes.Dest storage d = round.srcMap[src].destMap[dest];
        return (d.encSij, uint8(d.checkStatus), d.setTime, d.checkTime, d.sij, d.ephemPrivateKey);
    }

    function getGpkShare(bytes32 groupId, uint16 index)
        external
        view
        returns(bytes gpkShare1, bytes gpkShare2)
    {
        GpkTypes.Group storage group = groupMap[groupId];
        address src = group.addrMap[index];
        mapping(uint8 => GpkTypes.Round) roundMap = groupMap[groupId].roundMap[group.round];
        return (roundMap[0].srcMap[src].gpkShare, roundMap[1].srcMap[src].gpkShare);
    }

    function getGpk(bytes32 groupId)
        external
        view
        returns(bytes gpk1, bytes gpk2)
    {
        GpkTypes.Group storage group = groupMap[groupId];
        mapping(uint8 => GpkTypes.Round) roundMap = groupMap[groupId].roundMap[group.round];
        return (roundMap[0].gpk, roundMap[1].gpk);
    }

    /// @notice fallback function
    function () public payable {
        revert("Not support");
    }
}
          

openzeppelin-eth/contracts/introspection/IERC165.sol

pragma solidity ^0.4.24;


/**
 * @title IERC165
 * @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
 */
interface IERC165 {

  /**
   * @notice Query if a contract implements an interface
   * @param interfaceId The interface identifier, as specified in ERC-165
   * @dev Interface identification is specified in ERC-165. This function
   * uses less than 30,000 gas.
   */
  function supportsInterface(bytes4 interfaceId)
    external
    view
    returns (bool);
}
          

contracts/crossApproach/lib/RapidityLibV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;


import "./RapidityTxLib.sol";
import "./CrossTypesV1.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/IRC20Protocol.sol";
import "../../interfaces/ISmgFeeProxy.sol";

library RapidityLibV2 {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    /**
    *
    * STRUCTURES
    *
    */

    /// @notice struct of Rapidity storeman mint lock parameters
    struct CrossFeeParams {
        uint contractFee;                 /// token pair id on cross chain
        uint agentFee;                    /// exchange token value
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapidityUserLockParams {
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        uint currentChainID;              /// current chain ID
        bytes destUserAccount;            /// account of shadow chain, used to receive token
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapiditySmgMintParams {
        bytes32 uniqueID;                 /// Rapidity random number
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        address destTokenAccount;         /// shadow token account
        address destUserAccount;          /// account of shadow chain, used to receive token
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapidityUserBurnParams {
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint currentChainID;            /// current chain ID
        uint fee;                       /// exchange token fee
        address srcTokenAccount;        /// shadow token account
        bytes destUserAccount;          /// account of token destination chain, used to receive token
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapiditySmgReleaseParams {
        bytes32 uniqueID;               /// Rapidity random number
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        address destTokenAccount;       /// original token/coin account
        address destUserAccount;        /// account of token original chain, used to receive token
    }

    /**
     *
     * EVENTS
     *
     **/


    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity original token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserLockLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity shadow token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserBurnLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, uint fee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity shadow token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgMintLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity original token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgReleaseLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                         mintBridge, user lock token on token original chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user mint lock token on token original chain
    function userLock(CrossTypesV1.Data storage storageData, RapidityUserLockParams memory params)
        public
    {
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        (fromChainID,fromTokenAccount,toChainID) = storageData.tokenManager.getTokenPairInfoSlim(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        if (address(storageData.quota) != address(0)) {
            storageData.quota.userLock(params.tokenPairID, params.smgID, params.value);
        }

        uint contractFee = storageData.mapContractFee[fromChainID][toChainID];
        if (contractFee > 0) {
            if (storageData.smgFeeProxy == address(0)) {
                storageData.mapStoremanFee[bytes32(0)] = storageData.mapStoremanFee[bytes32(0)].add(contractFee);
            } else {
                (storageData.smgFeeProxy).transfer(contractFee);
            }
        }

        address tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);

        uint left;
        if (tokenScAddr == address(0)) {
            left = (msg.value).sub(params.value).sub(contractFee);
        } else {
            left = (msg.value).sub(contractFee);

            require(CrossTypesV1.transferFrom(tokenScAddr, msg.sender, this, params.value), "Lock token failed");
        }
        if (left != 0) {
            (msg.sender).transfer(left);
        }
        emit UserLockLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.destUserAccount);
    }

    /// @notice                         burnBridge, user lock token on token original chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user burn lock token on token original chain
    function userBurn(CrossTypesV1.Data storage storageData, RapidityUserBurnParams memory params)
        public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint256 contractFee;
        address tokenScAddr;
        if (params.currentChainID == toChainID) {
            contractFee = storageData.mapContractFee[toChainID][fromChainID];
            tokenScAddr = CrossTypesV1.bytesToAddress(toTokenAccount);
        } else if (params.currentChainID == fromChainID) {
            contractFee = storageData.mapContractFee[fromChainID][toChainID];
            tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        require(params.srcTokenAccount == tokenScAddr, "invalid token account");

        if (address(storageData.quota) != address(0)) {
            storageData.quota.userBurn(params.tokenPairID, params.smgID, params.value);
        }

        require(burnShadowToken(tokenManager, tokenScAddr, msg.sender, params.value), "burn failed");

        if (contractFee > 0) {
            if (storageData.smgFeeProxy == address(0)) {
                storageData.mapStoremanFee[bytes32(0)] = storageData.mapStoremanFee[bytes32(0)].add(contractFee);
            } else {
                (storageData.smgFeeProxy).transfer(contractFee);
            }
        }

        uint left = (msg.value).sub(contractFee);
        // uint left = (msg.value).sub(contractFee);
        if (left != 0) {
            (msg.sender).transfer(left);
        }

        emit UserBurnLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.fee, params.destUserAccount);
    }

    /// @notice                         mintBridge, storeman mint lock token on token shadow chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman mint lock token on token shadow chain
    function smgMint(CrossTypesV1.Data storage storageData, RapiditySmgMintParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (address(storageData.quota) != address(0)) {
            storageData.quota.smgMint(params.tokenPairID, params.smgID, params.value);
        }

        require(mintShadowToken(storageData.tokenManager, params.destTokenAccount, params.destUserAccount, params.value), "mint failed");

        emit SmgMintLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    /// @notice                         burnBridge, storeman burn lock token on token shadow chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman burn lock token on token shadow chain
    function smgRelease(CrossTypesV1.Data storage storageData, RapiditySmgReleaseParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (address(storageData.quota) != address(0)) {
            storageData.quota.smgRelease(params.tokenPairID, params.smgID, params.value);
        }

        if (params.destTokenAccount == address(0)) {
            (params.destUserAccount).transfer(params.value);
        } else {
            require(CrossTypesV1.transfer(params.destTokenAccount, params.destUserAccount, params.value), "Transfer token failed");
        }

        emit SmgReleaseLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    function burnShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(value);
    }

    function mintShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(value);
    }

}
          

contracts/interfaces/IMappingToken.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface IMappingToken {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string);
    function symbol() external view returns (string);
    function decimals() external view returns (uint8);
    function mint(address, uint) external;
    function burn(address, uint) external;
    function update(string, string) external;
}
          

contracts/oracle/OracleDelegate.sol

pragma solidity 0.4.26;

/**
 * Math operations with safety checks
 */

import "../components/Owned.sol";
import "./OracleStorage.sol";

contract OracleDelegate is OracleStorage, Owned {
  /**
    *
    * EVENTS
    *
    */
  event SetAdmin(address addr);
  event UpdatePrice(bytes32[] keys, uint[] prices);
  event SetDebtClean(bytes32 indexed id, bool isDebtClean);
  event SetStoremanGroupConfig(bytes32 indexed id, uint8 status, uint deposit, uint[2] chain, uint[2] curve, bytes gpk1, bytes gpk2, uint startTime, uint endTime);
  event SetStoremanGroupStatus(bytes32 indexed id, uint8 status);
  event UpdateDeposit(bytes32 indexed id, uint deposit);

  /**
    *
    * MODIFIERS
    *
    */

  modifier onlyAdmin() {
      require((msg.sender == admin) || (msg.sender == owner), "not admin");
      _;
  }

  /**
  *
  * MANIPULATIONS
  *
  */

  function updatePrice(
    bytes32[] keys,
    uint[] prices
  )
    external
    onlyAdmin
  {
    require(keys.length == prices.length, "length not same");

    for (uint256 i = 0; i < keys.length; i++) {
      mapPrices[keys[i]] = prices[i];
    }

    emit UpdatePrice(keys, prices);
  }

  function updateDeposit(
    bytes32 smgID,
    uint amount
  )
    external
    onlyAdmin
  {
    mapStoremanGroupConfig[smgID].deposit = amount;

    emit UpdateDeposit(smgID, amount);
  }

  function setStoremanGroupStatus(
    bytes32 id,
    uint8  status
  )
    external
    onlyAdmin
  {
    mapStoremanGroupConfig[id].status = status;

    emit SetStoremanGroupStatus(id, status);
  }

  function setStoremanGroupConfig(
    bytes32 id,
    uint8   status,
    uint    deposit,
    uint[2] chain,
    uint[2] curve,
    bytes   gpk1,
    bytes   gpk2,
    uint    startTime,
    uint    endTime
  )
    external
    onlyAdmin
  {
    mapStoremanGroupConfig[id].deposit = deposit;
    mapStoremanGroupConfig[id].status = status;
    mapStoremanGroupConfig[id].chain[0] = chain[0];
    mapStoremanGroupConfig[id].chain[1] = chain[1];
    mapStoremanGroupConfig[id].curve[0] = curve[0];
    mapStoremanGroupConfig[id].curve[1] = curve[1];
    mapStoremanGroupConfig[id].gpk1 = gpk1;
    mapStoremanGroupConfig[id].gpk2 = gpk2;
    mapStoremanGroupConfig[id].startTime = startTime;
    mapStoremanGroupConfig[id].endTime = endTime;

    emit SetStoremanGroupConfig(id, status, deposit, chain, curve, gpk1, gpk2, startTime, endTime);
  }

  function setDebtClean(
    bytes32 storemanGroupId,
    bool isClean
  )
    external
    onlyAdmin
  {
    mapStoremanGroupConfig[storemanGroupId].isDebtClean = isClean;

    emit SetDebtClean(storemanGroupId, isClean);
  }

  function setAdmin(
    address addr
  ) external onlyOwner
  {
    admin = addr;

    emit SetAdmin(addr);
  }

  function getValue(bytes32 key) external view returns (uint) {
    return mapPrices[key];
  }

  function getValues(bytes32[] keys) external view returns (uint[] values) {
    values = new uint[](keys.length);
    for(uint256 i = 0; i < keys.length; i++) {
        values[i] = mapPrices[keys[i]];
    }
  }

  function getDeposit(bytes32 smgID) external view returns (uint) {
    return mapStoremanGroupConfig[smgID].deposit;
  }

  function getStoremanGroupConfig(
    bytes32 id
  )
    external
    view
    returns(bytes32 groupId, uint8 status, uint deposit, uint chain1, uint chain2, uint curve1, uint curve2, bytes gpk1, bytes gpk2, uint startTime, uint endTime)
  {
    groupId = id;
    status = mapStoremanGroupConfig[id].status;
    deposit = mapStoremanGroupConfig[id].deposit;
    chain1 = mapStoremanGroupConfig[id].chain[0];
    chain2 = mapStoremanGroupConfig[id].chain[1];
    curve1 = mapStoremanGroupConfig[id].curve[0];
    curve2 = mapStoremanGroupConfig[id].curve[1];
    gpk1 = mapStoremanGroupConfig[id].gpk1;
    gpk2 = mapStoremanGroupConfig[id].gpk2;
    startTime = mapStoremanGroupConfig[id].startTime;
    endTime = mapStoremanGroupConfig[id].endTime;
  }

  function getStoremanGroupStatus(bytes32 id)
    public
    view
    returns(uint8 status, uint startTime, uint endTime)
  {
    status = mapStoremanGroupConfig[id].status;
    startTime = mapStoremanGroupConfig[id].startTime;
    endTime = mapStoremanGroupConfig[id].endTime;
  }

  function isDebtClean(
    bytes32 storemanGroupId
  )
    external
    view
    returns (bool)
  {
    return mapStoremanGroupConfig[storemanGroupId].isDebtClean;
  }
}
          

contracts/schnorr/Secp256k1SchnorrVerifier.sol

pragma solidity ^0.4.24;

import "./Secp256k1.sol";

contract Secp256k1SchnorrVerifier is Secp256k1 {
    struct Point {
        uint256 x; uint256 y;
    }

    struct Verification {
        Point groupKey;
        Point randomPoint;
        uint256 signature;
        bytes32 message;

        uint256 _hash;
        Point _left;
        Point _right;
    }

    function h(bytes32 m, uint256 a, uint256 b) public pure returns (uint256) {
        return uint256(sha256(abi.encodePacked(m, uint8(0x04), a, b)));
    }

    // function cmul(Point p, uint256 scalar) public pure returns (uint256, uint256) {
    function cmul(uint256 x, uint256 y, uint256 scalar) public view returns (uint256, uint256) {
        return ecmul(x, y, scalar);
    }

    function sg(uint256 sig_s) public view returns (uint256, uint256) {
        return ecmul(getGx(), getGy(), sig_s);
    }

    // function cadd(Point a, Point b) public pure returns (uint256, uint256) {
    function cadd(uint256 ax, uint256 ay, uint256 bx, uint256 by) public view returns (uint256, uint256) {
        return ecadd(ax, ay, bx, by);
    }

    function verify(bytes32 signature, bytes32 groupKeyX, bytes32 groupKeyY, bytes32 randomPointX, bytes32 randomPointY, bytes32 message)
        public
        view
        returns(bool)
    {
        bool flag = false;
        Verification memory state;

        state.signature = uint256(signature);
        state.groupKey.x = uint256(groupKeyX);
        state.groupKey.y = uint256(groupKeyY);
        state.randomPoint.x = uint256(randomPointX);
        state.randomPoint.y = uint256(randomPointY);
        state.message = message;

        state._hash = h(state.message, state.randomPoint.x, state.randomPoint.y);

        (state._left.x, state._left.y) = sg(state.signature);
        Point memory rightPart;
        (rightPart.x, rightPart.y) = cmul(state.groupKey.x, state.groupKey.y, state._hash);
        (state._right.x, state._right.y) = cadd(state.randomPoint.x, state.randomPoint.y, rightPart.x, rightPart.y);

        flag = state._left.x == state._right.x && state._left.y == state._right.y;

        return flag;
    }
}
          

contracts/gpk/lib/GpkTypes.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

library GpkTypes {

    struct Group {
        bytes32 groupId;
        uint16 round;
        uint32 ployCommitPeriod;
        uint32 defaultPeriod;
        uint32 negotiatePeriod;
        /// round -> curveIndex -> Round
        mapping(uint16 => mapping(uint8 => Round)) roundMap;
        uint16 smNumber;
        /// index -> txAddress
        mapping(uint => address) addrMap;
        /// txAddress -> slectedIndex
        mapping(address => uint) indexMap;
        /// txAddress -> pk
        mapping(address => bytes) pkMap;
    }

    struct Round {
        address curve;
        GpkStatus status;
        uint16 polyCommitCount;
        uint32 checkValidCount;
        uint16 slashCount;
        uint statusTime;
        bytes gpk;
        /// txAddress -> Src
        mapping(address => Src) srcMap;
    }

    enum GpkStatus {PolyCommit, Negotiate, Complete, Close}

    struct Src {
        bytes polyCommit;
        bytes gpkShare;
        /// txAddress -> Dest
        mapping(address => Dest) destMap;
        uint16 checkValidCount;
        SlashType slashType;
    }

    struct Dest {
        CheckStatus checkStatus;
        uint setTime;
        uint checkTime;
        uint sij;
        uint ephemPrivateKey;
        bytes encSij;
    }

    enum CheckStatus {Init, Valid, Invalid}

    enum SlashType {None, PolyCommitTimeout, EncSijTimout, CheckTimeout, SijTimeout, SijInvalid, CheckInvalid, Connive}
}
          

contracts/interfaces/IWrappedNFT721.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface IWrappedNFT721 {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string);
    function symbol() external view returns (string);
    function decimals() external view returns (uint8);
    function burn(address, uint) external;
    function update(string, string) external;
    function mint(address, uint, bytes) external;

    function burnBatch(address , uint256[]) public;
    function mintBatch(address , uint256[] , bytes) public;
}
          

contracts/components/WRC20Protocol.sol

pragma solidity 0.4.26;

contract WRC20Protocol {
    /* This is a slight change to the ERC20 base standard.
    function totalSupply() constant returns (uint supply);
    is replaced with:
    uint public totalSupply;
    This automatically creates a getter function for the totalSupply.
    This is moved to the base contract since public getter functions are not
    currently recognised as an implementation of the matching abstract
    function by the compiler.
    */

    /**************************************
     **
     ** VARIABLES
     **
     **************************************/

    string public name;
    string public symbol;
    uint8 public decimals;
    mapping (address => uint) balances;
    mapping (address => mapping (address => uint)) allowed;

    /// total amount of tokens
    uint public totalSupply;

    /// @param _owner The address from which the balance will be retrieved
    /// @return The balance
    function balanceOf(address _owner) public view returns (uint balance);

    /// @notice send `_value` token to `_to` from `msg.sender`
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transfer(address _to, uint _value) public returns (bool success);

    /// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
    /// @param _from The address of the sender
    /// @param _to The address of the recipient
    /// @param _value The amount of token to be transferred
    /// @return Whether the transfer was successful or not
    function transferFrom(address _from, address _to, uint _value) public returns (bool success);

    /// @notice `msg.sender` approves `_spender` to spend `_value` tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @param _value The amount of tokens to be approved for transfer
    /// @return Whether the approval was successful or not
    function approve(address _spender, uint _value) public returns (bool success);

    /// @param _owner The address of the account owning tokens
    /// @param _spender The address of the account able to transfer the tokens
    /// @return Amount of remaining tokens allowed to spent
    function allowance(address _owner, address _spender) public view returns (uint remaining);

    event Transfer(address indexed _from, address indexed _to, uint _value);
    event Approval(address indexed _owner, address indexed _spender, uint _value);
}
          

contracts/crossApproach/lib/CrossTypesV1.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "../../interfaces/IRC20Protocol.sol";
import "../../interfaces/IQuota.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/ISignatureVerifier.sol";
import "./HTLCTxLib.sol";
import "./RapidityTxLib.sol";

library CrossTypesV1 {
    using SafeMath for uint;

    /**
     *
     * STRUCTURES
     *
     */

    struct Data {

        /// map of the htlc transaction info
        HTLCTxLib.Data htlcTxData;

        /// map of the rapidity transaction info
        RapidityTxLib.Data rapidityTxData;

        /// quota data of storeman group
        IQuota quota;

        /// token manager instance interface
        ITokenManager tokenManager;

        /// storemanGroup admin instance interface
        IStoremanGroup smgAdminProxy;

        /// storemanGroup fee admin instance address
        address smgFeeProxy;

        ISignatureVerifier sigVerifier;

        /// @notice transaction fee, smgID => fee
        mapping(bytes32 => uint) mapStoremanFee;

        /// @notice transaction fee, origChainID => shadowChainID => fee
        mapping(uint => mapping(uint =>uint)) mapContractFee;

        /// @notice transaction fee, origChainID => shadowChainID => fee
        mapping(uint => mapping(uint =>uint)) mapAgentFee;

    }

    /**
     *
     * MANIPULATIONS
     *
     */

    // /// @notice       convert bytes32 to address
    // /// @param b      bytes32
    // function bytes32ToAddress(bytes32 b) internal pure returns (address) {
    //     return address(uint160(bytes20(b))); // high
    //     // return address(uint160(uint256(b))); // low
    // }

    /// @notice       convert bytes to address
    /// @param b      bytes
    function bytesToAddress(bytes b) internal pure returns (address addr) {
        assembly {
            addr := mload(add(b,20))
        }
    }

    function transfer(address tokenScAddr, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        // IRC20Protocol(tokenScAddr).transfer(to, value);
        tokenScAddr.call(bytes4(keccak256("transfer(address,uint256)")), to, value);
        afterBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }

    function transferFrom(address tokenScAddr, address from, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        // IRC20Protocol(tokenScAddr).transferFrom(from, to, value);
        tokenScAddr.call(bytes4(keccak256("transferFrom(address,address,uint256)")), from, to, value);
        afterBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }
}
          

contracts/interfaces/IQuota.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface IQuota {
  function userLock(uint tokenId, bytes32 storemanGroupId, uint value) external;
  function userBurn(uint tokenId, bytes32 storemanGroupId, uint value) external;

  function smgRelease(uint tokenId, bytes32 storemanGroupId, uint value) external;
  function smgMint(uint tokenId, bytes32 storemanGroupId, uint value) external;

  function upgrade(bytes32 storemanGroupId) external;

  function transferAsset(bytes32 srcStoremanGroupId, bytes32 dstStoremanGroupId) external;
  function receiveDebt(bytes32 srcStoremanGroupId, bytes32 dstStoremanGroupId) external;

  function getUserMintQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);
  function getSmgMintQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);

  function getUserBurnQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);
  function getSmgBurnQuota(uint tokenId, bytes32 storemanGroupId) external view returns (uint);

  function getAsset(uint tokenId, bytes32 storemanGroupId) external view returns (uint asset, uint asset_receivable, uint asset_payable);
  function getDebt(uint tokenId, bytes32 storemanGroupId) external view returns (uint debt, uint debt_receivable, uint debt_payable);

  function isDebtClean(bytes32 storemanGroupId) external view returns (bool);
}
          

contracts/storemanGroupAdmin/ListGroup.sol

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "../components/Admin.sol";
import "./StoremanUtil.sol";



contract ListGroup is Admin  {
  struct Group {
    bytes32 groupId;
    uint startTime;
    uint endTime;
  }

  Group[] groups;
  address public smg;
  address public posAddr;
  mapping(uint=>uint) epochDeposit;
  mapping(address=>mapping(address=>bytes32)) delegateQuitGroupId;
  mapping(address=>mapping(address=>bytes32)) delegateQuitNextGroupId;
  mapping(address=>mapping(address=>bytes32)) partQuitGroupId;
  mapping(address=>mapping(address=>bytes32)) partQuitNextGroupId;
  constructor(address _smg, address _pos) public {
    smg = _smg;
    posAddr = _pos;  
  }
  function setDelegateQuitGroupId(address wkAddr, address deAddr, bytes32 groupId, bytes32 nextGroupId)external {
    require(smg == msg.sender, "not allow");
    delegateQuitGroupId[wkAddr][deAddr] = groupId;
    delegateQuitNextGroupId[wkAddr][deAddr] = nextGroupId;
  }

  function setPartQuitGroupId(address wkAddr, address pnAddr, bytes32 groupId, bytes32 nextGroupId) external {
    require(smg == msg.sender, "not allow");
    partQuitGroupId[wkAddr][pnAddr] = groupId;
    partQuitNextGroupId[wkAddr][pnAddr] = nextGroupId;
  }
 
  function getDelegateQuitGroupId(address wkAddr, address deAddr) external view returns (bytes32 groupId, bytes32 nextGroupId){
    return (delegateQuitGroupId[wkAddr][deAddr], delegateQuitNextGroupId[wkAddr][deAddr]);
  }

  function getPartQuitGroupId(address wkAddr, address pnAddr) external view returns (bytes32 groupId, bytes32 nextGroupId){
    return (partQuitGroupId[wkAddr][pnAddr], partQuitNextGroupId[wkAddr][pnAddr]);
  }
 
  function addActiveGroup(bytes32 groupId, uint startTime, uint endTime) external  {
    require(smg == msg.sender, "not allow");
    for(uint i=0; i<groups.length; i++){
      require(groups[i].groupId != groupId,"existed");
    }
    Group memory one = Group(groupId, startTime, endTime);
    groups.push(one);
  }

  function setTotalDeposit(uint day, uint value) external {
    require(smg == msg.sender, "not allow");
    epochDeposit[day] = value;
  }

  function getTotalDeposit(uint day) external view returns(uint) {
    return epochDeposit[day];
  }
  
  function getGroups() external view returns (Group[]) {
    return groups;
  }

  function cleanExpiredGroup() external {
    for(uint i=groups.length; i>0; i--) {
        if(groups[i-1].endTime < now){ //  expired.
          if(i < groups.length){
            groups[i-1]= groups[groups.length-1];
          }
          groups.length--;
        } 
    }
  }          
  function getActiveGroupIds(uint epochId) external view returns (bytes32[]) {
    bytes32[] memory activeGroups = new bytes32[](groups.length);
    uint activeCount;
    
    for(uint i=groups.length; i>0; i--) {
      if(StoremanUtil.getDaybyTime(posAddr, groups[i-1].startTime)  <= epochId){
        if(StoremanUtil.getDaybyTime(posAddr, groups[i-1].endTime) > epochId){ //  not expired.
          activeGroups[activeCount] = groups[i-1].groupId;
          activeCount++;
        }
      }
    }
    bytes32[] memory ret = new bytes32[](activeCount);
    for(uint k; k<activeCount; k++) {
      ret[k] = activeGroups[k];
    }
    return ret;
  }
}

          

contracts/crossApproach/CrossDelegateXinFin.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./CrossDelegateV4.sol";


contract CrossDelegateXinFin is CrossDelegateV4 {
    function onXRC721Received(address operator, address from, uint256 tokenId, bytes data)
        external
        pure
        returns (bytes4)
    {
        return this.onXRC721Received.selector;
    }

    function onXRC1155Received(address _operator, address _from, uint256 _id, uint256 _value, bytes _data)
        external
        pure
        returns(bytes4)
    {
        return this.onXRC1155Received.selector;
    }

    function onXRC1155BatchReceived(address _operator, address _from, uint256[] _ids, uint256[] _values, bytes _data)
        external
        pure
        returns(bytes4)
    {
        return this.onXRC1155BatchReceived.selector;
    }
}
          

contracts/tokenManager/TokenManagerDelegate.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;
pragma experimental ABIEncoderV2;

/**
 * Math operations with safety checks
 */

import "../interfaces/IMappingToken.sol";
import "../components/Admin.sol";
import "./TokenManagerStorage.sol";
import "./MappingToken.sol";

contract TokenManagerDelegate is TokenManagerStorage, Admin {
    using SafeMath for uint;
    /************************************************************
     **
     ** EVENTS
     **
     ************************************************************/

     event AddToken(address tokenAddress, string name, string symbol, uint8 decimals);
     event AddTokenPair(uint indexed id, uint fromChainID, bytes fromAccount, uint toChainID, bytes toAccount);
     event UpdateTokenPair(uint indexed id, AncestorInfo aInfo, uint fromChainID, bytes fromAccount, uint toChainID, bytes toAccount);
     event RemoveTokenPair(uint indexed id);
     event UpdateToken(address tokenAddress, string name, string symbol);

    /**
     *
     * MODIFIERS
     *
     */

    modifier onlyNotExistID(uint id) {
        require(mapTokenPairInfo[id].fromChainID == 0, "token exist");
        _;
    }

    modifier onlyExistID(uint id) {
        require(mapTokenPairInfo[id].fromChainID > 0, "token not exist");
        _;
    }

    /**
    *
    * MANIPULATIONS
    *
    */
    
    function bytesToAddress(bytes b) internal pure returns (address addr) {
        assembly {
            addr := mload(add(b,20))
        }
    }

    function mintToken(
        address tokenAddress,
        address to,
        uint    value
    )
        external
        onlyAdmin
    {
        IMappingToken(tokenAddress).mint(to, value);
    }

    function burnToken(
        address tokenAddress,
        address from,
        uint    value
    )
        external
        onlyAdmin
    {
        IMappingToken(tokenAddress).burn(from, value);
    }

    function addToken(
        string name,
        string symbol,
        uint8 decimals
    )
        external
        onlyOwner
    {
        address tokenAddress = new MappingToken(name, symbol, decimals);
        
        emit AddToken(tokenAddress, name, symbol, decimals);
    }

    function addTokenPair(
        uint    id,

        AncestorInfo aInfo,

        uint    fromChainID,
        bytes   fromAccount,
        uint    toChainID,
        bytes   toAccount
    )
        public
        onlyOwner
        onlyNotExistID(id)
    {
        // create a new record
        mapTokenPairInfo[id].fromChainID = fromChainID;
        mapTokenPairInfo[id].fromAccount = fromAccount;
        mapTokenPairInfo[id].toChainID = toChainID;
        mapTokenPairInfo[id].toAccount = toAccount;

        mapTokenPairInfo[id].aInfo.account = aInfo.account;
        mapTokenPairInfo[id].aInfo.name = aInfo.name;
        mapTokenPairInfo[id].aInfo.symbol = aInfo.symbol;
        mapTokenPairInfo[id].aInfo.decimals = aInfo.decimals;
        mapTokenPairInfo[id].aInfo.chainID = aInfo.chainID;

        mapTokenPairIndex[totalTokenPairs] = id;
        totalTokenPairs = totalTokenPairs.add(1);

        // fire event
        emit AddTokenPair(id, fromChainID, fromAccount, toChainID, toAccount);
    }

    function updateTokenPair(
        uint    id,

        AncestorInfo aInfo,

        uint    fromChainID,
        bytes   fromAccount,
        uint    toChainID,
        bytes   toAccount
    )
        public
        onlyOwner
        onlyExistID(id)
    {
        mapTokenPairInfo[id].aInfo.account = aInfo.account;
        mapTokenPairInfo[id].aInfo.name = aInfo.name;
        mapTokenPairInfo[id].aInfo.symbol = aInfo.symbol;
        mapTokenPairInfo[id].aInfo.decimals = aInfo.decimals;
        mapTokenPairInfo[id].aInfo.chainID = aInfo.chainID;

        mapTokenPairInfo[id].fromChainID = fromChainID;
        mapTokenPairInfo[id].fromAccount = fromAccount;
        mapTokenPairInfo[id].toChainID = toChainID;
        mapTokenPairInfo[id].toAccount = toAccount;

        emit UpdateTokenPair(id, aInfo, fromChainID, fromAccount, toChainID, toAccount);
    }

    function removeTokenPair(
        uint id
    )
        external
        onlyOwner
        onlyExistID(id)
    {
        for(uint i=0; i<totalTokenPairs; i++) {
            if (id == mapTokenPairIndex[i]) {
                if (i != totalTokenPairs - 1) {
                    mapTokenPairIndex[i] = mapTokenPairIndex[totalTokenPairs - 1];
                }
 
                delete mapTokenPairIndex[totalTokenPairs - 1];
                totalTokenPairs--;
                delete mapTokenPairInfo[id];
                emit RemoveTokenPair(id);
                return;
            }
        }
    }

    function updateToken(address tokenAddress, string name, string symbol)
        external
        onlyOwner
    {
        IMappingToken(tokenAddress).update(name, symbol);

        emit UpdateToken(tokenAddress, name, symbol);
    }

    function changeTokenOwner(address tokenAddress, address _newOwner) external onlyOwner {
        IMappingToken(tokenAddress).changeOwner(_newOwner);
    }

    function acceptTokenOwnership(address tokenAddress) external {
        IMappingToken(tokenAddress).acceptOwnership();
    }

    function transferTokenOwner(address tokenAddress, address _newOwner) external onlyOwner {
        IMappingToken(tokenAddress).transferOwner(_newOwner);
    }

    function getTokenPairInfo(
        uint id
    )
        external
        view
        returns (uint fromChainID, bytes fromAccount, uint toChainID, bytes toAccount)
    {
        fromChainID = mapTokenPairInfo[id].fromChainID;
        fromAccount = mapTokenPairInfo[id].fromAccount;
        toChainID = mapTokenPairInfo[id].toChainID;
        toAccount = mapTokenPairInfo[id].toAccount;
    }

    function getTokenPairInfoSlim(
        uint id
    )
        external
        view
        returns (uint fromChainID, bytes fromAccount, uint toChainID)
    {
        fromChainID = mapTokenPairInfo[id].fromChainID;
        fromAccount = mapTokenPairInfo[id].fromAccount;
        toChainID = mapTokenPairInfo[id].toChainID;
    }

    function getTokenInfo(uint id) external view returns (address addr, string name, string symbol, uint8 decimals) {
        if (mapTokenPairInfo[id].fromChainID == 0) {
            name = '';
            symbol = '';
            decimals = 0;
            addr = address(0);
        } else {
            address instance = bytesToAddress(mapTokenPairInfo[id].toAccount);
            name = IMappingToken(instance).name();
            symbol = IMappingToken(instance).symbol();
            decimals = IMappingToken(instance).decimals();
            addr = instance;
        }
    }

    function getAncestorInfo(uint id) external view returns (bytes account, string name, string symbol, uint8 decimals, uint chainId) {
        account = mapTokenPairInfo[id].aInfo.account;
        name = mapTokenPairInfo[id].aInfo.name;
        symbol = mapTokenPairInfo[id].aInfo.symbol;
        decimals = mapTokenPairInfo[id].aInfo.decimals;
        chainId = mapTokenPairInfo[id].aInfo.chainID;
    }

    function getAncestorSymbol(uint id) external view returns (string symbol, uint8 decimals) {
        symbol = mapTokenPairInfo[id].aInfo.symbol;
        decimals = mapTokenPairInfo[id].aInfo.decimals;
    }

    function getAncestorChainID(uint id) external view returns (uint chainID) {
        chainID = mapTokenPairInfo[id].aInfo.chainID;
    }

    // function getTokenPairsFullFields()
    //     external
    //     view
    //     returns (TokenPairInfoFull[] tokenPairs)
    // {
    //     tokenPairs = new TokenPairInfoFull[](totalTokenPairs);
    //     for (uint i = 0; i < totalTokenPairs; i++) {
    //         uint theId = mapTokenPairIndex[i];
    //         tokenPairs[i].aInfo = mapTokenPairInfo[theId].aInfo;
    //         tokenPairs[i].fromChainID = mapTokenPairInfo[theId].fromChainID;
    //         tokenPairs[i].fromAccount = mapTokenPairInfo[theId].fromAccount;
    //         tokenPairs[i].toChainID = mapTokenPairInfo[theId].toChainID;
    //         tokenPairs[i].toAccount = mapTokenPairInfo[theId].toAccount;
    //         tokenPairs[i].id = theId;
    //     }
    //     return tokenPairs;
    // }

    // function getTokenPairsByChainID2(uint chainID1, uint chainID2)
    //     external
    //     view
    //     returns (TokenPairInfoFull[] tokenPairs)
    // {
    //     uint cnt = 0;
    //     uint i = 0;
    //     uint theId = 0;
    //     uint[] memory id_valid = new uint[](totalTokenPairs);
    //     for (; i < totalTokenPairs; i++ ) {
    //         theId = mapTokenPairIndex[i];
    //         if ((mapTokenPairInfo[theId].fromChainID == chainID1) && (mapTokenPairInfo[theId].toChainID == chainID2) ||
    //         (mapTokenPairInfo[theId].toChainID == chainID1) && (mapTokenPairInfo[theId].fromChainID == chainID2)) {
    //             id_valid[cnt] = theId;
    //             cnt ++;
    //         }
    //     }

    //     tokenPairs = new TokenPairInfoFull[](cnt);
    //     for (i = 0; i < cnt; i++) {
    //         theId = id_valid[i];
    //         tokenPairs[i].aInfo = mapTokenPairInfo[theId].aInfo;
    //         tokenPairs[i].fromChainID = mapTokenPairInfo[theId].fromChainID;
    //         tokenPairs[i].fromAccount = mapTokenPairInfo[theId].fromAccount;
    //         tokenPairs[i].toChainID = mapTokenPairInfo[theId].toChainID;
    //         tokenPairs[i].toAccount = mapTokenPairInfo[theId].toAccount;
    //         tokenPairs[i].id = theId;
    //     }
    // }

    function getTokenPairs()
        external
        view
        returns (uint[] id, uint[] fromChainID, bytes[] fromAccount, uint[] toChainID, bytes[] toAccount,
          string[] ancestorSymbol, uint8[] ancestorDecimals, bytes[] ancestorAccount, string[] ancestorName, uint[] ancestorChainID)
    {
        uint cnt = totalTokenPairs;
        uint theId = 0;
        uint i = 0;

        id = new uint[](cnt);
        fromChainID = new uint[](cnt);
        fromAccount = new bytes[](cnt);
        toChainID = new uint[](cnt);
        toAccount = new bytes[](cnt);

        ancestorSymbol = new string[](cnt);
        ancestorDecimals = new uint8[](cnt);

        ancestorAccount = new bytes[](cnt);
        ancestorName = new string[](cnt);
        ancestorChainID = new uint[](cnt);

        i = 0;
        theId = 0;
        uint j = 0;
        for (; j < totalTokenPairs; j++) {
            theId = mapTokenPairIndex[j];
            id[i] = theId;
            fromChainID[i] = mapTokenPairInfo[theId].fromChainID;
            fromAccount[i] = mapTokenPairInfo[theId].fromAccount;
            toChainID[i] = mapTokenPairInfo[theId].toChainID;
            toAccount[i] = mapTokenPairInfo[theId].toAccount;

            ancestorSymbol[i] = mapTokenPairInfo[theId].aInfo.symbol;
            ancestorDecimals[i] = mapTokenPairInfo[theId].aInfo.decimals;

            ancestorAccount[i] = mapTokenPairInfo[theId].aInfo.account;
            ancestorName[i] = mapTokenPairInfo[theId].aInfo.name;
            ancestorChainID[i] = mapTokenPairInfo[theId].aInfo.chainID;
            i ++;
        }
    }

    function getTokenPairsByChainID(uint chainID1, uint chainID2)
        external
        view
        returns (uint[] id, uint[] fromChainID, bytes[] fromAccount, uint[] toChainID, bytes[] toAccount,
          string[] ancestorSymbol, uint8[] ancestorDecimals, bytes[] ancestorAccount, string[] ancestorName, uint[] ancestorChainID)
    {
        uint cnt = 0;
        uint i = 0;
        uint theId = 0;
        uint[] memory id_valid = new uint[](totalTokenPairs);
        for (; i < totalTokenPairs; i++ ) {
            theId = mapTokenPairIndex[i];
            if ((mapTokenPairInfo[theId].fromChainID == chainID1) && (mapTokenPairInfo[theId].toChainID == chainID2) ||
            (mapTokenPairInfo[theId].toChainID == chainID1) && (mapTokenPairInfo[theId].fromChainID == chainID2)) {
                id_valid[cnt] = theId;
                cnt ++;
            }
        }

        id = new uint[](cnt);
        fromChainID = new uint[](cnt);
        fromAccount = new bytes[](cnt);
        toChainID = new uint[](cnt);
        toAccount = new bytes[](cnt);

        ancestorSymbol = new string[](cnt);
        ancestorDecimals = new uint8[](cnt);

        ancestorAccount = new bytes[](cnt);
        ancestorName = new string[](cnt);
        ancestorChainID = new uint[](cnt);

        for (i = 0; i < cnt; i++) {
            theId = id_valid[i];

            id[i] = theId;
            fromChainID[i] = mapTokenPairInfo[theId].fromChainID;
            fromAccount[i] = mapTokenPairInfo[theId].fromAccount;
            toChainID[i] = mapTokenPairInfo[theId].toChainID;
            toAccount[i] = mapTokenPairInfo[theId].toAccount;

            ancestorSymbol[i] = mapTokenPairInfo[theId].aInfo.symbol;
            ancestorDecimals[i] = mapTokenPairInfo[theId].aInfo.decimals;
            
            ancestorAccount[i] = mapTokenPairInfo[theId].aInfo.account;
            ancestorName[i] = mapTokenPairInfo[theId].aInfo.name;
            ancestorChainID[i] = mapTokenPairInfo[theId].aInfo.chainID;
        }
    }
}
          

contracts/crossApproach/CrossStorageV4.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "./CrossStorageV3.sol";

contract CrossStorageV4 is CrossStorageV3 {

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/
     uint internal maxBatchSize;
}
          

contracts/interfaces/ISignatureVerifier.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface ISignatureVerifier {
  function verify(
        uint curveId,
        bytes32 signature,
        bytes32 groupKeyX,
        bytes32 groupKeyY,
        bytes32 randomPointX,
        bytes32 randomPointY,
        bytes32 message
    ) external returns (bool);
}
          

contracts/crossApproach/CrossStorageV3.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "./CrossStorageV2.sol";

contract CrossStorageV3 is CrossStorageV2 {

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    /** STATE VARIABLES **/
    // tokenPairID => fee
    mapping(uint256 => uint256) mapTokenPairContractFee;

    struct SetTokenPairFeesParam {
        uint256 tokenPairID;
        uint256 contractFee;
    }

}
          

contracts/test/TestOrigTokenCreator.sol

pragma solidity ^0.4.24;

import "../interfaces/IMappingToken.sol";
import "../tokenManager/MappingToken.sol";
import "../components/WRC20Protocol.sol";
import "../components/BasicStorage.sol";
import "./TestIOwned.sol";

contract TestOrigTokenCreator is BasicStorage {
    address _admin;

    modifier onlyAdmin {
        require(_admin != address(0), "admin is null");
        _;
    }

    function setAdmin(address admin) external {
        _admin = admin;
    }

    function getAdmin() external view returns (address) {
        return _admin;
    }

    function createToken(string tokenName, string tokenSymbol, uint8 tokenDecimal) external {
        address tokenInst = new MappingToken(tokenName, tokenSymbol, tokenDecimal);
        addressData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenInst);
        uintData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenDecimal);
        // TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function changeOwner(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function acceptOwnership(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).acceptOwnership();
    }

    function getTokenAddr(string tokenName, string tokenSymbol) external view returns (address) {
        return addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
    }

    function mintToken(string tokenName, string tokenSymbol, address to, uint value) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        IMappingToken(tokenInst).mint(to, value);
    }

    function burnToken(string tokenName, string tokenSymbol, address from, uint value) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        IMappingToken(tokenInst).burn(from, value);
    }

    function tokenBalance(string tokenName, string tokenSymbol, address owner) external view returns (uint balance) {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        balance = WRC20Protocol(tokenInst).balanceOf(owner);
    }

    function getTokenDecimal(string tokenName, string tokenSymbol) external view returns (uint8) {
        return uint8(uintData.getStorage(bytes(tokenName), bytes(tokenSymbol)));
    }

    function destroyToken(string tokenName, string tokenSymbol) external {
        addressData.delStorage(bytes(tokenName), bytes(tokenSymbol));
        uintData.delStorage(bytes(tokenName), bytes(tokenSymbol));
    }
}
          

contracts/crossApproach/lib/RapidityLibV4.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./RapidityTxLib.sol";
import "./CrossTypesV1.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/IRC20Protocol.sol";

library RapidityLibV4 {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    enum TokenCrossType {ERC20, ERC721, ERC1155}

    /**
    *
    * STRUCTURES
    *
    */

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapidityUserLockParams {
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        uint currentChainID;              /// current chain ID
        uint tokenPairContractFee;        /// fee of token pair
        bytes destUserAccount;            /// account of shadow chain, used to receive token
        address smgFeeProxy;              /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapiditySmgMintParams {
        bytes32 uniqueID;                 /// Rapidity random number
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        uint fee;                         /// exchange token fee
        address destTokenAccount;         /// shadow token account
        address destUserAccount;          /// account of shadow chain, used to receive token
        address smgFeeProxy;              /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapidityUserBurnParams {
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint currentChainID;            /// current chain ID
        uint fee;                       /// exchange token fee
        uint tokenPairContractFee;      /// fee of token pair
        address srcTokenAccount;        /// shadow token account
        bytes destUserAccount;          /// account of token destination chain, used to receive token
        address smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapiditySmgReleaseParams {
        bytes32 uniqueID;               /// Rapidity random number
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint fee;                       /// exchange token fee
        address destTokenAccount;       /// original token/coin account
        address destUserAccount;        /// account of token original chain, used to receive token
        address smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /**
     *
     * EVENTS
     *
     **/


    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity original token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserLockLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity shadow token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserBurnLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, uint fee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity shadow token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgMintLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);
    event SmgMint(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity original token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgReleaseLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);
    event SmgRelease(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, string[] keys, bytes[] values);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                         mintBridge, user lock token on token original chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user mint lock token on token original chain
    function userLock(CrossTypesV1.Data storage storageData, RapidityUserLockParams memory params)
    public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint contractFee = params.tokenPairContractFee;
        address tokenScAddr;
        if (params.currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);
        } else if (params.currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(toTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        uint left;
        if (tokenScAddr == address(0)) {
            left = (msg.value).sub(params.value).sub(contractFee);
        } else {
            left = (msg.value).sub(contractFee);

            uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
            require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
            require(CrossTypesV1.transferFrom(tokenScAddr, msg.sender, address(this), params.value), "Lock token failed");
        }
        if (left != 0) {
            (msg.sender).transfer(left);
        }
        emit UserLockLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.destUserAccount);
    }

    /// @notice                         burnBridge, user lock token on token original chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user burn lock token on token original chain
    function userBurn(CrossTypesV1.Data storage storageData, RapidityUserBurnParams memory params)
    public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint256 contractFee = params.tokenPairContractFee;
        address tokenScAddr;
        if (params.currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(toTokenAccount);
        } else if (params.currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        require(params.srcTokenAccount == tokenScAddr, "Invalid token account");

        // Reuse variable fromChainID as tokenCrossType; burn token by tokenCrossType
        fromChainID = tokenManager.mapTokenPairType(params.tokenPairID);
        require(fromChainID == uint8(TokenCrossType.ERC20), "Not support");
        require(burnShadowToken(tokenManager, tokenScAddr, msg.sender, params.value), "Burn failed");

        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        uint left = (msg.value).sub(contractFee);
        if (left != 0) {
            (msg.sender).transfer(left);
        }

        emit UserBurnLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.fee, params.destUserAccount);
    }

    /// @notice                         mintBridge, storeman mint lock token on token shadow chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman mint lock token on token shadow chain
    function smgMint(CrossTypesV1.Data storage storageData, RapiditySmgMintParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        ITokenManager tokenManager = storageData.tokenManager;
        uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
        require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
        if (params.fee > 0) {
            require(mintShadowToken(tokenManager, params.destTokenAccount, params.smgFeeProxy, params.fee), "Mint fee failed");
        }
        require(mintShadowToken(tokenManager, params.destTokenAccount, params.destUserAccount, params.value), "Mint failed");

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);
        keys[0] = "value:uint256";
        values[0] = abi.encodePacked(params.value);
        keys[1] = "tokenAccount:address";
        values[1] = abi.encodePacked(params.destTokenAccount);
        keys[2] = "userAccount:address";
        values[2] = abi.encodePacked(params.destUserAccount);
        keys[3] = "fee:uint256";
        values[3] = abi.encodePacked(params.fee);
        emit SmgMint(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
        emit SmgMintLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    /// @notice                         burnBridge, storeman burn lock token on token shadow chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman burn lock token on token shadow chain
    function smgRelease(CrossTypesV1.Data storage storageData, RapiditySmgReleaseParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (params.destTokenAccount == address(0)) {
            (params.destUserAccount).transfer(params.value);
            if (params.fee > 0) {
                params.smgFeeProxy.transfer(params.fee);
            }
        } else {
            uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
            require(tokenCrossType == uint8(TokenCrossType.ERC20), "Not support");
            if (params.fee > 0) {
                require(CrossTypesV1.transfer(params.destTokenAccount, params.smgFeeProxy, params.fee), "Transfer token fee failed");
            }
            require(CrossTypesV1.transfer(params.destTokenAccount, params.destUserAccount, params.value), "Transfer token failed");
        }

        string[] memory keys = new string[](4);
        bytes[] memory values = new bytes[](4);
        keys[0] = "value:uint256";
        values[0] = abi.encodePacked(params.value);
        keys[1] = "tokenAccount:address";
        values[1] = abi.encodePacked(params.destTokenAccount);
        keys[2] = "userAccount:address";
        values[2] = abi.encodePacked(params.destUserAccount);
        keys[3] = "fee:uint256";
        values[3] = abi.encodePacked(params.fee);
        emit SmgRelease(params.uniqueID, params.smgID, params.tokenPairID, keys, values);
        emit SmgReleaseLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.destTokenAccount, params.destUserAccount);
    }

    function burnShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(value);
    }

    function mintShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(value);
    }
}
          

contracts/crossApproach/lib/HTLCTxLib.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';

library HTLCTxLib {
    using SafeMath for uint;

    /**
     *
     * ENUMS
     *
     */

    /// @notice tx info status
    /// @notice uninitialized,locked,redeemed,revoked
    enum TxStatus {None, Locked, Redeemed, Revoked, AssetLocked, DebtLocked}

    /**
     *
     * STRUCTURES
     *
     */

    /// @notice struct of HTLC user mint lock parameters
    struct HTLCUserParams {
        bytes32 xHash;                  /// hash of HTLC random number
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint lockFee;                   /// exchange token value
        uint lockedTime;                /// HTLC lock time
    }

    /// @notice HTLC(Hashed TimeLock Contract) tx info
    struct BaseTx {
        bytes32 smgID;                  /// HTLC transaction storeman ID
        uint lockedTime;                /// HTLC transaction locked time
        uint beginLockedTime;           /// HTLC transaction begin locked time
        TxStatus status;                /// HTLC transaction status
    }

    /// @notice user  tx info
    struct UserTx {
        BaseTx baseTx;
        uint tokenPairID;
        uint value;
        uint fee;
        address userAccount;            /// HTLC transaction sender address for the security check while user's revoke
    }
    /// @notice storeman  tx info
    struct SmgTx {
        BaseTx baseTx;
        uint tokenPairID;
        uint value;
        address  userAccount;          /// HTLC transaction user address for the security check while user's redeem
    }
    /// @notice storeman  debt tx info
    struct DebtTx {
        BaseTx baseTx;
        bytes32 srcSmgID;              /// HTLC transaction sender(source storeman) ID
    }

    struct Data {
        /// @notice mapping of hash(x) to UserTx -- xHash->htlcUserTxData
        mapping(bytes32 => UserTx) mapHashXUserTxs;

        /// @notice mapping of hash(x) to SmgTx -- xHash->htlcSmgTxData
        mapping(bytes32 => SmgTx) mapHashXSmgTxs;

        /// @notice mapping of hash(x) to DebtTx -- xHash->htlcDebtTxData
        mapping(bytes32 => DebtTx) mapHashXDebtTxs;

    }

    /**
     *
     * MANIPULATIONS
     *
     */

    /// @notice                     add user transaction info
    /// @param params               parameters for user tx
    function addUserTx(Data storage self, HTLCUserParams memory params)
        public
    {
        UserTx memory userTx = self.mapHashXUserTxs[params.xHash];
        // UserTx storage userTx = self.mapHashXUserTxs[params.xHash];
        // require(params.value != 0, "Value is invalid");
        require(userTx.baseTx.status == TxStatus.None, "User tx exists");

        userTx.baseTx.smgID = params.smgID;
        userTx.baseTx.lockedTime = params.lockedTime;
        userTx.baseTx.beginLockedTime = now;
        userTx.baseTx.status = TxStatus.Locked;
        userTx.tokenPairID = params.tokenPairID;
        userTx.value = params.value;
        userTx.fee = params.lockFee;
        userTx.userAccount = msg.sender;

        self.mapHashXUserTxs[params.xHash] = userTx;
    }

    /// @notice                     refund coins from HTLC transaction, which is used for storeman redeem(outbound)
    /// @param x                    HTLC random number
    function redeemUserTx(Data storage self, bytes32 x)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        require(userTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(now < userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime), "Redeem timeout");

        userTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /// @notice                     revoke user transaction
    /// @param  xHash               hash of HTLC random number
    function revokeUserTx(Data storage self, bytes32 xHash)
        external
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        require(userTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(now >= userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime), "Revoke is not permitted");

        userTx.baseTx.status = TxStatus.Revoked;
    }

    /// @notice                    function for get user info
    /// @param xHash               hash of HTLC random number
    /// @return smgID              ID of storeman which user has selected
    /// @return tokenPairID        token pair ID of cross chain
    /// @return value              exchange value
    /// @return fee                exchange fee
    /// @return userAccount        HTLC transaction sender address for the security check while user's revoke
    function getUserTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, uint, uint, uint, address)
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        return (userTx.baseTx.smgID, userTx.tokenPairID, userTx.value, userTx.fee, userTx.userAccount);
    }

    /// @notice                     add storeman transaction info
    /// @param  xHash               hash of HTLC random number
    /// @param  smgID               ID of the storeman which user has selected
    /// @param  tokenPairID         token pair ID of cross chain
    /// @param  value               HTLC transfer value of token
    /// @param  userAccount            user account address on the destination chain, which is used to redeem token
    function addSmgTx(Data storage self, bytes32 xHash, bytes32 smgID, uint tokenPairID, uint value, address userAccount, uint lockedTime)
        external
    {
        SmgTx memory smgTx = self.mapHashXSmgTxs[xHash];
        // SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(value != 0, "Value is invalid");
        require(smgTx.baseTx.status == TxStatus.None, "Smg tx exists");

        smgTx.baseTx.smgID = smgID;
        smgTx.baseTx.status = TxStatus.Locked;
        smgTx.baseTx.lockedTime = lockedTime;
        smgTx.baseTx.beginLockedTime = now;
        smgTx.tokenPairID = tokenPairID;
        smgTx.value = value;
        smgTx.userAccount = userAccount;

        self.mapHashXSmgTxs[xHash] = smgTx;
    }

    /// @notice                     refund coins from HTLC transaction, which is used for users redeem(inbound)
    /// @param x                    HTLC random number
    function redeemSmgTx(Data storage self, bytes32 x)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(smgTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(now < smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime), "Redeem timeout");

        smgTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /// @notice                     revoke storeman transaction
    /// @param  xHash               hash of HTLC random number
    function revokeSmgTx(Data storage self, bytes32 xHash)
        external
    {
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        require(smgTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(now >= smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime), "Revoke is not permitted");

        smgTx.baseTx.status = TxStatus.Revoked;
    }

    /// @notice                     function for get smg info
    /// @param xHash                hash of HTLC random number
    /// @return smgID               ID of storeman which user has selected
    /// @return tokenPairID         token pair ID of cross chain
    /// @return value               exchange value
    /// @return userAccount            user account address for redeem
    function getSmgTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, uint, uint, address)
    {
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        return (smgTx.baseTx.smgID, smgTx.tokenPairID, smgTx.value, smgTx.userAccount);
    }

    /// @notice                     add storeman transaction info
    /// @param  xHash               hash of HTLC random number
    /// @param  srcSmgID            ID of source storeman group
    /// @param  destSmgID           ID of the storeman which will take over of the debt of source storeman group
    /// @param  lockedTime          HTLC lock time
    /// @param  status              Status, should be 'Locked' for asset or 'DebtLocked' for debt
    function addDebtTx(Data storage self, bytes32 xHash, bytes32 srcSmgID, bytes32 destSmgID, uint lockedTime, TxStatus status)
        external
    {
        DebtTx memory debtTx = self.mapHashXDebtTxs[xHash];
        // DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        require(debtTx.baseTx.status == TxStatus.None, "Debt tx exists");

        debtTx.baseTx.smgID = destSmgID;
        debtTx.baseTx.status = status;//TxStatus.Locked;
        debtTx.baseTx.lockedTime = lockedTime;
        debtTx.baseTx.beginLockedTime = now;
        debtTx.srcSmgID = srcSmgID;

        self.mapHashXDebtTxs[xHash] = debtTx;
    }

    /// @notice                     refund coins from HTLC transaction
    /// @param x                    HTLC random number
    /// @param status               Status, should be 'Locked' for asset or 'DebtLocked' for debt
    function redeemDebtTx(Data storage self, bytes32 x, TxStatus status)
        external
        returns(bytes32 xHash)
    {
        xHash = sha256(abi.encodePacked(x));

        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        // require(debtTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(debtTx.baseTx.status == status, "Status is not locked");
        require(now < debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime), "Redeem timeout");

        debtTx.baseTx.status = TxStatus.Redeemed;

        return xHash;
    }

    /// @notice                     revoke debt transaction, which is used for source storeman group
    /// @param  xHash               hash of HTLC random number
    /// @param  status              Status, should be 'Locked' for asset or 'DebtLocked' for debt
    function revokeDebtTx(Data storage self, bytes32 xHash, TxStatus status)
        external
    {
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        // require(debtTx.baseTx.status == TxStatus.Locked, "Status is not locked");
        require(debtTx.baseTx.status == status, "Status is not locked");
        require(now >= debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime), "Revoke is not permitted");

        debtTx.baseTx.status = TxStatus.Revoked;
    }

    /// @notice                     function for get debt info
    /// @param xHash                hash of HTLC random number
    /// @return srcSmgID            ID of source storeman
    /// @return destSmgID           ID of destination storeman
    function getDebtTx(Data storage self, bytes32 xHash)
        external
        view
        returns (bytes32, bytes32)
    {
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        return (debtTx.srcSmgID, debtTx.baseTx.smgID);
    }

    function getLeftTime(uint endTime) private view returns (uint) {
        if (now < endTime) {
            return endTime.sub(now);
        }
        return 0;
    }

    /// @notice                     function for get debt info
    /// @param xHash                hash of HTLC random number
    /// @return leftTime            the left lock time
    function getLeftLockedTime(Data storage self, bytes32 xHash)
        external
        view
        returns (uint)
    {
        UserTx storage userTx = self.mapHashXUserTxs[xHash];
        if (userTx.baseTx.status != TxStatus.None) {
            return getLeftTime(userTx.baseTx.beginLockedTime.add(userTx.baseTx.lockedTime));
        }
        SmgTx storage smgTx = self.mapHashXSmgTxs[xHash];
        if (smgTx.baseTx.status != TxStatus.None) {
            return getLeftTime(smgTx.baseTx.beginLockedTime.add(smgTx.baseTx.lockedTime));
        }
        DebtTx storage debtTx = self.mapHashXDebtTxs[xHash];
        if (debtTx.baseTx.status != TxStatus.None) {
            return getLeftTime(debtTx.baseTx.beginLockedTime.add(debtTx.baseTx.lockedTime));
        }
        require(false, 'invalid xHash');
    }
}
          

contracts/storemanGroupAdmin/StoremanLib.sol

pragma solidity ^0.4.24;

import "./StoremanType.sol";
import "./StoremanUtil.sol";
import "../interfaces/IListGroup.sol";


library StoremanLib {
    using Deposit for Deposit.Records;
    using SafeMath for uint;

    uint constant MaxPartnerCount = 5;
    event stakeInEvent(bytes32 indexed groupId,address indexed wkAddr, address indexed from, uint  value);
    event stakeAppendEvent(address indexed wkAddr, address indexed from, uint indexed value);
    event stakeOutEvent(address indexed wkAddr, address indexed from);
    event stakeClaimEvent(address indexed wkAddr, address indexed from,bytes32 indexed groupId, uint value);
    event stakeIncentiveClaimEvent(address indexed wkAddr,address indexed sender,uint indexed amount);
    event stakeIncentiveCrossFeeEvent(address indexed wkAddr,address indexed sender,uint indexed amount);

    event storemanTransferEvent(bytes32 indexed groupId, bytes32 indexed preGroupId, address[] wkAddrs);
    event StoremanGroupUnregisterEvent(bytes32 indexed groupId);
    event delegateInEvent(address indexed wkAddr, address indexed from, uint indexed value);
    event delegateOutEvent(address indexed wkAddr, address indexed from);
    event delegateClaimEvent(address indexed wkAddr, address indexed from, uint256 indexed amount);
    event delegateIncentiveClaimEvent(address indexed wkAddr,address indexed sender,uint indexed amount);
    event partInEvent(address indexed wkAddr, address indexed from, uint indexed value);
    event partOutEvent(address indexed wkAddr, address indexed from);
    event partClaimEvent(address indexed wkAddr, address indexed from, uint256 indexed amount);

    function storemanGroupUnregister(StoremanType.StoremanData storage data,bytes32 groupId)
        external
    {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(now > group.workTime + group.totalTime, "not expired");
        require(group.status == StoremanType.GroupStatus.ready,"Invalid status");
        group.status = StoremanType.GroupStatus.unregistered;
        emit StoremanGroupUnregisterEvent(groupId);
    }

    function deleteStoremanNode(StoremanType.StoremanData storage data, address wkAddr) private {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        if(sk.deposit.getLastValue() == 0  && sk.delegatorCount == 0 && sk.partnerCount == 0) {
            delete data.candidates[0][wkAddr];
        }
    }

    function stakeIn(StoremanType.StoremanData storage data, bytes32 groupId, bytes PK, bytes enodeID) external
    {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(group.status == StoremanType.GroupStatus.curveSeted,"invalid group");
        require(now <= group.registerTime+group.registerDuration,"Registration closed");
        require(msg.value >= group.minStakeIn, "Too small value in stake");
        require(StoremanUtil.onCurve(PK), "invalid PK");
        require(StoremanUtil.onCurve(enodeID), "invalid enodeID");
        address wkAddr = address(keccak256(PK));
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        if(sk.sender != address(0x00)){
            deleteStoremanNode(data, wkAddr);
            sk = data.candidates[0][wkAddr];
        }
        require(sk.sender == address(0x00), "Candidate has existed");
        sk.sender = msg.sender;
        sk.enodeID = enodeID;
        sk.PK = PK;
        sk.wkAddr = wkAddr;
        sk.groupId = groupId;
        sk.deposit = Deposit.Records(0);
        sk.deposit.addRecord(Deposit.Record(StoremanUtil.getDaybyTime(data.posLib, now), msg.value));

        // only not whitelist address need add memberCount;
        if(!isWorkingNodeInGroup(group, wkAddr)) {
            group.skMap[group.memberCount] = sk.wkAddr;
            group.memberCount++;
        }

        // check if it is white
        if(group.whiteWk[wkAddr] != address(0x00)){
            if(group.whiteWk[wkAddr] != msg.sender){
                revert("invalid sender");
            }
            sk.isWhite = true;

            
            // check if it is a backup whitelist, if yes, change it's groupId to 0.
            for(uint i=group.whiteCount; i<group.whiteCountAll; i++) {
                if(group.whiteMap[i] == wkAddr){
                    sk.groupId = bytes32(0x00);
                    break;
                }
            }
        } else {
            realInsert(data,group, wkAddr, StoremanUtil.calSkWeight(data.conf.standaloneWeight, msg.value));
        }

        emit stakeInEvent(groupId, wkAddr, msg.sender, msg.value);
    }

    function stakeAppend(StoremanType.StoremanData storage data,  address wkAddr) external  {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        require(sk.sender == msg.sender, "Only the sender can stakeAppend");
        uint amount = sk.deposit.getLastValue();
        require(amount != 0, "Claimed");
        
        uint day = StoremanUtil.getDaybyTime(data.posLib, now);
        Deposit.Record memory r = Deposit.Record(day, msg.value);
        Deposit.Record memory rw = Deposit.Record(day, StoremanUtil.calSkWeight(data.conf.standaloneWeight, msg.value));
        sk.deposit.addRecord(r);
        StoremanType.StoremanGroup storage  group = data.groups[sk.groupId];
        StoremanType.StoremanGroup storage  nextGroup = data.groups[sk.nextGroupId];
        updateGroup(data, sk, group, r, rw);
        updateGroup(data, sk, nextGroup, r, rw);
        emit stakeAppendEvent(wkAddr, msg.sender,msg.value);
    }

    function checkCanStakeOut(StoremanType.StoremanData storage data,  address wkAddr) public returns(bool){
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        StoremanType.StoremanGroup storage  group = data.groups[sk.groupId];
        StoremanType.StoremanGroup storage  nextGroup = data.groups[sk.nextGroupId];
        // if a group haven't selected, can't quit.
        // if the sk joined in the next group, and the next group haven't selected, cannot quit. 
        //else change the flag quited==true
        if(group.status < StoremanType.GroupStatus.selected) {
            return false;
        }
        if(nextGroup.status != StoremanType.GroupStatus.none) {
            if(nextGroup.status < StoremanType.GroupStatus.selected){
                return false;
            }
        }
        return true;
    }
    function stakeOut(StoremanType.StoremanData storage data,  address wkAddr) external {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.sender == msg.sender, "Only the sender can stakeOut");
        require(checkCanStakeOut(data, wkAddr),"selecting");
        sk.quited = true;
        emit stakeOutEvent(wkAddr, msg.sender);
    }

    function isWorkingNodeInGroup(StoremanType.StoremanGroup storage group, address wkAddr) public  view returns (bool) {
        uint count = group.selectedCount;
        for(uint8 i = 0; i < count; i++) {
            if(wkAddr == group.selectedNode[i]) {
                return true;
            }
        }
        return false;
    }

    function checkCanStakeClaimFromGroup(address posLib, StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage group) private returns (bool) {
        // if group haven't selected, can't claim 
        // if group failed, can claim. 
        // if group selected and the sk haven't been selected, can claim.
        // if group selected and the sk was selected, then, must 1, group is dismissed. 2. incentived.
        if(group.status == StoremanType.GroupStatus.none) {
            return true; // group does not exist.
        }
        if(group.status == StoremanType.GroupStatus.failed) {
            return true; // group failed
        }
        if(group.status < StoremanType.GroupStatus.selected) {
            return false;
        }
        if(!isWorkingNodeInGroup(group, sk.wkAddr)){
            return true;
        } else {
            if(group.status == StoremanType.GroupStatus.dismissed
            && sk.incentivedDay+1 >= StoremanUtil.getDaybyTime(posLib, group.workTime+group.totalTime) ) {
                return true;
            }
        }
        return false;
    }
    function checkCanStakeClaim(StoremanType.StoremanData storage data, address wkAddr) public returns(bool) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        if(sk.wkAddr != wkAddr){ // sk doesn't exist.
            return false;
        }
        StoremanType.StoremanGroup storage  group = data.groups[sk.groupId];
        StoremanType.StoremanGroup storage  nextGroup = data.groups[sk.nextGroupId];
        if(checkCanStakeClaimFromGroup(data.posLib, sk, group) && checkCanStakeClaimFromGroup(data.posLib, sk, nextGroup)){
            return true;
        } else {
            return false;
        }
    }

    function stakeClaim(StoremanType.StoremanData storage data, address wkAddr) external {
        require(checkCanStakeClaim(data,wkAddr),"Cannot claim");
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        uint amount = sk.deposit.getLastValue();
        require(amount != 0, "Claimed");
        sk.deposit.clean();

        // slash the node
        if(sk.slashedCount >= data.conf.maxSlashedCount) {
            amount = 0;
        } else {
            amount = amount.mul(data.conf.maxSlashedCount.sub(sk.slashedCount)).div(data.conf.maxSlashedCount);
        }
        emit stakeClaimEvent(wkAddr, sk.sender, sk.groupId, amount);

        // the cross chain fee
        emit stakeIncentiveCrossFeeEvent(wkAddr, sk.sender, sk.crossIncoming);
        amount = amount.add(sk.crossIncoming);
        sk.crossIncoming = 0;

        // the incentive
        emit stakeIncentiveClaimEvent(wkAddr,sk.sender,sk.incentive[0]);
        amount = amount.add(sk.incentive[0]);
        sk.incentive[0] = 0;
        sk.quited = true;

        if(amount != 0){
            sk.sender.transfer(amount);
        }
    }

    function stakeIncentiveClaim(StoremanType.StoremanData storage data, address wkAddr) external {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");

        uint amount = sk.incentive[0];
        sk.incentive[0] = 0;

        if(amount != 0){
            sk.sender.transfer(amount);
        }
        emit stakeIncentiveClaimEvent(wkAddr,sk.sender,amount);
    }

    function realInsert(StoremanType.StoremanData storage data, StoremanType.StoremanGroup storage  group, address skAddr, uint weight) internal{
        for (uint i = group.whiteCount; i < group.selectedCount; i++) {
            StoremanType.Candidate storage cmpNode = data.candidates[0][group.selectedNode[i]];
            if (cmpNode.wkAddr == skAddr) { // keep self position, do not sort
                return;
            }
            uint cmpWeight = StoremanUtil.calSkWeight(data.conf.standaloneWeight, cmpNode.deposit.getLastValue().add(cmpNode.partnerDeposit)).add(cmpNode.delegateDeposit);
            if (weight > cmpWeight) {
                break;
            }
        }
        if (i < group.memberCountDesign) {
            address curAddr = group.selectedNode[i]; // must not be skAddr
            for (uint j = i; j < group.selectedCount; j++) {
                if (j + 1 < group.memberCountDesign) {
                    address nextAddr = group.selectedNode[j + 1];
                    group.selectedNode[j + 1] = curAddr;
                    if (nextAddr != skAddr) {
                        curAddr = nextAddr;
                    } else {
                        break;
                    }
                }
            }
            // insert or move to place i
            group.selectedNode[i] = skAddr;
            if ((group.selectedCount < group.memberCountDesign) && (j == group.selectedCount)) {
                group.selectedCount++;
            }
        }
    }

    function updateGroup(StoremanType.StoremanData storage data,StoremanType.Candidate storage sk, StoremanType.StoremanGroup storage  group, Deposit.Record r, Deposit.Record rw) internal {
        //if haven't selected, need not update group. 
        // if selected, need to update group. 
        if(group.status == StoremanType.GroupStatus.none){ // not exist group.
            return;
        }
        //address wkAddr = sk.wkAddr;

        if(group.status == StoremanType.GroupStatus.curveSeted) {
            if(group.whiteWk[sk.wkAddr] == address(0x00)){
                realInsert(data, group, sk.wkAddr, StoremanUtil.calSkWeight(data.conf.standaloneWeight, sk.deposit.getLastValue().add(sk.partnerDeposit)).add(sk.delegateDeposit));
            }            
        } else {
            if(isWorkingNodeInGroup(group, sk.wkAddr)){
                group.deposit.addRecord(r);
                group.depositWeight.addRecord(rw);
            }
        }
    }
    function delegateIn(StoremanType.StoremanData storage data, address wkAddr)
        external
    {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        StoremanType.StoremanGroup storage  group = data.groups[sk.groupId];
        StoremanType.StoremanGroup storage  nextGroup = data.groups[sk.nextGroupId];
        require(msg.value >= group.minDelegateIn, "Too small value");

        //require(sk.delegateDeposit.add(msg.value) <= sk.deposit.getLastValue().mul(data.conf.DelegationMulti), "Too many delegation");

        require(sk.delegateDeposit.add(msg.value) <= (sk.deposit.getLastValue().add(sk.partnerDeposit)).mul(data.conf.DelegationMulti), "Too many delegation");

        StoremanType.Delegator storage dk = sk.delegators[msg.sender];
        require(dk.quited == false, "Quited");
        if(dk.deposit.getLastValue() == 0) {
            sk.delegatorMap[sk.delegatorCount] = msg.sender;
            dk.index = sk.delegatorCount;
            sk.delegatorCount = sk.delegatorCount.add(1);
            // dk.sender = msg.sender;
            // dk.staker = wkAddr;
        }
        sk.delegateDeposit = sk.delegateDeposit.add(msg.value);
        uint day = StoremanUtil.getDaybyTime(data.posLib, now);
        Deposit.Record memory r = Deposit.Record(day, msg.value);
        dk.deposit.addRecord(r);
        updateGroup(data, sk, group, r, r);
        updateGroup(data, sk, nextGroup, r, r);
        emit delegateInEvent(wkAddr, msg.sender,msg.value);
    }

    // must specify all the whitelist.
    function inheritNode(StoremanType.StoremanData storage data, bytes32 groupId, bytes32 preGroupId, address[] wkAddrs, address[] senders) public
    {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        uint len = 0;
        if(preGroupId != bytes32(0x00)) {
            StoremanType.StoremanGroup storage oldGroup = data.groups[preGroupId];
            len = oldGroup.memberCountDesign * 2;
        }else {
            len = wkAddrs.length;
        }
        address[] memory oldAddr =  new address[](len);
        uint oldCount = 0;
        uint k = 0;

        group.whiteCount = wkAddrs.length.sub(data.conf.backupCount);
        group.whiteCountAll = wkAddrs.length;
        for(k = 0; k < wkAddrs.length; k++){
            group.whiteMap[k] = wkAddrs[k];
            group.whiteWk[wkAddrs[k]] = senders[k];
            StoremanType.Candidate storage skw = data.candidates[0][wkAddrs[k]];
            if(skw.wkAddr != address(0x00)){ // this node has exist
                if(preGroupId != bytes32(0x00)) {
                    require(skw.groupId == bytes32(0x00) || skw.groupId == preGroupId, "Invalid whitelist");
                }
                require(!skw.quited, "Invalid node");
                oldAddr[oldCount] = wkAddrs[k];
                oldCount++;
            }
            if(k < group.whiteCount) {
                group.selectedNode[k] = wkAddrs[k];
                if(skw.groupId==bytes32(0x00)){
                    skw.groupId = groupId;
                } else {
                    skw.nextGroupId = groupId;
                }
            }
        }
        group.selectedCount = group.whiteCount;
        group.memberCount = group.selectedCount;

        if (preGroupId != bytes32(0x00)) {
            oldCount = inheritStaker(data, groupId, preGroupId, oldAddr, oldCount);
        }
        address[] memory oldArray = new address[](oldCount);
        for (k = 0; k < oldCount; k++) {
            oldArray[k] = oldAddr[k];
        }
        emit storemanTransferEvent(groupId, preGroupId, oldArray);
    }

    function inheritStaker(StoremanType.StoremanData storage data, bytes32 groupId, bytes32 preGroupId, address[] oldAddr, uint oldCount) public returns(uint) {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        StoremanType.StoremanGroup storage oldGroup = data.groups[preGroupId];
        uint[] memory stakes = new uint[](oldGroup.memberCountDesign * 2);
        uint k;

        for (k = oldGroup.whiteCount; k < oldGroup.memberCountDesign; k++) {
            address wkAddr = oldGroup.selectedNode[k];
            StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
            if (sk.groupId == preGroupId && !sk.quited && sk.slashedCount == 0 && !sk.isWhite) {
                if (oldGroup.status == StoremanType.GroupStatus.failed){
                    sk.groupId = groupId;
                } else {
                    sk.nextGroupId = groupId;
                }
                group.memberCount++;
                oldAddr[oldCount] = sk.wkAddr;
                stakes[oldCount] = StoremanUtil.calSkWeight(data.conf.standaloneWeight, sk.deposit.getLastValue().add(sk.partnerDeposit)).add(sk.delegateDeposit);
                oldCount++;
            }
        }
        inheritSortedStaker(group, oldAddr, stakes, oldCount.sub(group.memberCount.sub(group.whiteCount)), oldCount);
        return oldCount;
    }

    function inheritSortedStaker(StoremanType.StoremanGroup storage group, address[] addresses, uint[] stakes, uint start, uint end) public {
      while ((group.selectedCount < group.memberCount) && (group.selectedCount < group.memberCountDesign)) {
        uint maxIndex = start;
        for (uint i = (start + 1); i < end; i++) {
          if (stakes[i] > stakes[maxIndex]) {
            maxIndex = i;
          }
        }
        group.selectedNode[group.selectedCount] = addresses[maxIndex];
        group.selectedCount++;
        if (maxIndex == start) {
          start += 1;
        } else {
          stakes[maxIndex] = 0;
        }
      }
    }

    function delegateOut(StoremanType.StoremanData storage data, address wkAddr, address listGroupAddr) external {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        require(checkCanStakeOut(data, wkAddr),"selecting");

        StoremanType.Delegator storage dk = sk.delegators[msg.sender];
        require(dk.quited == false,"Quited");
        require(dk.deposit.getLastValue() != 0, "no deposit");
        dk.quited = true;

        uint amount = dk.deposit.getLastValue();
        sk.delegateDeposit = sk.delegateDeposit.sub(amount);
        IListGroup(listGroupAddr).setDelegateQuitGroupId(wkAddr, msg.sender, sk.groupId, sk.nextGroupId);
        emit delegateOutEvent(wkAddr, msg.sender);
    }

    function delegateClaim(StoremanType.StoremanData storage data, address wkAddr, address listGroupAddr) external {
        require(checkCanDelegatorClaim(data, wkAddr, msg.sender, listGroupAddr),"Cannot claim");

        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage dk = sk.delegators[msg.sender];
        uint amount = dk.deposit.getLastValue();
        require(amount != 0,"not exist");
        dk.deposit.clean();
        emit delegateClaimEvent(wkAddr, msg.sender, amount);
        if(!dk.quited) {
            sk.delegateDeposit = sk.delegateDeposit.sub(amount);
        }
        address lastDkAddr = sk.delegatorMap[sk.delegatorCount.sub(1)];
        StoremanType.Delegator storage lastDk = sk.delegators[lastDkAddr];
        sk.delegatorMap[dk.index] = lastDkAddr;
        lastDk.index = dk.index;

        emit delegateIncentiveClaimEvent(wkAddr,msg.sender,dk.incentive[0]);
        amount = amount.add(dk.incentive[0]);
        dk.incentive[0] = 0;

        sk.delegatorCount = sk.delegatorCount.sub(1);
        delete sk.delegatorMap[sk.delegatorCount];
        delete sk.delegators[msg.sender];    
        IListGroup(listGroupAddr).setDelegateQuitGroupId(wkAddr, msg.sender, bytes32(0x00), bytes32(0x00));   
        msg.sender.transfer(amount);
    }
    

    function delegateIncentiveClaim(StoremanType.StoremanData storage data, address wkAddr) external {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        StoremanType.Delegator storage dk = sk.delegators[msg.sender];
        require(dk.deposit.getLastValue() != 0, "not exist");
        uint amount = dk.incentive[0];
        dk.incentive[0] = 0;

        if(amount!=0){
            msg.sender.transfer(amount);
        }
        emit delegateIncentiveClaimEvent(wkAddr,msg.sender,amount);
    }


    function partIn(StoremanType.StoremanData storage data, address wkAddr)
        external
    {
        uint maxPartnerCount = 5;
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        require(sk.wkAddr == wkAddr, "Candidate doesn't exist");
        StoremanType.StoremanGroup storage  group = data.groups[sk.groupId];
        StoremanType.StoremanGroup storage  nextGroup = data.groups[sk.nextGroupId];
        //require(msg.value >= group.minPartIn, "Too small value");

        StoremanType.Delegator storage pn = sk.partners[msg.sender];
        require(pn.quited == false, "Quited");
        if(pn.deposit.getLastValue() == 0) {

            require(msg.value >= group.minPartIn, "Too small value");

            require(sk.partnerCount<maxPartnerCount,"Too many partners");
            sk.partMap[sk.partnerCount] = msg.sender;
            pn.index = sk.partnerCount;
            sk.partnerCount++;
            // pn.sender = msg.sender;
            // pn.staker = wkAddr;
            sk.partners[msg.sender] = pn;
        }
        sk.partnerDeposit = sk.partnerDeposit.add(msg.value);
        uint day = StoremanUtil.getDaybyTime(data.posLib, now);
        Deposit.Record memory r = Deposit.Record(day, msg.value);
        Deposit.Record memory rw = Deposit.Record(day, StoremanUtil.calSkWeight(data.conf.standaloneWeight, msg.value));
        pn.deposit.addRecord(r);
        updateGroup(data, sk, group, r, rw);
        updateGroup(data, sk, nextGroup, r, rw);
        emit partInEvent(wkAddr, msg.sender, msg.value);
    }

    function partOut(StoremanType.StoremanData storage data, address wkAddr, address listGroupAddr) external {
        require(checkCanStakeOut(data, wkAddr),"selecting");

        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage pn = sk.partners[msg.sender];
        require(pn.quited == false,"Quited");   
        require(pn.deposit.getLastValue() != 0, "Partner doesn't exist");
        pn.quited = true;
        uint amount = pn.deposit.getLastValue();
        sk.partnerDeposit = sk.partnerDeposit.sub(amount);
        IListGroup(listGroupAddr).setPartQuitGroupId(wkAddr, msg.sender, sk.groupId, sk.nextGroupId);
        emit partOutEvent(wkAddr, msg.sender);
    }
    function checkGroupTerminated(StoremanType.StoremanData storage data, bytes32 groupId) public returns(bool){
        if(groupId == bytes32(0x00)) {
            return true;
        }
        StoremanType.StoremanGroup storage  group = data.groups[groupId];
        if(group.status == StoremanType.GroupStatus.none || group.status == StoremanType.GroupStatus.failed || group.status == StoremanType.GroupStatus.dismissed){
            return true;
        }
        return false;
    }
    function checkCanPartnerClaim(StoremanType.StoremanData storage data, address wkAddr, address pnAddr, address listGroupAddr) public returns(bool) {
        if(checkCanStakeClaim(data,wkAddr)){
            return true;
        }
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage pn = sk.partners[pnAddr];
        bytes32 quitGroupId;
        bytes32 quitNextGroupId;
        (quitGroupId,quitNextGroupId) = IListGroup(listGroupAddr).getPartQuitGroupId(wkAddr, pnAddr);
        if(pn.quited && checkGroupTerminated(data, quitGroupId) && checkGroupTerminated(data, quitNextGroupId)){
            return true;
        }
        return false;
    }
    function checkCanDelegatorClaim(StoremanType.StoremanData storage data, address wkAddr, address deAddr, address listGroupAddr) public returns(bool) {
        if(checkCanStakeClaim(data,wkAddr)){
            return true;
        }
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage de = sk.delegators[deAddr];
        bytes32 quitGroupId;
        bytes32 quitNextGroupId;
        (quitGroupId,quitNextGroupId) = IListGroup(listGroupAddr).getDelegateQuitGroupId(wkAddr, deAddr);
        if(de.quited && checkGroupTerminated(data, quitGroupId) && checkGroupTerminated(data, quitNextGroupId)){
            return true;
        }
        return false;
    }    
    function partClaim(StoremanType.StoremanData storage data, address wkAddr, address listGroupAddr) external {
        require(checkCanPartnerClaim(data,wkAddr, msg.sender,listGroupAddr),"Cannot claim");
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage pn = sk.partners[msg.sender];
        uint amount = pn.deposit.getLastValue();
        require(amount != 0, "not exist");
        pn.deposit.clean();
        if(!pn.quited) {
            sk.partnerDeposit = sk.partnerDeposit.sub(amount);
        }
        address lastPnAddr = sk.partMap[sk.partnerCount.sub(1)];
        StoremanType.Delegator storage lastPn = sk.partners[lastPnAddr];
        sk.partMap[pn.index] = lastPnAddr;
        lastPn.index = pn.index;

        sk.partnerCount = sk.partnerCount.sub(1);
        delete sk.partMap[sk.partnerCount];
        delete sk.partners[msg.sender];
        IListGroup(listGroupAddr).setPartQuitGroupId(wkAddr, msg.sender, bytes32(0x00), bytes32(0x00));

        // slash the node
        if(sk.slashedCount >= data.conf.maxSlashedCount) {
            amount = 0;
        } else {
            amount = amount.mul(data.conf.maxSlashedCount.sub(sk.slashedCount)).div(data.conf.maxSlashedCount);
        }

        emit partClaimEvent(wkAddr, msg.sender, amount);
        msg.sender.transfer(amount);
    }
}
          

openzeppelin-eth/contracts/token/ERC721/IERC721.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "../../introspection/IERC165.sol";


/**
 * @title ERC721 Non-Fungible Token Standard basic interface
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721 is Initializable, IERC165 {

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 indexed tokenId
  );
  event Approval(
    address indexed owner,
    address indexed approved,
    uint256 indexed tokenId
  );
  event ApprovalForAll(
    address indexed owner,
    address indexed operator,
    bool approved
  );

  function balanceOf(address owner) public view returns (uint256 balance);
  function ownerOf(uint256 tokenId) public view returns (address owner);

  function approve(address to, uint256 tokenId) public;
  function getApproved(uint256 tokenId)
    public view returns (address operator);

  function setApprovalForAll(address operator, bool _approved) public;
  function isApprovedForAll(address owner, address operator)
    public view returns (bool);

  function transferFrom(address from, address to, uint256 tokenId) public;
  function safeTransferFrom(address from, address to, uint256 tokenId)
    public;

  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes data
  )
    public;
}
          

contracts/metric/MetricDelegate.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "../components/Halt.sol";

import "./MetricStorage.sol";
import "./lib/MetricTypes.sol";
import "../interfaces/IStoremanGroup.sol";
import "../lib/CommonTool.sol";
import "./lib/MetricLib.sol";
import "../interfaces/IPosLib.sol";

contract MetricDelegate is MetricStorage, Halt{
    using SafeMath for uint;
    using MetricLib for MetricTypes.MetricStorageData;

    /**
     *
     * MODIFIERS
     *
     */
    modifier onlyLeader(bytes32 grpId) {
        address leader;
        leader = metricData.getLeader(grpId);
        require(msg.sender == leader, "Not leader");
        _;
    }

    /**
     *
     * MANIPULATIONS
     *
     */
    function getDependence()
    external
    view
    returns (address, address,address)
    {
        return (metricData.config, metricData.smg, metricData.posLib);
    }

    ///=======================================statistic=============================================

    /// @notice                         function for get incentive count of all store man during special epochs
    /// @param grpId                    group id
    /// @param startEpId                start epoch id
    /// @param endEpId                  end epoch id
    function getPrdInctMetric(bytes32 grpId, uint startEpId, uint endEpId)
    external
    view
    returns (uint[]) {
        require(endEpId >= startEpId, "endEpId<startEpId");
        uint[] memory ret;
        uint8 n = getSMCount(grpId);
        ret = new uint[](n);
        for (uint8 i = 0; i < n; i++) {
            for (uint j = startEpId; j <= endEpId; j++) {
                ret[i] = ret[i].add(metricData.mapInctCount[grpId][j][i]);
            }
        }
        return ret;
    }
    /// @notice                         function for get slash count of all store man during special epochs
    /// @param grpId                    group id
    /// @param startEpId                start epoch id
    /// @param endEpId                  end epoch id
    function getPrdSlshMetric(bytes32 grpId, uint startEpId, uint endEpId)
    external
    view
    returns (uint[])
    {
        require(endEpId >= startEpId, "endEpId<startEpId");
        uint[] memory ret;
        uint8 n = getSMCount(grpId);
        ret = new uint[](n);
        for (uint8 i = 0; i < n; i++) {
            for (uint j = startEpId; j <= endEpId; j++) {
                ret[i] = ret[i].add(metricData.mapSlshCount[grpId][j][i]);
            }
        }
        return ret;
    }
    /// @notice                         function for get success count of sign data
    /// @param grpId                    group id
    /// @param epId                     epoch id
    /// @param smIndex                  index of store man
    function getSmSuccCntByEpId(bytes32 grpId, uint epId, uint8 smIndex)
    external
    view
    returns (uint)
    {
        return metricData.mapInctCount[grpId][epId][smIndex];
    }
    /// @notice                         function for get slash count of one store man
    /// @param grpId                    group id
    /// @param epId                     epoch id
    /// @param smIndex                  index of store man
    function getSlshCntByEpId(bytes32 grpId, uint epId, uint8 smIndex)
    external
    view
    returns (uint)
    {
        return metricData.mapSlshCount[grpId][epId][smIndex];
    }

    /// @notice                         function for get R stage slash proof of one store man
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function getRSlshProof(bytes32 grpId, bytes32 hashX, uint8 smIndex)
    external
    view
    returns (MetricTypes.RSlshData)
    {
        return metricData.mapRSlsh[grpId][hashX][smIndex];

    }
    /// @notice                         function for get S stage slash proof of one store man
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param smIndex                  index of store man
    function getSSlshProof(bytes32 grpId, bytes32 hashX, uint8 smIndex)
    external
    view
    returns (MetricTypes.SSlshData)
    {
        return metricData.mapSSlsh[grpId][hashX][smIndex];
    }

    ///=======================================write incentive and slash=============================================

    /// @notice                         function for write incentive data
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param inctData                 incentive store man's bitmap
    function wrInct(bytes32 grpId, bytes32 hashX, uint inctData)
    external
    notHalted
    onlyLeader(grpId)
    {

        require(metricData.mapInct[grpId][hashX].smIndexes == uint(0), 'Duplicate Incentive');

        metricData.mapInct[grpId][hashX].smIndexes = inctData;
        uint8 smCount = getSMCount(grpId);
        uint epochId = getEpochId();

        for (uint8 i = 0; i < smCount; i++) {
            if (checkHamming(inctData, i)) {
                metricData.mapInctCount[grpId][epochId][i] = metricData.mapInctCount[grpId][epochId][i].add(uint(1));
            }
        }
    }
    /// @notice                         function for write R stage slash
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param rslshData                data of slash
    function wrRSlsh(bytes32 grpId, bytes32 hashX, MetricTypes.RSlshData memory rslshData)
    public
    notHalted
    onlyLeader(grpId)
    {
        bool success;
        uint8 smIndex;
        (success, smIndex) = metricData.writeRSlsh(grpId, hashX, rslshData, getSMCount(grpId));
        require(success, 'Fail to write R slsh');

        metricData.recordSmSlash(grpId, smIndex);

        emit SMSlshLogger(grpId, hashX, smIndex, MetricTypes.SlshReason.R);
    }
    /// @notice                         function for write S stage slash
    /// @param grpId                    group id
    /// @param hashX                    hash of the signed data
    /// @param sslshData                data of slash
    function wrSSlsh(bytes32 grpId, bytes32 hashX, MetricTypes.SSlshData memory sslshData)
    public
    notHalted
    onlyLeader(grpId)
    {
        bool success;
        uint8 smIndex;
        (success, smIndex) = metricData.writeSSlsh(grpId, hashX, sslshData, getSMCount(grpId));
        require(success, 'Fail to write S Slsh');

        metricData.recordSmSlash(grpId, smIndex);

        emit SMSlshLogger(grpId, hashX, smIndex, MetricTypes.SlshReason.S);
    }

    /// @notice                         function for set config and smg contract address
    /// @param configAddr               config contract address
    /// @param smgAddr                  smg contract address
    function setDependence(address configAddr, address smgAddr, address posAddr)
    external
    onlyOwner
    {
        require(configAddr != address(0), "Invalid config address");
        require(smgAddr != address(0), "Invalid smg address");
        require(posAddr != address(0), "Invalid posLib address");

        metricData.config = IConfig(configAddr);
        metricData.smg = IStoremanGroup(smgAddr);
        metricData.posLib = IPosLib(posAddr);
    }


    function getSMCount(bytes32 grpId)
    private
    view
    returns (uint8)
    {
        return uint8(metricData.getSMCount(grpId));
    }

    function getEpochId()
    private
    view
    returns (uint)
    {
        return IPosLib(metricData.posLib).getEpochId(now);
    }

    function checkHamming(uint indexes, uint8 smIndex)
    private
    pure
    returns (bool)
    {
        return indexes & (uint(1) << smIndex) != uint(0);
    }

    function() public payable {
        revert("Not support");
    }

}
          

contracts/storemanGroupAdmin/StoremanGroupStorage.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.26;

import "../components/BasicStorage.sol";
import "../interfaces/IMetric.sol";
import "./Deposit.sol";
import "./StoremanType.sol";
import "../interfaces/IQuota.sol";


contract StoremanGroupStorage is BasicStorage {
  address public metric;
  IQuota public quotaInst;
  address  public  createGpkAddr;

  StoremanType.StoremanData data;

  constructor() public {

    uint backupCountDefault = 3;
    uint maxSlashedCount = 2;
    uint standaloneWeightDefault = 15000;
    uint chainTypeCoDefault = 10000;
    uint DelegationMultiDefault = 5;


    data.conf.standaloneWeight = standaloneWeightDefault;
    data.conf.backupCount = backupCountDefault;
    data.conf.chainTypeCoDefault = chainTypeCoDefault;
    data.conf.maxSlashedCount = maxSlashedCount;
    data.conf.DelegationMulti = DelegationMultiDefault;
  }
}
          

openzeppelin-eth/contracts/introspection/ERC165.sol

pragma solidity ^0.4.24;

import "../zos-lib/Initializable.sol";
import "./IERC165.sol";


/**
 * @title ERC165
 * @author Matt Condon (@shrugs)
 * @dev Implements ERC165 using a lookup table.
 */
contract ERC165 is Initializable, IERC165 {

  bytes4 private constant _InterfaceId_ERC165 = 0x01ffc9a7;
  /**
   * 0x01ffc9a7 ===
   *   bytes4(keccak256('supportsInterface(bytes4)'))
   */

  /**
   * @dev a mapping of interface id to whether or not it's supported
   */
  mapping(bytes4 => bool) internal _supportedInterfaces;

  /**
   * @dev A contract implementing SupportsInterfaceWithLookup
   * implement ERC165 itself
   */
  function initialize()
    public
    initializer
  {
    _registerInterface(_InterfaceId_ERC165);
  }

  /**
   * @dev implement supportsInterface(bytes4) using a lookup table
   */
  function supportsInterface(bytes4 interfaceId)
    public
    view
    returns (bool)
  {
    return _supportedInterfaces[interfaceId];
  }

  /**
   * @dev private method for registering an interface
   */
  function _registerInterface(bytes4 interfaceId)
    internal
  {
    require(interfaceId != 0xffffffff);
    _supportedInterfaces[interfaceId] = true;
  }

  uint256[50] private ______gap;
}
          

contracts/interfaces/ICurve.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

interface ICurve {

    function add(uint256 x1, uint256 y1, uint256 x2, uint256 y2) external view returns(uint256 retx, uint256 rety, bool success);

    function mulG(uint256 scalar) external view returns(uint256 x, uint256 y, bool success);

    function calPolyCommit(bytes polyCommit, bytes pk) external view returns(uint256 sx, uint256 sy, bool success);

    function mulPk(uint256 scalar, uint256 xPk, uint256 yPk)
    external
    view
    returns (uint256 x, uint256 y, bool success);

    function equalPt (uint256 xLeft, uint256 yLeft,uint256 xRight, uint256 yRight) external view returns(bool);

    function checkSig (bytes32 hash, bytes32 r, bytes32 s, bytes pk) external view returns(bool);
}
          

contracts/components/Admin.sol

pragma solidity 0.4.26;

import "./Owned.sol";

contract Admin is Owned {
    mapping(address => bool) public mapAdmin;

    event AddAdmin(address admin);
    event RemoveAdmin(address admin);

    modifier onlyAdmin() {
        require(mapAdmin[msg.sender], "not admin");
        _;
    }

    function addAdmin(
        address admin
    )
        external
        onlyOwner
    {
        mapAdmin[admin] = true;

        emit AddAdmin(admin);
    }

    function removeAdmin(
        address admin
    )
        external
        onlyOwner
    {
        delete mapAdmin[admin];

        emit RemoveAdmin(admin);
    }
}
          

openzeppelin-eth/contracts/zos-lib/Initializable.sol

pragma solidity ^0.4.24;


/**
 * @title Initializable
 *
 * @dev Helper contract to support initializer functions. To use it, replace
 * the constructor with a function that has the `initializer` modifier.
 * WARNING: Unlike constructors, initializer functions must be manually
 * invoked. This applies both to deploying an Initializable contract, as well
 * as extending an Initializable contract via inheritance.
 * WARNING: When used with inheritance, manual care must be taken to not invoke
 * a parent initializer twice, or ensure that all initializers are idempotent,
 * because this is not dealt with automatically as with constructors.
 */
contract Initializable {

  /**
   * @dev Indicates that the contract has been initialized.
   */
  bool private initialized;

  /**
   * @dev Indicates that the contract is in the process of being initialized.
   */
  bool private initializing;

  /**
   * @dev Modifier to use in the initializer function of a contract.
   */
  modifier initializer() {
    require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");

    bool wasInitializing = initializing;
    initializing = true;
    initialized = true;

    _;

    initializing = wasInitializing;
  }

  /// @dev Returns true if and only if the function is running in the constructor
  function isConstructor() private view returns (bool) {
    // extcodesize checks the size of the code stored in an address, and
    // address returns the current address. Since the code is still not
    // deployed when running a constructor, any checks on its code size will
    // yield zero, making it an effective way to detect if a contract is
    // under construction or not.
    uint256 cs;
    assembly { cs := extcodesize(address) }
    return cs == 0;
  }

  // Reserved storage space to allow for layout changes in the future.
  uint256[50] private ______gap;
}
          

contracts/crossApproach/CrossStorageV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "../components/Proxy.sol";
import "../components/Halt.sol";
import "../components/ReentrancyGuard.sol";
import "./CrossStorageV1.sol";

contract CrossStorageV2 is CrossStorageV1, ReentrancyGuard, Halt, Proxy {

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    /** STATE VARIABLES **/
    uint256 public currentChainID;
    address public admin;

    /** STRUCTURES **/
    struct SetFeesParam {
        uint256 srcChainID;
        uint256 destChainID;
        uint256 contractFee;
        uint256 agentFee;
    }

    struct GetFeesParam {
        uint256 srcChainID;
        uint256 destChainID;
    }

    struct GetFeesReturn {
        uint256 contractFee;
        uint256 agentFee;
    }
}
          

openzeppelin-eth/contracts/ownership/Ownable.sol

pragma solidity ^0.4.24;

import "../zos-lib/Initializable.sol";

/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable is Initializable {
  address private _owner;


  event OwnershipRenounced(address indexed previousOwner);
  event OwnershipTransferred(
    address indexed previousOwner,
    address indexed newOwner
  );


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function initialize(address sender) public initializer {
    _owner = sender;
  }

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

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(isOwner());
    _;
  }

  /**
   * @return true if `msg.sender` is the owner of the contract.
   */
  function isOwner() public view returns(bool) {
    return msg.sender == _owner;
  }

  /**
   * @dev Allows the current owner to relinquish control of the contract.
   * @notice Renouncing to ownership will leave the contract without an owner.
   * It will not be possible to call the functions with the `onlyOwner`
   * modifier anymore.
   */
  function renounceOwnership() public onlyOwner {
    emit OwnershipRenounced(_owner);
    _owner = address(0);
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    _transferOwnership(newOwner);
  }

  /**
   * @dev Transfers control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function _transferOwnership(address newOwner) internal {
    require(newOwner != address(0));
    emit OwnershipTransferred(_owner, newOwner);
    _owner = newOwner;
  }

  uint256[50] private ______gap;
}
          

contracts/metric/MetricStorage.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../components/BasicStorage.sol";
import "./lib/MetricTypes.sol";
import "../interfaces/IConfig.sol";
import "../interfaces/IStoremanGroup.sol";

contract MetricStorage is BasicStorage {

    /**
     *
     * EVENTS
     *
     **/
    event SMSlshLogger(bytes32 indexed groupId, bytes32 indexed hashX, uint8 indexed smIndex, MetricTypes.SlshReason slshReason);

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    MetricTypes.MetricStorageData public metricData;

}
          

contracts/test/TestDeposit.sol

pragma solidity ^0.4.26;

import "../storemanGroupAdmin/Deposit.sol";

contract TestDeposit {
  using Deposit for Deposit.Records;
  Deposit.Records g;

  constructor()public{
    g.total = 0;
    return;
  }

  function add(uint id, uint v) public {
    Deposit.Record memory r = Deposit.Record(id, v);
    g.addRecord(r);
  }

  function clean()public {
    g.clean(); 
  }
  function getTotal() public view returns (uint){
    return g.total;
  }
  function getLastValue() public view returns(uint){
    return g.getLastValue();
  }
  function get(uint id) public view returns(uint value){
    uint  a = g.getValueById(id);
    return  a;
  }
}
          

contracts/tokenManager/TokenManagerStorage.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

import "../components/BasicStorage.sol";

contract TokenManagerStorage is BasicStorage {
    /************************************************************
     **
     ** STRUCTURE DEFINATIONS
     **
     ************************************************************/

    struct AncestorInfo {
      bytes   account;
      string  name;
      string  symbol;
      uint8   decimals;
      uint    chainID;
    }

    struct TokenPairInfo {
      AncestorInfo aInfo;               /// TODO:
      uint      fromChainID;            /// index in coinType.txt; e.g. eth=60, etc=61, wan=5718350
      bytes     fromAccount;            /// from address
      uint      toChainID;              ///
      bytes     toAccount;              /// to token address
    }
    
    struct TokenPairInfoFull {
      uint      id;
      AncestorInfo aInfo;
      uint      fromChainID;
      bytes     fromAccount;
      uint      toChainID;
      bytes     toAccount;
    }


    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    /// total amount of TokenPair instance
    uint public totalTokenPairs = 0;

    /// a map from a sequence ID to token pair
    mapping(uint => TokenPairInfo) public mapTokenPairInfo;
    // index -> tokenPairId
    mapping(uint => uint) public mapTokenPairIndex;
}
          

contracts/oracle/OracleStorage.sol

pragma solidity 0.4.26;

import "../components/BasicStorage.sol";

contract OracleStorage is BasicStorage {
  /************************************************************
    **
    ** STRUCTURE DEFINATIONS
    **
    ************************************************************/
  struct StoremanGroupConfig {
    uint    deposit;
    uint[2] chain;
    uint[2] curve;
    bytes   gpk1;
    bytes   gpk2;
    uint    startTime;
    uint    endTime;
    uint8   status;
    bool    isDebtClean;
  }

  /************************************************************
    **
    ** VARIABLES
    **
    ************************************************************/
  /// @notice symbol -> price,
  mapping(bytes32 => uint) public mapPrices;

  /// @notice smgId -> StoremanGroupConfig
  mapping(bytes32 => StoremanGroupConfig) public mapStoremanGroupConfig;

  /// @notice owner and admin have the authority of admin
  address public admin;
}
          

contracts/storemanGroupAdmin/Deposit.sol

pragma solidity ^0.4.26;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';

library Deposit {
    using SafeMath for uint;

    struct Record {
        uint id;
        uint value; // the value is current total value, include the old deposit
    }

    struct Records {
        uint total;
        mapping(uint=>Record) records;
    }

    function getLastValue(Records storage self) internal view returns (uint) {
        if(self.total == 0) {
            return 0;
        } else {
            return self.records[self.total-1].value;
        }
    }
    function getValueById(Records storage self, uint id) internal view returns (uint) {
        for (uint i = self.total; i > 0; i--) {
            if (id >= self.records[i-1].id){
                return self.records[i-1].value;
            }
        }
        return 0;
    }
    function clean(Records storage self) internal {
        self.total = 0;
    }
    function addRecord(Records storage self, Record r) internal {
        if(self.total == 0) {
            self.records[0] = r;
            self.total = 1;
        } else {
            Record storage e = self.records[self.total-1];
            if(e.id == r.id) {
                e.value = e.value.add(r.value);
            }else{
                Record memory n = Record(r.id, r.value);
                n.value = n.value.add(self.records[self.total-1].value);
                self.records[self.total] = n;
                self.total++;
            }
        }
    }
}
          

contracts/crossApproach/lib/HTLCDebtLibV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./CrossTypesV1.sol";

library HTLCDebtLibV2 {

    /**
     *
     * STRUCTURES
     *
     */

    /// @notice struct of debt and asset parameters
    struct DebtAssetParams {
        bytes32 uniqueID;               /// hash of HTLC random number
        bytes32 srcSmgID;               /// ID of source storeman group
        bytes32 destSmgID;              /// ID of destination storeman group
    }

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                     event of storeman asset transfer
    /// @param uniqueID                random number
    /// @param srcSmgID             ID of source storeman group
    /// @param destSmgID            ID of destination storeman group
    event TransferAssetLogger(bytes32 indexed uniqueID, bytes32 indexed srcSmgID, bytes32 indexed destSmgID);

    /// @notice                     event of storeman debt receive
    /// @param uniqueID                random number
    /// @param srcSmgID             ID of source storeman group
    /// @param destSmgID            ID of destination storeman group
    event ReceiveDebtLogger(bytes32 indexed uniqueID, bytes32 indexed srcSmgID, bytes32 indexed destSmgID);

    /**
     *
     * MANIPULATIONS
     *
     */

    /// @notice                     transfer asset
    /// @param  storageData         Cross storage data
    /// @param  params              parameters of storeman debt lock
    function transferAsset(CrossTypesV1.Data storage storageData, DebtAssetParams memory params)
        public
    {
        if (address(storageData.quota) != address(0)) {
            storageData.quota.transferAsset(params.srcSmgID, params.destSmgID);
        }
        emit TransferAssetLogger(params.uniqueID, params.srcSmgID, params.destSmgID);
    }

    /// @notice                     receive debt
    /// @param  storageData         Cross storage data
    /// @param  params              parameters of storeman debt lock
    function receiveDebt(CrossTypesV1.Data storage storageData, DebtAssetParams memory params)
        public
    {
        if (address(storageData.quota) != address(0)) {
            storageData.quota.receiveDebt(params.srcSmgID, params.destSmgID);
        }
        emit ReceiveDebtLogger(params.uniqueID, params.srcSmgID, params.destSmgID);
    }
}
          

contracts/storemanGroupAdmin/StoremanUtil.sol

pragma solidity ^0.4.24;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "./StoremanType.sol";
import "../interfaces/IPosLib.sol";
import "../lib/CommonTool.sol";

library StoremanUtil {
  using SafeMath for uint;

  function calSkWeight(uint standaloneWeight,uint deposit) public pure returns(uint) {
    return deposit*standaloneWeight/10000;
  }

  function getDaybyTime(address posLib, uint time)  public view returns(uint) {
    return IPosLib(posLib).getEpochId(time);
  }

  function getSelectedSmNumber(StoremanType.StoremanData storage data, bytes32 groupId) public view returns(uint) {
    StoremanType.StoremanGroup storage group = data.groups[groupId];
    return group.selectedCount;
  }
  function getSelectedStoreman(StoremanType.StoremanData storage data, bytes32 groupId) public view returns(address[]) {
    StoremanType.StoremanGroup storage group = data.groups[groupId];
    address[] memory storemans = new address[](group.selectedCount);
    for(uint8 i=0; i<group.selectedCount; i++){
      storemans[i] = group.selectedNode[i];
    }
    return storemans;
  }
  function onCurve(bytes pubkey) public view returns (bool) {
    if(pubkey.length != 64) return false;
    uint[2] memory P;
    P[0] =  CommonTool.bytes2uint(pubkey, 0, 32);
    P[1] =  CommonTool.bytes2uint(pubkey, 32, 32);
    uint p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F;
    if (0 == P[0] || P[0] == p || 0 == P[1] || P[1] == p)
      return false;
    uint LHS = mulmod(P[1], P[1], p);
    uint RHS = addmod(mulmod(mulmod(P[0], P[0], p), P[0], p), 7, p);
    return LHS == RHS;
  }
}
          

contracts/oracle/OracleProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;
import "../components/Owned.sol";
import "./OracleStorage.sol";
import "../components/Proxy.sol";

contract OracleProxy is OracleStorage, Owned, Proxy {
    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for setting or upgrading OracleDelegate address by owner
    /// @param impl                       OracleDelegate contract address
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/crossApproach/CrossStorageV1.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "../components/BasicStorage.sol";
import "./lib/CrossTypesV1.sol";
import "./lib/HTLCTxLib.sol";
import "./lib/RapidityTxLib.sol";

contract CrossStorageV1 is BasicStorage {
    using HTLCTxLib for HTLCTxLib.Data;
    using RapidityTxLib for RapidityTxLib.Data;

    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    CrossTypesV1.Data internal storageData;

    /// @notice locked time(in seconds)
    uint public lockedTime = uint(3600*36);

    /// @notice Since storeman group admin receiver address may be changed, system should make sure the new address
    /// @notice can be used, and the old address can not be used. The solution is add timestamp.
    /// @notice unit: second
    uint public smgFeeReceiverTimeout = uint(10*60);

    enum GroupStatus { none, initial, curveSeted, failed, selected, ready, unregistered, dismissed }

}
          

contracts/crossApproach/lib/RapidityLib.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;


import "./RapidityTxLib.sol";
import "./CrossTypes.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/IRC20Protocol.sol";
import "../../interfaces/ISmgFeeProxy.sol";

library RapidityLib {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    /**
    *
    * STRUCTURES
    *
    */

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapidityUserLockParams {
        bytes32 smgID;                      /// ID of storeman group which user has selected
        uint tokenPairID;                   /// token pair id on cross chain
        uint value;                         /// exchange token value
        bytes userShadowAccount;            /// account of shadow chain, used to receive token
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapiditySmgMintParams {
        bytes32 uniqueID;                   /// Rapidity random number
        bytes32 smgID;                      /// ID of storeman group which user has selected
        uint tokenPairID;                   /// token pair id on cross chain
        uint value;                         /// exchange token value
        address shadowTokenAccount;         /// shadow token account
        address userShadowAccount;          /// account of shadow chain, used to receive token
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapidityUserBurnParams {
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint fee;                       /// exchange token fee
        address shadowTokenAccount;     /// shadow token account
        bytes userOrigAccount;          /// account of token original chain, used to receive token
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapiditySmgReleaseParams {
        bytes32 uniqueID;               /// Rapidity random number
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        address origTokenAccount;       /// original token/coin account
        address userOrigAccount;        /// account of token original chain, used to receive token
    }

    /**
     *
     * EVENTS
     *
     **/


    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity original token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserLockLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint serviceFee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity shadow token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserBurnLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint serviceFee, uint fee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity shadow token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgMintLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param tokenAccount             Rapidity original token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgReleaseLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, address tokenAccount, address userAccount);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                         mintBridge, user lock token on token original chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user mint lock token on token original chain
    function userLock(CrossTypes.Data storage storageData, RapidityUserLockParams memory params)
        public
    {
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        (fromChainID,fromTokenAccount,toChainID) = storageData.tokenManager.getTokenPairInfoSlim(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint serviceFee = storageData.mapLockFee[fromChainID][toChainID];

        if (address(storageData.quota) != address(0)) {
            storageData.quota.userLock(params.tokenPairID, params.smgID, params.value);
        }

        if (serviceFee > 0) {
            if (storageData.smgFeeProxy == address(0)) {
                storageData.mapStoremanFee[params.smgID] = storageData.mapStoremanFee[params.smgID].add(serviceFee);
            } else {
                ISmgFeeProxy(storageData.smgFeeProxy).smgTransfer.value(serviceFee)(params.smgID);
            }
        }

        address tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);

        uint left;
        if (tokenScAddr == address(0)) {
            left = (msg.value).sub(params.value).sub(serviceFee);
        } else {
            left = (msg.value).sub(serviceFee);

            require(CrossTypes.transferFrom(tokenScAddr, msg.sender, this, params.value), "Lock token failed");
        }
        if (left != 0) {
            (msg.sender).transfer(left);
        }
        emit UserLockLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, serviceFee, params.userShadowAccount);
    }

    /// @notice                         burnBridge, user lock token on token original chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user burn lock token on token original chain
    function userBurn(CrossTypes.Data storage storageData, RapidityUserBurnParams memory params)
        public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        address tokenScAddr = CrossTypes.bytesToAddress(toTokenAccount);

        uint serviceFee;
        if (tokenScAddr == params.shadowTokenAccount) {
            serviceFee = storageData.mapLockFee[fromChainID][toChainID];
        } else {
            tokenScAddr = CrossTypes.bytesToAddress(fromTokenAccount);
            if (tokenScAddr == params.shadowTokenAccount) {
                serviceFee = storageData.mapLockFee[toChainID][fromChainID];
            } else {
                require(false, "Invalid Token account");
            }
        }

        if (address(storageData.quota) != address(0)) {
            storageData.quota.userBurn(params.tokenPairID, params.smgID, params.value);
        }

        require(burnShadowToken(tokenManager, tokenScAddr, msg.sender, params.value), "burn failed");

        if (serviceFee > 0) {
            if (storageData.smgFeeProxy == address(0)) {
                storageData.mapStoremanFee[params.smgID] = storageData.mapStoremanFee[params.smgID].add(serviceFee);
            } else {
                ISmgFeeProxy(storageData.smgFeeProxy).smgTransfer.value(serviceFee)(params.smgID);
            }
        }

        uint left = (msg.value).sub(serviceFee);
        if (left != 0) {
            (msg.sender).transfer(left);
        }

        emit UserBurnLogger(params.smgID, params.tokenPairID, params.shadowTokenAccount, params.value, serviceFee, params.fee, params.userOrigAccount);
    }

    /// @notice                         mintBridge, storeman mint lock token on token shadow chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman mint lock token on token shadow chain
    function smgMint(CrossTypes.Data storage storageData, RapiditySmgMintParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (address(storageData.quota) != address(0)) {
            storageData.quota.smgMint(params.tokenPairID, params.smgID, params.value);
        }

        require(mintShadowToken(storageData.tokenManager, params.shadowTokenAccount, params.userShadowAccount, params.value), "mint failed");

        emit SmgMintLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.shadowTokenAccount, params.userShadowAccount);
    }

    /// @notice                         burnBridge, storeman burn lock token on token shadow chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman burn lock token on token shadow chain
    function smgRelease(CrossTypes.Data storage storageData, RapiditySmgReleaseParams memory params)
        public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (address(storageData.quota) != address(0)) {
            storageData.quota.smgRelease(params.tokenPairID, params.smgID, params.value);
        }

        if (params.origTokenAccount == address(0)) {
            (params.userOrigAccount).transfer(params.value);
        } else {
            require(CrossTypes.transfer(params.origTokenAccount, params.userOrigAccount, params.value), "Transfer token failed");
        }

        emit SmgReleaseLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.origTokenAccount, params.userOrigAccount);
    }

    function burnShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(value);
    }

    function mintShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(value);
    }

}
          

contracts/interfaces/IStoremanGroup.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

interface IStoremanGroup {
    function getSelectedSmNumber(bytes32 groupId) external view returns(uint number);
    function getStoremanGroupConfig(bytes32 id) external view returns(bytes32 groupId, uint8 status, uint deposit, uint chain1, uint chain2, uint curve1, uint curve2,  bytes gpk1, bytes gpk2, uint startTime, uint endTime);
    function getDeposit(bytes32 id) external view returns(uint);
    function getStoremanGroupStatus(bytes32 id) external view returns(uint8 status, uint startTime, uint endTime);
    function setGpk(bytes32 groupId, bytes gpk1, bytes gpk2) external;
    function setInvalidSm(bytes32 groupId, uint[] indexs, uint8[] slashTypes) external returns(bool isContinue);
    function getThresholdByGrpId(bytes32 groupId) external view returns (uint);
    function getSelectedSmInfo(bytes32 groupId, uint index) external view returns(address wkAddr, bytes PK, bytes enodeId);
    function recordSmSlash(address wk) external;
}
          

contracts/gpk/lib/GpkLib.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

import "../../lib/CommonTool.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../interfaces/ICurve.sol";
import "../../interfaces/IConfig.sol";
import "./GpkTypes.sol";
import "../../storemanGroupAdmin/StoremanType.sol";


library GpkLib {

    /// submit period
    uint32 constant DEFAULT_PERIOD = 2 * 60 * 60;     // 2 hours
    uint32 constant PLOYCOMMIT_PERIOD = 48 * 60 * 60; // 48 hours
    uint32 constant NEGOTIATE_PERIOD = 6 * 60 * 60;   // 6 hours

    /**
     *
     * EVENTS
     *
     */

    /// @notice                           event for gpk created
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    /// @param gpk1                       group public key for chain1
    /// @param gpk2                       group public key for chain2
    event GpkCreatedLogger(bytes32 indexed groupId, uint16 indexed round, bytes gpk1, bytes gpk2);

    /// @notice                           event for contract slash storeman
    /// @param groupId                    storeman group id
    /// @param slashType                  the reason to slash
    /// @param slashed                    slashed storeman
    /// @param partner                     negotiate parter
    /// @param round                      group negotiate round
    /// @param curveIndex                 signature curve index
    event SlashLogger(bytes32 indexed groupId, uint8 indexed slashType, address indexed slashed, address partner, uint16 round, uint8 curveIndex);

    /// @notice                           event for group reset protocol
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate round
    event ResetLogger(bytes32 indexed groupId, uint16 indexed round);

    /// @notice                           event for group close protocol
    /// @param groupId                    storeman group id
    /// @param round                      group negotiate max round
    event CloseLogger(bytes32 indexed groupId, uint16 indexed round);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for init period
    /// @param groupId                    storeman group id
    /// @param group                      storeman group
    /// @param cfg                        group config
    /// @param smg                        storeman group contract address
    function initGroup(bytes32 groupId, GpkTypes.Group storage group, address cfg, address smg)
        public
    {
        // init period
        if (group.defaultPeriod == 0) {
            group.defaultPeriod = DEFAULT_PERIOD;
            group.ployCommitPeriod = PLOYCOMMIT_PERIOD;
            group.negotiatePeriod = NEGOTIATE_PERIOD;
        }

        // init signature curve
        uint8 status;
        uint256 curve1;
        uint256 curve2;
        (,status,,,,curve1,curve2,,,,) = IStoremanGroup(smg).getStoremanGroupConfig(groupId);
        require(status == uint8(StoremanType.GroupStatus.selected), "Invalid stage");

        group.roundMap[group.round][0].curve = IConfig(cfg).getCurve(uint8(curve1));
        group.roundMap[group.round][1].curve = IConfig(cfg).getCurve(uint8(curve2));

        group.groupId = groupId;

        // retrieve selected sm list
        group.smNumber = uint16(IStoremanGroup(smg).getSelectedSmNumber(groupId));
        address txAddress;
        bytes memory pk;
        for (uint i = 0; i < group.smNumber; i++) {
            (txAddress, pk,) = IStoremanGroup(smg).getSelectedSmInfo(groupId, i);
            group.addrMap[i] = txAddress;
            group.indexMap[txAddress] = i;
            group.pkMap[txAddress] = pk;
        }
    }

    /// @notice                           function for try to complete
    /// @param group                      storeman group
    function tryComplete(GpkTypes.Group storage group, address smg)
        public
    {
        GpkTypes.Round storage round1 = group.roundMap[group.round][0];
        GpkTypes.Round storage round2 = group.roundMap[group.round][1];
        if (round1.status == round2.status) {
            IStoremanGroup(smg).setGpk(group.groupId, round1.gpk, round2.gpk);
            emit GpkCreatedLogger(group.groupId, group.round, round1.gpk, round2.gpk);
        }
    }

    /// @notice                           function for update gpk
    /// @param round                      round
    /// @param polyCommit                 poly commit
    function updateGpk(GpkTypes.Round storage round, bytes polyCommit)
        public
    {
        bytes memory gpk = round.gpk;
        uint x = CommonTool.bytes2uint(polyCommit, 0, 32);
        uint y = CommonTool.bytes2uint(polyCommit, 32, 32);
        if (gpk.length != 0) {
            uint gpkX = CommonTool.bytes2uint(gpk, 0, 32);
            uint gpkY = CommonTool.bytes2uint(gpk, 32, 32);
            bool success;
            (x, y, success) = ICurve(round.curve).add(x, y, gpkX, gpkY);
            require(success == true, "Gpk failed");
        } else {
            gpk = new bytes(64);
        }
        assembly { mstore(add(gpk, 32), x) }
        assembly { mstore(add(gpk, 64), y) }
        round.gpk = gpk;
    }

    /// @notice                           function for update gpkShare
    /// @param group                      storeman group
    /// @param round                      round
    /// @param polyCommit                 poly commit
    function updateGpkShare(GpkTypes.Group storage group, GpkTypes.Round storage round, bytes polyCommit)
        public
    {
        uint x;
        uint y;
        bool success;
        for (uint i = 0; i < group.smNumber; i++) {
            address txAddress = group.addrMap[i];
            bytes memory pk = group.pkMap[txAddress];
            (x, y, success) = ICurve(round.curve).calPolyCommit(polyCommit, pk);
            require(success == true, "PolyCommit failed");

            bytes memory gpkShare = round.srcMap[txAddress].gpkShare;
            if (gpkShare.length != 0) {
                uint pkX = CommonTool.bytes2uint(gpkShare, 0, 32);
                uint pkY = CommonTool.bytes2uint(gpkShare, 32, 32);
                (x, y, success) = ICurve(round.curve).add(x, y, pkX, pkY);
                require(success == true, "Add failed");
            } else {
                gpkShare = new bytes(64);
            }
            assembly { mstore(add(gpkShare, 32), x) }
            assembly { mstore(add(gpkShare, 64), y) }
            round.srcMap[txAddress].gpkShare = gpkShare;
        }
    }

    /// @notice                           function for verify sij to judge challenge
    /// @param d                          Dest
    /// @param destPk                     dest storeman pk
    /// @param polyCommit                 polyCommit of pki
    /// @param curve                      curve contract address
    function verifySij(GpkTypes.Dest storage d, bytes destPk, bytes polyCommit, address curve)
        public
        view
        returns(bool)
    {
        // check sij
        uint x;
        uint y;
        uint pcX;
        uint pcY;
        bool success;
        (x, y, success) = ICurve(curve).mulG(d.sij);
        if (success) {
            (pcX, pcY, success) = ICurve(curve).calPolyCommit(polyCommit, destPk);
            if (success && (x == pcX) && (y == pcY)) {
                // check enc
                uint iv = CommonTool.bytes2uint(d.encSij, 65, 16);
                bytes memory cipher;
                (cipher, success) = CommonTool.enc(bytes32(d.ephemPrivateKey), bytes32(iv), d.sij, destPk);
                if (success) {
                    return CommonTool.cmpBytes(d.encSij, cipher);
                }
            }
        }
        return false;
    }

    /// @notice                           function for slash
    /// @param group                      storeman group
    /// @param curveIndex                 signature curve index
    /// @param slashType                  slash reason
    /// @param slashed                    slashed storeman
    /// @param parter                     negotiate parter
    /// @param toReset                    is reset immediately
    /// @param smg                        the storeman group admin contract
    function slash(GpkTypes.Group storage group, uint8 curveIndex, GpkTypes.SlashType slashType,
        address slashed, address parter, bool toReset, address smg)
        public
    {
        GpkTypes.Src storage src = group.roundMap[group.round][curveIndex].srcMap[slashed];
        if (src.slashType == GpkTypes.SlashType.None) {
            group.roundMap[group.round][curveIndex].slashCount++;
        }
        if ((slashType == GpkTypes.SlashType.SijInvalid)
         || (slashType == GpkTypes.SlashType.CheckInvalid)
         || (src.slashType == GpkTypes.SlashType.None) 
         || (src.slashType == GpkTypes.SlashType.Connive)) {
            src.slashType = slashType;
        }
        emit SlashLogger(group.groupId, uint8(slashType), slashed, parter, group.round, curveIndex);
        if (toReset) {
            uint[] memory ids = new uint[](1);
            ids[0] = group.indexMap[slashed];
            uint8[] memory types = new uint8[](1);
            types[0] = uint8(slashType);
            bool isContinue = IStoremanGroup(smg).setInvalidSm(group.groupId, ids, types);
            reset(group, isContinue);
        }
    }

    /// @notice                           function for slash
    /// @param group                      storeman group
    /// @param curveIndex                 singnature curve index
    /// @param smg                        smg contract address
    function slashMulti(GpkTypes.Group storage group, uint8 curveIndex, address smg)
        public
    {
        GpkTypes.Round storage round = group.roundMap[group.round][curveIndex];
        uint[] memory ids = new uint[](round.slashCount);
        uint8[] memory types = new uint8[](round.slashCount);
        uint slashCount = 0;
        for (uint i = 0; (i < group.smNumber) && (slashCount < round.slashCount); i++) {
            GpkTypes.Src storage src = round.srcMap[group.addrMap[i]];
            if (src.slashType != GpkTypes.SlashType.None) {
                ids[slashCount] = i;
                types[slashCount] = uint8(src.slashType);
                slashCount++;
            }
        }
        bool isContinue = IStoremanGroup(smg).setInvalidSm(group.groupId, ids, types);
        reset(group, isContinue);
    }

    /// @notice                           function for reset protocol
    /// @param group                      storeman group
    /// @param isContinue                 is continue to next round
    function reset(GpkTypes.Group storage group, bool isContinue)
        public
    {
        GpkTypes.Round storage round = group.roundMap[group.round][0];
        round.status = GpkTypes.GpkStatus.Close;
        round.statusTime = now;
        round = group.roundMap[group.round][1];
        round.status = GpkTypes.GpkStatus.Close;
        round.statusTime = now;

        // clear data
        for (uint i = 0; i < group.smNumber; i++) {
            delete group.pkMap[group.addrMap[i]];
            delete group.indexMap[group.addrMap[i]];
            delete group.addrMap[i];
        }
        group.smNumber = 0;

        if (isContinue) {
          emit ResetLogger(group.groupId, group.round);
          group.round++;
        } else {
          emit CloseLogger(group.groupId, group.round);
        }
    }
}
          

contracts/gpk/GpkStorage.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

import "../components/BasicStorage.sol";
import "./lib/GpkTypes.sol";

contract GpkStorage is BasicStorage {
    /// smg instance address
    address public smg;

    /// gpk config
    address public cfg;

    /// groupId -> Group
    mapping(bytes32 => GpkTypes.Group) public groupMap;
}
          

contracts/interfaces/IListGroup.sol

pragma solidity ^0.4.24;

interface IListGroup {
  function addActiveGroup(bytes32 groupId, uint startTime, uint endTime) external;
  function getActiveGroupIds(uint day) external view returns (bytes32[]);
  function getTotalDeposit(uint day) external view returns(uint);
  function setTotalDeposit(uint day, uint value) external;
  function cleanExpiredGroup() external;
  function getDelegateQuitGroupId(address wkAddr, address deAddr) external view returns (bytes32 groupId, bytes32 nextGroupId);
  function getPartQuitGroupId(address wkAddr, address pnAddr) external view returns (bytes32 groupId, bytes32 nextGroupId);
  function setDelegateQuitGroupId(address wkAddr, address deAddr, bytes32 groupId, bytes32 nextGroupId)external;
  function setPartQuitGroupId(address wkAddr, address pnAddr, bytes32 groupId, bytes32 nextGroupId) external;
}
          

contracts/interfaces/IWrappedNFT1155.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface IWrappedNFT1155 {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
    function transferOwner(address) external;
    function name() external view returns (string);
    function symbol() external view returns (string);
    function update(string, string) external;

    function burnBatch(address , uint256[] , uint256[] ) public;
    function mintBatch(address , uint256[] , uint256[] , bytes) public;
}
          

contracts/components/BasicStorage.sol

pragma solidity ^0.4.24;

import "../lib/BasicStorageLib.sol";

contract BasicStorage {
    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    //// basic variables
    using BasicStorageLib for BasicStorageLib.UintData;
    using BasicStorageLib for BasicStorageLib.BoolData;
    using BasicStorageLib for BasicStorageLib.AddressData;
    using BasicStorageLib for BasicStorageLib.BytesData;
    using BasicStorageLib for BasicStorageLib.StringData;

    BasicStorageLib.UintData    internal uintData;
    BasicStorageLib.BoolData    internal boolData;
    BasicStorageLib.AddressData internal addressData;
    BasicStorageLib.BytesData   internal bytesData;
    BasicStorageLib.StringData  internal stringData;
}
          

contracts/metric/MetricProxy.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

/**
 * Math operations with safety checks
 */

import "../components/Halt.sol";
import "../components/Admin.sol";
import "./MetricStorage.sol";
import "../components/Proxy.sol";

contract MetricProxy is MetricStorage, Halt, Proxy {

    ///@dev                   update the address of MetricDelegate contract
    ///@param impl            the address of the new MetricDelegate contract
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/test/FakeSmg.sol

pragma solidity ^0.4.24;

import '../storemanGroupAdmin/StoremanType.sol';
contract FakeSmg {
    /*
    *
    *   VARIABLES
    *
    */
    uint constant SelectedSMNumber = 4;
    uint constant ThresholdNumber = 3;
    string constant GroupIdStr = "0000000000000000000000000000000000000031353839393533323738313235";
    string constant GroupIdStr1 = "0000000000000000000000000000000000000031353839393533323738313236";
    string constant EnodeIdStr = "0000000000000000000000000000000000000000000000000000000000000001";
    string constant bytestr = "bytes";

    string constant gpk1Str = "82e5d4ad633e9e028b283e52338e4fe4c5467091fd4f5d9aec74cb78c25738be1154a9b1cff44b7fe935e774da7a9fad873b76323573138bc361a9cfdb6a20d2";
    string constant gpk2Str = "1761e90a6287d8e771373074626befaf4a46e6e3a2d45f8b7a2ec5361f1de7a102d43cd0d14e5a438d754c01d0d94cf2a8ff8fd9df49c9f7291975c831bcb983";


    string constant gpkShare1Str = "f716e789cd79d106343b8e9c3ac494865d02241337cf6ce8df4df6548ec1eccc900963c639664b1667df09d322a8e5c8a9185a09742f96b204b4fcc59dae7fab";
    string constant gpkShare2Str = "17a4f5c4add16108a4ab16fc1635635af0df9798176459ca3cd58a15ceb64d4808651a691e5f89ed012ee076bc39bff193064b852ce11741f0110a81c6d876d7";


    bytes32  grpId;

//    string[4] Pks = ["0425fa6a4190ddc87d9f9dd986726cafb901e15c21aafd2ed729efed1200c73de89f1657726631d29733f4565a97dc00200b772b4bc2f123a01e582e7e56b80cf8",
//    "04be3b7fd88613dc272a36f4de570297f5f33b87c26de3060ad04e2ea697e13125a2454acd296e1879a7ddd0084d9e4e724fca9ef610b21420978476e2632a1782",
//    "0495e8fd461c37f1db5da62bfbee2ad305d77e57fbef917ec8109e6425e942fb60ddc28b1edfdbcda1aa5ace3160b458b9d3d5b1fe306b4d09a030302a08e2db93",
//    "04ccd16e96a70a5b496ff1cec869902b6a8ffa00715897937518f1c9299726f7090bc36cc23c1d028087eb0988c779663e996391f290631317fc22f84fa9bf2467"];

    string[4] Pks = ["25fa6a4190ddc87d9f9dd986726cafb901e15c21aafd2ed729efed1200c73de89f1657726631d29733f4565a97dc00200b772b4bc2f123a01e582e7e56b80cf8",
    "be3b7fd88613dc272a36f4de570297f5f33b87c26de3060ad04e2ea697e13125a2454acd296e1879a7ddd0084d9e4e724fca9ef610b21420978476e2632a1782",
    "95e8fd461c37f1db5da62bfbee2ad305d77e57fbef917ec8109e6425e942fb60ddc28b1edfdbcda1aa5ace3160b458b9d3d5b1fe306b4d09a030302a08e2db93",
    "ccd16e96a70a5b496ff1cec869902b6a8ffa00715897937518f1c9299726f7090bc36cc23c1d028087eb0988c779663e996391f290631317fc22f84fa9bf2467"];

    address constant ADD_0 = 0x0000000000000000000000000000000000000000;
    address constant ADD_LEADER= 0x2d0e7c0813a51d3bd1d08246af2a8a7a57d8922e;

    address public leaderAdd;
    // groupId=>index=>pk
    mapping(bytes32 => mapping(uint8 => bytes)) mapSmgInfo;

    constructor() public {
        grpId = bytesToBytes32(fromHex(GroupIdStr), 0);

        for (uint i = 0; i < Pks.length; i++) {
            mapSmgInfo[grpId][uint8(i)] = fromHex(Pks[i]);
        }

        grpId = bytesToBytes32(fromHex(GroupIdStr1), 0);

        for (uint j = 0; j < Pks.length; j++) {
            mapSmgInfo[grpId][uint8(j)] = fromHex(Pks[j]);
        }

    }

    /*
    *
    *   FUNCTIONS
    *
    */

    function getSelectedSmNumber(bytes32 groupId) external pure returns (uint number){
        return SelectedSMNumber;
    }

    function getThresholdByGrpId(bytes32 groupId) external pure returns (uint){
        return ThresholdNumber;
    }

    function getSelectedSmInfo(bytes32 groupId, uint index) external view returns (address txAddress, bytes pk, bytes enodeId){
        (txAddress,pk,enodeId) = (leaderAdd, mapSmgInfo[groupId][uint8(index)], fromHex(EnodeIdStr));
    }


    function getStoremanInfo(address wkAddress) external pure  returns(
        bytes32 groupId,
        bytes32 nextGroupId)
    {
        return (bytesToBytes32(fromHex(GroupIdStr),0),bytesToBytes32(fromHex(GroupIdStr1),0));
    }

    function getStoremanGroupInfo(bytes32 id)
    external
    pure
    returns(bytes32 groupId, StoremanType.GroupStatus status, uint deposit, uint whiteCount,  uint memberCount,  uint startTime, uint endTime){
        return (bytesToBytes32(fromHex(GroupIdStr),0),StoremanType.GroupStatus.ready,uint(0),uint(0),uint(0),uint(0),uint(0));
    }


    function getStoremanGroupConfig(bytes32 id) external pure returns(bytes32 groupId, uint8 status, uint deposit, uint chain1, uint chain2,
        uint curve1, uint curve2,  bytes gpk1, bytes gpk2, uint startTime, uint endTime){
        return (bytesToBytes32(fromHex(GroupIdStr),0),0,0,0,0,0x00,0x01,fromHex(gpk1Str),fromHex(gpk2Str),0,0);
    }


    function getGpkShare(bytes32 groupId, uint index) external pure returns(bytes gpkShare1, bytes gpkShare2){
        return (fromHex(gpkShare1Str),fromHex(gpkShare2Str));
    }


    function setLeader(address leader) external{
        leaderAdd  = leader;
    }

    function bytesToBytes32(bytes b, uint offset) internal pure returns (bytes32) {
        bytes32 out;

        for (uint i = 0; i < 32; i++) {
            out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
        }
        return out;
    }

    // Convert an hexadecimal character to their value
    function fromHexChar(uint c) public pure returns (uint) {
        if (byte(c) >= byte('0') && byte(c) <= byte('9')) {
            return c - uint(byte('0'));
        }
        if (byte(c) >= byte('a') && byte(c) <= byte('f')) {
            return 10 + c - uint(byte('a'));
        }
        if (byte(c) >= byte('A') && byte(c) <= byte('F')) {
            return 10 + c - uint(byte('A'));
        }
        return uint(0);
    }

    // Convert an hexadecimal string to raw bytes
    function fromHex(string s) public pure returns (bytes) {
        bytes memory ss = bytes(s);
        require(ss.length % 2 == 0);
        // length must be even
        bytes memory r = new bytes(ss.length / 2);
        for (uint i = 0; i < ss.length / 2; ++i) {
            r[i] = byte(fromHexChar(uint(ss[2 * i])) * 16 +
                fromHexChar(uint(ss[2 * i + 1])));
        }
        return r;
    }

    function recordSmSlash(address wk) external{}
}
          

contracts/lib/BasicStorageLib.sol

pragma solidity ^0.4.24;

library BasicStorageLib {

    struct UintData {
        mapping(bytes => mapping(bytes => uint))           _storage;
    }

    struct BoolData {
        mapping(bytes => mapping(bytes => bool))           _storage;
    }

    struct AddressData {
        mapping(bytes => mapping(bytes => address))        _storage;
    }

    struct BytesData {
        mapping(bytes => mapping(bytes => bytes))          _storage;
    }

    struct StringData {
        mapping(bytes => mapping(bytes => string))         _storage;
    }

    /* uintStorage */

    function setStorage(UintData storage self, bytes memory key, bytes memory innerKey, uint value) internal {
        self._storage[key][innerKey] = value;
    }

    function getStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal view returns (uint) {
        return self._storage[key][innerKey];
    }

    function delStorage(UintData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /* boolStorage */

    function setStorage(BoolData storage self, bytes memory key, bytes memory innerKey, bool value) internal {
        self._storage[key][innerKey] = value;
    }

    function getStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal view returns (bool) {
        return self._storage[key][innerKey];
    }

    function delStorage(BoolData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /* addressStorage */

    function setStorage(AddressData storage self, bytes memory key, bytes memory innerKey, address value) internal {
        self._storage[key][innerKey] = value;
    }

    function getStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal view returns (address) {
        return self._storage[key][innerKey];
    }

    function delStorage(AddressData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /* bytesStorage */

    function setStorage(BytesData storage self, bytes memory key, bytes memory innerKey, bytes memory value) internal {
        self._storage[key][innerKey] = value;
    }

    function getStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal view returns (bytes memory) {
        return self._storage[key][innerKey];
    }

    function delStorage(BytesData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

    /* stringStorage */

    function setStorage(StringData storage self, bytes memory key, bytes memory innerKey, string memory value) internal {
        self._storage[key][innerKey] = value;
    }

    function getStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal view returns (string memory) {
        return self._storage[key][innerKey];
    }

    function delStorage(StringData storage self, bytes memory key, bytes memory innerKey) internal {
        delete self._storage[key][innerKey];
    }

}
          

openzeppelin-eth/contracts/token/ERC721/IERC721Metadata.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./IERC721.sol";


/**
 * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 * @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract IERC721Metadata is Initializable, IERC721 {
  function name() external view returns (string);
  function symbol() external view returns (string);
  function tokenURI(uint256 tokenId) public view returns (string);
}
          

contracts/crossApproach/lib/RapidityTxLib.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

library RapidityTxLib {

    /**
     *
     * ENUMS
     *
     */

    /// @notice tx info status
    /// @notice uninitialized,Redeemed
    enum TxStatus {None, Redeemed}

    /**
     *
     * STRUCTURES
     *
     */
    struct Data {
        /// @notice mapping of uniqueID to TxStatus -- uniqueID->TxStatus
        mapping(bytes32 => TxStatus) mapTxStatus;

    }

    /**
     *
     * MANIPULATIONS
     *
     */

    /// @notice                     add user transaction info
    /// @param  uniqueID            Rapidity random number
    function addRapidityTx(Data storage self, bytes32 uniqueID)
        internal
    {
        TxStatus status = self.mapTxStatus[uniqueID];
        require(status == TxStatus.None, "Rapidity tx exists");
        self.mapTxStatus[uniqueID] = TxStatus.Redeemed;
    }
}
          

contracts/components/StandardToken.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//


pragma solidity 0.4.26;

import "./WRC20Protocol.sol";
import 'openzeppelin-eth/contracts/math/SafeMath.sol';

contract StandardToken is WRC20Protocol {
    using SafeMath for uint;

    /**
    * @dev Fix for the ERC20 short address attack.
    */
    modifier onlyPayloadSize(uint size) {
        require(msg.data.length >= size + 4, "Payload size is incorrect");
        _;
    }

    function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) returns (bool success) {
        balances[msg.sender] = balances[msg.sender].sub(_value);
        balances[_to] = balances[_to].add(_value);
        emit Transfer(msg.sender, _to, _value);
        return true;
    }

    function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) returns (bool success) {
        balances[_to] = balances[_to].add(_value);
        balances[_from] = balances[_from].sub(_value);
        allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value);
        emit Transfer(_from, _to, _value);
        return true;
    }

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

    function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) returns (bool success) {
        //  To change the approve amount you first have to reduce the addresses`
        //  allowance to zero by calling `approve(_spender, 0)` if it is not
        //  already 0 to mitigate the race condition described here:
        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
        require((_value == 0) || (allowed[msg.sender][_spender] == 0), "Not permitted");

        allowed[msg.sender][_spender] = _value;
        emit Approval(msg.sender, _spender, _value);
        return true;
    }

    function allowance(address _owner, address _spender) public view returns (uint remaining) {
      return allowed[_owner][_spender];
    }
}
          

contracts/schnorr/Bn128SchnorrVerifier.sol

pragma solidity ^0.4.24;

import "./Bn128.sol";

contract Bn128SchnorrVerifier is Bn128 {
    struct Point {
        uint256 x; uint256 y;
    }

    struct Verification {
        Point groupKey;
        Point randomPoint;
        uint256 signature;
        bytes32 message;

        uint256 _hash;
        Point _left;
        Point _right;
    }

    function h(bytes32 m, uint256 a, uint256 b) public pure returns (uint256) {
        return uint256(sha256(abi.encodePacked(m, a, b)));
    }

    // function cmul(Point p, uint256 scalar) public pure returns (uint256, uint256) {
    function cmul(uint256 x, uint256 y, uint256 scalar) public view returns (uint256, uint256) {
        return ecmul(x, y, scalar);
    }

    function sg(uint256 sig_s) public view returns (uint256, uint256) {
        return ecmul(getGx(), getGy(), sig_s);
    }

    // function cadd(Point a, Point b) public pure returns (uint256, uint256) {
    function cadd(uint256 ax, uint256 ay, uint256 bx, uint256 by) public view returns (uint256, uint256) {
        return ecadd(ax, ay, bx, by);
    }

    function verify(bytes32 signature, bytes32 groupKeyX, bytes32 groupKeyY, bytes32 randomPointX, bytes32 randomPointY, bytes32 message)
        public
        view
        returns(bool)
    {
        bool flag = false;
        Verification memory state;

        state.signature = uint256(signature);
        state.groupKey.x = uint256(groupKeyX);
        state.groupKey.y = uint256(groupKeyY);
        state.randomPoint.x = uint256(randomPointX);
        state.randomPoint.y = uint256(randomPointY);
        state.message = message;

        state._hash = h(state.message, state.randomPoint.x, state.randomPoint.y);

        /// change to bn256 range.
        state._hash = uint256(state._hash).mod(getOrder());

        (state._left.x, state._left.y) = sg(state.signature);
        Point memory rightPart;
        (rightPart.x, rightPart.y) = cmul(state.groupKey.x, state.groupKey.y, state._hash);
        (state._right.x, state._right.y) = cadd(state.randomPoint.x, state.randomPoint.y, rightPart.x, rightPart.y);

        flag = state._left.x == state._right.x && state._left.y == state._right.y;

        return flag;
    }
}
          

contracts/quota/QuotaProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

/**
 * Math operations with safety checks
 */

import "../components/Halt.sol";
import "./QuotaStorage.sol";
import "../components/Proxy.sol";

contract QuotaProxy is QuotaStorage, Halt, Proxy {
    ///@dev                     update the address of HTLCDelegate contract
    ///@param impl            the address of the new HTLCDelegate contract
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(
            impl != _implementation,
            "Cannot upgrade to the same implementation"
        );
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/test/MappingNftToken.sol

// SPDX-License-Identifier: MIT

pragma solidity ^0.4.26;

import 'openzeppelin-eth/contracts/ownership/Ownable.sol';
import 'openzeppelin-eth/contracts/token/ERC721/ERC721Full.sol';


/**
* @notice This is the template for all NFT contract.
*/
contract MappingNftToken is ERC721Full, Ownable {

    using SafeMath for uint;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The defaut value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(
        string name_,
        string symbol_
    ) public {
        _name = name_;
        _symbol = symbol_;
        Ownable.initialize(msg.sender);
        ERC721.initialize();
        ERC721Enumerable.initialize();
        ERC721Metadata.initialize(name_, symbol_);
    }

    /****************************************************************************
     **
     ** MANIPULATIONS of mapping token
     **
     ****************************************************************************/

    /// @notice Create token
    /// @dev Create token
    /// @param account_ Address will receive token
    /// @param nftID ID of token to be minted
    function mint(address account_, uint256 nftID)
    external
    onlyOwner
    {
        _mint(account_, nftID);
    }

    /// @notice Burn token
    /// @dev Burn token
    /// @param account_ Address of whose token will be burnt
    /// @param nftID   ID of token to be burnt
    function burn(address account_, uint256 nftID)
        external
        onlyOwner
    {
        _burn(account_, nftID);
    }

    /// @notice update token name, symbol
    /// @dev update token name, symbol
    /// @param name_ token new name
    /// @param symbol_ token new symbol
    function update(string name_, string symbol_)
    external
    onlyOwner
    {
        _name = name_;
        _symbol = symbol_;
    }

    function transferOwner(address newOwner_) public onlyOwner {
        Ownable.transferOwnership(newOwner_);
    }

    // mint supprt data
    function mint(address account_, uint256 nftID, bytes data)
        external
        onlyOwner
    {
        _mint(account_, nftID);
    }

    function burnBatch(address account_, uint256[] nftIDs)
        external
        onlyOwner
    {
        for(uint i = 0; i < nftIDs.length; ++i) {
            _burn(account_, nftIDs[i]);
        }
    }

    function mintBatch(address account_, uint256[] nftIDs, bytes data)
        external
        onlyOwner
    {
         for(uint i = 0; i < nftIDs.length; ++i) {
             _mint(account_, nftIDs[i]);
         }
    }
}
          

contracts/quota/QuotaStorageV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

import "./QuotaProxy.sol";

/**
 * Math operations with safety checks
 */

contract QuotaStorageV2 is QuotaProxy {
    /// @dev mapping: tokenId => storemanPk => Quota
    mapping(uint => mapping(bytes32 => Quota)) v2QuotaMap;

    /// @dev mapping: storemanPk => tokenIndex => tokenId, tokenIndex:0,1,2,3...
    mapping(bytes32 => mapping(uint => uint)) v2TokensMap;

    /// @dev mapping: storemanPk => token count
    mapping(bytes32 => uint) v2TokenCountMap;

    /// upgrade version
    uint public version;
}
          

contracts/config/ConfigDelegate.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../components/Halt.sol";
import "../components/Admin.sol";
import "./ConfigStorage.sol";


contract ConfigDelegate is ConfigStorage, Halt , Admin{

    /// @notice                           function for set smg contract address
    /// @param curveId                    curve id array
    /// @param curveAddress               curve contract address array
    function setCurve(uint8[] curveId, address[] curveAddress)
    external
    onlyAdmin
    {
        uint8 length = uint8(curveId.length);
        require((length > 0) && (length == curveAddress.length), "Mismatched length");
        for (uint8 i = 0; i < length; i++) {
            curves[curveId[i]] = curveAddress[i];
        }
    }

    function getCurve(uint8 curveId)
    external
    view
    returns(address){
        require(curves[curveId] != address(0), "No curve");
        return curves[curveId];
    }

    function() public payable {
        revert("Not support");
    }

}
          

contracts/quota/QuotaDelegate.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

/**
 * Math operations with safety checks
 */

import "./QuotaStorageV2.sol";
import "../interfaces/IOracle.sol";

interface _ITokenManager {
    function getAncestorSymbol(uint id) external view returns (string symbol, uint8 decimals);
}

interface _IStoremanGroup {
    function getDeposit(bytes32 id) external view returns(uint deposit);
}

interface IDebtOracle {
    function isDebtClean(bytes32 storemanGroupId) external view returns (bool);
}


contract QuotaDelegate is QuotaStorageV2 {

    event AssetTransfered(bytes32 indexed srcStoremanGroupId, bytes32 indexed dstStoremanGroupId, uint tokenId, uint value);

    event DebtReceived(bytes32 indexed srcStoremanGroupId, bytes32 indexed dstStoremanGroupId, uint tokenId, uint value);

    modifier checkMinValue(uint tokenId, uint value) {
        if (fastCrossMinValue > 0) {
            string memory symbol;
            uint decimals;
            (symbol, decimals) = getTokenAncestorInfo(tokenId);
            uint price = getPrice(symbol);
            if (price > 0) {
                uint count = fastCrossMinValue.mul(10**decimals).div(price);
                require(value >= count, "value too small");
            }
        }
        _;
    }
    
    /// @notice                         config params for owner
    /// @param _priceOracleAddr         token price oracle contract address
    /// @param _htlcAddr                HTLC contract address
    /// @param _depositOracleAddr       deposit oracle address, storemanAdmin or oracle
    /// @param _depositRate             deposit rate value, 15000 means 150%
    /// @param _depositTokenSymbol      deposit token symbol, default is WAN
    /// @param _tokenManagerAddress     token manager contract address
    function config(
        address _priceOracleAddr,
        address _htlcAddr,
        address _fastHtlcAddr,
        address _depositOracleAddr,
        address _tokenManagerAddress,
        uint _depositRate,
        string _depositTokenSymbol
    ) external onlyOwner {
        priceOracleAddress = _priceOracleAddr;
        htlcGroupMap[_htlcAddr] = true;
        htlcGroupMap[_fastHtlcAddr] = true;
        depositOracleAddress = _depositOracleAddr;
        depositRate = _depositRate;
        depositTokenSymbol = _depositTokenSymbol;
        tokenManagerAddress = _tokenManagerAddress;
    }

    function setDebtOracle(address oracle) external onlyOwner {
        debtOracleAddress = oracle;
    }

    function setFastCrossMinValue(uint value) external onlyOwner {
        fastCrossMinValue = value;
    }

    /// @notice                                 get asset of storeman, tokenId
    /// @param tokenId                          tokenPairId of crosschain
    /// @param storemanGroupId                  PK of source storeman group
    function getAsset(uint tokenId, bytes32 storemanGroupId)
        public
        view
        returns (uint asset, uint asset_receivable, uint asset_payable)
    {
        uint tokenKey = getTokenKey(tokenId);
        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        return (quota._asset, quota.asset_receivable, quota.asset_payable);
    }

    /// @notice                                 get debt of storeman, tokenId
    /// @param tokenId                          tokenPairId of crosschain
    /// @param storemanGroupId                  PK of source storeman group
    function getDebt(uint tokenId, bytes32 storemanGroupId)
        public
        view
        returns (uint debt, uint debt_receivable, uint debt_payable)
    {
        uint tokenKey = getTokenKey(tokenId);
        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        return (quota._debt, quota.debt_receivable, quota.debt_payable);
    }

    /// @notice                                 get debt clean state of storeman
    /// @param storemanGroupId                  PK of source storeman group
    function isDebtClean(bytes32 storemanGroupId) external view returns (bool) {
        uint tokenCount = v2TokenCountMap[storemanGroupId];
        if (tokenCount == 0) {
            if (debtOracleAddress == address(0)) {
                return true;
            } else {
                IDebtOracle debtOracle = IDebtOracle(debtOracleAddress);
                return debtOracle.isDebtClean(storemanGroupId);
            }
        }

        for (uint i = 0; i < tokenCount; i++) {
            uint id = v2TokensMap[storemanGroupId][i];
            Quota storage src = v2QuotaMap[id][storemanGroupId];
            if (src._debt > 0 || src.debt_payable > 0 || src.debt_receivable > 0) {
                return false;
            }

            if (src._asset > 0 || src.asset_payable > 0 || src.asset_receivable > 0) {
                return false;
            }
        }
        return true;
    }

    /// @dev get minimize token count for fast cross chain
    function getFastMinCount(uint tokenId) public view returns (uint, string, uint, uint, uint) {
        if (fastCrossMinValue == 0) {
            return (0, "", 0, 0, 0);
        }
        string memory symbol;
        uint decimals;
        (symbol, decimals) = getTokenAncestorInfo(tokenId);
        uint price = getPrice(symbol);
        uint count = 0;
        if (price > 0) {
            count = fastCrossMinValue.mul(10**decimals).div(price);
        }
        return (fastCrossMinValue, symbol, decimals, price, count);
    }

    /** New Cross Chain Interface*/
    function userLock(uint tokenId, bytes32 storemanGroupId, uint value) 
        public 
        onlyHtlc 
        checkMinValue(tokenId, value) 
    {
        uint tokenKey = getTokenKey(tokenId);

        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];

        if (!quota._active) {
            quota._active = true;
            v2TokensMap[storemanGroupId][v2TokenCountMap[storemanGroupId]] = tokenKey;
            v2TokenCountMap[storemanGroupId] = v2TokenCountMap[storemanGroupId]
                .add(1);
        }
        quota._asset = quota._asset.add(value);
    }

    function userBurn(uint tokenId, bytes32 storemanGroupId, uint value) 
        external 
        onlyHtlc 
        checkMinValue(tokenId, value) 
    {
        uint tokenKey = getTokenKey(tokenId);

        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        quota._debt = quota._debt.sub(value);
    }

    function smgRelease(uint tokenId, bytes32 storemanGroupId, uint value) 
        external 
        onlyHtlc 
    {
        uint tokenKey = getTokenKey(tokenId);

        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        quota._asset = quota._asset.sub(value);
    }

    function smgMint(uint tokenId, bytes32 storemanGroupId, uint value)
        public onlyHtlc 
    {
        uint tokenKey = getTokenKey(tokenId);

        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];        
        if (!quota._active) {
            quota._active = true;
            v2TokensMap[storemanGroupId][v2TokenCountMap[storemanGroupId]] = tokenKey;
            v2TokenCountMap[storemanGroupId] = v2TokenCountMap[storemanGroupId]
                .add(1);
        }
        quota._debt = quota._debt.add(value);
    }

    function adjustSmgQuota(bytes32 storemanGroupId, uint tokenKey, uint asset, uint debt) external onlyOwner {
        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        quota._asset = asset;
        quota._debt = debt;
    }

    function upgrade(bytes32[] storemanGroupIdArray) external onlyOwner {
        require(version < 2, "Can upgrade again.");
        version = 2; //upgraded v2
        uint length = storemanGroupIdArray.length;

        for (uint m = 0; m < length; m++) {
            bytes32 storemanGroupId = storemanGroupIdArray[m];
            uint tokenCount = storemanTokenCountMap[storemanGroupId];

            for (uint i = 0; i < tokenCount; i++) {
                uint id = storemanTokensMap[storemanGroupId][i];
                uint tokenKey = getTokenKey(id);

                Quota storage src = quotaMap[id][storemanGroupId];

                uint debt = src._debt;
                if (debt > 0) {
                    Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];        
                    if (!quota._active) {
                        quota._active = true;
                        v2TokensMap[storemanGroupId][v2TokenCountMap[storemanGroupId]] = tokenKey;
                        v2TokenCountMap[storemanGroupId] = v2TokenCountMap[storemanGroupId]
                            .add(1);
                    }
                    quota._debt = quota._debt.add(debt);
                }

                uint asset = src._asset;
                if (asset > 0) {
                    Quota storage quota2 = v2QuotaMap[tokenKey][storemanGroupId];
                    if (!quota2._active) {
                        quota2._active = true;
                        v2TokensMap[storemanGroupId][v2TokenCountMap[storemanGroupId]] = tokenKey;
                        v2TokenCountMap[storemanGroupId] = v2TokenCountMap[storemanGroupId]
                            .add(1);
                    }
                    quota2._asset = quota2._asset.add(asset);
                }
            }
        }
    }

    function transferAsset(
        bytes32 srcStoremanGroupId,
        bytes32 dstStoremanGroupId
    ) external onlyHtlc {
        uint tokenCount = v2TokenCountMap[srcStoremanGroupId];
        for (uint i = 0; i < tokenCount; i++) {
            uint id = v2TokensMap[srcStoremanGroupId][i];
            Quota storage src = v2QuotaMap[id][srcStoremanGroupId];
            if (src._asset == 0) {
                continue;
            }
            Quota storage dst = v2QuotaMap[id][dstStoremanGroupId];
            if (!dst._active) {
                dst._active = true;
                v2TokensMap[dstStoremanGroupId][v2TokenCountMap[dstStoremanGroupId]] = id;
                v2TokenCountMap[dstStoremanGroupId] = v2TokenCountMap[dstStoremanGroupId]
                    .add(1);
            }
            /// Adjust quota record
            dst._asset = dst._asset.add(src._asset);

            emit AssetTransfered(srcStoremanGroupId, dstStoremanGroupId, id, src._asset);

            src.asset_payable = 0;
            src._asset = 0;
        }
    }

    function receiveDebt(
        bytes32 srcStoremanGroupId,
        bytes32 dstStoremanGroupId
    ) external onlyHtlc {
        uint tokenCount = v2TokenCountMap[srcStoremanGroupId];
        for (uint i = 0; i < tokenCount; i++) {
            uint id = v2TokensMap[srcStoremanGroupId][i];
            Quota storage src = v2QuotaMap[id][srcStoremanGroupId];
            if (src._debt == 0) {
                continue;
            }
            Quota storage dst = v2QuotaMap[id][dstStoremanGroupId];
            if (!dst._active) {
                dst._active = true;
                v2TokensMap[dstStoremanGroupId][v2TokenCountMap[dstStoremanGroupId]] = id;
                v2TokenCountMap[dstStoremanGroupId] = v2TokenCountMap[dstStoremanGroupId]
                    .add(1);
            }
            /// Adjust quota record
            dst._debt = dst._debt.add(src._debt);

            emit DebtReceived(srcStoremanGroupId, dstStoremanGroupId, id, src._debt);

            src.debt_payable = 0;
            src._debt = 0;
        }
    }

    function getQuotaMap(uint tokenKey, bytes32 storemanGroupId) 
        public view returns (uint debt_receivable, uint debt_payable, uint _debt, uint asset_receivable, uint asset_payable, uint _asset, bool _active) {
        Quota storage quota = v2QuotaMap[tokenKey][storemanGroupId];
        return (quota.debt_receivable, quota.debt_payable, quota._debt, quota.asset_receivable, quota.asset_payable, quota._asset, quota._active);
    }

    function getTokenKey(uint tokenId) public view returns (uint) {
        string memory symbol;
        uint decimals;
        (symbol, decimals) = getTokenAncestorInfo(tokenId);
        uint tokenKey = uint(keccak256(abi.encodePacked(symbol, decimals)));
        return tokenKey;
    }

    function getTokenCount(bytes32 storemanGroupId) public view returns (uint) {
        return v2TokenCountMap[storemanGroupId];
    }

    function getTokenId(bytes32 storemanGroupId, uint index) public view returns (uint) {
        return v2TokensMap[storemanGroupId][index];
    }

    function getTokenQuota(string ancestorSymbol, uint decimals, bytes32 storemanGroupId)
        public view returns (uint debt_receivable, uint debt_payable, uint _debt, uint asset_receivable, uint asset_payable, uint _asset, bool _active) {
        uint tokenKey = uint(keccak256(abi.encodePacked(ancestorSymbol, decimals)));
        return getQuotaMap(tokenKey, storemanGroupId);
    }

    function getOldQuotaMap(uint tokenId, bytes32 storemanGroupId) 
        public view returns (uint debt_receivable, uint debt_payable, uint _debt, uint asset_receivable, uint asset_payable, uint _asset, bool _active) {
        Quota storage quota = quotaMap[tokenId][storemanGroupId];
        return (quota.debt_receivable, quota.debt_payable, quota._debt, quota.asset_receivable, quota.asset_payable, quota._asset, quota._active);
    }

    // ----------- Private Functions ---------------

    function getTokenAncestorInfo(uint tokenId)
        private
        view
        returns (string ancestorSymbol, uint decimals)
    {
        _ITokenManager tokenManager = _ITokenManager(tokenManagerAddress);
        (ancestorSymbol,decimals) = tokenManager.getAncestorSymbol(tokenId);
    }

    function stringToBytes32(string memory source) public pure returns (bytes32 result) {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
            return 0x0;
        }

        assembly {
            result := mload(add(source, 32))
        }
    }

    function getPrice(string symbol) private view returns (uint price) {
        IOracle oracle = IOracle(priceOracleAddress);
        price = oracle.getValue(stringToBytes32(symbol));
    }
}
          

contracts/components/Owned.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

/// @dev `Owned` is a base level contract that assigns an `owner` that can be
///  later changed
contract Owned {

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /// @dev `owner` is the only address that can call a function with this
    /// modifier
    modifier onlyOwner() {
        require(msg.sender == owner, "Not owner");
        _;
    }

    address public owner;

    /// @notice The Constructor assigns the message sender to be `owner`
    constructor() public {
        owner = msg.sender;
    }

    address public newOwner;

    function transferOwner(address _newOwner) public onlyOwner {
        require(_newOwner != address(0), "New owner is the zero address");
        emit OwnershipTransferred(owner, _newOwner);
        owner = _newOwner;
    }

    /// @notice `owner` can step down and assign some other address to this role
    /// @param _newOwner The address of the new owner. 0x0 can be used to create
    ///  an unowned neutral vault, however that cannot be undone
    function changeOwner(address _newOwner) public onlyOwner {
        newOwner = _newOwner;
    }

    function acceptOwnership() public {
        if (msg.sender == newOwner) {
            owner = newOwner;
        }
    }

    function renounceOwnership() public onlyOwner {
        owner = address(0);
    }
}
          

contracts/components/Halt.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
import './Owned.sol';

contract Halt is Owned {

    bool public halted = false;

    modifier notHalted() {
        require(!halted, "Smart contract is halted");
        _;
    }

    modifier isHalted() {
        require(halted, "Smart contract is not halted");
        _;
    }

    /// @notice function Emergency situation that requires
    /// @notice contribution period to stop or not.
    function setHalt(bool halt)
        public
        onlyOwner
    {
        halted = halt;
    }
}
          

openzeppelin-eth/contracts/token/ERC721/ERC721.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../introspection/ERC165.sol";


/**
 * @title ERC721 Non-Fungible Token Standard basic implementation
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721 is Initializable, ERC165, IERC721 {

  using SafeMath for uint256;
  using Address for address;

  // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
  // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
  bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;

  // Mapping from token ID to owner
  mapping (uint256 => address) private _tokenOwner;

  // Mapping from token ID to approved address
  mapping (uint256 => address) private _tokenApprovals;

  // Mapping from owner to number of owned token
  mapping (address => uint256) private _ownedTokensCount;

  // Mapping from owner to operator approvals
  mapping (address => mapping (address => bool)) private _operatorApprovals;

  bytes4 private constant _InterfaceId_ERC721 = 0x80ac58cd;
  /*
   * 0x80ac58cd ===
   *   bytes4(keccak256('balanceOf(address)')) ^
   *   bytes4(keccak256('ownerOf(uint256)')) ^
   *   bytes4(keccak256('approve(address,uint256)')) ^
   *   bytes4(keccak256('getApproved(uint256)')) ^
   *   bytes4(keccak256('setApprovalForAll(address,bool)')) ^
   *   bytes4(keccak256('isApprovedForAll(address,address)')) ^
   *   bytes4(keccak256('transferFrom(address,address,uint256)')) ^
   *   bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^
   *   bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))
   */

  function initialize()
    public
    initializer
  {
    ERC165.initialize();

    // register the supported interfaces to conform to ERC721 via ERC165
    _registerInterface(_InterfaceId_ERC721);
  }

  function _hasBeenInitialized() internal view returns (bool) {
    return supportsInterface(_InterfaceId_ERC721);
  }

  /**
   * @dev Gets the balance of the specified address
   * @param owner address to query the balance of
   * @return uint256 representing the amount owned by the passed address
   */
  function balanceOf(address owner) public view returns (uint256) {
    require(owner != address(0));
    return _ownedTokensCount[owner];
  }

  /**
   * @dev Gets the owner of the specified token ID
   * @param tokenId uint256 ID of the token to query the owner of
   * @return owner address currently marked as the owner of the given token ID
   */
  function ownerOf(uint256 tokenId) public view returns (address) {
    address owner = _tokenOwner[tokenId];
    require(owner != address(0));
    return owner;
  }

  /**
   * @dev Approves another address to transfer the given token ID
   * The zero address indicates there is no approved address.
   * There can only be one approved address per token at a given time.
   * Can only be called by the token owner or an approved operator.
   * @param to address to be approved for the given token ID
   * @param tokenId uint256 ID of the token to be approved
   */
  function approve(address to, uint256 tokenId) public {
    address owner = ownerOf(tokenId);
    require(to != owner);
    require(msg.sender == owner || isApprovedForAll(owner, msg.sender));

    _tokenApprovals[tokenId] = to;
    emit Approval(owner, to, tokenId);
  }

  /**
   * @dev Gets the approved address for a token ID, or zero if no address set
   * Reverts if the token ID does not exist.
   * @param tokenId uint256 ID of the token to query the approval of
   * @return address currently approved for the given token ID
   */
  function getApproved(uint256 tokenId) public view returns (address) {
    require(_exists(tokenId));
    return _tokenApprovals[tokenId];
  }

  /**
   * @dev Sets or unsets the approval of a given operator
   * An operator is allowed to transfer all tokens of the sender on their behalf
   * @param to operator address to set the approval
   * @param approved representing the status of the approval to be set
   */
  function setApprovalForAll(address to, bool approved) public {
    require(to != msg.sender);
    _operatorApprovals[msg.sender][to] = approved;
    emit ApprovalForAll(msg.sender, to, approved);
  }

  /**
   * @dev Tells whether an operator is approved by a given owner
   * @param owner owner address which you want to query the approval of
   * @param operator operator address which you want to query the approval of
   * @return bool whether the given operator is approved by the given owner
   */
  function isApprovedForAll(
    address owner,
    address operator
  )
    public
    view
    returns (bool)
  {
    return _operatorApprovals[owner][operator];
  }

  /**
   * @dev Transfers the ownership of a given token ID to another address
   * Usage of this method is discouraged, use `safeTransferFrom` whenever possible
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
  */
  function transferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
  {
    require(_isApprovedOrOwner(msg.sender, tokenId));
    require(to != address(0));

    _clearApproval(from, tokenId);
    _removeTokenFrom(from, tokenId);
    _addTokenTo(to, tokenId);

    emit Transfer(from, to, tokenId);
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   *
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
  */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId
  )
    public
  {
    // solium-disable-next-line arg-overflow
    safeTransferFrom(from, to, tokenId, "");
  }

  /**
   * @dev Safely transfers the ownership of a given token ID to another address
   * If the target address is a contract, it must implement `onERC721Received`,
   * which is called upon a safe transfer, and return the magic value
   * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`; otherwise,
   * the transfer is reverted.
   * Requires the msg sender to be the owner, approved, or operator
   * @param from current owner of the token
   * @param to address to receive the ownership of the given token ID
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes data to send along with a safe transfer check
   */
  function safeTransferFrom(
    address from,
    address to,
    uint256 tokenId,
    bytes _data
  )
    public
  {
    transferFrom(from, to, tokenId);
    // solium-disable-next-line arg-overflow
    require(_checkAndCallSafeTransfer(from, to, tokenId, _data));
  }

  /**
   * @dev Returns whether the specified token exists
   * @param tokenId uint256 ID of the token to query the existence of
   * @return whether the token exists
   */
  function _exists(uint256 tokenId) internal view returns (bool) {
    address owner = _tokenOwner[tokenId];
    return owner != address(0);
  }

  /**
   * @dev Returns whether the given spender can transfer a given token ID
   * @param spender address of the spender to query
   * @param tokenId uint256 ID of the token to be transferred
   * @return bool whether the msg.sender is approved for the given token ID,
   *  is an operator of the owner, or is the owner of the token
   */
  function _isApprovedOrOwner(
    address spender,
    uint256 tokenId
  )
    internal
    view
    returns (bool)
  {
    address owner = ownerOf(tokenId);
    // Disable solium check because of
    // https://github.com/duaraghav8/Solium/issues/175
    // solium-disable-next-line operator-whitespace
    return (
      spender == owner ||
      getApproved(tokenId) == spender ||
      isApprovedForAll(owner, spender)
    );
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param to The address that will own the minted token
   * @param tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address to, uint256 tokenId) internal {
    require(to != address(0));
    _addTokenTo(to, tokenId);
    emit Transfer(address(0), to, tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    _clearApproval(owner, tokenId);
    _removeTokenFrom(owner, tokenId);
    emit Transfer(owner, address(0), tokenId);
  }

  /**
   * @dev Internal function to clear current approval of a given token ID
   * Reverts if the given address is not indeed the owner of the token
   * @param owner owner of the token
   * @param tokenId uint256 ID of the token to be transferred
   */
  function _clearApproval(address owner, uint256 tokenId) internal {
    require(ownerOf(tokenId) == owner);
    if (_tokenApprovals[tokenId] != address(0)) {
      _tokenApprovals[tokenId] = address(0);
    }
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param to address representing the new owner of the given token ID
   * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function _addTokenTo(address to, uint256 tokenId) internal {
    require(_tokenOwner[tokenId] == address(0));
    _tokenOwner[tokenId] = to;
    _ownedTokensCount[to] = _ownedTokensCount[to].add(1);
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param from address representing the previous owner of the given token ID
   * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function _removeTokenFrom(address from, uint256 tokenId) internal {
    require(ownerOf(tokenId) == from);
    _ownedTokensCount[from] = _ownedTokensCount[from].sub(1);
    _tokenOwner[tokenId] = address(0);
  }

  /**
   * @dev Internal function to invoke `onERC721Received` on a target address
   * The call is not executed if the target address is not a contract
   * @param from address representing the previous owner of the given token ID
   * @param to target address that will receive the tokens
   * @param tokenId uint256 ID of the token to be transferred
   * @param _data bytes optional data to send along with the call
   * @return whether the call correctly returned the expected magic value
   */
  function _checkAndCallSafeTransfer(
    address from,
    address to,
    uint256 tokenId,
    bytes _data
  )
    internal
    returns (bool)
  {
    if (!to.isContract()) {
      return true;
    }
    bytes4 retval = IERC721Receiver(to).onERC721Received(
      msg.sender, from, tokenId, _data);
    return (retval == _ERC721_RECEIVED);
  }

  uint256[50] private ______gap;
}
          

contracts/test/TestQuotaHelper.sol

pragma solidity 0.4.26;

import "../interfaces/ITokenManager.sol";

contract TestQuotaHelper {
    mapping(bytes32 => uint256) priceMap;

    constructor() public {
        priceMap[stringToBytes32("BTC")] = 998000000000;
        priceMap[stringToBytes32("ETH")] = 24500000000;
        priceMap[stringToBytes32("WAN")] = 21240000;
    }

    function stringToBytes32(string memory source) public pure returns (bytes32 result) {
        bytes memory tempEmptyStringTest = bytes(source);
        if (tempEmptyStringTest.length == 0) {
            return 0x0;
        }

        assembly {
            result := mload(add(source, 32))
        }
    }

    function getValue(bytes32 key) public view returns (uint256 price) {
        return priceMap[key];
    }

    function setValue(string key, uint256 value) public {
        priceMap[stringToBytes32(key)] = value;
    }

    function getStoremanGroupConfig(bytes32 storemanGroupId)
        external
        pure
        returns (
            bytes32 groupId,
            uint256 status,
            uint256 deposit,
            uint256 chain1,
            uint256 chain2,
            uint256 curve1,
            uint256 curve2,
            bytes gpk1,
            bytes gpk2,
            uint256 startTime,
            uint256 endTime
        )
    {
        if (storemanGroupId == keccak256("storeman1")) {
            deposit = 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman2")) {
            deposit = 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman3")) {
            deposit = 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman4")) {
            deposit = 1000 ether;
        }
    }

    function getDeposit(bytes32 storemanGroupId)
        public
        pure
        returns (uint256 deposit)
    {
        if (storemanGroupId == keccak256("storeman1")) {
            return 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman2")) {
            return 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman3")) {
            return 1000 ether;
        }

        if (storemanGroupId == keccak256("storeman4")) {
            return 100 ether;
        }

        return 0;
    }

    function getAncestorInfo(uint256 id)
        external
        pure
        returns (
            bytes account,
            string name,
            string symbol,
            uint8 decimals,
            uint256 chainId
        )
    {
        if (id == 0) {
            return ("", "", "WAN", 18, 1);
        }

        if (id == 1) {
            return ("", "", "BTC", 8, 1);
        }

        if (id == 2) {
            return ("", "", "ETH", 18, 1);
        }

        if (id == 3) {
            return ("", "", "ETC", 18, 1);
        }

        return ("", "", "", 0, 1);
    }

    function getAncestorSymbol(uint id) external pure returns (string symbol, uint8 decimals) {
        if (id == 0) {
            return ("WAN", 18);
        }

        if (id == 1) {
            return ("BTC", 8);
        }

        if (id == 2) {
            return ("ETH", 18);
        }

        if (id == 3) {
            return ("ETC", 18);
        }

        return ("", 0);
    }

    function isDebtClean(bytes32 storemanGroupId) external pure returns (bool) {
        return false;
    }
}
          

contracts/crossApproach/CrossDelegateV4.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./CrossStorageV4.sol";
import "./lib/RapidityLibV4.sol";
import "./lib/NFTLibV1.sol";


contract CrossDelegateV4 is CrossStorageV4 {
    using SafeMath for uint;

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                         event of admin config
    /// @param adminAccount             account of admin
    event SetAdmin(address adminAccount);

    /// @notice                         event of setFee or setFees
    /// @param srcChainID               source of cross chain
    /// @param destChainID              destination of cross chain
    /// @param contractFee              contract fee
    /// @param agentFee                 agent fee
    event SetFee(uint indexed srcChainID, uint indexed destChainID, uint contractFee, uint agentFee);

    /// @notice                         event of setFee or setFees
    /// @param tokenPairID              ID of token pair
    /// @param contractFee              contract fee
    event SetTokenPairFee(uint indexed tokenPairID, uint contractFee);

    /// @notice                         event of storeman group ID withdraw the original coin to receiver
    /// @param smgID                    ID of storeman group
    /// @param timeStamp                timestamp of the withdraw
    /// @param receiver                 receiver address
    /// @param fee                      shadow coin of the fee which the storeman group pk got it
    event WithdrawHistoryFeeLogger(bytes32 indexed smgID, uint indexed timeStamp, address indexed receiver, uint fee);

    /**
     *
     * MODIFIERS
     *
     */
    /// @notice                                 check the admin or not
    modifier onlyAdmin() {
        require(msg.sender == admin, "not admin");
        _;
    }

    /// @notice                                 check the storeman group is ready
    /// @param smgID                            ID of storeman group
    modifier onlyReadySmg(bytes32 smgID) {
        uint8 status;
        uint startTime;
        uint endTime;
        (status,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupStatus(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");
        _;
    }


    /**
     *
     * MANIPULATIONS
     *
     */
    /// @notice                                 request exchange orignal coin or token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain coin/token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive shadow chain token
    function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes userAccount)
    external
    payable
    notHalted
    onlyReadySmg(smgID)
    {
        address smgFeeProxy = getSmgFeeProxy();

        RapidityLibV4.RapidityUserLockParams memory params = RapidityLibV4.RapidityUserLockParams({
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        currentChainID: currentChainID,
        tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
        destUserAccount: userAccount,
        smgFeeProxy: smgFeeProxy
        });
        RapidityLibV4.userLock(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive original chain token
    function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes userAccount)
    external
    payable
    notHalted
    onlyReadySmg(smgID)
    {
        address smgFeeProxy = getSmgFeeProxy();

        RapidityLibV4.RapidityUserBurnParams memory params = RapidityLibV4.RapidityUserBurnParams({
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        currentChainID: currentChainID,
        tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
        srcTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: smgFeeProxy
        });
        RapidityLibV4.userBurn(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  fee                             exchange fee
    /// @param  userAccount                     address of user, used to receive WRC20 token
    /// @param  r                               signature
    /// @param  s                               signature
    function smgMint(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes r, bytes32 s)
    external
    notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV4.RapiditySmgMintParams memory params = RapidityLibV4.RapiditySmgMintParams({
        uniqueID: uniqueID,
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        destTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
        });
        RapidityLibV4.smgMint(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  fee                             exchange fee
    /// @param  userAccount                     address of user, used to receive original token/coin
    /// @param  r                               signature
    /// @param  s                               signature
    function smgRelease(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes r, bytes32 s)
    external
    notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV4.RapiditySmgReleaseParams memory params = RapidityLibV4.RapiditySmgReleaseParams({
        uniqueID: uniqueID,
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        destTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
        });
        RapidityLibV4.smgRelease(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param param                        struct of setFee parameter
    function setFee(SetFeesParam param) public onlyAdmin {
        storageData.mapContractFee[param.srcChainID][param.destChainID] = param.contractFee;
        storageData.mapAgentFee[param.srcChainID][param.destChainID] = param.agentFee;
        emit SetFee(param.srcChainID, param.destChainID, param.contractFee, param.agentFee);
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param params                        struct of setFees parameter
    function setFees(SetFeesParam [] params) public onlyAdmin {
        for (uint i = 0; i < params.length; ++i) {
            storageData.mapContractFee[params[i].srcChainID][params[i].destChainID] = params[i].contractFee;
            storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID] = params[i].agentFee;
            emit SetFee(params[i].srcChainID, params[i].destChainID, params[i].contractFee, params[i].agentFee);
        }
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param tokenPairID                  ID of token pair
    /// @param contractFee                  contractFee of token pair
    function setTokenPairFee(uint256 tokenPairID, uint256 contractFee) external onlyAdmin {
        mapTokenPairContractFee[tokenPairID] = contractFee;
        emit SetTokenPairFee(tokenPairID, contractFee);
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param params                       struct of setTokenPairFees parameter
    function setTokenPairFees(SetTokenPairFeesParam [] params) public onlyAdmin {
        for (uint i = 0; i < params.length; ++i) {
            mapTokenPairContractFee[params[i].tokenPairID] = params[i].contractFee;
            emit SetTokenPairFee(params[i].tokenPairID, params[i].contractFee);
        }
    }

    function setChainID(uint256 chainID) external onlyAdmin {
        if (currentChainID == 0) {
            currentChainID = chainID;
        }
    }

    function setAdmin(address adminAccount) external onlyOwner {
        admin = adminAccount;
        emit SetAdmin(adminAccount);
    }

    function setUintValue(bytes key, bytes innerKey, uint value) external onlyAdmin {
        return uintData.setStorage(key, innerKey, value);
    }

    function delUintValue(bytes key, bytes innerKey) external onlyAdmin {
        return uintData.delStorage(key, innerKey);
    }

    /// @notice                             update the initialized state value of this contract
    /// @param tokenManager                 address of the token manager
    /// @param smgAdminProxy                address of the storeman group admin
    /// @param smgFeeProxy                  address of the proxy to store fee for storeman group
    /// @param quota                        address of the quota
    /// @param sigVerifier                  address of the signature verifier
    function setPartners(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    external
    onlyOwner
    {
        // require(tokenManager != address(0) && smgAdminProxy != address(0) && quota != address(0) && sigVerifier != address(0),
        //     "Parameter is invalid");
        require(tokenManager != address(0) && smgAdminProxy != address(0) && sigVerifier != address(0),
            "Parameter is invalid");

        storageData.smgAdminProxy = IStoremanGroup(smgAdminProxy);
        storageData.tokenManager = ITokenManager(tokenManager);
        // storageData.quota = IQuota(quota);
        storageData.smgFeeProxy = smgFeeProxy;
        storageData.sigVerifier = ISignatureVerifier(sigVerifier);
    }


    /// @notice                             withdraw the history fee to foundation account
    /// @param smgIDs                       array of storemanGroup ID
    function smgWithdrawHistoryFee(bytes32 [] smgIDs) external {
        uint fee;
        uint currentFee;
        address smgFeeProxy = storageData.smgFeeProxy;
        if (smgFeeProxy == address(0)) {
            smgFeeProxy = owner;
        }
        require(smgFeeProxy != address(0), "invalid smgFeeProxy");

        for (uint i = 0; i < smgIDs.length; ++i) {
            currentFee = storageData.mapStoremanFee[smgIDs[i]];
            delete storageData.mapStoremanFee[smgIDs[i]];
            fee = fee.add(currentFee);
            emit WithdrawHistoryFeeLogger(smgIDs[i], block.timestamp, smgFeeProxy, currentFee);
        }
        if (fee > 0) {
            smgFeeProxy.transfer(fee);
        }
    }


    /** Get Functions */

    function getUintValue(bytes key, bytes innerKey) public view returns (uint) {
        return uintData.getStorage(key, innerKey);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param key                          key of storeman fee
    /// @return fee                         original coin the storeman group should get
    function getStoremanFee(bytes32 key) external view returns(uint fee) {
        fee = storageData.mapStoremanFee[key];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param param                        struct of getFee parameter
    /// @return fees                        struct of getFee return
    function getFee(GetFeesParam param) public view returns(GetFeesReturn fee) {
        fee.contractFee = storageData.mapContractFee[param.srcChainID][param.destChainID];
        fee.agentFee = storageData.mapAgentFee[param.srcChainID][param.destChainID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param params                       struct of getFees parameter
    /// @return fees                        struct of getFees return
    function getFees(GetFeesParam [] params) public view returns(GetFeesReturn [] fees) {
        fees = new GetFeesReturn[](params.length);
        for (uint i = 0; i < params.length; ++i) {
            fees[i].contractFee = storageData.mapContractFee[params[i].srcChainID][params[i].destChainID];
            fees[i].agentFee = storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID];
        }
    }

    /// @notice                             get the token pair fee of the storeman group should get
    /// @param tokenPairID                  ID of token pair
    /// @return contractFee                 contractFee of token pair
    function getTokenPairFee(uint256 tokenPairID) external view returns(uint256 contractFee) {
        contractFee = mapTokenPairContractFee[tokenPairID];
    }

    /// @notice                             get the token pair fees of the storeman group should get
    /// @param tokenPairIDs                 array of tokenPairID
    /// @return contractFees                array of tokenPair contractFee
    function getTokenPairFees(uint256[] tokenPairIDs) external view returns(uint256 [] contractFees) {
        contractFees = new uint256[](tokenPairIDs.length);
        for (uint i = 0; i < tokenPairIDs.length; ++i) {
            contractFees[i] = mapTokenPairContractFee[tokenPairIDs[i]];
        }
    }

    /// @notice                             get the initialized state value of this contract
    /// @return tokenManager                address of the token manager
    /// @return smgAdminProxy               address of the storeman group admin
    /// @return smgFeeProxy                 address of the proxy to store fee for storeman group
    /// @return quota                       address of the quota
    /// @return sigVerifier                 address of the signature verifier
    function getPartners()
    external
    view
    returns(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    {
        tokenManager = address(storageData.tokenManager);
        smgAdminProxy = address(storageData.smgAdminProxy);
        smgFeeProxy = storageData.smgFeeProxy;
        quota = address(storageData.quota);
        sigVerifier = address(storageData.sigVerifier);
    }


    /** Private and Internal Functions */

    /// @notice                                 check the storeman group is ready or not
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireReadySmgInfo(bytes32 smgID)
    internal
    view
    returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        uint startTime;
        uint endTime;
        (,status,,,,curveID,,PK,,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");

        return (curveID, PK);
    }

    /// @notice                                 get the unregistered storeman group info
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireUnregisteredSmgInfo(bytes32 smgID)
    internal
    view
    returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        (,status,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.unregistered), "PK is not unregistered");
    }

    /// @notice       convert bytes to bytes32
    /// @param b      bytes array
    /// @param offset offset of array to begin convert
    function bytesToBytes32(bytes memory b, uint offset) internal pure returns (bytes32 result) {
        assembly {
            result := mload(add(add(b, offset), 32))
        }
    }

    /// @notice             verify signature
    /// @param  curveID     ID of elliptic curve
    /// @param  message     message to be verified
    /// @param  r           Signature info r
    /// @param  s           Signature info s
    function verifySignature(uint curveID, bytes32 message, bytes PK, bytes r, bytes32 s) internal {
        bytes32 PKx = bytesToBytes32(PK, 0);
        bytes32 PKy = bytesToBytes32(PK, 32);

        bytes32 Rx = bytesToBytes32(r, 0);
        bytes32 Ry = bytesToBytes32(r, 32);

        require(storageData.sigVerifier.verify(curveID, s, PKx, PKy, Rx, Ry, message), "Signature verification failed");
    }

    function getSmgFeeProxy() internal view returns (address) {
        address smgFeeProxy = storageData.smgFeeProxy;
        return (smgFeeProxy == address(0)) ? owner : smgFeeProxy;
    }

    //*********************************************************************************************
    //*********************************************************************************************
    // NFT
    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a `safeTransfer`. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.

     * Note: the ERC721 contract address is always the message sender.

     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes data)
        public
        pure
        returns(bytes4)
    {
        return this.onERC721Received.selector;
    }

    function onERC1155Received(address, address, uint256, uint256, bytes memory) 
        public 
        pure 
        returns (bytes4)
    {
        return this.onERC1155Received.selector;
    }

    function onERC1155BatchReceived(address, address, uint256[] memory, uint256[] memory, bytes memory) 
        public
        pure
        returns (bytes4)
    {
        return this.onERC1155BatchReceived.selector;
    }


    function userLockNFT(bytes32 smgID, uint tokenPairID, uint[] tokenIDs, uint[] tokenValues, bytes userAccount)
        public
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        require(tokenIDs.length > 0 && tokenIDs.length <= getMaxBatchSize(), "Invalid length");
        require(tokenIDs.length == tokenValues.length, "Length mismatch");

        NFTLibV1.RapidityUserLockNFTParams memory params = NFTLibV1.RapidityUserLockNFTParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            tokenIDs: tokenIDs,
            tokenValues: tokenValues,
            currentChainID: currentChainID,
            tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
            destUserAccount: userAccount,
            smgFeeProxy: getSmgFeeProxy()
        });
        NFTLibV1.userLockNFT(storageData, params);
    }
    
    function userBurnNFT(bytes32 smgID, uint tokenPairID, uint[] tokenIDs, uint[] tokenValues, address tokenAccount, bytes userAccount)
        public
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        require(tokenIDs.length > 0 && tokenIDs.length <= getMaxBatchSize(), "Invalid length");
        require(tokenIDs.length == tokenValues.length, "Length mismatch");

        NFTLibV1.RapidityUserBurnNFTParams memory params = NFTLibV1.RapidityUserBurnNFTParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            tokenIDs: tokenIDs,
            tokenValues: tokenValues,
            currentChainID: currentChainID,
            tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
            srcTokenAccount: tokenAccount,
            destUserAccount: userAccount,
            smgFeeProxy: getSmgFeeProxy()
        });
        NFTLibV1.userBurnNFT(storageData, params);
    }

    function smgMintNFT(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint[] tokenIDs, uint[] tokenValues, bytes extData, address tokenAccount, address userAccount, bytes r, bytes32 s)
        public
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        NFTLibV1.RapiditySmgMintNFTParams memory params = NFTLibV1.RapiditySmgMintNFTParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            tokenIDs: tokenIDs,
            tokenValues: tokenValues,
            extData: extData,
            destTokenAccount: tokenAccount,
            destUserAccount: userAccount
        });

        NFTLibV1.smgMintNFT(storageData, params);
        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, tokenIDs, tokenValues, extData, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    function smgReleaseNFT(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint[] tokenIDs, uint[] tokenValues, address tokenAccount, address userAccount, bytes r, bytes32 s)
        public
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        NFTLibV1.RapiditySmgReleaseNFTParams memory params = NFTLibV1.RapiditySmgReleaseNFTParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            tokenIDs: tokenIDs,
            tokenValues: tokenValues,
            destTokenAccount: tokenAccount,
            destUserAccount: userAccount
        });
        NFTLibV1.smgReleaseNFT(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, tokenIDs, tokenValues, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    function setMaxBatchSize(uint _maxBatchSize) 
      external
      onlyAdmin
    {
      maxBatchSize = _maxBatchSize;
    }

    function getMaxBatchSize() 
      public
      view
      returns (uint)
    {
      if(maxBatchSize == 0) {
        return 20;
      }
      return maxBatchSize;
    }

    function getBatchFee(uint tokenPairID, uint batchLength) 
      external
      view
      returns (uint)
    {
      uint contractFee;
      (, contractFee) = NFTLibV1.getTokenScAddrAndContractFee(storageData, tokenPairID, mapTokenPairContractFee[tokenPairID], currentChainID, batchLength);
      return contractFee;
    }
}
          

contracts/components/ReentrancyGuard.sol

pragma solidity 0.4.26;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
contract ReentrancyGuard {
    bool private _notEntered;

    constructor () internal {
        // Storing an initial non-zero value makes deployment a bit more
        // expensive, but in exchange the refund on every call to nonReentrant
        // will be lower in amount. Since refunds are capped to a percetange of
        // the total transaction's gas, it is best to keep them low in cases
        // like this one, to increase the likelihood of the full refund coming
        // into effect.
        _notEntered = true;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_notEntered, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _notEntered = false;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _notEntered = true;
    }
}
          

contracts/test/TestWanToken.sol

pragma solidity ^0.4.24;

import "../tokenManager/WanToken.sol";
import "../components/BasicStorage.sol";
import "./TestIOwned.sol";

contract TestWanToken is BasicStorage {

    function createToken(string tokenName, string tokenSymbol, uint8 tokenDecimal) external {
        address tokenInst = new WanToken(tokenName, tokenSymbol, tokenDecimal);
        addressData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenInst);
        uintData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenDecimal);
        // TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function changeOwner(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function acceptOwnership(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).acceptOwnership();
    }

    function getTokenAddr(string tokenName, string tokenSymbol) external view returns (address) {
        return addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
    }

    function getTokenDecimal(string tokenName, string tokenSymbol) external view returns (uint8) {
        return uint8(uintData.getStorage(bytes(tokenName), bytes(tokenSymbol)));
    }

    function destroyToken(string tokenName, string tokenSymbol) external {
        addressData.delStorage(bytes(tokenName), bytes(tokenSymbol));
        uintData.delStorage(bytes(tokenName), bytes(tokenSymbol));
    }
}
          

contracts/storemanGroupAdmin/StoremanGroupDelegate.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';
import "../components/Halt.sol";
import "../components/Admin.sol";
import "./StoremanGroupStorage.sol";
import "../interfaces/IListGroup.sol";
import "./StoremanLib.sol";
import "./StoremanType.sol";
import "./IncentiveLib.sol";
import "../interfaces/IQuota.sol";
import "../gpk/lib/GpkTypes.sol";
import "../components/ReentrancyGuard.sol";

contract StoremanGroupDelegate is StoremanGroupStorage, Halt, Admin,ReentrancyGuard {
    using SafeMath for uint;
    using Deposit for Deposit.Records;
    bytes key = "openStoreman";
    bytes innerKey = "totalDeposit";

    event StoremanGroupRegisterStartEvent(bytes32 indexed groupId, bytes32 indexed preGroupId, uint workStart, uint workDuration, uint registerDuration);
    event StoremanGroupDismissedEvent(bytes32 indexed groupId, uint dismissTime);
    event StoremanGroupSetGpkEvent(bytes32 indexed groupId);
    event updateGroupChainEvent(bytes32 indexed groupId, uint256 indexed chain1, uint256 indexed chain2, uint256 curve1, uint256 curve2);
    event storemanGroupContributeEvent(address indexed sender, uint indexed value);

    modifier onlyGroupLeader(bytes32 groupId) {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(msg.sender == group.selectedNode[0], "Sender is not allowed");
        _;
    }

    /// @notice                           function for owner set token manager and htlc contract address
    /// @param metricAddr                 metricAddr contract address
    /// @param gpkAddr	                  gpkAddr contract address
    /// @param quotaAddr                  quotaAddr contract address
   function setDependence(address metricAddr, address gpkAddr,address quotaAddr, address posAddr)
        external
        onlyOwner
    {
        require(metricAddr != address(0), "Invalid metricAddr address");
        require(gpkAddr != address(0), "Invalid gpkAddr address");
        require(quotaAddr != address(0), "Invalid quotaAddr address");

        metric = metricAddr;
        data.posLib = posAddr;
        createGpkAddr = gpkAddr;
        quotaInst = IQuota(quotaAddr);
    }


    /// @notice                           function for owner to open a storeman group.
    /// @param wkAddrs                    white list work address array.
    /// @param senders                    senders address array of the white list enode.
    function storemanGroupRegisterStart(StoremanType.StoremanGroupInput smg,
        address[] wkAddrs, address[] senders)
        public
        onlyAdmin
    {
        bytes32 groupId = smg.groupId;
        bytes32 preGroupId = smg.preGroupId;
        require(wkAddrs.length == senders.length, "Invalid white list length");
        require(wkAddrs.length >= data.conf.backupCount, "Insufficient white list");
        require(wkAddrs.length <= smg.memberCountDesign+data.conf.backupCount, "Too many whitelist node");
        // check preGroupId exist.
        if(preGroupId != bytes32(0x00)){
            StoremanType.StoremanGroup storage preGroup = data.groups[preGroupId];
            require(preGroup.status == StoremanType.GroupStatus.ready || preGroup.status == StoremanType.GroupStatus.failed,"invalid preGroup");
        }

        initGroup(groupId, smg);
        emit StoremanGroupRegisterStartEvent(groupId, preGroupId, smg.workTime, smg.totalTime, smg.registerDuration);
        emit updateGroupChainEvent(groupId, smg.chain1, smg.chain2, smg.curve1, smg.curve2);

        return StoremanLib.inheritNode(data, groupId, preGroupId, wkAddrs, senders);
    }

    /// @dev	                    set the group chain and curve.
    function initGroup(bytes32 groupId, StoremanType.StoremanGroupInput smg)
        private
    {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(group.status == StoremanType.GroupStatus.none, "group has existed already");

        Deposit.Records memory deposit =  Deposit.Records(0);
        Deposit.Records memory depositWeight =  Deposit.Records(0);
        group.deposit = deposit;
        group.depositWeight = depositWeight;

        group.registerTime = now;
        group.status = StoremanType.GroupStatus.curveSeted;

        group.memberCountDesign = smg.memberCountDesign;
        group.workTime = smg.workTime;
        group.totalTime = smg.totalTime;
        group.registerDuration = smg.registerDuration;
        group.threshold = smg.threshold;
        group.minStakeIn = smg.minStakeIn;
        group.minDelegateIn = smg.minDelegateIn;
        group.minPartIn = smg.minPartIn;
        group.delegateFee = smg.delegateFee;
        group.chain1 = smg.chain1;
        group.chain2 = smg.chain2;
        group.curve1 = smg.curve1;
        group.curve2 = smg.curve2;
    }

    function incentiveCandidator( address wkAddr) external   {
        IncentiveLib.incentiveCandidator(data, wkAddr,metric, getGlobalGroupScAddr());
    }

    /// @notice                             Staker use this interface to stake wan to SC.
    /// @param groupId                      the storeman group index.
    /// @param PK                           the agent keystore's public key.
    /// @param enodeID                      the agent enodeID, use for p2p network.
    function stakeIn(bytes32 groupId, bytes PK, bytes enodeID)
        external
        notHalted
        payable
    {
        return StoremanLib.stakeIn(data, groupId, PK, enodeID);
    }

    /// @notice                             Staker use this interface to append wan to SC.
    /// @param wkAddr                     the agent keystore's address, which publickey is specified when stakeIn.
    function stakeAppend(address wkAddr)
        external
        notHalted
        payable
    {
        return StoremanLib.stakeAppend(data, wkAddr);
    }

    /// @notice                             Staker use this interface to anounce he will not continue in next group.
    ///  the next group will open in advance of the current group end. so if a node want to quit, it should call stakeOut before the new group open. 
    ///  If the new group has opened, the node in old group can't stake out.
    /// @param wkAddr                     the agent keystore's address, which publickey is specified when stakeIn.
    function stakeOut(address wkAddr) external notHalted {
        return StoremanLib.stakeOut(data, wkAddr);
    }
    function checkCanStakeOut(address wkAddr) external view returns(bool) {
        return StoremanLib.checkCanStakeOut(data, wkAddr);
    }

    function checkCanStakeClaim(address wkAddr) external view returns(bool){
        return StoremanLib.checkCanStakeClaim(data, wkAddr);
    }
    function checkCanPartnerClaim(address wkAddr, address pnAddr) external view returns(bool) {
        return StoremanLib.checkCanPartnerClaim(data, wkAddr, pnAddr, getGlobalGroupScAddr());
    }
    function checkCanDelegatorClaim(address wkAddr, address deAddr) external view returns(bool) {
        return StoremanLib.checkCanDelegatorClaim(data, wkAddr, deAddr, getGlobalGroupScAddr());
    }
    function stakeClaim(address wkAddr) external notHalted nonReentrant {
        return StoremanLib.stakeClaim(data,wkAddr);
    }
    function stakeIncentiveClaim(address wkAddr) external notHalted nonReentrant{
        return StoremanLib.stakeIncentiveClaim(data,wkAddr);
    }

    function delegateIn(address wkAddr)
        external
        notHalted
        payable
    {
        return StoremanLib.delegateIn(data,wkAddr);
    }
    function delegateOut(address wkAddr) external {
        return StoremanLib.delegateOut(data,wkAddr, getGlobalGroupScAddr());

    }
    function delegateClaim(address wkAddr) external notHalted nonReentrant{
        return StoremanLib.delegateClaim(data, wkAddr, getGlobalGroupScAddr());
    }
    function delegateIncentiveClaim(address wkAddr) external notHalted nonReentrant{

        return StoremanLib.delegateIncentiveClaim(data, wkAddr);

    }
    function partIn(address wkAddr)
        external
        notHalted
        payable
    {
        return StoremanLib.partIn(data,wkAddr);
    }
    function partOut(address wkAddr) external notHalted{
        return StoremanLib.partOut(data, wkAddr, getGlobalGroupScAddr());

    }
    function partClaim(address wkAddr) external notHalted nonReentrant{
        return StoremanLib.partClaim(data,wkAddr, getGlobalGroupScAddr());
    }

    function getSelectedSmNumber(bytes32 groupId) external view returns(uint) {
        return StoremanUtil.getSelectedSmNumber(data, groupId);
    }
    function getSelectedStoreman(bytes32 groupId) external view returns(address[]) {
        return StoremanUtil.getSelectedStoreman(data, groupId);
    }
    function select(bytes32 groupId)
        external
        notHalted
    {
        return IncentiveLib.toSelect(data, groupId);
    }

    function getSelectedSmInfo(bytes32 groupId, uint index) external view returns(address wkAddr, bytes PK, bytes enodeId) {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        address addr = group.selectedNode[index];
        StoremanType.Candidate storage sk = data.candidates[0][addr];
        return (sk.wkAddr, sk.PK, sk.enodeID);
    }

    // To change  group status for unexpected reason.
    function updateGroupStatus(bytes32 groupId, StoremanType.GroupStatus status) external  onlyAdmin {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        group.status = status;
    }

    function getStoremanIncentive(address wkAddr, uint day) external view returns(uint incentive) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        return sk.incentive[day];
    }

    function getSmDelegatorInfoIncentive(address wkAddr, address deAddr, uint day) external view returns ( uint) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage de = sk.delegators[deAddr];
        return (de.incentive[day]);
    }

    function getSmDelegatorInfo(address wkAddr, address deAddr) external view returns (address sender, uint deposit, uint incentive, bool quited) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage de = sk.delegators[deAddr];
        return (deAddr, de.deposit.getLastValue(),  de.incentive[0], de.quited);
    }
    function getSmPartnerInfo(address wkAddr, address pnAddr) external view returns (address sender, uint deposit, bool quited) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        StoremanType.Delegator storage pn = sk.partners[pnAddr];
        return (pnAddr, pn.deposit.getLastValue(), pn.quited);
    }
    function getSmPartnerAddr(address wkAddr, uint index) external view returns(address pkAddr) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        return sk.partMap[index];
    }
    function getSmDelegatorAddr(address wkAddr, uint index) external view returns(address deAddr) {
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];
        return sk.delegatorMap[index];
    } 
    function setGpk(bytes32 groupId, bytes gpk1, bytes gpk2)
        external
    {
        require(msg.sender == createGpkAddr, "Sender is not allowed");
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        require(group.status == StoremanType.GroupStatus.selected,"invalid status");
        group.gpk1 = gpk1;
        group.gpk2 = gpk2;
        group.status = StoremanType.GroupStatus.ready;
        addActiveGroup(groupId, group.workTime, group.workTime+group.totalTime);
        emit StoremanGroupSetGpkEvent(groupId);
    }
    function addActiveGroupId(bytes32 groupId) external onlyAdmin{
        address addr = getGlobalGroupScAddr();
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        IListGroup(addr).addActiveGroup(groupId, group.workTime, group.workTime+group.totalTime);
    }
    function getDependence() public view  returns(address metricAddr, address gpkAddr,address quotaAddr, address posAddr, address listGroupAddr) {
        return (metric, createGpkAddr,address(quotaInst), data.posLib, getGlobalGroupScAddr());
    }

    function setGlobalGroupScAddr(address _addr) external onlyOwner {
        addressData.setStorage(key, innerKey, _addr);
    }
    function getGlobalGroupScAddr() public view returns(address) {
        return addressData.getStorage(key, innerKey);
    }
    function addActiveGroup(bytes32 groupId, uint startTime, uint endTime) private {
        address addr = getGlobalGroupScAddr();
        IListGroup(addr).addActiveGroup(groupId, startTime, endTime);
    }
    function cleanExpiredGroup() private {
        address addr = getGlobalGroupScAddr();
        IListGroup(addr).cleanExpiredGroup();
    }
    function getActiveGroupIds(uint epochId) external view returns(bytes32[]){
        address addr = getGlobalGroupScAddr();
        return IListGroup(addr).getActiveGroupIds(epochId);
    }


    function setInvalidSm(bytes32 groupId, uint[] indexs, GpkTypes.SlashType[] slashTypes)
        external
        returns(bool isContinue)
    {
        require(msg.sender == createGpkAddr, "Sender is not allowed");
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        if (group.status != StoremanType.GroupStatus.selected) {
            return false;
        }
        for (uint i = 0; i < indexs.length; i++) {
            StoremanType.Candidate storage skt = data.candidates[0][group.selectedNode[indexs[i]]];
            if (slashTypes[i] == GpkTypes.SlashType.SijInvalid || slashTypes[i] == GpkTypes.SlashType.CheckInvalid || slashTypes[i] == GpkTypes.SlashType.SijTimeout) {
                recordSmSlash(group.selectedNode[indexs[i]]);
            }
            IncentiveLib.cleanSmNode(skt, groupId);
            if (group.tickedCount + group.whiteCount >= group.whiteCountAll) {
                group.status = StoremanType.GroupStatus.failed;
                return false;
            }
            group.tickedNode[group.tickedCount] = group.selectedNode[indexs[i]];
            group.selectedNode[indexs[i]] = group.whiteMap[group.whiteCount + group.tickedCount];
            group.tickedCount++;
            StoremanType.Candidate storage skn = data.candidates[0][group.selectedNode[indexs[i]]];
            if(skn.groupId == 0) {
                skn.groupId = groupId;
            }else {
                skn.nextGroupId = groupId;
            }

        }
        IncentiveLib.setGroupDeposit(data, group);
        return true;
    }

    function recordSmSlash(address wk) 
        public
    {
        require((msg.sender == metric) || (msg.sender == createGpkAddr), "Sender is not allowed");
        StoremanType.Candidate storage sk = data.candidates[0][wk];
        sk.slashedCount++;
    }



    function getThresholdByGrpId(bytes32 groupId) external view returns (uint){
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        return group.threshold;
    }


    /// @notice                           function for storeman group apply unregistration through the delegate
    /// @param groupId              storeman group groupId
    function storemanGroupUnregister(bytes32 groupId)
        external
        notHalted
        onlyGroupLeader(groupId)
    {
        StoremanLib.storemanGroupUnregister(data, groupId);
        return cleanExpiredGroup();
    }

    /// @notice                           function for storeman group apply unregistration through the delegate
    /// @param groupId                    storeman groupId
    function storemanGroupDismiss(bytes32 groupId)
        external
        notHalted
        onlyGroupLeader(groupId)
    {
        StoremanType.StoremanGroup storage group = data.groups[groupId];
        bool quitable = quotaInst.isDebtClean(groupId);
        require(quitable, "can not dismiss");

        group.status = StoremanType.GroupStatus.dismissed;
        emit StoremanGroupDismissedEvent(groupId, now);

        StoremanType.Candidate storage sk;
        for(uint i=0; i<group.selectedCount; i++){
            sk = data.candidates[0][group.selectedNode[i]];
            IncentiveLib.rotateSkGroup(data.posLib, sk, group);
        }
    }

    function checkGroupDismissable(bytes32 groupId) external view returns(bool) {
        bool dismissable = quotaInst.isDebtClean(groupId);
        return dismissable;
    }

    function getStoremanInfo(address wkAddr) external view returns(StoremanType.StoremanInfo si){
        StoremanType.Candidate storage sk = data.candidates[0][wkAddr];

        si.sender = sk.sender;
        si.enodeID = sk.enodeID;
        si.PK = sk.PK;
        si.wkAddr = sk.wkAddr;
        si.isWhite = sk.isWhite;
        si.quited = sk.quited;
        si.delegatorCount = sk.delegatorCount;
        si.delegateDeposit = sk.delegateDeposit;
        si.partnerCount = sk.partnerCount;
        si.partnerDeposit = sk.partnerDeposit;
        si.crossIncoming = sk.crossIncoming;
        si.slashedCount = sk.slashedCount;
        si.incentivedDelegator = sk.incentivedDelegator;
        si.incentivedDay = sk.incentivedDay;
        si.groupId = sk.groupId;
        si.incentive = sk.incentive[0];
        si.nextGroupId = sk.nextGroupId;
        si.deposit = sk.deposit.getLastValue();
    }
    function getStoremanGroupInfo(bytes32 id) external view returns(StoremanType.StoremanGroupInfo info){
        StoremanType.StoremanGroup storage smg = data.groups[id];
        info.groupId = id;
        info.status = smg.status;
        info.deposit = smg.deposit.getLastValue();
        info.depositWeight = smg.depositWeight.getLastValue();
        info.selectedCount = smg.selectedCount;
        info.memberCount = smg.memberCount;
        info.whiteCount = smg.whiteCount;
        info.whiteCountAll = smg.whiteCountAll;
        info.startTime = smg.workTime;
        info.endTime = smg.workTime+smg.totalTime;
        info.registerTime = smg.registerTime;
        info.registerDuration = smg.registerDuration;
        info.memberCountDesign = smg.memberCountDesign;
        info.threshold = smg.threshold;
        info.chain1 = smg.chain1;
        info.chain2 = smg.chain2;
        info.curve1 = smg.curve1;
        info.curve2 = smg.curve2;
        info.tickedCount = smg.tickedCount;
        info.minStakeIn = smg.minStakeIn;
        info.minDelegateIn = smg.minDelegateIn;
        info.minPartIn = smg.minPartIn;
        info.crossIncoming = smg.crossIncoming;
        info.gpk1 = smg.gpk1;
        info.gpk2 = smg.gpk2;
        info.delegateFee = smg.delegateFee;
    }

    function getStoremanGroupConfig(bytes32 id)
        external
        view
        returns(bytes32 groupId, StoremanType.GroupStatus status, uint deposit, uint chain1, uint chain2, uint curve1, uint curve2,  bytes gpk1, bytes gpk2, uint startTime, uint endTime)
    {
        StoremanType.StoremanGroup storage smg = data.groups[id];
        return (id, smg.status,smg.deposit.getLastValue(), smg.chain1, smg.chain2,smg.curve1, smg.curve2,
         smg.gpk1, smg.gpk2, smg.workTime, smg.workTime+smg.totalTime);
    }

    function getStoremanGroupStatus(bytes32 id)
        public
        view
        returns(StoremanType.GroupStatus status, uint startTime, uint endTime)
    {
        StoremanType.StoremanGroup storage smg = data.groups[id];
        return (smg.status, smg.workTime, smg.workTime+smg.totalTime);
    }

    function getDeposit(bytes32 id) 
        external
        view
        returns (uint)
    {
        return data.groups[id].deposit.getLastValue();
    }
    
    // function getStoremanGroupTime(bytes32 id)
    //     external
    //     view
    //     returns(bytes32 groupId,  uint registerTime, uint registerDuration,  uint startTime, uint endTime)
    // {
    //     StoremanType.StoremanGroup storage smg = data.groups[id];
    //     return (smg.groupId, smg.registerTime, smg.registerDuration, smg.workTime, smg.workTime+smg.totalTime);
    // }


    function checkGroupIncentive(bytes32 id, uint day) external view returns ( uint) {
        StoremanType.StoremanGroup storage group = data.groups[id];
        return group.groupIncentive[day];
    }

    function contribute() external payable {
        emit storemanGroupContributeEvent(msg.sender, msg.value);
        data.contribution = data.contribution.add(msg.value);
        return;
    }

    function smgTransfer(bytes32 smgID) external payable{
        StoremanType.StoremanGroup storage group = data.groups[smgID];
        group.crossIncoming =  group.crossIncoming.add(msg.value);
        uint i;
        StoremanType.Candidate storage sk;
        for(i=0; i<group.selectedCount; i++) {
            sk = data.candidates[0][group.selectedNode[i]];
            sk.crossIncoming = sk.crossIncoming.add(msg.value.div(group.selectedCount));
        }
    }

    function setChainTypeCo(uint chain1, uint chain2, uint co) external  onlyAdmin {
        if(chain1 < chain2) {
            data.chainTypeCo[chain1][chain2] = co;
        } else {
            data.chainTypeCo[chain2][chain1] = co;
        }
    }
    function getChainTypeCo(uint chain1, uint chain2) external view returns (uint co) {
        return IncentiveLib.getChainTypeCo(data, chain1, chain2);
    }

    function getStoremanConf() external view returns(uint backupCount, uint standaloneWeight, uint delegationMulti) {
        return (data.conf.backupCount, data.conf.standaloneWeight, data.conf.DelegationMulti);
    }
    function updateStoremanConf(uint backupCount, uint standaloneWeight, uint DelegationMulti) external onlyAdmin {
        data.conf.backupCount = backupCount;
        data.conf.standaloneWeight = standaloneWeight;
        data.conf.DelegationMulti = DelegationMulti;
    }
    function getGlobalIncentive() external view returns(uint contribution, uint totalReward) {
        return (data.contribution, data.totalReward);
    }
}

          

contracts/crossApproach/CrossDelegate.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "../components/Halt.sol";
import "../components/ReentrancyGuard.sol";
import "./CrossStorage.sol";
import "./lib/HTLCDebtLib.sol";
import "./lib/RapidityLib.sol";


contract CrossDelegate is CrossStorage, ReentrancyGuard, Halt {
    using SafeMath for uint;
    bytes constant currentChainIDKey = "current";
    bytes constant currentChainIDInnerKey = "chainID";

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                         event of storeman group ID withdraw the original coin to receiver
    /// @param smgID                    ID of storemanGroup
    /// @param timeStamp                timestamp of the withdraw
    /// @param receiver                 receiver address
    /// @param fee                      shadow coin of the fee which the storeman group pk got it
    event SmgWithdrawFeeLogger(bytes32 indexed smgID, uint timeStamp, address indexed receiver, uint fee);

    /**
     *
     * MODIFIERS
     *
     */

    /// @notice                                 check the storeman group is ready
    /// @param smgID                            ID of storeman group
    modifier onlyReadySmg(bytes32 smgID) {
        uint8 status;
        uint startTime;
        uint endTime;
        (status,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupStatus(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");
        _;
    }


    /**
     *
     * MANIPULATIONS
     *
     */

    /// @notice                                 check the storeman group is ready or not
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireReadySmgInfo(bytes32 smgID)
        private
        view
        returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        uint startTime;
        uint endTime;
        (,status,,,,curveID,,PK,,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");

        return (curveID, PK);
    }

    /// @notice                                 get the unregistered storeman group info
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireUnregisteredSmgInfo(bytes32 smgID)
        private
        view
        returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        (,status,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.unregistered), "PK is not unregistered");
    }

    /// @notice                                 request exchange orignal coin or token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain coin/token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive shadow chain token
    function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes userAccount)
        external
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        RapidityLib.RapidityUserLockParams memory params = RapidityLib.RapidityUserLockParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            userShadowAccount: userAccount
        });
        RapidityLib.userLock(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive original chain token
    function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes userAccount)
        external
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        RapidityLib.RapidityUserBurnParams memory params = RapidityLib.RapidityUserBurnParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            fee: fee,
            shadowTokenAccount: tokenAccount,
            userOrigAccount: userAccount
        });
        RapidityLib.userBurn(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     address of user, used to receive WRC20 token
    /// @param  r                               signature
    /// @param  s                               signature
    function smgMint(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, address tokenAccount, address userAccount, bytes r, bytes32 s)
        external
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLib.RapiditySmgMintParams memory params = RapidityLib.RapiditySmgMintParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            shadowTokenAccount: tokenAccount,
            userShadowAccount: userAccount
        });
        RapidityLib.smgMint(storageData, params);

        uint currentChainID = getUintValue(currentChainIDKey, currentChainIDInnerKey);
        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     address of user, used to receive original token/coin
    /// @param  r                               signature
    /// @param  s                               signature
    function smgRelease(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, address tokenAccount, address userAccount, bytes r, bytes32 s)
        external
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLib.RapiditySmgReleaseParams memory params = RapidityLib.RapiditySmgReleaseParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            origTokenAccount: tokenAccount,
            userOrigAccount: userAccount
        });
        RapidityLib.smgRelease(storageData, params);

        uint currentChainID = getUintValue(currentChainIDKey, currentChainIDInnerKey);
        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 transfer storeman asset
    /// @param  uniqueID                        random number (likes old xHash)
    /// @param  srcSmgID                        ID of src storeman
    /// @param  destSmgID                       ID of dst storeman
    /// @param  r                               signature
    /// @param  s                               signature
    function transferAsset(bytes32 uniqueID, bytes32 srcSmgID, bytes32 destSmgID, bytes r, bytes32 s)
        external
        notHalted
        onlyReadySmg(destSmgID)
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireUnregisteredSmgInfo(srcSmgID);

        HTLCDebtLib.DebtAssetParams memory params = HTLCDebtLib.DebtAssetParams({
            uniqueID: uniqueID,
            srcSmgID: srcSmgID,
            destSmgID: destSmgID
        });
        HTLCDebtLib.transferAsset(storageData, params);

        bytes32 mHash = sha256(abi.encode(getUintValue(currentChainIDKey, currentChainIDInnerKey), uniqueID, destSmgID));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 receive storeman debt
    /// @param  uniqueID                        random number (likes old xHash)
    /// @param  srcSmgID                        ID of src storeman
    /// @param  destSmgID                       ID of dst storeman
    /// @param  r                               signature
    /// @param  s                               signature
    function receiveDebt(bytes32 uniqueID, bytes32 srcSmgID, bytes32 destSmgID, bytes r, bytes32 s)
        external
        notHalted 
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(destSmgID);

        HTLCDebtLib.DebtAssetParams memory params = HTLCDebtLib.DebtAssetParams({
            uniqueID: uniqueID,
            srcSmgID: srcSmgID,
            destSmgID: destSmgID
        });
        HTLCDebtLib.receiveDebt(storageData, params);

        uint currentChainID = getUintValue(currentChainIDKey, currentChainIDInnerKey);
        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, srcSmgID));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param smgID                        ID of storemanGroup
    /// @return fee                         original coin the storeman group should get
    function getStoremanFee(bytes32 smgID)
        external
        view
        returns(uint fee)
    {
        fee = storageData.mapStoremanFee[smgID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param origChainID                  ID of token original chain
    /// @param shadowChainID                ID of token shadow chain
    /// @param lockFee                      Coin the storeman group should get while storeman redeem user lock
    /// @param revokeFee                    Coin the storeman group should get while user revoke its lock
    function setFees(uint origChainID, uint shadowChainID, uint lockFee, uint revokeFee)
        external
        onlyOwner
    {
        storageData.mapLockFee[origChainID][shadowChainID] = lockFee;
        storageData.mapRevokeFee[origChainID][shadowChainID] = revokeFee;
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param origChainID                  Original chain ID
    /// @param shadowChainID                Shadow Chain ID
    /// @return lockFee                     Coin the storeman group should get while storeman redeem user lock
    /// @return revokeFee                   Coin the storeman group should get while user revoke its lock
    function getFees(uint origChainID, uint shadowChainID)
        external
        view
        returns(uint lockFee, uint revokeFee)
    {
        lockFee = storageData.mapLockFee[origChainID][shadowChainID];
        revokeFee = storageData.mapRevokeFee[origChainID][shadowChainID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param time                         Coin the storeman group should get while storeman redeem user lock
    function setLockedTime(uint time)
        external
        onlyOwner
    {
        lockedTime = time;
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param  xHash                       hash of HTLC random number
    /// @return leftLockTime                left time of locked transaction
    function getLeftLockedTime(bytes32 xHash) external view returns (uint leftLockedTime) {
        leftLockedTime = storageData.htlcTxData.getLeftLockedTime(xHash);
    }

    /// @notice                             update the initialized state value of this contract
    /// @param tokenManager                 address of the token manager
    /// @param smgAdminProxy                address of the storeman group admin
    /// @param smgFeeProxy                  address of the proxy to store fee for storeman group
    /// @param quota                        address of the quota
    /// @param sigVerifier                  address of the signature verifier
    function setPartners(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
        external
        onlyOwner
    {
        // require(tokenManager != address(0) && smgAdminProxy != address(0) && quota != address(0) && sigVerifier != address(0),
        //     "Parameter is invalid");
        require(tokenManager != address(0) && smgAdminProxy != address(0) && sigVerifier != address(0),
            "Parameter is invalid");

        storageData.smgAdminProxy = IStoremanGroup(smgAdminProxy);
        storageData.tokenManager = ITokenManager(tokenManager);
        storageData.quota = IQuota(quota);
        storageData.smgFeeProxy = smgFeeProxy;
        storageData.sigVerifier = ISignatureVerifier(sigVerifier);
    }

    /// @notice                             get the initialized state value of this contract
    /// @return tokenManager                address of the token manager
    /// @return smgAdminProxy               address of the storeman group admin
    /// @return smgFeeProxy                 address of the proxy to store fee for storeman group
    /// @return quota                       address of the quota
    /// @return sigVerifier                 address of the signature verifier
    function getPartners()
        external
        view
        returns(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    {
        tokenManager = address(storageData.tokenManager);
        smgAdminProxy = address(storageData.smgAdminProxy);
        smgFeeProxy = storageData.smgFeeProxy;
        quota = address(storageData.quota);
        sigVerifier = address(storageData.sigVerifier);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param timeout                      Timeout for storeman group receiver withdraw fee, uint second
    function setWithdrawFeeTimeout(uint timeout)
        external
        onlyOwner
    {
        smgFeeReceiverTimeout = timeout;
    }

    /// @notice                             storeman group withdraw the fee to receiver account
    /// @param smgID                        ID of the storeman group
    /// @param receiver                     account of the receiver
    /// @param r                            signature
    /// @param s                            signature
    function smgWithdrawFee(bytes32 smgID, uint timeStamp, address receiver, bytes r, bytes32 s)
        external
        nonReentrant
    {
        require(now < timeStamp.add(smgFeeReceiverTimeout), "The receiver address expired");

        uint fee = storageData.mapStoremanFee[smgID];

        require(fee > 0, "Fee is null");

        delete storageData.mapStoremanFee[smgID];
        receiver.transfer(fee);

        uint curveID;
        bytes memory PK;
        (,,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);
        uint currentChainID = getUintValue(currentChainIDKey, currentChainIDInnerKey);
        verifySignature(curveID, sha256(abi.encode(currentChainID, timeStamp, receiver)), PK, r, s);

        emit SmgWithdrawFeeLogger(smgID, now, receiver, fee);
    }

    /// @notice       convert bytes to bytes32
    /// @param b      bytes array
    /// @param offset offset of array to begin convert
    function bytesToBytes32(bytes memory b, uint offset) private pure returns (bytes32 result) {
        assembly {
            result := mload(add(add(b, offset), 32))
        }
    }

    /// @notice             verify signature
    /// @param  curveID     ID of elliptic curve
    /// @param  message     message to be verified
    /// @param  r           Signature info r
    /// @param  s           Signature info s
    function verifySignature(uint curveID, bytes32 message, bytes PK, bytes r, bytes32 s)
        private
        // view
    {
        bytes32 PKx = bytesToBytes32(PK, 0);
        bytes32 PKy = bytesToBytes32(PK, 32);

        bytes32 Rx = bytesToBytes32(r, 0);
        bytes32 Ry = bytesToBytes32(r, 32);

        require(storageData.sigVerifier.verify(curveID, s, PKx, PKy, Rx, Ry, message), "Signature verification failed");
    }

    /* uintData */
    function setUintValue(bytes key, bytes innerKey, uint value)
        external
        onlyOwner
    {
        return uintData.setStorage(key, innerKey, value);
    }

    function getUintValue(bytes key, bytes innerKey)
        public
        view
        returns (uint)
    {
        return uintData.getStorage(key, innerKey);
    }

    function delUintValue(bytes key, bytes innerKey)
        external
        onlyOwner
    {
        return uintData.delStorage(key, innerKey);
    }

}
          

contracts/tokenManager/TokenManagerProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

/**
 * Math operations with safety checks
 */

import "../components/Admin.sol";
import "./TokenManagerStorage.sol";
import "../components/Proxy.sol";

contract TokenManagerProxy is TokenManagerStorage, Admin, Proxy {
    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for setting or upgrading TokenManagerDelegate address by owner
    /// @param impl                       TokenManagerDelegate contract address
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

openzeppelin-eth/contracts/token/ERC721/ERC721Enumerable.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./IERC721Enumerable.sol";
import "./ERC721.sol";
import "../../introspection/ERC165.sol";


contract ERC721Enumerable is Initializable, ERC165, ERC721, IERC721Enumerable {
  // Mapping from owner to list of owned token IDs
  mapping(address => uint256[]) private _ownedTokens;

  // Mapping from token ID to index of the owner tokens list
  mapping(uint256 => uint256) private _ownedTokensIndex;

  // Array with all token ids, used for enumeration
  uint256[] private _allTokens;

  // Mapping from token id to position in the allTokens array
  mapping(uint256 => uint256) private _allTokensIndex;

  bytes4 private constant _InterfaceId_ERC721Enumerable = 0x780e9d63;
  /**
   * 0x780e9d63 ===
   *   bytes4(keccak256('totalSupply()')) ^
   *   bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) ^
   *   bytes4(keccak256('tokenByIndex(uint256)'))
   */

  /**
   * @dev Constructor function
   */
  function initialize() public initializer {
    require(ERC721._hasBeenInitialized());

    // register the supported interface to conform to ERC721 via ERC165
    _registerInterface(_InterfaceId_ERC721Enumerable);
  }

  function _hasBeenInitialized() internal view returns (bool) {
    return supportsInterface(_InterfaceId_ERC721Enumerable);
  }

  /**
   * @dev Gets the token ID at a given index of the tokens list of the requested owner
   * @param owner address owning the tokens list to be accessed
   * @param index uint256 representing the index to be accessed of the requested tokens list
   * @return uint256 token ID at the given index of the tokens list owned by the requested address
   */
  function tokenOfOwnerByIndex(
    address owner,
    uint256 index
  )
    public
    view
    returns (uint256)
  {
    require(index < balanceOf(owner));
    return _ownedTokens[owner][index];
  }

  /**
   * @dev Gets the total amount of tokens stored by the contract
   * @return uint256 representing the total amount of tokens
   */
  function totalSupply() public view returns (uint256) {
    return _allTokens.length;
  }

  /**
   * @dev Gets the token ID at a given index of all the tokens in this contract
   * Reverts if the index is greater or equal to the total number of tokens
   * @param index uint256 representing the index to be accessed of the tokens list
   * @return uint256 token ID at the given index of the tokens list
   */
  function tokenByIndex(uint256 index) public view returns (uint256) {
    require(index < totalSupply());
    return _allTokens[index];
  }

  /**
   * @dev Internal function to add a token ID to the list of a given address
   * @param to address representing the new owner of the given token ID
   * @param tokenId uint256 ID of the token to be added to the tokens list of the given address
   */
  function _addTokenTo(address to, uint256 tokenId) internal {
    super._addTokenTo(to, tokenId);
    uint256 length = _ownedTokens[to].length;
    _ownedTokens[to].push(tokenId);
    _ownedTokensIndex[tokenId] = length;
  }

  /**
   * @dev Internal function to remove a token ID from the list of a given address
   * @param from address representing the previous owner of the given token ID
   * @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
   */
  function _removeTokenFrom(address from, uint256 tokenId) internal {
    super._removeTokenFrom(from, tokenId);

    // To prevent a gap in the array, we store the last token in the index of the token to delete, and
    // then delete the last slot.
    uint256 tokenIndex = _ownedTokensIndex[tokenId];
    uint256 lastTokenIndex = _ownedTokens[from].length.sub(1);
    uint256 lastToken = _ownedTokens[from][lastTokenIndex];

    _ownedTokens[from][tokenIndex] = lastToken;
    // This also deletes the contents at the last position of the array
    _ownedTokens[from].length--;

    // Note that this will handle single-element arrays. In that case, both tokenIndex and lastTokenIndex are going to
    // be zero. Then we can make sure that we will remove tokenId from the ownedTokens list since we are first swapping
    // the lastToken to the first position, and then dropping the element placed in the last position of the list

    _ownedTokensIndex[tokenId] = 0;
    _ownedTokensIndex[lastToken] = tokenIndex;
  }

  /**
   * @dev Internal function to mint a new token
   * Reverts if the given token ID already exists
   * @param to address the beneficiary that will own the minted token
   * @param tokenId uint256 ID of the token to be minted by the msg.sender
   */
  function _mint(address to, uint256 tokenId) internal {
    super._mint(to, tokenId);

    _allTokensIndex[tokenId] = _allTokens.length;
    _allTokens.push(tokenId);
  }

  /**
   * @dev Internal function to burn a specific token
   * Reverts if the token does not exist
   * @param owner owner of the token to burn
   * @param tokenId uint256 ID of the token being burned by the msg.sender
   */
  function _burn(address owner, uint256 tokenId) internal {
    super._burn(owner, tokenId);

    // Reorg all tokens array
    uint256 tokenIndex = _allTokensIndex[tokenId];
    uint256 lastTokenIndex = _allTokens.length.sub(1);
    uint256 lastToken = _allTokens[lastTokenIndex];

    _allTokens[tokenIndex] = lastToken;
    _allTokens[lastTokenIndex] = 0;

    _allTokens.length--;
    _allTokensIndex[tokenId] = 0;
    _allTokensIndex[lastToken] = tokenIndex;
  }

  uint256[50] private ______gap;
}
          

contracts/storemanGroupAdmin/StoremanGroupProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//  Code style according to: https://github.com/wanchain/wanchain-token/blob/master/style-guide.rst

pragma solidity ^0.4.24;

import "../components/Halt.sol";
import "../components/Admin.sol";
import "./StoremanGroupStorage.sol";
import "../components/Proxy.sol";
import "../components/ReentrancyGuard.sol";

contract StoremanGroupProxy is StoremanGroupStorage, Halt, Admin, ReentrancyGuard,Proxy {
    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                           function for setting or upgrading StoremanGroupDelegate address by owner
    /// @param impl                       StoremanGroupDelegate contract address
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

openzeppelin-eth/contracts/token/ERC721/IERC721Receiver.sol

pragma solidity ^0.4.24;


/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
contract IERC721Receiver {
  /**
   * @notice Handle the receipt of an NFT
   * @dev The ERC721 smart contract calls this function on the recipient
   * after a `safeTransfer`. This function MUST return the function selector,
   * otherwise the caller will revert the transaction. The selector to be
   * returned can be obtained as `this.onERC721Received.selector`. This
   * function MAY throw to revert and reject the transfer.
   * Note: the ERC721 contract address is always the message sender.
   * @param operator The address which called `safeTransferFrom` function
   * @param from The address which previously owned the token
   * @param tokenId The NFT identifier which is being transferred
   * @param data Additional data with no specified format
   * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
   */
  function onERC721Received(
    address operator,
    address from,
    uint256 tokenId,
    bytes data
  )
    public
    returns(bytes4);
}
          

contracts/interfaces/ISmgFeeProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

interface ISmgFeeProxy {
  function smgTransfer(bytes32 smgID) external payable;
}
          

contracts/interfaces/IConfig.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

interface IConfig {
    function getCurve(uint8 curveId) external returns(address);
}
          

contracts/config/ConfigStorage.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

import "../components/BasicStorage.sol";

contract ConfigStorage is BasicStorage {


    /************************************************************
     **
     ** VARIABLES
     **
     ************************************************************/

    /// curve -> contract address
    mapping(uint8 => address) curves;
}
          

contracts/test/TestNftTokenCreator.sol

pragma solidity ^0.4.24;

import "../interfaces/IMappingToken.sol";
import "../components/BasicStorage.sol";
import "./MappingNftToken.sol";
import "./TestIOwned.sol";

contract TestNftTokenCreator is BasicStorage {
    address _admin;

    modifier onlyAdmin {
        require(_admin != address(0), "admin is null");
        _;
    }

    function setAdmin(address admin) external {
        _admin = admin;
    }

    function getAdmin() external view returns (address) {
        return _admin;
    }

    function createToken(string tokenName, string tokenSymbol, uint8 tokenDecimal) external {
        address tokenInst = new MappingNftToken(tokenName, tokenSymbol);
        addressData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenInst);
        uintData.setStorage(bytes(tokenName), bytes(tokenSymbol), tokenDecimal);
        // TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function changeOwner(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).changeOwner(msg.sender);
    }

    function acceptOwnership(string tokenName, string tokenSymbol) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        TestIOwned(tokenInst).acceptOwnership();
    }

    function getTokenAddr(string tokenName, string tokenSymbol) external view returns (address) {
        return addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
    }

    function mintToken(string tokenName, string tokenSymbol, address to, uint value) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        IMappingToken(tokenInst).mint(to, value);
    }

    function burnToken(string tokenName, string tokenSymbol, address from, uint value) external {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        IMappingToken(tokenInst).burn(from, value);
    }

    function tokenBalance(string tokenName, string tokenSymbol, address owner) external view returns (uint balance) {
        address tokenInst = addressData.getStorage(bytes(tokenName), bytes(tokenSymbol));
        balance = MappingNftToken(tokenInst).balanceOf(owner);
    }

    function getTokenDecimal(string tokenName, string tokenSymbol) external view returns (uint8) {
        return uint8(uintData.getStorage(bytes(tokenName), bytes(tokenSymbol)));
    }

    function destroyToken(string tokenName, string tokenSymbol) external {
        addressData.delStorage(bytes(tokenName), bytes(tokenSymbol));
        uintData.delStorage(bytes(tokenName), bytes(tokenSymbol));
    }
}
          

contracts/test/FakePosLib.sol

pragma solidity ^0.4.26;
import 'openzeppelin-eth/contracts/math/SafeMath.sol';


library FakePosLib {
    using SafeMath for uint;
    uint public constant DIVISOR = 10000;
    address constant PRECOMPILE_CONTRACT_ADDR = 0x268;

    function getEpochId(uint256 blockTime) public pure returns (uint256) {
        return blockTime/1;
    }

    function getMinIncentive (uint256 smgDeposit,uint256 targetSecond, uint256 totalDeposit) public pure returns(uint256) {
        uint posCap = 60000000000;
        if(totalDeposit < posCap) return 30000000;
        uint cap = posCap.mul(smgDeposit).div(totalDeposit);
        return cap > 30000000 ? 30000000 : cap;
    }
}
          

openzeppelin-eth/contracts/token/ERC721/ERC721Full.sol

pragma solidity ^0.4.24;

import "../../zos-lib/Initializable.sol";
import "./ERC721.sol";
import "./ERC721Enumerable.sol";
import "./ERC721Metadata.sol";


/**
 * @title Full ERC721 Token
 * This implementation includes all the required and some optional functionality of the ERC721 standard
 * Moreover, it includes approve all functionality using operator terminology
 * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-721.md
 */
contract ERC721Full is Initializable, ERC721, ERC721Enumerable, ERC721Metadata {
  uint256[50] private ______gap;
}
          

contracts/crossApproach/CrossProxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

/**
 * Math operations with safety checks
 */

import "../components/Proxy.sol";
import "../components/Halt.sol";
import "../components/ReentrancyGuard.sol";
import "./CrossStorage.sol";


contract CrossProxy is CrossStorage, ReentrancyGuard, Halt, Proxy {

    ///@dev                   update the address of CrossDelegate contract
    ///@param impl            the address of the new CrossDelegate contract
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/crossApproach/CrossDelegateV3.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./CrossStorageV3.sol";
import "./lib/RapidityLibV3.sol";


contract CrossDelegateV3  is CrossStorageV3 {
    using SafeMath for uint;

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                         event of admin config
    /// @param adminAccount             account of admin
    event SetAdmin(address adminAccount);

    /// @notice                         event of setFee or setFees
    /// @param srcChainID               source of cross chain
    /// @param destChainID              destination of cross chain
    /// @param contractFee              contract fee
    /// @param agentFee                 agent fee
    event SetFee(uint indexed srcChainID, uint indexed destChainID, uint contractFee, uint agentFee);

    /// @notice                         event of setFee or setFees
    /// @param tokenPairID              ID of token pair
    /// @param contractFee              contract fee
    event SetTokenPairFee(uint indexed tokenPairID, uint contractFee);

    /// @notice                         event of storeman group ID withdraw the original coin to receiver
    /// @param smgID                    ID of storeman group
    /// @param timeStamp                timestamp of the withdraw
    /// @param receiver                 receiver address
    /// @param fee                      shadow coin of the fee which the storeman group pk got it
    event WithdrawHistoryFeeLogger(bytes32 indexed smgID, uint indexed timeStamp, address indexed receiver, uint fee);

    /**
     *
     * MODIFIERS
     *
     */
    /// @notice                                 check the admin or not
    modifier onlyAdmin() {
        require(msg.sender == admin, "not admin");
        _;
    }

    /// @notice                                 check the storeman group is ready
    /// @param smgID                            ID of storeman group
    modifier onlyReadySmg(bytes32 smgID) {
        uint8 status;
        uint startTime;
        uint endTime;
        (status,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupStatus(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");
        _;
    }


    /**
     *
     * MANIPULATIONS
     *
     */
    /// @notice                                 request exchange orignal coin or token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain coin/token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive shadow chain token
    function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes userAccount)
    external
    payable
    notHalted
    onlyReadySmg(smgID)
    {
        address smgFeeProxy = getSmgFeeProxy();

        RapidityLibV3.RapidityUserLockParams memory params = RapidityLibV3.RapidityUserLockParams({
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        currentChainID: currentChainID,
        tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
        destUserAccount: userAccount,
        smgFeeProxy: smgFeeProxy
        });
        RapidityLibV3.userLock(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive original chain token
    function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes userAccount)
    external
    payable
    notHalted
    onlyReadySmg(smgID)
    {
        address smgFeeProxy = getSmgFeeProxy();

        RapidityLibV3.RapidityUserBurnParams memory params = RapidityLibV3.RapidityUserBurnParams({
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        currentChainID: currentChainID,
        tokenPairContractFee: mapTokenPairContractFee[tokenPairID],
        srcTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: smgFeeProxy
        });
        RapidityLibV3.userBurn(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  fee                             exchange fee
    /// @param  userAccount                     address of user, used to receive WRC20 token
    /// @param  r                               signature
    /// @param  s                               signature
    function smgMint(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes r, bytes32 s)
    external
    notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV3.RapiditySmgMintParams memory params = RapidityLibV3.RapiditySmgMintParams({
        uniqueID: uniqueID,
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        destTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
        });
        RapidityLibV3.smgMint(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  fee                             exchange fee
    /// @param  userAccount                     address of user, used to receive original token/coin
    /// @param  r                               signature
    /// @param  s                               signature
    function smgRelease(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, address userAccount, bytes r, bytes32 s)
    external
    notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV3.RapiditySmgReleaseParams memory params = RapidityLibV3.RapiditySmgReleaseParams({
        uniqueID: uniqueID,
        smgID: smgID,
        tokenPairID: tokenPairID,
        value: value,
        fee: fee,
        destTokenAccount: tokenAccount,
        destUserAccount: userAccount,
        smgFeeProxy: (storageData.smgFeeProxy == address(0)) ? owner : storageData.smgFeeProxy // fix: Stack too deep
        });
        RapidityLibV3.smgRelease(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, fee, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }


    /// @notice                             set the fee of the storeman group should get
    /// @param param                        struct of setFee parameter
    function setFee(SetFeesParam param) public onlyAdmin {
        storageData.mapContractFee[param.srcChainID][param.destChainID] = param.contractFee;
        storageData.mapAgentFee[param.srcChainID][param.destChainID] = param.agentFee;
        emit SetFee(param.srcChainID, param.destChainID, param.contractFee, param.agentFee);
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param params                        struct of setFees parameter
    function setFees(SetFeesParam [] params) public onlyAdmin {
        for (uint i = 0; i < params.length; ++i) {
            storageData.mapContractFee[params[i].srcChainID][params[i].destChainID] = params[i].contractFee;
            storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID] = params[i].agentFee;
            emit SetFee(params[i].srcChainID, params[i].destChainID, params[i].contractFee, params[i].agentFee);
        }
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param tokenPairID                  ID of token pair
    /// @param contractFee                  contractFee of token pair
    function setTokenPairFee(uint256 tokenPairID, uint256 contractFee) external onlyAdmin {
        mapTokenPairContractFee[tokenPairID] = contractFee;
        emit SetTokenPairFee(tokenPairID, contractFee);
    }

    /// @notice                             set the fee of the storeman group should get
    /// @param params                       struct of setTokenPairFees parameter
    function setTokenPairFees(SetTokenPairFeesParam [] params) public onlyAdmin {
        for (uint i = 0; i < params.length; ++i) {
            mapTokenPairContractFee[params[i].tokenPairID] = params[i].contractFee;
            emit SetTokenPairFee(params[i].tokenPairID, params[i].contractFee);
        }
    }

    function setChainID(uint256 chainID) external onlyAdmin {
        if (currentChainID == 0) {
            currentChainID = chainID;
        }
    }

    function setAdmin(address adminAccount) external onlyOwner {
        admin = adminAccount;
        emit SetAdmin(adminAccount);
    }

    function setUintValue(bytes key, bytes innerKey, uint value) external onlyAdmin {
        return uintData.setStorage(key, innerKey, value);
    }

    function delUintValue(bytes key, bytes innerKey) external onlyAdmin {
        return uintData.delStorage(key, innerKey);
    }

    /// @notice                             update the initialized state value of this contract
    /// @param tokenManager                 address of the token manager
    /// @param smgAdminProxy                address of the storeman group admin
    /// @param smgFeeProxy                  address of the proxy to store fee for storeman group
    /// @param quota                        address of the quota
    /// @param sigVerifier                  address of the signature verifier
    function setPartners(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    external
    onlyOwner
    {
        // require(tokenManager != address(0) && smgAdminProxy != address(0) && quota != address(0) && sigVerifier != address(0),
        //     "Parameter is invalid");
        require(tokenManager != address(0) && smgAdminProxy != address(0) && sigVerifier != address(0),
            "Parameter is invalid");

        storageData.smgAdminProxy = IStoremanGroup(smgAdminProxy);
        storageData.tokenManager = ITokenManager(tokenManager);
        // storageData.quota = IQuota(quota);
        storageData.smgFeeProxy = smgFeeProxy;
        storageData.sigVerifier = ISignatureVerifier(sigVerifier);
    }


    /// @notice                             withdraw the history fee to foundation account
    /// @param smgIDs                       array of storemanGroup ID
    function smgWithdrawHistoryFee(bytes32 [] smgIDs) external {
        uint fee;
        uint currentFee;
        address smgFeeProxy = storageData.smgFeeProxy;
        if (smgFeeProxy == address(0)) {
            smgFeeProxy = owner;
        }
        require(smgFeeProxy != address(0), "invalid smgFeeProxy");

        for (uint i = 0; i < smgIDs.length; ++i) {
            currentFee = storageData.mapStoremanFee[smgIDs[i]];
            delete storageData.mapStoremanFee[smgIDs[i]];
            fee = fee.add(currentFee);
            emit WithdrawHistoryFeeLogger(smgIDs[i], block.timestamp, smgFeeProxy, currentFee);
        }
        if (fee > 0) {
            smgFeeProxy.transfer(fee);
        }
    }


    /** Get Functions */

    function getUintValue(bytes key, bytes innerKey) public view returns (uint) {
        return uintData.getStorage(key, innerKey);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param key                          key of storeman fee
    /// @return fee                         original coin the storeman group should get
    function getStoremanFee(bytes32 key) external view returns(uint fee) {
        fee = storageData.mapStoremanFee[key];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param param                        struct of getFee parameter
    /// @return fees                        struct of getFee return
    function getFee(GetFeesParam param) public view returns(GetFeesReturn fee) {
        fee.contractFee = storageData.mapContractFee[param.srcChainID][param.destChainID];
        fee.agentFee = storageData.mapAgentFee[param.srcChainID][param.destChainID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param params                       struct of getFees parameter
    /// @return fees                        struct of getFees return
    function getFees(GetFeesParam [] params) public view returns(GetFeesReturn [] fees) {
        fees = new GetFeesReturn[](params.length);
        for (uint i = 0; i < params.length; ++i) {
            fees[i].contractFee = storageData.mapContractFee[params[i].srcChainID][params[i].destChainID];
            fees[i].agentFee = storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID];
        }
    }

    /// @notice                             get the token pair fee of the storeman group should get
    /// @param tokenPairID                  ID of token pair
    /// @return contractFee                 contractFee of token pair
    function getTokenPairFee(uint256 tokenPairID) external view returns(uint256 contractFee) {
        contractFee = mapTokenPairContractFee[tokenPairID];
    }

    /// @notice                             get the token pair fees of the storeman group should get
    /// @param tokenPairIDs                 array of tokenPairID
    /// @return contractFees                array of tokenPair contractFee
    function getTokenPairFees(uint256[] tokenPairIDs) external view returns(uint256 [] contractFees) {
        contractFees = new uint256[](tokenPairIDs.length);
        for (uint i = 0; i < tokenPairIDs.length; ++i) {
            contractFees[i] = mapTokenPairContractFee[tokenPairIDs[i]];
        }
    }

    /// @notice                             get the initialized state value of this contract
    /// @return tokenManager                address of the token manager
    /// @return smgAdminProxy               address of the storeman group admin
    /// @return smgFeeProxy                 address of the proxy to store fee for storeman group
    /// @return quota                       address of the quota
    /// @return sigVerifier                 address of the signature verifier
    function getPartners()
    external
    view
    returns(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    {
        tokenManager = address(storageData.tokenManager);
        smgAdminProxy = address(storageData.smgAdminProxy);
        smgFeeProxy = storageData.smgFeeProxy;
        quota = address(storageData.quota);
        sigVerifier = address(storageData.sigVerifier);
    }


    /** Private and Internal Functions */

    /// @notice                                 check the storeman group is ready or not
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireReadySmgInfo(bytes32 smgID)
    internal
    view
    returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        uint startTime;
        uint endTime;
        (,status,,,,curveID,,PK,,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");

        return (curveID, PK);
    }

    /// @notice                                 get the unregistered storeman group info
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireUnregisteredSmgInfo(bytes32 smgID)
    internal
    view
    returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        (,status,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.unregistered), "PK is not unregistered");
    }

    /// @notice       convert bytes to bytes32
    /// @param b      bytes array
    /// @param offset offset of array to begin convert
    function bytesToBytes32(bytes memory b, uint offset) internal pure returns (bytes32 result) {
        assembly {
            result := mload(add(add(b, offset), 32))
        }
    }

    /// @notice             verify signature
    /// @param  curveID     ID of elliptic curve
    /// @param  message     message to be verified
    /// @param  r           Signature info r
    /// @param  s           Signature info s
    function verifySignature(uint curveID, bytes32 message, bytes PK, bytes r, bytes32 s) internal {
        bytes32 PKx = bytesToBytes32(PK, 0);
        bytes32 PKy = bytesToBytes32(PK, 32);

        bytes32 Rx = bytesToBytes32(r, 0);
        bytes32 Ry = bytesToBytes32(r, 32);

        require(storageData.sigVerifier.verify(curveID, s, PKx, PKy, Rx, Ry, message), "Signature verification failed");
    }

    function getSmgFeeProxy() internal view returns (address) {
        address smgFeeProxy = storageData.smgFeeProxy;
        return (smgFeeProxy == address(0)) ? owner : smgFeeProxy;
    }

    /**
     * @notice Handle the receipt of an NFT
     * @dev The ERC721 smart contract calls this function on the recipient
     * after a `safeTransfer`. This function MUST return the function selector,
     * otherwise the caller will revert the transaction. The selector to be
     * returned can be obtained as `this.onERC721Received.selector`. This
     * function MAY throw to revert and reject the transfer.

     * Note: the ERC721 contract address is always the message sender.

     * @param operator The address which called `safeTransferFrom` function
     * @param from The address which previously owned the token
     * @param tokenId The NFT identifier which is being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
     */
    function onERC721Received(address operator, address from, uint256 tokenId, bytes data)
    public
    pure
    returns(bytes4)
    {
        return this.onERC721Received.selector;
    }
}
          

contracts/components/Proxy.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

/**
 * Math operations with safety checks
 */


contract Proxy {

    event Upgraded(address indexed implementation);

    address internal _implementation;

    function implementation() public view returns (address) {
        return _implementation;
    }

    function () external payable {
        address _impl = _implementation;
        require(_impl != address(0), "implementation contract not set");

        assembly {
            let ptr := mload(0x40)
            calldatacopy(ptr, 0, calldatasize)
            let result := delegatecall(gas, _impl, ptr, calldatasize, 0, 0)
            let size := returndatasize
            returndatacopy(ptr, 0, size)

            switch result
            case 0 { revert(ptr, size) }
            default { return(ptr, size) }
        }
    }
}
          

contracts/crossApproach/CrossDelegateV2.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;

import "./CrossStorageV2.sol";
import "./lib/HTLCDebtLibV2.sol";
import "./lib/RapidityLibV2.sol";


contract CrossDelegateV2 is CrossStorageV2 {
    using SafeMath for uint;

    /**
     *
     * EVENTS
     *
     **/

    /// @notice                         event of admin config
    /// @param adminAccount             account of admin
    event SetAdmin(address adminAccount);

    /// @notice                         event of setFee or setFees
    /// @param srcChainID               source of cross chain 
    /// @param destChainID              destination of cross chain 
    /// @param contractFee              contract fee 
    /// @param agentFee                 agent fee
    event SetFee(uint srcChainID, uint destChainID, uint contractFee, uint agentFee);

    /// @notice                         event of storeman group ID withdraw the original coin to receiver
    /// @param smgID                    ID of storemanGroup
    /// @param timeStamp                timestamp of the withdraw
    /// @param receiver                 receiver address
    /// @param fee                      shadow coin of the fee which the storeman group pk got it
    event SmgWithdrawFeeLogger(bytes32 indexed smgID, uint indexed timeStamp, address indexed receiver, uint fee);
    event WithdrawContractFeeLogger(uint indexed block, uint indexed timeStamp, address indexed receiver, uint fee);

    /**
     *
     * MODIFIERS
     *
     */
    /// @notice                                 check the admin or not
    modifier onlyAdmin() {
        require(msg.sender == admin, "not admin");
        _;
    }

    /// @notice                                 check the storeman group is ready
    /// @param smgID                            ID of storeman group
    modifier onlyReadySmg(bytes32 smgID) {
        uint8 status;
        uint startTime;
        uint endTime;
        (status,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupStatus(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");
        _;
    }


    /**
     *
     * MANIPULATIONS
     *
     */
    /// @notice                                 request exchange orignal coin or token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain coin/token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive shadow chain token
    function userLock(bytes32 smgID, uint tokenPairID, uint value, bytes userAccount)
        external
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        RapidityLibV2.RapidityUserLockParams memory params = RapidityLibV2.RapidityUserLockParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            currentChainID: currentChainID,
            destUserAccount: userAccount
        });
        RapidityLibV2.userLock(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     account of user, used to receive original chain token
    function userBurn(bytes32 smgID, uint tokenPairID, uint value, uint fee, address tokenAccount, bytes userAccount)
        external
        payable
        notHalted
        onlyReadySmg(smgID)
    {
        RapidityLibV2.RapidityUserBurnParams memory params = RapidityLibV2.RapidityUserBurnParams({
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            fee: fee,
            currentChainID: currentChainID,
            srcTokenAccount: tokenAccount,
            destUserAccount: userAccount
        });
        RapidityLibV2.userBurn(storageData, params);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     address of user, used to receive WRC20 token
    /// @param  r                               signature
    /// @param  s                               signature
    function smgMint(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, address tokenAccount, address userAccount, bytes r, bytes32 s)
        external
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV2.RapiditySmgMintParams memory params = RapidityLibV2.RapiditySmgMintParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            destTokenAccount: tokenAccount,
            destUserAccount: userAccount
        });
        RapidityLibV2.smgMint(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 request exchange RC20 token with WRC20 on wanchain
    /// @param  uniqueID                        fast cross chain random number
    /// @param  smgID                           ID of storeman
    /// @param  tokenPairID                     token pair ID of cross chain token
    /// @param  value                           exchange value
    /// @param  userAccount                     address of user, used to receive original token/coin
    /// @param  r                               signature
    /// @param  s                               signature
    function smgRelease(bytes32 uniqueID, bytes32 smgID, uint tokenPairID, uint value, address tokenAccount, address userAccount, bytes r, bytes32 s)
        external
        notHalted
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(smgID);

        RapidityLibV2.RapiditySmgReleaseParams memory params = RapidityLibV2.RapiditySmgReleaseParams({
            uniqueID: uniqueID,
            smgID: smgID,
            tokenPairID: tokenPairID,
            value: value,
            destTokenAccount: tokenAccount,
            destUserAccount: userAccount
        });
        RapidityLibV2.smgRelease(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, tokenPairID, value, tokenAccount, userAccount));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 transfer storeman asset
    /// @param  uniqueID                        random number (likes old xHash)
    /// @param  srcSmgID                        ID of src storeman
    /// @param  destSmgID                       ID of dst storeman
    /// @param  r                               signature
    /// @param  s                               signature
    function transferAsset(bytes32 uniqueID, bytes32 srcSmgID, bytes32 destSmgID, bytes r, bytes32 s)
        external
        notHalted
        onlyReadySmg(destSmgID)
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireUnregisteredSmgInfo(srcSmgID);

        HTLCDebtLibV2.DebtAssetParams memory params = HTLCDebtLibV2.DebtAssetParams({
            uniqueID: uniqueID,
            srcSmgID: srcSmgID,
            destSmgID: destSmgID
        });
        HTLCDebtLibV2.transferAsset(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, destSmgID));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                                 receive storeman debt
    /// @param  uniqueID                        random number (likes old xHash)
    /// @param  srcSmgID                        ID of src storeman
    /// @param  destSmgID                       ID of dst storeman
    /// @param  r                               signature
    /// @param  s                               signature
    function receiveDebt(bytes32 uniqueID, bytes32 srcSmgID, bytes32 destSmgID, bytes r, bytes32 s)
        external
        notHalted 
    {
        uint curveID;
        bytes memory PK;
        (curveID, PK) = acquireReadySmgInfo(destSmgID);

        HTLCDebtLibV2.DebtAssetParams memory params = HTLCDebtLibV2.DebtAssetParams({
            uniqueID: uniqueID,
            srcSmgID: srcSmgID,
            destSmgID: destSmgID
        });
        HTLCDebtLibV2.receiveDebt(storageData, params);

        bytes32 mHash = sha256(abi.encode(currentChainID, uniqueID, srcSmgID));
        verifySignature(curveID, mHash, PK, r, s);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param param                        struct of setFee parameter
    function setFee(SetFeesParam param)
        public
        onlyAdmin
    {
        storageData.mapContractFee[param.srcChainID][param.destChainID] = param.contractFee;
        storageData.mapAgentFee[param.srcChainID][param.destChainID] = param.agentFee;
        emit SetFee(param.srcChainID, param.destChainID, param.contractFee, param.agentFee);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param params                        struct of setFees parameter
    function setFees(SetFeesParam [] params) public onlyAdmin {
        for (uint i = 0; i < params.length; ++i) {
            storageData.mapContractFee[params[i].srcChainID][params[i].destChainID] = params[i].contractFee;
            storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID] = params[i].agentFee;
            emit SetFee(params[i].srcChainID, params[i].destChainID, params[i].contractFee, params[i].agentFee);
        }
    }

    function setChainID(uint256 chainID) external onlyAdmin {
        if (currentChainID == 0) {
            currentChainID = chainID;
        }
    }

    function setAdmin(address adminAccount) external onlyOwner {
        admin = adminAccount;
        emit SetAdmin(adminAccount);
    }

    function setUintValue(bytes key, bytes innerKey, uint value) external onlyAdmin {
        return uintData.setStorage(key, innerKey, value);
    }

    function delUintValue(bytes key, bytes innerKey) external onlyAdmin {
        return uintData.delStorage(key, innerKey);
    }

    /// @notice                             update the initialized state value of this contract
    /// @param tokenManager                 address of the token manager
    /// @param smgAdminProxy                address of the storeman group admin
    /// @param smgFeeProxy                  address of the proxy to store fee for storeman group
    /// @param quota                        address of the quota
    /// @param sigVerifier                  address of the signature verifier
    function setPartners(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
        external
        onlyOwner
    {
        // require(tokenManager != address(0) && smgAdminProxy != address(0) && quota != address(0) && sigVerifier != address(0),
        //     "Parameter is invalid");
        require(tokenManager != address(0) && smgAdminProxy != address(0) && sigVerifier != address(0),
            "Parameter is invalid");

        storageData.smgAdminProxy = IStoremanGroup(smgAdminProxy);
        storageData.tokenManager = ITokenManager(tokenManager);
        storageData.quota = IQuota(quota);
        storageData.smgFeeProxy = smgFeeProxy;
        storageData.sigVerifier = ISignatureVerifier(sigVerifier);
    }

    /// @notice                             withdraw the history fee to foundation account
    /// @param smgIDs                       array of storemanGroup ID
    function smgWithdrawFee(bytes32 [] smgIDs) external {
        uint fee;
        uint currentFee;
        address smgFeeProxy = storageData.smgFeeProxy;
        if (smgFeeProxy == address(0)) {
            smgFeeProxy = owner;
        }
        require(smgFeeProxy != address(0), "invalid smgFeeProxy");

        for (uint i = 0; i < smgIDs.length; ++i) {
            currentFee = storageData.mapStoremanFee[smgIDs[i]];
            delete storageData.mapStoremanFee[smgIDs[i]];
            fee = fee.add(currentFee);
            emit SmgWithdrawFeeLogger(smgIDs[i], block.timestamp, smgFeeProxy, currentFee);
        }
        currentFee = storageData.mapStoremanFee[bytes32(0)];
        if (currentFee > 0) {
            delete storageData.mapStoremanFee[bytes32(0)];
            fee = fee.add(currentFee);
        }
        require(fee > 0, "Fee is null");

        smgFeeProxy.transfer(fee);
        emit WithdrawContractFeeLogger(block.number, block.timestamp, smgFeeProxy, fee);
    }


    /** Get Functions */

    function getUintValue(bytes key, bytes innerKey) public view returns (uint) {
        return uintData.getStorage(key, innerKey);
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param smgID                        ID of storemanGroup
    /// @return fee                         original coin the storeman group should get
    function getStoremanFee(bytes32 smgID) external view returns(uint fee) {
        fee = storageData.mapStoremanFee[smgID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param param                        struct of getFee parameter
    /// @return fees                        struct of getFee return
    function getFee(GetFeesParam param) public view returns(GetFeesReturn fee) {
        fee.contractFee = storageData.mapContractFee[param.srcChainID][param.destChainID];
        fee.agentFee = storageData.mapAgentFee[param.srcChainID][param.destChainID];
    }

    /// @notice                             get the fee of the storeman group should get
    /// @param params                       struct of getFees parameter
    /// @return fees                        struct of getFees return
    function getFees(GetFeesParam [] params) public view returns(GetFeesReturn [] fees) {
        fees = new GetFeesReturn[](params.length);
        for (uint i = 0; i < params.length; ++i) {
            fees[i].contractFee = storageData.mapContractFee[params[i].srcChainID][params[i].destChainID];
            fees[i].agentFee = storageData.mapAgentFee[params[i].srcChainID][params[i].destChainID];
        }
    }

    /// @notice                             get the initialized state value of this contract
    /// @return tokenManager                address of the token manager
    /// @return smgAdminProxy               address of the storeman group admin
    /// @return smgFeeProxy                 address of the proxy to store fee for storeman group
    /// @return quota                       address of the quota
    /// @return sigVerifier                 address of the signature verifier
    function getPartners()
        external
        view
        returns(address tokenManager, address smgAdminProxy, address smgFeeProxy, address quota, address sigVerifier)
    {
        tokenManager = address(storageData.tokenManager);
        smgAdminProxy = address(storageData.smgAdminProxy);
        smgFeeProxy = storageData.smgFeeProxy;
        quota = address(storageData.quota);
        sigVerifier = address(storageData.sigVerifier);
    }


    /** Private and Internal Functions */

    /// @notice                                 check the storeman group is ready or not
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireReadySmgInfo(bytes32 smgID)
        internal
        view
        returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        uint startTime;
        uint endTime;
        (,status,,,,curveID,,PK,,startTime,endTime) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.ready) && now >= startTime && now <= endTime, "PK is not ready");

        return (curveID, PK);
    }

    /// @notice                                 get the unregistered storeman group info
    /// @param smgID                            ID of storeman group
    /// @return curveID                         ID of elliptic curve
    /// @return PK                              PK of storeman group
    function acquireUnregisteredSmgInfo(bytes32 smgID)
        internal
        view
        returns (uint curveID, bytes memory PK)
    {
        uint8 status;
        (,status,,,,curveID,,PK,,,) = storageData.smgAdminProxy.getStoremanGroupConfig(smgID);

        require(status == uint8(GroupStatus.unregistered), "PK is not unregistered");
    }

    /// @notice       convert bytes to bytes32
    /// @param b      bytes array
    /// @param offset offset of array to begin convert
    function bytesToBytes32(bytes memory b, uint offset) internal pure returns (bytes32 result) {
        assembly {
            result := mload(add(add(b, offset), 32))
        }
    }

    /// @notice             verify signature
    /// @param  curveID     ID of elliptic curve
    /// @param  message     message to be verified
    /// @param  r           Signature info r
    /// @param  s           Signature info s
    function verifySignature(uint curveID, bytes32 message, bytes PK, bytes r, bytes32 s) internal {
        bytes32 PKx = bytesToBytes32(PK, 0);
        bytes32 PKy = bytesToBytes32(PK, 32);

        bytes32 Rx = bytesToBytes32(r, 0);
        bytes32 Ry = bytesToBytes32(r, 32);

        require(storageData.sigVerifier.verify(curveID, s, PKx, PKy, Rx, Ry, message), "Signature verification failed");
    }
}
          

contracts/test/TestBasicStorage.sol

pragma solidity ^0.4.24;

import "../components/BasicStorage.sol";

contract TestBasicStorage is BasicStorage {
    /* uintData */
    function setUintData(bytes key, bytes innerKey, uint value)
        external
    {
        return uintData.setStorage(key, innerKey, value);
    }

    function getUintData(bytes key, bytes innerKey)
        external
        view
        returns (uint)
    {
        return uintData.getStorage(key, innerKey);
    }

    function delUintData(bytes key, bytes innerKey)
        external
    {
        return uintData.delStorage(key, innerKey);
    }

    /* boolData */
    function setBoolData(bytes key, bytes innerKey, bool value)
        external
    {
        boolData.setStorage(key, innerKey, value);
    }

    function getBoolData(bytes key, bytes innerKey)
        external
        view
        returns (bool)
    {
        return boolData.getStorage(key, innerKey);
    }

    function delBoolData(bytes key, bytes innerKey)
        external
    {
        return boolData.delStorage(key, innerKey);
    }

    /* addressData */
    function setAddressData(bytes key, bytes innerKey, address value)
        external
    {
        addressData.setStorage(key, innerKey, value);
    }

    function getAddressData(bytes key, bytes innerKey)
        external
        view
        returns (address)
    {
        return addressData.getStorage(key, innerKey);
    }

    function delAddressData(bytes key, bytes innerKey)
        external
    {
        return addressData.delStorage(key, innerKey);
    }

    /* bytesData */
    function setBytesData(bytes key, bytes innerKey, bytes value)
        external
    {
        bytesData.setStorage(key, innerKey, value);
    }

    function getBytesData(bytes key, bytes innerKey)
        external
        view
        returns (bytes)
    {
        return bytesData.getStorage(key, innerKey);
    }

    function delBytesData(bytes key, bytes innerKey)
        external
    {
        return bytesData.delStorage(key, innerKey);
    }

  /* stringData */
    function setStringData(bytes key, bytes innerKey, string value)
        external
    {
        stringData.setStorage(key, innerKey, value);
    }

    function getStringData(bytes key, bytes innerKey)
        external
        view
        returns (string)
    {
        return stringData.getStorage(key, innerKey);
    }

   function delStringData(bytes key, bytes innerKey)
        external
    {
        return stringData.delStorage(key, innerKey);
    }

}
          

contracts/crossApproach/lib/CrossTypes.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

import "../../interfaces/IRC20Protocol.sol";
import "../../interfaces/IQuota.sol";
import "../../interfaces/IStoremanGroup.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/ISignatureVerifier.sol";
import "./HTLCTxLib.sol";
import "./RapidityTxLib.sol";

library CrossTypes {
    using SafeMath for uint;

    /**
     *
     * STRUCTURES
     *
     */

    struct Data {

        /// map of the htlc transaction info
        HTLCTxLib.Data htlcTxData;

        /// map of the rapidity transaction info
        RapidityTxLib.Data rapidityTxData;

        /// quota data of storeman group
        IQuota quota;

        /// token manager instance interface
        ITokenManager tokenManager;

        /// storemanGroup admin instance interface
        IStoremanGroup smgAdminProxy;

        /// storemanGroup fee admin instance address
        address smgFeeProxy;

        ISignatureVerifier sigVerifier;

        /// @notice transaction fee, smgID => fee
        mapping(bytes32 => uint) mapStoremanFee;

        /// @notice transaction fee, origChainID => shadowChainID => fee
        mapping(uint => mapping(uint =>uint)) mapLockFee;

        /// @notice transaction fee, origChainID => shadowChainID => fee
        mapping(uint => mapping(uint =>uint)) mapRevokeFee;

    }

    /**
     *
     * MANIPULATIONS
     *
     */

    // /// @notice       convert bytes32 to address
    // /// @param b      bytes32
    // function bytes32ToAddress(bytes32 b) internal pure returns (address) {
    //     return address(uint160(bytes20(b))); // high
    //     // return address(uint160(uint256(b))); // low
    // }

    /// @notice       convert bytes to address
    /// @param b      bytes
    function bytesToAddress(bytes b) internal pure returns (address addr) {
        assembly {
            addr := mload(add(b,20))
        }
    }

    function transfer(address tokenScAddr, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        // IRC20Protocol(tokenScAddr).transfer(to, value);
        tokenScAddr.call(bytes4(keccak256("transfer(address,uint256)")), to, value);
        afterBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }

    function transferFrom(address tokenScAddr, address from, address to, uint value)
        internal
        returns(bool)
    {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        // IRC20Protocol(tokenScAddr).transferFrom(from, to, value);
        tokenScAddr.call(bytes4(keccak256("transferFrom(address,address,uint256)")), from, to, value);
        afterBalance = IRC20Protocol(tokenScAddr).balanceOf(to);
        return afterBalance == beforeBalance.add(value);
    }
}
          

contracts/config/ConfigProxy.sol

/*

  Copyright 2020 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;
pragma experimental ABIEncoderV2;

/**
 * Math operations with safety checks
 */

import "../components/Halt.sol";
import "../components/Admin.sol";
import "./ConfigStorage.sol";
import "../components/Proxy.sol";

contract ConfigProxy is ConfigStorage, Halt, Admin, Proxy {

    ///@dev                   update the address of ConfigDelegate contract
    ///@param impl            the address of the new ConfigDelegate contract
    function upgradeTo(address impl) public onlyOwner {
        require(impl != address(0), "Cannot upgrade to invalid address");
        require(impl != _implementation, "Cannot upgrade to the same implementation");
        _implementation = impl;
        emit Upgraded(impl);
    }
}
          

contracts/storemanGroupAdmin/StoremanType.sol

pragma solidity ^0.4.26;

import "./Deposit.sol";

library StoremanType {
    using Deposit for Deposit.Records;
    enum GroupStatus {none, initial,curveSeted, failed,selected,ready,unregistered, dismissed}  //ready: gpk finished.


    struct Delegator {
        bool  quited;
        uint index; // for delete from candidate;
        Deposit.Records deposit;
        mapping(uint=>uint) incentive;
    }

    struct Candidate {
        address sender;
        bytes enodeID;
        bytes PK;
        address  wkAddr;
        bool isWhite;
        bool quited;
        uint delegatorCount;
        uint delegateDeposit; // only used when selecting. need not records.
        uint partnerCount;
        uint partnerDeposit;
        uint crossIncoming;
        uint slashedCount;

        uint incentivedDelegator; // how may delegator have beend incentived, == delegatorCount means incentive finished.
        uint incentivedDay;
        bytes32  groupId;
        bytes32  nextGroupId;
        Deposit.Records  deposit;         // the sk hiself's deposit.
        
        mapping(uint=>uint) incentive;       // without delegation.. set to 0 after claim.        

        // delegator index => delegator addr
        mapping(uint=>address) delegatorMap;
        mapping(address=>Delegator) delegators;

        // partner index => partner address
        mapping(uint=>address) partMap;
        mapping(address=>Delegator) partners;
        
    }

    struct StoremanGroup {
        GroupStatus    status;
        Deposit.Records    deposit;                  //group's deposit, used for calculate group incentive
        Deposit.Records     depositWeight;            // use for incentive distribution in a group
        uint selectedCount;
        uint memberCount;
        uint whiteCount;    // only used node, don't include backup.
        uint whiteCountAll; // all
        uint workTime;
        uint totalTime;
        uint registerTime;
        uint registerDuration; // how long allow to staking. check when stakeIn tx.
        uint memberCountDesign;
        uint threshold;
        uint chain1;
        uint chain2;
        uint curve1;
        uint curve2;
        uint tickedCount;
        uint minStakeIn;
        uint minDelegateIn;
        uint minPartIn;
        uint crossIncoming;
        bytes gpk1;
        bytes gpk2;
        uint delegateFee;   // div(10000)
        mapping(uint=>uint) tickedType;
        mapping(uint=>address) tickedNode;
        mapping(uint=>address) skMap;
        mapping(uint=>address) selectedNode;
        mapping(uint=>address) whiteMap;
        mapping(address=>address) whiteWk;   // the white list specified when start group. the from sender of whitelist.
        mapping(uint=>uint) groupIncentive; // by day.
    }
    struct StoremanGlobalConf {
        uint standaloneWeight; // defult 15000; need mul 10000
        uint DelegationMulti;  // 10
        uint backupCount;  // 3
        uint chainTypeCoDefault; //10000
        uint maxSlashedCount;
    }
    struct StoremanData {
        uint contribution;
        uint totalReward;
        address posLib;

        StoremanGlobalConf conf;
        
        mapping(bytes32 => StoremanType.StoremanGroup)  groups;
        mapping(uint=>mapping(address=>StoremanType.Candidate)) candidates;
        mapping(uint=> mapping(uint => uint)) chainTypeCo;
    }
    struct StoremanInfo {
        address sender;
        bytes enodeID;
        bytes PK;
        address  wkAddr;
        bool isWhite;
        bool quited;
        uint delegatorCount;
        uint delegateDeposit;
        uint partnerCount;
        uint partnerDeposit;
        uint crossIncoming;
        uint slashedCount;

        uint incentivedDelegator;
        uint incentivedDay;
        bytes32  groupId;
        bytes32  nextGroupId;
        uint  deposit;
        uint incentive;
    }
    struct StoremanGroupInfo {
        bytes32    groupId;
        GroupStatus    status;
        uint    deposit;
        uint    depositWeight;
        uint selectedCount;
        uint memberCount;
        uint whiteCount;    // only used node, don't include backup.
        uint whiteCountAll; // all
        uint startTime;
        uint endTime;
        uint registerTime;
        uint registerDuration; // how long allow to staking. check when stakeIn tx.
        uint memberCountDesign;
        uint threshold;
        uint chain1;
        uint chain2;
        uint curve1;
        uint curve2;
        uint tickedCount;
        uint minStakeIn;
        uint minDelegateIn;
        uint minPartIn;
        uint crossIncoming;
        bytes gpk1;
        bytes gpk2;
        uint delegateFee;
    }
    struct StoremanGroupInput {
        bytes32    groupId;
        bytes32    preGroupId;
        uint workTime;  // cross chain start time 
        uint totalTime; // cross chain duration. 
        uint registerDuration;
        uint memberCountDesign;
        uint threshold;
        uint chain1;
        uint chain2;
        uint curve1;
        uint curve2;
        uint minStakeIn;
        uint minDelegateIn;
        uint minPartIn;
        uint delegateFee;
    }
}
          

contracts/test/TestIOwned.sol

pragma solidity ^0.4.24;

interface TestIOwned {
    function changeOwner(address _newOwner) external;
    function acceptOwnership() external;
}
          

contracts/interfaces/IOracle.sol

pragma solidity 0.4.26;

interface IOracle {
  function getDeposit(bytes32 smgID) external view returns (uint);
  function getValue(bytes32 key) external view returns (uint);
  function getValues(bytes32[] keys) external view returns (uint[] values);
  function getStoremanGroupConfig(
    bytes32 id
  ) external view returns(bytes32 groupId, uint8 status, uint deposit, uint chain1, uint chain2, uint curve1, uint curve2, bytes gpk1, bytes gpk2, uint startTime, uint endTime);
}
          

contracts/interfaces/IERC1155.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

//interface IERC1155 is IERC165 {
interface IERC1155  {
    ///**
    // * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
    // */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    ///**
    // * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
    // * transfers.
    // */
    //event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);


    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    //function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) external;
}
          

contracts/schnorr/Bn128.sol

pragma solidity ^0.4.24;

import 'openzeppelin-eth/contracts/math/SafeMath.sol';

contract Bn128 {
    using SafeMath for uint;

    uint256 constant gx = 0x1;
    uint256 constant gy = 0x2;

    /// @dev Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1.
    uint256 constant order = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

    function getGx() public pure returns (uint256) {
        return gx;
    }

    function getGy() public pure returns (uint256) {
        return gy;
    }

    function getOrder() public pure returns (uint256) {
        return order;
    }

    function ecadd(
        uint256 x1,
        uint256 y1,
        uint256 x2,
        uint256 y2
    ) public view returns (uint256 x3, uint256 y3) {
        uint256[2] memory outValue;
        uint256[4] memory input;
        input[0] = x1;
        input[1] = y1;
        input[2] = x2;
        input[3] = y2;

        assembly {
            if iszero(staticcall(gas, 0x06, input, 0x80, outValue, 0x40)) {
                revert(0, 0)
            }
        }

        x3 = outValue[0];
        y3 = outValue[1];
    }

    function ecmul(
        uint256 x1,
        uint256 y1,
        uint256 scalar
    ) public view returns (uint256 x2, uint256 y2) {
        uint256[2] memory outValue;
        uint256[3] memory input;
        input[0] = x1;
        input[1] = y1;
        input[2] = scalar;

        assembly {
            if iszero(staticcall(gas, 0x07, input, 0x60, outValue, 0x40)) {
                revert(0, 0)
            }
        }

        x2 = outValue[0];
        y2 = outValue[1];
    }
}
          

contracts/tokenManager/MappingToken.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity 0.4.26;

import '../components/StandardToken.sol';
import '../components/Owned.sol';

contract MappingToken is StandardToken, Owned {
    using SafeMath for uint;
    /****************************************************************************
     **
     ** MODIFIERS
     **
     ****************************************************************************/
    modifier onlyMeaningfulValue(uint value) {
        require(value > 0, "Value is null");
        _;
    }

    /****************************************************************************
     **
     ** EVENTS
     **
     ****************************************************************************/

    ///@notice Initialize the TokenManager address
    ///@dev Initialize the TokenManager address
    ///@param tokenName The token name to be used
    ///@param tokenSymbol The token symbol to be used
    ///@param tokenDecimal The token decimals to be used
    constructor(string tokenName, string tokenSymbol, uint8 tokenDecimal)
        public
    {
        name = tokenName;
        symbol = tokenSymbol;
        decimals = tokenDecimal;
    }

    /****************************************************************************
     **
     ** MANIPULATIONS
     **
     ****************************************************************************/

    /// @notice Create token
    /// @dev Create token
    /// @param account Address will receive token
    /// @param value Amount of token to be minted
    function mint(address account, uint value)
        external
        onlyOwner
        onlyMeaningfulValue(value)
    {
        balances[account] = balances[account].add(value);
        totalSupply = totalSupply.add(value);

        emit Transfer(address(0), account, value);
    }

    /// @notice Burn token
    /// @dev Burn token
    /// @param account Address of whose token will be burnt
    /// @param value Amount of token to be burnt
    function burn(address account, uint value)
        external
        onlyOwner
        onlyMeaningfulValue(value)
    {
        balances[account] = balances[account].sub(value);
        totalSupply = totalSupply.sub(value);

        emit Transfer(account, address(0), value);
    }

    /// @notice update token name, symbol
    /// @dev update token name, symbol
    /// @param _name token new name
    /// @param _symbol token new symbol
    function update(string _name, string _symbol)
        external
        onlyOwner
    {
        name = _name;
        symbol = _symbol;
    }
}
          

openzeppelin-eth/contracts/math/SafeMath.sol

pragma solidity ^0.4.24;


/**
 * @title SafeMath
 * @dev Math operations with safety checks that revert on error
 */
library SafeMath {

  /**
  * @dev Multiplies two numbers, reverts on overflow.
  */
  function mul(uint256 a, uint256 b) internal pure returns (uint256) {
    // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
    // benefit is lost if 'b' is also tested.
    // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
    if (a == 0) {
      return 0;
    }

    uint256 c = a * b;
    require(c / a == b);

    return c;
  }

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

    return c;
  }

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

    return c;
  }

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

    return c;
  }

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

contracts/crossApproach/lib/RapidityLibV3.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;
pragma experimental ABIEncoderV2;


import 'openzeppelin-eth/contracts/token/ERC721/IERC721.sol';
import "./RapidityTxLib.sol";
import "./CrossTypesV1.sol";
import "../../interfaces/ITokenManager.sol";
import "../../interfaces/IRC20Protocol.sol";

library RapidityLibV3 {
    using SafeMath for uint;
    using RapidityTxLib for RapidityTxLib.Data;

    enum TokenCrossType {ERC20, ERC721}

    /**
    *
    * STRUCTURES
    *
    */

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapidityUserLockParams {
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        uint currentChainID;              /// current chain ID
        uint tokenPairContractFee;        /// fee of token pair
        bytes destUserAccount;            /// account of shadow chain, used to receive token
        address smgFeeProxy;              /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity storeman mint lock parameters
    struct RapiditySmgMintParams {
        bytes32 uniqueID;                 /// Rapidity random number
        bytes32 smgID;                    /// ID of storeman group which user has selected
        uint tokenPairID;                 /// token pair id on cross chain
        uint value;                       /// exchange token value
        uint fee;                         /// exchange token fee
        address destTokenAccount;         /// shadow token account
        address destUserAccount;          /// account of shadow chain, used to receive token
        address smgFeeProxy;              /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapidityUserBurnParams {
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint currentChainID;            /// current chain ID
        uint fee;                       /// exchange token fee
        uint tokenPairContractFee;      /// fee of token pair
        address srcTokenAccount;        /// shadow token account
        bytes destUserAccount;          /// account of token destination chain, used to receive token
        address smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /// @notice struct of Rapidity user burn lock parameters
    struct RapiditySmgReleaseParams {
        bytes32 uniqueID;               /// Rapidity random number
        bytes32 smgID;                  /// ID of storeman group which user has selected
        uint tokenPairID;               /// token pair id on cross chain
        uint value;                     /// exchange token value
        uint fee;                       /// exchange token fee
        address destTokenAccount;       /// original token/coin account
        address destUserAccount;        /// account of token original chain, used to receive token
        address smgFeeProxy;            /// address of the proxy to store fee for storeman group
    }

    /**
     *
     * EVENTS
     *
     **/


    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity original token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserLockLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param tokenAccount             Rapidity shadow token account
    /// @param value                    Rapidity value
    /// @param userAccount              account of shadow chain, used to receive token
    event UserBurnLogger(bytes32 indexed smgID, uint indexed tokenPairID, address indexed tokenAccount, uint value, uint contractFee, uint fee, bytes userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param fee                      Rapidity fee
    /// @param tokenAccount             Rapidity shadow token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgMintLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, uint fee, address tokenAccount, address userAccount);

    /// @notice                         event of exchange WRC-20 token with original chain token request
    /// @notice                         event invoked by storeman group
    /// @param uniqueID                 unique random number
    /// @param smgID                    ID of storemanGroup
    /// @param tokenPairID              token pair ID of cross chain token
    /// @param value                    Rapidity value
    /// @param fee                      Rapidity fee
    /// @param tokenAccount             Rapidity original token account
    /// @param userAccount              account of original chain, used to receive token
    event SmgReleaseLogger(bytes32 indexed uniqueID, bytes32 indexed smgID, uint indexed tokenPairID, uint value, uint fee, address tokenAccount, address userAccount);

    /**
    *
    * MANIPULATIONS
    *
    */

    /// @notice                         mintBridge, user lock token on token original chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user mint lock token on token original chain
    function userLock(CrossTypesV1.Data storage storageData, RapidityUserLockParams memory params)
    public
    {
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        (fromChainID,fromTokenAccount,toChainID) = storageData.tokenManager.getTokenPairInfoSlim(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint contractFee = params.tokenPairContractFee;
        if (contractFee == 0) {
            contractFee = storageData.mapContractFee[fromChainID][toChainID];
        }
        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        address tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);

        uint left;
        if (tokenScAddr == address(0)) {
            left = (msg.value).sub(params.value).sub(contractFee);
        } else {
            left = (msg.value).sub(contractFee);

            uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
            if (tokenCrossType == uint8(TokenCrossType.ERC20)) {
                require(CrossTypesV1.transferFrom(tokenScAddr, msg.sender, address(this), params.value), "Lock token failed");
            } else if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
                IERC721(tokenScAddr).safeTransferFrom(msg.sender, address(this), params.value);
            } else {
                require(false, "Not support");
            }
        }
        if (left != 0) {
            (msg.sender).transfer(left);
        }
        emit UserLockLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.destUserAccount);
    }

    /// @notice                         burnBridge, user lock token on token original chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for user burn lock token on token original chain
    function userBurn(CrossTypesV1.Data storage storageData, RapidityUserBurnParams memory params)
    public
    {
        ITokenManager tokenManager = storageData.tokenManager;
        uint fromChainID;
        uint toChainID;
        bytes memory fromTokenAccount;
        bytes memory toTokenAccount;
        (fromChainID,fromTokenAccount,toChainID,toTokenAccount) = tokenManager.getTokenPairInfo(params.tokenPairID);
        require(fromChainID != 0, "Token does not exist");

        uint256 contractFee = params.tokenPairContractFee;
        address tokenScAddr;
        if (params.currentChainID == toChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[toChainID][fromChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(toTokenAccount);
        } else if (params.currentChainID == fromChainID) {
            if (contractFee == 0) {
                contractFee = storageData.mapContractFee[fromChainID][toChainID];
            }
            tokenScAddr = CrossTypesV1.bytesToAddress(fromTokenAccount);
        } else {
            require(false, "Invalid token pair");
        }
        require(params.srcTokenAccount == tokenScAddr, "Invalid token account");

        // Reuse variable fromChainID as tokenCrossType; burn token by tokenCrossType
        fromChainID = tokenManager.mapTokenPairType(params.tokenPairID);
        if (fromChainID == uint8(TokenCrossType.ERC20)) {
            require(burnShadowToken(tokenManager, tokenScAddr, msg.sender, params.value), "Burn failed");
        } else if (fromChainID == uint8(TokenCrossType.ERC721)) {
            require(burnShadowNftToken(tokenManager, tokenScAddr, msg.sender, params.value), "Burn NFT failed");
        } else {
            require(false, "Not support");
        }

        if (contractFee > 0) {
            params.smgFeeProxy.transfer(contractFee);
        }

        uint left = (msg.value).sub(contractFee);
        if (left != 0) {
            (msg.sender).transfer(left);
        }

        emit UserBurnLogger(params.smgID, params.tokenPairID, tokenScAddr, params.value, contractFee, params.fee, params.destUserAccount);
    }

    /// @notice                         mintBridge, storeman mint lock token on token shadow chain
    /// @notice                         event invoked by user mint lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman mint lock token on token shadow chain
    function smgMint(CrossTypesV1.Data storage storageData, RapiditySmgMintParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        ITokenManager tokenManager = storageData.tokenManager;
        uint8 tokenCrossType = tokenManager.mapTokenPairType(params.tokenPairID);
        if (tokenCrossType == uint8(TokenCrossType.ERC20)) {
            if (params.fee > 0) {
                require(mintShadowToken(tokenManager, params.destTokenAccount, params.smgFeeProxy, params.fee), "Mint fee failed");
            }
            require(mintShadowToken(tokenManager, params.destTokenAccount, params.destUserAccount, params.value), "Mint failed");
        } else if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
            require(mintShadowNftToken(tokenManager, params.destTokenAccount, params.destUserAccount, params.value), "Mint NFT failed");
        } else {
            require(false, "Not support");
        }

        emit SmgMintLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.fee, params.destTokenAccount, params.destUserAccount);
    }

    /// @notice                         burnBridge, storeman burn lock token on token shadow chain
    /// @notice                         event invoked by user burn lock
    /// @param storageData              Cross storage data
    /// @param params                   parameters for storeman burn lock token on token shadow chain
    function smgRelease(CrossTypesV1.Data storage storageData, RapiditySmgReleaseParams memory params)
    public
    {
        storageData.rapidityTxData.addRapidityTx(params.uniqueID);

        if (params.destTokenAccount == address(0)) {
            (params.destUserAccount).transfer(params.value);
            if (params.fee > 0) {
                params.smgFeeProxy.transfer(params.fee);
            }
        } else {
            uint8 tokenCrossType = storageData.tokenManager.mapTokenPairType(params.tokenPairID);
            if (tokenCrossType == uint8(TokenCrossType.ERC20)) {
                if (params.fee > 0) {
                    require(CrossTypesV1.transfer(params.destTokenAccount, params.smgFeeProxy, params.fee), "Transfer token fee failed");
                }
                require(CrossTypesV1.transfer(params.destTokenAccount, params.destUserAccount, params.value), "Transfer token failed");
            } else if (tokenCrossType == uint8(TokenCrossType.ERC721)) {
                IERC721(params.destTokenAccount).safeTransferFrom(address(this), params.destUserAccount, params.value);
            } else {
                require(false, "Not support");
            }
        }

        emit SmgReleaseLogger(params.uniqueID, params.smgID, params.tokenPairID, params.value, params.fee, params.destTokenAccount, params.destUserAccount);
    }

    function burnShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(value);
    }

    function mintShadowToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(value);
    }

    function burnShadowNftToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).burnToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.sub(1);
    }

    function mintShadowNftToken(address tokenManager, address tokenAddress, address userAccount, uint value) private returns (bool) {
        uint beforeBalance;
        uint afterBalance;
        beforeBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);

        ITokenManager(tokenManager).mintToken(tokenAddress, userAccount, value);

        afterBalance = IRC20Protocol(tokenAddress).balanceOf(userAccount);
        return afterBalance == beforeBalance.add(1);
    }

    function addressToBytes32(address a) private pure returns (bytes32) {
        return bytes32(uint256(uint160(a)));
    }

}
          

contracts/interfaces/IMetric.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.24;

interface IMetric {
    // index of array: smIndex
    function getPrdInctMetric(bytes32 grpId, uint startEpId, uint endEpId) external returns(uint[]);
    function getPrdSlshMetric(bytes32 grpId, uint startEpId, uint endEpId) external returns(uint[]);

    function getSmSuccCntByEpId(bytes32 grpId, uint epId, uint8 smIndex) external returns(uint);
    function getSlshCntByEpId(bytes32 grpId, uint epId, uint8 smIndex) external returns(uint);
}
          

contracts/interfaces/IRC20Protocol.sol

/*

  Copyright 2019 Wanchain Foundation.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

*/

//                            _           _           _
//  __      ____ _ _ __   ___| |__   __ _(_)_ __   __| | _____   __
//  \ \ /\ / / _` | '_ \ / __| '_ \ / _` | | '_ \@/ _` |/ _ \ \ / /
//   \ V  V / (_| | | | | (__| | | | (_| | | | | | (_| |  __/\ V /
//    \_/\_/ \__,_|_| |_|\___|_| |_|\__,_|_|_| |_|\__,_|\___| \_/
//
//

pragma solidity ^0.4.26;

interface IRC20Protocol {
    function transfer(address, uint) external returns (bool);
    function transferFrom(address, address, uint) external returns (bool);
    function balanceOf(address _owner) external view returns (uint);
}
          

Contract ABI

[{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeAdmin","inputs":[{"type":"address","name":"admin"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"burnNFT","inputs":[{"type":"uint256","name":"tokenCrossType"},{"type":"address","name":"tokenAddress"},{"type":"address","name":"from"},{"type":"uint256[]","name":"tokenIDs"},{"type":"uint256[]","name":"values"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"removeTokenPair","inputs":[{"type":"uint256","name":"id"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"burnToken","inputs":[{"type":"address","name":"tokenAddress"},{"type":"address","name":"from"},{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"fromChainID"},{"type":"bytes","name":"fromAccount"},{"type":"uint256","name":"toChainID"}],"name":"getTokenPairInfoSlim","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"acceptTokenOwnership","inputs":[{"type":"address","name":"tokenAddress"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferTokenOwner","inputs":[{"type":"address","name":"tokenAddress"},{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeTokenOwner","inputs":[{"type":"address","name":"tokenAddress"},{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addTokenPair","inputs":[{"type":"uint256","name":"id"},{"type":"tuple","name":"aInfo","components":[{"type":"bytes","name":"account"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"},{"type":"uint256","name":"chainID"}]},{"type":"uint256","name":"fromChainID"},{"type":"bytes","name":"fromAccount"},{"type":"uint256","name":"toChainID"},{"type":"bytes","name":"toAccount"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"transferOwner","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"id"},{"type":"uint256[]","name":"fromChainID"},{"type":"bytes[]","name":"fromAccount"},{"type":"uint256[]","name":"toChainID"},{"type":"bytes[]","name":"toAccount"},{"type":"string[]","name":"ancestorSymbol"},{"type":"uint8[]","name":"ancestorDecimals"},{"type":"bytes[]","name":"ancestorAccount"},{"type":"string[]","name":"ancestorName"},{"type":"uint256[]","name":"ancestorChainID"}],"name":"getTokenPairsByChainID","inputs":[{"type":"uint256","name":"chainID1"},{"type":"uint256","name":"chainID2"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"operator","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"mapTokenPairIndex","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"implementation","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"tuple","name":"aInfo","components":[{"type":"bytes","name":"account"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"},{"type":"uint256","name":"chainID"}]},{"type":"uint256","name":"fromChainID"},{"type":"bytes","name":"fromAccount"},{"type":"uint256","name":"toChainID"},{"type":"bytes","name":"toAccount"}],"name":"mapTokenPairInfo","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"mintToken","inputs":[{"type":"address","name":"tokenAddress"},{"type":"address","name":"to"},{"type":"uint256","name":"value"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateTokenPair","inputs":[{"type":"uint256","name":"id"},{"type":"tuple","name":"aInfo","components":[{"type":"bytes","name":"account"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"},{"type":"uint256","name":"chainID"}]},{"type":"uint256","name":"fromChainID"},{"type":"bytes","name":"fromAccount"},{"type":"uint256","name":"toChainID"},{"type":"bytes","name":"toAccount"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addAdmin","inputs":[{"type":"address","name":"admin"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"renounceOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint8","name":""}],"name":"mapTokenPairType","inputs":[{"type":"uint256","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"acceptOwnership","inputs":[],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"addr"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"}],"name":"getTokenInfo","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"owner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bytes","name":"account"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"},{"type":"uint256","name":"chainId"}],"name":"getAncestorInfo","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"mintNFT","inputs":[{"type":"uint256","name":"tokenCrossType"},{"type":"address","name":"tokenAddress"},{"type":"address","name":"to"},{"type":"uint256[]","name":"tokenIDs"},{"type":"uint256[]","name":"values"},{"type":"bytes","name":"data"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"changeOwner","inputs":[{"type":"address","name":"_newOwner"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"updateToken","inputs":[{"type":"address","name":"tokenAddress"},{"type":"string","name":"name"},{"type":"string","name":"symbol"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setOperator","inputs":[{"type":"address","name":"account"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"fromChainID"},{"type":"bytes","name":"fromAccount"},{"type":"uint256","name":"toChainID"},{"type":"bytes","name":"toAccount"}],"name":"getTokenPairInfo","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setTokenPairTypes","inputs":[{"type":"uint256[]","name":"tokenPairIds"},{"type":"uint8[]","name":"tokenPairTypes"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"totalTokenPairs","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"newOwner","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"mapAdmin","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"}],"name":"getAncestorSymbol","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256[]","name":"id"},{"type":"uint256[]","name":"fromChainID"},{"type":"bytes[]","name":"fromAccount"},{"type":"uint256[]","name":"toChainID"},{"type":"bytes[]","name":"toAccount"},{"type":"string[]","name":"ancestorSymbol"},{"type":"uint8[]","name":"ancestorDecimals"},{"type":"bytes[]","name":"ancestorAccount"},{"type":"string[]","name":"ancestorName"},{"type":"uint256[]","name":"ancestorChainID"}],"name":"getTokenPairs","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"addToken","inputs":[{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"chainID"}],"name":"getAncestorChainID","inputs":[{"type":"uint256","name":"id"}],"constant":true},{"type":"fallback","stateMutability":"payable","payable":true},{"type":"event","name":"SetOperator","inputs":[{"type":"address","name":"oldOperator","indexed":true},{"type":"address","name":"newOperator","indexed":true}],"anonymous":false},{"type":"event","name":"SetTokenPairType","inputs":[{"type":"uint256","name":"tokenPairId","indexed":true},{"type":"uint256","name":"tokenPairType","indexed":true}],"anonymous":false},{"type":"event","name":"Upgraded","inputs":[{"type":"address","name":"implementation","indexed":true}],"anonymous":false},{"type":"event","name":"AddToken","inputs":[{"type":"address","name":"tokenAddress","indexed":false},{"type":"string","name":"name","indexed":false},{"type":"string","name":"symbol","indexed":false},{"type":"uint8","name":"decimals","indexed":false}],"anonymous":false},{"type":"event","name":"AddTokenPair","inputs":[{"type":"uint256","name":"id","indexed":true},{"type":"uint256","name":"fromChainID","indexed":false},{"type":"bytes","name":"fromAccount","indexed":false},{"type":"uint256","name":"toChainID","indexed":false},{"type":"bytes","name":"toAccount","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateTokenPair","inputs":[{"type":"uint256","name":"id","indexed":true},{"type":"tuple","name":"aInfo","indexed":false,"components":[{"type":"bytes","name":"account"},{"type":"string","name":"name"},{"type":"string","name":"symbol"},{"type":"uint8","name":"decimals"},{"type":"uint256","name":"chainID"}]},{"type":"uint256","name":"fromChainID","indexed":false},{"type":"bytes","name":"fromAccount","indexed":false},{"type":"uint256","name":"toChainID","indexed":false},{"type":"bytes","name":"toAccount","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveTokenPair","inputs":[{"type":"uint256","name":"id","indexed":true}],"anonymous":false},{"type":"event","name":"UpdateToken","inputs":[{"type":"address","name":"tokenAddress","indexed":false},{"type":"string","name":"name","indexed":false},{"type":"string","name":"symbol","indexed":false}],"anonymous":false},{"type":"event","name":"AddAdmin","inputs":[{"type":"address","name":"admin","indexed":false}],"anonymous":false},{"type":"event","name":"RemoveAdmin","inputs":[{"type":"address","name":"admin","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","indexed":true},{"type":"address","name":"newOwner","indexed":true}],"anonymous":false}]
              

Contract Creation Code

0x6080604052600060055560088054600160a060020a0319163317905561573a8061002a6000396000f300608060405260043610620001d95763ffffffff60e060020a6000350416631785f53c8114620002395780632859c58014620002605780632b56590514620002855780633416794d14620002aa5780633ad8873a14620002cf5780633cc281df146200030e578063408e743d146200033357806341246e5314620003585780634f600ae8146200037d5780634fb2e45d14620003a2578063563cb1ab14620003c7578063570ca735146200040457806358a007fb146200042b5780635c60da1b146200045f5780635d2e9ead14620004775780636bec32da14620004af5780636c45e2dc14620004d45780637048027514620004f9578063715018a6146200051e57806375d2e27d146200053657806379ba5097146200056a5780638c7a63ae14620005825780638da5cb5b14620005b95780639027e6f714620005d15780639947f9321462000609578063a6f9dae1146200062e578063af33f17e1462000653578063b3ab15fb1462000678578063b9073276146200069d578063cbfbd61a14620006d4578063d0ad718d14620006f9578063d4ee1d901462000711578063d51dddd71462000729578063e101d3c1146200075d578063e24e4fdb1462000792578063f3bdd86314620007aa578063f4debe1e14620007cf575b600b54600160a060020a0316801515620002135760405160e560020a62461bcd0281526004016200020a9062004436565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801562000235578184f35b8184fd5b3480156200024657600080fd5b506200025e6200025836600462003693565b620007f4565b005b3480156200026d57600080fd5b506200025e6200027f3660046200393f565b62000881565b3480156200029257600080fd5b506200025e620002a43660046200391e565b620009be565b348015620002b757600080fd5b506200025e620002c9366004620036fb565b62000b66565b348015620002dc57600080fd5b50620002f4620002ee3660046200391e565b62000c1f565b604051620003059392919062004521565b60405180910390f35b3480156200031b57600080fd5b506200025e6200032d36600462003693565b62000ce0565b3480156200034057600080fd5b506200025e62000352366004620036bc565b62000d34565b3480156200036557600080fd5b506200025e62000377366004620036bc565b62000de3565b3480156200038a57600080fd5b506200025e6200039c36600462003ac3565b62000e5a565b348015620003af57600080fd5b506200025e620003c136600462003693565b62001046565b348015620003d457600080fd5b50620003ec620003e636600462003b69565b6200110d565b604051620003059a999897969594939291906200422c565b3480156200041157600080fd5b506200041c620018f7565b6040516200030591906200401d565b3480156200043857600080fd5b50620004506200044a3660046200391e565b62001906565b60405162000305919062004511565b3480156200046c57600080fd5b506200041c62001918565b3480156200048457600080fd5b506200049c620004963660046200391e565b62001928565b60405162000305959493929190620044b4565b348015620004bc57600080fd5b506200025e620004ce366004620036fb565b62001c68565b348015620004e157600080fd5b506200025e620004f336600462003ac3565b62001ce8565b3480156200050657600080fd5b506200025e6200051836600462003693565b62001e8a565b3480156200052b57600080fd5b506200025e62001f0f565b3480156200054357600080fd5b506200055b620005553660046200391e565b62001f5e565b6040516200030591906200459f565b3480156200057757600080fd5b506200025e62001f73565b3480156200058f57600080fd5b50620005a7620005a13660046200391e565b62001fb9565b604051620003059493929190620041c2565b348015620005c657600080fd5b506200041c62002239565b348015620005de57600080fd5b50620005f6620005f03660046200391e565b62002248565b6040516200030595949392919062004328565b3480156200061657600080fd5b506200025e62000628366004620039e4565b62002462565b3480156200063b57600080fd5b506200025e6200064d36600462003693565b6200257f565b3480156200066057600080fd5b506200025e620006723660046200374f565b620025de565b3480156200068557600080fd5b506200025e6200069736600462003693565b620026d7565b348015620006aa57600080fd5b50620006c2620006bc3660046200391e565b62002770565b60405162000305949392919062004556565b348015620006e157600080fd5b506200025e620006f3366004620037df565b620028d1565b3480156200070657600080fd5b5062000450620029f4565b3480156200071e57600080fd5b506200041c620029fa565b3480156200073657600080fd5b506200074e6200074836600462003693565b62002a09565b60405162000305919062004318565b3480156200076a57600080fd5b50620007826200077c3660046200391e565b62002a1e565b60405162000305929190620043ee565b3480156200079f57600080fd5b50620003ec62002ae1565b348015620007b757600080fd5b506200025e620007c936600462003856565b620031d3565b348015620007dc57600080fd5b5062000450620007ee3660046200391e565b62003290565b600854600160a060020a03163314620008245760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381166000908152600a602052604090819020805460ff19169055517f753f40ca3312b2408759a67875b367955e7baa221daf08aa3d643d96202ac12b90620008769083906200401d565b60405180910390a150565b336000908152600a602052604090205460ff161515620008b85760405160e560020a62461bcd0281526004016200020a9062004490565b600185141562000945576040517fb2dc5dc3000000000000000000000000000000000000000000000000000000008152600160a060020a0385169063b2dc5dc3906200090b908690869060040162004033565b600060405180830381600087803b1580156200092657600080fd5b505af11580156200093b573d6000803e3d6000fd5b50505050620009b7565b60028514156200099a576040517f6b20c454000000000000000000000000000000000000000000000000000000008152600160a060020a03851690636b20c454906200090b9086908690869060040162004057565b60405160e560020a62461bcd0281526004016200020a906200447e565b5050505050565b600854600090600160a060020a03163314620009f15760405160e560020a62461bcd0281526004016200020a906200446c565b60008281526006602052604081206005015483911062000a285760405160e560020a62461bcd0281526004016200020a906200445a565b600091505b60055482101562000b615760008281526007602052604090205483141562000b555760055460001901821462000a7b5760055460001901600090815260076020526040808220548483529120555b60058054600019908101600090815260076020908152604080832083905584549093019093558581526006909252812090818162000aba8282620032c6565b62000aca600183016000620032c6565b62000ada600283016000620032c6565b5060038101805460ff19169055600060049091018190556005830181905562000b08906006840190620032c6565b600782016000905560088201600062000b229190620032c6565b505060405183907fa219112a711e6173c2e8978836823d4e86832d96c0ea2fd05ec77687b7a073ab90600090a262000b61565b60019091019062000a2d565b505050565b336000908152600a602052604090205460ff16151562000b9d5760405160e560020a62461bcd0281526004016200020a9062004490565b6040517f9dc29fac000000000000000000000000000000000000000000000000000000008152600160a060020a03841690639dc29fac9062000be690859085906004016200420d565b600060405180830381600087803b15801562000c0157600080fd5b505af115801562000c16573d6000803e3d6000fd5b50505050505050565b60008181526006602081815260408084206005810154930180548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529394606094909383018282801562000cc15780601f1062000c955761010080835404028352916020019162000cc1565b820191906000526020600020905b81548152906001019060200180831162000ca357829003601f168201915b5050506000968752505060066020526040909420600701549294915050565b80600160a060020a03166379ba50976040518163ffffffff1660e060020a028152600401600060405180830381600087803b15801562000d1f57600080fd5b505af1158015620009b7573d6000803e3d6000fd5b600854600160a060020a0316331462000d645760405160e560020a62461bcd0281526004016200020a906200446c565b6040517f4fb2e45d000000000000000000000000000000000000000000000000000000008152600160a060020a03831690634fb2e45d9062000dab9084906004016200401d565b600060405180830381600087803b15801562000dc657600080fd5b505af115801562000ddb573d6000803e3d6000fd5b505050505050565b600854600160a060020a0316331462000e135760405160e560020a62461bcd0281526004016200020a906200446c565b6040517fa6f9dae1000000000000000000000000000000000000000000000000000000008152600160a060020a0383169063a6f9dae19062000dab9084906004016200401d565b600854600160a060020a0316331462000e8a5760405160e560020a62461bcd0281526004016200020a906200446c565b60008681526006602052604090206005015486901562000ec15760405160e560020a62461bcd0281526004016200020a9062004424565b600087815260066020818152604090922060058101889055865162000eef9391909201919087019062003311565b50600087815260066020908152604090912060078101859055835162000f1e9260089092019185019062003311565b5085516000888152600660209081526040909120825162000f459391929091019062003311565b5060208087015160008981526006835260409020815162000f70936001909201929091019062003311565b50604080870151600089815260066020908152929020815162000f9e93600290920192919091019062003311565b506060860151600088815260066020908152604080832060038101805460ff191660ff9096169590951790945560808a015160049094019390935560058054835260079091529190208890555462000ff8906001620032a5565b60055560405187907f226f08da880957e11c8affd4d622bb21b058cf67830d2ee56bb82d9b7197e9a7906200103590889088908890889062004556565b60405180910390a250505050505050565b600854600160a060020a03163314620010765760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381161515620010a45760405160e560020a62461bcd0281526004016200020a9062004448565b600854604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b606080606080606080606080606080600080600060606000935060009250600091506005546040519080825280602002602001820160405280156200115c578160200160208202803883390190505b5090505b6005548310156200122757600760008481526020019081526020016000205491508f6006600084815260200190815260200160002060050154148015620011b757506000828152600660205260409020600701548f145b80620011f457508f6006600084815260200190815260200160002060070154148015620011f457506000828152600660205260409020600501548f145b156200121b578181858151811015156200120a57fe5b602090810290910101526001909301925b60019092019162001160565b8360405190808252806020026020018201604052801562001252578160200160208202803883390190505b509d508360405190808252806020026020018201604052801562001280578160200160208202803883390190505b509c5083604051908082528060200260200182016040528015620012b957816020015b6060815260200190600190039081620012a35790505b509b5083604051908082528060200260200182016040528015620012e7578160200160208202803883390190505b509a50836040519080825280602002602001820160405280156200132057816020015b60608152602001906001900390816200130a5790505b509950836040519080825280602002602001820160405280156200135957816020015b6060815260200190600190039081620013435790505b5098508360405190808252806020026020018201604052801562001387578160200160208202803883390190505b50975083604051908082528060200260200182016040528015620013c057816020015b6060815260200190600190039081620013aa5790505b50965083604051908082528060200260200182016040528015620013f957816020015b6060815260200190600190039081620013e35790505b5095508360405190808252806020026020018201604052801562001427578160200160208202803883390190505b509450600092505b83831015620018e45780838151811015156200144757fe5b906020019060200201519150818e848151811015156200146357fe5b60209081029091018101919091526000838152600690915260409020600501548d518e90859081106200149257fe5b60209081029190910181019190915260008381526006808352604091829020018054825160026001831615610100026000190190921691909104601f810185900485028201850190935282815292909190830182828015620015385780601f106200150c5761010080835404028352916020019162001538565b820191906000526020600020905b8154815290600101906020018083116200151a57829003601f168201915b50505050508c848151811015156200154c57fe5b60209081029091018101919091526000838152600690915260409020600701548b518c90859081106200157b57fe5b6020908102919091018101919091526000838152600682526040908190206008018054825160026001831615610100026000190190921691909104601f810185900485028201850190935282815292909190830182828015620016225780601f10620015f65761010080835404028352916020019162001622565b820191906000526020600020905b8154815290600101906020018083116200160457829003601f168201915b50505050508a848151811015156200163657fe5b6020908102909101810191909152600083815260068252604090819020600290810180548351601f60001961010060018516150201909216939093049081018590048502830185019093528282529092909190830182828015620016de5780601f10620016b257610100808354040283529160200191620016de565b820191906000526020600020905b815481529060010190602001808311620016c057829003601f168201915b50505050508984815181101515620016f257fe5b6020908102909101810191909152600083815260069091526040902060030154885160ff909116908990859081106200172757fe5b60ff909216602092830290910182015260008381526006825260409081902080548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529192909190830182828015620017ce5780601f10620017a257610100808354040283529160200191620017ce565b820191906000526020600020905b815481529060010190602001808311620017b057829003601f168201915b50505050508784815181101515620017e257fe5b602090810291909101810191909152600083815260068252604090819020600190810180548351600293821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156200188b5780601f106200185f576101008083540402835291602001916200188b565b820191906000526020600020905b8154815290600101906020018083116200186d57829003601f168201915b505050505086848151811015156200189f57fe5b60209081029091018101919091526000838152600690915260409020600401548551869085908110620018ce57fe5b602090810290910101526001909201916200142f565b505050509295989b9194979a5092959850565b600c54600160a060020a031681565b60076020526000908152604090205481565b600b54600160a060020a03165b90565b6006602090815260009182526040918290208251815460026001821615610100026000190190911604601f8101849004909302810160c090810190945260a08101838152919390928492849290918491840182828015620019cd5780601f10620019a157610100808354040283529160200191620019cd565b820191906000526020600020905b815481529060010190602001808311620019af57829003601f168201915b50505050508152602001600182018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801562001a735780601f1062001a475761010080835404028352916020019162001a73565b820191906000526020600020905b81548152906001019060200180831162001a5557829003601f168201915b5050509183525050600282810180546040805160206001841615610100026000190190931694909404601f8101839004830285018301909152808452938101939083018282801562001b095780601f1062001add5761010080835404028352916020019162001b09565b820191906000526020600020905b81548152906001019060200180831162001aeb57829003601f168201915b5050509183525050600382015460ff1660208083019190915260049092015460409182015260058401546006850180548351601f6002600019600185161561010002019093169290920491820186900486028101860190945280845294959194919390919083018282801562001bc35780601f1062001b975761010080835404028352916020019162001bc3565b820191906000526020600020905b81548152906001019060200180831162001ba557829003601f168201915b50505050600783015460088401805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152959693959394509083018282801562001c5e5780601f1062001c325761010080835404028352916020019162001c5e565b820191906000526020600020905b81548152906001019060200180831162001c4057829003601f168201915b5050505050905085565b336000908152600a602052604090205460ff16151562001c9f5760405160e560020a62461bcd0281526004016200020a9062004490565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152600160a060020a038416906340c10f199062000be690859085906004016200420d565b600854600160a060020a0316331462001d185760405160e560020a62461bcd0281526004016200020a906200446c565b60008681526006602052604081206005015487911062001d4f5760405160e560020a62461bcd0281526004016200020a906200445a565b85516000888152600660209081526040909120825162001d759391929091019062003311565b5060208087015160008981526006835260409020815162001da0936001909201929091019062003311565b50604080870151600089815260066020908152929020815162001dce93600290920192919091019062003311565b506060860151600088815260066020818152604090922060038101805460ff191660ff909516949094179093556080890151600484015560058301889055865162001e20939091019187019062003311565b50600087815260066020908152604090912060078101859055835162001e4f9260089092019185019062003311565b50867f4eb0f9fb05e08613a2eba9dc272a43421cf32f9ccab592725ab663e3238f5f55878787878760405162001035959493929190620044b4565b600854600160a060020a0316331462001eba5760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381166000908152600a602052604090819020805460ff19166001179055517fad6de4452a631e641cb59902236607946ce9272b9b981f2f80e8d129cb9084ba90620008769083906200401d565b600854600160a060020a0316331462001f3f5760405160e560020a62461bcd0281526004016200020a906200446c565b6008805473ffffffffffffffffffffffffffffffffffffffff19169055565b600d6020526000908152604090205460ff1681565b600954600160a060020a031633141562001fb7576009546008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b600081815260066020526040812060050154606090819083908190151562002006576040805160208181018352600080835283519182019093528281529196509450925084915062002231565b60008681526006602090815260409182902060080180548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452620020af9392830182828015620020a45780601f106200207857610100808354040283529160200191620020a4565b820191906000526020600020905b8154815290600101906020018083116200208657829003601f168201915b5050505050620032bf565b905080600160a060020a03166306fdde036040518163ffffffff1660e060020a028152600401600060405180830381600087803b158015620020f057600080fd5b505af115801562002105573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200212f9190810190620038e5565b935080600160a060020a03166395d89b416040518163ffffffff1660e060020a028152600401600060405180830381600087803b1580156200217057600080fd5b505af115801562002185573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620021af9190810190620038e5565b925080600160a060020a031663313ce5676040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015620021f057600080fd5b505af115801562002205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200222b919081019062003b9e565b91508094505b509193509193565b600854600160a060020a031681565b600081815260066020908152604080832080548251601f6002600019610100600186161502019093169290920491820185900485028101850190935280835260609485948594919384939091830182828015620022e95780601f10620022bd57610100808354040283529160200191620022e9565b820191906000526020600020905b815481529060010190602001808311620022cb57829003601f168201915b505050600089815260066020908152604091829020600190810180548451600293821615610100026000190190911692909204601f8101849004840283018401909452838252959a509493509091508301828280156200238d5780601f1062002361576101008083540402835291602001916200238d565b820191906000526020600020905b8154815290600101906020018083116200236f57829003601f168201915b5050506000898152600660209081526040918290206002908101805484516001821615610100026000190190911692909204601f8101849004840283018401909452838252959950949350909150830182828015620024305780601f10620024045761010080835404028352916020019162002430565b820191906000526020600020905b8154815290600101906020018083116200241257829003601f168201915b50505060009889525050600660205260409096206003810154600490910154959794969560ff90911694909350915050565b336000908152600a602052604090205460ff161515620024995760405160e560020a62461bcd0281526004016200020a9062004490565b600186141562002528576040517f22862482000000000000000000000000000000000000000000000000000000008152600160a060020a03861690632286248290620024ee90879087908690600401620040f4565b600060405180830381600087803b1580156200250957600080fd5b505af11580156200251e573d6000803e3d6000fd5b5050505062000ddb565b60028614156200099a576040517f1f7fdffa000000000000000000000000000000000000000000000000000000008152600160a060020a03861690631f7fdffa90620024ee9087908790879087906004016200409a565b600854600160a060020a03163314620025af5760405160e560020a62461bcd0281526004016200020a906200446c565b6009805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600854600160a060020a031633146200260e5760405160e560020a62461bcd0281526004016200020a906200446c565b6040517ff4c84d19000000000000000000000000000000000000000000000000000000008152600160a060020a0386169063f4c84d19906200265b90879087908790879060040162004387565b600060405180830381600087803b1580156200267657600080fd5b505af11580156200268b573d6000803e3d6000fd5b505050507f86ead451719b8f4b763de2648808971e9bf540eed93efadafb044cd7ef5d91f48585858585604051620026c89594939291906200412e565b60405180910390a15050505050565b600854600160a060020a03163314620027075760405160e560020a62461bcd0281526004016200020a906200446c565b600c54604051600160a060020a038084169216907f2709918445f306d3e94d280907c62c5d2525ac3192d2e544774c7f181d65af3e90600090a3600c805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60008181526006602081815260408084206005810154930180548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352939460609490938593929190830182828015620028175780601f10620027eb5761010080835404028352916020019162002817565b820191906000526020600020905b815481529060010190602001808311620027f957829003601f168201915b505050600088815260066020908152604091829020600781015460089091018054845160026001831615610100026000190190921691909104601f81018590048502820185019095528481529699509097509350909150830182828015620028c35780601f106200289757610100808354040283529160200191620028c3565b820191906000526020600020905b815481529060010190602001808311620028a557829003601f168201915b505050505090509193509193565b600c54600090600160a060020a03163314620029045760405160e560020a62461bcd0281526004016200020a90620044a2565b838214620029295760405160e560020a62461bcd0281526004016200020a9062004412565b5060005b83811015620009b7578282828181106200294357fe5b9050602002013560ff16600d600087878581811015156200296057fe5b90506020020135815260200190815260200160002060006101000a81548160ff021916908360ff16021790555082828281811015156200299c57fe5b9050602002013560ff1660ff168585838181101515620029b857fe5b905060200201357f20f86c53e8884644ce473603799d40ecf47d8c4c1d55384fe8d0eeaf697786eb60405160405180910390a36001016200292d565b60055481565b600954600160a060020a031681565b600a6020526000908152604090205460ff1681565b60008181526006602090815260408083206002908101805483516001821615610100026000190190911692909204601f8101859004850283018501909352828252606094939192909183018282801562002abc5780601f1062002a905761010080835404028352916020019162002abc565b820191906000526020600020905b81548152906001019060200180831162002a9e57829003601f168201915b505050600095865250506006602052604090932060030154929360ff90931692915050565b606080606080606080606080606080600080600080600554935060009250600091508360405190808252806020026020018201604052801562002b2e578160200160208202803883390190505b509d508360405190808252806020026020018201604052801562002b5c578160200160208202803883390190505b509c508360405190808252806020026020018201604052801562002b9557816020015b606081526020019060019003908162002b7f5790505b509b508360405190808252806020026020018201604052801562002bc3578160200160208202803883390190505b509a508360405190808252806020026020018201604052801562002bfc57816020015b606081526020019060019003908162002be65790505b5099508360405190808252806020026020018201604052801562002c3557816020015b606081526020019060019003908162002c1f5790505b5098508360405190808252806020026020018201604052801562002c63578160200160208202803883390190505b5097508360405190808252806020026020018201604052801562002c9c57816020015b606081526020019060019003908162002c865790505b5096508360405190808252806020026020018201604052801562002cd557816020015b606081526020019060019003908162002cbf5790505b5095508360405190808252806020026020018201604052801562002d03578160200160208202803883390190505b5094506000915060009250600090505b600554811015620031c3576000818152600760205260409020548e5190935083908f908490811062002d4157fe5b60209081029091018101919091526000848152600690915260409020600501548d518e908490811062002d7057fe5b60209081029190910181019190915260008481526006808352604091829020018054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529290919083018282801562002e165780601f1062002dea5761010080835404028352916020019162002e16565b820191906000526020600020905b81548152906001019060200180831162002df857829003601f168201915b50505050508c8381518110151562002e2a57fe5b60209081029091018101919091526000848152600690915260409020600701548b518c908490811062002e5957fe5b6020908102919091018101919091526000848152600682526040908190206008018054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529290919083018282801562002f005780601f1062002ed45761010080835404028352916020019162002f00565b820191906000526020600020905b81548152906001019060200180831162002ee257829003601f168201915b50505050508a8381518110151562002f1457fe5b6020908102909101810191909152600084815260068252604090819020600290810180548351601f6000196101006001851615020190921693909304908101859004850283018501909352828252909290919083018282801562002fbc5780601f1062002f905761010080835404028352916020019162002fbc565b820191906000526020600020905b81548152906001019060200180831162002f9e57829003601f168201915b5050505050898381518110151562002fd057fe5b6020908102909101810191909152600084815260069091526040902060030154885160ff909116908990849081106200300557fe5b60ff909216602092830290910182015260008481526006825260409081902080548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529192909190830182828015620030ac5780601f106200308057610100808354040283529160200191620030ac565b820191906000526020600020905b8154815290600101906020018083116200308e57829003601f168201915b50505050508783815181101515620030c057fe5b602090810291909101810191909152600084815260068252604090819020600190810180548351600293821615610100026000190190911692909204601f81018590048502830185019093528282529092909190830182828015620031695780601f106200313d5761010080835404028352916020019162003169565b820191906000526020600020905b8154815290600101906020018083116200314b57829003601f168201915b505050505086838151811015156200317d57fe5b60209081029091018101919091526000848152600690915260409020600401548551869084908110620031ac57fe5b602090810290910101526001918201910162002d13565b5050505090919293949596979899565b600854600090600160a060020a03163314620032065760405160e560020a62461bcd0281526004016200020a906200446c565b85858585856200321562003396565b62003225959493929190620043b2565b604051809103906000f08015801562003242573d6000803e3d6000fd5b5090507fbb5f9980e27ec75b79e41ce422e643c6c0116fd9f599776a72f89032f70fe205818787878787604051620032809695949392919062004175565b60405180910390a1505050505050565b60009081526006602052604090206004015490565b600082820183811015620032b857600080fd5b9392505050565b6014015190565b50805460018160011615610100020316600290046000825580601f10620032ee57506200330e565b601f0160209004906000526020600020908101906200330e9190620033a7565b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200335457805160ff191683800117855562003384565b8280016001018555821562003384579182015b828111156200338457825182559160200191906001019062003367565b5062003392929150620033a7565b5090565b604051611074806200468d83390190565b6200192591905b80821115620033925760008155600101620033ae565b6000620032b882356200462c565b600080601f83018413620033e557600080fd5b50813567ffffffffffffffff811115620033fe57600080fd5b6020830191508360208202830111156200341757600080fd5b9250929050565b6000601f820183136200343057600080fd5b8135620034476200344182620045d7565b620045af565b915081818352602084019350602081019050838560208402820111156200346d57600080fd5b60005b838110156200349d578162003486888262003669565b845250602092830192919091019060010162003470565b5050505092915050565b6000601f82018313620034b957600080fd5b8135620034ca6200344182620045f9565b91508082526020830160208301858383011115620034e757600080fd5b620034f483828462004643565b50505092915050565b600080601f830184136200351057600080fd5b50813567ffffffffffffffff8111156200352957600080fd5b6020830191508360018202830111156200341757600080fd5b6000601f820183136200355457600080fd5b8151620035656200344182620045f9565b915080825260208301602083018583830111156200358257600080fd5b620034f48382846200464f565b600060a08284031215620035a257600080fd5b620035ae60a0620045af565b9050813567ffffffffffffffff811115620035c857600080fd5b620035d684828501620034a7565b825250602082013567ffffffffffffffff811115620035f457600080fd5b6200360284828501620034a7565b602083015250604082013567ffffffffffffffff8111156200362357600080fd5b6200363184828501620034a7565b6040830152506060620036478482850162003677565b60608301525060806200365d8482850162003669565b60808301525092915050565b6000620032b8823562001925565b6000620032b882356200463d565b6000620032b882516200463d565b600060208284031215620036a657600080fd5b6000620036b48484620033c4565b949350505050565b60008060408385031215620036d057600080fd5b6000620036de8585620033c4565b9250506020620036f185828601620033c4565b9150509250929050565b6000806000606084860312156200371157600080fd5b60006200371f8686620033c4565b93505060206200373286828701620033c4565b9250506040620037458682870162003669565b9150509250925092565b6000806000806000606086880312156200376857600080fd5b6000620037768888620033c4565b955050602086013567ffffffffffffffff8111156200379457600080fd5b620037a288828901620034fd565b9450945050604086013567ffffffffffffffff811115620037c257600080fd5b620037d088828901620034fd565b92509250509295509295909350565b60008060008060408587031215620037f657600080fd5b843567ffffffffffffffff8111156200380e57600080fd5b6200381c87828801620033d2565b9450945050602085013567ffffffffffffffff8111156200383c57600080fd5b6200384a87828801620033d2565b95989497509550505050565b6000806000806000606086880312156200386f57600080fd5b853567ffffffffffffffff8111156200388757600080fd5b6200389588828901620034fd565b9550955050602086013567ffffffffffffffff811115620038b557600080fd5b620038c388828901620034fd565b93509350506040620038d88882890162003677565b9150509295509295909350565b600060208284031215620038f857600080fd5b815167ffffffffffffffff8111156200391057600080fd5b620036b48482850162003542565b6000602082840312156200393157600080fd5b6000620036b4848462003669565b600080600080600060a086880312156200395857600080fd5b600062003966888862003669565b95505060206200397988828901620033c4565b94505060406200398c88828901620033c4565b935050606086013567ffffffffffffffff811115620039aa57600080fd5b620039b8888289016200341e565b925050608086013567ffffffffffffffff811115620039d657600080fd5b620038d8888289016200341e565b60008060008060008060c08789031215620039fe57600080fd5b600062003a0c898962003669565b965050602062003a1f89828a01620033c4565b955050604062003a3289828a01620033c4565b945050606087013567ffffffffffffffff81111562003a5057600080fd5b62003a5e89828a016200341e565b935050608087013567ffffffffffffffff81111562003a7c57600080fd5b62003a8a89828a016200341e565b92505060a087013567ffffffffffffffff81111562003aa857600080fd5b62003ab689828a01620034a7565b9150509295509295509295565b60008060008060008060c0878903121562003add57600080fd5b600062003aeb898962003669565b965050602087013567ffffffffffffffff81111562003b0957600080fd5b62003b1789828a016200358f565b955050604062003b2a89828a0162003669565b945050606087013567ffffffffffffffff81111562003b4857600080fd5b62003b5689828a01620034a7565b935050608062003a8a89828a0162003669565b6000806040838503121562003b7d57600080fd5b600062003b8b858562003669565b9250506020620036f18582860162003669565b60006020828403121562003bb157600080fd5b6000620036b4848462003685565b62003bca816200462c565b82525050565b600062003bdd8262004628565b8084526020840193508360208202850162003bf88562004622565b60005b8481101562003c3557838303885262003c1683835162003d69565b925062003c238262004622565b60209890980197915060010162003bfb565b50909695505050505050565b600062003c4e8262004628565b8084526020840193508360208202850162003c698562004622565b60005b8481101562003c3557838303885262003c8783835162003d69565b925062003c948262004622565b60209890980197915060010162003c6c565b600062003cb38262004628565b80845260208401935062003cc78362004622565b60005b8281101562003cfd5762003ce086835162004007565b62003ceb8262004622565b60209690960195915060010162003cca565b5093949350505050565b600062003d148262004628565b80845260208401935062003d288362004622565b60005b8281101562003cfd5762003d4186835162004012565b62003d4c8262004622565b60209690960195915060010162003d2b565b62003bca8162004638565b600062003d768262004628565b80845262003d8c8160208601602086016200464f565b62003d978162004682565b9093016020019392505050565b600082845260208401935062003dbc83858462004643565b62003dc78362004682565b9093019392505050565b600f81527f6c656e677468206d69736d617463680000000000000000000000000000000000602082015260400190565b600b81527f746f6b656e206578697374000000000000000000000000000000000000000000602082015260400190565b601f81527f696d706c656d656e746174696f6e20636f6e7472616374206e6f742073657400602082015260400190565b601d81527f4e6577206f776e657220697320746865207a65726f2061646472657373000000602082015260400190565b600f81527f746f6b656e206e6f742065786973740000000000000000000000000000000000602082015260400190565b600981527f4e6f74206f776e65720000000000000000000000000000000000000000000000602082015260400190565b601081527f496e76616c6964204e4654207479706500000000000000000000000000000000602082015260400190565b600981527f6e6f742061646d696e0000000000000000000000000000000000000000000000602082015260400190565b600c81527f6e6f74206f70657261746f720000000000000000000000000000000000000000602082015260400190565b805160a08084526000919084019062003f9b828262003d69565b9150506020830151848203602086015262003fb7828262003d69565b9150506040830151848203604086015262003fd3828262003d69565b915050606083015162003fea606086018262004012565b50608083015162003fff608086018262004007565b509392505050565b62003bca8162001925565b62003bca816200463d565b602081016200402d828462003bbf565b92915050565b6040810162004043828562003bbf565b8181036020830152620036b4818462003ca6565b6060810162004067828662003bbf565b81810360208301526200407b818562003ca6565b9050818103604083015262004091818462003ca6565b95945050505050565b60808101620040aa828762003bbf565b8181036020830152620040be818662003ca6565b90508181036040830152620040d4818562003ca6565b90508181036060830152620040ea818462003d69565b9695505050505050565b6060810162004104828662003bbf565b818103602083015262004118818562003ca6565b9050818103604083015262004091818462003d69565b606081016200413e828862003bbf565b81810360208301526200415381868862003da4565b905081810360408301526200416a81848662003da4565b979650505050505050565b6080810162004185828962003bbf565b81810360208301526200419a81878962003da4565b90508181036040830152620041b181858762003da4565b90506200416a606083018462004012565b60808101620041d2828762003bbf565b8181036020830152620041e6818662003d69565b90508181036040830152620041fc818562003d69565b905062004091606083018462004012565b604081016200421d828562003bbf565b620032b8602083018462004007565b610140808252810162004240818d62003ca6565b9050818103602083015262004256818c62003ca6565b905081810360408301526200426c818b62003bd0565b9050818103606083015262004282818a62003ca6565b9050818103608083015262004298818962003bd0565b905081810360a0830152620042ae818862003c41565b905081810360c0830152620042c4818762003d07565b905081810360e0830152620042da818662003bd0565b9050818103610100830152620042f1818562003c41565b905081810361012083015262004308818462003ca6565b9c9b505050505050505050505050565b602081016200402d828462003d5e565b60a080825281016200433b818862003d69565b9050818103602083015262004351818762003d69565b9050818103604083015262004367818662003d69565b905062004378606083018562004012565b620040ea608083018462004007565b604080825281016200439b81868862003da4565b90508181036020830152620040ea81848662003da4565b60608082528101620043c681878962003da4565b90508181036020830152620043dd81858762003da4565b9050620040ea604083018462004012565b6040808252810162004401818562003d69565b9050620032b8602083018462004012565b602080825281016200402d8162003dd1565b602080825281016200402d8162003e01565b602080825281016200402d8162003e31565b602080825281016200402d8162003e61565b602080825281016200402d8162003e91565b602080825281016200402d8162003ec1565b602080825281016200402d8162003ef1565b602080825281016200402d8162003f21565b602080825281016200402d8162003f51565b60a08082528101620044c7818862003f81565b9050620044d8602083018762004007565b8181036040830152620044ec818662003d69565b9050620044fd606083018562004007565b81810360808301526200416a818462003d69565b602081016200402d828462004007565b6060810162004531828662004007565b818103602083015262004545818562003d69565b9050620036b4604083018462004007565b6080810162004566828762004007565b81810360208301526200457a818662003d69565b90506200458b604083018562004007565b8181036060830152620040ea818462003d69565b602081016200402d828462004012565b60405181810167ffffffffffffffff81118282101715620045cf57600080fd5b604052919050565b600067ffffffffffffffff821115620045ef57600080fd5b5060209081020190565b600067ffffffffffffffff8211156200461157600080fd5b506020601f91909101601f19160190565b60200190565b5190565b600160a060020a031690565b151590565b60ff1690565b82818337506000910152565b60005b838110156200466c57818101518382015260200162004652565b838111156200467c576000848401525b50505050565b601f01601f1916905600608060405234801561001057600080fd5b50604051620010743803806200107483398101604090815281516020808401519284015160068054600160a060020a031916331790559184018051909493909301926100629160009190860190610093565b508151610076906001906020850190610093565b506002805460ff191660ff929092169190911790555061012e9050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d457805160ff1916838001178555610101565b82800160010185558215610101579182015b828111156101015782518255916020019190600101906100e6565b5061010d929150610111565b5090565b61012b91905b8082111561010d5760008155600101610117565b90565b610f36806200013e6000396000f3006080604052600436106100fb5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610100578063095ea7b31461018a57806318160ddd146101c257806323b872dd146101e9578063313ce5671461021357806340c10f191461023e5780634fb2e45d1461026457806370a0823114610285578063715018a6146102a657806379ba5097146102bb5780638da5cb5b146102d057806395d89b41146103015780639dc29fac14610316578063a6f9dae11461033a578063a9059cbb1461035b578063d4ee1d901461037f578063dd62ed3e14610394578063f4c84d19146103bb575b600080fd5b34801561010c57600080fd5b506101156103e7565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561014f578181015183820152602001610137565b50505050905090810190601f16801561017c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561019657600080fd5b506101ae600160a060020a0360043516602435610475565b604080519115158252519081900360200190f35b3480156101ce57600080fd5b506101d76105be565b60408051918252519081900360200190f35b3480156101f557600080fd5b506101ae600160a060020a03600435811690602435166044356105c4565b34801561021f57600080fd5b50610228610716565b6040805160ff9092168252519081900360200190f35b34801561024a57600080fd5b50610262600160a060020a036004351660243561071f565b005b34801561027057600080fd5b50610262600160a060020a0360043516610854565b34801561029157600080fd5b506101d7600160a060020a036004351661096d565b3480156102b257600080fd5b50610262610988565b3480156102c757600080fd5b506102626109f7565b3480156102dc57600080fd5b506102e5610a3c565b60408051600160a060020a039092168252519081900360200190f35b34801561030d57600080fd5b50610115610a4b565b34801561032257600080fd5b50610262600160a060020a0360043516602435610aa5565b34801561034657600080fd5b50610262600160a060020a0360043516610bda565b34801561036757600080fd5b506101ae600160a060020a0360043516602435610c59565b34801561038b57600080fd5b506102e5610d55565b3480156103a057600080fd5b506101d7600160a060020a0360043581169060243516610d64565b3480156103c757600080fd5b506102626024600480358281019290820135918135918201910135610d8f565b6000805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561046d5780601f106104425761010080835404028352916020019161046d565b820191906000526020600020905b81548152906001019060200180831161045057829003601f168201915b505050505081565b6000604060443610156104d2576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b8215806105005750336000908152600460209081526040808320600160a060020a0388168452909152902054155b1515610556576040805160e560020a62461bcd02815260206004820152600d60248201527f4e6f74207065726d697474656400000000000000000000000000000000000000604482015290519081900360640190fd5b336000818152600460209081526040808320600160a060020a03891680855290835292819020879055805187815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b60055481565b600060606064361015610621576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b600160a060020a03841660009081526003602052604090205461064a908463ffffffff610dff16565b600160a060020a03808616600090815260036020526040808220939093559087168152205461067f908463ffffffff610e1816565b600160a060020a03861660009081526003602090815260408083209390935560048152828220338352905220546106bc908463ffffffff610e1816565b600160a060020a0380871660008181526004602090815260408083203384528252918290209490945580518781529051928816939192600080516020610eeb833981519152929181900390910190a3506001949350505050565b60025460ff1681565b600654600160a060020a0316331461076f576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b80600081116107c8576040805160e560020a62461bcd02815260206004820152600d60248201527f56616c7565206973206e756c6c00000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0383166000908152600360205260409020546107f1908363ffffffff610dff16565b600160a060020a03841660009081526003602052604090205560055461081d908363ffffffff610dff16565b600555604080518381529051600160a060020a03851691600091600080516020610eeb8339815191529181900360200190a3505050565b600654600160a060020a031633146108a4576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b600160a060020a0381161515610904576040805160e560020a62461bcd02815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f2061646472657373000000604482015290519081900360640190fd5b600654604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600160a060020a031660009081526003602052604090205490565b600654600160a060020a031633146109d8576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff19169055565b600754600160a060020a0316331415610a3a576007546006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b600654600160a060020a031681565b60018054604080516020600284861615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561046d5780601f106104425761010080835404028352916020019161046d565b600654600160a060020a03163314610af5576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b8060008111610b4e576040805160e560020a62461bcd02815260206004820152600d60248201527f56616c7565206973206e756c6c00000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a038316600090815260036020526040902054610b77908363ffffffff610e1816565b600160a060020a038416600090815260036020526040902055600554610ba3908363ffffffff610e1816565b600555604080518381529051600091600160a060020a03861691600080516020610eeb8339815191529181900360200190a3505050565b600654600160a060020a03163314610c2a576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600060406044361015610cb6576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b33600090815260036020526040902054610cd6908463ffffffff610e1816565b3360009081526003602052604080822092909255600160a060020a03861681522054610d08908463ffffffff610dff16565b600160a060020a038516600081815260036020908152604091829020939093558051868152905191923392600080516020610eeb8339815191529281900390910190a35060019392505050565b600754600160a060020a031681565b600160a060020a03918216600090815260046020908152604080832093909416825291909152205490565b600654600160a060020a03163314610ddf576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b610deb60008585610e2f565b50610df860018383610e2f565b5050505050565b600082820183811015610e1157600080fd5b9392505050565b60008083831115610e2857600080fd5b5050900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610e705782800160ff19823516178555610e9d565b82800160010185558215610e9d579182015b82811115610e9d578235825591602001919060010190610e82565b50610ea9929150610ead565b5090565b610ec791905b80821115610ea95760008155600101610eb3565b9056004e6f74206f776e65720000000000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058206d4252b7c832609eb582477b493727af6d5a697d8bd98ecb4fde197c9b29746b0029a265627a7a72305820eb2ddf721fe7086bedc02025ca331dcf40dabd4ca948de05f9dca0890c181b086c6578706572696d656e74616cf50037

Deployed ByteCode

0x608060405260043610620001d95763ffffffff60e060020a6000350416631785f53c8114620002395780632859c58014620002605780632b56590514620002855780633416794d14620002aa5780633ad8873a14620002cf5780633cc281df146200030e578063408e743d146200033357806341246e5314620003585780634f600ae8146200037d5780634fb2e45d14620003a2578063563cb1ab14620003c7578063570ca735146200040457806358a007fb146200042b5780635c60da1b146200045f5780635d2e9ead14620004775780636bec32da14620004af5780636c45e2dc14620004d45780637048027514620004f9578063715018a6146200051e57806375d2e27d146200053657806379ba5097146200056a5780638c7a63ae14620005825780638da5cb5b14620005b95780639027e6f714620005d15780639947f9321462000609578063a6f9dae1146200062e578063af33f17e1462000653578063b3ab15fb1462000678578063b9073276146200069d578063cbfbd61a14620006d4578063d0ad718d14620006f9578063d4ee1d901462000711578063d51dddd71462000729578063e101d3c1146200075d578063e24e4fdb1462000792578063f3bdd86314620007aa578063f4debe1e14620007cf575b600b54600160a060020a0316801515620002135760405160e560020a62461bcd0281526004016200020a9062004436565b60405180910390fd5b60405136600082376000803683855af43d806000843e81801562000235578184f35b8184fd5b3480156200024657600080fd5b506200025e6200025836600462003693565b620007f4565b005b3480156200026d57600080fd5b506200025e6200027f3660046200393f565b62000881565b3480156200029257600080fd5b506200025e620002a43660046200391e565b620009be565b348015620002b757600080fd5b506200025e620002c9366004620036fb565b62000b66565b348015620002dc57600080fd5b50620002f4620002ee3660046200391e565b62000c1f565b604051620003059392919062004521565b60405180910390f35b3480156200031b57600080fd5b506200025e6200032d36600462003693565b62000ce0565b3480156200034057600080fd5b506200025e62000352366004620036bc565b62000d34565b3480156200036557600080fd5b506200025e62000377366004620036bc565b62000de3565b3480156200038a57600080fd5b506200025e6200039c36600462003ac3565b62000e5a565b348015620003af57600080fd5b506200025e620003c136600462003693565b62001046565b348015620003d457600080fd5b50620003ec620003e636600462003b69565b6200110d565b604051620003059a999897969594939291906200422c565b3480156200041157600080fd5b506200041c620018f7565b6040516200030591906200401d565b3480156200043857600080fd5b50620004506200044a3660046200391e565b62001906565b60405162000305919062004511565b3480156200046c57600080fd5b506200041c62001918565b3480156200048457600080fd5b506200049c620004963660046200391e565b62001928565b60405162000305959493929190620044b4565b348015620004bc57600080fd5b506200025e620004ce366004620036fb565b62001c68565b348015620004e157600080fd5b506200025e620004f336600462003ac3565b62001ce8565b3480156200050657600080fd5b506200025e6200051836600462003693565b62001e8a565b3480156200052b57600080fd5b506200025e62001f0f565b3480156200054357600080fd5b506200055b620005553660046200391e565b62001f5e565b6040516200030591906200459f565b3480156200057757600080fd5b506200025e62001f73565b3480156200058f57600080fd5b50620005a7620005a13660046200391e565b62001fb9565b604051620003059493929190620041c2565b348015620005c657600080fd5b506200041c62002239565b348015620005de57600080fd5b50620005f6620005f03660046200391e565b62002248565b6040516200030595949392919062004328565b3480156200061657600080fd5b506200025e62000628366004620039e4565b62002462565b3480156200063b57600080fd5b506200025e6200064d36600462003693565b6200257f565b3480156200066057600080fd5b506200025e620006723660046200374f565b620025de565b3480156200068557600080fd5b506200025e6200069736600462003693565b620026d7565b348015620006aa57600080fd5b50620006c2620006bc3660046200391e565b62002770565b60405162000305949392919062004556565b348015620006e157600080fd5b506200025e620006f3366004620037df565b620028d1565b3480156200070657600080fd5b5062000450620029f4565b3480156200071e57600080fd5b506200041c620029fa565b3480156200073657600080fd5b506200074e6200074836600462003693565b62002a09565b60405162000305919062004318565b3480156200076a57600080fd5b50620007826200077c3660046200391e565b62002a1e565b60405162000305929190620043ee565b3480156200079f57600080fd5b50620003ec62002ae1565b348015620007b757600080fd5b506200025e620007c936600462003856565b620031d3565b348015620007dc57600080fd5b5062000450620007ee3660046200391e565b62003290565b600854600160a060020a03163314620008245760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381166000908152600a602052604090819020805460ff19169055517f753f40ca3312b2408759a67875b367955e7baa221daf08aa3d643d96202ac12b90620008769083906200401d565b60405180910390a150565b336000908152600a602052604090205460ff161515620008b85760405160e560020a62461bcd0281526004016200020a9062004490565b600185141562000945576040517fb2dc5dc3000000000000000000000000000000000000000000000000000000008152600160a060020a0385169063b2dc5dc3906200090b908690869060040162004033565b600060405180830381600087803b1580156200092657600080fd5b505af11580156200093b573d6000803e3d6000fd5b50505050620009b7565b60028514156200099a576040517f6b20c454000000000000000000000000000000000000000000000000000000008152600160a060020a03851690636b20c454906200090b9086908690869060040162004057565b60405160e560020a62461bcd0281526004016200020a906200447e565b5050505050565b600854600090600160a060020a03163314620009f15760405160e560020a62461bcd0281526004016200020a906200446c565b60008281526006602052604081206005015483911062000a285760405160e560020a62461bcd0281526004016200020a906200445a565b600091505b60055482101562000b615760008281526007602052604090205483141562000b555760055460001901821462000a7b5760055460001901600090815260076020526040808220548483529120555b60058054600019908101600090815260076020908152604080832083905584549093019093558581526006909252812090818162000aba8282620032c6565b62000aca600183016000620032c6565b62000ada600283016000620032c6565b5060038101805460ff19169055600060049091018190556005830181905562000b08906006840190620032c6565b600782016000905560088201600062000b229190620032c6565b505060405183907fa219112a711e6173c2e8978836823d4e86832d96c0ea2fd05ec77687b7a073ab90600090a262000b61565b60019091019062000a2d565b505050565b336000908152600a602052604090205460ff16151562000b9d5760405160e560020a62461bcd0281526004016200020a9062004490565b6040517f9dc29fac000000000000000000000000000000000000000000000000000000008152600160a060020a03841690639dc29fac9062000be690859085906004016200420d565b600060405180830381600087803b15801562000c0157600080fd5b505af115801562000c16573d6000803e3d6000fd5b50505050505050565b60008181526006602081815260408084206005810154930180548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529394606094909383018282801562000cc15780601f1062000c955761010080835404028352916020019162000cc1565b820191906000526020600020905b81548152906001019060200180831162000ca357829003601f168201915b5050506000968752505060066020526040909420600701549294915050565b80600160a060020a03166379ba50976040518163ffffffff1660e060020a028152600401600060405180830381600087803b15801562000d1f57600080fd5b505af1158015620009b7573d6000803e3d6000fd5b600854600160a060020a0316331462000d645760405160e560020a62461bcd0281526004016200020a906200446c565b6040517f4fb2e45d000000000000000000000000000000000000000000000000000000008152600160a060020a03831690634fb2e45d9062000dab9084906004016200401d565b600060405180830381600087803b15801562000dc657600080fd5b505af115801562000ddb573d6000803e3d6000fd5b505050505050565b600854600160a060020a0316331462000e135760405160e560020a62461bcd0281526004016200020a906200446c565b6040517fa6f9dae1000000000000000000000000000000000000000000000000000000008152600160a060020a0383169063a6f9dae19062000dab9084906004016200401d565b600854600160a060020a0316331462000e8a5760405160e560020a62461bcd0281526004016200020a906200446c565b60008681526006602052604090206005015486901562000ec15760405160e560020a62461bcd0281526004016200020a9062004424565b600087815260066020818152604090922060058101889055865162000eef9391909201919087019062003311565b50600087815260066020908152604090912060078101859055835162000f1e9260089092019185019062003311565b5085516000888152600660209081526040909120825162000f459391929091019062003311565b5060208087015160008981526006835260409020815162000f70936001909201929091019062003311565b50604080870151600089815260066020908152929020815162000f9e93600290920192919091019062003311565b506060860151600088815260066020908152604080832060038101805460ff191660ff9096169590951790945560808a015160049094019390935560058054835260079091529190208890555462000ff8906001620032a5565b60055560405187907f226f08da880957e11c8affd4d622bb21b058cf67830d2ee56bb82d9b7197e9a7906200103590889088908890889062004556565b60405180910390a250505050505050565b600854600160a060020a03163314620010765760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381161515620010a45760405160e560020a62461bcd0281526004016200020a9062004448565b600854604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b606080606080606080606080606080600080600060606000935060009250600091506005546040519080825280602002602001820160405280156200115c578160200160208202803883390190505b5090505b6005548310156200122757600760008481526020019081526020016000205491508f6006600084815260200190815260200160002060050154148015620011b757506000828152600660205260409020600701548f145b80620011f457508f6006600084815260200190815260200160002060070154148015620011f457506000828152600660205260409020600501548f145b156200121b578181858151811015156200120a57fe5b602090810290910101526001909301925b60019092019162001160565b8360405190808252806020026020018201604052801562001252578160200160208202803883390190505b509d508360405190808252806020026020018201604052801562001280578160200160208202803883390190505b509c5083604051908082528060200260200182016040528015620012b957816020015b6060815260200190600190039081620012a35790505b509b5083604051908082528060200260200182016040528015620012e7578160200160208202803883390190505b509a50836040519080825280602002602001820160405280156200132057816020015b60608152602001906001900390816200130a5790505b509950836040519080825280602002602001820160405280156200135957816020015b6060815260200190600190039081620013435790505b5098508360405190808252806020026020018201604052801562001387578160200160208202803883390190505b50975083604051908082528060200260200182016040528015620013c057816020015b6060815260200190600190039081620013aa5790505b50965083604051908082528060200260200182016040528015620013f957816020015b6060815260200190600190039081620013e35790505b5095508360405190808252806020026020018201604052801562001427578160200160208202803883390190505b509450600092505b83831015620018e45780838151811015156200144757fe5b906020019060200201519150818e848151811015156200146357fe5b60209081029091018101919091526000838152600690915260409020600501548d518e90859081106200149257fe5b60209081029190910181019190915260008381526006808352604091829020018054825160026001831615610100026000190190921691909104601f810185900485028201850190935282815292909190830182828015620015385780601f106200150c5761010080835404028352916020019162001538565b820191906000526020600020905b8154815290600101906020018083116200151a57829003601f168201915b50505050508c848151811015156200154c57fe5b60209081029091018101919091526000838152600690915260409020600701548b518c90859081106200157b57fe5b6020908102919091018101919091526000838152600682526040908190206008018054825160026001831615610100026000190190921691909104601f810185900485028201850190935282815292909190830182828015620016225780601f10620015f65761010080835404028352916020019162001622565b820191906000526020600020905b8154815290600101906020018083116200160457829003601f168201915b50505050508a848151811015156200163657fe5b6020908102909101810191909152600083815260068252604090819020600290810180548351601f60001961010060018516150201909216939093049081018590048502830185019093528282529092909190830182828015620016de5780601f10620016b257610100808354040283529160200191620016de565b820191906000526020600020905b815481529060010190602001808311620016c057829003601f168201915b50505050508984815181101515620016f257fe5b6020908102909101810191909152600083815260069091526040902060030154885160ff909116908990859081106200172757fe5b60ff909216602092830290910182015260008381526006825260409081902080548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529192909190830182828015620017ce5780601f10620017a257610100808354040283529160200191620017ce565b820191906000526020600020905b815481529060010190602001808311620017b057829003601f168201915b50505050508784815181101515620017e257fe5b602090810291909101810191909152600083815260068252604090819020600190810180548351600293821615610100026000190190911692909204601f810185900485028301850190935282825290929091908301828280156200188b5780601f106200185f576101008083540402835291602001916200188b565b820191906000526020600020905b8154815290600101906020018083116200186d57829003601f168201915b505050505086848151811015156200189f57fe5b60209081029091018101919091526000838152600690915260409020600401548551869085908110620018ce57fe5b602090810290910101526001909201916200142f565b505050509295989b9194979a5092959850565b600c54600160a060020a031681565b60076020526000908152604090205481565b600b54600160a060020a03165b90565b6006602090815260009182526040918290208251815460026001821615610100026000190190911604601f8101849004909302810160c090810190945260a08101838152919390928492849290918491840182828015620019cd5780601f10620019a157610100808354040283529160200191620019cd565b820191906000526020600020905b815481529060010190602001808311620019af57829003601f168201915b50505050508152602001600182018054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801562001a735780601f1062001a475761010080835404028352916020019162001a73565b820191906000526020600020905b81548152906001019060200180831162001a5557829003601f168201915b5050509183525050600282810180546040805160206001841615610100026000190190931694909404601f8101839004830285018301909152808452938101939083018282801562001b095780601f1062001add5761010080835404028352916020019162001b09565b820191906000526020600020905b81548152906001019060200180831162001aeb57829003601f168201915b5050509183525050600382015460ff1660208083019190915260049092015460409182015260058401546006850180548351601f6002600019600185161561010002019093169290920491820186900486028101860190945280845294959194919390919083018282801562001bc35780601f1062001b975761010080835404028352916020019162001bc3565b820191906000526020600020905b81548152906001019060200180831162001ba557829003601f168201915b50505050600783015460088401805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152959693959394509083018282801562001c5e5780601f1062001c325761010080835404028352916020019162001c5e565b820191906000526020600020905b81548152906001019060200180831162001c4057829003601f168201915b5050505050905085565b336000908152600a602052604090205460ff16151562001c9f5760405160e560020a62461bcd0281526004016200020a9062004490565b6040517f40c10f19000000000000000000000000000000000000000000000000000000008152600160a060020a038416906340c10f199062000be690859085906004016200420d565b600854600160a060020a0316331462001d185760405160e560020a62461bcd0281526004016200020a906200446c565b60008681526006602052604081206005015487911062001d4f5760405160e560020a62461bcd0281526004016200020a906200445a565b85516000888152600660209081526040909120825162001d759391929091019062003311565b5060208087015160008981526006835260409020815162001da0936001909201929091019062003311565b50604080870151600089815260066020908152929020815162001dce93600290920192919091019062003311565b506060860151600088815260066020818152604090922060038101805460ff191660ff909516949094179093556080890151600484015560058301889055865162001e20939091019187019062003311565b50600087815260066020908152604090912060078101859055835162001e4f9260089092019185019062003311565b50867f4eb0f9fb05e08613a2eba9dc272a43421cf32f9ccab592725ab663e3238f5f55878787878760405162001035959493929190620044b4565b600854600160a060020a0316331462001eba5760405160e560020a62461bcd0281526004016200020a906200446c565b600160a060020a0381166000908152600a602052604090819020805460ff19166001179055517fad6de4452a631e641cb59902236607946ce9272b9b981f2f80e8d129cb9084ba90620008769083906200401d565b600854600160a060020a0316331462001f3f5760405160e560020a62461bcd0281526004016200020a906200446c565b6008805473ffffffffffffffffffffffffffffffffffffffff19169055565b600d6020526000908152604090205460ff1681565b600954600160a060020a031633141562001fb7576009546008805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b600081815260066020526040812060050154606090819083908190151562002006576040805160208181018352600080835283519182019093528281529196509450925084915062002231565b60008681526006602090815260409182902060080180548351601f60026000196101006001861615020190931692909204918201849004840281018401909452808452620020af9392830182828015620020a45780601f106200207857610100808354040283529160200191620020a4565b820191906000526020600020905b8154815290600101906020018083116200208657829003601f168201915b5050505050620032bf565b905080600160a060020a03166306fdde036040518163ffffffff1660e060020a028152600401600060405180830381600087803b158015620020f057600080fd5b505af115801562002105573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526200212f9190810190620038e5565b935080600160a060020a03166395d89b416040518163ffffffff1660e060020a028152600401600060405180830381600087803b1580156200217057600080fd5b505af115801562002185573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052620021af9190810190620038e5565b925080600160a060020a031663313ce5676040518163ffffffff1660e060020a028152600401602060405180830381600087803b158015620021f057600080fd5b505af115801562002205573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506200222b919081019062003b9e565b91508094505b509193509193565b600854600160a060020a031681565b600081815260066020908152604080832080548251601f6002600019610100600186161502019093169290920491820185900485028101850190935280835260609485948594919384939091830182828015620022e95780601f10620022bd57610100808354040283529160200191620022e9565b820191906000526020600020905b815481529060010190602001808311620022cb57829003601f168201915b505050600089815260066020908152604091829020600190810180548451600293821615610100026000190190911692909204601f8101849004840283018401909452838252959a509493509091508301828280156200238d5780601f1062002361576101008083540402835291602001916200238d565b820191906000526020600020905b8154815290600101906020018083116200236f57829003601f168201915b5050506000898152600660209081526040918290206002908101805484516001821615610100026000190190911692909204601f8101849004840283018401909452838252959950949350909150830182828015620024305780601f10620024045761010080835404028352916020019162002430565b820191906000526020600020905b8154815290600101906020018083116200241257829003601f168201915b50505060009889525050600660205260409096206003810154600490910154959794969560ff90911694909350915050565b336000908152600a602052604090205460ff161515620024995760405160e560020a62461bcd0281526004016200020a9062004490565b600186141562002528576040517f22862482000000000000000000000000000000000000000000000000000000008152600160a060020a03861690632286248290620024ee90879087908690600401620040f4565b600060405180830381600087803b1580156200250957600080fd5b505af11580156200251e573d6000803e3d6000fd5b5050505062000ddb565b60028614156200099a576040517f1f7fdffa000000000000000000000000000000000000000000000000000000008152600160a060020a03861690631f7fdffa90620024ee9087908790879087906004016200409a565b600854600160a060020a03163314620025af5760405160e560020a62461bcd0281526004016200020a906200446c565b6009805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600854600160a060020a031633146200260e5760405160e560020a62461bcd0281526004016200020a906200446c565b6040517ff4c84d19000000000000000000000000000000000000000000000000000000008152600160a060020a0386169063f4c84d19906200265b90879087908790879060040162004387565b600060405180830381600087803b1580156200267657600080fd5b505af11580156200268b573d6000803e3d6000fd5b505050507f86ead451719b8f4b763de2648808971e9bf540eed93efadafb044cd7ef5d91f48585858585604051620026c89594939291906200412e565b60405180910390a15050505050565b600854600160a060020a03163314620027075760405160e560020a62461bcd0281526004016200020a906200446c565b600c54604051600160a060020a038084169216907f2709918445f306d3e94d280907c62c5d2525ac3192d2e544774c7f181d65af3e90600090a3600c805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b60008181526006602081815260408084206005810154930180548251601f60026000196101006001861615020190931692909204918201859004850281018501909352808352939460609490938593929190830182828015620028175780601f10620027eb5761010080835404028352916020019162002817565b820191906000526020600020905b815481529060010190602001808311620027f957829003601f168201915b505050600088815260066020908152604091829020600781015460089091018054845160026001831615610100026000190190921691909104601f81018590048502820185019095528481529699509097509350909150830182828015620028c35780601f106200289757610100808354040283529160200191620028c3565b820191906000526020600020905b815481529060010190602001808311620028a557829003601f168201915b505050505090509193509193565b600c54600090600160a060020a03163314620029045760405160e560020a62461bcd0281526004016200020a90620044a2565b838214620029295760405160e560020a62461bcd0281526004016200020a9062004412565b5060005b83811015620009b7578282828181106200294357fe5b9050602002013560ff16600d600087878581811015156200296057fe5b90506020020135815260200190815260200160002060006101000a81548160ff021916908360ff16021790555082828281811015156200299c57fe5b9050602002013560ff1660ff168585838181101515620029b857fe5b905060200201357f20f86c53e8884644ce473603799d40ecf47d8c4c1d55384fe8d0eeaf697786eb60405160405180910390a36001016200292d565b60055481565b600954600160a060020a031681565b600a6020526000908152604090205460ff1681565b60008181526006602090815260408083206002908101805483516001821615610100026000190190911692909204601f8101859004850283018501909352828252606094939192909183018282801562002abc5780601f1062002a905761010080835404028352916020019162002abc565b820191906000526020600020905b81548152906001019060200180831162002a9e57829003601f168201915b505050600095865250506006602052604090932060030154929360ff90931692915050565b606080606080606080606080606080600080600080600554935060009250600091508360405190808252806020026020018201604052801562002b2e578160200160208202803883390190505b509d508360405190808252806020026020018201604052801562002b5c578160200160208202803883390190505b509c508360405190808252806020026020018201604052801562002b9557816020015b606081526020019060019003908162002b7f5790505b509b508360405190808252806020026020018201604052801562002bc3578160200160208202803883390190505b509a508360405190808252806020026020018201604052801562002bfc57816020015b606081526020019060019003908162002be65790505b5099508360405190808252806020026020018201604052801562002c3557816020015b606081526020019060019003908162002c1f5790505b5098508360405190808252806020026020018201604052801562002c63578160200160208202803883390190505b5097508360405190808252806020026020018201604052801562002c9c57816020015b606081526020019060019003908162002c865790505b5096508360405190808252806020026020018201604052801562002cd557816020015b606081526020019060019003908162002cbf5790505b5095508360405190808252806020026020018201604052801562002d03578160200160208202803883390190505b5094506000915060009250600090505b600554811015620031c3576000818152600760205260409020548e5190935083908f908490811062002d4157fe5b60209081029091018101919091526000848152600690915260409020600501548d518e908490811062002d7057fe5b60209081029190910181019190915260008481526006808352604091829020018054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529290919083018282801562002e165780601f1062002dea5761010080835404028352916020019162002e16565b820191906000526020600020905b81548152906001019060200180831162002df857829003601f168201915b50505050508c8381518110151562002e2a57fe5b60209081029091018101919091526000848152600690915260409020600701548b518c908490811062002e5957fe5b6020908102919091018101919091526000848152600682526040908190206008018054825160026001831615610100026000190190921691909104601f81018590048502820185019093528281529290919083018282801562002f005780601f1062002ed45761010080835404028352916020019162002f00565b820191906000526020600020905b81548152906001019060200180831162002ee257829003601f168201915b50505050508a8381518110151562002f1457fe5b6020908102909101810191909152600084815260068252604090819020600290810180548351601f6000196101006001851615020190921693909304908101859004850283018501909352828252909290919083018282801562002fbc5780601f1062002f905761010080835404028352916020019162002fbc565b820191906000526020600020905b81548152906001019060200180831162002f9e57829003601f168201915b5050505050898381518110151562002fd057fe5b6020908102909101810191909152600084815260069091526040902060030154885160ff909116908990849081106200300557fe5b60ff909216602092830290910182015260008481526006825260409081902080548251601f600260001961010060018616150201909316929092049182018590048502810185019093528083529192909190830182828015620030ac5780601f106200308057610100808354040283529160200191620030ac565b820191906000526020600020905b8154815290600101906020018083116200308e57829003601f168201915b50505050508783815181101515620030c057fe5b602090810291909101810191909152600084815260068252604090819020600190810180548351600293821615610100026000190190911692909204601f81018590048502830185019093528282529092909190830182828015620031695780601f106200313d5761010080835404028352916020019162003169565b820191906000526020600020905b8154815290600101906020018083116200314b57829003601f168201915b505050505086838151811015156200317d57fe5b60209081029091018101919091526000848152600690915260409020600401548551869084908110620031ac57fe5b602090810290910101526001918201910162002d13565b5050505090919293949596979899565b600854600090600160a060020a03163314620032065760405160e560020a62461bcd0281526004016200020a906200446c565b85858585856200321562003396565b62003225959493929190620043b2565b604051809103906000f08015801562003242573d6000803e3d6000fd5b5090507fbb5f9980e27ec75b79e41ce422e643c6c0116fd9f599776a72f89032f70fe205818787878787604051620032809695949392919062004175565b60405180910390a1505050505050565b60009081526006602052604090206004015490565b600082820183811015620032b857600080fd5b9392505050565b6014015190565b50805460018160011615610100020316600290046000825580601f10620032ee57506200330e565b601f0160209004906000526020600020908101906200330e9190620033a7565b50565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200335457805160ff191683800117855562003384565b8280016001018555821562003384579182015b828111156200338457825182559160200191906001019062003367565b5062003392929150620033a7565b5090565b604051611074806200468d83390190565b6200192591905b80821115620033925760008155600101620033ae565b6000620032b882356200462c565b600080601f83018413620033e557600080fd5b50813567ffffffffffffffff811115620033fe57600080fd5b6020830191508360208202830111156200341757600080fd5b9250929050565b6000601f820183136200343057600080fd5b8135620034476200344182620045d7565b620045af565b915081818352602084019350602081019050838560208402820111156200346d57600080fd5b60005b838110156200349d578162003486888262003669565b845250602092830192919091019060010162003470565b5050505092915050565b6000601f82018313620034b957600080fd5b8135620034ca6200344182620045f9565b91508082526020830160208301858383011115620034e757600080fd5b620034f483828462004643565b50505092915050565b600080601f830184136200351057600080fd5b50813567ffffffffffffffff8111156200352957600080fd5b6020830191508360018202830111156200341757600080fd5b6000601f820183136200355457600080fd5b8151620035656200344182620045f9565b915080825260208301602083018583830111156200358257600080fd5b620034f48382846200464f565b600060a08284031215620035a257600080fd5b620035ae60a0620045af565b9050813567ffffffffffffffff811115620035c857600080fd5b620035d684828501620034a7565b825250602082013567ffffffffffffffff811115620035f457600080fd5b6200360284828501620034a7565b602083015250604082013567ffffffffffffffff8111156200362357600080fd5b6200363184828501620034a7565b6040830152506060620036478482850162003677565b60608301525060806200365d8482850162003669565b60808301525092915050565b6000620032b8823562001925565b6000620032b882356200463d565b6000620032b882516200463d565b600060208284031215620036a657600080fd5b6000620036b48484620033c4565b949350505050565b60008060408385031215620036d057600080fd5b6000620036de8585620033c4565b9250506020620036f185828601620033c4565b9150509250929050565b6000806000606084860312156200371157600080fd5b60006200371f8686620033c4565b93505060206200373286828701620033c4565b9250506040620037458682870162003669565b9150509250925092565b6000806000806000606086880312156200376857600080fd5b6000620037768888620033c4565b955050602086013567ffffffffffffffff8111156200379457600080fd5b620037a288828901620034fd565b9450945050604086013567ffffffffffffffff811115620037c257600080fd5b620037d088828901620034fd565b92509250509295509295909350565b60008060008060408587031215620037f657600080fd5b843567ffffffffffffffff8111156200380e57600080fd5b6200381c87828801620033d2565b9450945050602085013567ffffffffffffffff8111156200383c57600080fd5b6200384a87828801620033d2565b95989497509550505050565b6000806000806000606086880312156200386f57600080fd5b853567ffffffffffffffff8111156200388757600080fd5b6200389588828901620034fd565b9550955050602086013567ffffffffffffffff811115620038b557600080fd5b620038c388828901620034fd565b93509350506040620038d88882890162003677565b9150509295509295909350565b600060208284031215620038f857600080fd5b815167ffffffffffffffff8111156200391057600080fd5b620036b48482850162003542565b6000602082840312156200393157600080fd5b6000620036b4848462003669565b600080600080600060a086880312156200395857600080fd5b600062003966888862003669565b95505060206200397988828901620033c4565b94505060406200398c88828901620033c4565b935050606086013567ffffffffffffffff811115620039aa57600080fd5b620039b8888289016200341e565b925050608086013567ffffffffffffffff811115620039d657600080fd5b620038d8888289016200341e565b60008060008060008060c08789031215620039fe57600080fd5b600062003a0c898962003669565b965050602062003a1f89828a01620033c4565b955050604062003a3289828a01620033c4565b945050606087013567ffffffffffffffff81111562003a5057600080fd5b62003a5e89828a016200341e565b935050608087013567ffffffffffffffff81111562003a7c57600080fd5b62003a8a89828a016200341e565b92505060a087013567ffffffffffffffff81111562003aa857600080fd5b62003ab689828a01620034a7565b9150509295509295509295565b60008060008060008060c0878903121562003add57600080fd5b600062003aeb898962003669565b965050602087013567ffffffffffffffff81111562003b0957600080fd5b62003b1789828a016200358f565b955050604062003b2a89828a0162003669565b945050606087013567ffffffffffffffff81111562003b4857600080fd5b62003b5689828a01620034a7565b935050608062003a8a89828a0162003669565b6000806040838503121562003b7d57600080fd5b600062003b8b858562003669565b9250506020620036f18582860162003669565b60006020828403121562003bb157600080fd5b6000620036b4848462003685565b62003bca816200462c565b82525050565b600062003bdd8262004628565b8084526020840193508360208202850162003bf88562004622565b60005b8481101562003c3557838303885262003c1683835162003d69565b925062003c238262004622565b60209890980197915060010162003bfb565b50909695505050505050565b600062003c4e8262004628565b8084526020840193508360208202850162003c698562004622565b60005b8481101562003c3557838303885262003c8783835162003d69565b925062003c948262004622565b60209890980197915060010162003c6c565b600062003cb38262004628565b80845260208401935062003cc78362004622565b60005b8281101562003cfd5762003ce086835162004007565b62003ceb8262004622565b60209690960195915060010162003cca565b5093949350505050565b600062003d148262004628565b80845260208401935062003d288362004622565b60005b8281101562003cfd5762003d4186835162004012565b62003d4c8262004622565b60209690960195915060010162003d2b565b62003bca8162004638565b600062003d768262004628565b80845262003d8c8160208601602086016200464f565b62003d978162004682565b9093016020019392505050565b600082845260208401935062003dbc83858462004643565b62003dc78362004682565b9093019392505050565b600f81527f6c656e677468206d69736d617463680000000000000000000000000000000000602082015260400190565b600b81527f746f6b656e206578697374000000000000000000000000000000000000000000602082015260400190565b601f81527f696d706c656d656e746174696f6e20636f6e7472616374206e6f742073657400602082015260400190565b601d81527f4e6577206f776e657220697320746865207a65726f2061646472657373000000602082015260400190565b600f81527f746f6b656e206e6f742065786973740000000000000000000000000000000000602082015260400190565b600981527f4e6f74206f776e65720000000000000000000000000000000000000000000000602082015260400190565b601081527f496e76616c6964204e4654207479706500000000000000000000000000000000602082015260400190565b600981527f6e6f742061646d696e0000000000000000000000000000000000000000000000602082015260400190565b600c81527f6e6f74206f70657261746f720000000000000000000000000000000000000000602082015260400190565b805160a08084526000919084019062003f9b828262003d69565b9150506020830151848203602086015262003fb7828262003d69565b9150506040830151848203604086015262003fd3828262003d69565b915050606083015162003fea606086018262004012565b50608083015162003fff608086018262004007565b509392505050565b62003bca8162001925565b62003bca816200463d565b602081016200402d828462003bbf565b92915050565b6040810162004043828562003bbf565b8181036020830152620036b4818462003ca6565b6060810162004067828662003bbf565b81810360208301526200407b818562003ca6565b9050818103604083015262004091818462003ca6565b95945050505050565b60808101620040aa828762003bbf565b8181036020830152620040be818662003ca6565b90508181036040830152620040d4818562003ca6565b90508181036060830152620040ea818462003d69565b9695505050505050565b6060810162004104828662003bbf565b818103602083015262004118818562003ca6565b9050818103604083015262004091818462003d69565b606081016200413e828862003bbf565b81810360208301526200415381868862003da4565b905081810360408301526200416a81848662003da4565b979650505050505050565b6080810162004185828962003bbf565b81810360208301526200419a81878962003da4565b90508181036040830152620041b181858762003da4565b90506200416a606083018462004012565b60808101620041d2828762003bbf565b8181036020830152620041e6818662003d69565b90508181036040830152620041fc818562003d69565b905062004091606083018462004012565b604081016200421d828562003bbf565b620032b8602083018462004007565b610140808252810162004240818d62003ca6565b9050818103602083015262004256818c62003ca6565b905081810360408301526200426c818b62003bd0565b9050818103606083015262004282818a62003ca6565b9050818103608083015262004298818962003bd0565b905081810360a0830152620042ae818862003c41565b905081810360c0830152620042c4818762003d07565b905081810360e0830152620042da818662003bd0565b9050818103610100830152620042f1818562003c41565b905081810361012083015262004308818462003ca6565b9c9b505050505050505050505050565b602081016200402d828462003d5e565b60a080825281016200433b818862003d69565b9050818103602083015262004351818762003d69565b9050818103604083015262004367818662003d69565b905062004378606083018562004012565b620040ea608083018462004007565b604080825281016200439b81868862003da4565b90508181036020830152620040ea81848662003da4565b60608082528101620043c681878962003da4565b90508181036020830152620043dd81858762003da4565b9050620040ea604083018462004012565b6040808252810162004401818562003d69565b9050620032b8602083018462004012565b602080825281016200402d8162003dd1565b602080825281016200402d8162003e01565b602080825281016200402d8162003e31565b602080825281016200402d8162003e61565b602080825281016200402d8162003e91565b602080825281016200402d8162003ec1565b602080825281016200402d8162003ef1565b602080825281016200402d8162003f21565b602080825281016200402d8162003f51565b60a08082528101620044c7818862003f81565b9050620044d8602083018762004007565b8181036040830152620044ec818662003d69565b9050620044fd606083018562004007565b81810360808301526200416a818462003d69565b602081016200402d828462004007565b6060810162004531828662004007565b818103602083015262004545818562003d69565b9050620036b4604083018462004007565b6080810162004566828762004007565b81810360208301526200457a818662003d69565b90506200458b604083018562004007565b8181036060830152620040ea818462003d69565b602081016200402d828462004012565b60405181810167ffffffffffffffff81118282101715620045cf57600080fd5b604052919050565b600067ffffffffffffffff821115620045ef57600080fd5b5060209081020190565b600067ffffffffffffffff8211156200461157600080fd5b506020601f91909101601f19160190565b60200190565b5190565b600160a060020a031690565b151590565b60ff1690565b82818337506000910152565b60005b838110156200466c57818101518382015260200162004652565b838111156200467c576000848401525b50505050565b601f01601f1916905600608060405234801561001057600080fd5b50604051620010743803806200107483398101604090815281516020808401519284015160068054600160a060020a031916331790559184018051909493909301926100629160009190860190610093565b508151610076906001906020850190610093565b506002805460ff191660ff929092169190911790555061012e9050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d457805160ff1916838001178555610101565b82800160010185558215610101579182015b828111156101015782518255916020019190600101906100e6565b5061010d929150610111565b5090565b61012b91905b8082111561010d5760008155600101610117565b90565b610f36806200013e6000396000f3006080604052600436106100fb5763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166306fdde038114610100578063095ea7b31461018a57806318160ddd146101c257806323b872dd146101e9578063313ce5671461021357806340c10f191461023e5780634fb2e45d1461026457806370a0823114610285578063715018a6146102a657806379ba5097146102bb5780638da5cb5b146102d057806395d89b41146103015780639dc29fac14610316578063a6f9dae11461033a578063a9059cbb1461035b578063d4ee1d901461037f578063dd62ed3e14610394578063f4c84d19146103bb575b600080fd5b34801561010c57600080fd5b506101156103e7565b6040805160208082528351818301528351919283929083019185019080838360005b8381101561014f578181015183820152602001610137565b50505050905090810190601f16801561017c5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561019657600080fd5b506101ae600160a060020a0360043516602435610475565b604080519115158252519081900360200190f35b3480156101ce57600080fd5b506101d76105be565b60408051918252519081900360200190f35b3480156101f557600080fd5b506101ae600160a060020a03600435811690602435166044356105c4565b34801561021f57600080fd5b50610228610716565b6040805160ff9092168252519081900360200190f35b34801561024a57600080fd5b50610262600160a060020a036004351660243561071f565b005b34801561027057600080fd5b50610262600160a060020a0360043516610854565b34801561029157600080fd5b506101d7600160a060020a036004351661096d565b3480156102b257600080fd5b50610262610988565b3480156102c757600080fd5b506102626109f7565b3480156102dc57600080fd5b506102e5610a3c565b60408051600160a060020a039092168252519081900360200190f35b34801561030d57600080fd5b50610115610a4b565b34801561032257600080fd5b50610262600160a060020a0360043516602435610aa5565b34801561034657600080fd5b50610262600160a060020a0360043516610bda565b34801561036757600080fd5b506101ae600160a060020a0360043516602435610c59565b34801561038b57600080fd5b506102e5610d55565b3480156103a057600080fd5b506101d7600160a060020a0360043581169060243516610d64565b3480156103c757600080fd5b506102626024600480358281019290820135918135918201910135610d8f565b6000805460408051602060026001851615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561046d5780601f106104425761010080835404028352916020019161046d565b820191906000526020600020905b81548152906001019060200180831161045057829003601f168201915b505050505081565b6000604060443610156104d2576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b8215806105005750336000908152600460209081526040808320600160a060020a0388168452909152902054155b1515610556576040805160e560020a62461bcd02815260206004820152600d60248201527f4e6f74207065726d697474656400000000000000000000000000000000000000604482015290519081900360640190fd5b336000818152600460209081526040808320600160a060020a03891680855290835292819020879055805187815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b60055481565b600060606064361015610621576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b600160a060020a03841660009081526003602052604090205461064a908463ffffffff610dff16565b600160a060020a03808616600090815260036020526040808220939093559087168152205461067f908463ffffffff610e1816565b600160a060020a03861660009081526003602090815260408083209390935560048152828220338352905220546106bc908463ffffffff610e1816565b600160a060020a0380871660008181526004602090815260408083203384528252918290209490945580518781529051928816939192600080516020610eeb833981519152929181900390910190a3506001949350505050565b60025460ff1681565b600654600160a060020a0316331461076f576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b80600081116107c8576040805160e560020a62461bcd02815260206004820152600d60248201527f56616c7565206973206e756c6c00000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a0383166000908152600360205260409020546107f1908363ffffffff610dff16565b600160a060020a03841660009081526003602052604090205560055461081d908363ffffffff610dff16565b600555604080518381529051600160a060020a03851691600091600080516020610eeb8339815191529181900360200190a3505050565b600654600160a060020a031633146108a4576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b600160a060020a0381161515610904576040805160e560020a62461bcd02815260206004820152601d60248201527f4e6577206f776e657220697320746865207a65726f2061646472657373000000604482015290519081900360640190fd5b600654604051600160a060020a038084169216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a36006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600160a060020a031660009081526003602052604090205490565b600654600160a060020a031633146109d8576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b6006805473ffffffffffffffffffffffffffffffffffffffff19169055565b600754600160a060020a0316331415610a3a576007546006805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a039092169190911790555b565b600654600160a060020a031681565b60018054604080516020600284861615610100026000190190941693909304601f8101849004840282018401909252818152929183018282801561046d5780601f106104425761010080835404028352916020019161046d565b600654600160a060020a03163314610af5576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b8060008111610b4e576040805160e560020a62461bcd02815260206004820152600d60248201527f56616c7565206973206e756c6c00000000000000000000000000000000000000604482015290519081900360640190fd5b600160a060020a038316600090815260036020526040902054610b77908363ffffffff610e1816565b600160a060020a038416600090815260036020526040902055600554610ba3908363ffffffff610e1816565b600555604080518381529051600091600160a060020a03861691600080516020610eeb8339815191529181900360200190a3505050565b600654600160a060020a03163314610c2a576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b6007805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a0392909216919091179055565b600060406044361015610cb6576040805160e560020a62461bcd02815260206004820152601960248201527f5061796c6f61642073697a6520697320696e636f727265637400000000000000604482015290519081900360640190fd5b33600090815260036020526040902054610cd6908463ffffffff610e1816565b3360009081526003602052604080822092909255600160a060020a03861681522054610d08908463ffffffff610dff16565b600160a060020a038516600081815260036020908152604091829020939093558051868152905191923392600080516020610eeb8339815191529281900390910190a35060019392505050565b600754600160a060020a031681565b600160a060020a03918216600090815260046020908152604080832093909416825291909152205490565b600654600160a060020a03163314610ddf576040805160e560020a62461bcd0281526020600482015260096024820152600080516020610ecb833981519152604482015290519081900360640190fd5b610deb60008585610e2f565b50610df860018383610e2f565b5050505050565b600082820183811015610e1157600080fd5b9392505050565b60008083831115610e2857600080fd5b5050900390565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10610e705782800160ff19823516178555610e9d565b82800160010185558215610e9d579182015b82811115610e9d578235825591602001919060010190610e82565b50610ea9929150610ead565b5090565b610ec791905b80821115610ea95760008155600101610eb3565b9056004e6f74206f776e65720000000000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa165627a7a723058206d4252b7c832609eb582477b493727af6d5a697d8bd98ecb4fde197c9b29746b0029a265627a7a72305820eb2ddf721fe7086bedc02025ca331dcf40dabd4ca948de05f9dca0890c181b086c6578706572696d656e74616cf50037