Overview
ETH Balance
0 ETH
Eth Value
$0.00
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
There are no matching entriesUpdate your filters to view other transactions | |||||||||
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
TokenNetworkRegistry
Compiler Version
v0.4.25+commit.59dbf8f1
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/**
*Submitted for verification at Etherscan.io on 2018-10-25
*/
pragma solidity ^0.4.23;
/// @title Utils
/// @notice Utils contract for various helpers used by the Raiden Network smart
/// contracts.
contract Utils {
string constant public contract_version = "0.4.0";
/// @notice Check if a contract exists
/// @param contract_address The address to check whether a contract is
/// deployed or not
/// @return True if a contract exists, false otherwise
function contractExists(address contract_address) public view returns (bool) {
uint size;
assembly {
size := extcodesize(contract_address)
}
return size > 0;
}
}
interface Token {
/// @return total amount of tokens
function totalSupply() external view returns (uint256 supply);
/// @param _owner The address from which the balance will be retrieved
/// @return The balance
function balanceOf(address _owner) external view returns (uint256 balance);
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transfer(address _to, uint256 _value) external returns (bool success);
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);
/// @notice `msg.sender` approves `_spender` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Whether the approval was successful or not
function approve(address _spender, uint256 _value) external returns (bool success);
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
function allowance(address _owner, address _spender) external view returns (uint256 remaining);
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
// Optionally implemented function to show the number of decimals for the token
function decimals() external view returns (uint8 decimals);
}
library ECVerify {
function ecverify(bytes32 hash, bytes signature)
internal
pure
returns (address signature_address)
{
require(signature.length == 65);
bytes32 r;
bytes32 s;
uint8 v;
// The signature format is a compact form of:
// {bytes32 r}{bytes32 s}{uint8 v}
// Compact means, uint8 is not padded to 32 bytes.
assembly {
r := mload(add(signature, 32))
s := mload(add(signature, 64))
// Here we are loading the last 32 bytes, including 31 bytes of 's'.
v := byte(0, mload(add(signature, 96)))
}
// Version of signature should be 27 or 28, but 0 and 1 are also possible
if (v < 27) {
v += 27;
}
require(v == 27 || v == 28);
signature_address = ecrecover(hash, v, r, s);
// ecrecover returns zero on error
require(signature_address != address(0x0));
return signature_address;
}
}
/// @title SecretRegistry
/// @notice SecretRegistry contract for registering secrets from Raiden Network
/// clients.
contract SecretRegistry {
string constant public contract_version = "0.4.0";
// keccak256(secret) => block number at which the secret was revealed
mapping(bytes32 => uint256) private secrethash_to_block;
event SecretRevealed(bytes32 indexed secrethash, bytes32 secret);
/// @notice Registers a hash time lock secret and saves the block number.
/// This allows the lock to be unlocked after the expiration block.
/// @param secret The secret used to lock the hash time lock.
/// @return true if secret was registered, false if the secret was already
/// registered.
function registerSecret(bytes32 secret) public returns (bool) {
bytes32 secrethash = keccak256(abi.encodePacked(secret));
if (secret == bytes32(0x0) || secrethash_to_block[secrethash] > 0) {
return false;
}
secrethash_to_block[secrethash] = block.number;
emit SecretRevealed(secrethash, secret);
return true;
}
/// @notice Registers multiple hash time lock secrets and saves the block
/// number.
/// @param secrets The array of secrets to be registered.
/// @return true if all secrets could be registered, false otherwise.
function registerSecretBatch(bytes32[] secrets) public returns (bool) {
bool completeSuccess = true;
for(uint i = 0; i < secrets.length; i++) {
if(!registerSecret(secrets[i])) {
completeSuccess = false;
}
}
return completeSuccess;
}
/// @notice Get the stored block number at which the secret was revealed.
/// @param secrethash The hash of the registered secret `keccak256(secret)`.
/// @return The block number at which the secret was revealed.
function getSecretRevealBlockHeight(bytes32 secrethash) public view returns (uint256) {
return secrethash_to_block[secrethash];
}
}
/// @title TokenNetwork
/// @notice Stores and manages all the Raiden Network channels that use the
/// token specified
/// in this TokenNetwork contract.
contract TokenNetwork is Utils {
string constant public contract_version = "0.4.0";
// Instance of the token used by the channels
Token public token;
// Instance of SecretRegistry used for storing secrets revealed in a
// mediating transfer.
SecretRegistry public secret_registry;
// Chain ID as specified by EIP155 used in balance proof signatures to
// avoid replay attacks
uint256 public chain_id;
uint256 public settlement_timeout_min;
uint256 public settlement_timeout_max;
uint256 constant public MAX_SAFE_UINT256 = (
115792089237316195423570985008687907853269984665640564039457584007913129639935
);
// Red Eyes release deposit limits
// The combined deposit of one channel is limited to 0.15 ETH.
// So 0.075 ETH per participant.
uint256 constant public channel_participant_deposit_limit = 75000000000000000 wei;
// The total combined deposit of all channels across the whole network is
// limited to 250 ETH.
uint256 constant public token_network_deposit_limit = 250000000000000000000 wei;
// Global, monotonically increasing counter that keeps track of all the
// opened channels in this contract
uint256 public channel_counter;
string public constant signature_prefix = '\x19Ethereum Signed Message:\n';
// Only for the limited Red Eyes release
address public deprecation_executor;
bool public safety_deprecation_switch = false;
// channel_identifier => Channel
// channel identifier is the channel_counter value at the time of opening
// the channel
mapping (uint256 => Channel) public channels;
// This is needed to enforce one channel per pair of participants
// The key is keccak256(participant1_address, participant2_address)
mapping (bytes32 => uint256) public participants_hash_to_channel_identifier;
// We keep the unlock data in a separate mapping to allow channel data
// structures to be removed when settling uncooperatively. If there are
// locked pending transfers, we need to store data needed to unlock them at
// a later time.
// The key is `keccak256(uint256 channel_identifier, address participant,
// address partner)` Where `participant` is the participant that sent the
// pending transfers We need `partner` for knowing where to send the
// claimable tokens
mapping(bytes32 => UnlockData) private unlock_identifier_to_unlock_data;
struct Participant {
// Total amount of tokens transferred to this smart contract through
// the `setTotalDeposit` function, for a specific channel, in the
// participant's benefit.
// This is a strictly monotonic value. Note that direct token transfer
// cannot be tracked and will be burned.
uint256 deposit;
// Total amount of tokens withdrawn by the participant during the
// lifecycle of this channel.
// This is a strictly monotonic value.
uint256 withdrawn_amount;
// This is a value set to true after the channel has been closed, only
// if this is the participant who closed the channel.
bool is_the_closer;
// keccak256 of the balance data provided after a closeChannel or an
// updateNonClosingBalanceProof call
bytes32 balance_hash;
// Monotonically increasing counter of the off-chain transfers,
// provided along with the balance_hash
uint256 nonce;
}
enum ChannelState {
NonExistent, // 0
Opened, // 1
Closed, // 2
Settled, // 3; Note: The channel has at least one pending unlock
Removed // 4; Note: Channel data is removed, there are no pending unlocks
}
enum MessageTypeId {
None,
BalanceProof,
BalanceProofUpdate,
Withdraw,
CooperativeSettle
}
struct Channel {
// After opening the channel this value represents the settlement
// window. This is the number of blocks that need to be mined between
// closing the channel uncooperatively and settling the channel.
// After the channel has been uncooperatively closed, this value
// represents the block number after which settleChannel can be called.
uint256 settle_block_number;
ChannelState state;
mapping(address => Participant) participants;
}
struct SettlementData {
uint256 deposit;
uint256 withdrawn;
uint256 transferred;
uint256 locked;
}
struct UnlockData {
// Merkle root of the pending transfers tree from the Raiden client
bytes32 locksroot;
// Total amount of tokens locked in the pending transfers corresponding
// to the `locksroot`
uint256 locked_amount;
}
event ChannelOpened(
uint256 indexed channel_identifier,
address indexed participant1,
address indexed participant2,
uint256 settle_timeout
);
event ChannelNewDeposit(
uint256 indexed channel_identifier,
address indexed participant,
uint256 total_deposit
);
// total_withdraw is how much the participant has withdrawn during the
// lifetime of the channel. The actual amount which the participant withdrew
// is `total_withdraw - total_withdraw_from_previous_event_or_zero`
/* event ChannelWithdraw(
uint256 indexed channel_identifier,
address indexed participant,
uint256 total_withdraw
); */
event ChannelClosed(
uint256 indexed channel_identifier,
address indexed closing_participant,
uint256 indexed nonce
);
event ChannelUnlocked(
uint256 indexed channel_identifier,
address indexed participant,
address indexed partner,
bytes32 locksroot,
uint256 unlocked_amount,
uint256 returned_tokens
);
event NonClosingBalanceProofUpdated(
uint256 indexed channel_identifier,
address indexed closing_participant,
uint256 indexed nonce
);
event ChannelSettled(
uint256 indexed channel_identifier,
uint256 participant1_amount,
uint256 participant2_amount
);
modifier onlyDeprecationExecutor() {
require(msg.sender == deprecation_executor);
_;
}
modifier isSafe() {
require(safety_deprecation_switch == false);
_;
}
modifier isOpen(uint256 channel_identifier) {
require(channels[channel_identifier].state == ChannelState.Opened);
_;
}
modifier settleTimeoutValid(uint256 timeout) {
require(timeout >= settlement_timeout_min);
require(timeout <= settlement_timeout_max);
_;
}
constructor(
address _token_address,
address _secret_registry,
uint256 _chain_id,
uint256 _settlement_timeout_min,
uint256 _settlement_timeout_max,
address _deprecation_executor
)
public
{
require(_token_address != address(0x0));
require(_secret_registry != address(0x0));
require(_deprecation_executor != address(0x0));
require(_chain_id > 0);
require(_settlement_timeout_min > 0);
require(_settlement_timeout_max > _settlement_timeout_min);
require(contractExists(_token_address));
require(contractExists(_secret_registry));
token = Token(_token_address);
secret_registry = SecretRegistry(_secret_registry);
chain_id = _chain_id;
settlement_timeout_min = _settlement_timeout_min;
settlement_timeout_max = _settlement_timeout_max;
// Make sure the contract is indeed a token contract
require(token.totalSupply() > 0);
deprecation_executor = _deprecation_executor;
}
function deprecate() isSafe onlyDeprecationExecutor public {
safety_deprecation_switch = true;
}
/// @notice Opens a new channel between `participant1` and `participant2`.
/// Can be called by anyone.
/// @param participant1 Ethereum address of a channel participant.
/// @param participant2 Ethereum address of the other channel participant.
/// @param settle_timeout Number of blocks that need to be mined between a
/// call to closeChannel and settleChannel.
function openChannel(address participant1, address participant2, uint256 settle_timeout)
isSafe
settleTimeoutValid(settle_timeout)
public
returns (uint256)
{
bytes32 pair_hash;
uint256 channel_identifier;
// Red Eyes release token network limit
require(token.balanceOf(address(this)) < token_network_deposit_limit);
// First increment the counter
// There will never be a channel with channel_identifier == 0
channel_counter += 1;
channel_identifier = channel_counter;
pair_hash = getParticipantsHash(participant1, participant2);
// There must only be one channel opened between two participants at
// any moment in time.
require(participants_hash_to_channel_identifier[pair_hash] == 0);
participants_hash_to_channel_identifier[pair_hash] = channel_identifier;
Channel storage channel = channels[channel_identifier];
// We always increase the channel counter, therefore no channel data can already exist,
// corresponding to this channel_identifier. This check must never fail.
assert(channel.settle_block_number == 0);
assert(channel.state == ChannelState.NonExistent);
// Store channel information
channel.settle_block_number = settle_timeout;
channel.state = ChannelState.Opened;
emit ChannelOpened(
channel_identifier,
participant1,
participant2,
settle_timeout
);
return channel_identifier;
}
/// @notice Sets the channel participant total deposit value.
/// Can be called by anyone.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant Channel participant whose deposit is being set.
/// @param total_deposit The total amount of tokens that the participant
/// will have as a deposit.
/// @param partner Channel partner address, needed to compute the total
/// channel deposit.
function setTotalDeposit(
uint256 channel_identifier,
address participant,
uint256 total_deposit,
address partner
)
isSafe
isOpen(channel_identifier)
public
{
require(channel_identifier == getChannelIdentifier(participant, partner));
require(total_deposit > 0);
require(total_deposit <= channel_participant_deposit_limit);
uint256 added_deposit;
uint256 channel_deposit;
Channel storage channel = channels[channel_identifier];
Participant storage participant_state = channel.participants[participant];
Participant storage partner_state = channel.participants[partner];
// Calculate the actual amount of tokens that will be transferred
added_deposit = total_deposit - participant_state.deposit;
// The actual amount of tokens that will be transferred must be > 0
require(added_deposit > 0);
// Underflow check; we use <= because added_deposit == total_deposit for the first deposit
require(added_deposit <= total_deposit);
// This should never fail at this point. Added check for security, because we directly set
// the participant_state.deposit = total_deposit, while we transfer `added_deposit` tokens.
assert(participant_state.deposit + added_deposit == total_deposit);
// Red Eyes release token network limit
require(token.balanceOf(address(this)) + added_deposit <= token_network_deposit_limit);
// Update the participant's channel deposit
participant_state.deposit = total_deposit;
// Calculate the entire channel deposit, to avoid overflow
channel_deposit = participant_state.deposit + partner_state.deposit;
// Overflow check
require(channel_deposit >= participant_state.deposit);
emit ChannelNewDeposit(
channel_identifier,
participant,
participant_state.deposit
);
// Do the transfer
require(token.transferFrom(msg.sender, address(this), added_deposit));
}
/* /// @notice Allows `participant` to withdraw tokens from the channel that he
/// has with `partner`, without closing it. Can be called by anyone. Can
/// only be called once per each signed withdraw message.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant Channel participant, who will receive the withdrawn
/// amount.
/// @param total_withdraw Total amount of tokens that are marked as
/// withdrawn from the channel during the channel lifecycle.
/// @param participant_signature Participant's signature on the withdraw
/// data.
/// @param partner_signature Partner's signature on the withdraw data.
function setTotalWithdraw(
uint256 channel_identifier,
address participant,
uint256 total_withdraw,
bytes participant_signature,
bytes partner_signature
)
isOpen(channel_identifier)
external
{
uint256 total_deposit;
uint256 current_withdraw;
address partner;
require(total_withdraw > 0);
// Authenticate both channel partners via there signatures:
require(participant == recoverAddressFromWithdrawMessage(
channel_identifier,
participant,
total_withdraw,
participant_signature
));
partner = recoverAddressFromWithdrawMessage(
channel_identifier,
participant,
total_withdraw,
partner_signature
);
// Validate that authenticated partners and the channel identifier match
require(channel_identifier == getChannelIdentifier(participant, partner));
// Read channel state after validating the function input
Channel storage channel = channels[channel_identifier];
Participant storage participant_state = channel.participants[participant];
Participant storage partner_state = channel.participants[partner];
total_deposit = participant_state.deposit + partner_state.deposit;
// Entire withdrawn amount must not be bigger than the current channel deposit
require((total_withdraw + partner_state.withdrawn_amount) <= total_deposit);
require(total_withdraw <= (total_withdraw + partner_state.withdrawn_amount));
// Using the total_withdraw (monotonically increasing) in the signed
// message ensures that we do not allow replay attack to happen, by
// using the same withdraw proof twice.
// Next two lines enforce the monotonicity of total_withdraw and check for an underflow:
// (we use <= because current_withdraw == total_withdraw for the first withdraw)
current_withdraw = total_withdraw - participant_state.withdrawn_amount;
require(current_withdraw <= total_withdraw);
// The actual amount of tokens that will be transferred must be > 0 to disable the reuse of
// withdraw messages completely.
require(current_withdraw > 0);
// This should never fail at this point. Added check for security, because we directly set
// the participant_state.withdrawn_amount = total_withdraw,
// while we transfer `current_withdraw` tokens.
assert(participant_state.withdrawn_amount + current_withdraw == total_withdraw);
emit ChannelWithdraw(
channel_identifier,
participant,
total_withdraw
);
// Do the state change and tokens transfer
participant_state.withdrawn_amount = total_withdraw;
require(token.transfer(participant, current_withdraw));
// This should never happen, as we have an overflow check in setTotalDeposit
assert(total_deposit >= participant_state.deposit);
assert(total_deposit >= partner_state.deposit);
// A withdraw should never happen if a participant already has a
// balance proof in storage. This should never fail as we use isOpen.
assert(participant_state.nonce == 0);
assert(partner_state.nonce == 0);
} */
/// @notice Close the channel defined by the two participant addresses. Only
/// a participant may close the channel, providing a balance proof signed by
/// its partner. Callable only once.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param partner Channel partner of the `msg.sender`, who provided the
/// signature.
/// @param balance_hash Hash of (transferred_amount, locked_amount,
/// locksroot).
/// @param additional_hash Computed from the message. Used for message
/// authentication.
/// @param nonce Strictly monotonic value used to order transfers.
/// @param signature Partner's signature of the balance proof data.
function closeChannel(
uint256 channel_identifier,
address partner,
bytes32 balance_hash,
uint256 nonce,
bytes32 additional_hash,
bytes signature
)
isOpen(channel_identifier)
public
{
require(channel_identifier == getChannelIdentifier(msg.sender, partner));
address recovered_partner_address;
Channel storage channel = channels[channel_identifier];
channel.state = ChannelState.Closed;
channel.participants[msg.sender].is_the_closer = true;
// This is the block number at which the channel can be settled.
channel.settle_block_number += uint256(block.number);
// Nonce 0 means that the closer never received a transfer, therefore
// never received a balance proof, or he is intentionally not providing
// the latest transfer, in which case the closing party is going to
// lose the tokens that were transferred to him.
if (nonce > 0) {
recovered_partner_address = recoverAddressFromBalanceProof(
channel_identifier,
balance_hash,
nonce,
additional_hash,
signature
);
// Signature must be from the channel partner
require(partner == recovered_partner_address);
updateBalanceProofData(
channel,
recovered_partner_address,
nonce,
balance_hash
);
}
emit ChannelClosed(channel_identifier, msg.sender, nonce);
}
/// @notice Called on a closed channel, the function allows the non-closing
/// participant to provide the last balance proof, which modifies the
/// closing participant's state. Can be called multiple times by anyone.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param closing_participant Channel participant who closed the channel.
/// @param non_closing_participant Channel participant who needs to update
/// the balance proof.
/// @param balance_hash Hash of (transferred_amount, locked_amount,
/// locksroot).
/// @param additional_hash Computed from the message. Used for message
/// authentication.
/// @param nonce Strictly monotonic value used to order transfers.
/// @param closing_signature Closing participant's signature of the balance
/// proof data.
/// @param non_closing_signature Non-closing participant signature of the
/// balance proof data.
function updateNonClosingBalanceProof(
uint256 channel_identifier,
address closing_participant,
address non_closing_participant,
bytes32 balance_hash,
uint256 nonce,
bytes32 additional_hash,
bytes closing_signature,
bytes non_closing_signature
)
external
{
require(channel_identifier == getChannelIdentifier(
closing_participant,
non_closing_participant
));
require(balance_hash != bytes32(0x0));
require(nonce > 0);
address recovered_non_closing_participant;
address recovered_closing_participant;
Channel storage channel = channels[channel_identifier];
require(channel.state == ChannelState.Closed);
// Channel must be in the settlement window
require(channel.settle_block_number >= block.number);
// We need the signature from the non-closing participant to allow
// anyone to make this transaction. E.g. a monitoring service.
recovered_non_closing_participant = recoverAddressFromBalanceProofUpdateMessage(
channel_identifier,
balance_hash,
nonce,
additional_hash,
closing_signature,
non_closing_signature
);
require(non_closing_participant == recovered_non_closing_participant);
recovered_closing_participant = recoverAddressFromBalanceProof(
channel_identifier,
balance_hash,
nonce,
additional_hash,
closing_signature
);
require(closing_participant == recovered_closing_participant);
Participant storage closing_participant_state = channel.participants[closing_participant];
// Make sure the first signature is from the closing participant
require(closing_participant_state.is_the_closer);
// Update the balance proof data for the closing_participant
updateBalanceProofData(channel, closing_participant, nonce, balance_hash);
emit NonClosingBalanceProofUpdated(
channel_identifier,
closing_participant,
nonce
);
}
/// @notice Settles the balance between the two parties. Note that arguments
/// order counts: `participant1_transferred_amount +
/// participant1_locked_amount` <= `participant2_transferred_amount +
/// participant2_locked_amount`
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant1 Channel participant.
/// @param participant1_transferred_amount The latest known amount of tokens
/// transferred from `participant1` to `participant2`.
/// @param participant1_locked_amount Amount of tokens owed by
/// `participant1` to `participant2`, contained in locked transfers that
/// will be retrieved by calling `unlock` after the channel is settled.
/// @param participant1_locksroot The latest known merkle root of the
/// pending hash-time locks of `participant1`, used to validate the unlocked
/// proofs.
/// @param participant2 Other channel participant.
/// @param participant2_transferred_amount The latest known amount of tokens
/// transferred from `participant2` to `participant1`.
/// @param participant2_locked_amount Amount of tokens owed by
/// `participant2` to `participant1`, contained in locked transfers that
/// will be retrieved by calling `unlock` after the channel is settled.
/// @param participant2_locksroot The latest known merkle root of the
/// pending hash-time locks of `participant2`, used to validate the unlocked
/// proofs.
function settleChannel(
uint256 channel_identifier,
address participant1,
uint256 participant1_transferred_amount,
uint256 participant1_locked_amount,
bytes32 participant1_locksroot,
address participant2,
uint256 participant2_transferred_amount,
uint256 participant2_locked_amount,
bytes32 participant2_locksroot
)
public
{
// There are several requirements that this function MUST enforce:
// - it MUST never fail; therefore, any overflows or underflows must be
// handled gracefully
// - it MUST ensure that if participants use the latest valid balance proofs,
// provided by the official Raiden client, the participants will be able
// to receive correct final balances at the end of the channel lifecycle
// - it MUST ensure that the participants cannot cheat by providing an
// old, valid balance proof of their partner; meaning that their partner MUST
// receive at least the amount of tokens that he would have received if
// the latest valid balance proofs are used.
// - the contract cannot determine if a balance proof is invalid (values
// are not within the constraints enforced by the official Raiden client),
// therefore it cannot ensure correctness. Users MUST use the official
// Raiden clients for signing balance proofs.
require(channel_identifier == getChannelIdentifier(participant1, participant2));
bytes32 pair_hash;
pair_hash = getParticipantsHash(participant1, participant2);
Channel storage channel = channels[channel_identifier];
require(channel.state == ChannelState.Closed);
// Settlement window must be over
require(channel.settle_block_number < block.number);
Participant storage participant1_state = channel.participants[participant1];
Participant storage participant2_state = channel.participants[participant2];
require(verifyBalanceHashData(
participant1_state,
participant1_transferred_amount,
participant1_locked_amount,
participant1_locksroot
));
require(verifyBalanceHashData(
participant2_state,
participant2_transferred_amount,
participant2_locked_amount,
participant2_locksroot
));
// We are calculating the final token amounts that need to be
// transferred to the participants now and the amount of tokens that
// need to remain locked in the contract. These tokens can be unlocked
// by calling `unlock`.
// participant1_transferred_amount = the amount of tokens that
// participant1 will receive in this transaction.
// participant2_transferred_amount = the amount of tokens that
// participant2 will receive in this transaction.
// participant1_locked_amount = the amount of tokens remaining in the
// contract, representing pending transfers from participant1 to participant2.
// participant2_locked_amount = the amount of tokens remaining in the
// contract, representing pending transfers from participant2 to participant1.
// We are reusing variables due to the local variables number limit.
// For better readability this can be refactored further.
(
participant1_transferred_amount,
participant2_transferred_amount,
participant1_locked_amount,
participant2_locked_amount
) = getSettleTransferAmounts(
participant1_state,
participant1_transferred_amount,
participant1_locked_amount,
participant2_state,
participant2_transferred_amount,
participant2_locked_amount
);
// Remove the channel data from storage
delete channel.participants[participant1];
delete channel.participants[participant2];
delete channels[channel_identifier];
// Remove the pair's channel counter
delete participants_hash_to_channel_identifier[pair_hash];
// Store balance data needed for `unlock`, including the calculated
// locked amounts remaining in the contract.
storeUnlockData(
channel_identifier,
participant1,
participant2,
participant1_locked_amount,
participant1_locksroot
);
storeUnlockData(
channel_identifier,
participant2,
participant1,
participant2_locked_amount,
participant2_locksroot
);
emit ChannelSettled(
channel_identifier,
participant1_transferred_amount,
participant2_transferred_amount
);
// Do the actual token transfers
if (participant1_transferred_amount > 0) {
require(token.transfer(participant1, participant1_transferred_amount));
}
if (participant2_transferred_amount > 0) {
require(token.transfer(participant2, participant2_transferred_amount));
}
}
/// @notice Unlocks all pending off-chain transfers from `partner` to
/// `participant` and sends the locked tokens corresponding to locks with
/// secrets registered on-chain to the `participant`. Locked tokens
/// corresponding to locks where the secret was not revelead on-chain will
/// return to the `partner`. Anyone can call unlock.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant Address who will receive the claimable unlocked
/// tokens.
/// @param partner Address who sent the pending transfers and will receive
/// the unclaimable unlocked tokens.
/// @param merkle_tree_leaves The entire merkle tree of pending transfers
/// that `partner` sent to `participant`.
function unlock(
uint256 channel_identifier,
address participant,
address partner,
bytes merkle_tree_leaves
)
public
{
// Channel represented by channel_identifier must be settled and
// channel data deleted
require(channel_identifier != getChannelIdentifier(participant, partner));
// After the channel is settled the storage is cleared, therefore the
// value will be NonExistent and not Settled. The value Settled is used
// for the external APIs
require(channels[channel_identifier].state == ChannelState.NonExistent);
require(merkle_tree_leaves.length > 0);
bytes32 unlock_key;
bytes32 computed_locksroot;
uint256 unlocked_amount;
uint256 locked_amount;
uint256 returned_tokens;
// Calculate the locksroot for the pending transfers and the amount of
// tokens corresponding to the locked transfers with secrets revealed
// on chain.
(computed_locksroot, unlocked_amount) = getMerkleRootAndUnlockedAmount(
merkle_tree_leaves
);
// The partner must have a non-empty locksroot on-chain that must be
// the same as the computed locksroot.
// Get the amount of tokens that have been left in the contract, to
// account for the pending transfers `partner` -> `participant`.
unlock_key = getUnlockIdentifier(channel_identifier, partner, participant);
UnlockData storage unlock_data = unlock_identifier_to_unlock_data[unlock_key];
locked_amount = unlock_data.locked_amount;
// Locksroot must be the same as the computed locksroot
require(unlock_data.locksroot == computed_locksroot);
// There are no pending transfers if the locked_amount is 0.
// Transaction must fail
require(locked_amount > 0);
// Make sure we don't transfer more tokens than previously reserved in
// the smart contract.
unlocked_amount = min(unlocked_amount, locked_amount);
// Transfer the rest of the tokens back to the partner
returned_tokens = locked_amount - unlocked_amount;
// Remove partner's unlock data
delete unlock_identifier_to_unlock_data[unlock_key];
emit ChannelUnlocked(
channel_identifier,
participant,
partner,
computed_locksroot,
unlocked_amount,
returned_tokens
);
// Transfer the unlocked tokens to the participant. unlocked_amount can
// be 0
if (unlocked_amount > 0) {
require(token.transfer(participant, unlocked_amount));
}
// Transfer the rest of the tokens back to the partner
if (returned_tokens > 0) {
require(token.transfer(partner, returned_tokens));
}
// At this point, this should always be true
assert(locked_amount >= returned_tokens);
assert(locked_amount >= unlocked_amount);
}
/* /// @notice Cooperatively settles the balances between the two channel
/// participants and transfers the agreed upon token amounts to the
/// participants. After this the channel lifecycle has ended and no more
/// operations can be done on it.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant1_address Address of channel participant.
/// @param participant1_balance Amount of tokens that `participant1_address`
/// must receive when the channel is settled and removed.
/// @param participant2_address Address of the other channel participant.
/// @param participant2_balance Amount of tokens that `participant2_address`
/// must receive when the channel is settled and removed.
/// @param participant1_signature Signature of `participant1_address` on the
/// cooperative settle message.
/// @param participant2_signature Signature of `participant2_address` on the
/// cooperative settle message.
function cooperativeSettle(
uint256 channel_identifier,
address participant1_address,
uint256 participant1_balance,
address participant2_address,
uint256 participant2_balance,
bytes participant1_signature,
bytes participant2_signature
)
public
{
require(channel_identifier == getChannelIdentifier(
participant1_address,
participant2_address
));
bytes32 pair_hash;
address participant1;
address participant2;
uint256 total_available_deposit;
pair_hash = getParticipantsHash(participant1_address, participant2_address);
Channel storage channel = channels[channel_identifier];
require(channel.state == ChannelState.Opened);
participant1 = recoverAddressFromCooperativeSettleSignature(
channel_identifier,
participant1_address,
participant1_balance,
participant2_address,
participant2_balance,
participant1_signature
);
// The provided address must be the same as the recovered one
require(participant1 == participant1_address);
participant2 = recoverAddressFromCooperativeSettleSignature(
channel_identifier,
participant1_address,
participant1_balance,
participant2_address,
participant2_balance,
participant2_signature
);
// The provided address must be the same as the recovered one
require(participant2 == participant2_address);
Participant storage participant1_state = channel.participants[participant1];
Participant storage participant2_state = channel.participants[participant2];
total_available_deposit = getChannelAvailableDeposit(
participant1_state,
participant2_state
);
// The sum of the provided balances must be equal to the total
// available deposit
require(total_available_deposit == (participant1_balance + participant2_balance));
// Overflow check for the balances addition from the above check.
// This overflow should never happen if the token.transfer function is implemented
// correctly. We do not control the token implementation, therefore we add this
// check for safety.
require(participant1_balance <= participant1_balance + participant2_balance);
// Remove channel data from storage before doing the token transfers
delete channel.participants[participant1];
delete channel.participants[participant2];
delete channels[channel_identifier];
// Remove the pair's channel counter
delete participants_hash_to_channel_identifier[pair_hash];
emit ChannelSettled(channel_identifier, participant1_balance, participant2_balance);
// Do the token transfers
if (participant1_balance > 0) {
require(token.transfer(participant1, participant1_balance));
}
if (participant2_balance > 0) {
require(token.transfer(participant2, participant2_balance));
}
} */
/// @notice Returns the unique identifier for the channel given by the
/// contract.
/// @param participant Address of a channel participant.
/// @param partner Address of the other channel participant.
/// @return Unique identifier for the channel. It can be 0 if channel does
/// not exist.
function getChannelIdentifier(address participant, address partner)
view
public
returns (uint256)
{
require(participant != address(0x0));
require(partner != address(0x0));
require(participant != partner);
bytes32 pair_hash = getParticipantsHash(participant, partner);
return participants_hash_to_channel_identifier[pair_hash];
}
/// @dev Returns the channel specific data.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant1 Address of a channel participant.
/// @param participant2 Address of the other channel participant.
/// @return Channel settle_block_number and state.
function getChannelInfo(
uint256 channel_identifier,
address participant1,
address participant2
)
view
external
returns (uint256, ChannelState)
{
bytes32 unlock_key1;
bytes32 unlock_key2;
Channel storage channel = channels[channel_identifier];
ChannelState state = channel.state; // This must **not** update the storage
if (state == ChannelState.NonExistent &&
channel_identifier > 0 &&
channel_identifier <= channel_counter
) {
// The channel has been settled, channel data is removed Therefore,
// the channel state in storage is actually `0`, or `NonExistent`
// However, for this view function, we return `Settled`, in order
// to provide a consistent external API
state = ChannelState.Settled;
// We might still have data stored for future unlock operations
// Only if we do not, we can consider the channel as `Removed`
unlock_key1 = getUnlockIdentifier(channel_identifier, participant1, participant2);
UnlockData storage unlock_data1 = unlock_identifier_to_unlock_data[unlock_key1];
unlock_key2 = getUnlockIdentifier(channel_identifier, participant2, participant1);
UnlockData storage unlock_data2 = unlock_identifier_to_unlock_data[unlock_key2];
if (unlock_data1.locked_amount == 0 && unlock_data2.locked_amount == 0) {
state = ChannelState.Removed;
}
}
return (
channel.settle_block_number,
state
);
}
/// @dev Returns the channel specific data.
/// @param channel_identifier Identifier for the channel on which this
/// operation takes place.
/// @param participant Address of the channel participant whose data will be
/// returned.
/// @param partner Address of the channel partner.
/// @return Participant's deposit, withdrawn_amount, whether the participant
/// has called `closeChannel` or not, balance_hash, nonce, locksroot,
/// locked_amount.
function getChannelParticipantInfo(
uint256 channel_identifier,
address participant,
address partner
)
view
external
returns (uint256, uint256, bool, bytes32, uint256, bytes32, uint256)
{
bytes32 unlock_key;
Participant storage participant_state = channels[channel_identifier].participants[
participant
];
unlock_key = getUnlockIdentifier(channel_identifier, participant, partner);
UnlockData storage unlock_data = unlock_identifier_to_unlock_data[unlock_key];
return (
participant_state.deposit,
participant_state.withdrawn_amount,
participant_state.is_the_closer,
participant_state.balance_hash,
participant_state.nonce,
unlock_data.locksroot,
unlock_data.locked_amount
);
}
/// @dev Get the hash of the participant addresses, ordered
/// lexicographically.
/// @param participant Address of a channel participant.
/// @param partner Address of the other channel participant.
function getParticipantsHash(address participant, address partner)
pure
public
returns (bytes32)
{
require(participant != address(0x0));
require(partner != address(0x0));
require(participant != partner);
if (participant < partner) {
return keccak256(abi.encodePacked(participant, partner));
} else {
return keccak256(abi.encodePacked(partner, participant));
}
}
function getUnlockIdentifier(
uint256 channel_identifier,
address participant,
address partner
)
pure
public
returns (bytes32)
{
require(participant != partner);
return keccak256(abi.encodePacked(channel_identifier, participant, partner));
}
function updateBalanceProofData(
Channel storage channel,
address participant,
uint256 nonce,
bytes32 balance_hash
)
internal
{
Participant storage participant_state = channel.participants[participant];
// Multiple calls to updateNonClosingBalanceProof can be made and we
// need to store the last known balance proof data
require(nonce > participant_state.nonce);
participant_state.nonce = nonce;
participant_state.balance_hash = balance_hash;
}
function storeUnlockData(
uint256 channel_identifier,
address participant,
address partner,
uint256 locked_amount,
bytes32 locksroot
)
internal
{
// If there are transfers to unlock, store the locksroot and total
// amount of tokens
if (locked_amount == 0 || locksroot == 0) {
return;
}
bytes32 key = getUnlockIdentifier(channel_identifier, participant, partner);
UnlockData storage unlock_data = unlock_identifier_to_unlock_data[key];
unlock_data.locksroot = locksroot;
unlock_data.locked_amount = locked_amount;
}
function getChannelAvailableDeposit(
Participant storage participant1_state,
Participant storage participant2_state
)
view
internal
returns (uint256 total_available_deposit)
{
total_available_deposit = (
participant1_state.deposit +
participant2_state.deposit -
participant1_state.withdrawn_amount -
participant2_state.withdrawn_amount
);
}
/// @dev Function that calculates the amount of tokens that the participants
/// will receive when calling settleChannel.
/// Check https://github.com/raiden-network/raiden-contracts/issues/188 for the settlement
/// algorithm analysis and explanations.
function getSettleTransferAmounts(
Participant storage participant1_state,
uint256 participant1_transferred_amount,
uint256 participant1_locked_amount,
Participant storage participant2_state,
uint256 participant2_transferred_amount,
uint256 participant2_locked_amount
)
view
private
returns (uint256, uint256, uint256, uint256)
{
// The scope of this function is to compute the settlement amounts that
// the two channel participants will receive when calling settleChannel
// and the locked amounts that remain in the contract, to account for
// the pending, not finalized transfers, that will be received by the
// participants when calling `unlock`.
// The amount of tokens that participant1 MUST receive at the end of
// the channel lifecycle (after settleChannel and unlock) is:
// B1 = D1 - W1 + T2 - T1 + Lc2 - Lc1
// The amount of tokens that participant2 MUST receive at the end of
// the channel lifecycle (after settleChannel and unlock) is:
// B2 = D2 - W2 + T1 - T2 + Lc1 - Lc2
// B1 + B2 = TAD = D1 + D2 - W1 - W2
// TAD = total available deposit at settlement time
// L1 = Lc1 + Lu1
// L2 = Lc2 + Lu2
// where:
// B1 = final balance of participant1 after the channel is removed
// D1 = total amount deposited by participant1 into the channel
// W1 = total amount withdrawn by participant1 from the channel
// T2 = total amount transferred by participant2 to participant1 (finalized transfers)
// T1 = total amount transferred by participant1 to participant2 (finalized transfers)
// L1 = total amount of tokens locked in pending transfers, sent by
// participant1 to participant2
// L2 = total amount of tokens locked in pending transfers, sent by
// participant2 to participant1
// Lc2 = the amount that can be claimed by participant1 from the pending
// transfers (that have not been finalized off-chain), sent by
// participant2 to participant1. These are part of the locked amount
// value from participant2's balance proof. They are considered claimed
// if the secret corresponding to these locked transfers was registered
// on-chain, in the SecretRegistry contract, before the lock's expiration.
// Lu1 = unclaimable locked amount from L1
// Lc1 = the amount that can be claimed by participant2 from the pending
// transfers (that have not been finalized off-chain),
// sent by participant1 to participant2
// Lu2 = unclaimable locked amount from L2
// Notes:
// 1) The unclaimble tokens from a locked amount will return to the sender.
// At the time of calling settleChannel, the TokenNetwork contract does
// not know what locked amounts are claimable or unclaimable.
// 2) There are some Solidity constraints that make the calculations
// more difficult: attention to overflows and underflows, that MUST be
// handled without throwing.
// Cases that require attention:
// case1. If participant1 does NOT provide a balance proof or provides
// an old balance proof. participant2_transferred_amount can be [0,
// real_participant2_transferred_amount) We MUST NOT punish
// participant2.
// case2. If participant2 does NOT provide a balance proof or provides
// an old balance proof. participant1_transferred_amount can be [0,
// real_participant1_transferred_amount) We MUST NOT punish
// participant1.
// case3. If neither participants provide a balance proof, we just
// subtract their withdrawn amounts from their deposits.
// This is why, the algorithm implemented in Solidity is:
// (explained at each step, below)
// RmaxP1 = (T2 + L2) - (T1 + L1) + D1 - W1
// RmaxP1 = min(TAD, RmaxP1)
// RmaxP2 = TAD - RmaxP1
// SL2 = min(RmaxP1, L2)
// S1 = RmaxP1 - SL2
// SL1 = min(RmaxP2, L1)
// S2 = RmaxP2 - SL1
// where:
// RmaxP1 = due to possible over/underflows that only appear when using
// old balance proofs & the fact that settlement balance calculation
// is symmetric (we can calculate either RmaxP1 and RmaxP2 first,
// order does not affect result), this is a convention used to determine
// the maximum receivable amount of participant1 at settlement time
// S1 = amount received by participant1 when calling settleChannel
// SL1 = the maximum amount from L1 that can be locked in the
// TokenNetwork contract when calling settleChannel (due to overflows
// that only happen when using old balance proofs)
// S2 = amount received by participant2 when calling settleChannel
// SL2 = the maximum amount from L2 that can be locked in the
// TokenNetwork contract when calling settleChannel (due to overflows
// that only happen when using old balance proofs)
uint256 participant1_amount;
uint256 participant2_amount;
uint256 total_available_deposit;
SettlementData memory participant1_settlement;
SettlementData memory participant2_settlement;
participant1_settlement.deposit = participant1_state.deposit;
participant1_settlement.withdrawn = participant1_state.withdrawn_amount;
participant1_settlement.transferred = participant1_transferred_amount;
participant1_settlement.locked = participant1_locked_amount;
participant2_settlement.deposit = participant2_state.deposit;
participant2_settlement.withdrawn = participant2_state.withdrawn_amount;
participant2_settlement.transferred = participant2_transferred_amount;
participant2_settlement.locked = participant2_locked_amount;
// TAD = D1 + D2 - W1 - W2 = total available deposit at settlement time
total_available_deposit = getChannelAvailableDeposit(
participant1_state,
participant2_state
);
// RmaxP1 = (T2 + L2) - (T1 + L1) + D1 - W1
// This amount is the maximum possible amount that participant1 can
// receive at settlement time and also contains the entire locked amount
// of the pending transfers from participant2 to participant1.
participant1_amount = getMaxPossibleReceivableAmount(
participant1_settlement,
participant2_settlement
);
// RmaxP1 = min(TAD, RmaxP1)
// We need to bound this to the available channel deposit in order to
// not send tokens from other channels. The only case where TAD is
// smaller than RmaxP1 is when at least one balance proof is old.
participant1_amount = min(participant1_amount, total_available_deposit);
// RmaxP2 = TAD - RmaxP1
// Now it is safe to subtract without underflow
participant2_amount = total_available_deposit - participant1_amount;
// SL2 = min(RmaxP1, L2)
// S1 = RmaxP1 - SL2
// Both operations are done by failsafe_subtract
// We take out participant2's pending transfers locked amount, bounding
// it by the maximum receivable amount of participant1
(participant1_amount, participant2_locked_amount) = failsafe_subtract(
participant1_amount,
participant2_locked_amount
);
// SL1 = min(RmaxP2, L1)
// S2 = RmaxP2 - SL1
// Both operations are done by failsafe_subtract
// We take out participant1's pending transfers locked amount, bounding
// it by the maximum receivable amount of participant2
(participant2_amount, participant1_locked_amount) = failsafe_subtract(
participant2_amount,
participant1_locked_amount
);
// This should never throw:
// S1 and S2 MUST be smaller than TAD
assert(participant1_amount <= total_available_deposit);
assert(participant2_amount <= total_available_deposit);
// S1 + S2 + SL1 + SL2 == TAD
assert(total_available_deposit == (
participant1_amount +
participant2_amount +
participant1_locked_amount +
participant2_locked_amount
));
return (
participant1_amount,
participant2_amount,
participant1_locked_amount,
participant2_locked_amount
);
}
function getMaxPossibleReceivableAmount(
SettlementData participant1_settlement,
SettlementData participant2_settlement
)
pure
internal
returns (uint256)
{
uint256 participant1_max_transferred;
uint256 participant2_max_transferred;
uint256 participant1_net_max_received;
uint256 participant1_max_amount;
// This is the maximum possible amount that participant1 could transfer
// to participant2, if all the pending lock secrets have been
// registered
participant1_max_transferred = failsafe_addition(
participant1_settlement.transferred,
participant1_settlement.locked
);
// This is the maximum possible amount that participant2 could transfer
// to participant1, if all the pending lock secrets have been
// registered
participant2_max_transferred = failsafe_addition(
participant2_settlement.transferred,
participant2_settlement.locked
);
// We enforce this check artificially, in order to get rid of hard
// to deal with over/underflows. Settlement balance calculation is
// symmetric (we can calculate either RmaxP1 and RmaxP2 first, order does
// not affect result). This means settleChannel must be called with
// ordered values.
require(participant2_max_transferred >= participant1_max_transferred);
assert(participant1_max_transferred >= participant1_settlement.transferred);
assert(participant2_max_transferred >= participant2_settlement.transferred);
// This is the maximum amount that participant1 can receive at settlement time
participant1_net_max_received = (
participant2_max_transferred -
participant1_max_transferred
);
// Next, we add the participant1's deposit and subtract the already
// withdrawn amount
participant1_max_amount = failsafe_addition(
participant1_net_max_received,
participant1_settlement.deposit
);
// Subtract already withdrawn amount
(participant1_max_amount, ) = failsafe_subtract(
participant1_max_amount,
participant1_settlement.withdrawn
);
return participant1_max_amount;
}
function verifyBalanceHashData(
Participant storage participant,
uint256 transferred_amount,
uint256 locked_amount,
bytes32 locksroot
)
view
internal
returns (bool)
{
// When no balance proof has been provided, we need to check this
// separately because hashing values of 0 outputs a value != 0
if (participant.balance_hash == 0 &&
transferred_amount == 0 &&
locked_amount == 0 &&
locksroot == 0
) {
return true;
}
// Make sure the hash of the provided state is the same as the stored
// balance_hash
return participant.balance_hash == keccak256(abi.encodePacked(
transferred_amount,
locked_amount,
locksroot
));
}
function recoverAddressFromBalanceProof(
uint256 channel_identifier,
bytes32 balance_hash,
uint256 nonce,
bytes32 additional_hash,
bytes signature
)
view
internal
returns (address signature_address)
{
// Length of the actual message: 20 + 32 + 32 + 32 + 32 + 32 + 32
string memory message_length = '212';
bytes32 message_hash = keccak256(abi.encodePacked(
signature_prefix,
message_length,
address(this),
chain_id,
uint256(MessageTypeId.BalanceProof),
channel_identifier,
balance_hash,
nonce,
additional_hash
));
signature_address = ECVerify.ecverify(message_hash, signature);
}
function recoverAddressFromBalanceProofUpdateMessage(
uint256 channel_identifier,
bytes32 balance_hash,
uint256 nonce,
bytes32 additional_hash,
bytes closing_signature,
bytes non_closing_signature
)
view
internal
returns (address signature_address)
{
// Length of the actual message: 20 + 32 + 32 + 32 + 32 + 32 + 32 + 65
string memory message_length = '277';
bytes32 message_hash = keccak256(abi.encodePacked(
signature_prefix,
message_length,
address(this),
chain_id,
uint256(MessageTypeId.BalanceProofUpdate),
channel_identifier,
balance_hash,
nonce,
additional_hash,
closing_signature
));
signature_address = ECVerify.ecverify(message_hash, non_closing_signature);
}
/* function recoverAddressFromCooperativeSettleSignature(
uint256 channel_identifier,
address participant1,
uint256 participant1_balance,
address participant2,
uint256 participant2_balance,
bytes signature
)
view
internal
returns (address signature_address)
{
// Length of the actual message: 20 + 32 + 32 + 32 + 20 + 32 + 20 + 32
string memory message_length = '220';
bytes32 message_hash = keccak256(abi.encodePacked(
signature_prefix,
message_length,
address(this),
chain_id,
uint256(MessageTypeId.CooperativeSettle),
channel_identifier,
participant1,
participant1_balance,
participant2,
participant2_balance
));
signature_address = ECVerify.ecverify(message_hash, signature);
} */
/* function recoverAddressFromWithdrawMessage(
uint256 channel_identifier,
address participant,
uint256 total_withdraw,
bytes signature
)
view
internal
returns (address signature_address)
{
// Length of the actual message: 20 + 32 + 32 + 32 + 20 + 32
string memory message_length = '168';
bytes32 message_hash = keccak256(abi.encodePacked(
signature_prefix,
message_length,
address(this),
chain_id,
uint256(MessageTypeId.Withdraw),
channel_identifier,
participant,
total_withdraw
));
signature_address = ECVerify.ecverify(message_hash, signature);
} */
/// @dev Calculates the merkle root for the pending transfers data and
//calculates the amount / of tokens that can be unlocked because the secret
//was registered on-chain.
function getMerkleRootAndUnlockedAmount(bytes merkle_tree_leaves)
view
internal
returns (bytes32, uint256)
{
uint256 length = merkle_tree_leaves.length;
// each merkle_tree lock component has this form:
// (locked_amount || expiration_block || secrethash) = 3 * 32 bytes
require(length % 96 == 0);
uint256 i;
uint256 total_unlocked_amount;
uint256 unlocked_amount;
bytes32 lockhash;
bytes32 merkle_root;
bytes32[] memory merkle_layer = new bytes32[](length / 96 + 1);
for (i = 32; i < length; i += 96) {
(lockhash, unlocked_amount) = getLockDataFromMerkleTree(merkle_tree_leaves, i);
total_unlocked_amount += unlocked_amount;
merkle_layer[i / 96] = lockhash;
}
length /= 96;
while (length > 1) {
if (length % 2 != 0) {
merkle_layer[length] = merkle_layer[length - 1];
length += 1;
}
for (i = 0; i < length - 1; i += 2) {
if (merkle_layer[i] == merkle_layer[i + 1]) {
lockhash = merkle_layer[i];
} else if (merkle_layer[i] < merkle_layer[i + 1]) {
lockhash = keccak256(abi.encodePacked(merkle_layer[i], merkle_layer[i + 1]));
} else {
lockhash = keccak256(abi.encodePacked(merkle_layer[i + 1], merkle_layer[i]));
}
merkle_layer[i / 2] = lockhash;
}
length = i / 2;
}
merkle_root = merkle_layer[0];
return (merkle_root, total_unlocked_amount);
}
function getLockDataFromMerkleTree(bytes merkle_tree_leaves, uint256 offset)
view
internal
returns (bytes32, uint256)
{
uint256 expiration_block;
uint256 locked_amount;
uint256 reveal_block;
bytes32 secrethash;
bytes32 lockhash;
if (merkle_tree_leaves.length <= offset) {
return (lockhash, 0);
}
assembly {
expiration_block := mload(add(merkle_tree_leaves, offset))
locked_amount := mload(add(merkle_tree_leaves, add(offset, 32)))
secrethash := mload(add(merkle_tree_leaves, add(offset, 64)))
}
// Calculate the lockhash for computing the merkle root
lockhash = keccak256(abi.encodePacked(expiration_block, locked_amount, secrethash));
// Check if the lock's secret was revealed in the SecretRegistry The
// secret must have been revealed in the SecretRegistry contract before
// the lock's expiration_block in order for the hash time lock transfer
// to be successful.
reveal_block = secret_registry.getSecretRevealBlockHeight(secrethash);
if (reveal_block == 0 || expiration_block <= reveal_block) {
locked_amount = 0;
}
return (lockhash, locked_amount);
}
function min(uint256 a, uint256 b) pure internal returns (uint256)
{
return a > b ? b : a;
}
function max(uint256 a, uint256 b) pure internal returns (uint256)
{
return a > b ? a : b;
}
/// @dev Special subtraction function that does not fail when underflowing.
/// @param a Minuend
/// @param b Subtrahend
/// @return Minimum between the result of the subtraction and 0, the maximum
/// subtrahend for which no underflow occurs.
function failsafe_subtract(uint256 a, uint256 b)
pure
internal
returns (uint256, uint256)
{
return a > b ? (a - b, b) : (0, a);
}
/// @dev Special addition function that does not fail when overflowing.
/// @param a Addend
/// @param b Addend
/// @return Maximum between the result of the addition or the maximum
/// uint256 value.
function failsafe_addition(uint256 a, uint256 b)
pure
internal
returns (uint256)
{
uint256 sum = a + b;
return sum >= a ? sum : MAX_SAFE_UINT256;
}
}
/// @title TokenNetworkRegistry
/// @notice The TokenNetwork Registry deploys new TokenNetwork contracts for the
/// Raiden Network protocol.
contract TokenNetworkRegistry is Utils {
string constant public contract_version = "0.4.0";
address public secret_registry_address;
uint256 public chain_id;
uint256 public settlement_timeout_min;
uint256 public settlement_timeout_max;
// Only for the limited Red Eyes release
address public deprecation_executor;
bool public token_network_created = false;
// Token address => TokenNetwork address
mapping(address => address) public token_to_token_networks;
event TokenNetworkCreated(address indexed token_address, address indexed token_network_address);
modifier canCreateTokenNetwork() {
require(token_network_created == false);
_;
}
constructor(
address _secret_registry_address,
uint256 _chain_id,
uint256 _settlement_timeout_min,
uint256 _settlement_timeout_max
)
public
{
require(_chain_id > 0);
require(_settlement_timeout_min > 0);
require(_settlement_timeout_max > 0);
require(_settlement_timeout_max > _settlement_timeout_min);
require(_secret_registry_address != address(0x0));
require(contractExists(_secret_registry_address));
secret_registry_address = _secret_registry_address;
chain_id = _chain_id;
settlement_timeout_min = _settlement_timeout_min;
settlement_timeout_max = _settlement_timeout_max;
deprecation_executor = msg.sender;
}
/// @notice Deploy a new TokenNetwork contract for the Token deployed at
/// `_token_address`.
/// @param _token_address Ethereum address of an already deployed token, to
/// be used in the new TokenNetwork contract.
function createERC20TokenNetwork(address _token_address)
canCreateTokenNetwork
external
returns (address token_network_address)
{
require(token_to_token_networks[_token_address] == address(0x0));
// We limit the number of token networks to 1 for the Bug Bounty release
token_network_created = true;
TokenNetwork token_network;
// Token contract checks are in the corresponding TokenNetwork contract
token_network = new TokenNetwork(
_token_address,
secret_registry_address,
chain_id,
settlement_timeout_min,
settlement_timeout_max,
deprecation_executor
);
token_network_address = address(token_network);
token_to_token_networks[_token_address] = token_network_address;
emit TokenNetworkCreated(_token_address, token_network_address);
return token_network_address;
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"token_to_token_networks","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"settlement_timeout_max","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deprecation_executor","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"chain_id","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_token_address","type":"address"}],"name":"createERC20TokenNetwork","outputs":[{"name":"token_network_address","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"contract_address","type":"address"}],"name":"contractExists","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"contract_version","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"token_network_created","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"settlement_timeout_min","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"secret_registry_address","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_secret_registry_address","type":"address"},{"name":"_chain_id","type":"uint256"},{"name":"_settlement_timeout_min","type":"uint256"},{"name":"_settlement_timeout_max","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"token_address","type":"address"},{"indexed":true,"name":"token_network_address","type":"address"}],"name":"TokenNetworkCreated","type":"event"}]Contract Creation Code
60806040526000600460146101000a81548160ff02191690831515021790555034801561002b57600080fd5b506040516080806148348339810180604052810190808051906020019092919080519060200190929190805190602001909291908051906020019092919050505060008311151561007b57600080fd5b60008211151561008a57600080fd5b60008111151561009957600080fd5b81811115156100a757600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141515156100e357600080fd5b6100fb846101a5640100000000026401000000009004565b151561010657600080fd5b836000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555082600181905550816002819055508060038190555033600460006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505050506101b8565b600080823b905060008111915050919050565b61466d806101c76000396000f3006080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630fabd9e7146100a9578063224df42f1461012c57806323aa8174146101575780633af973b1146101ae5780634cf71a04146101d95780637709bc781461025c578063b32c65c8146102b7578063b61c408314610347578063b8378f7514610376578063d0ad4bec146103a1575b600080fd5b3480156100b557600080fd5b506100ea600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b5061014161042b565b6040518082815260200191505060405180910390f35b34801561016357600080fd5b5061016c610431565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101ba57600080fd5b506101c3610457565b6040518082815260200191505060405180910390f35b3480156101e557600080fd5b5061021a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061045d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561026857600080fd5b5061029d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610742565b604051808215151515815260200191505060405180910390f35b3480156102c357600080fd5b506102cc610755565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030c5780820151818401526020810190506102f1565b50505050905090810190601f1680156103395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561035357600080fd5b5061035c61078e565b604051808215151515815260200191505060405180910390f35b34801561038257600080fd5b5061038b6107a1565b6040518082815260200191505060405180910390f35b3480156103ad57600080fd5b506103b66107a7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b60008060001515600460149054906101000a900460ff16151514151561048257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561051c57600080fd5b6001600460146101000a81548160ff021916908315150217905550826000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600154600254600354600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661058e6107cc565b808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019650505050505050604051809103906000f08015801561065b573d6000803e3d6000fd5b50905080915081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167ff11a7558a113d9627989c5edf26cbd19143b7375248e621c8e30ac9e0847dc3f60405160405180910390a381915050919050565b600080823b905060008111915050919050565b6040805190810160405280600581526020017f302e342e3000000000000000000000000000000000000000000000000000000081525081565b600460149054906101000a900460ff1681565b60025481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b604051613e65806107dd83390190560060806040526000600660146101000a81548160ff0219169083151502179055503480156200002c57600080fd5b5060405160c08062003e65833981018060405281019080805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614151515620000bf57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614151515620000fc57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156200013957600080fd5b6000841115156200014957600080fd5b6000831115156200015957600080fd5b82821115156200016857600080fd5b620001828662000369640100000000026401000000009004565b15156200018e57600080fd5b620001a88562000369640100000000026401000000009004565b1515620001b457600080fd5b856000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600281905550826003819055508160048190555060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015620002d257600080fd5b505af1158015620002e7573d6000803e3d6000fd5b505050506040513d6020811015620002fe57600080fd5b81019080805190602001909291905050501115156200031c57600080fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050506200037c565b600080823b905060008111915050919050565b613ad9806200038c6000396000f30060806040526004361061016a576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303d9d2531461016f5780630a798f24146102225780630fcc0c28146102a3578063224df42f146102ba57806323aa8174146102e557806324d73a931461033c5780633af973b1146103935780634845be76146103be578063524bef8a146103e95780635d6e441b1461042e57806363ea014314610459578063679b3763146104d057806371e75992146104fb5780637709bc78146105265780637c4734f414610581578063838d6e05146106005780638723423714610696578063938bcd67146107265780639cadb1591461079d578063b32c65c81461084e578063b7506d70146108de578063b8378f751461090d578063db45479b14610938578063e5949b5d146109f1578063ee4516d914610a47578063fadc554b14610b06578063fc0c546a14610bc9578063fe49ba1c14610c20575b600080fd5b34801561017b57600080fd5b5061022060048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca9565b005b34801561022e57600080fd5b5061028d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611096565b6040518082815260200191505060405180910390f35b3480156102af57600080fd5b506102b8611355565b005b3480156102c657600080fd5b506102cf6113f0565b6040518082815260200191505060405180910390f35b3480156102f157600080fd5b506102fa6113f6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561034857600080fd5b5061035161141c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561039f57600080fd5b506103a8611442565b6040518082815260200191505060405180910390f35b3480156103ca57600080fd5b506103d3611448565b6040518082815260200191505060405180910390f35b3480156103f557600080fd5b506104186004803603810190808035600019169060200190929190505050611455565b6040518082815260200191505060405180910390f35b34801561043a57600080fd5b5061044361146d565b6040518082815260200191505060405180910390f35b34801561046557600080fd5b506104ce60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611479565b005b3480156104dc57600080fd5b506104e56118d1565b6040518082815260200191505060405180910390f35b34801561050757600080fd5b506105106118d7565b6040518082815260200191505060405180910390f35b34801561053257600080fd5b50610567600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118fb565b604051808215151515815260200191505060405180910390f35b34801561058d57600080fd5b506105e2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061190e565b60405180826000191660001916815260200191505060405180910390f35b34801561060c57600080fd5b5061066b60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c06565b6040518083815260200182600481111561068157fe5b60ff1681526020019250505060405180910390f35b3480156106a257600080fd5b506106ab611d07565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156106eb5780820151818401526020810190506106d0565b50505050905090810190601f1680156107185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561073257600080fd5b50610787600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d40565b6040518082815260200191505060405180910390f35b3480156107a957600080fd5b5061084c60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035600019169060200190929190505050611e27565b005b34801561085a57600080fd5b50610863612351565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108a3578082015181840152602081019050610888565b50505050905090810190601f1680156108d05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108ea57600080fd5b506108f361238a565b604051808215151515815260200191505060405180910390f35b34801561091957600080fd5b5061092261239d565b6040518082815260200191505060405180910390f35b34801561094457600080fd5b506109ef60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001909291908035600019169060200190929190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506123a3565b005b3480156109fd57600080fd5b50610a1c6004803603810190808035906020019092919050505061255f565b60405180838152602001826004811115610a3257fe5b60ff1681526020019250505060405180910390f35b348015610a5357600080fd5b50610ab260048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612590565b60405180888152602001878152602001861515151581526020018560001916600019168152602001848152602001836000191660001916815260200182815260200197505050505050505060405180910390f35b348015610b1257600080fd5b50610bc760048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560001916906020019092919080359060200190929190803560001916906020019092919080359060200190820180359060200191909192939192939080359060200190820180359060200191909192939192939050505061266c565b005b348015610bd557600080fd5b50610bde6128fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610c2c57600080fd5b50610c8b60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612920565b60405180826000191660001916815260200191505060405180910390f35b600080600080600080610cbc8989611d40565b8a14151515610cca57600080fd5b60006004811115610cd757fe5b600760008c815260200190815260200160002060010160009054906101000a900460ff166004811115610d0657fe5b141515610d1257600080fd5b60008751111515610d2257600080fd5b610d2b87612a6e565b8095508196505050610d3e8a898b612920565b95506009600087600019166000191681526020019081526020016000209050806001015492508460001916816000015460001916141515610d7e57600080fd5b600083111515610d8d57600080fd5b610d978484612e86565b93508383039150600960008760001916600019168152602001908152602001600020600080820160009055600182016000905550508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b7f8c03cf01b3d4e6068cc494e6fe02aa9e3d4af069d37c32ecc3b241af5c37e6c0888887604051808460001916600019168152602001838152602001828152602001935050505060405180910390a46000841115610f5e576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a866040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610f1757600080fd5b505af1158015610f2b573d6000803e3d6000fd5b505050506040513d6020811015610f4157600080fd5b81019080805190602001909291905050501515610f5d57600080fd5b5b6000821115611072576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561102b57600080fd5b505af115801561103f573d6000803e3d6000fd5b505050506040513d602081101561105557600080fd5b8101908080519060200190929190505050151561107157600080fd5b5b81831015151561107e57fe5b83831015151561108a57fe5b50505050505050505050565b60008060008060001515600660149054906101000a900460ff1615151415156110be57600080fd5b8460035481101515156110d057600080fd5b60045481111515156110e157600080fd5b680d8d726b7177a800006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156111a757600080fd5b505af11580156111bb573d6000803e3d6000fd5b505050506040513d60208110156111d157600080fd5b81019080805190602001909291905050501015156111ee57600080fd5b6001600560008282540192505081905550600554925061120e888861190e565b935060006008600086600019166000191681526020019081526020016000205414151561123a57600080fd5b82600860008660001916600019168152602001908152602001600020819055506007600084815260200190815260200160002091506000826000015414151561127f57fe5b6000600481111561128c57fe5b8260010160009054906101000a900460ff1660048111156112a957fe5b1415156112b257fe5b85826000018190555060018260010160006101000a81548160ff021916908360048111156112dc57fe5b02179055508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16847f669a4b0ac0b9994c0f82ed4dbe07bb421fe74e5951725af4f139c7443ebf049d896040518082815260200191505060405180910390a4829450505050509392505050565b60001515600660149054906101000a900460ff16151514151561137757600080fd5b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113d357600080fd5b6001600660146101000a81548160ff021916908315150217905550565b60045481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b680d8d726b7177a8000081565b60086020528060005260406000206000915090505481565b67010a741a4627800081565b6000806000806000801515600660149054906101000a900460ff1615151415156114a257600080fd5b88600160048111156114b057fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff1660048111156114df57fe5b1415156114eb57600080fd5b6114f58988611d40565b8a14151561150257600080fd5b60008811151561151157600080fd5b67010a741a46278000881115151561152857600080fd5b600760008b815260200190815260200160002093508360020160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002092508360020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508260000154880395506000861115156115db57600080fd5b8786111515156115ea57600080fd5b87868460000154011415156115fb57fe5b680d8d726b7177a80000866000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156116c257600080fd5b505af11580156116d6573d6000803e3d6000fd5b505050506040513d60208110156116ec57600080fd5b8101908080519060200190929190505050011115151561170b57600080fd5b878360000181905550816000015483600001540194508260000154851015151561173457600080fd5b8873ffffffffffffffffffffffffffffffffffffffff168a7f2b55547a3b586ab51f65ee9ce4927fa6d25191388299988e89e059a02f9dd44585600001546040518082815260200191505060405180910390a36000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330896040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561187f57600080fd5b505af1158015611893573d6000803e3d6000fd5b505050506040513d60208110156118a957600080fd5b810190808051906020019092919050505015156118c557600080fd5b50505050505050505050565b60055481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600080823b905060008111915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561194b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561198757600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156119c257600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161015611afd578282604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401925050506040516020818303038152906040526040518082805190602001908083835b602083101515611ac95780518252602082019150602081019050602083039250611aa4565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050611c00565b8183604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401925050506040516020818303038152906040526040518082805190602001908083835b602083101515611bd05780518252602082019150602081019050602083039250611bab565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b600080600080600080600080600760008c815260200190815260200160002093508360010160009054906101000a900460ff16925060006004811115611c4857fe5b836004811115611c5457fe5b148015611c61575060008b115b8015611c6f57506005548b11155b15611cef5760039250611c838b8b8b612920565b95506009600087600019166000191681526020019081526020016000209150611cad8b8a8c612920565b9450600960008660001916600019168152602001908152602001600020905060008260010154148015611ce4575060008160010154145b15611cee57600492505b5b83600001548397509750505050505050935093915050565b6040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525081565b600080600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515611d7f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611dbb57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515611df657600080fd5b611e00848461190e565b90506008600082600019166000191681526020019081526020016000205491505092915050565b600080600080611e378c89611d40565b8d141515611e4457600080fd5b611e4e8c8961190e565b9350600760008e8152602001908152602001600020925060026004811115611e7257fe5b8360010160009054906101000a900460ff166004811115611e8f57fe5b141515611e9b57600080fd5b438360000154101515611ead57600080fd5b8260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050611f3f828c8c8c612e9f565b1515611f4a57600080fd5b611f5681888888612e9f565b1515611f6157600080fd5b611f6f828c8c848b8b612f9b565b809950819d50829a50839e50505050508260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff02191690556003820160009055600482016000905550508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff0219169055600382016000905560048201600090555050600760008e81526020019081526020016000206000808201600090556001820160006101000a81549060ff02191690555050600860008560001916600019168152602001908152602001600020600090556120cd8d8d8a8d8d6130aa565b6120da8d898e89896130aa565b8c7f0e239ef20c651bd0bc45e6f6a5fd46252d77d39d6602103e347add00cabdb0b48c89604051808381526020018281526020019250505060405180910390a260008b111561222e576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8d8d6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156121e757600080fd5b505af11580156121fb573d6000803e3d6000fd5b505050506040513d602081101561221157600080fd5b8101908080519060200190929190505050151561222d57600080fd5b5b6000871115612342576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156122fb57600080fd5b505af115801561230f573d6000803e3d6000fd5b505050506040513d602081101561232557600080fd5b8101908080519060200190929190505050151561234157600080fd5b5b50505050505050505050505050565b6040805190810160405280600581526020017f302e342e3000000000000000000000000000000000000000000000000000000081525081565b600660149054906101000a900460ff1681565b60035481565b60008087600160048111156123b457fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff1660048111156123e357fe5b1415156123ef57600080fd5b6123f93389611d40565b8914151561240657600080fd5b600760008a8152602001908152602001600020915060028260010160006101000a81548160ff0219169083600481111561243c57fe5b021790555060018260020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160006101000a81548160ff021916908315150217905550438260000160008282540192505081905550600086111561250f576124c68988888888613117565b92508273ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614151561250257600080fd5b61250e8284888a613358565b5b853373ffffffffffffffffffffffffffffffffffffffff168a7f5fe3d4a343010393184843ef4873386b572e844e89f6b41c9f60f5ab912fbdfe60405160405180910390a4505050505050505050565b60076020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b600080600080600080600080600080600760008e815260200190815260200160002060020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091506125ff8d8d8d612920565b92506009600084600019166000191681526020019081526020016000209050816000015482600101548360020160009054906101000a900460ff16846003015485600401548560000154866001015499509950995099509950995099505050509397509397509397909450565b60008060008061267c8d8d611d40565b8e14151561268957600080fd5b6000600102600019168b60001916141515156126a457600080fd5b60008a1115156126b357600080fd5b600760008f81526020019081526020016000209150600260048111156126d557fe5b8260010160009054906101000a900460ff1660048111156126f257fe5b1415156126fe57600080fd5b4382600001541015151561271157600080fd5b6127838e8c8c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050508b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050506133cc565b93508373ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff161415156127bf57600080fd5b6127fe8e8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050613117565b92508273ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff1614151561283a57600080fd5b8160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16151561289a57600080fd5b6128a6828e8c8e613358565b898d73ffffffffffffffffffffffffffffffffffffffff168f7f09bd10d8ee6f30d654401133d6eac60e091a0d8e13f54005754de9394c11fbd360405160405180910390a45050505050505050505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561295d57600080fd5b838383604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140193505050506040516020818303038152906040526040518082805190602001908083835b602083101515612a385780518252602082019150602081019050602083039250612a13565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090509392505050565b6000806000806000806000806060895196506000606088811515612a8e57fe5b06141515612a9b57600080fd5b6001606088811515612aa957fe5b0401604051908082528060200260200182016040528015612ad95781602001602082028038833980820191505090505b509050602095505b86861015612b3e57612af38a87613663565b809550819450505083850194508281606088811515612b0e57fe5b04815181101515612b1b57fe5b906020019060200201906000191690816000191681525050606086019550612ae1565b606087811515612b4a57fe5b0496505b6001871115612e59576000600288811515612b6557fe5b06141515612bb5578060018803815181101515612b7e57fe5b906020019060200201518188815181101515612b9657fe5b9060200190602002019060001916908160001916815250506001870196505b600095505b60018703861015612e45578060018701815181101515612bd657fe5b90602001906020020151600019168187815181101515612bf257fe5b90602001906020020151600019161415612c25578086815181101515612c1457fe5b906020019060200201519250612e07565b8060018701815181101515612c3657fe5b90602001906020020151600019168187815181101515612c5257fe5b90602001906020020151600019161015612d38578086815181101515612c7457fe5b906020019060200201518160018801815181101515612c8f57fe5b906020019060200201516040516020018083600019166000191681526020018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b602083101515612d045780518252602082019150602081019050602083039250612cdf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250612e06565b8060018701815181101515612d4957fe5b906020019060200201518187815181101515612d6157fe5b906020019060200201516040516020018083600019166000191681526020018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b602083101515612dd65780518252602082019150602081019050602083039250612db1565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902092505b5b8281600288811515612e1557fe5b04815181101515612e2257fe5b906020019060200201906000191690816000191681525050600286019550612bba565b600286811515612e5157fe5b049650612b4e565b806000815181101515612e6857fe5b90602001906020020151915081859850985050505050505050915091565b6000818311612e955782612e97565b815b905092915050565b600080600102856003015460001916148015612ebb5750600084145b8015612ec75750600083145b8015612eda575060006001028260001916145b15612ee85760019050612f93565b83838360405160200180848152602001838152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b602083101515612f555780518252602082019150602081019050602083039250612f30565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019168560030154600019161490505b949350505050565b6000806000806000806000612fae613a84565b612fb6613a84565b8e600001548260000181815250508e600101548260200181815250508d8260400181815250508c8260600181815250508b600001548160000181815250508b600101548160200181815250508a816040018181525050898160600181815250506130208f8d61383d565b925061302c828261385e565b94506130388584612e86565b94508483039350613049858b6138f2565b809b50819650505061305b848e6138f2565b809e50819550505082851115151561306f57fe5b82841115151561307b57fe5b898d85870101018314151561308c57fe5b84848e8c985098509850985050505050509650965096509692505050565b60008060008414806130c3575060006001028360001916145b156130cd5761310e565b6130d8878787612920565b91506009600083600019166000191681526020019081526020016000209050828160000181600019169055508381600101819055505b50505050505050565b6000606060006040805190810160405280600381526020017f323132000000000000000000000000000000000000000000000000000000000081525091506040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546001600481111561319d57fe5b8c8c8c8c604051602001808a805190602001908083835b6020831015156131d957805182526020820191506020810190506020830392506131b4565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b60208310151561322c5780518252602082019150602081019050602083039250613207565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018460001916600019168152602001838152602001826000191660001916815260200199505050505050505050506040516020818303038152906040526040518082805190602001908083835b60208310151561331257805182526020820191506020810190506020830392506132ed565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905061334b8185613917565b9250505095945050505050565b60008460020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060040154831115156133af57600080fd5b828160040181905550818160030181600019169055505050505050565b6000606060006040805190810160405280600381526020017f323737000000000000000000000000000000000000000000000000000000000081525091506040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546002600481111561345257fe5b8d8d8d8d8d604051602001808b805190602001908083835b60208310151561348f578051825260208201915060208101905060208303925061346a565b6001836020036101000a0380198251168184511680821785525050505050509050018a805190602001908083835b6020831015156134e257805182526020820191506020810190506020830392506134bd565b6001836020036101000a0380198251168184511680821785525050505050509050018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018881526020018781526020018681526020018560001916600019168152602001848152602001836000191660001916815260200182805190602001908083835b6020831015156135aa5780518252602082019150602081019050602083039250613585565b6001836020036101000a0380198251168184511680821785525050505050509050019a50505050505050505050506040516020818303038152906040526040518082805190602001908083835b60208310151561361c57805182526020820191506020810190506020830392506135f7565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090506136558185613917565b925050509695505050505050565b60008060008060008060008789511115156136875780600080905096509650613831565b87890151945060208801890151935060408801890151915084848360405160200180848152602001838152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310151561370c57805182526020820191506020810190506020830392506136e7565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c1f62946836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156137d457600080fd5b505af11580156137e8573d6000803e3d6000fd5b505050506040513d60208110156137fe57600080fd5b8101908080519060200190929190505050925060008314806138205750828511155b1561382a57600093505b8084965096505b50505050509250929050565b60008160010154836001015483600001548560000154010303905092915050565b600080600080600061387887604001518860600151613a43565b935061388c86604001518760600151613a43565b925083831015151561389d57600080fd5b866040015184101515156138ad57fe5b856040015183101515156138bd57fe5b83830391506138d0828860000151613a43565b90506138e08188602001516138f2565b50809150508094505050505092915050565b6000808284116139075760008481915061390c565b828403835b915091509250929050565b6000806000806041855114151561392d57600080fd5b6020850151925060408501519150606085015160001a9050601b8160ff16101561395857601b810190505b601b8160ff16148061396d5750601c8160ff16145b151561397857600080fd5b600186828585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156139ef573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515613a3757600080fd5b83935050505092915050565b600080828401905083811015613a79577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613a7b565b805b91505092915050565b6080604051908101604052806000815260200160008152602001600081526020016000815250905600a165627a7a7230582031e6ac55398c2f815444a8e98e33222f5641cc4acbed9b812770679645b193810029a165627a7a723058209ec12abfaaee57e6f55ba7369730721a0919118cb6458b48be444e91e6015a9f00290000000000000000000000002d07731e878e4c59bda93ea3fe93e34fb0172bd0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000879a4
Deployed Bytecode
0x6080604052600436106100a4576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630fabd9e7146100a9578063224df42f1461012c57806323aa8174146101575780633af973b1146101ae5780634cf71a04146101d95780637709bc781461025c578063b32c65c8146102b7578063b61c408314610347578063b8378f7514610376578063d0ad4bec146103a1575b600080fd5b3480156100b557600080fd5b506100ea600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506103f8565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561013857600080fd5b5061014161042b565b6040518082815260200191505060405180910390f35b34801561016357600080fd5b5061016c610431565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156101ba57600080fd5b506101c3610457565b6040518082815260200191505060405180910390f35b3480156101e557600080fd5b5061021a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061045d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561026857600080fd5b5061029d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610742565b604051808215151515815260200191505060405180910390f35b3480156102c357600080fd5b506102cc610755565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561030c5780820151818401526020810190506102f1565b50505050905090810190601f1680156103395780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561035357600080fd5b5061035c61078e565b604051808215151515815260200191505060405180910390f35b34801561038257600080fd5b5061038b6107a1565b6040518082815260200191505060405180910390f35b3480156103ad57600080fd5b506103b66107a7565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b60056020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60035481565b600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60015481565b60008060001515600460149054906101000a900460ff16151514151561048257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff16600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614151561051c57600080fd5b6001600460146101000a81548160ff021916908315150217905550826000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16600154600254600354600460009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1661058e6107cc565b808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018581526020018481526020018381526020018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019650505050505050604051809103906000f08015801561065b573d6000803e3d6000fd5b50905080915081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167ff11a7558a113d9627989c5edf26cbd19143b7375248e621c8e30ac9e0847dc3f60405160405180910390a381915050919050565b600080823b905060008111915050919050565b6040805190810160405280600581526020017f302e342e3000000000000000000000000000000000000000000000000000000081525081565b600460149054906101000a900460ff1681565b60025481565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b604051613e65806107dd83390190560060806040526000600660146101000a81548160ff0219169083151502179055503480156200002c57600080fd5b5060405160c08062003e65833981018060405281019080805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff1614151515620000bf57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff1614151515620000fc57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141515156200013957600080fd5b6000841115156200014957600080fd5b6000831115156200015957600080fd5b82821115156200016857600080fd5b620001828662000369640100000000026401000000009004565b15156200018e57600080fd5b620001a88562000369640100000000026401000000009004565b1515620001b457600080fd5b856000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555084600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555083600281905550826003819055508160048190555060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b158015620002d257600080fd5b505af1158015620002e7573d6000803e3d6000fd5b505050506040513d6020811015620002fe57600080fd5b81019080805190602001909291905050501115156200031c57600080fd5b80600660006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505050505050506200037c565b600080823b905060008111915050919050565b613ad9806200038c6000396000f30060806040526004361061016a576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303d9d2531461016f5780630a798f24146102225780630fcc0c28146102a3578063224df42f146102ba57806323aa8174146102e557806324d73a931461033c5780633af973b1146103935780634845be76146103be578063524bef8a146103e95780635d6e441b1461042e57806363ea014314610459578063679b3763146104d057806371e75992146104fb5780637709bc78146105265780637c4734f414610581578063838d6e05146106005780638723423714610696578063938bcd67146107265780639cadb1591461079d578063b32c65c81461084e578063b7506d70146108de578063b8378f751461090d578063db45479b14610938578063e5949b5d146109f1578063ee4516d914610a47578063fadc554b14610b06578063fc0c546a14610bc9578063fe49ba1c14610c20575b600080fd5b34801561017b57600080fd5b5061022060048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610ca9565b005b34801561022e57600080fd5b5061028d600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050611096565b6040518082815260200191505060405180910390f35b3480156102af57600080fd5b506102b8611355565b005b3480156102c657600080fd5b506102cf6113f0565b6040518082815260200191505060405180910390f35b3480156102f157600080fd5b506102fa6113f6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561034857600080fd5b5061035161141c565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34801561039f57600080fd5b506103a8611442565b6040518082815260200191505060405180910390f35b3480156103ca57600080fd5b506103d3611448565b6040518082815260200191505060405180910390f35b3480156103f557600080fd5b506104186004803603810190808035600019169060200190929190505050611455565b6040518082815260200191505060405180910390f35b34801561043a57600080fd5b5061044361146d565b6040518082815260200191505060405180910390f35b34801561046557600080fd5b506104ce60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611479565b005b3480156104dc57600080fd5b506104e56118d1565b6040518082815260200191505060405180910390f35b34801561050757600080fd5b506105106118d7565b6040518082815260200191505060405180910390f35b34801561053257600080fd5b50610567600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506118fb565b604051808215151515815260200191505060405180910390f35b34801561058d57600080fd5b506105e2600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919050505061190e565b60405180826000191660001916815260200191505060405180910390f35b34801561060c57600080fd5b5061066b60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611c06565b6040518083815260200182600481111561068157fe5b60ff1681526020019250505060405180910390f35b3480156106a257600080fd5b506106ab611d07565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156106eb5780820151818401526020810190506106d0565b50505050905090810190601f1680156107185780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561073257600080fd5b50610787600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611d40565b6040518082815260200191505060405180910390f35b3480156107a957600080fd5b5061084c60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035600019169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035600019169060200190929190505050611e27565b005b34801561085a57600080fd5b50610863612351565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108a3578082015181840152602081019050610888565b50505050905090810190601f1680156108d05780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b3480156108ea57600080fd5b506108f361238a565b604051808215151515815260200191505060405180910390f35b34801561091957600080fd5b5061092261239d565b6040518082815260200191505060405180910390f35b34801561094457600080fd5b506109ef60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035600019169060200190929190803590602001909291908035600019169060200190929190803590602001908201803590602001908080601f01602080910402602001604051908101604052809392919081815260200183838082843782019150505050505091929192905050506123a3565b005b3480156109fd57600080fd5b50610a1c6004803603810190808035906020019092919050505061255f565b60405180838152602001826004811115610a3257fe5b60ff1681526020019250505060405180910390f35b348015610a5357600080fd5b50610ab260048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612590565b60405180888152602001878152602001861515151581526020018560001916600019168152602001848152602001836000191660001916815260200182815260200197505050505050505060405180910390f35b348015610b1257600080fd5b50610bc760048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803560001916906020019092919080359060200190929190803560001916906020019092919080359060200190820180359060200191909192939192939080359060200190820180359060200191909192939192939050505061266c565b005b348015610bd557600080fd5b50610bde6128fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b348015610c2c57600080fd5b50610c8b60048036038101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612920565b60405180826000191660001916815260200191505060405180910390f35b600080600080600080610cbc8989611d40565b8a14151515610cca57600080fd5b60006004811115610cd757fe5b600760008c815260200190815260200160002060010160009054906101000a900460ff166004811115610d0657fe5b141515610d1257600080fd5b60008751111515610d2257600080fd5b610d2b87612a6e565b8095508196505050610d3e8a898b612920565b95506009600087600019166000191681526020019081526020016000209050806001015492508460001916816000015460001916141515610d7e57600080fd5b600083111515610d8d57600080fd5b610d978484612e86565b93508383039150600960008760001916600019168152602001908152602001600020600080820160009055600182016000905550508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b7f8c03cf01b3d4e6068cc494e6fe02aa9e3d4af069d37c32ecc3b241af5c37e6c0888887604051808460001916600019168152602001838152602001828152602001935050505060405180910390a46000841115610f5e576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a866040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b158015610f1757600080fd5b505af1158015610f2b573d6000803e3d6000fd5b505050506040513d6020811015610f4157600080fd5b81019080805190602001909291905050501515610f5d57600080fd5b5b6000821115611072576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561102b57600080fd5b505af115801561103f573d6000803e3d6000fd5b505050506040513d602081101561105557600080fd5b8101908080519060200190929190505050151561107157600080fd5b5b81831015151561107e57fe5b83831015151561108a57fe5b50505050505050505050565b60008060008060001515600660149054906101000a900460ff1615151415156110be57600080fd5b8460035481101515156110d057600080fd5b60045481111515156110e157600080fd5b680d8d726b7177a800006000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156111a757600080fd5b505af11580156111bb573d6000803e3d6000fd5b505050506040513d60208110156111d157600080fd5b81019080805190602001909291905050501015156111ee57600080fd5b6001600560008282540192505081905550600554925061120e888861190e565b935060006008600086600019166000191681526020019081526020016000205414151561123a57600080fd5b82600860008660001916600019168152602001908152602001600020819055506007600084815260200190815260200160002091506000826000015414151561127f57fe5b6000600481111561128c57fe5b8260010160009054906101000a900460ff1660048111156112a957fe5b1415156112b257fe5b85826000018190555060018260010160006101000a81548160ff021916908360048111156112dc57fe5b02179055508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16847f669a4b0ac0b9994c0f82ed4dbe07bb421fe74e5951725af4f139c7443ebf049d896040518082815260200191505060405180910390a4829450505050509392505050565b60001515600660149054906101000a900460ff16151514151561137757600080fd5b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415156113d357600080fd5b6001600660146101000a81548160ff021916908315150217905550565b60045481565b600660009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b680d8d726b7177a8000081565b60086020528060005260406000206000915090505481565b67010a741a4627800081565b6000806000806000801515600660149054906101000a900460ff1615151415156114a257600080fd5b88600160048111156114b057fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff1660048111156114df57fe5b1415156114eb57600080fd5b6114f58988611d40565b8a14151561150257600080fd5b60008811151561151157600080fd5b67010a741a46278000881115151561152857600080fd5b600760008b815260200190815260200160002093508360020160008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002092508360020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508260000154880395506000861115156115db57600080fd5b8786111515156115ea57600080fd5b87868460000154011415156115fb57fe5b680d8d726b7177a80000866000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001915050602060405180830381600087803b1580156116c257600080fd5b505af11580156116d6573d6000803e3d6000fd5b505050506040513d60208110156116ec57600080fd5b8101908080519060200190929190505050011115151561170b57600080fd5b878360000181905550816000015483600001540194508260000154851015151561173457600080fd5b8873ffffffffffffffffffffffffffffffffffffffff168a7f2b55547a3b586ab51f65ee9ce4927fa6d25191388299988e89e059a02f9dd44585600001546040518082815260200191505060405180910390a36000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330896040518463ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561187f57600080fd5b505af1158015611893573d6000803e3d6000fd5b505050506040513d60208110156118a957600080fd5b810190808051906020019092919050505015156118c557600080fd5b50505050505050505050565b60055481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600080823b905060008111915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561194b57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415151561198757600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16141515156119c257600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161015611afd578282604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401925050506040516020818303038152906040526040518082805190602001908083835b602083101515611ac95780518252602082019150602081019050602083039250611aa4565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050611c00565b8183604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c01000000000000000000000000028152601401925050506040516020818303038152906040526040518082805190602001908083835b602083101515611bd05780518252602082019150602081019050602083039250611bab565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090505b92915050565b600080600080600080600080600760008c815260200190815260200160002093508360010160009054906101000a900460ff16925060006004811115611c4857fe5b836004811115611c5457fe5b148015611c61575060008b115b8015611c6f57506005548b11155b15611cef5760039250611c838b8b8b612920565b95506009600087600019166000191681526020019081526020016000209150611cad8b8a8c612920565b9450600960008660001916600019168152602001908152602001600020905060008260010154148015611ce4575060008160010154145b15611cee57600492505b5b83600001548397509750505050505050935093915050565b6040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525081565b600080600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515611d7f57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614151515611dbb57600080fd5b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515611df657600080fd5b611e00848461190e565b90506008600082600019166000191681526020019081526020016000205491505092915050565b600080600080611e378c89611d40565b8d141515611e4457600080fd5b611e4e8c8961190e565b9350600760008e8152602001908152602001600020925060026004811115611e7257fe5b8360010160009054906101000a900460ff166004811115611e8f57fe5b141515611e9b57600080fd5b438360000154101515611ead57600080fd5b8260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050611f3f828c8c8c612e9f565b1515611f4a57600080fd5b611f5681888888612e9f565b1515611f6157600080fd5b611f6f828c8c848b8b612f9b565b809950819d50829a50839e50505050508260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff02191690556003820160009055600482016000905550508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff0219169055600382016000905560048201600090555050600760008e81526020019081526020016000206000808201600090556001820160006101000a81549060ff02191690555050600860008560001916600019168152602001908152602001600020600090556120cd8d8d8a8d8d6130aa565b6120da8d898e89896130aa565b8c7f0e239ef20c651bd0bc45e6f6a5fd46252d77d39d6602103e347add00cabdb0b48c89604051808381526020018281526020019250505060405180910390a260008b111561222e576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8d8d6040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156121e757600080fd5b505af11580156121fb573d6000803e3d6000fd5b505050506040513d602081101561221157600080fd5b8101908080519060200190929190505050151561222d57600080fd5b5b6000871115612342576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896040518363ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156122fb57600080fd5b505af115801561230f573d6000803e3d6000fd5b505050506040513d602081101561232557600080fd5b8101908080519060200190929190505050151561234157600080fd5b5b50505050505050505050505050565b6040805190810160405280600581526020017f302e342e3000000000000000000000000000000000000000000000000000000081525081565b600660149054906101000a900460ff1681565b60035481565b60008087600160048111156123b457fe5b6007600083815260200190815260200160002060010160009054906101000a900460ff1660048111156123e357fe5b1415156123ef57600080fd5b6123f93389611d40565b8914151561240657600080fd5b600760008a8152602001908152602001600020915060028260010160006101000a81548160ff0219169083600481111561243c57fe5b021790555060018260020160003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160006101000a81548160ff021916908315150217905550438260000160008282540192505081905550600086111561250f576124c68988888888613117565b92508273ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614151561250257600080fd5b61250e8284888a613358565b5b853373ffffffffffffffffffffffffffffffffffffffff168a7f5fe3d4a343010393184843ef4873386b572e844e89f6b41c9f60f5ab912fbdfe60405160405180910390a4505050505050505050565b60076020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b600080600080600080600080600080600760008e815260200190815260200160002060020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002091506125ff8d8d8d612920565b92506009600084600019166000191681526020019081526020016000209050816000015482600101548360020160009054906101000a900460ff16846003015485600401548560000154866001015499509950995099509950995099505050509397509397509397909450565b60008060008061267c8d8d611d40565b8e14151561268957600080fd5b6000600102600019168b60001916141515156126a457600080fd5b60008a1115156126b357600080fd5b600760008f81526020019081526020016000209150600260048111156126d557fe5b8260010160009054906101000a900460ff1660048111156126f257fe5b1415156126fe57600080fd5b4382600001541015151561271157600080fd5b6127838e8c8c8c8c8c8080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050508b8b8080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050506133cc565b93508373ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff161415156127bf57600080fd5b6127fe8e8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437820191505050505050613117565b92508273ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff1614151561283a57600080fd5b8160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16151561289a57600080fd5b6128a6828e8c8e613358565b898d73ffffffffffffffffffffffffffffffffffffffff168f7f09bd10d8ee6f30d654401133d6eac60e091a0d8e13f54005754de9394c11fbd360405160405180910390a45050505050505050505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415151561295d57600080fd5b838383604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c0100000000000000000000000002815260140193505050506040516020818303038152906040526040518082805190602001908083835b602083101515612a385780518252602082019150602081019050602083039250612a13565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090509392505050565b6000806000806000806000806060895196506000606088811515612a8e57fe5b06141515612a9b57600080fd5b6001606088811515612aa957fe5b0401604051908082528060200260200182016040528015612ad95781602001602082028038833980820191505090505b509050602095505b86861015612b3e57612af38a87613663565b809550819450505083850194508281606088811515612b0e57fe5b04815181101515612b1b57fe5b906020019060200201906000191690816000191681525050606086019550612ae1565b606087811515612b4a57fe5b0496505b6001871115612e59576000600288811515612b6557fe5b06141515612bb5578060018803815181101515612b7e57fe5b906020019060200201518188815181101515612b9657fe5b9060200190602002019060001916908160001916815250506001870196505b600095505b60018703861015612e45578060018701815181101515612bd657fe5b90602001906020020151600019168187815181101515612bf257fe5b90602001906020020151600019161415612c25578086815181101515612c1457fe5b906020019060200201519250612e07565b8060018701815181101515612c3657fe5b90602001906020020151600019168187815181101515612c5257fe5b90602001906020020151600019161015612d38578086815181101515612c7457fe5b906020019060200201518160018801815181101515612c8f57fe5b906020019060200201516040516020018083600019166000191681526020018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b602083101515612d045780518252602082019150602081019050602083039250612cdf565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209250612e06565b8060018701815181101515612d4957fe5b906020019060200201518187815181101515612d6157fe5b906020019060200201516040516020018083600019166000191681526020018260001916600019168152602001925050506040516020818303038152906040526040518082805190602001908083835b602083101515612dd65780518252602082019150602081019050602083039250612db1565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902092505b5b8281600288811515612e1557fe5b04815181101515612e2257fe5b906020019060200201906000191690816000191681525050600286019550612bba565b600286811515612e5157fe5b049650612b4e565b806000815181101515612e6857fe5b90602001906020020151915081859850985050505050505050915091565b6000818311612e955782612e97565b815b905092915050565b600080600102856003015460001916148015612ebb5750600084145b8015612ec75750600083145b8015612eda575060006001028260001916145b15612ee85760019050612f93565b83838360405160200180848152602001838152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b602083101515612f555780518252602082019150602081019050602083039250612f30565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020600019168560030154600019161490505b949350505050565b6000806000806000806000612fae613a84565b612fb6613a84565b8e600001548260000181815250508e600101548260200181815250508d8260400181815250508c8260600181815250508b600001548160000181815250508b600101548160200181815250508a816040018181525050898160600181815250506130208f8d61383d565b925061302c828261385e565b94506130388584612e86565b94508483039350613049858b6138f2565b809b50819650505061305b848e6138f2565b809e50819550505082851115151561306f57fe5b82841115151561307b57fe5b898d85870101018314151561308c57fe5b84848e8c985098509850985050505050509650965096509692505050565b60008060008414806130c3575060006001028360001916145b156130cd5761310e565b6130d8878787612920565b91506009600083600019166000191681526020019081526020016000209050828160000181600019169055508381600101819055505b50505050505050565b6000606060006040805190810160405280600381526020017f323132000000000000000000000000000000000000000000000000000000000081525091506040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546001600481111561319d57fe5b8c8c8c8c604051602001808a805190602001908083835b6020831015156131d957805182526020820191506020810190506020830392506131b4565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b60208310151561322c5780518252602082019150602081019050602083039250613207565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018781526020018681526020018581526020018460001916600019168152602001838152602001826000191660001916815260200199505050505050505050506040516020818303038152906040526040518082805190602001908083835b60208310151561331257805182526020820191506020810190506020830392506132ed565b6001836020036101000a0380198251168184511680821785525050505050509050019150506040518091039020905061334b8185613917565b9250505095945050505050565b60008460020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060040154831115156133af57600080fd5b828160040181905550818160030181600019169055505050505050565b6000606060006040805190810160405280600381526020017f323737000000000000000000000000000000000000000000000000000000000081525091506040805190810160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546002600481111561345257fe5b8d8d8d8d8d604051602001808b805190602001908083835b60208310151561348f578051825260208201915060208101905060208303925061346a565b6001836020036101000a0380198251168184511680821785525050505050509050018a805190602001908083835b6020831015156134e257805182526020820191506020810190506020830392506134bd565b6001836020036101000a0380198251168184511680821785525050505050509050018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166c010000000000000000000000000281526014018881526020018781526020018681526020018560001916600019168152602001848152602001836000191660001916815260200182805190602001908083835b6020831015156135aa5780518252602082019150602081019050602083039250613585565b6001836020036101000a0380198251168184511680821785525050505050509050019a50505050505050505050506040516020818303038152906040526040518082805190602001908083835b60208310151561361c57805182526020820191506020810190506020830392506135f7565b6001836020036101000a038019825116818451168082178552505050505050905001915050604051809103902090506136558185613917565b925050509695505050505050565b60008060008060008060008789511115156136875780600080905096509650613831565b87890151945060208801890151935060408801890151915084848360405160200180848152602001838152602001826000191660001916815260200193505050506040516020818303038152906040526040518082805190602001908083835b60208310151561370c57805182526020820191506020810190506020830392506136e7565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390209050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c1f62946836040518263ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808260001916600019168152602001915050602060405180830381600087803b1580156137d457600080fd5b505af11580156137e8573d6000803e3d6000fd5b505050506040513d60208110156137fe57600080fd5b8101908080519060200190929190505050925060008314806138205750828511155b1561382a57600093505b8084965096505b50505050509250929050565b60008160010154836001015483600001548560000154010303905092915050565b600080600080600061387887604001518860600151613a43565b935061388c86604001518760600151613a43565b925083831015151561389d57600080fd5b866040015184101515156138ad57fe5b856040015183101515156138bd57fe5b83830391506138d0828860000151613a43565b90506138e08188602001516138f2565b50809150508094505050505092915050565b6000808284116139075760008481915061390c565b828403835b915091509250929050565b6000806000806041855114151561392d57600080fd5b6020850151925060408501519150606085015160001a9050601b8160ff16101561395857601b810190505b601b8160ff16148061396d5750601c8160ff16145b151561397857600080fd5b600186828585604051600081526020016040526040518085600019166000191681526020018460ff1660ff1681526020018360001916600019168152602001826000191660001916815260200194505050505060206040516020810390808403906000865af11580156139ef573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614151515613a3757600080fd5b83935050505092915050565b600080828401905083811015613a79577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613a7b565b805b91505092915050565b6080604051908101604052806000815260200160008152602001600081526020016000815250905600a165627a7a7230582031e6ac55398c2f815444a8e98e33222f5641cc4acbed9b812770679645b193810029a165627a7a723058209ec12abfaaee57e6f55ba7369730721a0919118cb6458b48be444e91e6015a9f0029
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000002d07731e878e4c59bda93ea3fe93e34fb0172bd0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000879a4
-----Decoded View---------------
Arg [0] : _secret_registry_address (address): 0x2D07731E878e4C59bDA93eA3Fe93e34Fb0172Bd0
Arg [1] : _chain_id (uint256): 1
Arg [2] : _settlement_timeout_min (uint256): 500
Arg [3] : _settlement_timeout_max (uint256): 555428
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 0000000000000000000000002d07731e878e4c59bda93ea3fe93e34fb0172bd0
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [3] : 00000000000000000000000000000000000000000000000000000000000879a4
Swarm Source
bzzr://9ec12abfaaee57e6f55ba7369730721a0919118cb6458b48be444e91e6015a9f
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
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.