More Info
Private Name Tags
ContractCreator
Latest 25 from a total of 87 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Settle Channel | 10997262 | 1269 days ago | IN | 0 ETH | 0.00347179 | ||||
Update Non Closi... | 10997050 | 1269 days ago | IN | 0 ETH | 0.00942666 | ||||
Close Channel | 10996999 | 1269 days ago | IN | 0 ETH | 0.00963365 | ||||
Close Channel | 10935075 | 1279 days ago | IN | 0 ETH | 0.00486752 | ||||
Set Total Deposi... | 10653189 | 1322 days ago | IN | 0 ETH | 0.00707051 | ||||
Set Total Deposi... | 10620050 | 1327 days ago | IN | 0 ETH | 0.00461562 | ||||
Set Total Deposi... | 10608139 | 1329 days ago | IN | 0 ETH | 0.00442615 | ||||
Open Channel | 10608122 | 1329 days ago | IN | 0 ETH | 0.00539897 | ||||
Set Total Deposi... | 10576065 | 1334 days ago | IN | 0 ETH | 0.00374949 | ||||
Open Channel | 10576052 | 1334 days ago | IN | 0 ETH | 0.00563805 | ||||
Close Channel | 10562802 | 1336 days ago | IN | 0 ETH | 0.00357028 | ||||
Set Total Deposi... | 10562614 | 1336 days ago | IN | 0 ETH | 0.00457947 | ||||
Open Channel | 10562601 | 1336 days ago | IN | 0 ETH | 0.00595823 | ||||
Set Total Deposi... | 10502585 | 1346 days ago | IN | 0 ETH | 0.00773463 | ||||
Set Total Withdr... | 10431822 | 1356 days ago | IN | 0 ETH | 0.00221715 | ||||
Set Total Withdr... | 10426860 | 1357 days ago | IN | 0 ETH | 0.0006662 | ||||
Set Total Deposi... | 10407937 | 1360 days ago | IN | 0 ETH | 0.00172602 | ||||
Open Channel | 10315440 | 1375 days ago | IN | 0 ETH | 0.00379331 | ||||
Settle Channel | 10296682 | 1377 days ago | IN | 0 ETH | 0.00254535 | ||||
Update Non Closi... | 10296184 | 1377 days ago | IN | 0 ETH | 0.00357298 | ||||
Close Channel | 10296174 | 1377 days ago | IN | 0 ETH | 0.00229429 | ||||
Set Total Deposi... | 10250345 | 1385 days ago | IN | 0 ETH | 0.00329227 | ||||
Open Channel | 10250329 | 1385 days ago | IN | 0 ETH | 0.00394625 | ||||
Set Total Deposi... | 10230888 | 1388 days ago | IN | 0 ETH | 0.00272238 | ||||
Open Channel | 10230871 | 1388 days ago | IN | 0 ETH | 0.00328032 |
Latest 1 internal transaction
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
10095793 | 1409 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Contract Name:
TokenNetwork
Compiler Version
v0.6.4+commit.1dca32f3
Optimization Enabled:
No with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity)
/** *Submitted for verification at Etherscan.io on 2020-05-19 */ pragma solidity 0.6.4; library ECVerify { function ecverify(bytes32 hash, bytes memory 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 following the signature. 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; } } interface Token { /// @return supply total amount of tokens function totalSupply() external view returns (uint256 supply); /// @param _owner The address from which the balance will be retrieved /// @return balance 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 success 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 success 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 success 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 remaining 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); } /// @title Utils /// @notice Utils contract for various helpers used by the Raiden Network smart /// contracts. contract Utils { enum MessageTypeId { None, BalanceProof, BalanceProofUpdate, Withdraw, CooperativeSettle, IOU, MSReward } /// @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; } } /// @title SecretRegistry /// @notice SecretRegistry contract for registering secrets from Raiden Network /// clients. contract SecretRegistry { // sha256(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 = sha256(abi.encodePacked(secret)); if (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[] memory 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]; } } // MIT License // Copyright (c) 2018 // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. /// @title TokenNetwork /// @notice Stores and manages all the Raiden Network channels that use the /// token specified /// in this TokenNetwork contract. contract TokenNetwork is Utils { // 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 ); // The deposit limit per channel per participant. uint256 public channel_participant_deposit_limit; // The total combined deposit of all channels across the whole network uint256 public token_network_deposit_limit; // 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 // into the contract cannot be tracked and will be stuck. 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 } 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 { // keccak256 hash of the pending locks from the Raiden client bytes32 locksroot; // Total amount of tokens locked in the pending locks 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 ); // Fires when the deprecation_switch's value changes event DeprecationSwitch(bool new_value); // 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, bytes32 balance_hash ); event ChannelUnlocked( uint256 indexed channel_identifier, address indexed receiver, address indexed sender, bytes32 locksroot, uint256 unlocked_amount, uint256 returned_tokens ); event NonClosingBalanceProofUpdated( uint256 indexed channel_identifier, address indexed closing_participant, uint256 indexed nonce, bytes32 balance_hash ); event ChannelSettled( uint256 indexed channel_identifier, uint256 participant1_amount, bytes32 participant1_locksroot, uint256 participant2_amount, bytes32 participant2_locksroot ); 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); _; } /// @param _token_address The address of the ERC20 token contract /// @param _secret_registry The address of SecretRegistry contract that witnesses the onchain secret reveals /// @param _chain_id EIP-155 Chain ID of the blockchain where this instance is being deployed /// @param _settlement_timeout_min The shortest settlement period (in number of blocks) /// that can be chosen at the channel opening /// @param _settlement_timeout_max The longest settlement period (in number of blocks) /// that can be chosen at the channel opening /// @param _deprecation_executor The Ethereum address that can disable new deposits and channel creation /// @param _channel_participant_deposit_limit The maximum amount of tokens that can be deposited by each /// participant of each channel. MAX_SAFE_UINT256 means no limits /// @param _token_network_deposit_limit The maximum amount of tokens that this contract can hold /// MAX_SAFE_UINT256 means no limits constructor( address _token_address, address _secret_registry, uint256 _chain_id, uint256 _settlement_timeout_min, uint256 _settlement_timeout_max, address _deprecation_executor, uint256 _channel_participant_deposit_limit, uint256 _token_network_deposit_limit ) 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)); require(_channel_participant_deposit_limit > 0); require(_token_network_deposit_limit > 0); require(_token_network_deposit_limit >= _channel_participant_deposit_limit); 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; channel_participant_deposit_limit = _channel_participant_deposit_limit; token_network_deposit_limit = _token_network_deposit_limit; } function deprecate() public isSafe onlyDeprecationExecutor { safety_deprecation_switch = true; emit DeprecationSwitch(safety_deprecation_switch); } /// @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) public isSafe settleTimeoutValid(settle_timeout) 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 ) public isSafe isOpen(channel_identifier) { 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, uint256 expiration_block, bytes calldata participant_signature, bytes calldata partner_signature ) external isOpen(channel_identifier) { uint256 total_deposit; uint256 current_withdraw; address partner; require(total_withdraw > 0); require(block.number < expiration_block); // Authenticate both channel partners via their signatures. // `participant` is a part of the signed message, so given in the calldata. require(participant == recoverAddressFromWithdrawMessage( channel_identifier, participant, total_withdraw, expiration_block, participant_signature )); partner = recoverAddressFromWithdrawMessage( channel_identifier, participant, total_withdraw, expiration_block, 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. /// Anybody can call this function on behalf of a participant (called /// the closing participant), providing a balance proof signed by /// both parties. Callable only once /// @param channel_identifier Identifier for the channel on which this /// operation takes place /// @param closing_participant Channel participant who closes the channel /// @param non_closing_participant Channel partner of the `closing_participant`, /// who provided 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 non_closing_signature Non-closing participant's signature of the balance proof data /// @param closing_signature Closing participant's signature of the balance /// proof data function closeChannel( uint256 channel_identifier, address non_closing_participant, address closing_participant, // The next four arguments form a balance proof. bytes32 balance_hash, uint256 nonce, bytes32 additional_hash, bytes memory non_closing_signature, bytes memory closing_signature ) public isOpen(channel_identifier) { require(channel_identifier == getChannelIdentifier(closing_participant, non_closing_participant)); address recovered_non_closing_participant_address; Channel storage channel = channels[channel_identifier]; channel.state = ChannelState.Closed; channel.participants[closing_participant].is_the_closer = true; // This is the block number at which the channel can be settled. channel.settle_block_number += uint256(block.number); // The closing participant must have signed the balance proof. address recovered_closing_participant_address = recoverAddressFromBalanceProofCounterSignature( MessageTypeId.BalanceProof, channel_identifier, balance_hash, nonce, additional_hash, non_closing_signature, closing_signature ); require(closing_participant == recovered_closing_participant_address); // 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_non_closing_participant_address = recoverAddressFromBalanceProof( channel_identifier, balance_hash, nonce, additional_hash, non_closing_signature ); // Signature must be from the channel partner require(non_closing_participant == recovered_non_closing_participant_address); updateBalanceProofData( channel, recovered_non_closing_participant_address, nonce, balance_hash ); } emit ChannelClosed(channel_identifier, closing_participant, nonce, balance_hash); } /// @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, // The next four arguments form a balance proof bytes32 balance_hash, uint256 nonce, bytes32 additional_hash, bytes calldata closing_signature, bytes calldata 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); // Calling this function after the settlement window is forbidden to // fix the following race condition: // // 1 A badly configured node A, that doesn't have a monitoring service // and is temporarily offline does not call update during the // settlement window. // 2 The well behaved partner B, who called close, sees the // settlement window is over and calls settle. At this point the B's // balance proofs which should be provided by A is missing, so B will // call settle with its balance proof zeroed out. // 3 A restarts and calls update, which will change B's balance // proof. // 4 At this point, the transactions from 2 and 3 are racing, and one // of them will fail. // // To avoid the above race condition, which would require special // handling on both nodes, the call to update is forbidden after the // settlement window. This does not affect safety, since we assume the // nodes are always properly configured and have a monitoring service // available to call update on the user's behalf. 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 = recoverAddressFromBalanceProofCounterSignature( MessageTypeId.BalanceProofUpdate, 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, balance_hash ); } /// @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 hash of the /// pending hash-time locks of `participant1`, used to validate the unlocked /// proofs. If no balance_hash has been submitted, locksroot is ignored /// @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 hash of the /// pending hash-time locks of `participant2`, used to validate the unlocked /// proofs. If no balance_hash has been submitted, locksroot is ignored 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, participant1_locksroot, participant2_transferred_amount, participant2_locksroot ); // 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 `sender` to /// `receiver` and sends the locked tokens corresponding to locks with /// secrets registered on-chain to the `receiver`. Locked tokens /// corresponding to locks where the secret was not revealed on-chain will /// return to the `sender`. Anyone can call unlock. /// @param channel_identifier Identifier for the channel on which this /// operation takes place /// @param receiver Address who will receive the claimable unlocked /// tokens /// @param sender Address who sent the pending transfers and will receive /// the unclaimable unlocked tokens /// @param locks All pending locks concatenated in order of creation /// that `sender` sent to `receiver` function unlock( uint256 channel_identifier, address receiver, address sender, bytes memory locks ) public { // Channel represented by channel_identifier must be settled and // channel data deleted require(channel_identifier != getChannelIdentifier(receiver, sender)); // 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); 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) = getHashAndUnlockedAmount( locks ); // The sender 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 `sender` -> `receiver`. unlock_key = getUnlockIdentifier(channel_identifier, sender, receiver); 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 sender returned_tokens = locked_amount - unlocked_amount; // Remove sender's unlock data delete unlock_identifier_to_unlock_data[unlock_key]; emit ChannelUnlocked( channel_identifier, receiver, sender, computed_locksroot, unlocked_amount, returned_tokens ); // Transfer the unlocked tokens to the receiver. unlocked_amount can // be 0 if (unlocked_amount > 0) { require(token.transfer(receiver, unlocked_amount)); } // Transfer the rest of the tokens back to the sender if (returned_tokens > 0) { require(token.transfer(sender, 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) public view 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 /// @notice The contract cannot really distinguish Settled and Removed /// states, especially when wrong participants are given as input. /// The contract does not remember the participants of the channel function getChannelInfo( uint256 channel_identifier, address participant1, address participant2 ) external view 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 ) external view 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) public pure 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)); } } /// @dev Get the hash of the channel identifier and the participant /// addresses (whose ordering matters). The hash might be useful for /// the receiver to look up the appropriate UnlockData to claim /// @param channel_identifier Identifier for the channel which the /// UnlockData is about /// @param sender Sender of the pending transfers that the UnlockData /// represents /// @param receiver Receiver of the pending transfers that the UnlockData /// represents function getUnlockIdentifier( uint256 channel_identifier, address sender, address receiver ) public pure returns (bytes32) { require(sender != receiver); return keccak256(abi.encodePacked(channel_identifier, sender, receiver)); } 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. // This line prevents Monitoring Services from getting rewards // again and again using the same reward proof. require(nonce > participant_state.nonce); participant_state.nonce = nonce; participant_state.balance_hash = balance_hash; } function storeUnlockData( uint256 channel_identifier, address sender, address receiver, uint256 locked_amount, bytes32 locksroot ) internal { // If there are transfers to unlock, store the locksroot and total // amount of tokens if (locked_amount == 0) { return; } bytes32 key = getUnlockIdentifier(channel_identifier, sender, receiver); 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 ) internal view 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 ) private view 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 memory participant1_settlement, SettlementData memory participant2_settlement ) internal pure 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 ) internal view 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 is ignored. */ ) { 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 memory signature ) internal view 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 recoverAddressFromBalanceProofCounterSignature( MessageTypeId message_type_id, uint256 channel_identifier, bytes32 balance_hash, uint256 nonce, bytes32 additional_hash, bytes memory closing_signature, bytes memory non_closing_signature ) internal view 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(message_type_id), 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, uint256 expiration_block, bytes memory signature ) internal view returns (address signature_address) { // Length of the actual message: 20 + 32 + 32 + 32 + 20 + 32 + 32 string memory message_length = '200'; bytes32 message_hash = keccak256(abi.encodePacked( signature_prefix, message_length, address(this), chain_id, uint256(MessageTypeId.Withdraw), channel_identifier, participant, total_withdraw, expiration_block )); signature_address = ECVerify.ecverify(message_hash, signature); } /// @dev Calculates the hash of the pending transfers data and /// calculates the amount of tokens that can be unlocked because the secret /// was registered on-chain. function getHashAndUnlockedAmount(bytes memory locks) internal view returns (bytes32, uint256) { uint256 length = locks.length; // each lock 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 total_hash; for (i = 32; i < length; i += 96) { unlocked_amount = getLockedAmountFromLock(locks, i); total_unlocked_amount += unlocked_amount; } total_hash = keccak256(locks); return (total_hash, total_unlocked_amount); } function getLockedAmountFromLock(bytes memory locks, uint256 offset) internal view returns (uint256) { uint256 expiration_block; uint256 locked_amount; uint256 reveal_block; bytes32 secrethash; if (locks.length <= offset) { return 0; } assembly { expiration_block := mload(add(locks, offset)) locked_amount := mload(add(locks, add(offset, 32))) secrethash := mload(add(locks, add(offset, 64))) } // 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 locked_amount; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a > b ? b : a; } function max(uint256 a, uint256 b) internal pure 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) internal pure 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) internal pure returns (uint256) { uint256 sum = a + b; return sum >= a ? sum : MAX_SAFE_UINT256; } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_token_address","type":"address"},{"internalType":"address","name":"_secret_registry","type":"address"},{"internalType":"uint256","name":"_chain_id","type":"uint256"},{"internalType":"uint256","name":"_settlement_timeout_min","type":"uint256"},{"internalType":"uint256","name":"_settlement_timeout_max","type":"uint256"},{"internalType":"address","name":"_deprecation_executor","type":"address"},{"internalType":"uint256","name":"_channel_participant_deposit_limit","type":"uint256"},{"internalType":"uint256","name":"_token_network_deposit_limit","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"closing_participant","type":"address"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"balance_hash","type":"bytes32"}],"name":"ChannelClosed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"participant","type":"address"},{"indexed":false,"internalType":"uint256","name":"total_deposit","type":"uint256"}],"name":"ChannelNewDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"participant1","type":"address"},{"indexed":true,"internalType":"address","name":"participant2","type":"address"},{"indexed":false,"internalType":"uint256","name":"settle_timeout","type":"uint256"}],"name":"ChannelOpened","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"participant1_amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"participant1_locksroot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"participant2_amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"participant2_locksroot","type":"bytes32"}],"name":"ChannelSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"bytes32","name":"locksroot","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"unlocked_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"returned_tokens","type":"uint256"}],"name":"ChannelUnlocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"participant","type":"address"},{"indexed":false,"internalType":"uint256","name":"total_withdraw","type":"uint256"}],"name":"ChannelWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"new_value","type":"bool"}],"name":"DeprecationSwitch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"indexed":true,"internalType":"address","name":"closing_participant","type":"address"},{"indexed":true,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"balance_hash","type":"bytes32"}],"name":"NonClosingBalanceProofUpdated","type":"event"},{"inputs":[],"name":"MAX_SAFE_UINT256","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chain_id","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"channel_counter","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"channel_participant_deposit_limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"channels","outputs":[{"internalType":"uint256","name":"settle_block_number","type":"uint256"},{"internalType":"enum TokenNetwork.ChannelState","name":"state","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"non_closing_participant","type":"address"},{"internalType":"address","name":"closing_participant","type":"address"},{"internalType":"bytes32","name":"balance_hash","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"additional_hash","type":"bytes32"},{"internalType":"bytes","name":"non_closing_signature","type":"bytes"},{"internalType":"bytes","name":"closing_signature","type":"bytes"}],"name":"closeChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contract_address","type":"address"}],"name":"contractExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deprecate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deprecation_executor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"participant","type":"address"},{"internalType":"address","name":"partner","type":"address"}],"name":"getChannelIdentifier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"participant1","type":"address"},{"internalType":"address","name":"participant2","type":"address"}],"name":"getChannelInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"enum TokenNetwork.ChannelState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"participant","type":"address"},{"internalType":"address","name":"partner","type":"address"}],"name":"getChannelParticipantInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bool","name":"","type":"bool"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"participant","type":"address"},{"internalType":"address","name":"partner","type":"address"}],"name":"getParticipantsHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"receiver","type":"address"}],"name":"getUnlockIdentifier","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"participant1","type":"address"},{"internalType":"address","name":"participant2","type":"address"},{"internalType":"uint256","name":"settle_timeout","type":"uint256"}],"name":"openChannel","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"participants_hash_to_channel_identifier","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"safety_deprecation_switch","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secret_registry","outputs":[{"internalType":"contract SecretRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"participant","type":"address"},{"internalType":"uint256","name":"total_deposit","type":"uint256"},{"internalType":"address","name":"partner","type":"address"}],"name":"setTotalDeposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"participant","type":"address"},{"internalType":"uint256","name":"total_withdraw","type":"uint256"},{"internalType":"uint256","name":"expiration_block","type":"uint256"},{"internalType":"bytes","name":"participant_signature","type":"bytes"},{"internalType":"bytes","name":"partner_signature","type":"bytes"}],"name":"setTotalWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"participant1","type":"address"},{"internalType":"uint256","name":"participant1_transferred_amount","type":"uint256"},{"internalType":"uint256","name":"participant1_locked_amount","type":"uint256"},{"internalType":"bytes32","name":"participant1_locksroot","type":"bytes32"},{"internalType":"address","name":"participant2","type":"address"},{"internalType":"uint256","name":"participant2_transferred_amount","type":"uint256"},{"internalType":"uint256","name":"participant2_locked_amount","type":"uint256"},{"internalType":"bytes32","name":"participant2_locksroot","type":"bytes32"}],"name":"settleChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"settlement_timeout_max","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"settlement_timeout_min","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signature_prefix","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"contract Token","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token_network_deposit_limit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"locks","type":"bytes"}],"name":"unlock","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"channel_identifier","type":"uint256"},{"internalType":"address","name":"closing_participant","type":"address"},{"internalType":"address","name":"non_closing_participant","type":"address"},{"internalType":"bytes32","name":"balance_hash","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"additional_hash","type":"bytes32"},{"internalType":"bytes","name":"closing_signature","type":"bytes"},{"internalType":"bytes","name":"non_closing_signature","type":"bytes"}],"name":"updateNonClosingBalanceProof","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526000600860146101000a81548160ff0219169083151502179055503480156200002c57600080fd5b5060405162003da738038062003da783398181016040526101008110156200005357600080fd5b810190808051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190805190602001909291908051906020019092919080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff161415620000e557600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1614156200012057600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff1614156200015b57600080fd5b600086116200016957600080fd5b600085116200017757600080fd5b8484116200018457600080fd5b62000195886200038960201b60201c565b6200019f57600080fd5b620001b0876200038960201b60201c565b620001ba57600080fd5b60008211620001c857600080fd5b60008111620001d657600080fd5b81811015620001e457600080fd5b876000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555086600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555085600281905550846003819055508360048190555060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015620002e457600080fd5b505afa158015620002f9573d6000803e3d6000fd5b505050506040513d60208110156200031057600080fd5b8101908080519060200190929190505050116200032c57600080fd5b82600860006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550816005819055508060068190555050505050505050506200039c565b600080823b905060008111915050919050565b6139fb80620003ac6000396000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80637c4734f4116100f9578063b7506d7011610097578063ee4516d911610071578063ee4516d914610bcb578063fadc554b14610c7b578063fc0c546a14610db2578063fe49ba1c14610dfc576101c4565b8063b7506d7014610b34578063b8378f7514610b56578063e5949b5d14610b74576101c4565b806387234237116100d35780638723423714610882578063938bcd67146109055780639cadb1591461097d5780639e67ca5f14610a28576101c4565b80637c4734f4146105b857806382fd779514610630578063838d6e05146107eb576101c4565b80634845be761161016657806363ea01431161014057806363ea0143146104a8578063679b37631461052057806371e759921461053e5780637709bc781461055c576101c4565b80634845be761461042a578063524bef8a146104485780635d6e441b1461048a576101c4565b8063224df42f116101a2578063224df42f1461035a57806323aa81741461037857806324d73a93146103c25780633af973b11461040c576101c4565b806303d9d253146101c95780630a798f24146102ce5780630fcc0c2814610350575b600080fd5b6102cc600480360360808110156101df57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561024657600080fd5b82018360208201111561025857600080fd5b8035906020019184600183028401116401000000008311171561027a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610e7e565b005b61033a600480360360608110156102e457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111f4565b6040518082815260200191505060405180910390f35b610358611470565b005b610362611551565b6040518082815260200191505060405180910390f35b610380611557565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103ca61157d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104146115a3565b6040518082815260200191505060405180910390f35b6104326115a9565b6040518082815260200191505060405180910390f35b6104746004803603602081101561045e57600080fd5b81019080803590602001909291905050506115af565b6040518082815260200191505060405180910390f35b6104926115c7565b6040518082815260200191505060405180910390f35b61051e600480360360808110156104be57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115cd565b005b6105286119ca565b6040518082815260200191505060405180910390f35b6105466119d0565b6040518082815260200191505060405180910390f35b61059e6004803603602081101561057257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506119f4565b604051808215151515815260200191505060405180910390f35b61061a600480360360408110156105ce57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611a07565b6040518082815260200191505060405180910390f35b6107e9600480360361010081101561064757600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803590602001906401000000008111156106cc57600080fd5b8201836020820111156106de57600080fd5b8035906020019184600183028401116401000000008311171561070057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561076357600080fd5b82018360208201111561077557600080fd5b8035906020019184600183028401116401000000008311171561079757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611c13565b005b6108576004803603606081101561080157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e23565b6040518083815260200182600481111561086d57fe5b60ff1681526020019250505060405180910390f35b61088a611f16565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ca5780820151818401526020810190506108af565b50505050905090810190601f1680156108f75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6109676004803603604081101561091b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611f4f565b6040518082815260200191505060405180910390f35b610a26600480360361012081101561099457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050612028565b005b610b32600480360360c0811015610a3e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610a9957600080fd5b820183602082011115610aab57600080fd5b80359060200191846001830284011164010000000083111715610acd57600080fd5b909192939192939080359060200190640100000000811115610aee57600080fd5b820183602082011115610b0057600080fd5b80359060200191846001830284011164010000000083111715610b2257600080fd5b9091929391929390505050612516565b005b610b3c6128fd565b604051808215151515815260200191505060405180910390f35b610b5e612910565b6040518082815260200191505060405180910390f35b610ba060048036036020811015610b8a57600080fd5b8101908080359060200190929190505050612916565b60405180838152602001826004811115610bb657fe5b60ff1681526020019250505060405180910390f35b610c3760048036036060811015610be157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612947565b604051808881526020018781526020018615151515815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b610db06004803603610100811015610c9257600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610d1757600080fd5b820183602082011115610d2957600080fd5b80359060200191846001830284011164010000000083111715610d4b57600080fd5b909192939192939080359060200190640100000000811115610d6c57600080fd5b820183602082011115610d7e57600080fd5b80359060200191846001830284011164010000000083111715610da057600080fd5b9091929391929390505050612a1c565b005b610dba612cd6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610e6860048036036060811015610e1257600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612cfb565b6040518082815260200191505060405180910390f35b610e888383611f4f565b841415610e9457600080fd5b60006004811115610ea157fe5b6009600086815260200190815260200160002060010160009054906101000a900460ff166004811115610ed057fe5b14610eda57600080fd5b6000806000806000610eeb86612dd4565b8094508195505050610efe89888a612cfb565b94506000600b600087815260200190815260200160002090508060010154925084816000015414610f2e57600080fd5b60008311610f3b57600080fd5b610f458484612e40565b93508383039150600b6000878152602001908152602001600020600080820160009055600182016000905550508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b7f8c03cf01b3d4e6068cc494e6fe02aa9e3d4af069d37c32ecc3b241af5c37e6c088888760405180848152602001838152602001828152602001935050505060405180910390a460008411156110de576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561109957600080fd5b505af11580156110ad573d6000803e3d6000fd5b505050506040513d60208110156110c357600080fd5b81019080805190602001909291905050506110dd57600080fd5b5b60008211156111d4576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561118f57600080fd5b505af11580156111a3573d6000803e3d6000fd5b505050506040513d60208110156111b957600080fd5b81019080805190602001909291905050506111d357600080fd5b5b818310156111de57fe5b838310156111e857fe5b50505050505050505050565b6000801515600860149054906101000a900460ff1615151461121557600080fd5b8160035481101561122557600080fd5b60045481111561123457600080fd5b6000806006546000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156112d857600080fd5b505afa1580156112ec573d6000803e3d6000fd5b505050506040513d602081101561130257600080fd5b81019080805190602001909291905050501061131d57600080fd5b6001600760008282540192505081905550600754905061133d8787611a07565b91506000600a6000848152602001908152602001600020541461135f57600080fd5b80600a6000848152602001908152602001600020819055506000600960008381526020019081526020016000209050600081600001541461139c57fe5b600060048111156113a957fe5b8160010160009054906101000a900460ff1660048111156113c657fe5b146113cd57fe5b85816000018190555060018160010160006101000a81548160ff021916908360048111156113f757fe5b02179055508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16837f669a4b0ac0b9994c0f82ed4dbe07bb421fe74e5951725af4f139c7443ebf049d896040518082815260200191505060405180910390a4819450505050509392505050565b60001515600860149054906101000a900460ff1615151461149057600080fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114ea57600080fd5b6001600860146101000a81548160ff0219169083151502179055507f6151930a846a85f5e64d2dd1cc5deeafb010c63eec4b600458158edd0e33f15d600860149054906101000a900460ff16604051808215151515815260200191505060405180910390a1565b60045481565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b60065481565b600a6020528060005260406000206000915090505481565b60055481565b60001515600860149054906101000a900460ff161515146115ed57600080fd5b83600160048111156115fb57fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff16600481111561162a57fe5b1461163457600080fd5b61163e8483611f4f565b851461164957600080fd5b6000831161165657600080fd5b60055483111561166557600080fd5b600080600060096000898152602001908152602001600020905060008160020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508160000154880394506000851161171f57600080fd5b8785111561172c57600080fd5b87858360000154011461173b57fe5b600654856000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117dd57600080fd5b505afa1580156117f1573d6000803e3d6000fd5b505050506040513d602081101561180757600080fd5b810190808051906020019092919050505001111561182457600080fd5b87826000018190555080600001548260000154019350816000015484101561184b57600080fd5b8873ffffffffffffffffffffffffffffffffffffffff168a7f2b55547a3b586ab51f65ee9ce4927fa6d25191388299988e89e059a02f9dd44584600001546040518082815260200191505060405180910390a36000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561197a57600080fd5b505af115801561198e573d6000803e3d6000fd5b505050506040513d60208110156119a457600080fd5b81019080805190602001909291905050506119be57600080fd5b50505050505050505050565b60075481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600080823b905060008111915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611a4257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a7c57600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611ab557600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161015611b7d578282604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050611c0d565b8183604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012090505b92915050565b8760016004811115611c2157fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff166004811115611c5057fe5b14611c5a57600080fd5b611c648789611f4f565b8914611c6f57600080fd5b600080600960008c8152602001908152602001600020905060028160010160006101000a81548160ff02191690836004811115611ca857fe5b021790555060018160020160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160006101000a81548160ff0219169083151502179055504381600001600082825401925050819055506000611d2e60018d8b8b8b8b8b612e59565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611d6857600080fd5b6000881115611dc557611d7e8c8a8a8a8a613073565b92508273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1614611db857600080fd5b611dc482848a8c613239565b5b878a73ffffffffffffffffffffffffffffffffffffffff168d7f09d2f946e008c38931cd739dd20e35146deff8ab3134caee6d54fe50816a81b88c6040518082815260200191505060405180910390a4505050505050505050505050565b600080600080600060096000898152602001908152602001600020905060008160010160009054906101000a900460ff16905060006004811115611e6357fe5b816004811115611e6f57fe5b148015611e7c5750600089115b8015611e8a57506007548911155b15611f005760039050611e9e898989612cfb565b93506000600b60008681526020019081526020016000209050611ec28a898b612cfb565b93506000600b6000868152602001908152602001600020905060008260010154148015611ef3575060008160010154145b15611efd57600492505b50505b8160000154819550955050505050935093915050565b6040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525081565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f8a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611fc457600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611ffd57600080fd5b60006120098484611a07565b9050600a60008281526020019081526020016000205491505092915050565b6120328885611f4f565b891461203d57600080fd5b60006120498986611a07565b90506000600960008c815260200190815260200160002090506002600481111561206f57fe5b8160010160009054906101000a900460ff16600481111561208c57fe5b1461209657600080fd5b438160000154106120a657600080fd5b60008160020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061213c828c8c8c6132a7565b61214557600080fd5b612151818888886132a7565b61215a57600080fd5b612168828c8c848b8b613321565b809950819d50829a50839e50505050508260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff02191690556003820160009055600482016000905550508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff0219169055600382016000905560048201600090555050600960008e81526020019081526020016000206000808201600090556001820160006101000a81549060ff02191690555050600a6000858152602001908152602001600020600090556122be8d8d8a8d8d61342a565b6122cb8d898e898961342a565b8c7f8db0e7d323ca765ce9ab550780131837e4942ccfea3be2b635ec1084c81f72628c8b8a896040518085815260200184815260200183815260200182815260200194505050505060405180910390a260008b1115612411576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8d8d6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156123cc57600080fd5b505af11580156123e0573d6000803e3d6000fd5b505050506040513d60208110156123f657600080fd5b810190808051906020019092919050505061241057600080fd5b5b6000871115612507576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124c257600080fd5b505af11580156124d6573d6000803e3d6000fd5b505050506040513d60208110156124ec57600080fd5b810190808051906020019092919050505061250657600080fd5b5b50505050505050505050505050565b876001600481111561252457fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff16600481111561255357fe5b1461255d57600080fd5b6000806000808a1161256e57600080fd5b88431061257a57600080fd5b6125cb8c8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061347a565b73ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff161461260257600080fd5b6126538c8c8c8c8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061347a565b905061265f8b82611f4f565b8c1461266a57600080fd5b6000600960008e8152602001908152602001600020905060008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806000015482600001540195508581600101548e01111561272b57600080fd5b80600101548d018d111561273e57600080fd5b81600101548d0394508c85111561275457600080fd5b6000851161276157600080fd5b8c858360010154011461277057fe5b8d73ffffffffffffffffffffffffffffffffffffffff168f7f98ed0357b86b313fa9f968de5c9d2bcf591432355b34aa1ab7e3e9e92f4284088f6040518082815260200191505060405180910390a38c82600101819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8f876040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561287057600080fd5b505af1158015612884573d6000803e3d6000fd5b505050506040513d602081101561289a57600080fd5b81019080805190602001909291905050506128b457600080fd5b81600001548610156128c257fe5b80600001548610156128d057fe5b60008260040154146128de57fe5b60008160040154146128ec57fe5b505050505050505050505050505050565b600860149054906101000a900460ff1681565b60035481565b60096020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b6000806000806000806000806000600960008d815260200190815260200160002060020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506129b58c8c8c612cfb565b91506000600b60008481526020019081526020016000209050816000015482600101548360020160009054906101000a900460ff16846003015485600401548560000154866001015499509950995099509950995099505050509397509397509397909450565b612a268989611f4f565b8a14612a3157600080fd5b6000801b871415612a4157600080fd5b60008611612a4e57600080fd5b6000806000600960008e8152602001908152602001600020905060026004811115612a7557fe5b8160010160009054906101000a900460ff166004811115612a9257fe5b14612a9c57600080fd5b4381600001541015612aad57600080fd5b612b4560028e8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612e59565b92508273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1614612b7f57600080fd5b612bd08d8b8b8b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050613073565b91508173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff1614612c0a57600080fd5b60008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16612c6a57600080fd5b612c76828e8c8e613239565b898d73ffffffffffffffffffffffffffffffffffffffff168f7f6fc5b4f4f9e65bfdc4c45456373906876cee8832b605478e281902468875eaed8e6040518082815260200191505060405180910390a45050505050505050505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612d3657600080fd5b838383604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140193505050506040516020818303038152906040528051906020012090509392505050565b600080600083519050600060608281612de957fe5b0614612df457600080fd5b6000806000806000602094505b85851015612e2557612e13898661366f565b92508284019350606085019450612e01565b88805190602001209050808497509750505050505050915091565b6000818311612e4f5782612e51565b815b905092915050565b600060606040518060400160405280600381526020017f3237370000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002548d6006811115612ede57fe5b8d8d8d8d8d604051602001808b805190602001908083835b60208310612f195780518252602082019150602081019050602083039250612ef6565b6001836020036101000a0380198251168184511680821785525050505050509050018a805190602001908083835b60208310612f6a5780518252602082019150602081019050602083039250612f47565b6001836020036101000a0380198251168184511680821785525050505050509050018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140188815260200187815260200186815260200185815260200184815260200183815260200182805190602001908083835b602083106130145780518252602082019150602081019050602083039250612ff1565b6001836020036101000a0380198251168184511680821785525050505050509050019a5050505050505050505050604051602081830303815290604052805190602001209050613064818561377b565b92505050979650505050505050565b600060606040518060400160405280600381526020017f3231320000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152508230600254600160068111156130f957fe5b8c8c8c8c604051602001808a805190602001908083835b602083106131335780518252602082019150602081019050602083039250613110565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b602083106131845780518252602082019150602081019050602083039250613161565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401878152602001868152602001858152602001848152602001838152602001828152602001995050505050505050505060405160208183030381529060405280519060200120905061322c818561377b565b9250505095945050505050565b60008460020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060040154831161328e57600080fd5b8281600401819055508181600301819055505050505050565b60008060001b85600301541480156132bf5750600084145b80156132cb5750600083145b156132d95760019050613319565b8383836040516020018084815260200183815260200182815260200193505050506040516020818303038152906040528051906020012085600301541490505b949350505050565b600080600080600080600061333461399d565b61333c61399d565b8e600001548260000181815250508e600101548260200181815250508d8260400181815250508c8260600181815250508b600001548160000181815250508b600101548160200181815250508a816040018181525050898160600181815250506133a68f8d613888565b92506133b282826138a9565b94506133be8584612e40565b945084830393506133cf858b613937565b809b5081965050506133e1848e613937565b809e508195505050828511156133f357fe5b828411156133fd57fe5b898d8587010101831461340c57fe5b84848e8c985098509850985050505050509650965096509692505050565b600082141561343857613473565b6000613445868686612cfb565b90506000600b6000838152602001908152602001600020905082816000018190555083816001018190555050505b5050505050565b600060606040518060400160405280600381526020017f3230300000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546003600681111561350057fe5b8c8c8c8c604051602001808a805190602001908083835b6020831061353a5780518252602082019150602081019050602083039250613517565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b6020831061358b5780518252602082019150602081019050602083039250613568565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018381526020018281526020019950505050505050505050604051602081830303815290604052805190602001209050613662818561377b565b9250505095945050505050565b60008060008060008587511161368c576000945050505050613775565b858701519350602086018701519250604086018701519050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c1f62946826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561371757600080fd5b505afa15801561372b573d6000803e3d6000fd5b505050506040513d602081101561374157600080fd5b8101908080519060200190929190505050915060008214806137635750818411155b1561376d57600092505b829450505050505b92915050565b6000604182511461378b57600080fd5b60008060006020850151925060408501519150606085015160001a9050601b8160ff1610156137bb57601b810190505b601b8160ff1614806137d05750601c8160ff16145b6137d957600080fd5b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015613836573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561387c57600080fd5b83935050505092915050565b60008160010154836001015483600001548560000154010303905092915050565b60008060008060006138c38760400151886060015161395c565b93506138d78660400151876060015161395c565b9250838310156138e657600080fd5b86604001518410156138f457fe5b856040015183101561390257fe5b838303915061391582886000015161395c565b9050613925818860200151613937565b50809150508094505050505092915050565b60008082841161394c57600084819150613951565b828403835b915091509250929050565b600080828401905083811015613992577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613994565b805b91505092915050565b604051806080016040528060008152602001600081526020016000815260200160008152509056fea26469706673582212208dd315d3eefaf6a432871865941baa5fa54c8e0eaa7f48d8104ab992c364098b64736f6c63430006040033000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000070f0c29b946e63803bd0be796e17e47138668a680000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000bbf11c2f66e1887681c902095cefb1018c854c0f00000000000000000000000000000000000000000000000040fe01d848bc7ad00000000000000000000000000000000000000000000000fde03734dc203fbc80
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80637c4734f4116100f9578063b7506d7011610097578063ee4516d911610071578063ee4516d914610bcb578063fadc554b14610c7b578063fc0c546a14610db2578063fe49ba1c14610dfc576101c4565b8063b7506d7014610b34578063b8378f7514610b56578063e5949b5d14610b74576101c4565b806387234237116100d35780638723423714610882578063938bcd67146109055780639cadb1591461097d5780639e67ca5f14610a28576101c4565b80637c4734f4146105b857806382fd779514610630578063838d6e05146107eb576101c4565b80634845be761161016657806363ea01431161014057806363ea0143146104a8578063679b37631461052057806371e759921461053e5780637709bc781461055c576101c4565b80634845be761461042a578063524bef8a146104485780635d6e441b1461048a576101c4565b8063224df42f116101a2578063224df42f1461035a57806323aa81741461037857806324d73a93146103c25780633af973b11461040c576101c4565b806303d9d253146101c95780630a798f24146102ce5780630fcc0c2814610350575b600080fd5b6102cc600480360360808110156101df57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019064010000000081111561024657600080fd5b82018360208201111561025857600080fd5b8035906020019184600183028401116401000000008311171561027a57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050610e7e565b005b61033a600480360360608110156102e457600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506111f4565b6040518082815260200191505060405180910390f35b610358611470565b005b610362611551565b6040518082815260200191505060405180910390f35b610380611557565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6103ca61157d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6104146115a3565b6040518082815260200191505060405180910390f35b6104326115a9565b6040518082815260200191505060405180910390f35b6104746004803603602081101561045e57600080fd5b81019080803590602001909291905050506115af565b6040518082815260200191505060405180910390f35b6104926115c7565b6040518082815260200191505060405180910390f35b61051e600480360360808110156104be57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506115cd565b005b6105286119ca565b6040518082815260200191505060405180910390f35b6105466119d0565b6040518082815260200191505060405180910390f35b61059e6004803603602081101561057257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506119f4565b604051808215151515815260200191505060405180910390f35b61061a600480360360408110156105ce57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611a07565b6040518082815260200191505060405180910390f35b6107e9600480360361010081101561064757600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803590602001906401000000008111156106cc57600080fd5b8201836020820111156106de57600080fd5b8035906020019184600183028401116401000000008311171561070057600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192908035906020019064010000000081111561076357600080fd5b82018360208201111561077557600080fd5b8035906020019184600183028401116401000000008311171561079757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050509192919290505050611c13565b005b6108576004803603606081101561080157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611e23565b6040518083815260200182600481111561086d57fe5b60ff1681526020019250505060405180910390f35b61088a611f16565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156108ca5780820151818401526020810190506108af565b50505050905090810190601f1680156108f75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6109676004803603604081101561091b57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050611f4f565b6040518082815260200191505060405180910390f35b610a26600480360361012081101561099457600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190929190505050612028565b005b610b32600480360360c0811015610a3e57600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610a9957600080fd5b820183602082011115610aab57600080fd5b80359060200191846001830284011164010000000083111715610acd57600080fd5b909192939192939080359060200190640100000000811115610aee57600080fd5b820183602082011115610b0057600080fd5b80359060200191846001830284011164010000000083111715610b2257600080fd5b9091929391929390505050612516565b005b610b3c6128fd565b604051808215151515815260200191505060405180910390f35b610b5e612910565b6040518082815260200191505060405180910390f35b610ba060048036036020811015610b8a57600080fd5b8101908080359060200190929190505050612916565b60405180838152602001826004811115610bb657fe5b60ff1681526020019250505060405180910390f35b610c3760048036036060811015610be157600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612947565b604051808881526020018781526020018615151515815260200185815260200184815260200183815260200182815260200197505050505050505060405180910390f35b610db06004803603610100811015610c9257600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001909291908035906020019092919080359060200190640100000000811115610d1757600080fd5b820183602082011115610d2957600080fd5b80359060200191846001830284011164010000000083111715610d4b57600080fd5b909192939192939080359060200190640100000000811115610d6c57600080fd5b820183602082011115610d7e57600080fd5b80359060200191846001830284011164010000000083111715610da057600080fd5b9091929391929390505050612a1c565b005b610dba612cd6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b610e6860048036036060811015610e1257600080fd5b8101908080359060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050612cfb565b6040518082815260200191505060405180910390f35b610e888383611f4f565b841415610e9457600080fd5b60006004811115610ea157fe5b6009600086815260200190815260200160002060010160009054906101000a900460ff166004811115610ed057fe5b14610eda57600080fd5b6000806000806000610eeb86612dd4565b8094508195505050610efe89888a612cfb565b94506000600b600087815260200190815260200160002090508060010154925084816000015414610f2e57600080fd5b60008311610f3b57600080fd5b610f458484612e40565b93508383039150600b6000878152602001908152602001600020600080820160009055600182016000905550508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b7f8c03cf01b3d4e6068cc494e6fe02aa9e3d4af069d37c32ecc3b241af5c37e6c088888760405180848152602001838152602001828152602001935050505060405180910390a460008411156110de576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8a866040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561109957600080fd5b505af11580156110ad573d6000803e3d6000fd5b505050506040513d60208110156110c357600080fd5b81019080805190602001909291905050506110dd57600080fd5b5b60008211156111d4576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89846040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561118f57600080fd5b505af11580156111a3573d6000803e3d6000fd5b505050506040513d60208110156111b957600080fd5b81019080805190602001909291905050506111d357600080fd5b5b818310156111de57fe5b838310156111e857fe5b50505050505050505050565b6000801515600860149054906101000a900460ff1615151461121557600080fd5b8160035481101561122557600080fd5b60045481111561123457600080fd5b6000806006546000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156112d857600080fd5b505afa1580156112ec573d6000803e3d6000fd5b505050506040513d602081101561130257600080fd5b81019080805190602001909291905050501061131d57600080fd5b6001600760008282540192505081905550600754905061133d8787611a07565b91506000600a6000848152602001908152602001600020541461135f57600080fd5b80600a6000848152602001908152602001600020819055506000600960008381526020019081526020016000209050600081600001541461139c57fe5b600060048111156113a957fe5b8160010160009054906101000a900460ff1660048111156113c657fe5b146113cd57fe5b85816000018190555060018160010160006101000a81548160ff021916908360048111156113f757fe5b02179055508673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff16837f669a4b0ac0b9994c0f82ed4dbe07bb421fe74e5951725af4f139c7443ebf049d896040518082815260200191505060405180910390a4819450505050509392505050565b60001515600860149054906101000a900460ff1615151461149057600080fd5b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16146114ea57600080fd5b6001600860146101000a81548160ff0219169083151502179055507f6151930a846a85f5e64d2dd1cc5deeafb010c63eec4b600458158edd0e33f15d600860149054906101000a900460ff16604051808215151515815260200191505060405180910390a1565b60045481565b600860009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60025481565b60065481565b600a6020528060005260406000206000915090505481565b60055481565b60001515600860149054906101000a900460ff161515146115ed57600080fd5b83600160048111156115fb57fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff16600481111561162a57fe5b1461163457600080fd5b61163e8483611f4f565b851461164957600080fd5b6000831161165657600080fd5b60055483111561166557600080fd5b600080600060096000898152602001908152602001600020905060008160020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508160000154880394506000851161171f57600080fd5b8785111561172c57600080fd5b87858360000154011461173b57fe5b600654856000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166370a08231306040518263ffffffff1660e01b8152600401808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060206040518083038186803b1580156117dd57600080fd5b505afa1580156117f1573d6000803e3d6000fd5b505050506040513d602081101561180757600080fd5b810190808051906020019092919050505001111561182457600080fd5b87826000018190555080600001548260000154019350816000015484101561184b57600080fd5b8873ffffffffffffffffffffffffffffffffffffffff168a7f2b55547a3b586ab51f65ee9ce4927fa6d25191388299988e89e059a02f9dd44584600001546040518082815260200191505060405180910390a36000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166323b872dd3330886040518463ffffffff1660e01b8152600401808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019350505050602060405180830381600087803b15801561197a57600080fd5b505af115801561198e573d6000803e3d6000fd5b505050506040513d60208110156119a457600080fd5b81019080805190602001909291905050506119be57600080fd5b50505050505050505050565b60075481565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81565b600080823b905060008111915050919050565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611a4257600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611a7c57600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611ab557600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161015611b7d578282604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140192505050604051602081830303815290604052805190602001209050611c0d565b8183604051602001808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401925050506040516020818303038152906040528051906020012090505b92915050565b8760016004811115611c2157fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff166004811115611c5057fe5b14611c5a57600080fd5b611c648789611f4f565b8914611c6f57600080fd5b600080600960008c8152602001908152602001600020905060028160010160006101000a81548160ff02191690836004811115611ca857fe5b021790555060018160020160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060020160006101000a81548160ff0219169083151502179055504381600001600082825401925050819055506000611d2e60018d8b8b8b8b8b612e59565b90508073ffffffffffffffffffffffffffffffffffffffff168a73ffffffffffffffffffffffffffffffffffffffff1614611d6857600080fd5b6000881115611dc557611d7e8c8a8a8a8a613073565b92508273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1614611db857600080fd5b611dc482848a8c613239565b5b878a73ffffffffffffffffffffffffffffffffffffffff168d7f09d2f946e008c38931cd739dd20e35146deff8ab3134caee6d54fe50816a81b88c6040518082815260200191505060405180910390a4505050505050505050505050565b600080600080600060096000898152602001908152602001600020905060008160010160009054906101000a900460ff16905060006004811115611e6357fe5b816004811115611e6f57fe5b148015611e7c5750600089115b8015611e8a57506007548911155b15611f005760039050611e9e898989612cfb565b93506000600b60008681526020019081526020016000209050611ec28a898b612cfb565b93506000600b6000868152602001908152602001600020905060008260010154148015611ef3575060008160010154145b15611efd57600492505b50505b8160000154819550955050505050935093915050565b6040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525081565b60008073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611f8a57600080fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415611fc457600080fd5b8173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415611ffd57600080fd5b60006120098484611a07565b9050600a60008281526020019081526020016000205491505092915050565b6120328885611f4f565b891461203d57600080fd5b60006120498986611a07565b90506000600960008c815260200190815260200160002090506002600481111561206f57fe5b8160010160009054906101000a900460ff16600481111561208c57fe5b1461209657600080fd5b438160000154106120a657600080fd5b60008160020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905061213c828c8c8c6132a7565b61214557600080fd5b612151818888886132a7565b61215a57600080fd5b612168828c8c848b8b613321565b809950819d50829a50839e50505050508260020160008d73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff02191690556003820160009055600482016000905550508260020160008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008082016000905560018201600090556002820160006101000a81549060ff0219169055600382016000905560048201600090555050600960008e81526020019081526020016000206000808201600090556001820160006101000a81549060ff02191690555050600a6000858152602001908152602001600020600090556122be8d8d8a8d8d61342a565b6122cb8d898e898961342a565b8c7f8db0e7d323ca765ce9ab550780131837e4942ccfea3be2b635ec1084c81f72628c8b8a896040518085815260200184815260200183815260200182815260200194505050505060405180910390a260008b1115612411576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8d8d6040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156123cc57600080fd5b505af11580156123e0573d6000803e3d6000fd5b505050506040513d60208110156123f657600080fd5b810190808051906020019092919050505061241057600080fd5b5b6000871115612507576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb89896040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b1580156124c257600080fd5b505af11580156124d6573d6000803e3d6000fd5b505050506040513d60208110156124ec57600080fd5b810190808051906020019092919050505061250657600080fd5b5b50505050505050505050505050565b876001600481111561252457fe5b6009600083815260200190815260200160002060010160009054906101000a900460ff16600481111561255357fe5b1461255d57600080fd5b6000806000808a1161256e57600080fd5b88431061257a57600080fd5b6125cb8c8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061347a565b73ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff161461260257600080fd5b6126538c8c8c8c8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505061347a565b905061265f8b82611f4f565b8c1461266a57600080fd5b6000600960008e8152602001908152602001600020905060008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020905060008260020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000209050806000015482600001540195508581600101548e01111561272b57600080fd5b80600101548d018d111561273e57600080fd5b81600101548d0394508c85111561275457600080fd5b6000851161276157600080fd5b8c858360010154011461277057fe5b8d73ffffffffffffffffffffffffffffffffffffffff168f7f98ed0357b86b313fa9f968de5c9d2bcf591432355b34aa1ab7e3e9e92f4284088f6040518082815260200191505060405180910390a38c82600101819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663a9059cbb8f876040518363ffffffff1660e01b8152600401808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200182815260200192505050602060405180830381600087803b15801561287057600080fd5b505af1158015612884573d6000803e3d6000fd5b505050506040513d602081101561289a57600080fd5b81019080805190602001909291905050506128b457600080fd5b81600001548610156128c257fe5b80600001548610156128d057fe5b60008260040154146128de57fe5b60008160040154146128ec57fe5b505050505050505050505050505050565b600860149054906101000a900460ff1681565b60035481565b60096020528060005260406000206000915090508060000154908060010160009054906101000a900460ff16905082565b6000806000806000806000806000600960008d815260200190815260200160002060020160008c73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090506129b58c8c8c612cfb565b91506000600b60008481526020019081526020016000209050816000015482600101548360020160009054906101000a900460ff16846003015485600401548560000154866001015499509950995099509950995099505050509397509397509397909450565b612a268989611f4f565b8a14612a3157600080fd5b6000801b871415612a4157600080fd5b60008611612a4e57600080fd5b6000806000600960008e8152602001908152602001600020905060026004811115612a7557fe5b8160010160009054906101000a900460ff166004811115612a9257fe5b14612a9c57600080fd5b4381600001541015612aad57600080fd5b612b4560028e8c8c8c8c8c8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f820116905080830192505050505050508b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050612e59565b92508273ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff1614612b7f57600080fd5b612bd08d8b8b8b8b8b8080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050613073565b91508173ffffffffffffffffffffffffffffffffffffffff168c73ffffffffffffffffffffffffffffffffffffffff1614612c0a57600080fd5b60008160020160008e73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060020160009054906101000a900460ff16612c6a57600080fd5b612c76828e8c8e613239565b898d73ffffffffffffffffffffffffffffffffffffffff168f7f6fc5b4f4f9e65bfdc4c45456373906876cee8832b605478e281902468875eaed8e6040518082815260200191505060405180910390a45050505050505050505050505050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415612d3657600080fd5b838383604051602001808481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140193505050506040516020818303038152906040528051906020012090509392505050565b600080600083519050600060608281612de957fe5b0614612df457600080fd5b6000806000806000602094505b85851015612e2557612e13898661366f565b92508284019350606085019450612e01565b88805190602001209050808497509750505050505050915091565b6000818311612e4f5782612e51565b815b905092915050565b600060606040518060400160405280600381526020017f3237370000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002548d6006811115612ede57fe5b8d8d8d8d8d604051602001808b805190602001908083835b60208310612f195780518252602082019150602081019050602083039250612ef6565b6001836020036101000a0380198251168184511680821785525050505050509050018a805190602001908083835b60208310612f6a5780518252602082019150602081019050602083039250612f47565b6001836020036101000a0380198251168184511680821785525050505050509050018973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b815260140188815260200187815260200186815260200185815260200184815260200183815260200182805190602001908083835b602083106130145780518252602082019150602081019050602083039250612ff1565b6001836020036101000a0380198251168184511680821785525050505050509050019a5050505050505050505050604051602081830303815290604052805190602001209050613064818561377b565b92505050979650505050505050565b600060606040518060400160405280600381526020017f3231320000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a0000000000008152508230600254600160068111156130f957fe5b8c8c8c8c604051602001808a805190602001908083835b602083106131335780518252602082019150602081019050602083039250613110565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b602083106131845780518252602082019150602081019050602083039250613161565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b8152601401878152602001868152602001858152602001848152602001838152602001828152602001995050505050505050505060405160208183030381529060405280519060200120905061322c818561377b565b9250505095945050505050565b60008460020160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002090508060040154831161328e57600080fd5b8281600401819055508181600301819055505050505050565b60008060001b85600301541480156132bf5750600084145b80156132cb5750600083145b156132d95760019050613319565b8383836040516020018084815260200183815260200182815260200193505050506040516020818303038152906040528051906020012085600301541490505b949350505050565b600080600080600080600061333461399d565b61333c61399d565b8e600001548260000181815250508e600101548260200181815250508d8260400181815250508c8260600181815250508b600001548160000181815250508b600101548160200181815250508a816040018181525050898160600181815250506133a68f8d613888565b92506133b282826138a9565b94506133be8584612e40565b945084830393506133cf858b613937565b809b5081965050506133e1848e613937565b809e508195505050828511156133f357fe5b828411156133fd57fe5b898d8587010101831461340c57fe5b84848e8c985098509850985050505050509650965096509692505050565b600082141561343857613473565b6000613445868686612cfb565b90506000600b6000838152602001908152602001600020905082816000018190555083816001018190555050505b5050505050565b600060606040518060400160405280600381526020017f3230300000000000000000000000000000000000000000000000000000000000815250905060006040518060400160405280601a81526020017f19457468657265756d205369676e6564204d6573736167653a0a00000000000081525082306002546003600681111561350057fe5b8c8c8c8c604051602001808a805190602001908083835b6020831061353a5780518252602082019150602081019050602083039250613517565b6001836020036101000a03801982511681845116808217855250505050505090500189805190602001908083835b6020831061358b5780518252602082019150602081019050602083039250613568565b6001836020036101000a0380198251168184511680821785525050505050509050018873ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018781526020018681526020018581526020018473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1660601b81526014018381526020018281526020019950505050505050505050604051602081830303815290604052805190602001209050613662818561377b565b9250505095945050505050565b60008060008060008587511161368c576000945050505050613775565b858701519350602086018701519250604086018701519050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663c1f62946826040518263ffffffff1660e01b81526004018082815260200191505060206040518083038186803b15801561371757600080fd5b505afa15801561372b573d6000803e3d6000fd5b505050506040513d602081101561374157600080fd5b8101908080519060200190929190505050915060008214806137635750818411155b1561376d57600092505b829450505050505b92915050565b6000604182511461378b57600080fd5b60008060006020850151925060408501519150606085015160001a9050601b8160ff1610156137bb57601b810190505b601b8160ff1614806137d05750601c8160ff16145b6137d957600080fd5b60018682858560405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015613836573d6000803e3d6000fd5b505050602060405103519350600073ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16141561387c57600080fd5b83935050505092915050565b60008160010154836001015483600001548560000154010303905092915050565b60008060008060006138c38760400151886060015161395c565b93506138d78660400151876060015161395c565b9250838310156138e657600080fd5b86604001518410156138f457fe5b856040015183101561390257fe5b838303915061391582886000015161395c565b9050613925818860200151613937565b50809150508094505050505092915050565b60008082841161394c57600084819150613951565b828403835b915091509250929050565b600080828401905083811015613992577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff613994565b805b91505092915050565b604051806080016040528060008152602001600081526020016000815260200160008152509056fea26469706673582212208dd315d3eefaf6a432871865941baa5fa54c8e0eaa7f48d8104ab992c364098b64736f6c63430006040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000070f0c29b946e63803bd0be796e17e47138668a680000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006400000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000bbf11c2f66e1887681c902095cefb1018c854c0f00000000000000000000000000000000000000000000000040fe01d848bc7ad00000000000000000000000000000000000000000000000fde03734dc203fbc80
-----Decoded View---------------
Arg [0] : _token_address (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _secret_registry (address): 0x70f0c29b946E63803BD0Be796E17E47138668A68
Arg [2] : _chain_id (uint256): 1
Arg [3] : _settlement_timeout_min (uint256): 100
Arg [4] : _settlement_timeout_max (uint256): 500
Arg [5] : _deprecation_executor (address): 0xbBF11c2f66E1887681C902095CEfB1018C854c0f
Arg [6] : _channel_participant_deposit_limit (uint256): 4683182690956770000
Arg [7] : _token_network_deposit_limit (uint256): 4683182690956770000000
-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 00000000000000000000000070f0c29b946e63803bd0be796e17e47138668a68
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [4] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [5] : 000000000000000000000000bbf11c2f66e1887681c902095cefb1018c854c0f
Arg [6] : 00000000000000000000000000000000000000000000000040fe01d848bc7ad0
Arg [7] : 0000000000000000000000000000000000000000000000fde03734dc203fbc80
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 24 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
ETH | 100.00% | $3,574.76 | 0.1363 | $487.17 |
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.