Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
0x93a9c8b006f9cafda6fc9016dd440dad5c93056a42798e1417239efb8d631af1 | Start Exit With ... | (pending) | 9 mins ago | IN | 0 ETH | (Pending) | |||
0x818403b49febda60cc3379be5cf0b50efc7e369809e13b5ae2a8e01afcbc508b | Start Exit With ... | (pending) | 39 mins ago | IN | 0 ETH | (Pending) | |||
Start Exit With ... | 21272776 | 13 hrs ago | IN | 0 ETH | 0.00897766 | ||||
Start Exit With ... | 21272484 | 14 hrs ago | IN | 0 ETH | 0.0068578 | ||||
Start Exit With ... | 21272395 | 14 hrs ago | IN | 0 ETH | 0.00425843 | ||||
Start Exit With ... | 21272354 | 14 hrs ago | IN | 0 ETH | 0.00420456 | ||||
Start Exit With ... | 21270284 | 21 hrs ago | IN | 0 ETH | 0.00410341 | ||||
Start Exit With ... | 21269699 | 23 hrs ago | IN | 0 ETH | 0.00364976 | ||||
Start Exit With ... | 21266195 | 35 hrs ago | IN | 0 ETH | 0.00929781 | ||||
Start Exit With ... | 21263105 | 45 hrs ago | IN | 0 ETH | 0.00324085 | ||||
Start Exit With ... | 21261103 | 2 days ago | IN | 0 ETH | 0.00558361 | ||||
Start Exit With ... | 21256772 | 2 days ago | IN | 0 ETH | 0.00379634 | ||||
Start Exit With ... | 21254038 | 3 days ago | IN | 0 ETH | 0.00601547 | ||||
Start Exit With ... | 21252120 | 3 days ago | IN | 0 ETH | 0.01043208 | ||||
Start Exit With ... | 21250661 | 3 days ago | IN | 0 ETH | 0.00693861 | ||||
Start Exit With ... | 21246040 | 4 days ago | IN | 0 ETH | 0.01005152 | ||||
Start Exit With ... | 21245366 | 4 days ago | IN | 0 ETH | 0.0065002 | ||||
Start Exit With ... | 21245057 | 4 days ago | IN | 0 ETH | 0.00646701 | ||||
Start Exit With ... | 21244452 | 4 days ago | IN | 0 ETH | 0.00836085 | ||||
Start Exit With ... | 21243138 | 4 days ago | IN | 0 ETH | 0.00586779 | ||||
Start Exit With ... | 21243036 | 4 days ago | IN | 0 ETH | 0.00465532 | ||||
Start Exit With ... | 21240487 | 5 days ago | IN | 0 ETH | 0.00487314 | ||||
Start Exit With ... | 21239048 | 5 days ago | IN | 0 ETH | 0.0073379 | ||||
Start Exit With ... | 21231912 | 6 days ago | IN | 0 ETH | 0.00733781 | ||||
Start Exit With ... | 21228248 | 6 days ago | IN | 0 ETH | 0.00550478 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Contract Name:
ERC20PredicateBurnOnly
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2023-08-07 */ pragma solidity ^0.5.2; /** * @title SafeMath * @dev Unsigned math operations with safety checks that revert on error */ library SafeMath { /** * @dev Multiplies two unsigned integers, reverts on overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b); return c; } /** * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { require(b <= a); uint256 c = a - b; return c; } /** * @dev Adds two unsigned integers, reverts on overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a); return c; } /** * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), * reverts when dividing by zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { require(b != 0); return a % b; } } library BytesLib { function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) { bytes memory tempBytes; assembly { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // Store the length of the first bytes array at the beginning of // the memory for tempBytes. let length := mload(_preBytes) mstore(tempBytes, length) // Maintain a memory counter for the current write location in the // temp bytes array by adding the 32 bytes for the array length to // the starting location. let mc := add(tempBytes, 0x20) // Stop copying when the memory counter reaches the length of the // first bytes array. let end := add(mc, length) for { // Initialize a copy counter to the start of the _preBytes data, // 32 bytes into its memory. let cc := add(_preBytes, 0x20) } lt(mc, end) { // Increase both counters by 32 bytes each iteration. mc := add(mc, 0x20) cc := add(cc, 0x20) } { // Write the _preBytes data into the tempBytes memory 32 bytes // at a time. mstore(mc, mload(cc)) } // Add the length of _postBytes to the current length of tempBytes // and store it as the new length in the first 32 bytes of the // tempBytes memory. length := mload(_postBytes) mstore(tempBytes, add(length, mload(tempBytes))) // Move the memory counter back from a multiple of 0x20 to the // actual end of the _preBytes data. mc := end // Stop copying when the memory counter reaches the new combined // length of the arrays. end := add(mc, length) for { let cc := add(_postBytes, 0x20) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } // Update the free-memory pointer by padding our last write location // to 32 bytes: add 31 bytes to the end of tempBytes to move to the // next 32 byte block, then round down to the nearest multiple of // 32. If the sum of the length of the two arrays is zero then add // one before rounding down to leave a blank 32 bytes (the length block with 0). mstore( 0x40, and( add(add(end, iszero(add(length, mload(_preBytes)))), 31), not(31) // Round down to the nearest 32 bytes. ) ) } return tempBytes; } function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) { require(_bytes.length >= (_start + _length)); bytes memory tempBytes; assembly { switch iszero(_length) case 0 { // Get a location of some free memory and store it in tempBytes as // Solidity does for memory variables. tempBytes := mload(0x40) // The first word of the slice result is potentially a partial // word read from the original array. To read it, we calculate // the length of that partial word and start copying that many // bytes into the array. The first word we copy will start with // data we don't care about, but the last `lengthmod` bytes will // land at the beginning of the contents of the new array. When // we're done copying, we overwrite the full first word with // the actual length of the slice. let lengthmod := and(_length, 31) // The multiplication in the next line is necessary // because when slicing multiples of 32 bytes (lengthmod == 0) // the following copy loop was copying the origin's length // and then ending prematurely not copying everything it should. let mc := add( add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)) ) let end := add(mc, _length) for { // The multiplication in the next line has the same exact purpose // as the one above. let cc := add( add( add(_bytes, lengthmod), mul(0x20, iszero(lengthmod)) ), _start ) } lt(mc, end) { mc := add(mc, 0x20) cc := add(cc, 0x20) } { mstore(mc, mload(cc)) } mstore(tempBytes, _length) //update free-memory pointer //allocating the array padded to 32 bytes like the compiler does now mstore(0x40, and(add(mc, 31), not(31))) } //if we want a zero-length slice let's just return a zero-length array default { tempBytes := mload(0x40) mstore(0x40, add(tempBytes, 0x20)) } } return tempBytes; } // Pad a bytes array to 32 bytes function leftPad(bytes memory _bytes) internal pure returns (bytes memory) { // may underflow if bytes.length < 32. Hence using SafeMath.sub bytes memory newBytes = new bytes(SafeMath.sub(32, _bytes.length)); return concat(newBytes, _bytes); } function toBytes32(bytes memory b) internal pure returns (bytes32) { require(b.length >= 32, "Bytes array should atleast be 32 bytes"); bytes32 out; for (uint256 i = 0; i < 32; i++) { out |= bytes32(b[i] & 0xFF) >> (i * 8); } return out; } function toBytes4(bytes memory b) internal pure returns (bytes4 result) { assembly { result := mload(add(b, 32)) } } function fromBytes32(bytes32 x) internal pure returns (bytes memory) { bytes memory b = new bytes(32); for (uint256 i = 0; i < 32; i++) { b[i] = bytes1(uint8(uint256(x) / (2**(8 * (31 - i))))); } return b; } function fromUint(uint256 _num) internal pure returns (bytes memory _ret) { _ret = new bytes(32); assembly { mstore(add(_ret, 32), _num) } } function toUint(bytes memory _bytes, uint256 _start) internal pure returns (uint256) { require(_bytes.length >= (_start + 32)); uint256 tempUint; assembly { tempUint := mload(add(add(_bytes, 0x20), _start)) } return tempUint; } function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) { require(_bytes.length >= (_start + 20)); address tempAddress; assembly { tempAddress := div( mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000 ) } return tempAddress; } } library Common { function getV(bytes memory v, uint16 chainId) public pure returns (uint8) { if (chainId > 0) { return uint8( BytesLib.toUint(BytesLib.leftPad(v), 0) - (chainId * 2) - 8 ); } else { return uint8(BytesLib.toUint(BytesLib.leftPad(v), 0)); } } //assemble the given address bytecode. If bytecode exists then the _addr is a contract. function isContract(address _addr) public view returns (bool) { uint256 length; assembly { //retrieve the size of the code on target address, this needs assembly length := extcodesize(_addr) } return (length > 0); } // convert bytes to uint8 function toUint8(bytes memory _arg) public pure returns (uint8) { return uint8(_arg[0]); } function toUint16(bytes memory _arg) public pure returns (uint16) { return (uint16(uint8(_arg[0])) << 8) | uint16(uint8(_arg[1])); } } /** * @title Math * @dev Assorted math operations */ library Math { /** * @dev Returns the largest of two numbers. */ function max(uint256 a, uint256 b) internal pure returns (uint256) { return a >= b ? a : b; } /** * @dev Returns the smallest of two numbers. */ function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; } /** * @dev Calculates the average of two numbers. Since these are integers, * averages of an even and odd number cannot be represented, and will be * rounded down. */ function average(uint256 a, uint256 b) internal pure returns (uint256) { // (a + b) / 2 can overflow, so we distribute return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2); } } // Library for RLP encoding a list of bytes arrays. // Modeled after ethereumjs/rlp (https://github.com/ethereumjs/rlp) // [Very] modified version of Sam Mayo's library. library RLPEncode { // Encode an item (bytes memory) function encodeItem(bytes memory self) internal pure returns (bytes memory) { bytes memory encoded; if (self.length == 1 && uint8(self[0] & 0xFF) < 0x80) { encoded = new bytes(1); encoded = self; } else { encoded = BytesLib.concat(encodeLength(self.length, 128), self); } return encoded; } // Encode a list of items function encodeList(bytes[] memory self) internal pure returns (bytes memory) { bytes memory encoded; for (uint256 i = 0; i < self.length; i++) { encoded = BytesLib.concat(encoded, encodeItem(self[i])); } return BytesLib.concat(encodeLength(encoded.length, 192), encoded); } // Hack to encode nested lists. If you have a list as an item passed here, included // pass = true in that index. E.g. // [item, list, item] --> pass = [false, true, false] // function encodeListWithPasses(bytes[] memory self, bool[] pass) internal pure returns (bytes memory) { // bytes memory encoded; // for (uint i=0; i < self.length; i++) { // if (pass[i] == true) { // encoded = BytesLib.concat(encoded, self[i]); // } else { // encoded = BytesLib.concat(encoded, encodeItem(self[i])); // } // } // return BytesLib.concat(encodeLength(encoded.length, 192), encoded); // } // Generate the prefix for an item or the entire list based on RLP spec function encodeLength(uint256 L, uint256 offset) internal pure returns (bytes memory) { if (L < 56) { bytes memory prefix = new bytes(1); prefix[0] = bytes1(uint8(L + offset)); return prefix; } else { // lenLen is the length of the hex representation of the data length uint256 lenLen; uint256 i = 0x1; while (L / i != 0) { lenLen++; i *= 0x100; } bytes memory prefix0 = getLengthBytes(offset + 55 + lenLen); bytes memory prefix1 = getLengthBytes(L); return BytesLib.concat(prefix0, prefix1); } } function getLengthBytes(uint256 x) internal pure returns (bytes memory b) { // Figure out if we need 1 or two bytes to express the length. // 1 byte gets us to max 255 // 2 bytes gets us to max 65535 (no payloads will be larger than this) uint256 nBytes = 1; if (x > 255) { nBytes = 2; } b = new bytes(nBytes); // Encode the length and return it for (uint256 i = 0; i < nBytes; i++) { b[i] = bytes1(uint8(x / (2**(8 * (nBytes - 1 - i))))); } } } /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ library RLPReader { uint8 constant STRING_SHORT_START = 0x80; uint8 constant STRING_LONG_START = 0xb8; uint8 constant LIST_SHORT_START = 0xc0; uint8 constant LIST_LONG_START = 0xf8; uint8 constant WORD_SIZE = 32; struct RLPItem { uint len; uint memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint nextPtr; // Position of the next item in the list. } /* * @dev Returns the next element in the iteration. Reverts if it has not next element. * @param self The iterator. * @return The next element in the iteration. */ function next(Iterator memory self) internal pure returns (RLPItem memory) { require(hasNext(self)); uint ptr = self.nextPtr; uint itemLength = _itemLength(ptr); self.nextPtr = ptr + itemLength; return RLPItem(itemLength, ptr); } /* * @dev Returns true if the iteration has more elements. * @param self The iterator. * @return true if the iteration has more elements. */ function hasNext(Iterator memory self) internal pure returns (bool) { RLPItem memory item = self.item; return self.nextPtr < item.memPtr + item.len; } /* * @param item RLP encoded bytes */ function toRlpItem(bytes memory item) internal pure returns (RLPItem memory) { uint memPtr; assembly { memPtr := add(item, 0x20) } return RLPItem(item.length, memPtr); } /* * @dev Create an iterator. Reverts if item is not a list. * @param self The RLP item. * @return An 'Iterator' over the item. */ function iterator(RLPItem memory self) internal pure returns (Iterator memory) { require(isList(self)); uint ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param item RLP encoded bytes */ function rlpLen(RLPItem memory item) internal pure returns (uint) { return item.len; } /* * @param item RLP encoded bytes */ function payloadLen(RLPItem memory item) internal pure returns (uint) { return item.len - _payloadOffset(item.memPtr); } /* * @param item RLP encoded list in bytes */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint memPtr = item.memPtr + _payloadOffset(item.memPtr); uint dataLen; for (uint i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } return result; } // @return indicator whether encoded payload is a list. negate this function call for isData. function isList(RLPItem memory item) internal pure returns (bool) { if (item.len == 0) return false; uint8 byte0; uint memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /** RLPItem conversions into data types **/ // @returns raw rlp encoding in bytes function toRlpBytes(RLPItem memory item) internal pure returns (bytes memory) { bytes memory result = new bytes(item.len); if (result.length == 0) return result; uint ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint result; uint memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } return result == 0 ? false : true; } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(toUint(item)); } function toUint(RLPItem memory item) internal pure returns (uint) { require(item.len > 0 && item.len <= 33); uint offset = _payloadOffset(item.memPtr); uint len = item.len - offset; uint result; uint memPtr = item.memPtr + offset; assembly { result := mload(memPtr) // shfit to the correct location if neccesary if lt(len, 32) { result := div(result, exp(256, sub(32, len))) } } return result; } // enforces 32 byte length function toUintStrict(RLPItem memory item) internal pure returns (uint) { // one byte prefix require(item.len == 33); uint result; uint memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); uint offset = _payloadOffset(item.memPtr); uint len = item.len - offset; // data length bytes memory result = new bytes(len); uint destPtr; assembly { destPtr := add(0x20, result) } copy(item.memPtr + offset, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint) { if (item.len == 0) return 0; uint count = 0; uint currPtr = item.memPtr + _payloadOffset(item.memPtr); uint endPtr = item.memPtr + item.len; while (currPtr < endPtr) { currPtr = currPtr + _itemLength(currPtr); // skip over an item count++; } return count; } // @return entire rlp item byte length function _itemLength(uint memPtr) private pure returns (uint) { uint itemLen; uint byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) itemLen = 1; else if (byte0 < STRING_LONG_START) itemLen = byte0 - STRING_SHORT_START + 1; else if (byte0 < LIST_SHORT_START) { assembly { let byteLen := sub(byte0, 0xb7) // # of bytes the actual length is memPtr := add(memPtr, 1) // skip over the first byte /* 32 byte word size */ let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to get the len itemLen := add(dataLen, add(byteLen, 1)) } } else if (byte0 < LIST_LONG_START) { itemLen = byte0 - LIST_SHORT_START + 1; } else { assembly { let byteLen := sub(byte0, 0xf7) memPtr := add(memPtr, 1) let dataLen := div(mload(memPtr), exp(256, sub(32, byteLen))) // right shifting to the correct length itemLen := add(dataLen, add(byteLen, 1)) } } return itemLen; } // @return number of bytes until the data function _payloadOffset(uint memPtr) private pure returns (uint) { uint byte0; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < STRING_SHORT_START) return 0; else if (byte0 < STRING_LONG_START || (byte0 >= LIST_SHORT_START && byte0 < LIST_LONG_START)) return 1; else if (byte0 < LIST_SHORT_START) // being explicit return byte0 - (STRING_LONG_START - 1) + 1; else return byte0 - (LIST_LONG_START - 1) + 1; } /* * @param src Pointer to source * @param dest Pointer to destination * @param len Amount of memory to copy from the source */ function copy(uint src, uint dest, uint len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } // left over bytes. Mask is used to remove unwanted bytes from the word uint mask = 256 ** (WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } } library ExitPayloadReader { using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; uint8 constant WORD_SIZE = 32; struct ExitPayload { RLPReader.RLPItem[] data; } struct Receipt { RLPReader.RLPItem[] data; bytes raw; uint256 logIndex; } struct Log { RLPReader.RLPItem data; RLPReader.RLPItem[] list; } struct LogTopics { RLPReader.RLPItem[] data; } function toExitPayload(bytes memory data) internal pure returns (ExitPayload memory) { RLPReader.RLPItem[] memory payloadData = data .toRlpItem() .toList(); return ExitPayload(payloadData); } function copy(uint src, uint dest, uint len) private pure { if (len == 0) return; // copy as many word sizes as possible for (; len >= WORD_SIZE; len -= WORD_SIZE) { assembly { mstore(dest, mload(src)) } src += WORD_SIZE; dest += WORD_SIZE; } // left over bytes. Mask is used to remove unwanted bytes from the word uint mask = 256 ** (WORD_SIZE - len) - 1; assembly { let srcpart := and(mload(src), not(mask)) // zero out src let destpart := and(mload(dest), mask) // retrieve the bytes mstore(dest, or(destpart, srcpart)) } } function getHeaderNumber(ExitPayload memory payload) internal pure returns(uint256) { return payload.data[0].toUint(); } function getBlockProof(ExitPayload memory payload) internal pure returns(bytes memory) { return payload.data[1].toBytes(); } function getBlockNumber(ExitPayload memory payload) internal pure returns(uint256) { return payload.data[2].toUint(); } function getBlockTime(ExitPayload memory payload) internal pure returns(uint256) { return payload.data[3].toUint(); } function getTxRoot(ExitPayload memory payload) internal pure returns(bytes32) { return bytes32(payload.data[4].toUint()); } function getReceiptRoot(ExitPayload memory payload) internal pure returns(bytes32) { return bytes32(payload.data[5].toUint()); } function getReceipt(ExitPayload memory payload) internal pure returns(Receipt memory receipt) { receipt.raw = payload.data[6].toBytes(); RLPReader.RLPItem memory receiptItem = receipt.raw.toRlpItem(); if (receiptItem.isList()) { // legacy tx receipt.data = receiptItem.toList(); } else { // pop first byte before parsting receipt bytes memory typedBytes = receipt.raw; bytes memory result = new bytes(typedBytes.length - 1); uint256 srcPtr; uint256 destPtr; assembly { srcPtr := add(33, typedBytes) destPtr := add(0x20, result) } copy(srcPtr, destPtr, result.length); receipt.data = result.toRlpItem().toList(); } receipt.logIndex = getReceiptLogIndex(payload); return receipt; } function getReceiptProof(ExitPayload memory payload) internal pure returns(bytes memory) { return payload.data[7].toBytes(); } function getBranchMaskAsBytes(ExitPayload memory payload) internal pure returns(bytes memory) { return payload.data[8].toBytes(); } function getBranchMaskAsUint(ExitPayload memory payload) internal pure returns(uint256) { return payload.data[8].toUint(); } function getReceiptLogIndex(ExitPayload memory payload) internal pure returns(uint256) { return payload.data[9].toUint(); } function getTx(ExitPayload memory payload) internal pure returns(bytes memory) { return payload.data[10].toBytes(); } function getTxProof(ExitPayload memory payload) internal pure returns(bytes memory) { return payload.data[11].toBytes(); } // Receipt methods function toBytes(Receipt memory receipt) internal pure returns(bytes memory) { return receipt.raw; } function getLog(Receipt memory receipt) internal pure returns(Log memory) { RLPReader.RLPItem memory logData = receipt.data[3].toList()[receipt.logIndex]; return Log(logData, logData.toList()); } // Log methods function getEmitter(Log memory log) internal pure returns(address) { return RLPReader.toAddress(log.list[0]); } function getTopics(Log memory log) internal pure returns(LogTopics memory) { return LogTopics(log.list[1].toList()); } function getData(Log memory log) internal pure returns(bytes memory) { return log.list[2].toBytes(); } function toRlpBytes(Log memory log) internal pure returns(bytes memory) { return log.data.toRlpBytes(); } // LogTopics methods function getField(LogTopics memory topics, uint256 index) internal pure returns(RLPReader.RLPItem memory) { return topics.data[index]; } } contract IWithdrawManager { function createExitQueue(address token) external; function verifyInclusion( bytes calldata data, uint8 offset, bool verifyTxInclusion ) external view returns (uint256 age); function addExitToQueue( address exitor, address childToken, address rootToken, uint256 exitAmountOrTokenId, bytes32 txHash, bool isRegularExit, uint256 priority ) external; function addInput( uint256 exitId, uint256 age, address utxoOwner, address token ) external; function challengeExit( uint256 exitId, uint256 inputId, bytes calldata challengeData, address adjudicatorPredicate ) external; } interface IDepositManager { function depositEther() external payable; function transferAssets( address _token, address _user, uint256 _amountOrNFTId ) external; function depositERC20(address _token, uint256 _amount) external; function depositERC721(address _token, uint256 _tokenId) external; } /** * @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 { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev The Ownable constructor sets the original `owner` of the contract to the sender * account. */ constructor () internal { _owner = msg.sender; emit OwnershipTransferred(address(0), _owner); } /** * @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. * It will not be possible to call the functions with the `onlyOwner` * modifier anymore. * @notice Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public onlyOwner { emit OwnershipTransferred(_owner, address(0)); _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; } } contract ProxyStorage is Ownable { address internal proxyTo; } interface IGovernance { function update(address target, bytes calldata data) external; } contract Governable { IGovernance public governance; constructor(address _governance) public { governance = IGovernance(_governance); } modifier onlyGovernance() { _assertGovernance(); _; } function _assertGovernance() private view { require( msg.sender == address(governance), "Only governance contract is authorized" ); } } contract Registry is Governable { // @todo hardcode constants bytes32 private constant WETH_TOKEN = keccak256("wethToken"); bytes32 private constant DEPOSIT_MANAGER = keccak256("depositManager"); bytes32 private constant STAKE_MANAGER = keccak256("stakeManager"); bytes32 private constant VALIDATOR_SHARE = keccak256("validatorShare"); bytes32 private constant WITHDRAW_MANAGER = keccak256("withdrawManager"); bytes32 private constant CHILD_CHAIN = keccak256("childChain"); bytes32 private constant STATE_SENDER = keccak256("stateSender"); bytes32 private constant SLASHING_MANAGER = keccak256("slashingManager"); address public erc20Predicate; address public erc721Predicate; mapping(bytes32 => address) public contractMap; mapping(address => address) public rootToChildToken; mapping(address => address) public childToRootToken; mapping(address => bool) public proofValidatorContracts; mapping(address => bool) public isERC721; enum Type {Invalid, ERC20, ERC721, Custom} struct Predicate { Type _type; } mapping(address => Predicate) public predicates; event TokenMapped(address indexed rootToken, address indexed childToken); event ProofValidatorAdded(address indexed validator, address indexed from); event ProofValidatorRemoved(address indexed validator, address indexed from); event PredicateAdded(address indexed predicate, address indexed from); event PredicateRemoved(address indexed predicate, address indexed from); event ContractMapUpdated(bytes32 indexed key, address indexed previousContract, address indexed newContract); constructor(address _governance) public Governable(_governance) {} function updateContractMap(bytes32 _key, address _address) external onlyGovernance { emit ContractMapUpdated(_key, contractMap[_key], _address); contractMap[_key] = _address; } /** * @dev Map root token to child token * @param _rootToken Token address on the root chain * @param _childToken Token address on the child chain * @param _isERC721 Is the token being mapped ERC721 */ function mapToken( address _rootToken, address _childToken, bool _isERC721 ) external onlyGovernance { require(_rootToken != address(0x0) && _childToken != address(0x0), "INVALID_TOKEN_ADDRESS"); rootToChildToken[_rootToken] = _childToken; childToRootToken[_childToken] = _rootToken; isERC721[_rootToken] = _isERC721; IWithdrawManager(contractMap[WITHDRAW_MANAGER]).createExitQueue(_rootToken); emit TokenMapped(_rootToken, _childToken); } function addErc20Predicate(address predicate) public onlyGovernance { require(predicate != address(0x0), "Can not add null address as predicate"); erc20Predicate = predicate; addPredicate(predicate, Type.ERC20); } function addErc721Predicate(address predicate) public onlyGovernance { erc721Predicate = predicate; addPredicate(predicate, Type.ERC721); } function addPredicate(address predicate, Type _type) public onlyGovernance { require(predicates[predicate]._type == Type.Invalid, "Predicate already added"); predicates[predicate]._type = _type; emit PredicateAdded(predicate, msg.sender); } function removePredicate(address predicate) public onlyGovernance { require(predicates[predicate]._type != Type.Invalid, "Predicate does not exist"); delete predicates[predicate]; emit PredicateRemoved(predicate, msg.sender); } function getValidatorShareAddress() public view returns (address) { return contractMap[VALIDATOR_SHARE]; } function getWethTokenAddress() public view returns (address) { return contractMap[WETH_TOKEN]; } function getDepositManagerAddress() public view returns (address) { return contractMap[DEPOSIT_MANAGER]; } function getStakeManagerAddress() public view returns (address) { return contractMap[STAKE_MANAGER]; } function getSlashingManagerAddress() public view returns (address) { return contractMap[SLASHING_MANAGER]; } function getWithdrawManagerAddress() public view returns (address) { return contractMap[WITHDRAW_MANAGER]; } function getChildChainAndStateSender() public view returns (address, address) { return (contractMap[CHILD_CHAIN], contractMap[STATE_SENDER]); } function isTokenMapped(address _token) public view returns (bool) { return rootToChildToken[_token] != address(0x0); } function isTokenMappedAndIsErc721(address _token) public view returns (bool) { require(isTokenMapped(_token), "TOKEN_NOT_MAPPED"); return isERC721[_token]; } function isTokenMappedAndGetPredicate(address _token) public view returns (address) { if (isTokenMappedAndIsErc721(_token)) { return erc721Predicate; } return erc20Predicate; } function isChildTokenErc721(address childToken) public view returns (bool) { address rootToken = childToRootToken[childToken]; require(rootToken != address(0x0), "Child token is not mapped"); return isERC721[rootToken]; } } contract ChainIdMixin { bytes constant public networkId = hex"6D"; uint256 constant public CHAINID = 109; } contract RootChainHeader { event NewHeaderBlock( address indexed proposer, uint256 indexed headerBlockId, uint256 indexed reward, uint256 start, uint256 end, bytes32 root ); // housekeeping event event ResetHeaderBlock(address indexed proposer, uint256 indexed headerBlockId); struct HeaderBlock { bytes32 root; uint256 start; uint256 end; uint256 createdAt; address proposer; } } contract RootChainStorage is ProxyStorage, RootChainHeader, ChainIdMixin { bytes32 public heimdallId; uint8 public constant VOTE_TYPE = 2; uint16 internal constant MAX_DEPOSITS = 10000; uint256 public _nextHeaderBlock = MAX_DEPOSITS; uint256 internal _blockDepositId = 1; mapping(uint256 => HeaderBlock) public headerBlocks; Registry internal registry; } contract IStakeManager { // validator replacement function startAuction( uint256 validatorId, uint256 amount, bool acceptDelegation, bytes calldata signerPubkey ) external; function confirmAuctionBid(uint256 validatorId, uint256 heimdallFee) external; function transferFunds( uint256 validatorId, uint256 amount, address delegator ) external returns (bool); function delegationDeposit( uint256 validatorId, uint256 amount, address delegator ) external returns (bool); function unstake(uint256 validatorId) external; function totalStakedFor(address addr) external view returns (uint256); function stakeFor( address user, uint256 amount, uint256 heimdallFee, bool acceptDelegation, bytes memory signerPubkey ) public; function checkSignatures( uint256 blockInterval, bytes32 voteHash, bytes32 stateRoot, address proposer, uint[3][] calldata sigs ) external returns (uint256); function updateValidatorState(uint256 validatorId, int256 amount) public; function ownerOf(uint256 tokenId) public view returns (address); function slash(bytes calldata slashingInfoList) external returns (uint256); function validatorStake(uint256 validatorId) public view returns (uint256); function epoch() public view returns (uint256); function getRegistry() public view returns (address); function withdrawalDelay() public view returns (uint256); function delegatedAmount(uint256 validatorId) public view returns(uint256); function decreaseValidatorDelegatedAmount(uint256 validatorId, uint256 amount) public; function withdrawDelegatorsReward(uint256 validatorId) public returns(uint256); function delegatorsReward(uint256 validatorId) public view returns(uint256); function dethroneAndStake( address auctionUser, uint256 heimdallFee, uint256 validatorId, uint256 auctionAmount, bool acceptDelegation, bytes calldata signerPubkey ) external; } interface IRootChain { function slash() external; function submitHeaderBlock(bytes calldata data, bytes calldata sigs) external; function submitCheckpoint(bytes calldata data, uint[3][] calldata sigs) external; function getLastChildBlock() external view returns (uint256); function currentHeaderBlock() external view returns (uint256); } contract RootChain is RootChainStorage, IRootChain { using SafeMath for uint256; using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; modifier onlyDepositManager() { require(msg.sender == registry.getDepositManagerAddress(), "UNAUTHORIZED_DEPOSIT_MANAGER_ONLY"); _; } function submitHeaderBlock(bytes calldata data, bytes calldata sigs) external { revert(); } function submitCheckpoint(bytes calldata data, uint[3][] calldata sigs) external { (address proposer, uint256 start, uint256 end, bytes32 rootHash, bytes32 accountHash, uint256 _borChainID) = abi .decode(data, (address, uint256, uint256, bytes32, bytes32, uint256)); require(CHAINID == _borChainID, "Invalid bor chain id"); require(_buildHeaderBlock(proposer, start, end, rootHash), "INCORRECT_HEADER_DATA"); // check if it is better to keep it in local storage instead IStakeManager stakeManager = IStakeManager(registry.getStakeManagerAddress()); uint256 _reward = stakeManager.checkSignatures( end.sub(start).add(1), /** prefix 01 to data 01 represents positive vote on data and 00 is negative vote malicious validator can try to send 2/3 on negative vote so 01 is appended */ keccak256(abi.encodePacked(bytes(hex"01"), data)), accountHash, proposer, sigs ); require(_reward != 0, "Invalid checkpoint"); emit NewHeaderBlock(proposer, _nextHeaderBlock, _reward, start, end, rootHash); _nextHeaderBlock = _nextHeaderBlock.add(MAX_DEPOSITS); _blockDepositId = 1; } function updateDepositId(uint256 numDeposits) external onlyDepositManager returns (uint256 depositId) { depositId = currentHeaderBlock().add(_blockDepositId); // deposit ids will be (_blockDepositId, _blockDepositId + 1, .... _blockDepositId + numDeposits - 1) _blockDepositId = _blockDepositId.add(numDeposits); require( // Since _blockDepositId is initialized to 1; only (MAX_DEPOSITS - 1) deposits per header block are allowed _blockDepositId <= MAX_DEPOSITS, "TOO_MANY_DEPOSITS" ); } function getLastChildBlock() external view returns (uint256) { return headerBlocks[currentHeaderBlock()].end; } function slash() external { //TODO: future implementation } function currentHeaderBlock() public view returns (uint256) { return _nextHeaderBlock.sub(MAX_DEPOSITS); } function _buildHeaderBlock( address proposer, uint256 start, uint256 end, bytes32 rootHash ) private returns (bool) { uint256 nextChildBlock; /* The ID of the 1st header block is MAX_DEPOSITS. if _nextHeaderBlock == MAX_DEPOSITS, then the first header block is yet to be submitted, hence nextChildBlock = 0 */ if (_nextHeaderBlock > MAX_DEPOSITS) { nextChildBlock = headerBlocks[currentHeaderBlock()].end + 1; } if (nextChildBlock != start) { return false; } HeaderBlock memory headerBlock = HeaderBlock({ root: rootHash, start: nextChildBlock, end: end, createdAt: now, proposer: proposer }); headerBlocks[_nextHeaderBlock] = headerBlock; return true; } // Housekeeping function. @todo remove later function setNextHeaderBlock(uint256 _value) public onlyOwner { require(_value % MAX_DEPOSITS == 0, "Invalid value"); for (uint256 i = _value; i < _nextHeaderBlock; i += MAX_DEPOSITS) { delete headerBlocks[i]; } _nextHeaderBlock = _value; _blockDepositId = 1; emit ResetHeaderBlock(msg.sender, _nextHeaderBlock); } // Housekeeping function. @todo remove later function setHeimdallId(string memory _heimdallId) public onlyOwner { heimdallId = keccak256(abi.encodePacked(_heimdallId)); } } /** * @title IERC165 * @dev https://eips.ethereum.org/EIPS/eip-165 */ 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); } /** * @title ERC721 Non-Fungible Token Standard basic interface * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract IERC721 is 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 memory data) public; } /** * @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 `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))` */ function onERC721Received(address operator, address from, uint256 tokenId, bytes memory data) public returns (bytes4); } /** * 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. // solhint-disable-next-line no-inline-assembly assembly { size := extcodesize(account) } return size > 0; } } /** * @title Counters * @author Matt Condon (@shrugs) * @dev Provides counters that can only be incremented or decremented by one. This can be used e.g. to track the number * of elements in a mapping, issuing ERC721 ids, or counting request ids * * Include with `using Counters for Counters.Counter;` * Since it is not possible to overflow a 256 bit integer with increments of one, `increment` can skip the SafeMath * overflow check, thereby saving gas. This does assume however correct usage, in that the underlying `_value` is never * directly accessed. */ library Counters { using SafeMath for uint256; struct Counter { // This variable should never be directly accessed by users of the library: interactions must be restricted to // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add // this feature: see https://github.com/ethereum/solidity/issues/4637 uint256 _value; // default: 0 } function current(Counter storage counter) internal view returns (uint256) { return counter._value; } function increment(Counter storage counter) internal { counter._value += 1; } function decrement(Counter storage counter) internal { counter._value = counter._value.sub(1); } } /** * @title ERC165 * @author Matt Condon (@shrugs) * @dev Implements ERC165 using a lookup table. */ contract ERC165 is IERC165 { bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7; /* * 0x01ffc9a7 === * bytes4(keccak256('supportsInterface(bytes4)')) */ /** * @dev a mapping of interface id to whether or not it's supported */ mapping(bytes4 => bool) private _supportedInterfaces; /** * @dev A contract implementing SupportsInterfaceWithLookup * implement ERC165 itself */ constructor () internal { _registerInterface(_INTERFACE_ID_ERC165); } /** * @dev implement supportsInterface(bytes4) using a lookup table */ function supportsInterface(bytes4 interfaceId) external view returns (bool) { return _supportedInterfaces[interfaceId]; } /** * @dev internal method for registering an interface */ function _registerInterface(bytes4 interfaceId) internal { require(interfaceId != 0xffffffff); _supportedInterfaces[interfaceId] = true; } } /** * @title ERC721 Non-Fungible Token Standard basic implementation * @dev see https://eips.ethereum.org/EIPS/eip-721 */ contract ERC721 is ERC165, IERC721 { using SafeMath for uint256; using Address for address; using Counters for Counters.Counter; // 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 => Counters.Counter) private _ownedTokensCount; // Mapping from owner to operator approvals mapping (address => mapping (address => bool)) private _operatorApprovals; bytes4 private constant _INTERFACE_ID_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)')) */ constructor () public { // register the supported interfaces to conform to ERC721 via ERC165 _registerInterface(_INTERFACE_ID_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].current(); } /** * @dev Gets the owner of the specified token ID * @param tokenId uint256 ID of the token to query the owner of * @return 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)); _transferFrom(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 { 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 memory _data) public { transferFrom(from, to, tokenId); require(_checkOnERC721Received(from, to, tokenId, _data)); } /** * @dev Returns whether the specified token exists * @param tokenId uint256 ID of the token to query the existence of * @return bool 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); 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 */ function _mint(address to, uint256 tokenId) internal { require(to != address(0)); require(!_exists(tokenId)); _tokenOwner[tokenId] = to; _ownedTokensCount[to].increment(); emit Transfer(address(0), to, tokenId); } /** * @dev Internal function to burn a specific token * Reverts if the token does not exist * Deprecated, use _burn(uint256) instead. * @param owner owner of the token to burn * @param tokenId uint256 ID of the token being burned */ function _burn(address owner, uint256 tokenId) internal { require(ownerOf(tokenId) == owner); _clearApproval(tokenId); _ownedTokensCount[owner].decrement(); _tokenOwner[tokenId] = address(0); emit Transfer(owner, address(0), 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 */ function _burn(uint256 tokenId) internal { _burn(ownerOf(tokenId), tokenId); } /** * @dev Internal function to transfer ownership of a given token ID to another address. * As opposed to transferFrom, this imposes no restrictions on msg.sender. * @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) internal { require(ownerOf(tokenId) == from); require(to != address(0)); _clearApproval(tokenId); _ownedTokensCount[from].decrement(); _ownedTokensCount[to].increment(); _tokenOwner[tokenId] = to; emit Transfer(from, to, tokenId); } /** * @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 bool whether the call correctly returned the expected magic value */ function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory _data) internal returns (bool) { if (!to.isContract()) { return true; } bytes4 retval = IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data); return (retval == _ERC721_RECEIVED); } /** * @dev Private function to clear current approval of a given token ID * @param tokenId uint256 ID of the token to be transferred */ function _clearApproval(uint256 tokenId) private { if (_tokenApprovals[tokenId] != address(0)) { _tokenApprovals[tokenId] = address(0); } } } contract ExitNFT is ERC721 { Registry internal registry; modifier onlyWithdrawManager() { require( msg.sender == registry.getWithdrawManagerAddress(), "UNAUTHORIZED_WITHDRAW_MANAGER_ONLY" ); _; } constructor(address _registry) public { registry = Registry(_registry); } function mint(address _owner, uint256 _tokenId) external onlyWithdrawManager { _mint(_owner, _tokenId); } function burn(uint256 _tokenId) external onlyWithdrawManager { _burn(_tokenId); } function exists(uint256 tokenId) public view returns (bool) { return _exists(tokenId); } } contract ExitsDataStructure { struct Input { address utxoOwner; address predicate; address token; } struct PlasmaExit { uint256 receiptAmountOrNFTId; bytes32 txHash; address owner; address token; bool isRegularExit; address predicate; // Mapping from age of input to Input mapping(uint256 => Input) inputs; } } contract WithdrawManagerHeader is ExitsDataStructure { event Withdraw(uint256 indexed exitId, address indexed user, address indexed token, uint256 amount); event ExitStarted( address indexed exitor, uint256 indexed exitId, address indexed token, uint256 amount, bool isRegularExit ); event ExitUpdated(uint256 indexed exitId, uint256 indexed age, address signer); event ExitPeriodUpdate(uint256 indexed oldExitPeriod, uint256 indexed newExitPeriod); event ExitCancelled(uint256 indexed exitId); } contract WithdrawManagerStorage is ProxyStorage, WithdrawManagerHeader { // 0.5 week = 7 * 86400 / 2 = 302400 uint256 public HALF_EXIT_PERIOD = 302400; // Bonded exits collaterized at 0.1 ETH uint256 internal constant BOND_AMOUNT = 10**17; Registry internal registry; RootChain internal rootChain; mapping(uint128 => bool) isKnownExit; mapping(uint256 => PlasmaExit) public exits; // mapping with token => (owner => exitId) keccak(token+owner) keccak(token+owner+tokenId) mapping(bytes32 => uint256) public ownerExits; mapping(address => address) public exitsQueues; ExitNFT public exitNft; // ERC721, ERC20 and Weth transfers require 155000, 100000, 52000 gas respectively // Processing each exit in a while loop iteration requires ~52000 gas (@todo check if this changed) // uint32 constant internal ITERATION_GAS = 52000; // So putting an upper limit of 155000 + 52000 + leeway uint32 public ON_FINALIZE_GAS_LIMIT = 300000; uint256 public exitWindow; } interface IPredicate { /** * @notice Verify the deprecation of a state update * @param exit ABI encoded PlasmaExit data * @param inputUtxo ABI encoded Input UTXO data * @param challengeData RLP encoded data of the challenge reference tx that encodes the following fields * headerNumber Header block number of which the reference tx was a part of * blockProof Proof that the block header (in the child chain) is a leaf in the submitted merkle root * blockNumber Block number of which the reference tx is a part of * blockTime Reference tx block time * blocktxRoot Transactions root of block * blockReceiptsRoot Receipts root of block * receipt Receipt of the reference transaction * receiptProof Merkle proof of the reference receipt * branchMask Merkle proof branchMask for the receipt * logIndex Log Index to read from the receipt * tx Challenge transaction * txProof Merkle proof of the challenge tx * @return Whether or not the state is deprecated */ function verifyDeprecation( bytes calldata exit, bytes calldata inputUtxo, bytes calldata challengeData ) external returns (bool); function interpretStateUpdate(bytes calldata state) external view returns (bytes memory); function onFinalizeExit(bytes calldata data) external; } contract PredicateUtils is ExitsDataStructure, ChainIdMixin { using RLPReader for RLPReader.RLPItem; // Bonded exits collaterized at 0.1 ETH uint256 private constant BOND_AMOUNT = 10**17; IWithdrawManager internal withdrawManager; IDepositManager internal depositManager; modifier onlyWithdrawManager() { require( msg.sender == address(withdrawManager), "ONLY_WITHDRAW_MANAGER" ); _; } modifier isBondProvided() { require(msg.value == BOND_AMOUNT, "Invalid Bond amount"); _; } function onFinalizeExit(bytes calldata data) external onlyWithdrawManager { (, address token, address exitor, uint256 tokenId) = decodeExitForProcessExit( data ); depositManager.transferAssets(token, exitor, tokenId); } function sendBond() internal { address(uint160(address(withdrawManager))).transfer(BOND_AMOUNT); } function getAddressFromTx(RLPReader.RLPItem[] memory txList) internal pure returns (address signer, bytes32 txHash) { bytes[] memory rawTx = new bytes[](9); for (uint8 i = 0; i <= 5; i++) { rawTx[i] = txList[i].toBytes(); } rawTx[6] = networkId; rawTx[7] = hex""; // [7] and [8] have something to do with v, r, s values rawTx[8] = hex""; txHash = keccak256(RLPEncode.encodeList(rawTx)); signer = ecrecover( txHash, Common.getV(txList[6].toBytes(), Common.toUint16(networkId)), bytes32(txList[7].toUint()), bytes32(txList[8].toUint()) ); } function decodeExit(bytes memory data) internal pure returns (PlasmaExit memory) { (address owner, address token, uint256 amountOrTokenId, bytes32 txHash, bool isRegularExit) = abi .decode(data, (address, address, uint256, bytes32, bool)); return PlasmaExit( amountOrTokenId, txHash, owner, token, isRegularExit, address(0) /* predicate value is not required */ ); } function decodeExitForProcessExit(bytes memory data) internal pure returns (uint256 exitId, address token, address exitor, uint256 tokenId) { (exitId, token, exitor, tokenId) = abi.decode( data, (uint256, address, address, uint256) ); } function decodeInputUtxo(bytes memory data) internal pure returns (uint256 age, address signer, address predicate, address token) { (age, signer, predicate, token) = abi.decode( data, (uint256, address, address, address) ); } } contract IErcPredicate is IPredicate, PredicateUtils { enum ExitType {Invalid, OutgoingTransfer, IncomingTransfer, Burnt} struct ExitTxData { uint256 amountOrToken; bytes32 txHash; address childToken; address signer; ExitType exitType; } struct ReferenceTxData { uint256 closingBalance; uint256 age; address childToken; address rootToken; } uint256 internal constant MAX_LOGS = 10; constructor(address _withdrawManager, address _depositManager) public { withdrawManager = IWithdrawManager(_withdrawManager); depositManager = IDepositManager(_depositManager); } } contract ERC20PredicateBurnOnly is IErcPredicate { using RLPReader for bytes; using RLPReader for RLPReader.RLPItem; using SafeMath for uint256; using ExitPayloadReader for bytes; using ExitPayloadReader for ExitPayloadReader.ExitPayload; using ExitPayloadReader for ExitPayloadReader.Receipt; using ExitPayloadReader for ExitPayloadReader.Log; using ExitPayloadReader for ExitPayloadReader.LogTopics; // keccak256('Withdraw(address,address,uint256,uint256,uint256)') bytes32 constant WITHDRAW_EVENT_SIG = 0xebff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f; constructor( address _withdrawManager, address _depositManager ) public IErcPredicate(_withdrawManager, _depositManager) { } function startExitWithBurntTokens(bytes calldata data) external { ExitPayloadReader.ExitPayload memory payload = data.toExitPayload(); ExitPayloadReader.Receipt memory receipt = payload.getReceipt(); uint256 logIndex = payload.getReceiptLogIndex(); require(logIndex < MAX_LOGS, "Supporting a max of 10 logs"); uint256 age = withdrawManager.verifyInclusion( data, 0, /* offset */ false /* verifyTxInclusion */ ); ExitPayloadReader.Log memory log = receipt.getLog(); // "address" (contract address that emitted the log) field in the receipt address childToken = log.getEmitter(); ExitPayloadReader.LogTopics memory topics = log.getTopics(); // now, inputItems[i] refers to i-th (0-based) topic in the topics array // event Withdraw(address indexed token, address indexed from, uint256 amountOrTokenId, uint256 input1, uint256 output1) require( bytes32(topics.getField(0).toUint()) == WITHDRAW_EVENT_SIG, "Not a withdraw event signature" ); require( msg.sender == address(topics.getField(2).toUint()), // from "Withdrawer and burn exit tx do not match" ); address rootToken = address(topics.getField(1).toUint()); uint256 exitAmount = BytesLib.toUint(log.getData(), 0); // amountOrTokenId withdrawManager.addExitToQueue( msg.sender, childToken, rootToken, exitAmount, bytes32(0x0), true, /* isRegularExit */ age << 1 ); } function verifyDeprecation( bytes calldata exit, bytes calldata inputUtxo, bytes calldata challengeData ) external returns (bool) {} function interpretStateUpdate(bytes calldata state) external view returns (bytes memory) {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_withdrawManager","type":"address"},{"internalType":"address","name":"_depositManager","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"constant":true,"inputs":[],"name":"CHAINID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"state","type":"bytes"}],"name":"interpretStateUpdate","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"networkId","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"onFinalizeExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"startExitWithBurntTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"exit","type":"bytes"},{"internalType":"bytes","name":"inputUtxo","type":"bytes"},{"internalType":"bytes","name":"challengeData","type":"bytes"}],"name":"verifyDeprecation","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
608060405234801561001057600080fd5b50604051610fb8380380610fb88339818101604052604081101561003357600080fd5b508051602090910151600080546001600160a01b039384166001600160a01b03199182161790915560018054939092169216919091179055610f3e8061007a6000396000f3fe608060405234801561001057600080fd5b50600436106100625760003560e01c80637bd94e03146100675780637c5264b4146100d757806382e3464c146101455780639025e64c14610228578063cc79f97b14610230578063ec58410c1461024a575b600080fd5b6100d56004803603602081101561007d57600080fd5b810190602081018135600160201b81111561009757600080fd5b8201836020820111156100a957600080fd5b803590602001918460018302840111600160201b831117156100ca57600080fd5b50909250905061036c565b005b6100d5600480360360208110156100ed57600080fd5b810190602081018135600160201b81111561010757600080fd5b82018360208201111561011957600080fd5b803590602001918460018302840111600160201b8311171561013a57600080fd5b50909250905061048a565b6101b36004803603602081101561015b57600080fd5b810190602081018135600160201b81111561017557600080fd5b82018360208201111561018757600080fd5b803590602001918460018302840111600160201b831117156101a857600080fd5b5090925090506107ef565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101ed5781810151838201526020016101d5565b50505050905090810190601f16801561021a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b36107f7565b610238610814565b60408051918252519081900360200190f35b6103586004803603606081101561026057600080fd5b810190602081018135600160201b81111561027a57600080fd5b82018360208201111561028c57600080fd5b803590602001918460018302840111600160201b831117156102ad57600080fd5b919390929091602081019035600160201b8111156102ca57600080fd5b8201836020820111156102dc57600080fd5b803590602001918460018302840111600160201b831117156102fd57600080fd5b919390929091602081019035600160201b81111561031a57600080fd5b82018360208201111561032c57600080fd5b803590602001918460018302840111600160201b8311171561034d57600080fd5b509092509050610819565b604080519115158252519081900360200190f35b6000546001600160a01b031633146103c3576040805162461bcd60e51b815260206004820152601560248201527427a7262cafaba4aa24222920abafa6a0a720a3a2a960591b604482015290519081900360640190fd5b600080600061040785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061082592505050565b600154604080516349f4cc1760e01b81526001600160a01b03808716600483015280861660248301526044820185905291519599509397509195501692506349f4cc1791606480830192600092919082900301818387803b15801561046b57600080fd5b505af115801561047f573d6000803e3d6000fd5b505050505050505050565b610492610e73565b6104d183838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061086292505050565b90506104db610e86565b6104e482610894565b905060006104f183610976565b9050600a8110610548576040805162461bcd60e51b815260206004820152601b60248201527f537570706f7274696e672061206d6178206f66203130206c6f67730000000000604482015290519081900360640190fd5b6000805460405163ad1d806960e01b81526024810183905260448101839052606060048201908152606482018890526001600160a01b039092169163ad1d80699189918991869182918190608401868680828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b1580156105d257600080fd5b505afa1580156105e6573d6000803e3d6000fd5b505050506040513d60208110156105fc57600080fd5b50519050610608610ea7565b6106118461099f565b9050600061061e82610a0c565b9050610628610e73565b61063183610a2f565b90507febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f61066d61066883600063ffffffff610a5e16565b610a84565b146106bf576040805162461bcd60e51b815260206004820152601e60248201527f4e6f742061207769746864726177206576656e74207369676e61747572650000604482015290519081900360640190fd5b6106d361066882600263ffffffff610a5e16565b6001600160a01b0316336001600160a01b0316146107225760405162461bcd60e51b8152600401808060200182810382526028815260200180610ee26028913960400191505060405180910390fd5b600061073861066883600163ffffffff610a5e16565b9050600061074f61074886610ae4565b6000610afa565b600080546040805163d931a86960e01b81523360048201526001600160a01b03898116602483015287811660448301526064820186905260848201859052600160a483018190528c901b60c4830152915194955091169263d931a8699260e48084019391929182900301818387803b1580156107ca57600080fd5b505af11580156107de573d6000803e3d6000fd5b505050505050505050505050505050565b606092915050565b604051806040016040528060018152602001606d60f81b81525081565b606d81565b60009695505050505050565b60008060008084806020019051608081101561084057600080fd5b5080516020820151604083015160609093015191989097509195509350915050565b61086a610e73565b606061087d61087884610b16565b610b3b565b60408051602081019091529081529150505b919050565b61089c610e86565b6108bd82600001516006815181106108b057fe5b6020026020010151610c0c565b60208201526108ca610ec7565b6108d78260200151610b16565b90506108e281610c7c565b156108f7576108f081610b3b565b8252610962565b606082602001519050606060018251036040519080825280601f01601f191660200182016040528015610931576020820181803883390190505b50905060008083602101915082602001905061094f82828551610cb6565b61095b61087884610b16565b8652505050505b61096b83610976565b604083015250919050565b6000610999826000015160098151811061098c57fe5b6020026020010151610a84565b92915050565b6109a7610ea7565b6109af610ec7565b6109d083600001516003815181106109c357fe5b6020026020010151610b3b565b8360400151815181106109df57fe5b602002602001015190506040518060400160405280828152602001610a0383610b3b565b90529392505050565b60006109998260200151600081518110610a2257fe5b6020026020010151610d01565b610a37610e73565b6040518060200160405280610a5684602001516001815181106109c357fe5b905292915050565b610a66610ec7565b8251805183908110610a7457fe5b6020026020010151905092915050565b805160009015801590610a9957508151602110155b610aa257600080fd5b6000610ab18360200151610d1b565b83516020808601518301805193945091849003929190831015610adb57826020036101000a820491505b50949350505050565b606061099982602001516002815181106108b057fe5b60008160200183511015610b0d57600080fd5b50016020015190565b610b1e610ec7565b506040805180820190915281518152602082810190820152919050565b6060610b4682610c7c565b610b4f57600080fd5b6000610b5a83610d7e565b9050606081604051908082528060200260200182016040528015610b9857816020015b610b85610ec7565b815260200190600190039081610b7d5790505b5090506000610baa8560200151610d1b565b60208601510190506000805b84811015610c0157610bc783610dda565b9150604051806040016040528083815260200184815250848281518110610bea57fe5b602090810291909101015291810191600101610bb6565b509195945050505050565b8051606090610c1a57600080fd5b6000610c298360200151610d1b565b83516040805191839003808352601f19601f8201168301602001909152919250606090828015610c60576020820181803883390190505b5090506000816020019050610adb848760200151018285610cb6565b8051600090610c8d5750600061088f565b6020820151805160001a9060c0821015610cac5760009250505061088f565b5060019392505050565b80610cc057610cfc565b5b60208110610ce0578251825260209283019290910190601f1901610cc1565b8251825160208390036101000a60001901801990921691161782525b505050565b8051600090601514610d1257600080fd5b61099982610a84565b8051600090811a6080811015610d3557600091505061088f565b60b8811080610d50575060c08110801590610d50575060f881105b15610d5f57600191505061088f565b60c0811015610d735760b51901905061088f565b60f51901905061088f565b8051600090610d8f5750600061088f565b60008090506000610da38460200151610d1b565b602085015185519181019250015b80821015610dd157610dc282610dda565b60019093019290910190610db1565b50909392505050565b80516000908190811a6080811015610df55760019150610e6c565b60b8811015610e0a57607e1981019150610e6c565b60c0811015610e375760b78103600185019450806020036101000a85510460018201810193505050610e6c565b60f8811015610e4c5760be1981019150610e6c565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b6040518060400160405280610eba610ec7565b8152602001606081525090565b60405180604001604052806000815260200160008152509056fe5769746864726177657220616e64206275726e206578697420747820646f206e6f74206d61746368a265627a7a723158204c44ae7931df8ce197aef34dc4d579da8fff9097f29f078bf439fa622f2ffb0364736f6c634300051100320000000000000000000000005f683665ca87dbc3d1358913da80e3c71c328fb0000000000000000000000000885fce983b6a01633f764325b8c3c5d31032c995
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100625760003560e01c80637bd94e03146100675780637c5264b4146100d757806382e3464c146101455780639025e64c14610228578063cc79f97b14610230578063ec58410c1461024a575b600080fd5b6100d56004803603602081101561007d57600080fd5b810190602081018135600160201b81111561009757600080fd5b8201836020820111156100a957600080fd5b803590602001918460018302840111600160201b831117156100ca57600080fd5b50909250905061036c565b005b6100d5600480360360208110156100ed57600080fd5b810190602081018135600160201b81111561010757600080fd5b82018360208201111561011957600080fd5b803590602001918460018302840111600160201b8311171561013a57600080fd5b50909250905061048a565b6101b36004803603602081101561015b57600080fd5b810190602081018135600160201b81111561017557600080fd5b82018360208201111561018757600080fd5b803590602001918460018302840111600160201b831117156101a857600080fd5b5090925090506107ef565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101ed5781810151838201526020016101d5565b50505050905090810190601f16801561021a5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6101b36107f7565b610238610814565b60408051918252519081900360200190f35b6103586004803603606081101561026057600080fd5b810190602081018135600160201b81111561027a57600080fd5b82018360208201111561028c57600080fd5b803590602001918460018302840111600160201b831117156102ad57600080fd5b919390929091602081019035600160201b8111156102ca57600080fd5b8201836020820111156102dc57600080fd5b803590602001918460018302840111600160201b831117156102fd57600080fd5b919390929091602081019035600160201b81111561031a57600080fd5b82018360208201111561032c57600080fd5b803590602001918460018302840111600160201b8311171561034d57600080fd5b509092509050610819565b604080519115158252519081900360200190f35b6000546001600160a01b031633146103c3576040805162461bcd60e51b815260206004820152601560248201527427a7262cafaba4aa24222920abafa6a0a720a3a2a960591b604482015290519081900360640190fd5b600080600061040785858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061082592505050565b600154604080516349f4cc1760e01b81526001600160a01b03808716600483015280861660248301526044820185905291519599509397509195501692506349f4cc1791606480830192600092919082900301818387803b15801561046b57600080fd5b505af115801561047f573d6000803e3d6000fd5b505050505050505050565b610492610e73565b6104d183838080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061086292505050565b90506104db610e86565b6104e482610894565b905060006104f183610976565b9050600a8110610548576040805162461bcd60e51b815260206004820152601b60248201527f537570706f7274696e672061206d6178206f66203130206c6f67730000000000604482015290519081900360640190fd5b6000805460405163ad1d806960e01b81526024810183905260448101839052606060048201908152606482018890526001600160a01b039092169163ad1d80699189918991869182918190608401868680828437600081840152601f19601f8201169050808301925050509550505050505060206040518083038186803b1580156105d257600080fd5b505afa1580156105e6573d6000803e3d6000fd5b505050506040513d60208110156105fc57600080fd5b50519050610608610ea7565b6106118461099f565b9050600061061e82610a0c565b9050610628610e73565b61063183610a2f565b90507febff2602b3f468259e1e99f613fed6691f3a6526effe6ef3e768ba7ae7a36c4f61066d61066883600063ffffffff610a5e16565b610a84565b146106bf576040805162461bcd60e51b815260206004820152601e60248201527f4e6f742061207769746864726177206576656e74207369676e61747572650000604482015290519081900360640190fd5b6106d361066882600263ffffffff610a5e16565b6001600160a01b0316336001600160a01b0316146107225760405162461bcd60e51b8152600401808060200182810382526028815260200180610ee26028913960400191505060405180910390fd5b600061073861066883600163ffffffff610a5e16565b9050600061074f61074886610ae4565b6000610afa565b600080546040805163d931a86960e01b81523360048201526001600160a01b03898116602483015287811660448301526064820186905260848201859052600160a483018190528c901b60c4830152915194955091169263d931a8699260e48084019391929182900301818387803b1580156107ca57600080fd5b505af11580156107de573d6000803e3d6000fd5b505050505050505050505050505050565b606092915050565b604051806040016040528060018152602001606d60f81b81525081565b606d81565b60009695505050505050565b60008060008084806020019051608081101561084057600080fd5b5080516020820151604083015160609093015191989097509195509350915050565b61086a610e73565b606061087d61087884610b16565b610b3b565b60408051602081019091529081529150505b919050565b61089c610e86565b6108bd82600001516006815181106108b057fe5b6020026020010151610c0c565b60208201526108ca610ec7565b6108d78260200151610b16565b90506108e281610c7c565b156108f7576108f081610b3b565b8252610962565b606082602001519050606060018251036040519080825280601f01601f191660200182016040528015610931576020820181803883390190505b50905060008083602101915082602001905061094f82828551610cb6565b61095b61087884610b16565b8652505050505b61096b83610976565b604083015250919050565b6000610999826000015160098151811061098c57fe5b6020026020010151610a84565b92915050565b6109a7610ea7565b6109af610ec7565b6109d083600001516003815181106109c357fe5b6020026020010151610b3b565b8360400151815181106109df57fe5b602002602001015190506040518060400160405280828152602001610a0383610b3b565b90529392505050565b60006109998260200151600081518110610a2257fe5b6020026020010151610d01565b610a37610e73565b6040518060200160405280610a5684602001516001815181106109c357fe5b905292915050565b610a66610ec7565b8251805183908110610a7457fe5b6020026020010151905092915050565b805160009015801590610a9957508151602110155b610aa257600080fd5b6000610ab18360200151610d1b565b83516020808601518301805193945091849003929190831015610adb57826020036101000a820491505b50949350505050565b606061099982602001516002815181106108b057fe5b60008160200183511015610b0d57600080fd5b50016020015190565b610b1e610ec7565b506040805180820190915281518152602082810190820152919050565b6060610b4682610c7c565b610b4f57600080fd5b6000610b5a83610d7e565b9050606081604051908082528060200260200182016040528015610b9857816020015b610b85610ec7565b815260200190600190039081610b7d5790505b5090506000610baa8560200151610d1b565b60208601510190506000805b84811015610c0157610bc783610dda565b9150604051806040016040528083815260200184815250848281518110610bea57fe5b602090810291909101015291810191600101610bb6565b509195945050505050565b8051606090610c1a57600080fd5b6000610c298360200151610d1b565b83516040805191839003808352601f19601f8201168301602001909152919250606090828015610c60576020820181803883390190505b5090506000816020019050610adb848760200151018285610cb6565b8051600090610c8d5750600061088f565b6020820151805160001a9060c0821015610cac5760009250505061088f565b5060019392505050565b80610cc057610cfc565b5b60208110610ce0578251825260209283019290910190601f1901610cc1565b8251825160208390036101000a60001901801990921691161782525b505050565b8051600090601514610d1257600080fd5b61099982610a84565b8051600090811a6080811015610d3557600091505061088f565b60b8811080610d50575060c08110801590610d50575060f881105b15610d5f57600191505061088f565b60c0811015610d735760b51901905061088f565b60f51901905061088f565b8051600090610d8f5750600061088f565b60008090506000610da38460200151610d1b565b602085015185519181019250015b80821015610dd157610dc282610dda565b60019093019290910190610db1565b50909392505050565b80516000908190811a6080811015610df55760019150610e6c565b60b8811015610e0a57607e1981019150610e6c565b60c0811015610e375760b78103600185019450806020036101000a85510460018201810193505050610e6c565b60f8811015610e4c5760be1981019150610e6c565b60f78103600185019450806020036101000a855104600182018101935050505b5092915050565b6040518060200160405280606081525090565b60405180606001604052806060815260200160608152602001600081525090565b6040518060400160405280610eba610ec7565b8152602001606081525090565b60405180604001604052806000815260200160008152509056fe5769746864726177657220616e64206275726e206578697420747820646f206e6f74206d61746368a265627a7a723158204c44ae7931df8ce197aef34dc4d579da8fff9097f29f078bf439fa622f2ffb0364736f6c63430005110032
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000005f683665ca87dbc3d1358913da80e3c71c328fb0000000000000000000000000885fce983b6a01633f764325b8c3c5d31032c995
-----Decoded View---------------
Arg [0] : _withdrawManager (address): 0x5F683665ca87dbC3D1358913da80e3C71c328Fb0
Arg [1] : _depositManager (address): 0x885fcE983b6a01633f764325B8c3c5D31032C995
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000005f683665ca87dbc3d1358913da80e3c71c328fb0
Arg [1] : 000000000000000000000000885fce983b6a01633f764325b8c3c5d31032c995
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.