Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
WithdrawManager
Compiler Version
v0.5.17+commit.d19bba13
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
pragma solidity ^0.5.2;
import {ERC20} from "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
import {ERC721} from "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import {Math} from "openzeppelin-solidity/contracts/math/Math.sol";
import {Merkle} from "../../common/lib/Merkle.sol";
import {MerklePatriciaProof} from "../../common/lib/MerklePatriciaProof.sol";
import {PriorityQueue} from "../../common/lib/PriorityQueue.sol";
import {ExitPayloadReader} from "../../common/lib/ExitPayloadReader.sol";
import {ExitNFT} from "./ExitNFT.sol";
import {DepositManager} from "../depositManager/DepositManager.sol";
import {IPredicate} from "../predicates/IPredicate.sol";
import {IWithdrawManager} from "./IWithdrawManager.sol";
import {RootChainHeader} from "../RootChainStorage.sol";
import {Registry} from "../../common/Registry.sol";
import {WithdrawManagerStorage} from "./WithdrawManagerStorage.sol";
contract WithdrawManager is WithdrawManagerStorage, IWithdrawManager {
using Merkle for bytes32;
using ExitPayloadReader for bytes;
using ExitPayloadReader for ExitPayloadReader.ExitPayload;
using ExitPayloadReader for ExitPayloadReader.Receipt;
using ExitPayloadReader for ExitPayloadReader.Log;
using ExitPayloadReader for ExitPayloadReader.LogTopics;
modifier isBondProvided() {
require(msg.value == BOND_AMOUNT, "Invalid Bond amount");
_;
}
modifier isPredicateAuthorized() {
require(registry.predicates(msg.sender) != Registry.Type.Invalid, "PREDICATE_NOT_AUTHORIZED");
_;
}
modifier checkPredicateAndTokenMapping(address rootToken) {
Registry.Type _type = registry.predicates(msg.sender);
require(registry.rootToChildToken(rootToken) != address(0x0), "rootToken not supported");
if (_type == Registry.Type.ERC20) {
require(registry.isERC721(rootToken) == false, "Predicate supports only ERC20 tokens");
} else if (_type == Registry.Type.ERC721) {
require(registry.isERC721(rootToken) == true, "Predicate supports only ERC721 tokens");
} else if (_type == Registry.Type.Custom) {} else {
revert("PREDICATE_NOT_AUTHORIZED");
}
_;
}
/**
* @dev Receive bond for bonded exits
*/
function() external payable {}
function createExitQueue(address token) external {
require(msg.sender == address(registry), "UNAUTHORIZED_REGISTRY_ONLY");
exitsQueues[token] = address(new PriorityQueue());
}
/**
During coverage tests verifyInclusion fails co compile with "stack too deep" error.
*/
struct VerifyInclusionVars {
uint256 headerNumber;
uint256 blockNumber;
uint256 createdAt;
uint256 branchMask;
bytes32 txRoot;
bytes32 receiptRoot;
bytes branchMaskBytes;
}
/**
* @dev Verify the inclusion of the receipt in the checkpoint
* @param data RLP encoded data of the reference tx(s) that encodes the following fields for each tx
* 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
* @param offset offset in the data array
* @param verifyTxInclusion Whether to also verify the inclusion of the raw tx in the txRoot
* @return ageOfInput Measure of the position of the receipt and the log in the child chain
*/
function verifyInclusion(
bytes calldata data,
uint8 offset,
bool verifyTxInclusion
)
external
view
returns (
uint256 /* ageOfInput */
)
{
ExitPayloadReader.ExitPayload memory payload = data.toExitPayload();
VerifyInclusionVars memory vars;
vars.headerNumber = payload.getHeaderNumber();
vars.branchMaskBytes = payload.getBranchMaskAsBytes();
require(vars.branchMaskBytes[0] == 0, "incorrect mask");
vars.txRoot = payload.getTxRoot();
vars.receiptRoot = payload.getReceiptRoot();
require(
MerklePatriciaProof.verify(
payload.getReceipt().toBytes(),
vars.branchMaskBytes,
payload.getReceiptProof(),
vars.receiptRoot
),
"INVALID_RECEIPT_MERKLE_PROOF"
);
if (verifyTxInclusion) {
require(
MerklePatriciaProof.verify(
payload.getTx(),
vars.branchMaskBytes,
payload.getTxProof(),
vars.txRoot
),
"INVALID_TX_MERKLE_PROOF"
);
}
vars.blockNumber = payload.getBlockNumber();
vars.createdAt = checkBlockMembershipInCheckpoint(
vars.blockNumber,
payload.getBlockTime(),
vars.txRoot,
vars.receiptRoot,
vars.headerNumber,
payload.getBlockProof()
);
vars.branchMask = payload.getBranchMaskAsUint();
require(
vars.branchMask & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000 == 0,
"Branch mask should be 32 bits"
);
// ageOfInput is denoted as
// 1 reserve bit (see last 2 lines in comment)
// 128 bits for exitableAt timestamp
// 95 bits for child block number
// 32 bits for receiptPos + logIndex * MAX_LOGS + oIndex
// In predicates, the exitId will be evaluated by shifting the ageOfInput left by 1 bit
// (Only in erc20Predicate) Last bit is to differentiate whether the sender or receiver of the in-flight tx is starting an exit
return (getExitableAt(vars.createdAt) << 127) | (vars.blockNumber << 32) | vars.branchMask;
}
function startExitWithDepositedTokens(
uint256 depositId,
address token,
uint256 amountOrToken
) external payable isBondProvided {
// (bytes32 depositHash, uint256 createdAt) = getDepositManager().deposits(depositId);
// require(keccak256(abi.encodePacked(msg.sender, token, amountOrToken)) == depositHash, "UNAUTHORIZED_EXIT");
// uint256 ageOfInput = getExitableAt(createdAt) << 127 | (depositId % 10000 /* MAX_DEPOSITS */);
// uint256 exitId = ageOfInput << 1;
// address predicate = registry.isTokenMappedAndGetPredicate(token);
// _addExitToQueue(
// msg.sender,
// token,
// amountOrToken,
// bytes32(0), /* txHash */
// false, /* isRegularExit */
// exitId,
// predicate
// );
// _addInput(
// exitId,
// ageOfInput,
// msg.sender, /* utxoOwner */
// predicate,
// token
// );
}
function addExitToQueue(
address exitor,
address childToken,
address rootToken,
uint256 exitAmountOrTokenId,
bytes32 txHash,
bool isRegularExit,
uint256 priority
) external checkPredicateAndTokenMapping(rootToken) {
require(registry.rootToChildToken(rootToken) == childToken, "INVALID_ROOT_TO_CHILD_TOKEN_MAPPING");
_addExitToQueue(exitor, rootToken, exitAmountOrTokenId, txHash, isRegularExit, priority, msg.sender);
}
function challengeExit(
uint256 exitId,
uint256 inputId,
bytes calldata challengeData,
address adjudicatorPredicate
) external {
PlasmaExit storage exit = exits[exitId];
Input storage input = exit.inputs[inputId];
require(exit.owner != address(0x0) && input.utxoOwner != address(0x0), "Invalid exit or input id");
require(registry.predicates(adjudicatorPredicate) != Registry.Type.Invalid, "INVALID_PREDICATE");
require(
IPredicate(adjudicatorPredicate).verifyDeprecation(
encodeExit(exit),
encodeInputUtxo(inputId, input),
challengeData
),
"Challenge failed"
);
// In the call to burn(exitId), there is an implicit check that prevents challenging the same exit twice
ExitNFT(exitNft).burn(exitId);
// Send bond amount to challenger
msg.sender.send(BOND_AMOUNT);
// delete exits[exitId];
emit ExitCancelled(exitId);
}
function processExits(address _token) public {
uint256 exitableAt;
uint256 exitId;
PriorityQueue exitQueue = PriorityQueue(exitsQueues[_token]);
while (exitQueue.currentSize() > 0 && gasleft() > ON_FINALIZE_GAS_LIMIT) {
(exitableAt, exitId) = exitQueue.getMin();
exitId = (exitableAt << 128) | exitId;
PlasmaExit memory currentExit = exits[exitId];
// Stop processing exits if the exit that is next is queue is still in its challenge period
if (exitableAt > block.timestamp) return;
exitQueue.delMin();
// If the exitNft was deleted as a result of a challenge, skip processing this exit
if (!exitNft.exists(exitId)) continue;
address exitor = exitNft.ownerOf(exitId);
exits[exitId].owner = exitor;
exitNft.burn(exitId);
// If finalizing a particular exit is reverting, it will block any following exits from being processed.
// Hence, call predicate.onFinalizeExit in a revertless manner.
// (bool success, bytes memory result) =
currentExit.predicate.call(
abi.encodeWithSignature("onFinalizeExit(bytes)", encodeExitForProcessExit(exitId))
);
emit Withdraw(exitId, exitor, _token, currentExit.receiptAmountOrNFTId);
if (!currentExit.isRegularExit) {
// return the bond amount if this was a MoreVp style exit
address(uint160(exitor)).send(BOND_AMOUNT);
}
}
}
function processExitsBatch(address[] calldata _tokens) external {
for (uint256 i = 0; i < _tokens.length; i++) {
processExits(_tokens[i]);
}
}
/**
* @dev Add a state update (UTXO style input) to an exit
* @param exitId Exit ID
* @param age age of the UTXO style input
* @param utxoOwner User for whom the input acts as a proof-of-funds
* (alternate expression) User who could have potentially spent this UTXO
* @param token Token (Think of it like Utxo color)
*/
function addInput(
uint256 exitId,
uint256 age,
address utxoOwner,
address token
) external isPredicateAuthorized {
PlasmaExit storage exitObject = exits[exitId];
require(exitObject.owner != address(0x0), "INVALID_EXIT_ID");
_addInput(
exitId,
age,
utxoOwner,
/* predicate */
msg.sender,
token
);
}
function _addInput(
uint256 exitId,
uint256 age,
address utxoOwner,
address predicate,
address token
) internal {
exits[exitId].inputs[age] = Input(utxoOwner, predicate, token);
emit ExitUpdated(exitId, age, utxoOwner);
}
function encodeExit(PlasmaExit storage exit) internal view returns (bytes memory) {
return
abi.encode(
exit.owner,
registry.rootToChildToken(exit.token),
exit.receiptAmountOrNFTId,
exit.txHash,
exit.isRegularExit
);
}
function encodeExitForProcessExit(uint256 exitId) internal view returns (bytes memory) {
PlasmaExit storage exit = exits[exitId];
return abi.encode(exitId, exit.token, exit.owner, exit.receiptAmountOrNFTId);
}
function encodeInputUtxo(uint256 age, Input storage input) internal view returns (bytes memory) {
return abi.encode(age, input.utxoOwner, input.predicate, registry.rootToChildToken(input.token));
}
function _addExitToQueue(
address exitor,
address rootToken,
uint256 exitAmountOrTokenId,
bytes32 txHash,
bool isRegularExit,
uint256 exitId,
address predicate
) internal {
require(exits[exitId].token == address(0x0), "EXIT_ALREADY_EXISTS");
exits[exitId] = PlasmaExit(
exitAmountOrTokenId,
txHash,
exitor,
rootToken,
isRegularExit,
predicate
);
PlasmaExit storage _exitObject = exits[exitId];
bytes32 key = getKey(_exitObject.token, _exitObject.owner, _exitObject.receiptAmountOrNFTId);
if (isRegularExit) {
require(!isKnownExit[uint128(exitId)], "KNOWN_EXIT");
isKnownExit[uint128(exitId)] = true;
} else {
// a user cannot start 2 MoreVP exits for the same erc20 token or nft
require(ownerExits[key] == 0, "EXIT_ALREADY_IN_PROGRESS");
ownerExits[key] = exitId;
}
PriorityQueue queue = PriorityQueue(exitsQueues[_exitObject.token]);
// Way priority queue is implemented is such that it expects 2 uint256 params with most significant 128 bits masked out
// This is a workaround to split exitId, which otherwise is conclusive in itself
// exitId >> 128 gives 128 most significant bits
// uint256(uint128(exitId)) gives 128 least significant bits
// @todo Fix this mess
queue.insert(exitId >> 128, uint256(uint128(exitId)));
// create exit nft
exitNft.mint(_exitObject.owner, exitId);
emit ExitStarted(exitor, exitId, rootToken, exitAmountOrTokenId, isRegularExit);
}
function checkBlockMembershipInCheckpoint(
uint256 blockNumber,
uint256 blockTime,
bytes32 txRoot,
bytes32 receiptRoot,
uint256 headerNumber,
bytes memory blockProof
)
internal
view
returns (
uint256 /* createdAt */
)
{
(bytes32 headerRoot, uint256 startBlock, , uint256 createdAt, ) = rootChain.headerBlocks(headerNumber);
require(
keccak256(abi.encodePacked(blockNumber, blockTime, txRoot, receiptRoot)).checkMembership(
blockNumber - startBlock,
headerRoot,
blockProof
),
"WITHDRAW_BLOCK_NOT_A_PART_OF_SUBMITTED_HEADER"
);
return createdAt;
}
function getKey(
address token,
address exitor,
uint256 amountOrToken
) internal view returns (bytes32 key) {
if (registry.isERC721(token)) {
key = keccak256(abi.encodePacked(token, exitor, amountOrToken));
} else {
// validate amount
require(amountOrToken > 0, "CANNOT_EXIT_ZERO_AMOUNTS");
key = keccak256(abi.encodePacked(token, exitor));
}
}
function getDepositManager() internal view returns (DepositManager) {
return DepositManager(address(uint160(registry.getDepositManagerAddress())));
}
function getExitableAt(uint256 createdAt) internal view returns (uint256) {
return Math.max(createdAt + 2 * HALF_EXIT_PERIOD, now + HALF_EXIT_PERIOD);
}
// Housekeeping function. @todo remove later
function updateExitPeriod(uint256 halfExitPeriod) public onlyOwner {
emit ExitPeriodUpdate(HALF_EXIT_PERIOD, halfExitPeriod);
HALF_EXIT_PERIOD = halfExitPeriod;
}
}pragma solidity ^0.5.2;
import {IGovernance} from "./IGovernance.sol";
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"
);
}
}pragma solidity ^0.5.2;
interface IGovernance {
function update(address target, bytes calldata data) external;
}pragma solidity ^0.5.2;
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
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;
}
}pragma solidity ^0.5.2;
import "./BytesLib.sol";
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]));
}
}pragma solidity 0.5.17;
import {RLPReader} from "./RLPReader.sol";
import {BytesLib} from "./BytesLib.sol";
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];
}
}pragma solidity ^0.5.2;
library Merkle {
function checkMembership(
bytes32 leaf,
uint256 index,
bytes32 rootHash,
bytes memory proof
) internal pure returns (bool) {
require(proof.length % 32 == 0, "Invalid proof length");
uint256 proofHeight = proof.length / 32;
// Proof of size n means, height of the tree is n+1.
// In a tree of height n+1, max #leafs possible is 2 ^ n
require(index < 2 ** proofHeight, "Leaf index is too big");
bytes32 proofElement;
bytes32 computedHash = leaf;
for (uint256 i = 32; i <= proof.length; i += 32) {
assembly {
proofElement := mload(add(proof, i))
}
if (index % 2 == 0) {
computedHash = keccak256(
abi.encodePacked(computedHash, proofElement)
);
} else {
computedHash = keccak256(
abi.encodePacked(proofElement, computedHash)
);
}
index = index / 2;
}
return computedHash == rootHash;
}
}pragma solidity ^0.5.2;
import {RLPReader} from "./RLPReader.sol";
library MerklePatriciaProof {
/*
* @dev Verifies a merkle patricia proof.
* @param value The terminating value in the trie.
* @param encodedPath The path in the trie leading to value.
* @param rlpParentNodes The rlp encoded stack of nodes.
* @param root The root hash of the trie.
* @return The boolean validity of the proof.
*/
function verify(
bytes memory value,
bytes memory encodedPath,
bytes memory rlpParentNodes,
bytes32 root
) internal pure returns (bool) {
RLPReader.RLPItem memory item = RLPReader.toRlpItem(rlpParentNodes);
RLPReader.RLPItem[] memory parentNodes = RLPReader.toList(item);
bytes memory currentNode;
RLPReader.RLPItem[] memory currentNodeList;
bytes32 nodeKey = root;
uint256 pathPtr = 0;
bytes memory path = _getNibbleArray(encodedPath);
if (path.length == 0) {
return false;
}
for (uint256 i = 0; i < parentNodes.length; i++) {
if (pathPtr > path.length) {
return false;
}
currentNode = RLPReader.toRlpBytes(parentNodes[i]);
if (nodeKey != keccak256(currentNode)) {
return false;
}
currentNodeList = RLPReader.toList(parentNodes[i]);
if (currentNodeList.length == 17) {
if (pathPtr == path.length) {
if (
keccak256(RLPReader.toBytes(currentNodeList[16])) ==
keccak256(value)
) {
return true;
} else {
return false;
}
}
uint8 nextPathNibble = uint8(path[pathPtr]);
if (nextPathNibble > 16) {
return false;
}
nodeKey = bytes32(
RLPReader.toUintStrict(currentNodeList[nextPathNibble])
);
pathPtr += 1;
} else if (currentNodeList.length == 2) {
bytes memory nodeValue = RLPReader.toBytes(currentNodeList[0]);
uint256 traversed = _nibblesToTraverse(
nodeValue,
path,
pathPtr
);
//enforce correct nibble
bytes1 prefix = _getNthNibbleOfBytes(0, nodeValue);
if (pathPtr + traversed == path.length) {
//leaf node
if (
keccak256(RLPReader.toBytes(currentNodeList[1])) == keccak256(value) &&
(prefix == bytes1(uint8(2)) || prefix == bytes1(uint8(3)))
) {
return true;
} else {
return false;
}
}
//extension node
if (traversed == 0 || (prefix != bytes1(uint8(0)) && prefix != bytes1(uint8(1)))) {
return false;
}
pathPtr += traversed;
nodeKey = bytes32(RLPReader.toUintStrict(currentNodeList[1]));
} else {
return false;
}
}
}
function _nibblesToTraverse(
bytes memory encodedPartialPath,
bytes memory path,
uint256 pathPtr
) private pure returns (uint256) {
uint256 len;
// encodedPartialPath has elements that are each two hex characters (1 byte), but partialPath
// and slicedPath have elements that are each one hex character (1 nibble)
bytes memory partialPath = _getNibbleArray(encodedPartialPath);
bytes memory slicedPath = new bytes(partialPath.length);
// pathPtr counts nibbles in path
// partialPath.length is a number of nibbles
for (uint256 i = pathPtr; i < pathPtr + partialPath.length; i++) {
bytes1 pathNibble = path[i];
slicedPath[i - pathPtr] = pathNibble;
}
if (keccak256(partialPath) == keccak256(slicedPath)) {
len = partialPath.length;
} else {
len = 0;
}
return len;
}
// bytes b must be hp encoded
function _getNibbleArray(bytes memory b)
private
pure
returns (bytes memory)
{
bytes memory nibbles;
if (b.length > 0) {
uint8 offset;
uint8 hpNibble = uint8(_getNthNibbleOfBytes(0, b));
if (hpNibble == 1 || hpNibble == 3) {
nibbles = new bytes(b.length * 2 - 1);
bytes1 oddNibble = _getNthNibbleOfBytes(1, b);
nibbles[0] = oddNibble;
offset = 1;
} else {
nibbles = new bytes(b.length * 2 - 2);
offset = 0;
}
for (uint256 i = offset; i < nibbles.length; i++) {
nibbles[i] = _getNthNibbleOfBytes(i - offset + 2, b);
}
}
return nibbles;
}
function _getNthNibbleOfBytes(uint256 n, bytes memory str)
private
pure
returns (bytes1)
{
return
bytes1(
n % 2 == 0 ? uint8(str[n / 2]) / 0x10 : uint8(str[n / 2]) % 0x10
);
}
}pragma solidity ^0.5.2;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";
/**
* @title PriorityQueue
* @dev A priority queue implementation.
*/
contract PriorityQueue is Ownable {
using SafeMath for uint256;
uint256[] heapList;
uint256 public currentSize;
constructor() public {
heapList = [0];
}
/**
* @dev Inserts an element into the priority queue.
* @param _priority Priority to insert.
* @param _value Some additional value.
*/
function insert(uint256 _priority, uint256 _value) public onlyOwner {
uint256 element = (_priority << 128) | _value;
heapList.push(element);
currentSize = currentSize.add(1);
_percUp(currentSize);
}
/**
* @dev Returns the top element of the heap.
* @return The smallest element in the priority queue.
*/
function getMin() public view returns (uint256, uint256) {
return _splitElement(heapList[1]);
}
/**
* @dev Deletes the top element of the heap and shifts everything up.
* @return The smallest element in the priorty queue.
*/
function delMin() public onlyOwner returns (uint256, uint256) {
uint256 retVal = heapList[1];
heapList[1] = heapList[currentSize];
delete heapList[currentSize];
currentSize = currentSize.sub(1);
_percDown(1);
heapList.length = heapList.length.sub(1);
return _splitElement(retVal);
}
/**
* @dev Determines the minimum child of a given node in the tree.
* @param _index Index of the node in the tree.
* @return The smallest child node.
*/
function _minChild(uint256 _index) private view returns (uint256) {
if (_index.mul(2).add(1) > currentSize) {
return _index.mul(2);
} else {
if (heapList[_index.mul(2)] < heapList[_index.mul(2).add(1)]) {
return _index.mul(2);
} else {
return _index.mul(2).add(1);
}
}
}
/**
* @dev Bubbles the element at some index up.
*/
function _percUp(uint256 _index) private {
uint256 index = _index;
uint256 j = index;
uint256 newVal = heapList[index];
while (newVal < heapList[index.div(2)]) {
heapList[index] = heapList[index.div(2)];
index = index.div(2);
}
if (index != j) {
heapList[index] = newVal;
}
}
/**
* @dev Bubbles the element at some index down.
*/
function _percDown(uint256 _index) private {
uint256 index = _index;
uint256 j = index;
uint256 newVal = heapList[index];
uint256 mc = _minChild(index);
while (mc <= currentSize && newVal > heapList[mc]) {
heapList[index] = heapList[mc];
index = mc;
mc = _minChild(index);
}
if (index != j) {
heapList[index] = newVal;
}
}
/**
* @dev Split an element into its priority and value.
* @param _element Element to decode.
* @return A tuple containing the priority and value.
*/
function _splitElement(uint256 _element)
private
pure
returns (uint256, uint256)
{
uint256 priority = _element >> 128;
uint256 value = uint256(uint128(_element));
return (priority, value);
}
}// 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.
pragma solidity ^0.5.2;
import "./BytesLib.sol";
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)))));
}
}
}// SPDX-License-Identifier: Apache-2.0 /* * @author Hamdi Allam [email protected] * Please reach out with any questions or concerns */ pragma solidity >=0.5.10 <0.9.0; 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 { uint256 len; uint256 memPtr; } struct Iterator { RLPItem item; // Item that's being iterated over. uint256 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)); uint256 ptr = self.nextPtr; uint256 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) { uint256 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)); uint256 ptr = self.memPtr + _payloadOffset(self.memPtr); return Iterator(self, ptr); } /* * @param the RLP item. */ function rlpLen(RLPItem memory item) internal pure returns (uint256) { return item.len; } /* * @param the RLP item. * @return (memPtr, len) pair: location of the item's payload in memory. */ function payloadLocation(RLPItem memory item) internal pure returns (uint256, uint256) { uint256 offset = _payloadOffset(item.memPtr); uint256 memPtr = item.memPtr + offset; uint256 len = item.len - offset; // data length return (memPtr, len); } /* * @param the RLP item. */ function payloadLen(RLPItem memory item) internal pure returns (uint256) { (, uint256 len) = payloadLocation(item); return len; } /* * @param the RLP item containing the encoded list. */ function toList(RLPItem memory item) internal pure returns (RLPItem[] memory) { require(isList(item)); uint256 items = numItems(item); RLPItem[] memory result = new RLPItem[](items); uint256 memPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 dataLen; for (uint256 i = 0; i < items; i++) { dataLen = _itemLength(memPtr); result[i] = RLPItem(dataLen, memPtr); memPtr = memPtr + dataLen; } // New check to see if the last mempointer of the last read item has moved farther than the parent item is long require(memPtr - item.memPtr == item.len, "Wrong total length."); 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; uint256 memPtr = item.memPtr; assembly { byte0 := byte(0, mload(memPtr)) } if (byte0 < LIST_SHORT_START) return false; return true; } /* * @dev A cheaper version of keccak256(toRlpBytes(item)) that avoids copying memory. * @return keccak256 hash of RLP encoded bytes. */ function rlpBytesKeccak256(RLPItem memory item) internal pure returns (bytes32) { uint256 ptr = item.memPtr; uint256 len = item.len; bytes32 result; assembly { result := keccak256(ptr, len) } return result; } /* * @dev A cheaper version of keccak256(toBytes(item)) that avoids copying memory. * @return keccak256 hash of the item payload. */ function payloadKeccak256(RLPItem memory item) internal pure returns (bytes32) { (uint256 memPtr, uint256 len) = payloadLocation(item); bytes32 result; assembly { result := keccak256(memPtr, len) } return result; } /** 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; uint256 ptr; assembly { ptr := add(0x20, result) } copy(item.memPtr, ptr, item.len); return result; } // any non-zero byte except "0x80" is considered true function toBoolean(RLPItem memory item) internal pure returns (bool) { require(item.len == 1); uint256 result; uint256 memPtr = item.memPtr; assembly { result := byte(0, mload(memPtr)) } // SEE Github Issue #5. // Summary: Most commonly used RLP libraries (i.e Geth) will encode // "0" as "0x80" instead of as "0". We handle this edge case explicitly // here. if (result == 0 || result == STRING_SHORT_START) { return false; } else { return true; } } function toAddress(RLPItem memory item) internal pure returns (address) { // 1 byte for the length prefix require(item.len == 21); return address(uint160(toUint(item))); } function toUint(RLPItem memory item) internal pure returns (uint256) { require(item.len > 0 && item.len <= 33); (uint256 memPtr, uint256 len) = payloadLocation(item); uint256 result; assembly { result := mload(memPtr) // shift 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 (uint256) { // one byte prefix require(item.len == 33); uint256 result; uint256 memPtr = item.memPtr + 1; assembly { result := mload(memPtr) } return result; } function toBytes(RLPItem memory item) internal pure returns (bytes memory) { require(item.len > 0); (uint256 memPtr, uint256 len) = payloadLocation(item); bytes memory result = new bytes(len); uint256 destPtr; assembly { destPtr := add(0x20, result) } copy(memPtr, destPtr, len); return result; } /* * Private Helpers */ // @return number of payload items inside an encoded list. function numItems(RLPItem memory item) private pure returns (uint256) { if (item.len == 0) return 0; uint256 count = 0; uint256 currPtr = item.memPtr + _payloadOffset(item.memPtr); uint256 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(uint256 memPtr) private pure returns (uint256) { uint256 itemLen; uint256 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(uint256 memPtr) private pure returns (uint256) { uint256 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(uint256 src, uint256 dest, uint256 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; } if (len > 0) { // left over bytes. Mask is used to remove unwanted bytes from the word uint256 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)) } } } }
pragma solidity ^0.5.2;
import {Ownable} from "openzeppelin-solidity/contracts/ownership/Ownable.sol";
contract ProxyStorage is Ownable {
address internal proxyTo;
}pragma solidity ^0.5.2;
contract ChainIdMixin {
bytes constant public networkId = hex"6D";
uint256 constant public CHAINID = 109;
}pragma solidity ^0.5.2;
import {Governable} from "../governance/Governable.sol";
import {Lockable} from "./Lockable.sol";
contract GovernanceLockable is Lockable, Governable {
constructor(address governance) public Governable(governance) {}
function lock() public onlyGovernance {
super.lock();
}
function unlock() public onlyGovernance {
super.unlock();
}
}pragma solidity ^0.5.2;
contract Lockable {
bool public locked;
modifier onlyWhenUnlocked() {
_assertUnlocked();
_;
}
function _assertUnlocked() private view {
require(!locked, "locked");
}
function lock() public {
locked = true;
}
function unlock() public {
locked = false;
}
}pragma solidity ^0.5.2;
import {Governable} from "./governance/Governable.sol";
import {IWithdrawManager} from "../root/withdrawManager/IWithdrawManager.sol";
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];
}
}pragma solidity ^0.5.2;
import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol";
contract WETH is ERC20 {
event Deposit(address indexed dst, uint256 wad);
event Withdrawal(address indexed src, uint256 wad);
function deposit() public payable;
function withdraw(uint256 wad) public;
function withdraw(uint256 wad, address user) public;
}pragma solidity ^0.5.2;
import {ERC721Holder} from "openzeppelin-solidity/contracts/token/ERC721/ERC721Holder.sol";
import {IERC20} from "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import {IERC721} from "openzeppelin-solidity/contracts/token/ERC721/IERC721.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import {SafeERC20} from "openzeppelin-solidity/contracts/token/ERC20/SafeERC20.sol";
import {Registry} from "../../common/Registry.sol";
import {WETH} from "../../common/tokens/WETH.sol";
import {IDepositManager} from "./IDepositManager.sol";
import {DepositManagerStorage} from "./DepositManagerStorage.sol";
import {StateSender} from "../stateSyncer/StateSender.sol";
import {GovernanceLockable} from "../../common/mixin/GovernanceLockable.sol";
import {RootChain} from "../RootChain.sol";
contract DepositManager is DepositManagerStorage, IDepositManager, ERC721Holder {
using SafeMath for uint256;
using SafeERC20 for IERC20;
modifier isTokenMapped(address _token) {
require(registry.isTokenMapped(_token), "TOKEN_NOT_SUPPORTED");
_;
}
modifier isPredicateAuthorized() {
require(uint8(registry.predicates(msg.sender)) != 0, "Not a valid predicate");
_;
}
constructor() public GovernanceLockable(address(0x0)) {}
// deposit ETH by sending to this contract
function() external payable {
depositEther();
}
function updateMaxErc20Deposit(uint256 maxDepositAmount) public onlyGovernance {
require(maxDepositAmount != 0);
emit MaxErc20DepositUpdate(maxErc20Deposit, maxDepositAmount);
maxErc20Deposit = maxDepositAmount;
}
function transferAssets(
address _token,
address _user,
uint256 _amountOrNFTId
) external isPredicateAuthorized {
address wethToken = registry.getWethTokenAddress();
if (registry.isERC721(_token)) {
IERC721(_token).transferFrom(address(this), _user, _amountOrNFTId);
} else if (_token == wethToken) {
WETH t = WETH(_token);
t.withdraw(_amountOrNFTId, _user);
} else {
require(IERC20(_token).transfer(_user, _amountOrNFTId), "TRANSFER_FAILED");
}
}
function depositERC20(address _token, uint256 _amount) external {
depositERC20ForUser(_token, msg.sender, _amount);
}
function depositERC721(address _token, uint256 _tokenId) external {
depositERC721ForUser(_token, msg.sender, _tokenId);
}
function depositBulk(
address[] calldata _tokens,
uint256[] calldata _amountOrTokens,
address _user
)
external
onlyWhenUnlocked // unlike other deposit functions, depositBulk doesn't invoke _safeCreateDepositBlock
{
require(_tokens.length == _amountOrTokens.length, "Invalid Input");
uint256 depositId = rootChain.updateDepositId(_tokens.length);
Registry _registry = registry;
for (uint256 i = 0; i < _tokens.length; i++) {
// will revert if token is not mapped
if (_registry.isTokenMappedAndIsErc721(_tokens[i])) {
_safeTransferERC721(msg.sender, _tokens[i], _amountOrTokens[i]);
} else {
IERC20(_tokens[i]).safeTransferFrom(msg.sender, address(this), _amountOrTokens[i]);
}
_createDepositBlock(_user, _tokens[i], _amountOrTokens[i], depositId);
depositId = depositId.add(1);
}
}
/**
* @dev Caches childChain and stateSender (frequently used variables) from registry
*/
function updateChildChainAndStateSender() public {
(address _childChain, address _stateSender) = registry.getChildChainAndStateSender();
require(
_stateSender != address(stateSender) || _childChain != childChain,
"Atleast one of stateSender or childChain address should change"
);
childChain = _childChain;
stateSender = StateSender(_stateSender);
}
function depositERC20ForUser(
address _token,
address _user,
uint256 _amount
) public {
require(_amount <= maxErc20Deposit, "exceed maximum deposit amount");
IERC20(_token).safeTransferFrom(msg.sender, address(this), _amount);
_safeCreateDepositBlock(_user, _token, _amount);
}
function depositERC721ForUser(
address _token,
address _user,
uint256 _tokenId
) public {
require(registry.isTokenMappedAndIsErc721(_token), "not erc721");
_safeTransferERC721(msg.sender, _token, _tokenId);
_safeCreateDepositBlock(_user, _token, _tokenId);
}
// @todo: write depositEtherForUser
function depositEther() public payable {
address wethToken = registry.getWethTokenAddress();
WETH t = WETH(wethToken);
t.deposit.value(msg.value)();
_safeCreateDepositBlock(msg.sender, wethToken, msg.value);
}
function _safeCreateDepositBlock(
address _user,
address _token,
uint256 _amountOrToken
) internal onlyWhenUnlocked isTokenMapped(_token) {
_createDepositBlock(
_user,
_token,
_amountOrToken,
rootChain.updateDepositId(1) /* returns _depositId */
);
}
function _createDepositBlock(
address _user,
address _token,
uint256 _amountOrToken,
uint256 _depositId
) internal {
deposits[_depositId] = DepositBlock(keccak256(abi.encodePacked(_user, _token, _amountOrToken)), now);
stateSender.syncState(childChain, abi.encode(_user, _token, _amountOrToken, _depositId));
emit NewDepositBlock(_user, _token, _amountOrToken, _depositId);
}
// Housekeeping function. @todo remove later
function updateRootChain(address _rootChain) public onlyOwner {
rootChain = RootChain(_rootChain);
}
function _safeTransferERC721(address _user, address _token, uint256 _tokenId) private {
IERC721(_token).safeTransferFrom(_user, address(this), _tokenId);
}
}pragma solidity ^0.5.2;
import {Registry} from "../../common/Registry.sol";
import {RootChain} from "../RootChain.sol";
import {ProxyStorage} from "../../common/misc/ProxyStorage.sol";
import {StateSender} from "../stateSyncer/StateSender.sol";
import {GovernanceLockable} from "../../common/mixin/GovernanceLockable.sol";
contract DepositManagerHeader {
event NewDepositBlock(address indexed owner, address indexed token, uint256 amountOrNFTId, uint256 depositBlockId);
event MaxErc20DepositUpdate(uint256 indexed oldLimit, uint256 indexed newLimit);
struct DepositBlock {
bytes32 depositHash;
uint256 createdAt;
}
}
contract DepositManagerStorage is ProxyStorage, GovernanceLockable, DepositManagerHeader {
Registry public registry;
RootChain public rootChain;
StateSender public stateSender;
mapping(uint256 => DepositBlock) public deposits;
address public childChain;
uint256 public maxErc20Deposit = 100 * (10**18);
}pragma solidity ^0.5.2;
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;
}pragma solidity ^0.5.2;
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);
}pragma solidity ^0.5.2;
import {RLPReader} from "../../common/lib/RLPReader.sol";
import {Common} from "../../common/lib/Common.sol";
import {RLPEncode} from "../../common/lib/RLPEncode.sol";
import {IWithdrawManager} from "../withdrawManager/IWithdrawManager.sol";
import {IDepositManager} from "../depositManager/IDepositManager.sol";
import {ExitsDataStructure} from "../withdrawManager/WithdrawManagerStorage.sol";
import {ChainIdMixin} from "../../common/mixin/ChainIdMixin.sol";
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())
);
require(signer != address(0), "Invalid signer");
}
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);
}
}pragma solidity ^0.5.2;
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";
import {RootChainHeader, RootChainStorage} from "./RootChainStorage.sol";
import {IStakeManager} from "../staking/stakeManager/IStakeManager.sol";
import {IRootChain} from "./IRootChain.sol";
import {Registry} from "../common/Registry.sol";
contract RootChain is RootChainStorage, IRootChain {
using SafeMath for uint256;
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));
}
}pragma solidity ^0.5.2;
import {Registry} from "../common/Registry.sol";
import {ProxyStorage} from "../common/misc/ProxyStorage.sol";
import {ChainIdMixin} from "../common/mixin/ChainIdMixin.sol";
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;
}pragma solidity ^0.5.2;
import {Ownable} from "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import {SafeMath} from "openzeppelin-solidity/contracts/math/SafeMath.sol";
contract StateSender is Ownable {
using SafeMath for uint256;
uint256 public counter;
mapping(address => address) public registrations;
event NewRegistration(
address indexed user,
address indexed sender,
address indexed receiver
);
event RegistrationUpdated(
address indexed user,
address indexed sender,
address indexed receiver
);
event StateSynced(
uint256 indexed id,
address indexed contractAddress,
bytes data
);
modifier onlyRegistered(address receiver) {
require(registrations[receiver] == msg.sender, "Invalid sender");
_;
}
function syncState(address receiver, bytes calldata data)
external
onlyRegistered(receiver)
{
counter = counter.add(1);
emit StateSynced(counter, receiver, data);
}
// register new contract for state sync
function register(address sender, address receiver) public {
require(
isOwner() || registrations[receiver] == msg.sender,
"StateSender.register: Not authorized to register"
);
registrations[receiver] = sender;
if (registrations[receiver] == address(0)) {
emit NewRegistration(msg.sender, sender, receiver);
} else {
emit RegistrationUpdated(msg.sender, sender, receiver);
}
}
}pragma solidity ^0.5.2;
import {ERC721} from "openzeppelin-solidity/contracts/token/ERC721/ERC721.sol";
import {Registry} from "../../common/Registry.sol";
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);
}
}pragma solidity ^0.5.2;
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;
}pragma solidity ^0.5.2;
import {ProxyStorage} from "../../common/misc/ProxyStorage.sol";
import {Registry} from "../../common/Registry.sol";
import {RootChain} from "../RootChain.sol";
import {ExitNFT} from "./ExitNFT.sol";
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;
}pragma solidity 0.5.17;
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;
}pragma solidity ^0.5.2;
import "../math/SafeMath.sol";
/**
* @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);
}
}pragma solidity ^0.5.2;
import "./IERC165.sol";
/**
* @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;
}
}pragma solidity ^0.5.2;
/**
* @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);
}pragma solidity ^0.5.2;
/**
* @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);
}
}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;
}
}pragma solidity ^0.5.2;
/**
* @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;
}
}pragma solidity ^0.5.2;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* https://eips.ethereum.org/EIPS/eip-20
* Originally based on code by FirstBlood:
* https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*
* This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for
* all accounts just by listening to said events. Note that this isn't required by the specification, and other
* compliant implementations may not do it.
*/
contract ERC20 is IERC20 {
using SafeMath for uint256;
mapping (address => uint256) private _balances;
mapping (address => mapping (address => uint256)) private _allowed;
uint256 private _totalSupply;
/**
* @dev Total number of tokens in existence
*/
function totalSupply() public view returns (uint256) {
return _totalSupply;
}
/**
* @dev Gets the balance of the specified address.
* @param owner The address to query the balance of.
* @return A uint256 representing the amount owned by the passed address.
*/
function balanceOf(address owner) public view returns (uint256) {
return _balances[owner];
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param owner address The address which owns the funds.
* @param spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address owner, address spender) public view returns (uint256) {
return _allowed[owner][spender];
}
/**
* @dev Transfer token to a specified address
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function transfer(address to, uint256 value) public returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* Beware that changing an allowance with this method brings the risk that someone may use both the old
* and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this
* race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
* @param spender The address which will spend the funds.
* @param value The amount of tokens to be spent.
*/
function approve(address spender, uint256 value) public returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
/**
* @dev Transfer tokens from one address to another.
* Note that while this function emits an Approval event, this is not required as per the specification,
* and other compliant implementations may not emit the event.
* @param from address The address which you want to send tokens from
* @param to address The address which you want to transfer to
* @param value uint256 the amount of tokens to be transferred
*/
function transferFrom(address from, address to, uint256 value) public returns (bool) {
_transfer(from, to, value);
_approve(from, msg.sender, _allowed[from][msg.sender].sub(value));
return true;
}
/**
* @dev Increase the amount of tokens that an owner allowed to a spender.
* approve should be called when _allowed[msg.sender][spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param addedValue The amount of tokens to increase the allowance by.
*/
function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));
return true;
}
/**
* @dev Decrease the amount of tokens that an owner allowed to a spender.
* approve should be called when _allowed[msg.sender][spender] == 0. To decrement
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
* Emits an Approval event.
* @param spender The address which will spend the funds.
* @param subtractedValue The amount of tokens to decrease the allowance by.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {
_approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));
return true;
}
/**
* @dev Transfer token for a specified addresses
* @param from The address to transfer from.
* @param to The address to transfer to.
* @param value The amount to be transferred.
*/
function _transfer(address from, address to, uint256 value) internal {
require(to != address(0));
_balances[from] = _balances[from].sub(value);
_balances[to] = _balances[to].add(value);
emit Transfer(from, to, value);
}
/**
* @dev Internal function that mints an amount of the token and assigns it to
* an account. This encapsulates the modification of balances such that the
* proper events are emitted.
* @param account The account that will receive the created tokens.
* @param value The amount that will be created.
*/
function _mint(address account, uint256 value) internal {
require(account != address(0));
_totalSupply = _totalSupply.add(value);
_balances[account] = _balances[account].add(value);
emit Transfer(address(0), account, value);
}
/**
* @dev Internal function that burns an amount of the token of a given
* account.
* @param account The account whose tokens will be burnt.
* @param value The amount that will be burnt.
*/
function _burn(address account, uint256 value) internal {
require(account != address(0));
_totalSupply = _totalSupply.sub(value);
_balances[account] = _balances[account].sub(value);
emit Transfer(account, address(0), value);
}
/**
* @dev Approve an address to spend another addresses' tokens.
* @param owner The address that owns the tokens.
* @param spender The address that will spend the tokens.
* @param value The number of tokens that can be spent.
*/
function _approve(address owner, address spender, uint256 value) internal {
require(spender != address(0));
require(owner != address(0));
_allowed[owner][spender] = value;
emit Approval(owner, spender, value);
}
/**
* @dev Internal function that burns an amount of the token of a given
* account, deducting from the sender's allowance for said account. Uses the
* internal burn function.
* Emits an Approval event (reflecting the reduced allowance).
* @param account The account whose tokens will be burnt.
* @param value The amount that will be burnt.
*/
function _burnFrom(address account, uint256 value) internal {
_burn(account, value);
_approve(account, msg.sender, _allowed[account][msg.sender].sub(value));
}
}pragma solidity ^0.5.2;
/**
* @title ERC20 interface
* @dev see https://eips.ethereum.org/EIPS/eip-20
*/
interface IERC20 {
function transfer(address to, uint256 value) external returns (bool);
function approve(address spender, uint256 value) external returns (bool);
function transferFrom(address from, address to, uint256 value) external returns (bool);
function totalSupply() external view returns (uint256);
function balanceOf(address who) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}pragma solidity ^0.5.2;
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require((value == 0) || (token.allowance(address(this), spender) == 0));
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must equal true).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
require(address(token).isContract());
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success);
if (returndata.length > 0) { // Return data is optional
require(abi.decode(returndata, (bool)));
}
}
}pragma solidity ^0.5.2;
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";
import "../../drafts/Counters.sol";
import "../../introspection/ERC165.sol";
/**
* @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);
}
}
}pragma solidity ^0.5.2;
import "./IERC721Receiver.sol";
contract ERC721Holder is IERC721Receiver {
function onERC721Received(address, address, uint256, bytes memory) public returns (bytes4) {
return this.onERC721Received.selector;
}
}pragma solidity ^0.5.2;
import "../../introspection/IERC165.sol";
/**
* @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;
}pragma solidity ^0.5.2;
/**
* @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);
}pragma solidity ^0.5.2;
/**
* 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;
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"}],"name":"ExitCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldExitPeriod","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newExitPeriod","type":"uint256"}],"name":"ExitPeriodUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"exitor","type":"address"},{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"isRegularExit","type":"bool"}],"name":"ExitStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"age","type":"uint256"},{"indexed":false,"internalType":"address","name":"signer","type":"address"}],"name":"ExitUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"exitId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":true,"inputs":[],"name":"HALF_EXIT_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ON_FINALIZE_GAS_LIMIT","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"exitor","type":"address"},{"internalType":"address","name":"childToken","type":"address"},{"internalType":"address","name":"rootToken","type":"address"},{"internalType":"uint256","name":"exitAmountOrTokenId","type":"uint256"},{"internalType":"bytes32","name":"txHash","type":"bytes32"},{"internalType":"bool","name":"isRegularExit","type":"bool"},{"internalType":"uint256","name":"priority","type":"uint256"}],"name":"addExitToQueue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"exitId","type":"uint256"},{"internalType":"uint256","name":"age","type":"uint256"},{"internalType":"address","name":"utxoOwner","type":"address"},{"internalType":"address","name":"token","type":"address"}],"name":"addInput","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"exitId","type":"uint256"},{"internalType":"uint256","name":"inputId","type":"uint256"},{"internalType":"bytes","name":"challengeData","type":"bytes"},{"internalType":"address","name":"adjudicatorPredicate","type":"address"}],"name":"challengeExit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"createExitQueue","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exitNft","outputs":[{"internalType":"contract ExitNFT","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"exitWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"exits","outputs":[{"internalType":"uint256","name":"receiptAmountOrNFTId","type":"uint256"},{"internalType":"bytes32","name":"txHash","type":"bytes32"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"token","type":"address"},{"internalType":"bool","name":"isRegularExit","type":"bool"},{"internalType":"address","name":"predicate","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"exitsQueues","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isOwner","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"ownerExits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"processExits","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"processExitsBatch","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"renounceOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"depositId","type":"uint256"},{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountOrToken","type":"uint256"}],"name":"startExitWithDepositedTokens","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"halfExitPeriod","type":"uint256"}],"name":"updateExitPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint8","name":"offset","type":"uint8"},{"internalType":"bool","name":"verifyTxInclusion","type":"bool"}],"name":"verifyInclusion","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]Contract Creation Code
6080604081905262049d406002556009805461249f60a51b63ffffffff60a01b19909116179055600080546001600160a01b03191633178082556001600160a01b0316917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3613d72806100776000396000f3fe6080604052600436106200013a5760003560e01c80639145e6df11620000af578063d11f045c116200006d578063d11f045c1462000571578063d931a86914620005a8578063ed4a0be81462000609578063edeca09b1462000621578063f2fde38b1462000639576200013a565b80639145e6df146200035d5780639492b0b8146200039457806396cbd812146200042d578063ad1d8069146200045e578063c74ab88a14620004ed576200013a565b8063433c76bf11620000fd578063433c76bf1462000289578063661429c814620002b7578063715018a614620002e55780638da5cb5b14620002fd5780638f32d59b1462000331576200013a565b80630f6795f2146200013c578063144a03b314620001735780631e29848b14620001a857806322f192af14620001d2578063342de179146200021d575b005b3480156200014957600080fd5b506200013a600480360360208110156200016257600080fd5b50356001600160a01b031662000670565b6200013a600480360360608110156200018b57600080fd5b508035906001600160a01b03602082013516906040013562000bed565b348015620001b557600080fd5b50620001c062000c45565b60408051918252519081900360200190f35b348015620001df57600080fd5b506200013a60048036036080811015620001f857600080fd5b508035906020810135906001600160a01b036040820135811691606001351662000c4b565b3480156200022a57600080fd5b506200024b600480360360208110156200024357600080fd5b503562000d96565b6040805196875260208701959095526001600160a01b03938416868601529183166060860152151560808501521660a0830152519081900360c00190f35b3480156200029657600080fd5b506200013a60048036036020811015620002af57600080fd5b503562000ddf565b348015620002c457600080fd5b50620001c060048036036020811015620002dd57600080fd5b503562000e27565b348015620002f257600080fd5b506200013a62000e39565b3480156200030a57600080fd5b506200031562000e97565b604080516001600160a01b039092168252519081900360200190f35b3480156200033e57600080fd5b506200034962000ea6565b604080519115158252519081900360200190f35b3480156200036a57600080fd5b506200013a600480360360208110156200038357600080fd5b50356001600160a01b031662000eb7565b348015620003a157600080fd5b506200013a60048036036080811015620003ba57600080fd5b813591602081013591810190606081016040820135640100000000811115620003e257600080fd5b820183602082011115620003f557600080fd5b803590602001918460018302840111640100000000831117156200041857600080fd5b9193509150356001600160a01b031662000f71565b3480156200043a57600080fd5b506200044562001362565b6040805163ffffffff9092168252519081900360200190f35b3480156200046b57600080fd5b50620001c0600480360360608110156200048457600080fd5b810190602081018135640100000000811115620004a057600080fd5b820183602082011115620004b357600080fd5b80359060200191846001830284011164010000000083111715620004d657600080fd5b919350915060ff8135169060200135151562001375565b348015620004fa57600080fd5b506200013a600480360360208110156200051357600080fd5b8101906020810181356401000000008111156200052f57600080fd5b8201836020820111156200054257600080fd5b803590602001918460208302840111640100000000831117156200056557600080fd5b50909250905062001655565b3480156200057e57600080fd5b5062000315600480360360208110156200059757600080fd5b50356001600160a01b031662001691565b348015620005b557600080fd5b506200013a600480360360e0811015620005ce57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060808101359060a081013515159060c00135620016ac565b3480156200061657600080fd5b50620001c062001afb565b3480156200062e57600080fd5b506200031562001b01565b3480156200064657600080fd5b506200013a600480360360208110156200065f57600080fd5b50356001600160a01b031662001b10565b6001600160a01b0380821660009081526008602052604081205490918291165b6000816001600160a01b031663bda1504b6040518163ffffffff1660e01b815260040160206040518083038186803b158015620006cc57600080fd5b505afa158015620006e1573d6000803e3d6000fd5b505050506040513d6020811015620006f857600080fd5b5051118015620007165750600954600160a01b900463ffffffff165a115b1562000be657806001600160a01b031663d6362e976040518163ffffffff1660e01b8152600401604080518083038186803b1580156200075557600080fd5b505afa1580156200076a573d6000803e3d6000fd5b505050506040513d60408110156200078157600080fd5b508051602090910151909350608084901b1791506200079f62003381565b50600082815260066020908152604091829020825160c0810184528154815260018201549281019290925260028101546001600160a01b039081169383019390935260038101548084166060840152600160a01b900460ff16151560808301526004015490911660a0820152428411156200081e575050505062000bea565b816001600160a01b031663b07576ac6040518163ffffffff1660e01b81526004016040805180830381600087803b1580156200085957600080fd5b505af11580156200086e573d6000803e3d6000fd5b505050506040513d60408110156200088557600080fd5b505060095460408051634f558e7960e01b81526004810186905290516001600160a01b0390921691634f558e7991602480820192602092909190829003018186803b158015620008d457600080fd5b505afa158015620008e9573d6000803e3d6000fd5b505050506040513d60208110156200090057600080fd5b50516200090e575062000690565b600954604080516331a9108f60e11b81526004810186905290516000926001600160a01b031691636352211e916024808301926020929190829003018186803b1580156200095b57600080fd5b505afa15801562000970573d6000803e3d6000fd5b505050506040513d60208110156200098757600080fd5b505160008581526006602052604080822060020180546001600160a01b0319166001600160a01b03808616919091179091556009548251630852cd8d60e31b8152600481018a9052925194955016926342966c689260248084019391929182900301818387803b158015620009fb57600080fd5b505af115801562000a10573d6000803e3d6000fd5b505050508160a001516001600160a01b031662000a2d8562001b2f565b6040516024018080602001828103825283818151815260200191508051906020019080838360005b8381101562000a6f57818101518382015260200162000a55565b50505050905090810190601f16801562000a9d5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316637bd94e0360e01b178152905182519295509350839250908083835b6020831062000afa5780518252601f19909201916020918201910162000ad9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811462000b5e576040519150601f19603f3d011682016040523d82523d6000602084013e62000b63565b606091505b5050825160408051918252516001600160a01b03808a16935084169187917ffeb2000dca3e617cd6f3a8bbb63014bb54a124aac6ccbf73ee7229b4cd01f1209181900360200190a4816080015162000bde576040516001600160a01b0382169060009067016345785d8a00009082818181858883f150505050505b505062000690565b5050505b50565b67016345785d8a0000341462000c40576040805162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908109bdb9908185b5bdd5b9d606a1b604482015290519081900360640190fd5b505050565b600a5481565b600354604080516337b1d58560e01b815233600482015290516000926001600160a01b0316916337b1d585916024808301926020929190829003018186803b15801562000c9757600080fd5b505afa15801562000cac573d6000803e3d6000fd5b505050506040513d602081101562000cc357600080fd5b5051600381111562000cd157fe5b141562000d20576040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b600084815260066020526040902060028101546001600160a01b031662000d80576040805162461bcd60e51b815260206004820152600f60248201526e1253959053125117d156125517d251608a1b604482015290519081900360640190fd5b62000d8f858585338662001b8c565b5050505050565b60066020526000908152604090208054600182015460028301546003840154600490940154929391926001600160a01b039182169282811692600160a01b90910460ff16911686565b62000de962000ea6565b62000df357600080fd5b6002546040518291907f06b98f3947a8966918fef150b41170e78ba1d91dd2b1d2fd48a59c91ffbd66a190600090a3600255565b60076020526000908152604090205481565b62000e4362000ea6565b62000e4d57600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b6003546001600160a01b0316331462000f17576040805162461bcd60e51b815260206004820152601a60248201527f554e415554484f52495a45445f52454749535452595f4f4e4c59000000000000604482015290519081900360640190fd5b60405162000f2590620033b6565b604051809103906000f08015801562000f42573d6000803e3d6000fd5b506001600160a01b03918216600090815260086020526040902080546001600160a01b03191691909216179055565b60008581526006602090815260408083208784526005810190925290912060028201546001600160a01b03161580159062000fb5575080546001600160a01b031615155b62001007576040805162461bcd60e51b815260206004820152601860248201527f496e76616c69642065786974206f7220696e7075742069640000000000000000604482015290519081900360640190fd5b6000600354604080516337b1d58560e01b81526001600160a01b038781166004830152915191909216916337b1d585916024808301926020929190829003018186803b1580156200105757600080fd5b505afa1580156200106c573d6000803e3d6000fd5b505050506040513d60208110156200108357600080fd5b505160038111156200109157fe5b1415620010d9576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f50524544494341544560781b604482015290519081900360640190fd5b826001600160a01b031663ec58410c620010f38462001c4b565b620010ff898562001d3a565b88886040518563ffffffff1660e01b815260040180806020018060200180602001848103845288818151815260200191508051906020019080838360005b83811015620011575781810151838201526020016200113d565b50505050905090810190601f168015620011855780820380516001836020036101000a031916815260200191505b50848103835287518152875160209182019189019080838360005b83811015620011ba578181015183820152602001620011a0565b50505050905090810190601f168015620011e85780820380516001836020036101000a031916815260200191505b508481038252858152602001868680828437600081840152601f19601f820116905080830192505050975050505050505050602060405180830381600087803b1580156200123557600080fd5b505af11580156200124a573d6000803e3d6000fd5b505050506040513d60208110156200126157600080fd5b5051620012a8576040805162461bcd60e51b815260206004820152601060248201526f10da185b1b195b99d94819985a5b195960821b604482015290519081900360640190fd5b60095460408051630852cd8d60e31b8152600481018a905290516001600160a01b03909216916342966c689160248082019260009290919082900301818387803b158015620012f657600080fd5b505af11580156200130b573d6000803e3d6000fd5b50506040513392506000915067016345785d8a00009082818181858883f150506040518a93507f93a8052a01c184f88312af177ab8fae2e56a9973b6aa4bdc62dfcf744e09d041925060009150a250505050505050565b600954600160a01b900463ffffffff1681565b600062001381620033c4565b620013c286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062001e1492505050565b9050620013ce620033d7565b620013d98262001e4a565b8152620013e68262001e76565b60c082018190528051600090620013f957fe5b01602001516001600160f81b031916156200144c576040805162461bcd60e51b815260206004820152600e60248201526d696e636f7272656374206d61736b60901b604482015290519081900360640190fd5b620014578262001e9c565b6080820152620014678262001eb4565b60a0820152620014a0620014856200147f8462001ecc565b62001fb7565b8260c00151620014958562001fbe565b8460a0015162001fd6565b620014f2576040805162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f524543454950545f4d45524b4c455f50524f4f4600000000604482015290519081900360640190fd5b83156200157557620015236200150883620022de565b8260c001516200151885620022f6565b846080015162001fd6565b62001575576040805162461bcd60e51b815260206004820152601760248201527f494e56414c49445f54585f4d45524b4c455f50524f4f46000000000000000000604482015290519081900360640190fd5b62001580826200230e565b60208201819052620015b490620015978462002326565b608084015160a08501518551620015ae886200233e565b62002356565b6040820152620015c482620024ba565b6060820181905263ffffffff19161562001625576040805162461bcd60e51b815260206004820152601d60248201527f4272616e6368206d61736b2073686f756c642062652033322062697473000000604482015290519081900360640190fd5b806060015160208260200151901b607f620016448460400151620024d2565b901b1717925050505b949350505050565b60005b8181101562000c4057620016888383838181106200167257fe5b905060200201356001600160a01b031662000670565b60010162001658565b6008602052600090815260409020546001600160a01b031681565b600354604080516337b1d58560e01b8152336004820152905187926000926001600160a01b03909116916337b1d58591602480820192602092909190829003018186803b158015620016fd57600080fd5b505afa15801562001712573d6000803e3d6000fd5b505050506040513d60208110156200172957600080fd5b505160035460408051633a9831f160e21b81526001600160a01b0386811660048301529151939450600093919092169163ea60c7c4916024808301926020929190829003018186803b1580156200177f57600080fd5b505afa15801562001794573d6000803e3d6000fd5b505050506040513d6020811015620017ab57600080fd5b50516001600160a01b031614156200180a576040805162461bcd60e51b815260206004820152601760248201527f726f6f74546f6b656e206e6f7420737570706f72746564000000000000000000604482015290519081900360640190fd5b60018160038111156200181957fe5b1415620018e057600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200186e57600080fd5b505afa15801562001883573d6000803e3d6000fd5b505050506040513d60208110156200189a57600080fd5b505115620018da5760405162461bcd60e51b815260040180806020018281038252602481526020018062003cf76024913960400191505060405180910390fd5b62001a18565b6002816003811115620018ef57fe5b1415620019b457600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200194457600080fd5b505afa15801562001959573d6000803e3d6000fd5b505050506040513d60208110156200197057600080fd5b50511515600114620018da5760405162461bcd60e51b815260040180806020018281038252602581526020018062003ca56025913960400191505060405180910390fd5b6003816003811115620019c357fe5b1415620019d05762001a18565b6040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b60035460408051633a9831f160e21b81526001600160a01b038a811660048301529151828c16939092169163ea60c7c491602480820192602092909190829003018186803b15801562001a6a57600080fd5b505afa15801562001a7f573d6000803e3d6000fd5b505050506040513d602081101562001a9657600080fd5b50516001600160a01b03161462001adf5760405162461bcd60e51b815260040180806020018281038252602381526020018062003d1b6023913960400191505060405180910390fd5b62001af089888888888833620024eb565b505050505050505050565b60025481565b6009546001600160a01b031681565b62001b1a62000ea6565b62001b2457600080fd5b62000bea8162002873565b60008181526006602090815260409182902060038101546002820154915484519384018690526001600160a01b0391821684860152911660608301526080808301919091528251808303909101815260a09091019091525b919050565b604080516060810182526001600160a01b03808616808352858216602080850191825286841685870190815260008c8152600683528781208c82526005018352879020955186549086166001600160a01b03199182161787559251600187018054918716918516919091179055516002909501805495909416949091169390931790915582519081529151869288927f87d2daa6e85f166015ebbcf09f5ee4bc50f93677579339fe128e3561a6807cb692918290030190a35050505050565b6002810154600380549083015460408051633a9831f160e21b81526001600160a01b03928316600482015290516060948316939092169163ea60c7c491602480820192602092909190829003018186803b15801562001ca957600080fd5b505afa15801562001cbe573d6000803e3d6000fd5b505050506040513d602081101562001cd557600080fd5b5051835460018501546003860154604080516001600160a01b03968716602082015295909416858501526060850192909252608084015260ff600160a01b90910416151560a0808401919091528151808403909101815260c090920190529050919050565b80546001820154600354600284015460408051633a9831f160e21b81526001600160a01b039283166004820152905160609588959084169490841693169163ea60c7c4916024808301926020929190829003018186803b15801562001d9e57600080fd5b505afa15801562001db3573d6000803e3d6000fd5b505050506040513d602081101562001dca57600080fd5b50516040805160208101959095526001600160a01b03938416858201529183166060850152919091166080808401919091528151808403909101815260a090920190529392505050565b62001e1e620033c4565b606062001e3562001e2f84620028e2565b62002909565b60408051602081019091529081529392505050565b600062001e70826000015160008151811062001e6257fe5b602002602001015162002a3c565b92915050565b606062001e70826000015160088151811062001e8e57fe5b602002602001015162002a8e565b600062001e70826000015160048151811062001e6257fe5b600062001e70826000015160058151811062001e6257fe5b62001ed66200341a565b62001eec826000015160068151811062001e8e57fe5b602082015262001efb6200343b565b62001f0a8260200151620028e2565b905062001f178162002afa565b1562001f305762001f288162002909565b825262001fa1565b606082602001519050606060018251036040519080825280601f01601f19166020018201604052801562001f6b576020820181803883390190505b50905060008083602101915082602001905062001f8b8282855162002b38565b62001f9a62001e2f84620028e2565b8652505050505b62001fac8362002b87565b604083015250919050565b6020015190565b606062001e70826000015160078151811062001e8e57fe5b600062001fe26200343b565b62001fed84620028e2565b9050606062001ffc8262002909565b905060608085600082620020108b62002b9f565b90508051600014156200202e5760009750505050505050506200164d565b60005b8651811015620022ce57815183111562002057576000985050505050505050506200164d565b620020768782815181106200206857fe5b602002602001015162002ce7565b95508580519060200120841462002099576000985050505050505050506200164d565b620020b8878281518110620020aa57fe5b602002602001015162002909565b9450845160111415620021835781518314156200211b578c80519060200120620020e98660108151811062001e8e57fe5b80519060200120141562002109576001985050505050505050506200164d565b6000985050505050505050506200164d565b60008284815181106200212a57fe5b016020015160f81c905060108111156200215157600099505050505050505050506200164d565b62002173868260ff16815181106200216557fe5b602002602001015162002d54565b94505060019290920191620022c5565b84516002141562002109576060620021a28660008151811062001e8e57fe5b90506000620021b382858762002d72565b90506000620021c460008462002e45565b90508451828701141562002256578f80519060200120620021ec8960018151811062001e8e57fe5b805190602001201480156200222657506001600160f81b03198116600160f91b14806200222657506001600160f81b03198116600360f81b145b15620022415760019b5050505050505050505050506200164d565b60009b5050505050505050505050506200164d565b8115806200228757506001600160f81b03198116158015906200228757506001600160f81b03198116600160f81b14155b15620022a25760009b5050505050505050505050506200164d565b8186019550620022b9886001815181106200216557fe5b9650620022c592505050565b60010162002031565b5050505050505050949350505050565b606062001e708260000151600a8151811062001e8e57fe5b606062001e708260000151600b8151811062001e8e57fe5b600062001e70826000015160028151811062001e6257fe5b600062001e70826000015160038151811062001e6257fe5b606062001e70826000015160018151811062001e8e57fe5b60048054604080516320a9cea560e11b8152928301859052516000928392839283926001600160a01b03909216916341539d4a9160248083019260a0929190829003018186803b158015620023aa57600080fd5b505afa158015620023bf573d6000803e3d6000fd5b505050506040513d60a0811015620023d657600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050509350509250925062002470828b0384878d8d8d8d604051602001808581526020018481526020018381526020018281526020019450505050506040516020818303038152906040528051906020012062002ea8909392919063ffffffff16565b620024ad5760405162461bcd60e51b815260040180806020018281038252602d81526020018062003cca602d913960400191505060405180910390fd5b9998505050505050505050565b600062001e70826000015160088151811062001e6257fe5b600062001e706002546002028301600254420162003006565b6000828152600660205260409020600301546001600160a01b0316156200254f576040805162461bcd60e51b8152602060048201526013602482015272455849545f414c52454144595f45584953545360681b604482015290519081900360640190fd5b6040805160c08101825286815260208082018781526001600160a01b03808c168486019081528b8216606086019081528915156080870190815288841660a0880190815260008b8152600690975297862096518088559451600188015591516002870180549185166001600160a01b03199283161790819055915160038801805494511515600160a01b0260ff60a01b199287169584169590951791909116939093179283905596516004870180549185169190981617909655939492936200261f93908216929116906200301f565b90508415620026ad576001600160801b03841660009081526005602052604090205460ff161562002684576040805162461bcd60e51b815260206004820152600a60248201526912d393d5d397d156125560b21b604482015290519081900360640190fd5b6001600160801b0384166000908152600560205260409020805460ff1916600117905562002721565b600081815260076020526040902054156200270f576040805162461bcd60e51b815260206004820152601860248201527f455849545f414c52454144595f494e5f50524f47524553530000000000000000604482015290519081900360640190fd5b60008181526007602052604090208490555b60038201546001600160a01b03908116600090815260086020526040808220548151631d834a1b60e01b8152608089901c60048201526001600160801b038916602482015291519316928392631d834a1b926044808201939182900301818387803b1580156200279057600080fd5b505af1158015620027a5573d6000803e3d6000fd5b50506009546002860154604080516340c10f1960e01b81526001600160a01b039283166004820152602481018b905290519190921693506340c10f199250604480830192600092919082900301818387803b1580156200280457600080fd5b505af115801562002819573d6000803e3d6000fd5b5050604080518b8152891515602082015281516001600160a01b03808f1695508a94508f16927faa5303fdad123ab5ecaefaf69137bf8632257839546d43a3b3dd148cc2879d6f928290030190a450505050505050505050565b6001600160a01b0381166200288757600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b620028ec6200343b565b506040805180820190915281518152602082810190820152919050565b6060620029168262002afa565b6200292057600080fd5b60006200292d8362003197565b90506060816040519080825280602002602001820160405280156200296f57816020015b6200295b6200343b565b815260200190600190039081620029515790505b5090506000620029838560200151620031fb565b60208601510190506000805b84811015620029df57620029a38362003267565b9150604051806040016040528083815260200184815250848281518110620029c757fe5b6020908102919091010152918101916001016200298f565b508551602087015183031462002a32576040805162461bcd60e51b81526020600482015260136024820152722bb937b733903a37ba30b6103632b733ba341760691b604482015290519081900360640190fd5b5090949350505050565b80516000901580159062002a5257508151602110155b62002a5c57600080fd5b60008062002a6a8462003303565b8151919350915060208210156200164d5760208290036101000a9004949350505050565b805160609062002a9d57600080fd5b60008062002aab8462003303565b915091506060816040519080825280601f01601f19166020018201604052801562002add576020820181803883390190505b5090506020810162002af18482856200332b565b50949350505050565b805160009062002b0d5750600062001b87565b6020820151805160001a9060c082101562002b2e5760009250505062001b87565b5060019392505050565b8062002b445762000c40565b5b6020811062002b66578251825260209283019290910190601f190162002b45565b915181516020939093036101000a6000190180199091169216919091179052565b600062001e70826000015160098151811062001e6257fe5b60608060008351111562001e705760008062002bbd60008662002e45565b60f81c9050600181148062002bd557508060ff166003145b1562002c535760018551600202036040519080825280601f01601f19166020018201604052801562002c0e576020820181803883390190505b509250600062002c2060018762002e45565b9050808460008151811062002c3157fe5b60200101906001600160f81b031916908160001a905350600192505062002c8e565b60028551600202036040519080825280601f01601f19166020018201604052801562002c86576020820181803883390190505b509250600091505b60ff82165b835181101562002cde5762002cb18360ff1682036002018762002e45565b84828151811062002cbe57fe5b60200101906001600160f81b031916908160001a90535060010162002c93565b50505092915050565b60608082600001516040519080825280601f01601f19166020018201604052801562002d1a576020820181803883390190505b50905080516000141562002d3057905062001b87565b600081602001905062002d4d84602001518286600001516200332b565b5092915050565b805160009060211462002d6657600080fd5b50602001516001015190565b600080606062002d828662002b9f565b9050606081516040519080825280601f01601f19166020018201604052801562002db3576020820181803883390190505b509050845b8251860181101562002e1157600087828151811062002dd357fe5b602001015160f81c60f81b905080838884038151811062002df057fe5b60200101906001600160f81b031916908160001a9053505060010162002db8565b5080805190602001208280519060200120141562002e33578151925062002e38565b600092505b50909150505b9392505050565b6000600283061562002e7a57601082600285048151811062002e6357fe5b016020015160f81c8162002e7357fe5b0662002e9e565b601082600285048151811062002e8c57fe5b016020015160f81c8162002e9c57fe5b045b60f81b9392505050565b6000602082518162002eb657fe5b061562002f01576040805162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b604482015290519081900360640190fd5b6000602083518162002f0f57fe5b0490508060020a851062002f62576040805162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b604482015290519081900360640190fd5b60008660205b8551811162002ff8578581015192506002880662002fb7578183604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120915062002fe9565b828260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b60028804975060200162002f68565b509094149695505050505050565b60008183101562003018578162002e3e565b5090919050565b600354604080516336a8279560e21b81526001600160a01b0386811660048301529151600093929092169163daa09e5491602480820192602092909190829003018186803b1580156200307157600080fd5b505afa15801562003086573d6000803e3d6000fd5b505050506040513d60208110156200309d57600080fd5b505115620030f8575060408051606085811b6bffffffffffffffffffffffff199081166020808501919091529186901b1660348301526048808301859052835180840390910181526068909201909252805191012062002e3e565b600082116200314e576040805162461bcd60e51b815260206004820152601860248201527f43414e4e4f545f455849545f5a45524f5f414d4f554e54530000000000000000604482015290519081900360640190fd5b5050604080516bffffffffffffffffffffffff19606094851b81166020808401919091529390941b90931660348401528051602881850301815260489093019052815191012090565b8051600090620031aa5750600062001b87565b60008090506000620031c08460200151620031fb565b602085015185519181019250015b80821015620031f257620031e28262003267565b60019093019290910190620031ce565b50909392505050565b8051600090811a60808110156200321757600091505062001b87565b60b881108062003234575060c0811080159062003234575060f881105b156200324557600191505062001b87565b60c08110156200325b5760b51901905062001b87565b60f51901905062001b87565b80516000908190811a608081101562003284576001915062002d4d565b60b88110156200329b57607e198101915062002d4d565b60c0811015620032ca5760b78103600185019450806020036101000a8551046001820181019350505062002d4d565b60f8811015620032e15760be198101915062002d4d565b60019390930151602084900360f7016101000a900490920160f5190192915050565b6000806000620033178460200151620031fb565b602085015194519481019594039392505050565b80620033375762000c40565b5b6020811062003359578251825260209283019290910190601f190162003338565b801562000c4057915181516020939093036101000a6000190180199091169216919091179052565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b61084f806200345683390190565b6040518060200160405280606081525090565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000801916815260200160008019168152602001606081525090565b60405180606001604052806060815260200160608152602001600081525090565b60405180604001604052806000815260200160008152509056fe608060405234801561001057600080fd5b50600080546001600160a01b03191633178082556040516001600160a01b039190911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3604080516020810190915260008152610076906001908161007c565b506100e9565b8280548282559060005260206000209081019282156100bc579160200282015b828111156100bc578251829060ff1690559160200191906001019061009c565b506100c89291506100cc565b5090565b6100e691905b808211156100c857600081556001016100d2565b90565b610757806100f86000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b07576ac1161005b578063b07576ac146100fa578063bda1504b1461011b578063d6362e9714610135578063f2fde38b1461013d57610088565b80631d834a1b1461008d578063715018a6146100b25780638da5cb5b146100ba5780638f32d59b146100de575b600080fd5b6100b0600480360360408110156100a357600080fd5b5080359060200135610163565b005b6100b06101d8565b6100c2610233565b604080516001600160a01b039092168252519081900360200190f35b6100e6610243565b604080519115158252519081900360200190f35b610102610254565b6040805192835260208301919091528051918290030190f35b610123610325565b60408051918252519081900360200190f35b61010261032b565b6100b06004803603602081101561015357600080fd5b50356001600160a01b0316610356565b61016b610243565b61017457600080fd5b6001805480820182556000829052608084901b83177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690910181905560025490916101c5919063ffffffff61037316565b60028190556101d39061038e565b505050565b6101e0610243565b6101e957600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b03165b90565b6000546001600160a01b0316331490565b60008061025f610243565b61026857600080fd5b60006001808154811061027757fe5b9060005260206000200154905060016002548154811061029357fe5b9060005260206000200154600180815481106102ab57fe5b90600052602060002001819055506001600254815481106102c857fe5b60009182526020822001556002546102e790600163ffffffff61046216565b6002556102f46001610477565b600180546103079163ffffffff61046216565b6103126001826106e5565b5061031c81610542565b92509250509091565b60025481565b60008061034e6001808154811061033e57fe5b9060005260206000200154610542565b915091509091565b61035e610243565b61036757600080fd5b6103708161055f565b50565b60008282018381101561038557600080fd5b90505b92915050565b600180548291829160009190839081106103a457fe5b906000526020600020015490505b60016103c584600263ffffffff6105cd16565b815481106103cf57fe5b906000526020600020015481101561043a5760016103f484600263ffffffff6105cd16565b815481106103fe57fe5b90600052602060002001546001848154811061041657fe5b60009182526020909120015561043383600263ffffffff6105cd16565b92506103b2565b81831461045c57806001848154811061044f57fe5b6000918252602090912001555b50505050565b60008282111561047157600080fd5b50900390565b6001805482918291600091908390811061048d57fe5b9060005260206000200154905060006104a5846105ef565b90505b60025481111580156104d05750600181815481106104c257fe5b906000526020600020015482115b1561051957600181815481106104e257fe5b9060005260206000200154600185815481106104fa57fe5b600091825260209091200155925082610512816105ef565b90506104a8565b82841461053b57816001858154811061052e57fe5b6000918252602090912001555b5050505050565b608081901c6fffffffffffffffffffffffffffffffff8216915091565b6001600160a01b03811661057257600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60008082116105db57600080fd5b60008284816105e657fe5b04949350505050565b6000600254610619600161060d6002866106be90919063ffffffff16565b9063ffffffff61037316565b11156106375761063082600263ffffffff6106be16565b90506106b9565b600161064e8161060d85600263ffffffff6106be16565b8154811061065857fe5b600091825260209091200154600161067784600263ffffffff6106be16565b8154811061068157fe5b906000526020600020015410156106a35761063082600263ffffffff6106be16565b610630600161060d84600263ffffffff6106be16565b919050565b6000826106cd57506000610388565b828202828482816106da57fe5b041461038557600080fd5b8154818355818111156101d3576000838152602090206101d391810190830161024091905b8082111561071e576000815560010161070a565b509056fea265627a7a72315820dcbc52c43c8707f4c23d33cb4c40b9b416b5d88f272f064d0fa2d9e29683a5a064736f6c6343000511003250726564696361746520737570706f727473206f6e6c792045524337323120746f6b656e7357495448445241575f424c4f434b5f4e4f545f415f504152545f4f465f5355424d49545445445f48454144455250726564696361746520737570706f727473206f6e6c7920455243323020746f6b656e73494e56414c49445f524f4f545f544f5f4348494c445f544f4b454e5f4d415050494e47a265627a7a72315820dbd7b9bada9509238aad05d46deb3cee3c11df2a5237e4539fc3e0347352c57964736f6c63430005110032
Deployed Bytecode
0x6080604052600436106200013a5760003560e01c80639145e6df11620000af578063d11f045c116200006d578063d11f045c1462000571578063d931a86914620005a8578063ed4a0be81462000609578063edeca09b1462000621578063f2fde38b1462000639576200013a565b80639145e6df146200035d5780639492b0b8146200039457806396cbd812146200042d578063ad1d8069146200045e578063c74ab88a14620004ed576200013a565b8063433c76bf11620000fd578063433c76bf1462000289578063661429c814620002b7578063715018a614620002e55780638da5cb5b14620002fd5780638f32d59b1462000331576200013a565b80630f6795f2146200013c578063144a03b314620001735780631e29848b14620001a857806322f192af14620001d2578063342de179146200021d575b005b3480156200014957600080fd5b506200013a600480360360208110156200016257600080fd5b50356001600160a01b031662000670565b6200013a600480360360608110156200018b57600080fd5b508035906001600160a01b03602082013516906040013562000bed565b348015620001b557600080fd5b50620001c062000c45565b60408051918252519081900360200190f35b348015620001df57600080fd5b506200013a60048036036080811015620001f857600080fd5b508035906020810135906001600160a01b036040820135811691606001351662000c4b565b3480156200022a57600080fd5b506200024b600480360360208110156200024357600080fd5b503562000d96565b6040805196875260208701959095526001600160a01b03938416868601529183166060860152151560808501521660a0830152519081900360c00190f35b3480156200029657600080fd5b506200013a60048036036020811015620002af57600080fd5b503562000ddf565b348015620002c457600080fd5b50620001c060048036036020811015620002dd57600080fd5b503562000e27565b348015620002f257600080fd5b506200013a62000e39565b3480156200030a57600080fd5b506200031562000e97565b604080516001600160a01b039092168252519081900360200190f35b3480156200033e57600080fd5b506200034962000ea6565b604080519115158252519081900360200190f35b3480156200036a57600080fd5b506200013a600480360360208110156200038357600080fd5b50356001600160a01b031662000eb7565b348015620003a157600080fd5b506200013a60048036036080811015620003ba57600080fd5b813591602081013591810190606081016040820135640100000000811115620003e257600080fd5b820183602082011115620003f557600080fd5b803590602001918460018302840111640100000000831117156200041857600080fd5b9193509150356001600160a01b031662000f71565b3480156200043a57600080fd5b506200044562001362565b6040805163ffffffff9092168252519081900360200190f35b3480156200046b57600080fd5b50620001c0600480360360608110156200048457600080fd5b810190602081018135640100000000811115620004a057600080fd5b820183602082011115620004b357600080fd5b80359060200191846001830284011164010000000083111715620004d657600080fd5b919350915060ff8135169060200135151562001375565b348015620004fa57600080fd5b506200013a600480360360208110156200051357600080fd5b8101906020810181356401000000008111156200052f57600080fd5b8201836020820111156200054257600080fd5b803590602001918460208302840111640100000000831117156200056557600080fd5b50909250905062001655565b3480156200057e57600080fd5b5062000315600480360360208110156200059757600080fd5b50356001600160a01b031662001691565b348015620005b557600080fd5b506200013a600480360360e0811015620005ce57600080fd5b506001600160a01b03813581169160208101358216916040820135169060608101359060808101359060a081013515159060c00135620016ac565b3480156200061657600080fd5b50620001c062001afb565b3480156200062e57600080fd5b506200031562001b01565b3480156200064657600080fd5b506200013a600480360360208110156200065f57600080fd5b50356001600160a01b031662001b10565b6001600160a01b0380821660009081526008602052604081205490918291165b6000816001600160a01b031663bda1504b6040518163ffffffff1660e01b815260040160206040518083038186803b158015620006cc57600080fd5b505afa158015620006e1573d6000803e3d6000fd5b505050506040513d6020811015620006f857600080fd5b5051118015620007165750600954600160a01b900463ffffffff165a115b1562000be657806001600160a01b031663d6362e976040518163ffffffff1660e01b8152600401604080518083038186803b1580156200075557600080fd5b505afa1580156200076a573d6000803e3d6000fd5b505050506040513d60408110156200078157600080fd5b508051602090910151909350608084901b1791506200079f62003381565b50600082815260066020908152604091829020825160c0810184528154815260018201549281019290925260028101546001600160a01b039081169383019390935260038101548084166060840152600160a01b900460ff16151560808301526004015490911660a0820152428411156200081e575050505062000bea565b816001600160a01b031663b07576ac6040518163ffffffff1660e01b81526004016040805180830381600087803b1580156200085957600080fd5b505af11580156200086e573d6000803e3d6000fd5b505050506040513d60408110156200088557600080fd5b505060095460408051634f558e7960e01b81526004810186905290516001600160a01b0390921691634f558e7991602480820192602092909190829003018186803b158015620008d457600080fd5b505afa158015620008e9573d6000803e3d6000fd5b505050506040513d60208110156200090057600080fd5b50516200090e575062000690565b600954604080516331a9108f60e11b81526004810186905290516000926001600160a01b031691636352211e916024808301926020929190829003018186803b1580156200095b57600080fd5b505afa15801562000970573d6000803e3d6000fd5b505050506040513d60208110156200098757600080fd5b505160008581526006602052604080822060020180546001600160a01b0319166001600160a01b03808616919091179091556009548251630852cd8d60e31b8152600481018a9052925194955016926342966c689260248084019391929182900301818387803b158015620009fb57600080fd5b505af115801562000a10573d6000803e3d6000fd5b505050508160a001516001600160a01b031662000a2d8562001b2f565b6040516024018080602001828103825283818151815260200191508051906020019080838360005b8381101562000a6f57818101518382015260200162000a55565b50505050905090810190601f16801562000a9d5780820380516001836020036101000a031916815260200191505b5060408051601f198184030181529181526020820180516001600160e01b0316637bd94e0360e01b178152905182519295509350839250908083835b6020831062000afa5780518252601f19909201916020918201910162000ad9565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d806000811462000b5e576040519150601f19603f3d011682016040523d82523d6000602084013e62000b63565b606091505b5050825160408051918252516001600160a01b03808a16935084169187917ffeb2000dca3e617cd6f3a8bbb63014bb54a124aac6ccbf73ee7229b4cd01f1209181900360200190a4816080015162000bde576040516001600160a01b0382169060009067016345785d8a00009082818181858883f150505050505b505062000690565b5050505b50565b67016345785d8a0000341462000c40576040805162461bcd60e51b8152602060048201526013602482015272125b9d985b1a5908109bdb9908185b5bdd5b9d606a1b604482015290519081900360640190fd5b505050565b600a5481565b600354604080516337b1d58560e01b815233600482015290516000926001600160a01b0316916337b1d585916024808301926020929190829003018186803b15801562000c9757600080fd5b505afa15801562000cac573d6000803e3d6000fd5b505050506040513d602081101562000cc357600080fd5b5051600381111562000cd157fe5b141562000d20576040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b600084815260066020526040902060028101546001600160a01b031662000d80576040805162461bcd60e51b815260206004820152600f60248201526e1253959053125117d156125517d251608a1b604482015290519081900360640190fd5b62000d8f858585338662001b8c565b5050505050565b60066020526000908152604090208054600182015460028301546003840154600490940154929391926001600160a01b039182169282811692600160a01b90910460ff16911686565b62000de962000ea6565b62000df357600080fd5b6002546040518291907f06b98f3947a8966918fef150b41170e78ba1d91dd2b1d2fd48a59c91ffbd66a190600090a3600255565b60076020526000908152604090205481565b62000e4362000ea6565b62000e4d57600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b031690565b6000546001600160a01b0316331490565b6003546001600160a01b0316331462000f17576040805162461bcd60e51b815260206004820152601a60248201527f554e415554484f52495a45445f52454749535452595f4f4e4c59000000000000604482015290519081900360640190fd5b60405162000f2590620033b6565b604051809103906000f08015801562000f42573d6000803e3d6000fd5b506001600160a01b03918216600090815260086020526040902080546001600160a01b03191691909216179055565b60008581526006602090815260408083208784526005810190925290912060028201546001600160a01b03161580159062000fb5575080546001600160a01b031615155b62001007576040805162461bcd60e51b815260206004820152601860248201527f496e76616c69642065786974206f7220696e7075742069640000000000000000604482015290519081900360640190fd5b6000600354604080516337b1d58560e01b81526001600160a01b038781166004830152915191909216916337b1d585916024808301926020929190829003018186803b1580156200105757600080fd5b505afa1580156200106c573d6000803e3d6000fd5b505050506040513d60208110156200108357600080fd5b505160038111156200109157fe5b1415620010d9576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f50524544494341544560781b604482015290519081900360640190fd5b826001600160a01b031663ec58410c620010f38462001c4b565b620010ff898562001d3a565b88886040518563ffffffff1660e01b815260040180806020018060200180602001848103845288818151815260200191508051906020019080838360005b83811015620011575781810151838201526020016200113d565b50505050905090810190601f168015620011855780820380516001836020036101000a031916815260200191505b50848103835287518152875160209182019189019080838360005b83811015620011ba578181015183820152602001620011a0565b50505050905090810190601f168015620011e85780820380516001836020036101000a031916815260200191505b508481038252858152602001868680828437600081840152601f19601f820116905080830192505050975050505050505050602060405180830381600087803b1580156200123557600080fd5b505af11580156200124a573d6000803e3d6000fd5b505050506040513d60208110156200126157600080fd5b5051620012a8576040805162461bcd60e51b815260206004820152601060248201526f10da185b1b195b99d94819985a5b195960821b604482015290519081900360640190fd5b60095460408051630852cd8d60e31b8152600481018a905290516001600160a01b03909216916342966c689160248082019260009290919082900301818387803b158015620012f657600080fd5b505af11580156200130b573d6000803e3d6000fd5b50506040513392506000915067016345785d8a00009082818181858883f150506040518a93507f93a8052a01c184f88312af177ab8fae2e56a9973b6aa4bdc62dfcf744e09d041925060009150a250505050505050565b600954600160a01b900463ffffffff1681565b600062001381620033c4565b620013c286868080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525062001e1492505050565b9050620013ce620033d7565b620013d98262001e4a565b8152620013e68262001e76565b60c082018190528051600090620013f957fe5b01602001516001600160f81b031916156200144c576040805162461bcd60e51b815260206004820152600e60248201526d696e636f7272656374206d61736b60901b604482015290519081900360640190fd5b620014578262001e9c565b6080820152620014678262001eb4565b60a0820152620014a0620014856200147f8462001ecc565b62001fb7565b8260c00151620014958562001fbe565b8460a0015162001fd6565b620014f2576040805162461bcd60e51b815260206004820152601c60248201527f494e56414c49445f524543454950545f4d45524b4c455f50524f4f4600000000604482015290519081900360640190fd5b83156200157557620015236200150883620022de565b8260c001516200151885620022f6565b846080015162001fd6565b62001575576040805162461bcd60e51b815260206004820152601760248201527f494e56414c49445f54585f4d45524b4c455f50524f4f46000000000000000000604482015290519081900360640190fd5b62001580826200230e565b60208201819052620015b490620015978462002326565b608084015160a08501518551620015ae886200233e565b62002356565b6040820152620015c482620024ba565b6060820181905263ffffffff19161562001625576040805162461bcd60e51b815260206004820152601d60248201527f4272616e6368206d61736b2073686f756c642062652033322062697473000000604482015290519081900360640190fd5b806060015160208260200151901b607f620016448460400151620024d2565b901b1717925050505b949350505050565b60005b8181101562000c4057620016888383838181106200167257fe5b905060200201356001600160a01b031662000670565b60010162001658565b6008602052600090815260409020546001600160a01b031681565b600354604080516337b1d58560e01b8152336004820152905187926000926001600160a01b03909116916337b1d58591602480820192602092909190829003018186803b158015620016fd57600080fd5b505afa15801562001712573d6000803e3d6000fd5b505050506040513d60208110156200172957600080fd5b505160035460408051633a9831f160e21b81526001600160a01b0386811660048301529151939450600093919092169163ea60c7c4916024808301926020929190829003018186803b1580156200177f57600080fd5b505afa15801562001794573d6000803e3d6000fd5b505050506040513d6020811015620017ab57600080fd5b50516001600160a01b031614156200180a576040805162461bcd60e51b815260206004820152601760248201527f726f6f74546f6b656e206e6f7420737570706f72746564000000000000000000604482015290519081900360640190fd5b60018160038111156200181957fe5b1415620018e057600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200186e57600080fd5b505afa15801562001883573d6000803e3d6000fd5b505050506040513d60208110156200189a57600080fd5b505115620018da5760405162461bcd60e51b815260040180806020018281038252602481526020018062003cf76024913960400191505060405180910390fd5b62001a18565b6002816003811115620018ef57fe5b1415620019b457600354604080516336a8279560e21b81526001600160a01b0385811660048301529151919092169163daa09e54916024808301926020929190829003018186803b1580156200194457600080fd5b505afa15801562001959573d6000803e3d6000fd5b505050506040513d60208110156200197057600080fd5b50511515600114620018da5760405162461bcd60e51b815260040180806020018281038252602581526020018062003ca56025913960400191505060405180910390fd5b6003816003811115620019c357fe5b1415620019d05762001a18565b6040805162461bcd60e51b8152602060048201526018602482015277141491511250d0551157d393d517d055551213d49256915160421b604482015290519081900360640190fd5b60035460408051633a9831f160e21b81526001600160a01b038a811660048301529151828c16939092169163ea60c7c491602480820192602092909190829003018186803b15801562001a6a57600080fd5b505afa15801562001a7f573d6000803e3d6000fd5b505050506040513d602081101562001a9657600080fd5b50516001600160a01b03161462001adf5760405162461bcd60e51b815260040180806020018281038252602381526020018062003d1b6023913960400191505060405180910390fd5b62001af089888888888833620024eb565b505050505050505050565b60025481565b6009546001600160a01b031681565b62001b1a62000ea6565b62001b2457600080fd5b62000bea8162002873565b60008181526006602090815260409182902060038101546002820154915484519384018690526001600160a01b0391821684860152911660608301526080808301919091528251808303909101815260a09091019091525b919050565b604080516060810182526001600160a01b03808616808352858216602080850191825286841685870190815260008c8152600683528781208c82526005018352879020955186549086166001600160a01b03199182161787559251600187018054918716918516919091179055516002909501805495909416949091169390931790915582519081529151869288927f87d2daa6e85f166015ebbcf09f5ee4bc50f93677579339fe128e3561a6807cb692918290030190a35050505050565b6002810154600380549083015460408051633a9831f160e21b81526001600160a01b03928316600482015290516060948316939092169163ea60c7c491602480820192602092909190829003018186803b15801562001ca957600080fd5b505afa15801562001cbe573d6000803e3d6000fd5b505050506040513d602081101562001cd557600080fd5b5051835460018501546003860154604080516001600160a01b03968716602082015295909416858501526060850192909252608084015260ff600160a01b90910416151560a0808401919091528151808403909101815260c090920190529050919050565b80546001820154600354600284015460408051633a9831f160e21b81526001600160a01b039283166004820152905160609588959084169490841693169163ea60c7c4916024808301926020929190829003018186803b15801562001d9e57600080fd5b505afa15801562001db3573d6000803e3d6000fd5b505050506040513d602081101562001dca57600080fd5b50516040805160208101959095526001600160a01b03938416858201529183166060850152919091166080808401919091528151808403909101815260a090920190529392505050565b62001e1e620033c4565b606062001e3562001e2f84620028e2565b62002909565b60408051602081019091529081529392505050565b600062001e70826000015160008151811062001e6257fe5b602002602001015162002a3c565b92915050565b606062001e70826000015160088151811062001e8e57fe5b602002602001015162002a8e565b600062001e70826000015160048151811062001e6257fe5b600062001e70826000015160058151811062001e6257fe5b62001ed66200341a565b62001eec826000015160068151811062001e8e57fe5b602082015262001efb6200343b565b62001f0a8260200151620028e2565b905062001f178162002afa565b1562001f305762001f288162002909565b825262001fa1565b606082602001519050606060018251036040519080825280601f01601f19166020018201604052801562001f6b576020820181803883390190505b50905060008083602101915082602001905062001f8b8282855162002b38565b62001f9a62001e2f84620028e2565b8652505050505b62001fac8362002b87565b604083015250919050565b6020015190565b606062001e70826000015160078151811062001e8e57fe5b600062001fe26200343b565b62001fed84620028e2565b9050606062001ffc8262002909565b905060608085600082620020108b62002b9f565b90508051600014156200202e5760009750505050505050506200164d565b60005b8651811015620022ce57815183111562002057576000985050505050505050506200164d565b620020768782815181106200206857fe5b602002602001015162002ce7565b95508580519060200120841462002099576000985050505050505050506200164d565b620020b8878281518110620020aa57fe5b602002602001015162002909565b9450845160111415620021835781518314156200211b578c80519060200120620020e98660108151811062001e8e57fe5b80519060200120141562002109576001985050505050505050506200164d565b6000985050505050505050506200164d565b60008284815181106200212a57fe5b016020015160f81c905060108111156200215157600099505050505050505050506200164d565b62002173868260ff16815181106200216557fe5b602002602001015162002d54565b94505060019290920191620022c5565b84516002141562002109576060620021a28660008151811062001e8e57fe5b90506000620021b382858762002d72565b90506000620021c460008462002e45565b90508451828701141562002256578f80519060200120620021ec8960018151811062001e8e57fe5b805190602001201480156200222657506001600160f81b03198116600160f91b14806200222657506001600160f81b03198116600360f81b145b15620022415760019b5050505050505050505050506200164d565b60009b5050505050505050505050506200164d565b8115806200228757506001600160f81b03198116158015906200228757506001600160f81b03198116600160f81b14155b15620022a25760009b5050505050505050505050506200164d565b8186019550620022b9886001815181106200216557fe5b9650620022c592505050565b60010162002031565b5050505050505050949350505050565b606062001e708260000151600a8151811062001e8e57fe5b606062001e708260000151600b8151811062001e8e57fe5b600062001e70826000015160028151811062001e6257fe5b600062001e70826000015160038151811062001e6257fe5b606062001e70826000015160018151811062001e8e57fe5b60048054604080516320a9cea560e11b8152928301859052516000928392839283926001600160a01b03909216916341539d4a9160248083019260a0929190829003018186803b158015620023aa57600080fd5b505afa158015620023bf573d6000803e3d6000fd5b505050506040513d60a0811015620023d657600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050509350509250925062002470828b0384878d8d8d8d604051602001808581526020018481526020018381526020018281526020019450505050506040516020818303038152906040528051906020012062002ea8909392919063ffffffff16565b620024ad5760405162461bcd60e51b815260040180806020018281038252602d81526020018062003cca602d913960400191505060405180910390fd5b9998505050505050505050565b600062001e70826000015160088151811062001e6257fe5b600062001e706002546002028301600254420162003006565b6000828152600660205260409020600301546001600160a01b0316156200254f576040805162461bcd60e51b8152602060048201526013602482015272455849545f414c52454144595f45584953545360681b604482015290519081900360640190fd5b6040805160c08101825286815260208082018781526001600160a01b03808c168486019081528b8216606086019081528915156080870190815288841660a0880190815260008b8152600690975297862096518088559451600188015591516002870180549185166001600160a01b03199283161790819055915160038801805494511515600160a01b0260ff60a01b199287169584169590951791909116939093179283905596516004870180549185169190981617909655939492936200261f93908216929116906200301f565b90508415620026ad576001600160801b03841660009081526005602052604090205460ff161562002684576040805162461bcd60e51b815260206004820152600a60248201526912d393d5d397d156125560b21b604482015290519081900360640190fd5b6001600160801b0384166000908152600560205260409020805460ff1916600117905562002721565b600081815260076020526040902054156200270f576040805162461bcd60e51b815260206004820152601860248201527f455849545f414c52454144595f494e5f50524f47524553530000000000000000604482015290519081900360640190fd5b60008181526007602052604090208490555b60038201546001600160a01b03908116600090815260086020526040808220548151631d834a1b60e01b8152608089901c60048201526001600160801b038916602482015291519316928392631d834a1b926044808201939182900301818387803b1580156200279057600080fd5b505af1158015620027a5573d6000803e3d6000fd5b50506009546002860154604080516340c10f1960e01b81526001600160a01b039283166004820152602481018b905290519190921693506340c10f199250604480830192600092919082900301818387803b1580156200280457600080fd5b505af115801562002819573d6000803e3d6000fd5b5050604080518b8152891515602082015281516001600160a01b03808f1695508a94508f16927faa5303fdad123ab5ecaefaf69137bf8632257839546d43a3b3dd148cc2879d6f928290030190a450505050505050505050565b6001600160a01b0381166200288757600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b620028ec6200343b565b506040805180820190915281518152602082810190820152919050565b6060620029168262002afa565b6200292057600080fd5b60006200292d8362003197565b90506060816040519080825280602002602001820160405280156200296f57816020015b6200295b6200343b565b815260200190600190039081620029515790505b5090506000620029838560200151620031fb565b60208601510190506000805b84811015620029df57620029a38362003267565b9150604051806040016040528083815260200184815250848281518110620029c757fe5b6020908102919091010152918101916001016200298f565b508551602087015183031462002a32576040805162461bcd60e51b81526020600482015260136024820152722bb937b733903a37ba30b6103632b733ba341760691b604482015290519081900360640190fd5b5090949350505050565b80516000901580159062002a5257508151602110155b62002a5c57600080fd5b60008062002a6a8462003303565b8151919350915060208210156200164d5760208290036101000a9004949350505050565b805160609062002a9d57600080fd5b60008062002aab8462003303565b915091506060816040519080825280601f01601f19166020018201604052801562002add576020820181803883390190505b5090506020810162002af18482856200332b565b50949350505050565b805160009062002b0d5750600062001b87565b6020820151805160001a9060c082101562002b2e5760009250505062001b87565b5060019392505050565b8062002b445762000c40565b5b6020811062002b66578251825260209283019290910190601f190162002b45565b915181516020939093036101000a6000190180199091169216919091179052565b600062001e70826000015160098151811062001e6257fe5b60608060008351111562001e705760008062002bbd60008662002e45565b60f81c9050600181148062002bd557508060ff166003145b1562002c535760018551600202036040519080825280601f01601f19166020018201604052801562002c0e576020820181803883390190505b509250600062002c2060018762002e45565b9050808460008151811062002c3157fe5b60200101906001600160f81b031916908160001a905350600192505062002c8e565b60028551600202036040519080825280601f01601f19166020018201604052801562002c86576020820181803883390190505b509250600091505b60ff82165b835181101562002cde5762002cb18360ff1682036002018762002e45565b84828151811062002cbe57fe5b60200101906001600160f81b031916908160001a90535060010162002c93565b50505092915050565b60608082600001516040519080825280601f01601f19166020018201604052801562002d1a576020820181803883390190505b50905080516000141562002d3057905062001b87565b600081602001905062002d4d84602001518286600001516200332b565b5092915050565b805160009060211462002d6657600080fd5b50602001516001015190565b600080606062002d828662002b9f565b9050606081516040519080825280601f01601f19166020018201604052801562002db3576020820181803883390190505b509050845b8251860181101562002e1157600087828151811062002dd357fe5b602001015160f81c60f81b905080838884038151811062002df057fe5b60200101906001600160f81b031916908160001a9053505060010162002db8565b5080805190602001208280519060200120141562002e33578151925062002e38565b600092505b50909150505b9392505050565b6000600283061562002e7a57601082600285048151811062002e6357fe5b016020015160f81c8162002e7357fe5b0662002e9e565b601082600285048151811062002e8c57fe5b016020015160f81c8162002e9c57fe5b045b60f81b9392505050565b6000602082518162002eb657fe5b061562002f01576040805162461bcd60e51b8152602060048201526014602482015273092dcecc2d8d2c840e0e4dedecc40d8cadccee8d60631b604482015290519081900360640190fd5b6000602083518162002f0f57fe5b0490508060020a851062002f62576040805162461bcd60e51b81526020600482015260156024820152744c65616620696e64657820697320746f6f2062696760581b604482015290519081900360640190fd5b60008660205b8551811162002ff8578581015192506002880662002fb7578183604051602001808381526020018281526020019250505060405160208183030381529060405280519060200120915062002fe9565b828260405160200180838152602001828152602001925050506040516020818303038152906040528051906020012091505b60028804975060200162002f68565b509094149695505050505050565b60008183101562003018578162002e3e565b5090919050565b600354604080516336a8279560e21b81526001600160a01b0386811660048301529151600093929092169163daa09e5491602480820192602092909190829003018186803b1580156200307157600080fd5b505afa15801562003086573d6000803e3d6000fd5b505050506040513d60208110156200309d57600080fd5b505115620030f8575060408051606085811b6bffffffffffffffffffffffff199081166020808501919091529186901b1660348301526048808301859052835180840390910181526068909201909252805191012062002e3e565b600082116200314e576040805162461bcd60e51b815260206004820152601860248201527f43414e4e4f545f455849545f5a45524f5f414d4f554e54530000000000000000604482015290519081900360640190fd5b5050604080516bffffffffffffffffffffffff19606094851b81166020808401919091529390941b90931660348401528051602881850301815260489093019052815191012090565b8051600090620031aa5750600062001b87565b60008090506000620031c08460200151620031fb565b602085015185519181019250015b80821015620031f257620031e28262003267565b60019093019290910190620031ce565b50909392505050565b8051600090811a60808110156200321757600091505062001b87565b60b881108062003234575060c0811080159062003234575060f881105b156200324557600191505062001b87565b60c08110156200325b5760b51901905062001b87565b60f51901905062001b87565b80516000908190811a608081101562003284576001915062002d4d565b60b88110156200329b57607e198101915062002d4d565b60c0811015620032ca5760b78103600185019450806020036101000a8551046001820181019350505062002d4d565b60f8811015620032e15760be198101915062002d4d565b60019390930151602084900360f7016101000a900490920160f5190192915050565b6000806000620033178460200151620031fb565b602085015194519481019594039392505050565b80620033375762000c40565b5b6020811062003359578251825260209283019290910190601f190162003338565b801562000c4057915181516020939093036101000a6000190180199091169216919091179052565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b61084f806200345683390190565b6040518060200160405280606081525090565b6040518060e00160405280600081526020016000815260200160008152602001600081526020016000801916815260200160008019168152602001606081525090565b60405180606001604052806060815260200160608152602001600081525090565b60405180604001604052806000815260200160008152509056fe608060405234801561001057600080fd5b50600080546001600160a01b03191633178082556040516001600160a01b039190911691907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a3604080516020810190915260008152610076906001908161007c565b506100e9565b8280548282559060005260206000209081019282156100bc579160200282015b828111156100bc578251829060ff1690559160200191906001019061009c565b506100c89291506100cc565b5090565b6100e691905b808211156100c857600081556001016100d2565b90565b610757806100f86000396000f3fe608060405234801561001057600080fd5b50600436106100885760003560e01c8063b07576ac1161005b578063b07576ac146100fa578063bda1504b1461011b578063d6362e9714610135578063f2fde38b1461013d57610088565b80631d834a1b1461008d578063715018a6146100b25780638da5cb5b146100ba5780638f32d59b146100de575b600080fd5b6100b0600480360360408110156100a357600080fd5b5080359060200135610163565b005b6100b06101d8565b6100c2610233565b604080516001600160a01b039092168252519081900360200190f35b6100e6610243565b604080519115158252519081900360200190f35b610102610254565b6040805192835260208301919091528051918290030190f35b610123610325565b60408051918252519081900360200190f35b61010261032b565b6100b06004803603602081101561015357600080fd5b50356001600160a01b0316610356565b61016b610243565b61017457600080fd5b6001805480820182556000829052608084901b83177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf690910181905560025490916101c5919063ffffffff61037316565b60028190556101d39061038e565b505050565b6101e0610243565b6101e957600080fd5b600080546040516001600160a01b03909116907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908390a3600080546001600160a01b0319169055565b6000546001600160a01b03165b90565b6000546001600160a01b0316331490565b60008061025f610243565b61026857600080fd5b60006001808154811061027757fe5b9060005260206000200154905060016002548154811061029357fe5b9060005260206000200154600180815481106102ab57fe5b90600052602060002001819055506001600254815481106102c857fe5b60009182526020822001556002546102e790600163ffffffff61046216565b6002556102f46001610477565b600180546103079163ffffffff61046216565b6103126001826106e5565b5061031c81610542565b92509250509091565b60025481565b60008061034e6001808154811061033e57fe5b9060005260206000200154610542565b915091509091565b61035e610243565b61036757600080fd5b6103708161055f565b50565b60008282018381101561038557600080fd5b90505b92915050565b600180548291829160009190839081106103a457fe5b906000526020600020015490505b60016103c584600263ffffffff6105cd16565b815481106103cf57fe5b906000526020600020015481101561043a5760016103f484600263ffffffff6105cd16565b815481106103fe57fe5b90600052602060002001546001848154811061041657fe5b60009182526020909120015561043383600263ffffffff6105cd16565b92506103b2565b81831461045c57806001848154811061044f57fe5b6000918252602090912001555b50505050565b60008282111561047157600080fd5b50900390565b6001805482918291600091908390811061048d57fe5b9060005260206000200154905060006104a5846105ef565b90505b60025481111580156104d05750600181815481106104c257fe5b906000526020600020015482115b1561051957600181815481106104e257fe5b9060005260206000200154600185815481106104fa57fe5b600091825260209091200155925082610512816105ef565b90506104a8565b82841461053b57816001858154811061052e57fe5b6000918252602090912001555b5050505050565b608081901c6fffffffffffffffffffffffffffffffff8216915091565b6001600160a01b03811661057257600080fd5b600080546040516001600160a01b03808516939216917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a3600080546001600160a01b0319166001600160a01b0392909216919091179055565b60008082116105db57600080fd5b60008284816105e657fe5b04949350505050565b6000600254610619600161060d6002866106be90919063ffffffff16565b9063ffffffff61037316565b11156106375761063082600263ffffffff6106be16565b90506106b9565b600161064e8161060d85600263ffffffff6106be16565b8154811061065857fe5b600091825260209091200154600161067784600263ffffffff6106be16565b8154811061068157fe5b906000526020600020015410156106a35761063082600263ffffffff6106be16565b610630600161060d84600263ffffffff6106be16565b919050565b6000826106cd57506000610388565b828202828482816106da57fe5b041461038557600080fd5b8154818355818111156101d3576000838152602090206101d391810190830161024091905b8082111561071e576000815560010161070a565b509056fea265627a7a72315820dcbc52c43c8707f4c23d33cb4c40b9b416b5d88f272f064d0fa2d9e29683a5a064736f6c6343000511003250726564696361746520737570706f727473206f6e6c792045524337323120746f6b656e7357495448445241575f424c4f434b5f4e4f545f415f504152545f4f465f5355424d49545445445f48454144455250726564696361746520737570706f727473206f6e6c7920455243323020746f6b656e73494e56414c49445f524f4f545f544f5f4348494c445f544f4b454e5f4d415050494e47a265627a7a72315820dbd7b9bada9509238aad05d46deb3cee3c11df2a5237e4539fc3e0347352c57964736f6c63430005110032
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.