Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
This contract has been partially verified via Sourcify.
View contract in Sourcify repository
- Contract name:
- FastExitHandlerMigration
- Optimization enabled
- true
- Compiler version
- v0.5.2+commit.1df8f40c
- Optimization runs
- 200
- EVM Version
- byzantium
- Verified at
- 2026-04-22T18:08:24.365311Z
FastExitHandlerMigration.sol
/**
*Submitted for verification at Etherscan.io on 2019-06-20
*/
/**
*Submitted for verification at Etherscan.io on 2019-02-09
*/
/**
* Copyright (c) 2018-present, Leap DAO (leapdao.org)
*
* This source code is licensed under the Mozilla Public License, version 2,
* found in the LICENSE file in the root directory of this source tree.
*/
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);
}
}
contract Bridge {
event NewHeight(uint256 height, bytes32 indexed root);
event NewOperator(address operator);
struct Period {
uint32 height; // the height of last block in period
uint32 timestamp;
}
bytes32 constant GENESIS = 0x4920616d207665727920616e6772792c20627574206974207761732066756e21;
bytes32 public tipHash; // hash of first period that has extended chain to some height
uint256 public genesisBlockNumber;
uint256 parentBlockInterval; // how often epochs can be submitted max
uint256 public lastParentBlock; // last ethereum block when epoch was submitted
address public operator; // the operator contract
mapping(bytes32 => Period) public periods;
function getParentBlockInterval() public view returns (uint256) {
return parentBlockInterval;
}
function setParentBlockInterval(uint256 _parentBlockInterval) public {
parentBlockInterval = _parentBlockInterval;
}
function submitPeriod(
bytes32 _prevHash,
bytes32 _root)
public returns (uint256 newHeight) {
}
}
contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private initializing;
/**
* @dev Modifier to use in the initializer function of a contract.
*/
modifier initializer() {
require(initializing || isConstructor() || !initialized, "Contract instance has already been initialized");
bool wasInitializing = initializing;
initializing = true;
initialized = true;
_;
initializing = wasInitializing;
}
/// @dev Returns true if and only if the function is running in the constructor
function isConstructor() private view returns (bool) {
// extcodesize checks the size of the code stored in an address, and
// address returns the current address. Since the code is still not
// deployed when running a constructor, any checks on its code size will
// yield zero, making it an effective way to detect if a contract is
// under construction or not.
uint256 cs;
assembly { cs := extcodesize(address) }
return cs == 0;
}
// Reserved storage space to allow for layout changes in the future.
uint256[50] private ______gap;
}
/**
* @title Adminable
*
* @dev Helper contract to support initializer functions. To use it, replace
* the constructor with a function that has the `initializer` modifier.
* WARNING: Unlike constructors, initializer functions must be manually
* invoked. This applies both to deploying an Initializable contract, as well
* as extending an Initializable contract via inheritance.
* WARNING: When used with inheritance, manual care must be taken to not invoke
* a parent initializer twice, or ensure that all initializers are idempotent,
* because this is not dealt with automatically as with constructors.
*/
contract Adminable is Initializable {
/**
* @dev Storage slot with the admin of the contract.
* This is the keccak-256 hash of "org.zeppelinos.proxy.admin", and is
* validated in the constructor.
*/
bytes32 private constant ADMIN_SLOT = 0x10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b;
/**
* @dev Modifier to check whether the `msg.sender` is the admin.
* If it is, it will run the function. Otherwise, fails.
*/
modifier ifAdmin() {
require(msg.sender == _admin());
_;
}
function admin() external view returns (address) {
return _admin();
}
/**
* @return The admin slot.
*/
function _admin() internal view returns (address adm) {
bytes32 slot = ADMIN_SLOT;
assembly {
adm := sload(slot)
}
}
}
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
interface ERC20 {
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);
}
/**
* @title IERC165
* @dev https://github.com/ethereum/EIPs/blob/master/EIPS/eip-165.md
*/
interface ERC165 {
/**
* @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);
}
contract TransferrableToken is ERC165 {
function transferFrom(address _from, address _to, uint256 _valueOrTokenId) public;
function approve(address _to, uint256 _value) public;
}
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;
}
}
/**
* @title PriorityQueue
* @dev A priority queue implementation
*/
library PriorityQueue {
using SafeMath for uint256;
struct Token {
TransferrableToken addr;
uint256[] heapList;
uint256 currentSize;
}
function insert(Token storage self, uint256 k) public {
self.heapList.push(k);
self.currentSize = self.currentSize.add(1);
percUp(self, self.currentSize);
}
function minChild(Token storage self, uint256 i) public view returns (uint256) {
if (i.mul(2).add(1) > self.currentSize) {
return i.mul(2);
} else {
if (self.heapList[i.mul(2)] < self.heapList[i.mul(2).add(1)]) {
return i.mul(2);
} else {
return i.mul(2).add(1);
}
}
}
function getMin(Token storage self) public view returns (uint256) {
return self.heapList[1];
}
function delMin(Token storage self) public returns (uint256) {
uint256 retVal = self.heapList[1];
self.heapList[1] = self.heapList[self.currentSize];
delete self.heapList[self.currentSize];
self.currentSize = self.currentSize.sub(1);
percDown(self, 1);
self.heapList.length = self.heapList.length.sub(1);
return retVal;
}
// solium-disable-next-line security/no-assign-params
function percUp(Token storage self, uint256 i) private {
uint256 j = i;
uint256 newVal = self.heapList[i];
while (newVal < self.heapList[i.div(2)]) {
self.heapList[i] = self.heapList[i.div(2)];
i = i.div(2);
}
if (i != j) self.heapList[i] = newVal;
}
// solium-disable-next-line security/no-assign-params
function percDown(Token storage self, uint256 i) private {
uint256 j = i;
uint256 newVal = self.heapList[i];
uint256 mc = minChild(self, i);
while (mc <= self.currentSize && newVal > self.heapList[mc]) {
self.heapList[i] = self.heapList[mc];
i = mc;
mc = minChild(self, i);
}
if (i != j) self.heapList[i] = newVal;
}
}
contract Vault is Adminable {
event NewToken(address indexed tokenAddr, uint16 color);
Bridge public bridge;
uint16 public erc20TokenCount;
uint16 public nftTokenCount;
mapping(uint16 => PriorityQueue.Token) public tokens;
mapping(address => bool) public tokenColors;
function initialize(Bridge _bridge) public initializer {
bridge = _bridge;
}
function getTokenAddr(uint16 _color) public view returns (address) {
return address(tokens[_color].addr);
}
function registerToken(address _token, bool _isERC721) public ifAdmin {
// make sure token is not 0x0 and that it has not been registered yet
require(_token != address(0), "Tried to register 0x0 address");
require(!tokenColors[_token], "Token already registered");
uint16 color;
if (_isERC721) {
require(TransferrableToken(_token).supportsInterface(0x80ac58cd) == true, "Not an ERC721 token");
color = 32769 + nftTokenCount; // NFT color namespace starts from 2^15 + 1
nftTokenCount += 1;
} else {
require(ERC20(_token).totalSupply() >= 0, "Not an ERC20 token");
color = erc20TokenCount;
erc20TokenCount += 1;
}
uint256[] memory arr = new uint256[](1);
tokenColors[_token] = true;
tokens[color] = PriorityQueue.Token({
addr: TransferrableToken(_token),
heapList: arr,
currentSize: 0
});
emit NewToken(_token, color);
}
// solium-disable-next-line mixedcase
uint256[50] private ______gap;
}
contract DepositHandler is Vault {
event NewDeposit(
uint32 indexed depositId,
address indexed depositor,
uint256 indexed color,
uint256 amount
);
event MinGasPrice(uint256 minGasPrice);
struct Deposit {
uint64 time;
uint16 color;
address owner;
uint256 amount;
}
uint32 public depositCount;
uint256 public minGasPrice;
mapping(uint32 => Deposit) public deposits;
function setMinGasPrice(uint256 _minGasPrice) public ifAdmin {
minGasPrice = _minGasPrice;
emit MinGasPrice(minGasPrice);
}
/**
* @notice Add to the network `(_amountOrTokenId)` amount of a `(_color)` tokens
* or `(_amountOrTokenId)` token id if `(_color)` is NFT.
* @dev Token should be registered with the Bridge first.
* @param _owner Account to transfer tokens from
* @param _amountOrTokenId Amount (for ERC20) or token ID (for ERC721) to transfer
* @param _color Color of the token to deposit
*/
function deposit(address _owner, uint256 _amountOrTokenId, uint16 _color) public {
TransferrableToken token = tokens[_color].addr;
require(address(token) != address(0), "Token color not registered");
require(_amountOrTokenId > 0 || _color > 32769, "no 0 deposits for fungible tokens");
token.transferFrom(_owner, address(this), _amountOrTokenId);
bytes32 tipHash = bridge.tipHash();
uint256 timestamp;
(, timestamp) = bridge.periods(tipHash);
depositCount++;
deposits[depositCount] = Deposit({
time: uint32(timestamp),
owner: _owner,
color: _color,
amount: _amountOrTokenId
});
emit NewDeposit(
depositCount,
_owner,
_color,
_amountOrTokenId
);
}
// solium-disable-next-line mixedcase
uint256[50] private ______gap;
}
library TxLib {
uint constant internal WORD_SIZE = 32;
uint constant internal ONES = ~uint(0);
enum TxType { None0, None1, Deposit, Transfer, None4, None5,
None6, None7, None8, None9, None10, None11, None12, SpendCond }
struct Outpoint {
bytes32 hash;
uint8 pos;
}
struct Input {
Outpoint outpoint;
bytes32 r;
bytes32 s;
uint8 v;
bytes script;
bytes msgData;
}
struct Output {
uint256 value;
uint16 color;
address owner;
bytes32 stateRoot;
}
struct Tx {
TxType txType;
Input[] ins;
Output[] outs;
}
function parseInput(
TxType _type, bytes memory _txData, uint256 _pos, uint256 offset, Input[] memory _ins
) internal pure returns (uint256 newOffset) {
bytes32 inputData;
uint8 index;
if (_type == TxType.Deposit) {
assembly {
// load the depositId (4 bytes) starting from byte 2 of tx
inputData := mload(add(add(offset, 4), _txData))
}
inputData = bytes32(uint256(uint32(uint256(inputData))));
index = 0;
newOffset = offset + 4;
} else {
assembly {
// load the prevHash (32 bytes) from input
inputData := mload(add(add(offset, 32), _txData))
// load the output index (1 byte) from input
index := mload(add(add(offset, 33), _txData))
}
newOffset = offset + 33;
}
Outpoint memory outpoint = Outpoint(inputData, index);
bytes memory data = new bytes(0);
Input memory input = Input(outpoint, 0, 0, 0, data, data); // solium-disable-line arg-overflow
if (_type == TxType.SpendCond) {
uint16 len;
assembly {
len := mload(add(add(offset, 35), _txData))
}
// read msgData
data = new bytes(len);
uint src;
uint dest;
assembly {
src := add(add(add(offset, 35), 0x20), _txData)
dest := add(data, 0x20)
}
memcopy(src, dest, len);
input.msgData = data;
newOffset = offset + 37 + len;
assembly {
len := mload(add(newOffset, _txData))
}
// read script
data = new bytes(len);
assembly {
src := add(add(add(newOffset, 0), 0x20), _txData)
dest := add(data, 0x20)
}
memcopy(src, dest, len);
input.script = data;
newOffset = newOffset + len;
}
if (_type == TxType.Transfer) {
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := mload(add(add(offset, 65), _txData))
s := mload(add(add(offset, 97), _txData))
v := mload(add(add(offset, 98), _txData))
}
input.r = r;
input.s = s;
input.v = v;
newOffset = offset + 33 + 65;
}
_ins[_pos] = input;
}
// Copies 'len' bytes from 'srcPtr' to 'destPtr'.
// NOTE: This function does not check if memory is allocated, it only copies the bytes.
function memcopy(uint srcPtr, uint destPtr, uint len) internal pure {
uint offset = 0;
uint size = len / WORD_SIZE;
// Copy word-length chunks while possible.
for (uint i = 0; i < size; i++) {
offset = i * WORD_SIZE;
assembly {
mstore(add(destPtr, offset), mload(add(srcPtr, offset)))
}
}
offset = size*WORD_SIZE;
uint mask = ONES << 8*(32 - len % WORD_SIZE);
assembly {
let nSrc := add(srcPtr, offset)
let nDest := add(destPtr, offset)
mstore(nDest, or(and(mload(nSrc), mask), and(mload(nDest), not(mask))))
}
}
function parseOutput(
bytes memory _txData, uint256 _pos, uint256 offset, Output[] memory _outs
) internal pure returns (uint256 newOffset) {
uint256 value;
uint16 color;
address owner;
assembly {
value := mload(add(add(offset, 32), _txData))
color := mload(add(add(offset, 34), _txData))
owner := mload(add(add(offset, 54), _txData))
}
Output memory output = Output(value, color, owner, 0); // solium-disable-line arg-overflow
_outs[_pos] = output;
newOffset = offset + 54;
}
function parseTx(bytes memory _txData) internal pure returns (Tx memory txn) {
// read type
TxType txType;
uint256 a;
assembly {
a := mload(add(0x20, _txData))
}
a = a >> 248; // get first byte
if (a == 2) {
txType = TxType.Deposit;
} else if (a == 3) {
txType = TxType.Transfer;
} else if (a == 13) {
txType = TxType.SpendCond;
} else {
revert("unknown tx type");
}
// read ins and outs
assembly {
a := mload(add(0x21, _txData))
}
a = a >> 252; // get ins-length nibble
Input[] memory ins = new Input[](a);
uint256 offset = 2;
for (uint i = 0; i < ins.length; i++) {
offset = parseInput(txType, _txData, i, offset, ins); // solium-disable-line arg-overflow
}
assembly {
a := mload(add(0x21, _txData))
}
a = (a >> 248) & 0x0f; // get outs-length nibble
Output[] memory outs = new Output[](a);
for (uint256 i = 0; i < outs.length; i++) {
offset = parseOutput(_txData, i, offset, outs); // solium-disable-line arg-overflow
}
txn = Tx(txType, ins, outs);
}
function getSigHash(bytes memory _txData) internal pure returns (bytes32 sigHash) {
uint256 a;
assembly {
a := mload(add(0x20, _txData))
}
a = a >> 248;
// if not transfer, sighash is just tx hash
require(a == 3);
// read ins
assembly {
a := mload(add(0x21, _txData))
}
a = a >> 252; // get ins-length nibble
bytes memory sigData = new bytes(_txData.length);
assembly {
// copy type
mstore8(add(sigData, 32), byte(0, mload(add(_txData, 32))))
// copy #inputs / #outputs
mstore8(add(sigData, 33), byte(1, mload(add(_txData, 32))))
let offset := 0
for
{ let i := 0 }
lt(i, a)
{ i := add(i, 1) }
{
mstore(add(sigData, add(34, offset)), mload(add(_txData, add(34, offset))))
mstore8(add(sigData, add(66, offset)), byte(0, mload(add(_txData, add(66, offset)))))
offset := add(offset, add(33, 65))
}
for
{ let i := add(34, offset) }
lt(i, add(64, mload(_txData)))
{ i := add(i, 0x20) }
{
mstore(add(sigData, i), mload(add(_txData, i)))
}
}
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", uint2str(_txData.length), sigData));
}
// solium-disable-next-line security/no-assign-params
function getMerkleRoot(
bytes32 _leaf, uint256 _index, uint256 _offset, bytes32[] memory _proof
) internal pure returns (bytes32) {
bytes32 temp;
for (uint256 i = _offset; i < _proof.length; i++) {
temp = _proof[i];
if (_index % 2 == 0) {
assembly {
mstore(0, _leaf)
mstore(0x20, temp)
_leaf := keccak256(0, 0x40)
}
} else {
assembly {
mstore(0, temp)
mstore(0x20, _leaf)
_leaf := keccak256(0, 0x40)
}
}
_index = _index / 2;
}
return _leaf;
}
//validate that transaction is included to the period (merkle proof)
function validateProof(
uint256 _cdOffset, bytes32[] memory _proof
) internal pure returns (uint64 txPos, bytes32 txHash, bytes memory txData) {
uint256 offset = uint8(uint256(_proof[1] >> 248));
uint256 txLength = uint16(uint256(_proof[1] >> 224));
txData = new bytes(txLength);
assembly {
calldatacopy(add(txData, 0x20), add(68, add(offset, _cdOffset)), txLength)
}
txHash = keccak256(txData);
txPos = uint64(uint256(_proof[1] >> 160));
bytes32 root = getMerkleRoot(
txHash,
txPos,
uint8(uint256(_proof[1] >> 240)),
_proof
);
require(root == _proof[0]);
}
function recoverTxSigner(uint256 offset, bytes32[] memory _proof) internal pure returns (address dest) {
uint16 txLength = uint16(uint256(_proof[1] >> 224));
bytes memory txData = new bytes(txLength);
bytes32 r;
bytes32 s;
uint8 v;
assembly {
calldatacopy(add(txData, 32), add(114, offset), 43)
r := calldataload(add(157, offset))
s := calldataload(add(189, offset))
v := calldataload(add(190, offset))
calldatacopy(add(txData, 140), add(222, offset), 28) // 32 + 43 + 65
}
dest = ecrecover(getSigHash(txData), v, r, s); // solium-disable-line arg-overflow
}
// https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol#L886
// solium-disable-next-line security/no-assign-params
function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
if (_i == 0) {
return "0";
}
uint j = _i;
uint len;
while (j != 0) {
len++;
j /= 10;
}
bytes memory bstr = new bytes(len);
uint k = len - 1;
while (_i != 0) {
bstr[k--] = byte(uint8(48 + _i % 10));
_i /= 10;
}
return string(bstr);
}
}
contract ExitHandler is DepositHandler {
using PriorityQueue for PriorityQueue.Token;
event ExitStarted(
bytes32 indexed txHash,
uint8 indexed outIndex,
uint256 indexed color,
address exitor,
uint256 amount
);
struct Exit {
uint256 amount;
uint16 color;
address owner;
bool finalized;
uint32 priorityTimestamp;
uint256 stake;
}
uint256 public exitDuration;
uint256 public exitStake;
uint256 public nftExitCounter;
/**
* UTXO → Exit mapping. Contains exits for both NFT and ERC20 colors
*/
mapping(bytes32 => Exit) public exits;
function initializeWithExit(
Bridge _bridge,
uint256 _exitDuration,
uint256 _exitStake) public initializer {
initialize(_bridge);
exitDuration = _exitDuration;
exitStake = _exitStake;
emit MinGasPrice(0);
}
function setExitStake(uint256 _exitStake) public ifAdmin {
exitStake = _exitStake;
}
function setExitDuration(uint256 _exitDuration) public ifAdmin {
exitDuration = _exitDuration;
}
function startExit(
bytes32[] memory _youngestInputProof, bytes32[] memory _proof,
uint8 _outputIndex, uint8 _inputIndex
) public payable {
require(msg.value >= exitStake, "Not enough ether sent to pay for exit stake");
uint32 timestamp;
(, timestamp) = bridge.periods(_proof[0]);
require(timestamp > 0, "The referenced period was not submitted to bridge");
if (_youngestInputProof.length > 0) {
(, timestamp) = bridge.periods(_youngestInputProof[0]);
require(timestamp > 0, "The referenced period was not submitted to bridge");
}
// check exiting tx inclusion in the root chain block
bytes32 txHash;
bytes memory txData;
uint64 txPos;
(txPos, txHash, txData) = TxLib.validateProof(32 * (_youngestInputProof.length + 2) + 64, _proof);
// parse exiting tx and check if it is exitable
TxLib.Tx memory exitingTx = TxLib.parseTx(txData);
TxLib.Output memory out = exitingTx.outs[_outputIndex];
bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash)));
require(out.owner == msg.sender, "Only UTXO owner can start exit");
require(out.value > 0, "UTXO has no value");
require(exits[utxoId].amount == 0, "The exit for UTXO has already been started");
require(!exits[utxoId].finalized, "The exit for UTXO has already been finalized");
uint256 priority;
if (_youngestInputProof.length > 0) {
// check youngest input tx inclusion in the root chain block
bytes32 inputTxHash;
(txPos, inputTxHash,) = TxLib.validateProof(96, _youngestInputProof);
require(
inputTxHash == exitingTx.ins[_inputIndex].outpoint.hash,
"Input from the proof is not referenced in exiting tx"
);
if (isNft(out.color)) {
priority = (nftExitCounter << 128) | uint128(uint256(utxoId));
nftExitCounter++;
} else {
priority = getERC20ExitPriority(timestamp, utxoId, txPos);
}
} else {
require(exitingTx.txType == TxLib.TxType.Deposit, "Expected deposit tx");
if (isNft(out.color)) {
priority = (nftExitCounter << 128) | uint128(uint256(utxoId));
nftExitCounter++;
} else {
priority = getERC20ExitPriority(timestamp, utxoId, txPos);
}
}
tokens[out.color].insert(priority);
exits[utxoId] = Exit({
owner: out.owner,
color: out.color,
amount: out.value,
finalized: false,
stake: exitStake,
priorityTimestamp: timestamp
});
emit ExitStarted(
txHash,
_outputIndex,
out.color,
out.owner,
out.value
);
}
function startDepositExit(uint256 _depositId) public payable {
require(msg.value >= exitStake, "Not enough ether sent to pay for exit stake");
// check that deposit exits
Deposit memory deposit = deposits[uint32(_depositId)];
require(deposit.owner == msg.sender, "Only deposit owner can start exit");
require(deposit.amount > 0, "deposit has no value");
require(exits[bytes32(_depositId)].amount == 0, "The exit of deposit has already been started");
require(!exits[bytes32(_depositId)].finalized, "The exit for deposit has already been finalized");
uint256 priority;
if (isNft(deposit.color)) {
priority = (nftExitCounter << 128) | uint128(_depositId);
nftExitCounter++;
} else {
priority = getERC20ExitPriority(uint32(deposit.time), bytes32(_depositId), 0);
}
tokens[deposit.color].insert(priority);
exits[bytes32(_depositId)] = Exit({
owner: deposit.owner,
color: deposit.color,
amount: deposit.amount,
finalized: false,
stake: exitStake,
priorityTimestamp: uint32(now)
});
emit ExitStarted(
bytes32(_depositId),
0,
deposit.color,
deposit.owner,
deposit.amount
);
}
// @dev Finalizes exit for the chosen color with the highest priority
function finalizeExits(uint16 _color) public {
bytes32 utxoId;
uint256 exitableAt;
Exit memory currentExit;
(utxoId, exitableAt) = getNextExit(_color);
require(tokens[_color].currentSize > 0, "Queue empty for color.");
for (uint i = 0; i<20; i++) {
// if queue is empty or top exit cannot be exited yet, stop
if (exitableAt > block.timestamp) {
return;
}
currentExit = exits[utxoId];
if (currentExit.owner != address(0) || currentExit.amount != 0) { // exit was not removed
// Note: for NFTs, the amount is actually the NFT id (both uint256)
if (isNft(currentExit.color)) {
tokens[currentExit.color].addr.transferFrom(address(this), currentExit.owner, currentExit.amount);
} else {
tokens[currentExit.color].addr.approve(address(this), currentExit.amount);
tokens[currentExit.color].addr.transferFrom(address(this), currentExit.owner, currentExit.amount);
}
// Pay exit stake
address(uint160(currentExit.owner)).send(currentExit.stake);
}
tokens[currentExit.color].delMin();
exits[utxoId].finalized = true;
if (tokens[currentExit.color].currentSize > 0) {
(utxoId, exitableAt) = getNextExit(_color);
} else {
return;
}
}
}
// @dev For backwards compatibility reasons...
function finalizeTopExit(uint16 _color) public {
finalizeExits(_color);
}
function challengeExit(
bytes32[] memory _proof,
bytes32[] memory _prevProof,
uint8 _outputIndex,
uint8 _inputIndex
) public {
// validate exiting tx
uint256 offset = 32 * (_proof.length + 2);
bytes32 txHash1;
bytes memory txData;
(, txHash1, txData) = TxLib.validateProof(offset + 64, _prevProof);
bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash1)));
TxLib.Tx memory txn;
if (_proof.length > 0) {
// validate spending tx
bytes32 txHash;
(, txHash, txData) = TxLib.validateProof(96, _proof);
txn = TxLib.parseTx(txData);
// make sure one is spending the other one
require(txHash1 == txn.ins[_inputIndex].outpoint.hash);
require(_outputIndex == txn.ins[_inputIndex].outpoint.pos);
// if transfer, make sure signature correct
if (txn.txType == TxLib.TxType.Transfer) {
bytes32 sigHash = TxLib.getSigHash(txData);
address signer = ecrecover(
sigHash,
txn.ins[_inputIndex].v,
txn.ins[_inputIndex].r,
txn.ins[_inputIndex].s
);
require(exits[utxoId].owner == signer);
} else {
revert("unknown tx type");
}
} else {
// challenging deposit exit
txn = TxLib.parseTx(txData);
utxoId = txn.ins[_inputIndex].outpoint.hash;
if (txn.txType == TxLib.TxType.Deposit) {
// check that deposit was included correctly
// only then it should be usable for challenge
Deposit memory deposit = deposits[uint32(uint256(utxoId))];
require(deposit.amount == txn.outs[0].value, "value mismatch");
require(deposit.owner == txn.outs[0].owner, "owner mismatch");
require(deposit.color == txn.outs[0].color, "color mismatch");
// todo: check timely inclusion of deposit tx
// this will prevent grieving attacks by the operator
} else {
revert("unexpected tx type");
}
}
require(exits[utxoId].amount > 0, "exit not found");
require(!exits[utxoId].finalized, "The exit has already been finalized");
// award stake to challanger
msg.sender.transfer(exits[utxoId].stake);
// delete invalid exit
delete exits[utxoId];
}
function challengeYoungestInput(
bytes32[] memory _youngerInputProof,
bytes32[] memory _exitingTxProof,
uint8 _outputIndex,
uint8 _inputIndex
) public {
// validate exiting input tx
bytes32 txHash;
bytes memory txData;
(, txHash, txData) = TxLib.validateProof(32 * (_youngerInputProof.length + 2) + 64, _exitingTxProof);
bytes32 utxoId = bytes32(uint256(_outputIndex) << 120 | uint120(uint256(txHash)));
// check the exit exists
require(exits[utxoId].amount > 0, "There is no exit for this UTXO");
TxLib.Tx memory exitingTx = TxLib.parseTx(txData);
// validate younger input tx
(,txHash,) = TxLib.validateProof(96, _youngerInputProof);
// check younger input is actually an input of exiting tx
require(txHash == exitingTx.ins[_inputIndex].outpoint.hash, "Given output is not referenced in exiting tx");
uint32 youngerInputTimestamp;
(,youngerInputTimestamp) = bridge.periods(_youngerInputProof[0]);
require(youngerInputTimestamp > 0, "The referenced period was not submitted to bridge");
require(exits[utxoId].priorityTimestamp < youngerInputTimestamp, "Challenged input should be older");
// award stake to challanger
msg.sender.transfer(exits[utxoId].stake);
// delete invalid exit
delete exits[utxoId];
}
function getNextExit(uint16 _color) internal view returns (bytes32 utxoId, uint256 exitableAt) {
uint256 priority = tokens[_color].getMin();
utxoId = bytes32(uint256(uint128(priority)));
exitableAt = priority >> 192;
}
function isNft(uint16 _color) internal pure returns (bool) {
return _color > 32768; // 2^15
}
function getERC20ExitPriority(
uint32 timestamp, bytes32 utxoId, uint64 txPos
) internal view returns (uint256 priority) {
uint256 exitableAt = Math.max(timestamp + (2 * exitDuration), block.timestamp + exitDuration);
return (exitableAt << 192) | uint256(txPos) << 128 | uint128(uint256(utxoId));
}
// solium-disable-next-line mixedcase
uint256[50] private ______gap;
}
contract FastExitHandlerMigration is ExitHandler {
struct Data {
uint32 timestamp;
bytes32 txHash;
uint64 txPos;
bytes32 utxoId;
}
function deposit(address, uint256, uint16) public {
revert("not implemented");
}
function startExit(bytes32[] memory, bytes32[] memory, uint8, uint8) public payable {
revert("not implemented");
}
function startDepositExit(uint256) public payable {
revert("not implemented");
}
function startBoughtExit(bytes32[] memory, bytes32[] memory, uint8, uint8, bytes32[] memory) public payable {
revert("not implemented");
}
modifier onlyMultisig() {
// replace this on mainnet:
require(msg.sender == 0xC5cDcD5470AEf35fC33BDDff3f8eCeC027F95B1d, "msg.sender not multisig");
_;
}
function withdrawSupply(address _token) public onlyMultisig {
require(_token != address(0), "not real address");
ERC20 token = ERC20(_token);
token.transfer(msg.sender, token.balanceOf(address(this)));
}
}
Compiler Settings
{"remappings":[],"optimizer":{"runs":200,"enabled":true},"libraries":{},"evmVersion":"byzantium","compilationTarget":{"FastExitHandlerMigration.sol":"FastExitHandlerMigration"}}
Contract ABI
[{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint32","name":""}],"name":"depositCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"challengeYoungestInput","inputs":[{"type":"bytes32[]","name":"_youngerInputProof"},{"type":"bytes32[]","name":"_exitingTxProof"},{"type":"uint8","name":"_outputIndex"},{"type":"uint8","name":"_inputIndex"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"exitStake","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint64","name":"time"},{"type":"uint16","name":"color"},{"type":"address","name":"owner"},{"type":"uint256","name":"amount"}],"name":"deposits","inputs":[{"type":"uint32","name":""}],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"challengeExit","inputs":[{"type":"bytes32[]","name":"_proof"},{"type":"bytes32[]","name":"_prevProof"},{"type":"uint8","name":"_outputIndex"},{"type":"uint8","name":"_inputIndex"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"registerToken","inputs":[{"type":"address","name":"_token"},{"type":"bool","name":"_isERC721"}],"constant":false},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startBoughtExit","inputs":[{"type":"bytes32[]","name":""},{"type":"bytes32[]","name":""},{"type":"uint8","name":""},{"type":"uint8","name":""},{"type":"bytes32[]","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint16","name":""}],"name":"nftTokenCount","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"nftExitCounter","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeExits","inputs":[{"type":"uint16","name":"_color"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setMinGasPrice","inputs":[{"type":"uint256","name":"_minGasPrice"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"exitDuration","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExitStake","inputs":[{"type":"uint256","name":"_exitStake"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initializeWithExit","inputs":[{"type":"address","name":"_bridge"},{"type":"uint256","name":"_exitDuration"},{"type":"uint256","name":"_exitStake"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint16","name":""}],"name":"erc20TokenCount","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"finalizeTopExit","inputs":[{"type":"uint16","name":"_color"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"initialize","inputs":[{"type":"address","name":"_bridge"}],"constant":false},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"deposit","inputs":[{"type":"address","name":""},{"type":"uint256","name":""},{"type":"uint16","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":""}],"name":"minGasPrice","inputs":[],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"getTokenAddr","inputs":[{"type":"uint16","name":"_color"}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"bridge","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"setExitDuration","inputs":[{"type":"uint256","name":"_exitDuration"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"bool","name":""}],"name":"tokenColors","inputs":[{"type":"address","name":""}],"constant":true},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":"addr"},{"type":"uint256","name":"currentSize"}],"name":"tokens","inputs":[{"type":"uint16","name":""}],"constant":true},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startDepositExit","inputs":[{"type":"uint256","name":""}],"constant":false},{"type":"function","stateMutability":"payable","payable":true,"outputs":[],"name":"startExit","inputs":[{"type":"bytes32[]","name":""},{"type":"bytes32[]","name":""},{"type":"uint8","name":""},{"type":"uint8","name":""}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"address","name":""}],"name":"admin","inputs":[],"constant":true},{"type":"function","stateMutability":"nonpayable","payable":false,"outputs":[],"name":"withdrawSupply","inputs":[{"type":"address","name":"_token"}],"constant":false},{"type":"function","stateMutability":"view","payable":false,"outputs":[{"type":"uint256","name":"amount"},{"type":"uint16","name":"color"},{"type":"address","name":"owner"},{"type":"bool","name":"finalized"},{"type":"uint32","name":"priorityTimestamp"},{"type":"uint256","name":"stake"}],"name":"exits","inputs":[{"type":"bytes32","name":""}],"constant":true},{"type":"event","name":"ExitStarted","inputs":[{"type":"bytes32","name":"txHash","indexed":true},{"type":"uint8","name":"outIndex","indexed":true},{"type":"uint256","name":"color","indexed":true},{"type":"address","name":"exitor","indexed":false},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"NewDeposit","inputs":[{"type":"uint32","name":"depositId","indexed":true},{"type":"address","name":"depositor","indexed":true},{"type":"uint256","name":"color","indexed":true},{"type":"uint256","name":"amount","indexed":false}],"anonymous":false},{"type":"event","name":"MinGasPrice","inputs":[{"type":"uint256","name":"minGasPrice","indexed":false}],"anonymous":false},{"type":"event","name":"NewToken","inputs":[{"type":"address","name":"tokenAddr","indexed":true},{"type":"uint16","name":"color","indexed":false}],"anonymous":false}]
Contract Creation Code
0x608060405234801561001057600080fd5b50613055806100206000396000f3fe6080604052600436106101c65760003560e060020a90048063bc48bc22116100fb578063eabd686811610099578063f6169e3511610068578063f6169e3514610a32578063f851a44014610b69578063ff293da214610b7e578063ffa696d314610bb1576101c6565b8063eabd686814610953578063eefc30831461097d578063f3c20de0146109c4578063f5239f6414610a15576101c6565b8063d2d0e066116100d5578063d2d0e0661461089c578063d96ed505146108df578063db9ed47e146108f4578063e78cea921461093e576101c6565b8063bc48bc2214610826578063c215f1be1461083b578063c4d66de814610869576101c6565b80637695d79b1161016857806390ac18661161014257806390ac18661461077e5780639eeaa7f4146107a8578063ac3d8558146107bd578063ba27a911146107e7576101c6565b80637695d79b1461070f57806378e706451461073b5780638290fe2514610750576101c6565b80635bae510d116101a45780635bae510d1461036657806365f0b9b5146103d25780636710b83f14610516578063690505a714610551576101c6565b80632dfdf0b5146101cb578063374a5435146101f95780633882f7421461033f575b600080fd5b3480156101d757600080fd5b506101e0610c1f565b6040805163ffffffff9092168252519081900360200190f35b34801561020557600080fd5b5061033d6004803603608081101561021c57600080fd5b81019060208101813564010000000081111561023757600080fd5b82018360208201111561024957600080fd5b8035906020019184602083028401116401000000008311171561026b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156102bb57600080fd5b8201836020820111156102cd57600080fd5b803590602001918460208302840111640100000000831117156102ef57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610c2b9050565b005b34801561034b57600080fd5b50610354610f48565b60408051918252519081900360200190f35b34801561037257600080fd5b506103966004803603602081101561038957600080fd5b503563ffffffff16610f4e565b6040805167ffffffffffffffff909516855261ffff9093166020850152600160a060020a03909116838301526060830152519081900360800190f35b3480156103de57600080fd5b5061033d600480360360808110156103f557600080fd5b81019060208101813564010000000081111561041057600080fd5b82018360208201111561042257600080fd5b8035906020019184602083028401116401000000008311171561044457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561049457600080fd5b8201836020820111156104a657600080fd5b803590602001918460208302840111640100000000831117156104c857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610f9d9050565b34801561052257600080fd5b5061033d6004803603604081101561053957600080fd5b50600160a060020a03813516906020013515156115c8565b61033d600480360360a081101561056757600080fd5b81019060208101813564010000000081111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460208302840111640100000000831117156105b657600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561060657600080fd5b82018360208201111561061857600080fd5b8035906020019184602083028401116401000000008311171561063a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929560ff853581169660208701359091169591945092506060810191506040013564010000000081111561069d57600080fd5b8201836020820111156106af57600080fd5b803590602001918460208302840111640100000000831117156106d157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611a16945050505050565b34801561071b57600080fd5b50610724611a66565b6040805161ffff9092168252519081900360200190f35b34801561074757600080fd5b50610354611a77565b34801561075c57600080fd5b5061033d6004803603602081101561077357600080fd5b503561ffff16611a7d565b34801561078a57600080fd5b5061033d600480360360208110156107a157600080fd5b5035611f09565b3480156107b457600080fd5b50610354611f60565b3480156107c957600080fd5b5061033d600480360360208110156107e057600080fd5b5035611f66565b3480156107f357600080fd5b5061033d6004803603606081101561080a57600080fd5b50600160a060020a038135169060208101359060400135611f87565b34801561083257600080fd5b50610724612072565b34801561084757600080fd5b5061033d6004803603602081101561085e57600080fd5b503561ffff16612094565b34801561087557600080fd5b5061033d6004803603602081101561088c57600080fd5b5035600160a060020a031661209d565b3480156108a857600080fd5b5061033d600480360360608110156108bf57600080fd5b508035600160a060020a0316906020810135906040013561ffff16611a16565b3480156108eb57600080fd5b5061035461215f565b34801561090057600080fd5b506109226004803603602081101561091757600080fd5b503561ffff16612165565b60408051600160a060020a039092168252519081900360200190f35b34801561094a57600080fd5b50610922612188565b34801561095f57600080fd5b5061033d6004803603602081101561097657600080fd5b5035612197565b34801561098957600080fd5b506109b0600480360360208110156109a057600080fd5b5035600160a060020a03166121b8565b604080519115158252519081900360200190f35b3480156109d057600080fd5b506109f2600480360360208110156109e757600080fd5b503561ffff166121cd565b60408051600160a060020a03909316835260208301919091528051918290030190f35b61033d60048036036020811015610a2b57600080fd5b5035611a16565b61033d60048036036080811015610a4857600080fd5b810190602081018135640100000000811115610a6357600080fd5b820183602082011115610a7557600080fd5b80359060200191846020830284011164010000000083111715610a9757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610ae757600080fd5b820183602082011115610af957600080fd5b80359060200191846020830284011164010000000083111715610b1b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150611a169050565b348015610b7557600080fd5b506109226121f2565b348015610b8a57600080fd5b5061033d60048036036020811015610ba157600080fd5b5035600160a060020a0316612202565b348015610bbd57600080fd5b50610bdb60048036036020811015610bd457600080fd5b50356123e1565b6040805196875261ffff9095166020870152600160a060020a0390931685850152901515606085015263ffffffff16608084015260a0830152519081900360c00190f35b60685463ffffffff1681565b60006060610c43865160020160200260400186612445565b6f0100000000000000000000000000000060ff8816026effffffffffffffffffffffffffffff831617600081815260a06020526040812054939650919450925010610cd8576040805160e560020a62461bcd02815260206004820152601e60248201527f5468657265206973206e6f206578697420666f722074686973205554584f0000604482015290519081900360640190fd5b610ce0612e42565b610ce983612587565b9050610cf6606089612445565b5060208301518051919650915060ff8716908110610d1057fe5b6020908102909101015151518414610d5c5760405160e560020a62461bcd02815260040180806020018281038252602c815260200180612fad602c913960400191505060405180910390fd5b6033548851600091600160a060020a03169063c222ef6d908b9084908110610d8057fe5b906020019060200201516040518263ffffffff1660e060020a02815260040180828152602001915050604080518083038186803b158015610dc057600080fd5b505afa158015610dd4573d6000803e3d6000fd5b505050506040513d6040811015610dea57600080fd5b50602001519050600063ffffffff821611610e395760405160e560020a62461bcd028152600401808060200182810382526031815260200180612f7c6031913960400191505060405180910390fd5b600083815260a0602052604090206001015463ffffffff808316770100000000000000000000000000000000000000000000009092041610610ec5576040805160e560020a62461bcd02815260206004820181905260248201527f4368616c6c656e67656420696e7075742073686f756c64206265206f6c646572604482015290519081900360640190fd5b600083815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015610f02573d6000803e3d6000fd5b505050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff1916905560020155505050505050565b609e5481565b606a602052600090815260409020805460019091015467ffffffffffffffff82169168010000000000000000810461ffff16916a0100000000000000000000909104600160a060020a03169084565b835160020160200260006060610fb66040840187612445565b9093509150506f0100000000000000000000000000000060ff8616026effffffffffffffffffffffffffffff831617610fed612e42565b6000895111156111f757600061100460608b612445565b95509150611013905084612587565b915081602001518760ff1681518110151561102a57fe5b602090810290910101515151851461104157600080fd5b6020820151805160ff891690811061105557fe5b602090810290910181015151015160ff89811691161461107457600080fd5b60038251600d81111561108357fe5b14156111a157600061109485612705565b9050600060018285602001518b60ff168151811015156110b057fe5b906020019060200201516060015186602001518c60ff168151811015156110d357fe5b906020019060200201516020015187602001518d60ff168151811015156110f657fe5b906020019060200201516040015160405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561115b573d6000803e3d6000fd5b505060408051601f190151600088815260a06020529190912060010154909250600160a060020a03808416620100009092041614905061119a57600080fd5b50506111f1565b6040805160e560020a62461bcd02815260206004820152600f60248201527f756e6b6e6f776e20747820747970650000000000000000000000000000000000604482015290519081900360640190fd5b50611486565b61120083612587565b905080602001518660ff1681518110151561121757fe5b602090810290910101515151915060028151600d81111561123457fe5b141561143657611242612e64565b5063ffffffff82166000908152606a602090815260408083208151608081018352815467ffffffffffffffff8116825268010000000000000000810461ffff16948201949094526a0100000000000000000000909304600160a060020a03168383015260010154606083015283015180519192909181106112bf57fe5b6020908102909101015151606082015114611324576040805160e560020a62461bcd02815260206004820152600e60248201527f76616c7565206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b60408201518051600090811061133657fe5b9060200190602002015160400151600160a060020a03168160400151600160a060020a03161415156113b2576040805160e560020a62461bcd02815260206004820152600e60248201527f6f776e6572206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040820151805160009081106113c457fe5b906020019060200201516020015161ffff16816020015161ffff161415156111f1576040805160e560020a62461bcd02815260206004820152600e60248201527f636f6c6f72206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160e560020a62461bcd02815260206004820152601260248201527f756e657870656374656420747820747970650000000000000000000000000000604482015290519081900360640190fd5b600082815260a06020526040812054116114ea576040805160e560020a62461bcd02815260206004820152600e60248201527f65786974206e6f7420666f756e64000000000000000000000000000000000000604482015290519081900360640190fd5b600082815260a0602052604090206001015460b060020a900460ff16156115455760405160e560020a62461bcd028152600401808060200182810382526023815260200180612fd96023913960400191505060405180910390fd5b600082815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015611582573d6000803e3d6000fd5b5050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002015550505050505050565b6115d06128e5565b600160a060020a031633146115e457600080fd5b600160a060020a0382161515611644576040805160e560020a62461bcd02815260206004820152601d60248201527f547269656420746f207265676973746572203078302061646472657373000000604482015290519081900360640190fd5b600160a060020a03821660009081526035602052604090205460ff16156116b5576040805160e560020a62461bcd02815260206004820152601860248201527f546f6b656e20616c726561647920726567697374657265640000000000000000604482015290519081900360640190fd5b6000811561180857604080517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f80ac58cd0000000000000000000000000000000000000000000000000000000060048201529051600160a060020a038516916301ffc9a7916024808301926020929190829003018186803b15801561173c57600080fd5b505afa158015611750573d6000803e3d6000fd5b505050506040513d602081101561176657600080fd5b505115156001146117c1576040805160e560020a62461bcd02815260206004820152601360248201527f4e6f7420616e2045524337323120746f6b656e00000000000000000000000000604482015290519081900360640190fd5b506033805477ffff0000000000000000000000000000000000000000000019811660b060020a9182900461ffff908116600181019091169092021790915561800101611916565b600083600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d602081101561187057600080fd5b505110156118c8576040805160e560020a62461bcd02815260206004820152601260248201527f4e6f7420616e20455243323020746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b506033805475ffff0000000000000000000000000000000000000000198116740100000000000000000000000000000000000000009182900461ffff90811660018101909116909202179091555b60408051600180825281830190925260609160208083019080388339505050600160a060020a0385811660008181526035602090815260408083208054600160ff199091168117909155815160608101835294855284830187815285830185905261ffff8a16855260348452919093208451815473ffffffffffffffffffffffffffffffffffffffff1916961695909517855551805195965092946119c2939285019290910190612e8b565b50604091820151600290910155805161ffff841681529051600160a060020a038616917ffe74dea79bde70d1990ddb655bac45735b14f495ddc508cfab80b7729aa9d668919081900360200190a250505050565b6040805160e560020a62461bcd02815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015290519081900360640190fd5b60335460b060020a900461ffff1681565b609f5481565b600080611a88612ed6565b611a918461290a565b61ffff861660009081526034602052604081206002015492955090935010611b03576040805160e560020a62461bcd02815260206004820152601660248201527f517565756520656d70747920666f7220636f6c6f722e00000000000000000000604482015290519081900360640190fd5b60005b6014811015611f015742831115611b205750505050611f06565b600084815260a06020818152604092839020835160c08101855281548152600182015461ffff811693820193909352620100008304600160a060020a031694810185905260b060020a830460ff16151560608201527701000000000000000000000000000000000000000000000090920463ffffffff16608083015260020154918101919091529250151580611bb65750815115155b15611ddf57611bc882602001516129f1565b15611c745760208083015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611c5757600080fd5b505af1158015611c6b573d6000803e3d6000fd5b50505050611dae565b60208083015161ffff1660009081526034909152604080822054845182517f095ea7b300000000000000000000000000000000000000000000000000000000815230600482015260248101919091529151600160a060020a039091169263095ea7b3926044808201939182900301818387803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b5050505060208281015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050505b8160400151600160a060020a03166108fc8360a001519081150290604051600060405180830381858888f150505050505b60208083015161ffff1660009081526034825260409081902081517f09cbc02000000000000000000000000000000000000000000000000000000000815260048101919091529051732c84bbdc7b9202949b7fbb0db29153190f23d1a5926309cbc0209260248082019391829003018186803b158015611e5e57600080fd5b505af4158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5050600084815260a060209081526040808320600101805476ff00000000000000000000000000000000000000000000191660b060020a1790558482015161ffff16835260349091528120600201541115611ef057611ee68561290a565b9094509250611ef9565b50505050611f06565b600101611b06565b505050505b50565b611f116128e5565b600160a060020a03163314611f2557600080fd5b60698190556040805182815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a150565b609d5481565b611f6e6128e5565b600160a060020a03163314611f8257600080fd5b609e55565b600054610100900460ff1680611fa05750611fa06129ff565b80611fae575060005460ff16155b1515611fee5760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b60008054600161010061ff00198316811760ff1916919091179092550460ff166120178461209d565b609d839055609e829055604080516000815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a1600080549115156101000261ff0019909216919091179055505050565b60335474010000000000000000000000000000000000000000900461ffff1681565b611f0681611a7d565b600054610100900460ff16806120b657506120b66129ff565b806120c4575060005460ff16155b15156121045760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b600080546033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03949094169390931790925561ff001980831661010090811760ff19166001179091169281900460ff16151502919091179055565b60695481565b61ffff8116600090815260346020526040902054600160a060020a03165b919050565b603354600160a060020a031681565b61219f6128e5565b600160a060020a031633146121b357600080fd5b609d55565b60356020526000908152604090205460ff1681565b60346020526000908152604090208054600290910154600160a060020a039091169082565b60006121fc6128e5565b90505b90565b73c5cdcd5470aef35fc33bddff3f8ecec027f95b1d331461226d576040805160e560020a62461bcd02815260206004820152601760248201527f6d73672e73656e646572206e6f74206d756c7469736967000000000000000000604482015290519081900360640190fd5b600160a060020a03811615156122cd576040805160e560020a62461bcd02815260206004820152601060248201527f6e6f74207265616c206164647265737300000000000000000000000000000000604482015290519081900360640190fd5b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518291600160a060020a0383169163a9059cbb91339184916370a08231916024808301926020929190829003018186803b15801561233857600080fd5b505afa15801561234c573d6000803e3d6000fd5b505050506040513d602081101561236257600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506040513d60208110156123db57600080fd5b50505050565b60a060205260009081526040902080546001820154600290920154909161ffff811691620100008204600160a060020a03169160b060020a810460ff16917701000000000000000000000000000000000000000000000090910463ffffffff169086565b6000806060600060f885600181518110151561245d57fe5b90602001906020020151908060020a82049150506001900460ff169050600060e086600181518110151561248d57fe5b90602001906020020151908060020a82049150506001900461ffff169050806040519080825280601f01601f1916602001820160405280156124d6576020820181803883390190505b5092508087830160440160208501378280519060200120935060a086600181518110151561250057fe5b90602001906020020151908060020a82049150506001900494506000612557858767ffffffffffffffff1660f08a600181518110151561253c57fe5b6020908102909101015160ff60029290920a9004168a612a05565b905086600081518110151561256857fe5b60209081029091010151811461257d57600080fd5b5050509250925092565b61258f612e42565b602082015160009060f860020a900460028114156125b057600291506125d0565b80600314156125c257600391506125d0565b80600d14156111a157600d91505b506021830151604080517f100000000000000000000000000000000000000000000000000000000000000090920480835260208082028401019091529060609082801561263757816020015b612624612f0b565b81526020019060019003908161261c5790505b509050600260005b825181101561265f576126558588838587612a74565b915060010161263f565b5060218601516040805160f860020a909204600f16808352602080820284010190915293506060908480156126ae57816020015b61269b612e64565b8152602001906001900390816126935790505b50905060005b81518110156126d3576126c988828585612c73565b92506001016126b4565b5060606040519081016040528086600d8111156126ec57fe5b8152602081019490945260409093015250949350505050565b602081015160009060f860020a90046003811461272157600080fd5b506021820151825160408051828152601f19601f84011681016020019091527f100000000000000000000000000000000000000000000000000000000000000090920491606091801561277b576020820181803883390190505b509050602084015160001a6020820153602084015160011a60218201536000805b838110156127cf578582016022818101518585019182015260429182015160001a9101536062919091019060010161279c565b50806022015b85516040018110156127f15785810151838201526020016127d5565b50506127fd8451612ced565b8160405160200180807f19457468657265756d205369676e6564204d6573736167653a0a000000000000815250601a0183805190602001908083835b602083106128585780518252601f199092019160209182019101612839565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106128a05780518252601f199092019160209182019101612881565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040528051906020012092505050919050565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b61ffff8116600090815260346020908152604080832081517f2e5f2ace0000000000000000000000000000000000000000000000000000000081526004810191909152905183928392732c84bbdc7b9202949b7fbb0db29153190f23d1a592632e5f2ace92602480840193919291829003018186803b15801561298c57600080fd5b505af41580156129a0573d6000803e3d6000fd5b505050506040513d60208110156129b657600080fd5b50516fffffffffffffffffffffffffffffffff8116957801000000000000000000000000000000000000000000000000909104945092505050565b61800061ffff821611919050565b303b1590565b600080835b8351811015612a69578381815181101515612a2157fe5b602090810290910101519150600286061515612a4b57866000528160205260406000209650612a5b565b8160005286602052604060002096505b600286049550600101612a0a565b509495945050505050565b60008080600288600d811115612a8657fe5b1415612aa85750505060048483018101519083019063ffffffff166000612abe565b5050508184016020810151602191820151918401915b612ac6612f4a565b5060408051808201825283815260ff831660208083019190915282516000815290810190925290612af5612f0b565b506040805160c08101825283815260006020820181905291810182905260608101919091526080810182905260a08101829052600d8b600d811115612b3657fe5b1415612c0a57878a01602301516040805161ffff8316808252601f19601f8201168201602001909252908015612b73576020820181803883390190505b509250888b0160430160208401612b8f828261ffff8616612de9565b848460a001819052508261ffff168b6025010198508c89015192508261ffff166040519080825280601f01601f191660200182016040528015612bd9576020820181803883390190505b5094505060208c8901810191508401612bf7828261ffff8616612de9565b50506080820183905261ffff1695909501945b60038b600d811115612c1857fe5b1415612c4b57878a01604181015160618201516062928301516020850192909252604084015260ff166060830152880195505b80878a815181101515612c5a57fe5b6020908102909101015250939998505050505050505050565b8184016020810151602282015160369092015160009290612c92612e64565b506040805160808101825284815261ffff84166020820152600160a060020a03831691810191909152600060608201528551819087908a908110612cd257fe5b60209081029091010152505060369094019695505050505050565b6060811515612d30575060408051808201909152600181527f30000000000000000000000000000000000000000000000000000000000000006020820152612183565b8160005b8115612d4857600101600a82049150612d34565b6060816040519080825280601f01601f191660200182016040528015612d75576020820181803883390190505b50905060001982015b8515612de057815160001982019160f860020a6030600a8a060102918491908110612da557fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550612d7e565b50949350505050565b600060208204815b81811015612e0f576020810286810151868201529250600101612df1565b506020908102938401805195909401516008601f9094169091039290920260020a60000391821691199390931617905250565b6040805160608101909152806000815260200160608152602001606081525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b828054828255906000526020600020908101928215612ec6579160200282015b82811115612ec6578251825591602001919060010190612eab565b50612ed2929150612f61565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60e060405190810160405280612f1f612f4a565b8152600060208201819052604082018190526060808301919091526080820181905260a09091015290565b604080518082019091526000808252602082015290565b6121ff91905b80821115612ed25760008155600101612f6756fe546865207265666572656e63656420706572696f6420776173206e6f74207375626d697474656420746f20627269646765476976656e206f7574707574206973206e6f74207265666572656e63656420696e2065786974696e6720747854686520657869742068617320616c7265616479206265656e2066696e616c697a6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a723058203b95f5a4944122e81b6e1d53b8f7798764d3c6402db0df21ae37ec0c995ec0ad0029
Deployed ByteCode
0x6080604052600436106101c65760003560e060020a90048063bc48bc22116100fb578063eabd686811610099578063f6169e3511610068578063f6169e3514610a32578063f851a44014610b69578063ff293da214610b7e578063ffa696d314610bb1576101c6565b8063eabd686814610953578063eefc30831461097d578063f3c20de0146109c4578063f5239f6414610a15576101c6565b8063d2d0e066116100d5578063d2d0e0661461089c578063d96ed505146108df578063db9ed47e146108f4578063e78cea921461093e576101c6565b8063bc48bc2214610826578063c215f1be1461083b578063c4d66de814610869576101c6565b80637695d79b1161016857806390ac18661161014257806390ac18661461077e5780639eeaa7f4146107a8578063ac3d8558146107bd578063ba27a911146107e7576101c6565b80637695d79b1461070f57806378e706451461073b5780638290fe2514610750576101c6565b80635bae510d116101a45780635bae510d1461036657806365f0b9b5146103d25780636710b83f14610516578063690505a714610551576101c6565b80632dfdf0b5146101cb578063374a5435146101f95780633882f7421461033f575b600080fd5b3480156101d757600080fd5b506101e0610c1f565b6040805163ffffffff9092168252519081900360200190f35b34801561020557600080fd5b5061033d6004803603608081101561021c57600080fd5b81019060208101813564010000000081111561023757600080fd5b82018360208201111561024957600080fd5b8035906020019184602083028401116401000000008311171561026b57600080fd5b91908080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525092959493602081019350359150506401000000008111156102bb57600080fd5b8201836020820111156102cd57600080fd5b803590602001918460208302840111640100000000831117156102ef57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610c2b9050565b005b34801561034b57600080fd5b50610354610f48565b60408051918252519081900360200190f35b34801561037257600080fd5b506103966004803603602081101561038957600080fd5b503563ffffffff16610f4e565b6040805167ffffffffffffffff909516855261ffff9093166020850152600160a060020a03909116838301526060830152519081900360800190f35b3480156103de57600080fd5b5061033d600480360360808110156103f557600080fd5b81019060208101813564010000000081111561041057600080fd5b82018360208201111561042257600080fd5b8035906020019184602083028401116401000000008311171561044457600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561049457600080fd5b8201836020820111156104a657600080fd5b803590602001918460208302840111640100000000831117156104c857600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150610f9d9050565b34801561052257600080fd5b5061033d6004803603604081101561053957600080fd5b50600160a060020a03813516906020013515156115c8565b61033d600480360360a081101561056757600080fd5b81019060208101813564010000000081111561058257600080fd5b82018360208201111561059457600080fd5b803590602001918460208302840111640100000000831117156105b657600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561060657600080fd5b82018360208201111561061857600080fd5b8035906020019184602083028401116401000000008311171561063a57600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929560ff853581169660208701359091169591945092506060810191506040013564010000000081111561069d57600080fd5b8201836020820111156106af57600080fd5b803590602001918460208302840111640100000000831117156106d157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929550611a16945050505050565b34801561071b57600080fd5b50610724611a66565b6040805161ffff9092168252519081900360200190f35b34801561074757600080fd5b50610354611a77565b34801561075c57600080fd5b5061033d6004803603602081101561077357600080fd5b503561ffff16611a7d565b34801561078a57600080fd5b5061033d600480360360208110156107a157600080fd5b5035611f09565b3480156107b457600080fd5b50610354611f60565b3480156107c957600080fd5b5061033d600480360360208110156107e057600080fd5b5035611f66565b3480156107f357600080fd5b5061033d6004803603606081101561080a57600080fd5b50600160a060020a038135169060208101359060400135611f87565b34801561083257600080fd5b50610724612072565b34801561084757600080fd5b5061033d6004803603602081101561085e57600080fd5b503561ffff16612094565b34801561087557600080fd5b5061033d6004803603602081101561088c57600080fd5b5035600160a060020a031661209d565b3480156108a857600080fd5b5061033d600480360360608110156108bf57600080fd5b508035600160a060020a0316906020810135906040013561ffff16611a16565b3480156108eb57600080fd5b5061035461215f565b34801561090057600080fd5b506109226004803603602081101561091757600080fd5b503561ffff16612165565b60408051600160a060020a039092168252519081900360200190f35b34801561094a57600080fd5b50610922612188565b34801561095f57600080fd5b5061033d6004803603602081101561097657600080fd5b5035612197565b34801561098957600080fd5b506109b0600480360360208110156109a057600080fd5b5035600160a060020a03166121b8565b604080519115158252519081900360200190f35b3480156109d057600080fd5b506109f2600480360360208110156109e757600080fd5b503561ffff166121cd565b60408051600160a060020a03909316835260208301919091528051918290030190f35b61033d60048036036020811015610a2b57600080fd5b5035611a16565b61033d60048036036080811015610a4857600080fd5b810190602081018135640100000000811115610a6357600080fd5b820183602082011115610a7557600080fd5b80359060200191846020830284011164010000000083111715610a9757600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295949360208101935035915050640100000000811115610ae757600080fd5b820183602082011115610af957600080fd5b80359060200191846020830284011164010000000083111715610b1b57600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295505060ff8335811694506020909301359092169150611a169050565b348015610b7557600080fd5b506109226121f2565b348015610b8a57600080fd5b5061033d60048036036020811015610ba157600080fd5b5035600160a060020a0316612202565b348015610bbd57600080fd5b50610bdb60048036036020811015610bd457600080fd5b50356123e1565b6040805196875261ffff9095166020870152600160a060020a0390931685850152901515606085015263ffffffff16608084015260a0830152519081900360c00190f35b60685463ffffffff1681565b60006060610c43865160020160200260400186612445565b6f0100000000000000000000000000000060ff8816026effffffffffffffffffffffffffffff831617600081815260a06020526040812054939650919450925010610cd8576040805160e560020a62461bcd02815260206004820152601e60248201527f5468657265206973206e6f206578697420666f722074686973205554584f0000604482015290519081900360640190fd5b610ce0612e42565b610ce983612587565b9050610cf6606089612445565b5060208301518051919650915060ff8716908110610d1057fe5b6020908102909101015151518414610d5c5760405160e560020a62461bcd02815260040180806020018281038252602c815260200180612fad602c913960400191505060405180910390fd5b6033548851600091600160a060020a03169063c222ef6d908b9084908110610d8057fe5b906020019060200201516040518263ffffffff1660e060020a02815260040180828152602001915050604080518083038186803b158015610dc057600080fd5b505afa158015610dd4573d6000803e3d6000fd5b505050506040513d6040811015610dea57600080fd5b50602001519050600063ffffffff821611610e395760405160e560020a62461bcd028152600401808060200182810382526031815260200180612f7c6031913960400191505060405180910390fd5b600083815260a0602052604090206001015463ffffffff808316770100000000000000000000000000000000000000000000009092041610610ec5576040805160e560020a62461bcd02815260206004820181905260248201527f4368616c6c656e67656420696e7075742073686f756c64206265206f6c646572604482015290519081900360640190fd5b600083815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015610f02573d6000803e3d6000fd5b505050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff1916905560020155505050505050565b609e5481565b606a602052600090815260409020805460019091015467ffffffffffffffff82169168010000000000000000810461ffff16916a0100000000000000000000909104600160a060020a03169084565b835160020160200260006060610fb66040840187612445565b9093509150506f0100000000000000000000000000000060ff8616026effffffffffffffffffffffffffffff831617610fed612e42565b6000895111156111f757600061100460608b612445565b95509150611013905084612587565b915081602001518760ff1681518110151561102a57fe5b602090810290910101515151851461104157600080fd5b6020820151805160ff891690811061105557fe5b602090810290910181015151015160ff89811691161461107457600080fd5b60038251600d81111561108357fe5b14156111a157600061109485612705565b9050600060018285602001518b60ff168151811015156110b057fe5b906020019060200201516060015186602001518c60ff168151811015156110d357fe5b906020019060200201516020015187602001518d60ff168151811015156110f657fe5b906020019060200201516040015160405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa15801561115b573d6000803e3d6000fd5b505060408051601f190151600088815260a06020529190912060010154909250600160a060020a03808416620100009092041614905061119a57600080fd5b50506111f1565b6040805160e560020a62461bcd02815260206004820152600f60248201527f756e6b6e6f776e20747820747970650000000000000000000000000000000000604482015290519081900360640190fd5b50611486565b61120083612587565b905080602001518660ff1681518110151561121757fe5b602090810290910101515151915060028151600d81111561123457fe5b141561143657611242612e64565b5063ffffffff82166000908152606a602090815260408083208151608081018352815467ffffffffffffffff8116825268010000000000000000810461ffff16948201949094526a0100000000000000000000909304600160a060020a03168383015260010154606083015283015180519192909181106112bf57fe5b6020908102909101015151606082015114611324576040805160e560020a62461bcd02815260206004820152600e60248201527f76616c7565206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b60408201518051600090811061133657fe5b9060200190602002015160400151600160a060020a03168160400151600160a060020a03161415156113b2576040805160e560020a62461bcd02815260206004820152600e60248201527f6f776e6572206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040820151805160009081106113c457fe5b906020019060200201516020015161ffff16816020015161ffff161415156111f1576040805160e560020a62461bcd02815260206004820152600e60248201527f636f6c6f72206d69736d61746368000000000000000000000000000000000000604482015290519081900360640190fd5b6040805160e560020a62461bcd02815260206004820152601260248201527f756e657870656374656420747820747970650000000000000000000000000000604482015290519081900360640190fd5b600082815260a06020526040812054116114ea576040805160e560020a62461bcd02815260206004820152600e60248201527f65786974206e6f7420666f756e64000000000000000000000000000000000000604482015290519081900360640190fd5b600082815260a0602052604090206001015460b060020a900460ff16156115455760405160e560020a62461bcd028152600401808060200182810382526023815260200180612fd96023913960400191505060405180910390fd5b600082815260a06020526040808220600201549051339282156108fc02929190818181858888f19350505050158015611582573d6000803e3d6000fd5b5050600090815260a0602052604081208181556001810180547affffffffffffffffffffffffffffffffffffffffffffffffffffff191690556002015550505050505050565b6115d06128e5565b600160a060020a031633146115e457600080fd5b600160a060020a0382161515611644576040805160e560020a62461bcd02815260206004820152601d60248201527f547269656420746f207265676973746572203078302061646472657373000000604482015290519081900360640190fd5b600160a060020a03821660009081526035602052604090205460ff16156116b5576040805160e560020a62461bcd02815260206004820152601860248201527f546f6b656e20616c726561647920726567697374657265640000000000000000604482015290519081900360640190fd5b6000811561180857604080517f01ffc9a70000000000000000000000000000000000000000000000000000000081527f80ac58cd0000000000000000000000000000000000000000000000000000000060048201529051600160a060020a038516916301ffc9a7916024808301926020929190829003018186803b15801561173c57600080fd5b505afa158015611750573d6000803e3d6000fd5b505050506040513d602081101561176657600080fd5b505115156001146117c1576040805160e560020a62461bcd02815260206004820152601360248201527f4e6f7420616e2045524337323120746f6b656e00000000000000000000000000604482015290519081900360640190fd5b506033805477ffff0000000000000000000000000000000000000000000019811660b060020a9182900461ffff908116600181019091169092021790915561800101611916565b600083600160a060020a03166318160ddd6040518163ffffffff1660e060020a02815260040160206040518083038186803b15801561184657600080fd5b505afa15801561185a573d6000803e3d6000fd5b505050506040513d602081101561187057600080fd5b505110156118c8576040805160e560020a62461bcd02815260206004820152601260248201527f4e6f7420616e20455243323020746f6b656e0000000000000000000000000000604482015290519081900360640190fd5b506033805475ffff0000000000000000000000000000000000000000198116740100000000000000000000000000000000000000009182900461ffff90811660018101909116909202179091555b60408051600180825281830190925260609160208083019080388339505050600160a060020a0385811660008181526035602090815260408083208054600160ff199091168117909155815160608101835294855284830187815285830185905261ffff8a16855260348452919093208451815473ffffffffffffffffffffffffffffffffffffffff1916961695909517855551805195965092946119c2939285019290910190612e8b565b50604091820151600290910155805161ffff841681529051600160a060020a038616917ffe74dea79bde70d1990ddb655bac45735b14f495ddc508cfab80b7729aa9d668919081900360200190a250505050565b6040805160e560020a62461bcd02815260206004820152600f60248201527f6e6f7420696d706c656d656e7465640000000000000000000000000000000000604482015290519081900360640190fd5b60335460b060020a900461ffff1681565b609f5481565b600080611a88612ed6565b611a918461290a565b61ffff861660009081526034602052604081206002015492955090935010611b03576040805160e560020a62461bcd02815260206004820152601660248201527f517565756520656d70747920666f7220636f6c6f722e00000000000000000000604482015290519081900360640190fd5b60005b6014811015611f015742831115611b205750505050611f06565b600084815260a06020818152604092839020835160c08101855281548152600182015461ffff811693820193909352620100008304600160a060020a031694810185905260b060020a830460ff16151560608201527701000000000000000000000000000000000000000000000090920463ffffffff16608083015260020154918101919091529250151580611bb65750815115155b15611ddf57611bc882602001516129f1565b15611c745760208083015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611c5757600080fd5b505af1158015611c6b573d6000803e3d6000fd5b50505050611dae565b60208083015161ffff1660009081526034909152604080822054845182517f095ea7b300000000000000000000000000000000000000000000000000000000815230600482015260248101919091529151600160a060020a039091169263095ea7b3926044808201939182900301818387803b158015611cf357600080fd5b505af1158015611d07573d6000803e3d6000fd5b5050505060208281015161ffff166000908152603490915260408082205481850151855183517f23b872dd000000000000000000000000000000000000000000000000000000008152306004820152600160a060020a039283166024820152604481019190915292519116926323b872dd926064808201939182900301818387803b158015611d9557600080fd5b505af1158015611da9573d6000803e3d6000fd5b505050505b8160400151600160a060020a03166108fc8360a001519081150290604051600060405180830381858888f150505050505b60208083015161ffff1660009081526034825260409081902081517f09cbc02000000000000000000000000000000000000000000000000000000000815260048101919091529051732c84bbdc7b9202949b7fbb0db29153190f23d1a5926309cbc0209260248082019391829003018186803b158015611e5e57600080fd5b505af4158015611e72573d6000803e3d6000fd5b505050506040513d6020811015611e8857600080fd5b5050600084815260a060209081526040808320600101805476ff00000000000000000000000000000000000000000000191660b060020a1790558482015161ffff16835260349091528120600201541115611ef057611ee68561290a565b9094509250611ef9565b50505050611f06565b600101611b06565b505050505b50565b611f116128e5565b600160a060020a03163314611f2557600080fd5b60698190556040805182815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a150565b609d5481565b611f6e6128e5565b600160a060020a03163314611f8257600080fd5b609e55565b600054610100900460ff1680611fa05750611fa06129ff565b80611fae575060005460ff16155b1515611fee5760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b60008054600161010061ff00198316811760ff1916919091179092550460ff166120178461209d565b609d839055609e829055604080516000815290517f85feea100eda69e1c4fe1b228ed4d7229f3e9e9ebf7d30893d71de8165c46abb9181900360200190a1600080549115156101000261ff0019909216919091179055505050565b60335474010000000000000000000000000000000000000000900461ffff1681565b611f0681611a7d565b600054610100900460ff16806120b657506120b66129ff565b806120c4575060005460ff16155b15156121045760405160e560020a62461bcd02815260040180806020018281038252602e815260200180612ffc602e913960400191505060405180910390fd5b600080546033805473ffffffffffffffffffffffffffffffffffffffff1916600160a060020a03949094169390931790925561ff001980831661010090811760ff19166001179091169281900460ff16151502919091179055565b60695481565b61ffff8116600090815260346020526040902054600160a060020a03165b919050565b603354600160a060020a031681565b61219f6128e5565b600160a060020a031633146121b357600080fd5b609d55565b60356020526000908152604090205460ff1681565b60346020526000908152604090208054600290910154600160a060020a039091169082565b60006121fc6128e5565b90505b90565b73c5cdcd5470aef35fc33bddff3f8ecec027f95b1d331461226d576040805160e560020a62461bcd02815260206004820152601760248201527f6d73672e73656e646572206e6f74206d756c7469736967000000000000000000604482015290519081900360640190fd5b600160a060020a03811615156122cd576040805160e560020a62461bcd02815260206004820152601060248201527f6e6f74207265616c206164647265737300000000000000000000000000000000604482015290519081900360640190fd5b604080517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015290518291600160a060020a0383169163a9059cbb91339184916370a08231916024808301926020929190829003018186803b15801561233857600080fd5b505afa15801561234c573d6000803e3d6000fd5b505050506040513d602081101561236257600080fd5b50516040805160e060020a63ffffffff8616028152600160a060020a03909316600484015260248301919091525160448083019260209291908290030181600087803b1580156123b157600080fd5b505af11580156123c5573d6000803e3d6000fd5b505050506040513d60208110156123db57600080fd5b50505050565b60a060205260009081526040902080546001820154600290920154909161ffff811691620100008204600160a060020a03169160b060020a810460ff16917701000000000000000000000000000000000000000000000090910463ffffffff169086565b6000806060600060f885600181518110151561245d57fe5b90602001906020020151908060020a82049150506001900460ff169050600060e086600181518110151561248d57fe5b90602001906020020151908060020a82049150506001900461ffff169050806040519080825280601f01601f1916602001820160405280156124d6576020820181803883390190505b5092508087830160440160208501378280519060200120935060a086600181518110151561250057fe5b90602001906020020151908060020a82049150506001900494506000612557858767ffffffffffffffff1660f08a600181518110151561253c57fe5b6020908102909101015160ff60029290920a9004168a612a05565b905086600081518110151561256857fe5b60209081029091010151811461257d57600080fd5b5050509250925092565b61258f612e42565b602082015160009060f860020a900460028114156125b057600291506125d0565b80600314156125c257600391506125d0565b80600d14156111a157600d91505b506021830151604080517f100000000000000000000000000000000000000000000000000000000000000090920480835260208082028401019091529060609082801561263757816020015b612624612f0b565b81526020019060019003908161261c5790505b509050600260005b825181101561265f576126558588838587612a74565b915060010161263f565b5060218601516040805160f860020a909204600f16808352602080820284010190915293506060908480156126ae57816020015b61269b612e64565b8152602001906001900390816126935790505b50905060005b81518110156126d3576126c988828585612c73565b92506001016126b4565b5060606040519081016040528086600d8111156126ec57fe5b8152602081019490945260409093015250949350505050565b602081015160009060f860020a90046003811461272157600080fd5b506021820151825160408051828152601f19601f84011681016020019091527f100000000000000000000000000000000000000000000000000000000000000090920491606091801561277b576020820181803883390190505b509050602084015160001a6020820153602084015160011a60218201536000805b838110156127cf578582016022818101518585019182015260429182015160001a9101536062919091019060010161279c565b50806022015b85516040018110156127f15785810151838201526020016127d5565b50506127fd8451612ced565b8160405160200180807f19457468657265756d205369676e6564204d6573736167653a0a000000000000815250601a0183805190602001908083835b602083106128585780518252601f199092019160209182019101612839565b51815160209384036101000a600019018019909216911617905285519190930192850191508083835b602083106128a05780518252601f199092019160209182019101612881565b6001836020036101000a038019825116818451168082178552505050505050905001925050506040516020818303038152906040528051906020012092505050919050565b7f10d6a54a4754c8869d6886b5f5d7fbfa5b4522237ea5c60d11bc4e7a1ff9390b5490565b61ffff8116600090815260346020908152604080832081517f2e5f2ace0000000000000000000000000000000000000000000000000000000081526004810191909152905183928392732c84bbdc7b9202949b7fbb0db29153190f23d1a592632e5f2ace92602480840193919291829003018186803b15801561298c57600080fd5b505af41580156129a0573d6000803e3d6000fd5b505050506040513d60208110156129b657600080fd5b50516fffffffffffffffffffffffffffffffff8116957801000000000000000000000000000000000000000000000000909104945092505050565b61800061ffff821611919050565b303b1590565b600080835b8351811015612a69578381815181101515612a2157fe5b602090810290910101519150600286061515612a4b57866000528160205260406000209650612a5b565b8160005286602052604060002096505b600286049550600101612a0a565b509495945050505050565b60008080600288600d811115612a8657fe5b1415612aa85750505060048483018101519083019063ffffffff166000612abe565b5050508184016020810151602191820151918401915b612ac6612f4a565b5060408051808201825283815260ff831660208083019190915282516000815290810190925290612af5612f0b565b506040805160c08101825283815260006020820181905291810182905260608101919091526080810182905260a08101829052600d8b600d811115612b3657fe5b1415612c0a57878a01602301516040805161ffff8316808252601f19601f8201168201602001909252908015612b73576020820181803883390190505b509250888b0160430160208401612b8f828261ffff8616612de9565b848460a001819052508261ffff168b6025010198508c89015192508261ffff166040519080825280601f01601f191660200182016040528015612bd9576020820181803883390190505b5094505060208c8901810191508401612bf7828261ffff8616612de9565b50506080820183905261ffff1695909501945b60038b600d811115612c1857fe5b1415612c4b57878a01604181015160618201516062928301516020850192909252604084015260ff166060830152880195505b80878a815181101515612c5a57fe5b6020908102909101015250939998505050505050505050565b8184016020810151602282015160369092015160009290612c92612e64565b506040805160808101825284815261ffff84166020820152600160a060020a03831691810191909152600060608201528551819087908a908110612cd257fe5b60209081029091010152505060369094019695505050505050565b6060811515612d30575060408051808201909152600181527f30000000000000000000000000000000000000000000000000000000000000006020820152612183565b8160005b8115612d4857600101600a82049150612d34565b6060816040519080825280601f01601f191660200182016040528015612d75576020820181803883390190505b50905060001982015b8515612de057815160001982019160f860020a6030600a8a060102918491908110612da557fe5b9060200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a905350600a86049550612d7e565b50949350505050565b600060208204815b81811015612e0f576020810286810151868201529250600101612df1565b506020908102938401805195909401516008601f9094169091039290920260020a60000391821691199390931617905250565b6040805160608101909152806000815260200160608152602001606081525090565b60408051608081018252600080825260208201819052918101829052606081019190915290565b828054828255906000526020600020908101928215612ec6579160200282015b82811115612ec6578251825591602001919060010190612eab565b50612ed2929150612f61565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081019190915290565b60e060405190810160405280612f1f612f4a565b8152600060208201819052604082018190526060808301919091526080820181905260a09091015290565b604080518082019091526000808252602082015290565b6121ff91905b80821115612ed25760008155600101612f6756fe546865207265666572656e63656420706572696f6420776173206e6f74207375626d697474656420746f20627269646765476976656e206f7574707574206973206e6f74207265666572656e63656420696e2065786974696e6720747854686520657869742068617320616c7265616479206265656e2066696e616c697a6564436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a6564a165627a7a723058203b95f5a4944122e81b6e1d53b8f7798764d3c6402db0df21ae37ec0c995ec0ad0029