Transaction Hash:
Block:
14594794 at Apr-16-2022 06:43:15 AM +UTC
Transaction Fee:
0.004933583513902068 ETH
$11.68
Gas Used:
144,327 Gas / 34.183371884 Gwei
Emitted Events:
61 |
EthVault.0xa866edf1861d39a9973d7892f3869e1bb4b76bc00d216872c1dd2bc547f2da2e( 0xa866edf1861d39a9973d7892f3869e1bb4b76bc00d216872c1dd2bc547f2da2e, 00000000000000000000000000000000000000000000000000000000000000e0, 0000000000000000000000000000000000000000000000000000000000000120, 0000000000000000000000000000000000000000000000000000000000000160, 00000000000000000000000000000000000000000000000000000000000001a0, 00000000000000000000000000000000000000000000000000000000000001e0, 0000000000000000000000000000000000000000000000000000000000000240, 00000000000000000000000000000000000000000000000000000000000002c0, 0000000000000000000000000000000000000000000000000000000000000006, 4b4c4159544e0000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 2c87580fd39808af96b2506ab425c8ba3efc96ed000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 5ee9b02523aadc4c2128bb57ac4f26d106bf8e76000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000014, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000002, 50f408f4b0fb17bf4f5143de4bd95802410d00422f008e9deef06fb101a0f060, 760596312ccccd975754ccac9e0579880b4f83e040409a958d51f8ac2d583885, 0000000000000000000000000000000000000000000000000000000000000003, 000000000000000000000000000000000000000000000000006a798e63eb2000, 0000000000000000000000000000000000000000000000000000000000000012, 00000000000000000000000000000000000000000000000000000000000142c9, 0000000000000000000000000000000000000000000000000000000000000000 )
|
Execution Trace
EthVault.2ac5ab1b( )
0xe62fa6c59ad14b46d4e7791fa817030732953b79.2ac5ab1b( )
-
Null: 0x000...002.1bf68a9d( )
-
Null: 0x000...002.1bf68a9d( )
-
Null: 0x000...002.b5680a55( )
-
Null: 0x000...002.1bf68a9d( )
-
Null: 0x000...002.b5680a55( )
-
Null: 0x000...001.1f2f83eb( )
-
Null: 0x000...001.1f2f83eb( )
-
Null: 0x000...001.1f2f83eb( )
-
Null: 0x000...001.1f2f83eb( )
-
Null: 0x000...001.1f2f83eb( )
-
Null: 0x000...001.1f2f83eb( )
- ETH 0.02997
0x5ee9b02523aadc4c2128bb57ac4f26d106bf8e76.CALL( )
-
{"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"}}