ETH Price: $2,547.70 (+0.33%)

Transaction Decoder

Block:
13991619 at Jan-12-2022 03:54:00 PM +UTC
Transaction Fee:
0.025176006834799067 ETH $64.14
Gas Used:
146,341 Gas / 172.036591487 Gwei

Emitted Events:

40 EthVault.0xa866edf1861d39a9973d7892f3869e1bb4b76bc00d216872c1dd2bc547f2da2e( 0xa866edf1861d39a9973d7892f3869e1bb4b76bc00d216872c1dd2bc547f2da2e, 00000000000000000000000000000000000000000000000000000000000000e0, 0000000000000000000000000000000000000000000000000000000000000120, 0000000000000000000000000000000000000000000000000000000000000160, 00000000000000000000000000000000000000000000000000000000000001a0, 00000000000000000000000000000000000000000000000000000000000001e0, 0000000000000000000000000000000000000000000000000000000000000240, 00000000000000000000000000000000000000000000000000000000000002c0, 0000000000000000000000000000000000000000000000000000000000000006, 4b4c4159544e0000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 0edd98bfcf021468d305fff872b9bb9f6406e1d4000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 0777eff009d0770eff7bafc1c0ba7da9ab0c8a95000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000002, 50f408f4b0fb17bf4f5143de4bd95802410d00422f008e9deef06fb101a0f060, 7625e8dd92c4c4382992618aacc5e59ee25027430563ca8d1f81428fa7b76ec4, 0000000000000000000000000000000000000000000000000000000000000003, 00000000000000000000000000000000000000000000000017e0b6f9c1333500, 0000000000000000000000000000000000000000000000000000000000000012, 00000000000000000000000000000000000000000000000000000000000105e1, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x0777efF0...9aB0C8A95 0.028356923147187467 Eth1.748933164607187467 Eth1.72057624146
0x1Bf68A9d...293cb489a
(Orbit Chain: ETH Vault)
38,715.092744106025615325 Eth38,713.372167864565615325 Eth1.72057624146
(F2Pool Old)
3,036.524587486825848261 Eth3,036.525026509825848261 Eth0.000439023
0xdc5432C5...d2B0Bc522
5.682431327450945056 Eth
Nonce: 37836
5.657255320616145989 Eth
Nonce: 37837
0.025176006834799067

Execution Trace

EthVault.2ac5ab1b( )
  • EthVaultImpl.withdraw( )
    • Null: 0x000...002.1bf68a9d( )
    • Null: 0x000...002.1bf68a9d( )
    • Null: 0x000...002.b5680a55( )
    • Null: 0x000...002.1bf68a9d( )
    • Null: 0x000...002.b5680a55( )
    • Null: 0x000...001.bac14b09( )
    • Null: 0x000...001.bac14b09( )
    • Null: 0x000...001.bac14b09( )
    • Null: 0x000...001.bac14b09( )
    • Null: 0x000...001.bac14b09( )
    • Null: 0x000...001.bac14b09( )
    • ETH 1.72057624146 0x0777eff009d0770eff7bafc1c0ba7da9ab0c8a95.CALL( )
      File 1 of 2: EthVault
      {"EthVault.impl.sol":{"content":"pragma solidity ^0.5.0;\n\nimport \"./SafeMath.sol\";\nimport \"./EthVault.sol\";\n\ninterface IERC20 {\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address who) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    function decimals() external view returns (uint8);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\ncontract TIERC20 {\n    function transfer(address to, uint value) public;\n    function transferFrom(address from, address to, uint value) public;\n\n    function balanceOf(address who) public view returns (uint);\n    function allowance(address owner, address spender) public view returns (uint256);\n\n    function decimals() external view returns (uint8);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n\ncontract EthVaultImpl is EthVault, SafeMath{\n    event Deposit(string fromChain, string toChain, address fromAddr, bytes toAddr, address token, uint8 decimal, uint amount, uint depositId, uint block);\n    event Withdraw(address hubContract, string fromChain, string toChain, bytes fromAddr, bytes toAddr, bytes token, bytes32[] bytes32s, uint[] uints);\n\n    modifier onlyActivated {\n        require(isActivated);\n        _;\n    }\n\n    constructor(address[] memory _owner) public EthVault(_owner, _owner.length, address(0), address(0)) {\n    }\n\n    function getVersion() public pure returns(string memory){\n        return \"1028\";\n    }\n\n    function changeActivate(bool activate) public onlyWallet {\n        isActivated = activate;\n    }\n\n    function setTetherAddress(address tether) public onlyWallet {\n        tetherAddress = tether;\n    }\n\n    function getChainId(string memory _chain) public view returns(bytes32){\n        return sha256(abi.encodePacked(address(this), _chain));\n    }\n\n    function setValidChain(string memory _chain, bool valid) public onlyWallet {\n        isValidChain[getChainId(_chain)] = valid;\n    }\n\n    function deposit(string memory toChain, bytes memory toAddr) payable public onlyActivated {\n        require(isValidChain[getChainId(toChain)]);\n        require(msg.value \u003e 0);\n\n        depositCount = depositCount + 1;\n        emit Deposit(chain, toChain, msg.sender, toAddr, address(0), 18, msg.value, depositCount, block.number);\n    }\n\n    function depositToken(address token, string memory toChain, bytes memory toAddr, uint amount) public onlyActivated{\n        require(isValidChain[getChainId(toChain)]);\n        require(token != address(0));\n        require(amount \u003e 0);\n\n        uint8 decimal = 0;\n        if(token == tetherAddress){\n            TIERC20(token).transferFrom(msg.sender, address(this), amount);\n            decimal = TIERC20(token).decimals();\n        }else{\n            if(!IERC20(token).transferFrom(msg.sender, address(this), amount)) revert();\n            decimal = IERC20(token).decimals();\n        }\n        \n        require(decimal \u003e 0);\n\n        depositCount = depositCount + 1;\n        emit Deposit(chain, toChain, msg.sender, toAddr, token, decimal, amount, depositCount, block.number);\n    }\n\n    // Fix Data Info\n    ///@param bytes32s [0]:govId, [1]:txHash\n    ///@param uints [0]:amount, [1]:decimals\n    function withdraw(\n        address hubContract,\n        string memory fromChain,\n        bytes memory fromAddr,\n        bytes memory toAddr,\n        bytes memory token,\n        bytes32[] memory bytes32s,\n        uint[] memory uints,\n        uint8[] memory v,\n        bytes32[] memory r,\n        bytes32[] memory s\n    ) public onlyActivated {\n        require(bytes32s.length \u003e= 1);\n        require(bytes32s[0] == sha256(abi.encodePacked(hubContract, chain, address(this))));\n        require(uints.length \u003e= 2);\n        require(isValidChain[getChainId(fromChain)]);\n\n        bytes32 whash = sha256(abi.encodePacked(hubContract, fromChain, chain, fromAddr, toAddr, token, bytes32s, uints));\n\n        require(!isUsedWithdrawal[whash]);\n        isUsedWithdrawal[whash] = true;\n\n        uint validatorCount = _validate(whash, v, r, s);\n        require(validatorCount \u003e= required);\n\n        address payable _toAddr = bytesToAddress(toAddr);\n        address tokenAddress = bytesToAddress(token);\n        if(tokenAddress == address(0)){\n            if(!_toAddr.send(uints[0])) revert();\n        }else{\n            if(tokenAddress == tetherAddress){\n                TIERC20(tokenAddress).transfer(_toAddr, uints[0]);\n            }\n            else{\n                if(!IERC20(tokenAddress).transfer(_toAddr, uints[0])) revert();\n            }\n        }\n\n        emit Withdraw(hubContract, fromChain, chain, fromAddr, toAddr, token, bytes32s, uints);\n    }\n\n    function _validate(bytes32 whash, uint8[] memory v, bytes32[] memory r, bytes32[] memory s) private view returns(uint){\n        uint validatorCount = 0;\n        address[] memory vaList = new address[](owners.length);\n\n        uint i=0;\n        uint j=0;\n\n        for(i; i\u003cv.length; i++){\n            address va = ecrecover(whash,v[i],r[i],s[i]);\n            if(isOwner[va]){\n                for(j=0; j\u003cvalidatorCount; j++){\n                    require(vaList[j] != va);\n                }\n\n                vaList[validatorCount] = va;\n                validatorCount += 1;\n            }\n        }\n\n        return validatorCount;\n    }\n\n    function bytesToAddress(bytes memory bys) private pure returns (address payable addr) {\n        assembly {\n            addr := mload(add(bys,20))\n        }\n    }\n\n    function () payable external{\n    }\n}\n"},"EthVault.sol":{"content":"pragma solidity ^0.5.0;\n\nimport \"./MultiSigWallet.sol\";\n\ncontract EthVault is MultiSigWallet{\n    string public constant chain = \"ETH\";\n\n    bool public isActivated = true;\n\n    address payable public implementation;\n    address public tetherAddress;\n\n    uint public depositCount = 0;\n\n    mapping(bytes32 =\u003e bool) public isUsedWithdrawal;\n\n    mapping(bytes32 =\u003e address) public tokenAddr;\n    mapping(address =\u003e bytes32) public tokenSummaries;\n\n    mapping(bytes32 =\u003e bool) public isValidChain;\n\n    constructor(address[] memory _owners, uint _required, address payable _implementation, address _tetherAddress) MultiSigWallet(_owners, _required) public {\n        implementation = _implementation;\n        tetherAddress = _tetherAddress;\n\n        // klaytn valid chain default setting\n        isValidChain[sha256(abi.encodePacked(address(this), \"KLAYTN\"))] = true;\n    }\n\n    function _setImplementation(address payable _newImp) public onlyWallet {\n        require(implementation != _newImp);\n        implementation = _newImp;\n\n    }\n\n    function () payable external {\n        address impl = implementation;\n        require(impl != address(0));\n        assembly {\n            let ptr := mload(0x40)\n            calldatacopy(ptr, 0, calldatasize)\n            let result := delegatecall(gas, impl, ptr, calldatasize, 0, 0)\n            let size := returndatasize\n            returndatacopy(ptr, 0, size)\n\n            switch result\n            case 0 { revert(ptr, size) }\n            default { return(ptr, size) }\n        }\n    }\n}\n"},"MultiSigWallet.sol":{"content":"pragma solidity ^0.5.0;\n\n/// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.\n/// @author Stefan George - \[email protected]\u003e\ncontract MultiSigWallet {\n\n    uint constant public MAX_OWNER_COUNT = 50;\n\n    event Confirmation(address indexed sender, uint indexed transactionId);\n    event Revocation(address indexed sender, uint indexed transactionId);\n    event Submission(uint indexed transactionId);\n    event Execution(uint indexed transactionId);\n    event ExecutionFailure(uint indexed transactionId);\n    event Deposit(address indexed sender, uint value);\n    event OwnerAddition(address indexed owner);\n    event OwnerRemoval(address indexed owner);\n    event RequirementChange(uint required);\n\n    mapping (uint =\u003e Transaction) public transactions;\n    mapping (uint =\u003e mapping (address =\u003e bool)) public confirmations;\n    mapping (address =\u003e bool) public isOwner;\n    address[] public owners;\n    uint public required;\n    uint public transactionCount;\n\n    struct Transaction {\n        address destination;\n        uint value;\n        bytes data;\n        bool executed;\n    }\n\n    modifier onlyWallet() {\n        if (msg.sender != address(this))\n            revert(\"Unauthorized.\");\n        _;\n    }\n\n    modifier ownerDoesNotExist(address owner) {\n        if (isOwner[owner])\n            revert(\"Unauthorized.\");\n        _;\n    }\n\n    modifier ownerExists(address owner) {\n        if (!isOwner[owner])\n            revert(\"Unauthorized.\");\n        _;\n    }\n\n    modifier transactionExists(uint transactionId) {\n        if (transactions[transactionId].destination == address(0))\n            revert(\"Existed transaction id.\");\n        _;\n    }\n\n    modifier confirmed(uint transactionId, address owner) {\n        if (!confirmations[transactionId][owner])\n            revert(\"Not confirmed transaction.\");\n        _;\n    }\n\n    modifier notConfirmed(uint transactionId, address owner) {\n        if (confirmations[transactionId][owner])\n            revert(\"Confirmed transaction.\");\n        _;\n    }\n\n    modifier notExecuted(uint transactionId) {\n        if (transactions[transactionId].executed)\n            revert(\"Executed transaction.\");\n        _;\n    }\n\n    modifier notNull(address _address) {\n        if (_address == address(0))\n            revert(\"Address is null\");\n        _;\n    }\n\n    modifier validRequirement(uint ownerCount, uint _required) {\n        if (   ownerCount \u003e MAX_OWNER_COUNT\n            || _required \u003e ownerCount\n            || _required == 0\n            || ownerCount == 0)\n            revert(\"Invalid requirement\");\n        _;\n    }\n\n    /// @dev Fallback function allows to deposit ether.\n    function()\n        external\n        payable\n    {\n        if (msg.value \u003e 0)\n            emit Deposit(msg.sender, msg.value);\n    }\n\n    /*\n     * Public functions\n     */\n    /// @dev Contract constructor sets initial owners and required number of confirmations.\n    /// @param _owners List of initial owners.\n    /// @param _required Number of required confirmations.\n    constructor(address[] memory _owners, uint _required)\n        public\n        validRequirement(_owners.length, _required)\n    {\n        for (uint i=0; i\u003c_owners.length; i++) {\n            if (isOwner[_owners[i]] || _owners[i] == address(0))\n                revert(\"Invalid owner\");\n            isOwner[_owners[i]] = true;\n        }\n        owners = _owners;\n        required = _required;\n    }\n\n    /// @dev Allows to add a new owner. Transaction has to be sent by wallet.\n    /// @param owner Address of new owner.\n    function addOwner(address owner)\n        public\n        onlyWallet\n        ownerDoesNotExist(owner)\n        notNull(owner)\n        validRequirement(owners.length + 1, required)\n    {\n        isOwner[owner] = true;\n        owners.push(owner);\n        emit OwnerAddition(owner);\n    }\n\n    /// @dev Allows to remove an owner. Transaction has to be sent by wallet.\n    /// @param owner Address of owner.\n    function removeOwner(address owner)\n        public\n        onlyWallet\n        ownerExists(owner)\n    {\n        isOwner[owner] = false;\n        for (uint i=0; i\u003cowners.length - 1; i++)\n            if (owners[i] == owner) {\n                owners[i] = owners[owners.length - 1];\n                break;\n            }\n        owners.length -= 1;\n        if (required \u003e owners.length)\n            changeRequirement(owners.length);\n        emit OwnerRemoval(owner);\n    }\n\n    /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.\n    /// @param owner Address of owner to be replaced.\n    /// @param owner Address of new owner.\n    function replaceOwner(address owner, address newOwner)\n        public\n        onlyWallet\n        ownerExists(owner)\n        ownerDoesNotExist(newOwner)\n    {\n        for (uint i=0; i\u003cowners.length; i++)\n            if (owners[i] == owner) {\n                owners[i] = newOwner;\n                break;\n            }\n        isOwner[owner] = false;\n        isOwner[newOwner] = true;\n        emit OwnerRemoval(owner);\n        emit OwnerAddition(newOwner);\n    }\n\n    /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.\n    /// @param _required Number of required confirmations.\n    function changeRequirement(uint _required)\n        public\n        onlyWallet\n        validRequirement(owners.length, _required)\n    {\n        required = _required;\n        emit RequirementChange(_required);\n    }\n\n    /// @dev Allows an owner to submit and confirm a transaction.\n    /// @param destination Transaction target address.\n    /// @param value Transaction ether value.\n    /// @param data Transaction data payload.\n    /// @return Returns transaction ID.\n    function submitTransaction(address destination, uint value, bytes memory data)\n        public\n        returns (uint transactionId)\n    {\n        transactionId = addTransaction(destination, value, data);\n        confirmTransaction(transactionId);\n    }\n\n    /// @dev Allows an owner to confirm a transaction.\n    /// @param transactionId Transaction ID.\n    function confirmTransaction(uint transactionId)\n        public\n        ownerExists(msg.sender)\n        transactionExists(transactionId)\n        notConfirmed(transactionId, msg.sender)\n    {\n        confirmations[transactionId][msg.sender] = true;\n        emit Confirmation(msg.sender, transactionId);\n        executeTransaction(transactionId);\n    }\n\n    /// @dev Allows an owner to revoke a confirmation for a transaction.\n    /// @param transactionId Transaction ID.\n    function revokeConfirmation(uint transactionId)\n        public\n        ownerExists(msg.sender)\n        confirmed(transactionId, msg.sender)\n        notExecuted(transactionId)\n    {\n        confirmations[transactionId][msg.sender] = false;\n        emit Revocation(msg.sender, transactionId);\n    }\n\n    /// @dev Allows anyone to execute a confirmed transaction.\n    /// @param transactionId Transaction ID.\n    function executeTransaction(uint transactionId)\n        public\n        notExecuted(transactionId)\n    {\n        if (isConfirmed(transactionId)) {\n            Transaction storage txn = transactions[transactionId];\n            txn.executed = true;\n            (bool result, ) = txn.destination.call.value(txn.value)(txn.data);\n            if (result)\n                emit Execution(transactionId);\n            else {\n                emit ExecutionFailure(transactionId);\n                txn.executed = false;\n            }\n        }\n    }\n\n    /// @dev Returns the confirmation status of a transaction.\n    /// @param transactionId Transaction ID.\n    /// @return Confirmation status.\n    function isConfirmed(uint transactionId)\n        public\n        view\n        returns (bool)\n    {\n        uint count = 0;\n        for (uint i=0; i\u003cowners.length; i++) {\n            if (confirmations[transactionId][owners[i]])\n                count += 1;\n            if (count == required)\n                return true;\n        }\n    }\n\n    /*\n     * Internal functions\n     */\n    /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.\n    /// @param destination Transaction target address.\n    /// @param value Transaction ether value.\n    /// @param data Transaction data payload.\n    /// @return Returns transaction ID.\n    function addTransaction(address destination, uint value, bytes memory data)\n        public\n        notNull(destination)\n        returns (uint transactionId)\n    {\n        transactionId = transactionCount;\n        transactions[transactionId] = Transaction({\n            destination: destination,\n            value: value,\n            data: data,\n            executed: false\n        });\n        transactionCount += 1;\n        emit Submission(transactionId);\n    }\n\n    /*\n     * Web3 call functions\n     */\n    /// @dev Returns number of confirmations of a transaction.\n    /// @param transactionId Transaction ID.\n    /// @return Number of confirmations.\n    function getConfirmationCount(uint transactionId)\n        public\n        view\n        returns (uint count)\n    {\n        for (uint i=0; i\u003cowners.length; i++)\n            if (confirmations[transactionId][owners[i]])\n                count += 1;\n    }\n\n    /// @dev Returns total number of transactions after filers are applied.\n    /// @param pending Include pending transactions.\n    /// @param executed Include executed transactions.\n    /// @return Total number of transactions after filters are applied.\n    function getTransactionCount(bool pending, bool executed)\n        public\n        view\n        returns (uint count)\n    {\n        for (uint i=0; i\u003ctransactionCount; i++)\n            if (   pending \u0026\u0026 !transactions[i].executed\n                || executed \u0026\u0026 transactions[i].executed)\n                count += 1;\n    }\n\n    /// @dev Returns list of owners.\n    /// @return List of owner addresses.\n    function getOwners()\n        public\n        view\n        returns (address[] memory)\n    {\n        return owners;\n    }\n\n    /// @dev Returns array with owner addresses, which confirmed transaction.\n    /// @param transactionId Transaction ID.\n    /// @return Returns array of owner addresses.\n    function getConfirmations(uint transactionId)\n        public\n        view\n        returns (address[] memory _confirmations)\n    {\n        address[] memory confirmationsTemp = new address[](owners.length);\n        uint count = 0;\n        uint i;\n        for (i=0; i\u003cowners.length; i++)\n            if (confirmations[transactionId][owners[i]]) {\n                confirmationsTemp[count] = owners[i];\n                count += 1;\n            }\n        _confirmations = new address[](count);\n        for (i=0; i\u003ccount; i++)\n            _confirmations[i] = confirmationsTemp[i];\n    }\n\n    /// @dev Returns list of transaction IDs in defined range.\n    /// @param from Index start position of transaction array.\n    /// @param to Index end position of transaction array.\n    /// @param pending Include pending transactions.\n    /// @param executed Include executed transactions.\n    /// @return Returns array of transaction IDs.\n    function getTransactionIds(uint from, uint to, bool pending, bool executed)\n        public\n        view\n        returns (uint[] memory _transactionIds)\n    {\n        uint[] memory transactionIdsTemp = new uint[](transactionCount);\n        uint count = 0;\n        uint i;\n        for (i=0; i\u003ctransactionCount; i++)\n            if (   pending \u0026\u0026 !transactions[i].executed\n                || executed \u0026\u0026 transactions[i].executed)\n            {\n                transactionIdsTemp[count] = i;\n                count += 1;\n            }\n        _transactionIds = new uint[](to - from);\n        for (i=from; i\u003cto; i++)\n            _transactionIds[i - from] = transactionIdsTemp[i];\n    }\n}\n"},"SafeMath.sol":{"content":"pragma solidity ^0.5.0;\n\ncontract SafeMath {\n    function safeMul(uint a, uint b) internal pure returns(uint) {\n        uint c = a * b;\n        assertion(a == 0 || c / a == b);\n        return c;\n    }\n\n    function safeSub(uint a, uint b) internal pure returns(uint) {\n        assertion(b \u003c= a);\n        return a - b;\n    }\n\n    function safeAdd(uint a, uint b) internal pure returns(uint) {\n        uint c = a + b;\n        assertion(c \u003e= a \u0026\u0026 c \u003e= b);\n        return c;\n    }\n\n    function safeDiv(uint a, uint b) internal pure returns(uint) {\n        require(b != 0, \u0027Divide by zero\u0027);\n\n        return a / b;\n    }\n\n    function safeCeil(uint a, uint b) internal pure returns (uint) {\n        require(b \u003e 0);\n\n        uint v = a / b;\n\n        if(v * b == a) return v;\n\n        return v + 1;  // b cannot be 1, so v \u003c= a / 2\n    }\n\n    function assertion(bool flag) internal pure {\n        if (!flag) revert(\u0027Assertion fail.\u0027);\n    }\n}\n"}}

      File 2 of 2: EthVaultImpl
      pragma solidity 0.5.0;
      
      library SafeMath {
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
      
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
      
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
      
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              if (a == 0) {
                  return 0;
              }
      
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
      
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
      
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b > 0, errorMessage);
              uint256 c = a / b;
      
              return c;
          }
      
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
      
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      library Address {
          function isContract(address account) internal view returns (bool) {
              uint256 size;
              assembly { size := extcodesize(account) }
              return size > 0;
          }
      }
      
      interface IERC20 {
          function totalSupply() external view returns (uint256);
          function balanceOf(address account) external view returns (uint256);
          function transfer(address recipient, uint256 amount) external returns (bool);
          function allowance(address owner, address spender) external view returns (uint256);
          function approve(address spender, uint256 amount) external returns (bool);
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          function decimals() external view returns (uint8);
      }
      
      library SafeERC20 {
          using SafeMath for uint256;
          using Address for address;
      
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
      
          function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
              callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
      
          function safeApprove(IERC20 token, address spender, uint256 value) internal {
              require((value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
      
          function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 newAllowance = token.allowance(address(this), spender).add(value);
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
      
          function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
      
          function callOptionalReturn(IERC20 token, bytes memory data) private {
              require(address(token).isContract(), "SafeERC20: call to non-contract");
      
              (bool success, bytes memory returndata) = address(token).call(data);
              require(success, "SafeERC20: low-level call failed");
      
              if (returndata.length > 0) {
                  require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
              }
          }
      }
      
      interface IERC721 {
          function balanceOf(address owner) external view returns (uint256 balance);
          function ownerOf(uint256 tokenId) external view returns (address owner);
          function safeTransferFrom(address from, address to, uint256 tokenId) external;
          function transferFrom(address from, address to, uint256 tokenId) external;
          function approve(address to, uint256 tokenId) external;
          function getApproved(uint256 tokenId) external view returns (address operator);
          function setApprovalForAll(address operator, bool _approved) external;
          function isApprovedForAll(address owner, address operator) external view returns (bool);
          function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
      }
      
      interface IFarm {
          function deposit(uint amount) external;
          function withdrawAll() external;
          function withdraw(address toAddr, uint amount) external;
      }
      
      interface OrbitBridgeReceiver {
          function onTokenBridgeReceived(address _token, uint256 _value, bytes calldata _data) external returns(uint);
      	function onNFTBridgeReceived(address _token, uint256 _tokenId, bytes calldata _data) external returns(uint);
      }
      
      library LibCallBridgeReceiver {
          function callReceiver(bool isFungible, uint gasLimitForBridgeReceiver, address tokenAddress, uint256 _int, bytes memory data, address toAddr) internal returns (bool){
              bool result;
              bytes memory callbytes;
              bytes memory returnbytes;
              if (isFungible) {
                  callbytes = abi.encodeWithSignature("onTokenBridgeReceived(address,uint256,bytes)", tokenAddress, _int, data);
              } else {
                  callbytes = abi.encodeWithSignature("onNFTBridgeReceived(address,uint256,bytes)", tokenAddress, _int, data);
              }
              if (gasLimitForBridgeReceiver > 0) {
                  (result, returnbytes) = toAddr.call.gas(gasLimitForBridgeReceiver)(callbytes);
              } else {
                  (result, returnbytes) = toAddr.call(callbytes);
              }
      
              if(!result){
                  return false;
              } else {
                  (uint flag) = abi.decode(returnbytes, (uint));
                  return flag > 0;
              }
          }
      }
      
      contract EthVaultStorage {
          /////////////////////////////////////////////////////////////////////////
          // MultiSigWallet.sol
          uint constant public MAX_OWNER_COUNT = 50;
          mapping (uint => Transaction) public transactions;
          mapping (uint => mapping (address => bool)) public confirmations;
          mapping (address => bool) public isOwner;
          address[] public owners;
          uint public required;
          uint public transactionCount;
          struct Transaction {
              address destination;
              uint value;
              bytes data;
              bool executed;
          }
          /////////////////////////////////////////////////////////////////////////
      
          /////////////////////////////////////////////////////////////////////////
          // EthVault.sol
          string public constant chain = "ETH";
          bool public isActivated = true;
          address payable public implementation;
          address public tetherAddress;
          uint public depositCount = 0;
          mapping(bytes32 => bool) public isUsedWithdrawal;
          mapping(bytes32 => address) public tokenAddr;
          mapping(address => bytes32) public tokenSummaries;
          mapping(bytes32 => bool) public isValidChain;
          /////////////////////////////////////////////////////////////////////////
      
          /////////////////////////////////////////////////////////////////////////
          // EthVault.impl.sol
          uint public bridgingFee = 0;
          address payable public feeGovernance;
          mapping(address => bool) public silentTokenList;
          mapping(address => address payable) public farms;
          uint public taxRate; // 0.01% interval
          address public taxReceiver;
          uint public gasLimitForBridgeReceiver;
      
          address public policyAdmin;
          mapping(bytes32 => uint256) public chainFee;
          mapping(bytes32 => uint256) public chainFeeWithData;
      
          mapping(bytes32 => uint256) public chainUintsLength;
          mapping(bytes32 => uint256) public chainAddressLength;
          /////////////////////////////////////////////////////////////////////////
      }
      
      contract EthVaultImpl is EthVaultStorage {
          using SafeERC20 for IERC20;
          using SafeMath for uint;
      
          event Deposit(string toChain, address fromAddr, bytes toAddr, address token, uint8 decimal, uint amount, uint depositId, bytes data);
          event DepositNFT(string toChain, address fromAddr, bytes toAddr, address token, uint tokenId, uint amount, uint depositId, bytes data);
      
          event Withdraw(string fromChain, bytes fromAddr, bytes toAddr, bytes token, bytes32[] bytes32s, uint[] uints, bytes data);
          event WithdrawNFT(string fromChain, bytes fromAddr, bytes toAddr, bytes token, bytes32[] bytes32s, uint[] uints, bytes data);
      
          event BridgeReceiverResult(bool success, bytes fromAddress, address tokenAddress, bytes data);
      
          modifier onlyActivated {
              require(isActivated);
              _;
          }
      
          modifier onlyWallet {
              require(msg.sender == address(this));
              _;
          }
      
          modifier onlyPolicyAdmin {
              require(msg.sender == policyAdmin);
              _;
          }
      
          constructor() public payable { }
      
          function getVersion() public pure returns(string memory){
              return "EthVault20210817A";
          }
      
          function getChainId(string memory _chain) public view returns(bytes32){
              return sha256(abi.encodePacked(address(this), _chain));
          }
      
          function setValidChain(string memory _chain, bool valid, uint fromAddrLen, uint uintsLen) public onlyWallet {
              bytes32 chainId = getChainId(_chain);
              require(chainId != getChainId(chain));
              isValidChain[chainId] = valid;
              if(valid){
                  chainAddressLength[chainId] = fromAddrLen;
                  chainUintsLength[chainId] = uintsLen;
              }
              else{
                  chainAddressLength[chainId] = 0;
                  chainUintsLength[chainId] = 0;
              }
          }
      
          function setTaxParams(uint _taxRate, address _taxReceiver) public onlyWallet {
              require(_taxRate < 10000);
              require(_taxReceiver != address(0));
              taxRate = _taxRate;
              taxReceiver = _taxReceiver;
          }
      
          function setPolicyAdmin(address _policyAdmin) public onlyWallet {
              require(_policyAdmin != address(0));
      
              policyAdmin = _policyAdmin;
          }
      
          function changeActivate(bool activate) public onlyPolicyAdmin {
              isActivated = activate;
          }
      
          function setSilentToken(address token, bool v) public onlyPolicyAdmin {
              require(token != address(0));
      
              silentTokenList[token] = v;
          }
      
          function setFeeGovernance(address payable _feeGovernance) public onlyWallet {
              require(_feeGovernance != address(0));
      
              feeGovernance = _feeGovernance;
          }
      
          function setChainFee(string memory chainSymbol, uint256 _fee, uint256 _feeWithData) public onlyPolicyAdmin {
              bytes32 chainId = getChainId(chainSymbol);
              require(isValidChain[chainId]);
      
              chainFee[chainId] = _fee;
              chainFeeWithData[chainId] = _feeWithData;
          }
      
          function setGasLimitForBridgeReceiver(uint256 _gasLimitForBridgeReceiver) public onlyPolicyAdmin {
              gasLimitForBridgeReceiver = _gasLimitForBridgeReceiver;
          }
      
          function addFarm(address token, address payable proxy) public onlyWallet {
              require(farms[token] == address(0));
      
              uint amount;
              if(token == address(0)){
                  amount = address(this).balance;
              }
              else{
                  amount = IERC20(token).balanceOf(address(this));
              }
      
              _transferToken(token, proxy, amount);
              IFarm(proxy).deposit(amount);
      
              farms[token] = proxy;
          }
      
          function removeFarm(address token, address payable newProxy) public onlyWallet {
              require(farms[token] != address(0));
      
              IFarm(farms[token]).withdrawAll();
      
              if(newProxy != address(0)){
                  uint amount;
                  if(token == address(0)){
                      amount = address(this).balance;
                  }
                  else{
                      amount = IERC20(token).balanceOf(address(this));
                  }
      
                  _transferToken(token, newProxy, amount);
                  IFarm(newProxy).deposit(amount);
              }
      
              farms[token] = newProxy;
          }
      
          function deposit(string memory toChain, bytes memory toAddr) payable public {
              uint256 fee = chainFee[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value > fee);
                  _transferToken(address(0), feeGovernance, fee);
              }
      
              _depositToken(address(0), toChain, toAddr, (msg.value).sub(fee), "");
          }
      
          function deposit(string memory toChain, bytes memory toAddr, bytes memory data) payable public {
              require(data.length != 0);
      
              uint256 fee = chainFeeWithData[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value > fee);
                  _transferToken(address(0), feeGovernance, fee);
              }
      
              _depositToken(address(0), toChain, toAddr, (msg.value).sub(fee), data);
          }
      
          function depositToken(address token, string memory toChain, bytes memory toAddr, uint amount) public payable {
              require(token != address(0));
      
              uint256 fee = chainFee[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value >= fee);
                  _transferToken(address(0), feeGovernance, msg.value);
              }
      
              _depositToken(token, toChain, toAddr, amount, "");
          }
      
          function depositToken(address token, string memory toChain, bytes memory toAddr, uint amount, bytes memory data) public payable {
              require(token != address(0));
              require(data.length != 0);
      
              uint256 fee = chainFeeWithData[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value >= fee);
                  _transferToken(address(0), feeGovernance, msg.value);
              }
      
              _depositToken(token, toChain, toAddr, amount, data);
          }
      
          function _depositToken(address token, string memory toChain, bytes memory toAddr, uint amount, bytes memory data) private onlyActivated {
              require(isValidChain[getChainId(toChain)]);
              require(amount != 0);
              require(!silentTokenList[token]);
      
              uint8 decimal;
              if(token == address(0)){
                  decimal = 18;
              }
              else{
                  IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
                  decimal = IERC20(token).decimals();
              }
              require(decimal > 0);
      
              address payable farm = farms[token];
              if(farm != address(0)){
                  _transferToken(token, farm, amount);
                  IFarm(farm).deposit(amount);
              }
      
              if(taxRate > 0 && taxReceiver != address(0)){
                  uint tax = _payTax(token, amount, decimal);
                  amount = amount.sub(tax);
              }
      
              depositCount = depositCount + 1;
              emit Deposit(toChain, msg.sender, toAddr, token, decimal, amount, depositCount, data);
          }
      
          function depositNFT(address token, string memory toChain, bytes memory toAddr, uint tokenId) public payable {
              uint256 fee = chainFee[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value >= fee);
                  _transferToken(address(0), feeGovernance, msg.value);
              }
      
              _depositNFT(token, toChain, toAddr, tokenId, "");
          }
      
          function depositNFT(address token, string memory toChain, bytes memory toAddr, uint tokenId, bytes memory data) public payable {
              require(data.length != 0);
      
              uint256 fee = chainFeeWithData[getChainId(toChain)];
              if(fee != 0){
                  require(msg.value >= fee);
                  _transferToken(address(0), feeGovernance, msg.value);
              }
      
              _depositNFT(token, toChain, toAddr, tokenId, data);
          }
      
          function _depositNFT(address token, string memory toChain, bytes memory toAddr, uint tokenId, bytes memory data) private onlyActivated {
              require(isValidChain[getChainId(toChain)]);
              require(token != address(0));
              require(IERC721(token).ownerOf(tokenId) == msg.sender);
              require(!silentTokenList[token]);
      
              IERC721(token).transferFrom(msg.sender, address(this), tokenId);
              require(IERC721(token).ownerOf(tokenId) == address(this));
      
              depositCount = depositCount + 1;
              emit DepositNFT(toChain, msg.sender, toAddr, token, tokenId, 1, depositCount, data);
          }
      
          // Fix Data Info
          ///@param bytes32s [0]:govId, [1]:txHash
          ///@param uints [0]:amount, [1]:decimal
          function withdraw(
              address hubContract,
              string memory fromChain,
              bytes memory fromAddr,
              address payable toAddr,
              address token,
              bytes32[] memory bytes32s,
              uint[] memory uints,
              bytes memory data,
              uint8[] memory v,
              bytes32[] memory r,
              bytes32[] memory s
          ) public onlyActivated {
              require(bytes32s.length == 2);
              require(uints.length == chainUintsLength[getChainId(fromChain)]);
              require(uints[1] <= 100);
              require(fromAddr.length == chainAddressLength[getChainId(fromChain)]);
      
              require(bytes32s[0] == sha256(abi.encodePacked(hubContract, chain, address(this))));
              require(isValidChain[getChainId(fromChain)]);
      
              {
              bytes32 whash = sha256(abi.encodePacked(hubContract, fromChain, chain, fromAddr, toAddr, token, bytes32s, uints, data));
      
              require(!isUsedWithdrawal[whash]);
              isUsedWithdrawal[whash] = true;
      
              uint validatorCount = _validate(whash, v, r, s);
              require(validatorCount >= required);
              }
      
      
              if(farms[token] != address(0)){
                  IFarm(farms[token]).withdraw(toAddr, uints[0]);
              }
              else{
                  _transferToken(token, toAddr, uints[0]);
              }
      
              if(isContract(toAddr) && data.length != 0){
                  bool result = LibCallBridgeReceiver.callReceiver(true, gasLimitForBridgeReceiver, token, uints[0], data, toAddr);
                  emit BridgeReceiverResult(result, fromAddr, token, data);
              }
      
              emit Withdraw(fromChain, fromAddr, abi.encodePacked(toAddr), abi.encodePacked(token), bytes32s, uints, data);
          }
      
          // Fix Data Info
          ///@param bytes32s [0]:govId, [1]:txHash
          ///@param uints [0]:amount, [1]:tokenId
          function withdrawNFT(
              address hubContract,
              string memory fromChain,
              bytes memory fromAddr,
              address payable toAddr,
              address token,
              bytes32[] memory bytes32s,
              uint[] memory uints,
              bytes memory data,
              uint8[] memory v,
              bytes32[] memory r,
              bytes32[] memory s
          ) public onlyActivated {
              require(bytes32s.length == 2);
              require(uints.length == chainUintsLength[getChainId(fromChain)]);
              require(fromAddr.length == chainAddressLength[getChainId(fromChain)]);
      
              require(bytes32s[0] == sha256(abi.encodePacked(hubContract, chain, address(this))));
              require(isValidChain[getChainId(fromChain)]);
      
              {
              bytes32 whash = sha256(abi.encodePacked("NFT", hubContract, fromChain, chain, fromAddr, toAddr, token, bytes32s, uints, data));
      
              require(!isUsedWithdrawal[whash]);
              isUsedWithdrawal[whash] = true;
      
              uint validatorCount = _validate(whash, v, r, s);
              require(validatorCount >= required);
              }
      
              require(IERC721(token).ownerOf(uints[1]) == address(this));
              IERC721(token).transferFrom(address(this), toAddr, uints[1]);
              require(IERC721(token).ownerOf(uints[1]) == toAddr);
      
              if(isContract(toAddr) && data.length != 0){
                  bool result = LibCallBridgeReceiver.callReceiver(false, gasLimitForBridgeReceiver, token, uints[1], data, toAddr);
                  emit BridgeReceiverResult(result, fromAddr, token, data);
              }
      
              emit WithdrawNFT(fromChain, fromAddr, abi.encodePacked(toAddr), abi.encodePacked(token), bytes32s, uints, data);
          }
      
          function _validate(bytes32 whash, uint8[] memory v, bytes32[] memory r, bytes32[] memory s) private view returns(uint){
              uint validatorCount = 0;
              address[] memory vaList = new address[](owners.length);
      
              uint i=0;
              uint j=0;
      
              for(i; i<v.length; i++){
                  address va = ecrecover(whash,v[i],r[i],s[i]);
                  if(isOwner[va]){
                      for(j=0; j<validatorCount; j++){
                          require(vaList[j] != va);
                      }
      
                      vaList[validatorCount] = va;
                      validatorCount += 1;
                  }
              }
      
              return validatorCount;
          }
      
          function _payTax(address token, uint amount, uint8 decimal) private returns (uint tax) {
              tax = amount.mul(taxRate).div(10000);
              if(tax > 0){
                  depositCount = depositCount + 1;
                  emit Deposit("ORBIT", msg.sender, abi.encodePacked(taxReceiver), token, decimal, tax, depositCount, "");
              }
          }
      
          function _transferToken(address token, address payable destination, uint amount) private {
              if(token == address(0)){
                  (bool transfered,) = destination.call.value(amount)("");
                  require(transfered);
              }
              else{
                  IERC20(token).safeTransfer(destination, amount);
              }
          }
      
          function isContract(address _addr) private view returns (bool){
              uint32 size;
              assembly {
                  size := extcodesize(_addr)
              }
              return (size > 0);
          }
      
          function bytesToAddress(bytes memory bys) public pure returns (address payable addr) {
              assembly {
                  addr := mload(add(bys,20))
              }
          }
      
          function () payable external{
          }
      }