ETH Price: $2,183.80 (+4.56%)
Gas: 0.05 Gwei

Contract

0x7917b6f2C5deC4021Ed5D0ff3e5bb27A69B2eaCf
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Method Block
From
To
-114575242020-12-15 12:09:501916 days ago1608034190  Contract Creation0 ETH
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NitroAdjudicator

Compiler Version
v0.7.4+commit.3f05b770

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

import './interfaces/IAdjudicator.sol';
import './ForceMove.sol';
import './Outcome.sol';
import './AssetHolder.sol';

/**
 * @dev The NitroAdjudicator contract extends ForceMove and hence inherits all ForceMove methods, and also extends and implements the Adjudicator interface, allowing for a finalized outcome to be pushed to an asset holder.
 */
contract NitroAdjudicator is IAdjudicator, ForceMove {
    /**
     * @notice Allows a finalized channel's outcome to be decoded and one or more AssetOutcomes registered in external Asset Holder contracts.
     * @dev Allows a finalized channel's outcome to be decoded and one or more AssetOutcomes registered in external Asset Holder contracts.
     * @param channelId Unique identifier for a state channel
     * @param turnNumRecord A turnNum that (the adjudicator knows and stores) is supported by a signature from each participant.
     * @param finalizesAt The unix timestamp when this channel will finalize
     * @param stateHash The keccak256 of the abi.encode of the State (struct) stored by the adjudicator
     * @param challengerAddress The address of the participant whom registered the challenge, if any.
     * @param outcomeBytes The encoded Outcome of this state channel.
     */
    function pushOutcome(
        bytes32 channelId,
        uint48 turnNumRecord,
        uint48 finalizesAt,
        bytes32 stateHash,
        address challengerAddress,
        bytes memory outcomeBytes
    ) public override {
        // requirements
        _requireChannelFinalized(channelId);

        bytes32 outcomeHash = keccak256(outcomeBytes);

        _requireMatchingStorage(
            ChannelData(turnNumRecord, finalizesAt, stateHash, challengerAddress, outcomeHash),
            channelId
        );

        Outcome.OutcomeItem[] memory outcome = abi.decode(outcomeBytes, (Outcome.OutcomeItem[]));

        for (uint256 i = 0; i < outcome.length; i++) {
            AssetHolder(outcome[i].assetHolderAddress).setAssetOutcomeHash(
                channelId,
                keccak256(outcome[i].assetOutcomeBytes)
            );
        }
    }

    /**
     * @notice Allows a finalized channel's outcome to be decoded and transferAll to be triggered in external Asset Holder contracts.
     * @dev Allows a finalized channel's outcome to be decoded and one or more AssetOutcomes registered in external Asset Holder contracts.
     * @param channelId Unique identifier for a state channel
     * @param turnNumRecord A turnNum that (the adjudicator knows and stores) is supported by a signature from each participant.
     * @param finalizesAt The unix timestamp when this channel will finalize
     * @param stateHash The keccak256 of the abi.encode of the State (struct) stored by the adjudicator
     * @param challengerAddress The address of the participant whom registered the challenge, if any.
     * @param outcomeBytes The encoded Outcome of this state channel.
     */
    function pushOutcomeAndTransferAll(
        bytes32 channelId,
        uint48 turnNumRecord,
        uint48 finalizesAt,
        bytes32 stateHash,
        address challengerAddress,
        bytes memory outcomeBytes
    ) public {
        // requirements
        _requireChannelFinalized(channelId);

        bytes32 outcomeHash = keccak256(outcomeBytes);

        _requireMatchingStorage(
            ChannelData(turnNumRecord, finalizesAt, stateHash, challengerAddress, outcomeHash),
            channelId
        );

        _transferAllFromAllAssetHolders(channelId, outcomeBytes);
    }

    /**
     * @notice Finalizes a channel by providing a finalization proof, allows a finalized channel's outcome to be decoded and transferAll to be triggered in external Asset Holder contracts.
     * @dev Finalizes a channel by providing a finalization proof, allows a finalized channel's outcome to be decoded and transferAll to be triggered in external Asset Holder contracts.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param appPartHash The keccak256 of the abi.encode of `(challengeDuration, appDefinition, appData)`. Applies to all states in the finalization proof.
     * @param outcomeBytes abi.encode of an array of Outcome.OutcomeItem structs.
     * @param numStates The number of states in the finalization proof.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     */
    function concludePushOutcomeAndTransferAll(
        uint48 largestTurnNum,
        FixedPart memory fixedPart,
        bytes32 appPartHash,
        bytes memory outcomeBytes,
        uint8 numStates,
        uint8[] memory whoSignedWhat,
        Signature[] memory sigs
    ) public {
        bytes32 outcomeHash = keccak256(outcomeBytes);
        bytes32 channelId = _conclude(
            largestTurnNum,
            fixedPart,
            appPartHash,
            outcomeHash,
            numStates,
            whoSignedWhat,
            sigs
        );
        _transferAllFromAllAssetHolders(channelId, outcomeBytes);
    }

    /**
     * @notice Triggers transferAll in all external Asset Holder contracts specified in a given outcome for a given channelId.
     * @dev Triggers transferAll in  all external Asset Holder contracts specified in a given outcome for a given channelId.
     * @param channelId Unique identifier for a state channel
     * @param outcomeBytes abi.encode of an array of Outcome.OutcomeItem structs.
     */
    function _transferAllFromAllAssetHolders(bytes32 channelId, bytes memory outcomeBytes)
        internal
    {
        Outcome.OutcomeItem[] memory outcome = abi.decode(outcomeBytes, (Outcome.OutcomeItem[]));

        for (uint256 i = 0; i < outcome.length; i++) {
            Outcome.AssetOutcome memory assetOutcome = abi.decode(
                outcome[i].assetOutcomeBytes,
                (Outcome.AssetOutcome)
            );
            if (assetOutcome.assetOutcomeType == uint8(Outcome.AssetOutcomeType.Allocation)) {
                AssetHolder(outcome[i].assetHolderAddress).transferAllAdjudicatorOnly(
                    channelId,
                    assetOutcome.allocationOrGuaranteeBytes
                );
            } else {
                revert('_transferAllFromAllAssetHolders: AssetOutcomeType is not an allocation');
            }
        }
    }

    /**
    * @notice Check that the submitted pair of states form a valid transition (public wrapper for internal function _requireValidTransition)
    * @dev Check that the submitted pair of states form a valid transition (public wrapper for internal function _requireValidTransition)
    * @param nParticipants Number of participants in the channel.
    transition
    * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final.
    * @param ab Variable parts of each of the pair of states
    * @param turnNumB turnNum of the later state of the pair.
    * @param appDefinition Address of deployed contract containing application-specific validTransition function.
    * @return true if the later state is a validTransition from its predecessor, reverts otherwise.
    */
    function validTransition(
        uint256 nParticipants,
        bool[2] memory isFinalAB, // [a.isFinal, b.isFinal]
        IForceMoveApp.VariablePart[2] memory ab, // [a,b]
        uint48 turnNumB,
        address appDefinition
    ) public pure returns (bool) {
        return _requireValidTransition(nParticipants, isFinalAB, ab, turnNumB, appDefinition);
    }
}

File 2 of 9 : IAdjudicator.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

/**
 * @dev The IAdjudicator Interface calls for a method that allows a finalized outcome to be pushed to an asset holder.
 */
interface IAdjudicator {
    /**
     * @notice Allows a finalized channel's outcome to be decoded and one or more AssetOutcomes registered in external Asset Holder contracts.
     * @dev Allows a finalized channel's outcome to be decoded and one or more AssetOutcomes registered in external Asset Holder contracts.
     * @param channelId Unique identifier for a state channel
     * @param turnNumRecord A turnNum that (the adjudicator knows and stores) is supported by a signature from each participant.
     * @param finalizesAt The unix timestamp when this channel will finalize
     * @param stateHash The keccak256 of the abi.encode of the State (struct) stored by the adjudicator
     * @param challengerAddress The address of the participant whom registered the challenge, if any.
     * @param outcomeBytes The encoded Outcome of this state channel.
     */
    function pushOutcome(
        bytes32 channelId,
        uint48 turnNumRecord,
        uint48 finalizesAt,
        bytes32 stateHash,
        address challengerAddress,
        bytes calldata outcomeBytes
    ) external;
}

File 3 of 9 : ForceMove.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

import './interfaces/IForceMove.sol';
import './interfaces/IForceMoveApp.sol';

/**
 * @dev An implementation of ForceMove protocol, which allows state channels to be adjudicated and finalized.
 */
contract ForceMove is IForceMove {
    mapping(bytes32 => bytes32) public channelStorageHashes;

    // Public methods:

    /**
     * @notice Unpacks turnNumRecord, finalizesAt and fingerprint from the channelStorageHash of a particular channel.
     * @dev Unpacks turnNumRecord, finalizesAt and fingerprint from the channelStorageHash of a particular channel.
     * @param channelId Unique identifier for a state channel.
     * @return turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant.
     * @return finalizesAt The unix timestamp when `channelId` will finalize.
     * @return fingerprint Unique identifier for the channel's current state, up to hash collisions.
     */
    function getChannelStorage(bytes32 channelId)
        external
        view
        returns (
            uint48 turnNumRecord,
            uint48 finalizesAt,
            uint160 fingerprint
        )
    {
        (turnNumRecord, finalizesAt, fingerprint) = _getChannelStorage(channelId);
    }

    /**
     * @notice Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time.
     * @dev Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update. Length is from 1 to the number of participants (inclusive).
     * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`. There must be one for each participant, e.g.: [sig-from-p0, sig-from-p1, ...]
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param challengerSig The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove').
     */
    function challenge(
        FixedPart memory fixedPart,
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] memory variableParts,
        uint8 isFinalCount, // how many of the states are final
        Signature[] memory sigs,
        uint8[] memory whoSignedWhat,
        Signature memory challengerSig
    ) external override {
        // input type validation
        requireValidInput(
            fixedPart.participants.length,
            variableParts.length,
            sigs.length,
            whoSignedWhat.length
        );

        bytes32 channelId = _getChannelId(fixedPart);

        if (_mode(channelId) == ChannelMode.Open) {
            _requireNonDecreasedTurnNumber(channelId, largestTurnNum);
        } else if (_mode(channelId) == ChannelMode.Challenge) {
            _requireIncreasedTurnNumber(channelId, largestTurnNum);
        } else {
            // This should revert.
            _requireChannelNotFinalized(channelId);
        }
        bytes32 supportedStateHash = _requireStateSupportedBy(
            largestTurnNum,
            variableParts,
            isFinalCount,
            channelId,
            fixedPart,
            sigs,
            whoSignedWhat
        );

        address challenger = _requireChallengerIsParticipant(
            supportedStateHash,
            fixedPart.participants,
            challengerSig
        );

        // effects

        emit ChallengeRegistered(
            channelId,
            largestTurnNum,
            uint48(block.timestamp) + fixedPart.challengeDuration, //solhint-disable-line not-rely-on-time
            // This could overflow, so don't join a channel with a huge challengeDuration
            challenger,
            isFinalCount > 0,
            fixedPart,
            variableParts,
            sigs,
            whoSignedWhat
        );

        channelStorageHashes[channelId] = _hashChannelData(
            ChannelData(
                largestTurnNum,
                uint48(block.timestamp) + fixedPart.challengeDuration, //solhint-disable-line not-rely-on-time
                supportedStateHash,
                challenger,
                keccak256(variableParts[variableParts.length - 1].outcome)
            )
        );
    }

    /**
     * @notice Repsonds to an ongoing challenge registered against a state channel.
     * @dev Repsonds to an ongoing challenge registered against a state channel.
     * @param challenger The address of the participant whom registered the challenge.
     * @param isFinalAB An pair of booleans describing if the challenge state and/or the response state have the `isFinal` property set to `true`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param variablePartAB An pair of structs, each decribing the properties of the state channel that may change with each state update (for the challenge state and for the response state).
     * @param sig The responder's signature on the `responseStateHash`.
     */
    function respond(
        address challenger,
        bool[2] memory isFinalAB,
        FixedPart memory fixedPart,
        IForceMoveApp.VariablePart[2] memory variablePartAB,
        // variablePartAB[0] = challengeVariablePart
        // variablePartAB[1] = responseVariablePart
        Signature memory sig
    ) external override {
        // No need to validate fixedPart.participants.length here, as that validation would have happened during challenge

        bytes32 channelId = _getChannelId(fixedPart);
        (uint48 turnNumRecord, uint48 finalizesAt, ) = _getChannelStorage(channelId);

        bytes32 challengeOutcomeHash = keccak256(variablePartAB[0].outcome);
        bytes32 responseOutcomeHash = keccak256(variablePartAB[1].outcome);
        bytes32 challengeStateHash = _hashState(
            turnNumRecord,
            isFinalAB[0],
            channelId,
            fixedPart,
            variablePartAB[0].appData,
            challengeOutcomeHash
        );

        bytes32 responseStateHash = _hashState(
            turnNumRecord + 1,
            isFinalAB[1],
            channelId,
            fixedPart,
            variablePartAB[1].appData,
            responseOutcomeHash
        );

        // checks

        _requireSpecificChallenge(
            ChannelData(
                turnNumRecord,
                finalizesAt,
                challengeStateHash,
                challenger,
                challengeOutcomeHash
            ),
            channelId
        );

        require(
            _recoverSigner(responseStateHash, sig) ==
                fixedPart.participants[(turnNumRecord + 1) % fixedPart.participants.length],
            'Response not signed by authorized mover'
        );

        _requireValidTransition(
            fixedPart.participants.length,
            isFinalAB,
            variablePartAB,
            turnNumRecord + 1,
            fixedPart.appDefinition
        );

        // effects
        _clearChallenge(channelId, turnNumRecord + 1);
    }

    /**
     * @notice Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant.
     * @dev Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update.
     * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     */
    function checkpoint(
        FixedPart memory fixedPart,
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] memory variableParts,
        uint8 isFinalCount, // how many of the states are final
        Signature[] memory sigs,
        uint8[] memory whoSignedWhat
    ) external override {
        // input type validation
        requireValidInput(
            fixedPart.participants.length,
            variableParts.length,
            sigs.length,
            whoSignedWhat.length
        );

        bytes32 channelId = _getChannelId(fixedPart);

        // checks
        _requireChannelNotFinalized(channelId);
        _requireIncreasedTurnNumber(channelId, largestTurnNum);
        _requireStateSupportedBy(
            largestTurnNum,
            variableParts,
            isFinalCount,
            channelId,
            fixedPart,
            sigs,
            whoSignedWhat
        );

        // effects
        _clearChallenge(channelId, largestTurnNum);
    }

    /**
     * @notice Finalizes a channel by providing a finalization proof. External wrapper for _conclude.
     * @dev Finalizes a channel by providing a finalization proof. External wrapper for _conclude.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param appPartHash The keccak256 of the abi.encode of `(challengeDuration, appDefinition, appData)`. Applies to all states in the finalization proof.
     * @param outcomeHash The keccak256 of the abi.encode of the `outcome`. Applies to all states in the finalization proof.
     * @param numStates The number of states in the finalization proof.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     */
    function conclude(
        uint48 largestTurnNum,
        FixedPart memory fixedPart,
        bytes32 appPartHash,
        bytes32 outcomeHash,
        uint8 numStates,
        uint8[] memory whoSignedWhat,
        Signature[] memory sigs
    ) external override {
        _conclude(
            largestTurnNum,
            fixedPart,
            appPartHash,
            outcomeHash,
            numStates,
            whoSignedWhat,
            sigs
        );
    }

    /**
     * @notice Finalizes a channel by providing a finalization proof. Internal method.
     * @dev Finalizes a channel by providing a finalization proof. Internal method.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param appPartHash The keccak256 of the abi.encode of `(challengeDuration, appDefinition, appData)`. Applies to all states in the finalization proof.
     * @param outcomeHash The keccak256 of the `outcome`. Applies to all stats in the finalization proof.
     * @param numStates The number of states in the finalization proof.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     */
    function _conclude(
        uint48 largestTurnNum,
        FixedPart memory fixedPart,
        bytes32 appPartHash,
        bytes32 outcomeHash,
        uint8 numStates,
        uint8[] memory whoSignedWhat,
        Signature[] memory sigs
    ) internal returns (bytes32 channelId) {
        channelId = _getChannelId(fixedPart);
        _requireChannelNotFinalized(channelId);

        // input type validation
        requireValidInput(
            fixedPart.participants.length,
            numStates,
            sigs.length,
            whoSignedWhat.length
        );

        require(
            largestTurnNum + 1 >= numStates,
            'largestTurnNum + 1 must be greater than or equal to numStates'
        );
        // ^^ SW-C101: prevent underflow

        channelId = _getChannelId(fixedPart);
        _requireChannelNotFinalized(channelId);

        // By construction, the following states form a valid transition
        bytes32[] memory stateHashes = new bytes32[](numStates);
        for (uint48 i = 0; i < numStates; i++) {
            stateHashes[i] = keccak256(
                abi.encode(
                    State(
                        largestTurnNum + (i + 1) - numStates, // turnNum
                        // ^^ SW-C101: It is not easy to use SafeMath here, since we are not using uint256s
                        // Instead, we are protected by the require statement above
                        true, // isFinal
                        channelId,
                        appPartHash,
                        outcomeHash
                    )
                )
            );
        }

        // checks
        require(
            _validSignatures(
                largestTurnNum,
                fixedPart.participants,
                stateHashes,
                sigs,
                whoSignedWhat
            ),
            'Invalid signatures OR isFinal=true expected'
        );

        // effects
        channelStorageHashes[channelId] = _hashChannelData(
            ChannelData(0, uint48(block.timestamp), bytes32(0), address(0), outcomeHash) //solhint-disable-line not-rely-on-time
        );
        emit Concluded(channelId, uint48(block.timestamp)); //solhint-disable-line not-rely-on-time
    }

    // Internal methods:

    /**
     * @notice Checks that the challengerSignature was created by one of the supplied participants.
     * @dev Checks that the challengerSignature was created by one of the supplied participants.
     * @param supportedStateHash Forms part of the digest to be signed, along with the string 'forceMove'.
     * @param participants A list of addresses representing the participants of a channel.
     * @param challengerSignature The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove').
     */
    function _requireChallengerIsParticipant(
        bytes32 supportedStateHash,
        address[] memory participants,
        Signature memory challengerSignature
    ) internal pure returns (address challenger) {
        challenger = _recoverSigner(
            keccak256(abi.encode(supportedStateHash, 'forceMove')),
            challengerSignature
        );
        require(_isAddressInArray(challenger, participants), 'Challenger is not a participant');
    }

    /**
     * @notice Tests whether a given address is in a given array of addresses.
     * @dev Tests whether a given address is in a given array of addresses.
     * @param suspect A single address of interest.
     * @param addresses A line-up of possible perpetrators.
     * @return true if the address is in the array, false otherwise
     */
    function _isAddressInArray(address suspect, address[] memory addresses)
        internal
        pure
        returns (bool)
    {
        for (uint256 i = 0; i < addresses.length; i++) {
            if (suspect == addresses[i]) {
                return true;
            }
        }
        return false;
    }

    /**
     * @notice Given an array of state hashes, checks the validity of the supplied signatures. Valid means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array.
     * @dev Given an array of state hashes, checks the validity of the supplied signatures. Valid means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param participants A list of addresses representing the participants of a channel.
     * @param stateHashes Array of keccak256(State) submitted in support of a state,
     * @param sigs Array of Signatures, one for each participant
     * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]]
     * @return true if the signatures are valid, false otherwise
     */
    function _validSignatures(
        uint48 largestTurnNum,
        address[] memory participants,
        bytes32[] memory stateHashes,
        Signature[] memory sigs,
        uint8[] memory whoSignedWhat // whoSignedWhat[i] is the index of the state in stateHashes that was signed by participants[i]
    ) internal pure returns (bool) {
        uint256 nParticipants = participants.length;
        uint256 nStates = stateHashes.length;

        require(
            _acceptableWhoSignedWhat(whoSignedWhat, largestTurnNum, nParticipants, nStates),
            'Unacceptable whoSignedWhat array'
        );
        for (uint256 i = 0; i < nParticipants; i++) {
            address signer = _recoverSigner(stateHashes[whoSignedWhat[i]], sigs[i]);
            if (signer != participants[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * @notice Given a declaration of which state in the support proof was signed by which participant, check if this declaration is acceptable. Acceptable means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array.
     * @dev Given a declaration of which state in the support proof was signed by which participant, check if this declaration is acceptable. Acceptable means there is a signature for each participant, either on the hash of the state for which they are a mover, or on the hash of a state that appears after that state in the array.
     * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]]
     * @param largestTurnNum Largest turnNum of the support proof
     * @param nParticipants Number of participants in the channel
     * @param nStates Number of states in the support proof
     * @return true if whoSignedWhat is acceptable, false otherwise
     */
    function _acceptableWhoSignedWhat(
        uint8[] memory whoSignedWhat,
        uint48 largestTurnNum,
        uint256 nParticipants,
        uint256 nStates
    ) internal pure returns (bool) {
        require(
            whoSignedWhat.length == nParticipants,
            '_validSignatures: whoSignedWhat must be the same length as participants'
        );
        for (uint256 i = 0; i < nParticipants; i++) {
            uint256 offset = (nParticipants + largestTurnNum - i) % nParticipants;
            // offset is the difference between the index of participant[i] and the index of the participant who owns the largesTurnNum state
            // the additional nParticipants in the dividend ensures offset always positive
            if (whoSignedWhat[i] + offset + 1 < nStates) {
                return false;
            }
        }
        return true;
    }

    /**
     * @notice Given a digest and ethereum digital signature, recover the signer
     * @dev Given a digest and digital signature, recover the signer
     * @param _d message digest
     * @param sig ethereum digital signature
     * @return signer
     */
    function _recoverSigner(bytes32 _d, Signature memory sig) internal pure returns (address) {
        bytes32 prefixedHash = keccak256(abi.encodePacked('\x19Ethereum Signed Message:\n32', _d));
        address a = ecrecover(prefixedHash, sig.v, sig.r, sig.s);
        require(a != address(0), 'Invalid signature');
        return (a);
    }

    /**
     * @notice Check that the submitted data constitute a support proof.
     * @dev Check that the submitted data constitute a support proof.
     * @param largestTurnNum Largest turnNum of the support proof
     * @param variableParts Variable parts of the states in the support proof
     * @param isFinalCount How many of the states are final? The final isFinalCount states are implied final, the remainder are implied not final.
     * @param channelId Unique identifier for a channel.
     * @param fixedPart Fixed Part of the states in the support proof
     * @param sigs A signature from each participant.
     * @param whoSignedWhat participant[i] signed stateHashes[whoSignedWhat[i]]
     * @return The hash of the latest state in the proof, if supported, else reverts.
     */
    function _requireStateSupportedBy(
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] memory variableParts,
        uint8 isFinalCount,
        bytes32 channelId,
        FixedPart memory fixedPart,
        Signature[] memory sigs,
        uint8[] memory whoSignedWhat
    ) internal pure returns (bytes32) {
        bytes32[] memory stateHashes = _requireValidTransitionChain(
            largestTurnNum,
            variableParts,
            isFinalCount,
            channelId,
            fixedPart
        );

        require(
            _validSignatures(
                largestTurnNum,
                fixedPart.participants,
                stateHashes,
                sigs,
                whoSignedWhat
            ),
            'Invalid signatures'
        );

        return stateHashes[stateHashes.length - 1];
    }

    /**
     * @notice Check that the submitted states form a chain of valid transitions
     * @dev Check that the submitted states form a chain of valid transitions
     * @param largestTurnNum Largest turnNum of the support proof
     * @param variableParts Variable parts of the states in the support proof
     * @param isFinalCount How many of the states are final? The final isFinalCount states are implied final, the remainder are implied not final.
     * @param channelId Unique identifier for a channel.
     * @param fixedPart Fixed Part of the states in the support proof
     * @return true if every state is a validTransition from its predecessor, false otherwise.
     */
    function _requireValidTransitionChain(
        // returns stateHashes array if valid
        // else, reverts
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] memory variableParts,
        uint8 isFinalCount,
        bytes32 channelId,
        FixedPart memory fixedPart
    ) internal pure returns (bytes32[] memory) {
        bytes32[] memory stateHashes = new bytes32[](variableParts.length);
        uint48 firstFinalTurnNum = largestTurnNum - isFinalCount + 1;
        uint48 turnNum;

        for (uint48 i = 0; i < variableParts.length; i++) {
            turnNum = largestTurnNum - uint48(variableParts.length) + 1 + i;
            stateHashes[i] = _hashState(
                turnNum,
                turnNum >= firstFinalTurnNum,
                channelId,
                fixedPart,
                variableParts[i].appData,
                keccak256(variableParts[i].outcome)
            );
            if (turnNum < largestTurnNum) {
                _requireValidTransition(
                    fixedPart.participants.length,
                    [turnNum >= firstFinalTurnNum, turnNum + 1 >= firstFinalTurnNum],
                    [variableParts[i], variableParts[i + 1]],
                    turnNum + 1,
                    fixedPart.appDefinition
                );
            }
        }
        return stateHashes;
    }

    enum IsValidTransition {True, NeedToCheckApp}

    /**
    * @notice Check that the submitted pair of states form a valid transition
    * @dev Check that the submitted pair of states form a valid transition
    * @param nParticipants Number of participants in the channel.
    transition
    * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final.
    * @param ab Variable parts of each of the pair of states
    * @param turnNumB turnNum of the later state of the pair
    * @return true if the later state is a validTransition from its predecessor, false otherwise.
    */
    function _requireValidProtocolTransition(
        uint256 nParticipants,
        bool[2] memory isFinalAB, // [a.isFinal, b.isFinal]
        IForceMoveApp.VariablePart[2] memory ab, // [a,b]
        uint48 turnNumB
    ) internal pure returns (IsValidTransition) {
        // a separate check on the signatures for the submitted states implies that the following fields are equal for a and b:
        // chainId, participants, channelNonce, appDefinition, challengeDuration
        // and that the b.turnNum = a.turnNum + 1
        if (isFinalAB[1]) {
            require(
                _bytesEqual(ab[1].outcome, ab[0].outcome),
                'InvalidTransitionError: Cannot move to a final state with a different default outcome'
            );
        } else {
            require(
                !isFinalAB[0],
                'InvalidTransitionError: Cannot move from a final state to a non final state'
            );
            if (turnNumB < 2 * nParticipants) {
                require(
                    _bytesEqual(ab[1].outcome, ab[0].outcome),
                    'InvalidTransitionError: Cannot change the default outcome during setup phase'
                );
                require(
                    _bytesEqual(ab[1].appData, ab[0].appData),
                    'InvalidTransitionError: Cannot change the appData during setup phase'
                );
            } else {
                return IsValidTransition.NeedToCheckApp;
            }
        }
        return IsValidTransition.True;
    }

    /**
    * @notice Check that the submitted pair of states form a valid transition
    * @dev Check that the submitted pair of states form a valid transition
    * @param nParticipants Number of participants in the channel.
    transition
    * @param isFinalAB Pair of booleans denoting whether the first and second state (resp.) are final.
    * @param ab Variable parts of each of the pair of states
    * @param turnNumB turnNum of the later state of the pair.
    * @param appDefinition Address of deployed contract containing application-specific validTransition function.
    * @return true if the later state is a validTransition from its predecessor, false otherwise.
    */
    function _requireValidTransition(
        uint256 nParticipants,
        bool[2] memory isFinalAB, // [a.isFinal, b.isFinal]
        IForceMoveApp.VariablePart[2] memory ab, // [a,b]
        uint48 turnNumB,
        address appDefinition
    ) internal pure returns (bool) {
        IsValidTransition isValidProtocolTransition = _requireValidProtocolTransition(
            nParticipants,
            isFinalAB, // [a.isFinal, b.isFinal]
            ab, // [a,b]
            turnNumB
        );

        if (isValidProtocolTransition == IsValidTransition.NeedToCheckApp) {
            require(
                IForceMoveApp(appDefinition).validTransition(ab[0], ab[1], turnNumB, nParticipants),
                'Invalid ForceMoveApp Transition'
            );
        }

        return true;
    }

    /**
     * @notice Check for equality of two byte strings
     * @dev Check for equality of two byte strings
     * @param _preBytes One bytes string
     * @param _postBytes The other bytes string
     * @return true if the bytes are identical, false otherwise.
     */
    function _bytesEqual(bytes memory _preBytes, bytes memory _postBytes)
        internal
        pure
        returns (bool)
    {
        // copied from https://www.npmjs.com/package/solidity-bytes-utils/v/0.1.1
        bool success = true;

        /* solhint-disable no-inline-assembly */
        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
                case 1 {
                    // cb is a circuit breaker in the for loop since there's
                    //  no said feature for inline assembly loops
                    // cb = 1 - don't breaker
                    // cb = 0 - break
                    let cb := 1

                    let mc := add(_preBytes, 0x20)
                    let end := add(mc, length)

                    for {
                        let cc := add(_postBytes, 0x20)
                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                    } eq(add(lt(mc, end), cb), 2) {
                        mc := add(mc, 0x20)
                        cc := add(cc, 0x20)
                    } {
                        // if any of these checks fails then arrays are not equal
                        if iszero(eq(mload(mc), mload(cc))) {
                            // unsuccess:
                            success := 0
                            cb := 0
                        }
                    }
                }
                default {
                    // unsuccess:
                    success := 0
                }
        }
        /* solhint-disable no-inline-assembly */

        return success;
    }

    /**
     * @notice Clears a challenge by updating the turnNumRecord and resetting the remaining channel storage fields, and emits a ChallengeCleared event.
     * @dev Clears a challenge by updating the turnNumRecord and resetting the remaining channel storage fields, and emits a ChallengeCleared event.
     * @param channelId Unique identifier for a channel.
     * @param newTurnNumRecord New turnNumRecord to overwrite existing value
     */
    function _clearChallenge(bytes32 channelId, uint48 newTurnNumRecord) internal {
        channelStorageHashes[channelId] = _hashChannelData(
            ChannelData(newTurnNumRecord, 0, bytes32(0), address(0), bytes32(0))
        );
        emit ChallengeCleared(channelId, newTurnNumRecord);
    }

    /**
     * @notice Checks that the submitted turnNumRecord is strictly greater than the turnNumRecord stored on chain.
     * @dev Checks that the submitted turnNumRecord is strictly greater than the turnNumRecord stored on chain.
     * @param channelId Unique identifier for a channel.
     * @param newTurnNumRecord New turnNumRecord intended to overwrite existing value
     */
    function _requireIncreasedTurnNumber(bytes32 channelId, uint48 newTurnNumRecord) internal view {
        (uint48 turnNumRecord, , ) = _getChannelStorage(channelId);
        require(newTurnNumRecord > turnNumRecord, 'turnNumRecord not increased.');
    }

    /**
     * @notice Checks that the submitted turnNumRecord is greater than or equal to the turnNumRecord stored on chain.
     * @dev Checks that the submitted turnNumRecord is greater than or equal to the turnNumRecord stored on chain.
     * @param channelId Unique identifier for a channel.
     * @param newTurnNumRecord New turnNumRecord intended to overwrite existing value
     */
    function _requireNonDecreasedTurnNumber(bytes32 channelId, uint48 newTurnNumRecord)
        internal
        view
    {
        (uint48 turnNumRecord, , ) = _getChannelStorage(channelId);
        require(newTurnNumRecord >= turnNumRecord, 'turnNumRecord decreased.');
    }

    /**
     * @notice Checks that a given ChannelData struct matches the challenge stored on chain, and that the channel is in Challenge mode.
     * @dev Checks that a given ChannelData struct matches the challenge stored on chain, and that the channel is in Challenge mode.
     * @param data A given ChannelData data structure.
     * @param channelId Unique identifier for a channel.
     */
    function _requireSpecificChallenge(ChannelData memory data, bytes32 channelId) internal view {
        _requireMatchingStorage(data, channelId);
        _requireOngoingChallenge(channelId);
    }

    /**
     * @notice Checks that a given channel is in the Challenge mode.
     * @dev Checks that a given channel is in the Challenge mode.
     * @param channelId Unique identifier for a channel.
     */
    function _requireOngoingChallenge(bytes32 channelId) internal view {
        require(_mode(channelId) == ChannelMode.Challenge, 'No ongoing challenge.');
    }

    /**
     * @notice Checks that a given channel is NOT in the Finalized mode.
     * @dev Checks that a given channel is in the Challenge mode.
     * @param channelId Unique identifier for a channel.
     */
    function _requireChannelNotFinalized(bytes32 channelId) internal view {
        require(_mode(channelId) != ChannelMode.Finalized, 'Channel finalized.');
    }

    /**
     * @notice Checks that a given channel is in the Finalized mode.
     * @dev Checks that a given channel is in the Challenge mode.
     * @param channelId Unique identifier for a channel.
     */
    function _requireChannelFinalized(bytes32 channelId) internal view {
        require(_mode(channelId) == ChannelMode.Finalized, 'Channel not finalized.');
    }

    /**
     * @notice Checks that a given channel is in the Open mode.
     * @dev Checks that a given channel is in the Challenge mode.
     * @param channelId Unique identifier for a channel.
     */
    function _requireChannelOpen(bytes32 channelId) internal view {
        require(_mode(channelId) == ChannelMode.Open, 'Channel not open.');
    }

    /**
     * @notice Checks that a given ChannelData struct matches the challenge stored on chain.
     * @dev Checks that a given ChannelData struct matches the challenge stored on chain.
     * @param data A given ChannelData data structure.
     * @param channelId Unique identifier for a channel.
     */
    function _requireMatchingStorage(ChannelData memory data, bytes32 channelId) internal view {
        require(
            _matchesHash(data, channelStorageHashes[channelId]),
            'Channel storage does not match stored version.'
        );
    }

    /**
     * @notice Computes the ChannelMode for a given channelId.
     * @dev Computes the ChannelMode for a given channelId.
     * @param channelId Unique identifier for a channel.
     */
    function _mode(bytes32 channelId) internal view returns (ChannelMode) {
        // Note that _getChannelStorage(someRandomChannelId) returns (0,0,0), which is
        // correct when nobody has written to storage yet.

        (, uint48 finalizesAt, ) = _getChannelStorage(channelId);
        if (finalizesAt == 0) {
            return ChannelMode.Open;
            // solhint-disable-next-line not-rely-on-time
        } else if (finalizesAt <= block.timestamp) {
            return ChannelMode.Finalized;
        } else {
            return ChannelMode.Challenge;
        }
    }

    /**
     * @notice Hashes the input data and formats it for on chain storage.
     * @dev Hashes the input data and formats it for on chain storage.
     * @param channelData ChannelData data.
     */
    function _hashChannelData(ChannelData memory channelData)
        internal
        pure
        returns (bytes32 newHash)
    {
        // The hash is constructed from left to right.
        uint256 result;
        uint16 cursor = 256;

        // Shift turnNumRecord 208 bits left to fill the first 48 bits
        result = uint256(channelData.turnNumRecord) << (cursor -= 48);

        // logical or with finalizesAt padded with 160 zeros to get the next 48 bits
        result |= (uint256(channelData.finalizesAt) << (cursor -= 48));

        // logical or with the last 160 bits of the hash of the encoded storage
        result |= uint256(uint160(uint256(keccak256(abi.encode(channelData)))));

        newHash = bytes32(result);
    }

    /**
     * @notice Unpacks turnNumRecord, finalizesAt and fingerprint from the channelStorageHash of a particular channel.
     * @dev Unpacks turnNumRecord, finalizesAt and fingerprint from the channelStorageHash of a particular channel.
     * @param channelId Unique identifier for a state channel.
     * @return turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant.
     * @return finalizesAt The unix timestamp when `channelId` will finalize.
     * @return fingerprint Unique identifier for the channel's current state, up to hash collisions.
     */
    function _getChannelStorage(bytes32 channelId)
        internal
        view
        returns (
            uint48 turnNumRecord,
            uint48 finalizesAt,
            uint160 fingerprint
        )
    {
        bytes32 storageHash = channelStorageHashes[channelId];
        uint16 cursor = 256;
        turnNumRecord = uint48(uint256(storageHash) >> (cursor -= 48));
        finalizesAt = uint48(uint256(storageHash) >> (cursor -= 48));
        fingerprint = uint160(uint256(storageHash));
    }

    /**
     * @notice Checks that a given ChannelData struct matches a supplied bytes32 when formatted for storage.
     * @dev Checks that a given ChannelData struct matches a supplied bytes32 when formatted for storage.
     * @param data A given ChannelData data structure.
     * @param h Some data in on-chain storage format.
     */
    function _matchesHash(ChannelData memory data, bytes32 h) internal pure returns (bool) {
        return _hashChannelData(data) == h;
    }

    /**
     * @notice Computes the hash of the state corresponding to the input data.
     * @dev Computes the hash of the state corresponding to the input data.
     * @param turnNum Turn number
     * @param isFinal Is the state final?
     * @param channelId Unique identifier for the channel
     * @param fixedPart Part of the state that does not change
     * @param appData Application specific date
     * @param outcomeHash Hash of the outcome.
     * @return The stateHash
     */
    function _hashState(
        uint48 turnNum,
        bool isFinal,
        bytes32 channelId,
        FixedPart memory fixedPart,
        bytes memory appData,
        bytes32 outcomeHash
    ) internal pure returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    State(
                        turnNum,
                        isFinal,
                        channelId,
                        keccak256(
                            abi.encode(
                                fixedPart.challengeDuration,
                                fixedPart.appDefinition,
                                appData
                            )
                        ),
                        outcomeHash
                    )
                )
            );
    }

    function getChainID() public pure returns (uint256) {
        uint256 id;
        /* solhint-disable no-inline-assembly */
        assembly {
            id := chainid()
        }
        /* solhint-disable no-inline-assembly */
        return id;
    }

    /**
     * @notice Computes the unique id of a channel.
     * @dev Computes the unique id of a channel.
     * @param fixedPart Part of the state that does not change
     * @return channelId
     */
    function _getChannelId(FixedPart memory fixedPart) internal pure returns (bytes32 channelId) {
        require(fixedPart.chainId == getChainID(), 'Incorrect chainId');
        channelId = keccak256(
            abi.encode(getChainID(), fixedPart.participants, fixedPart.channelNonce)
        );
    }

    /**
     * @notice Validates input for several external methods.
     * @dev Validates input for several external methods.
     * @param numParticipants Length of the participants array
     * @param numStates Number of states submitted
     * @param numSigs Number of signatures submitted
     * @param numWhoSignedWhats whoSignedWhat.length
     */
    function requireValidInput(
        uint256 numParticipants,
        uint256 numStates,
        uint256 numSigs,
        uint256 numWhoSignedWhats
    ) public pure returns (bool) {
        require(
            (numParticipants >= numStates) && (numStates > 0),
            'ForceMove | You must submit at least one but no more than numParticipants states'
        );
        require(
            (numSigs == numParticipants) && (numWhoSignedWhats == numParticipants),
            'ForceMove | Require exactly 1 signature per participant & who signed what for all participants'
        );
        require(numParticipants < type(uint8).max, 'ForceMove | Too many participants!');
        return true;
    }
}

File 4 of 9 : Outcome.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

library Outcome {
    //An outcome is an array of OutcomeItems
    // Outcome = OutcomeItem[]
    // OutcomeItem = (AssetHolderAddress, AssetOutcome)
    // AssetOutcome = (AssetOutcomeType, Allocation | Guarantee)
    // Allocation = AllocationItem[]
    // AllocationItem = (Destination, Amount)
    // Guarantee = (ChannelAddress, Destination[])
    // Destination = ChannelAddress | ExternalDestination

    struct OutcomeItem {
        address assetHolderAddress;
        bytes assetOutcomeBytes; // abi.encode(AssetOutcome)
    }

    enum AssetOutcomeType {Allocation, Guarantee}

    struct AssetOutcome {
        uint8 assetOutcomeType; // AssetOutcomeType.Allocation or AssetOutcomeType.Guarantee
        bytes allocationOrGuaranteeBytes; // abi.encode(AllocationItem[]) or abi.encode(Guarantee), depending on OutcomeType
    }

    // reserve Allocation to refer to AllocationItem[]
    struct AllocationItem {
        bytes32 destination;
        uint256 amount;
    }

    struct Guarantee {
        bytes32 targetChannelId;
        bytes32[] destinations;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;
import './Outcome.sol';
import '@openzeppelin/contracts/math/SafeMath.sol';
import './interfaces/IAssetHolder.sol';

/**
 * @dev An implementation of the IAssetHolder interface. The AssetHolder contract escrows ETH or tokens against state channels. It allows assets to be internally accounted for, and ultimately prepared for transfer from one channel to other channel and/or external destinations, as well as for guarantees to be claimed. Note there is no deposit function and the _transferAsset function is unimplemented; inheriting contracts should implement these functions in a manner appropriate to the asset type (e.g. ETH or ERC20 tokens).
 */
contract AssetHolder is IAssetHolder {
    using SafeMath for uint256;

    address public AdjudicatorAddress;

    mapping(bytes32 => uint256) public holdings;

    mapping(bytes32 => bytes32) public assetOutcomeHashes;

    // **************
    // External methods
    // **************

    /**
     * @notice Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries.
     * @dev Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries.
     * @param fromChannelId Unique identifier for state channel to transfer funds *from*.
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation
     * @param indices Array with each entry denoting the index of a destination to transfer funds to.
     */
    function transfer(
        bytes32 fromChannelId,
        bytes calldata allocationBytes,
        uint256[] memory indices
    ) external override {
        // checks
        _requireIncreasingIndices(indices);
        _requireCorrectAllocationHash(fromChannelId, allocationBytes);
        // effects and interactions
        _transfer(fromChannelId, allocationBytes, indices);
    }

    /**
     * @notice Transfers the funds escrowed against `channelId` to the beneficiaries of that channel. Checks against the storage in this contract.
     * @dev Transfers the funds escrowed against `channelId` and transfers them to the beneficiaries of that channel. Checks against the storage in this contract.
     * @param channelId Unique identifier for a state channel.
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation
     */
    function transferAll(bytes32 channelId, bytes calldata allocationBytes) external {
        // checks
        _requireCorrectAllocationHash(channelId, allocationBytes);
        // effects and interactions
        _transfer(channelId, allocationBytes, new uint256[](0));
    }

    /**
     * @notice Transfers as many funds escrowed against `guarantorChannelId` as can be afforded for a specific destination in the beneficiaries of the __target__ of that channel. Checks against the storage in this contract.
     * @dev Transfers as many funds escrowed against `guarantorChannelId` as can be afforded for a specific destination in the beneficiaries of the __target__ of that channel. Checks against the storage in this contract.
     * @param guarantorChannelId Unique identifier for a guarantor state channel.
     * @param guaranteeBytes The abi.encode of Outcome.Guarantee
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation for the __target__
     * @param destination External destination or channel to transfer funds *to*.
     */
    function claim(
        bytes32 guarantorChannelId,
        bytes calldata guaranteeBytes,
        bytes calldata allocationBytes,
        bytes32 destination
    ) external {
        // checks
        _requireCorrectGuaranteeHash(guarantorChannelId, guaranteeBytes);
        Outcome.Guarantee memory guarantee = abi.decode(guaranteeBytes, (Outcome.Guarantee));
        _requireCorrectAllocationHash(guarantee.targetChannelId, allocationBytes);
        // effects and interactions
        _claim(guarantorChannelId, guarantee, allocationBytes, destination);
    }

    /**
     * @notice Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel. Checks against the storage in this contract.
     * @dev Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel. Checks against the storage in this contract.
     * @param guarantorChannelId Unique identifier for a guarantor state channel.
     * @param guaranteeBytes The abi.encode of Outcome.Guarantee
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation for the __target__
     */
    function claimAll(
        bytes32 guarantorChannelId,
        bytes calldata guaranteeBytes,
        bytes calldata allocationBytes
    ) external override {
        // checks
        _requireCorrectGuaranteeHash(guarantorChannelId, guaranteeBytes);
        Outcome.Guarantee memory guarantee = abi.decode(guaranteeBytes, (Outcome.Guarantee));
        _requireCorrectAllocationHash(guarantee.targetChannelId, allocationBytes);
        // effects and interactions
        _claimAll(guarantorChannelId, guarantee, allocationBytes);
    }

    // **************
    // Permissioned methods
    // **************

    modifier AdjudicatorOnly {
        require(msg.sender == AdjudicatorAddress, 'Only NitroAdjudicator authorized');
        _;
    }

    /**
     * @notice Transfers the funds escrowed against `channelId` to the beneficiaries of that channel. No checks performed against storage in this contract. Permissioned.
     * @dev Transfers the funds escrowed against `channelId` and transfers them to the beneficiaries of that channel. No checks performed against storage in this contract. Permissioned.
     * @param channelId Unique identifier for a state channel.
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation
     */
    function transferAllAdjudicatorOnly(bytes32 channelId, bytes calldata allocationBytes)
        external
        virtual
        AdjudicatorOnly
    {
        // no checks
        //
        // effects and interactions
        _transfer(channelId, allocationBytes, new uint256[](0));
    }

    /**
     * @notice Sets the given assetOutcomeHash for the given channelId in the assetOutcomeHashes storage mapping.
     * @dev Sets the given assetOutcomeHash for the given channelId in the assetOutcomeHashes storage mapping.
     * @param channelId Unique identifier for a state channel.
     * @param assetOutcomeHash The keccak256 of the abi.encode of the Outcome.
     */
    function setAssetOutcomeHash(bytes32 channelId, bytes32 assetOutcomeHash)
        external
        AdjudicatorOnly
    {
        _setAssetOutcomeHash(channelId, assetOutcomeHash);
    }

    // **************
    // Internal methods
    // **************

    function _computeNewAllocation(
        uint256 initialHoldings,
        Outcome.AllocationItem[] memory allocation,
        uint256[] memory indices
    )
        internal
        pure
        returns (
            Outcome.AllocationItem[] memory newAllocation,
            bool safeToDelete,
            uint256[] memory payouts,
            uint256 totalPayouts
        )
    {
        // `indices == []` means "pay out to all"
        // Note: by initializing payouts to be an array of fixed length, its entries are initialized to be `0`
        payouts = new uint256[](indices.length > 0 ? indices.length : allocation.length);
        totalPayouts = 0;
        newAllocation = new Outcome.AllocationItem[](allocation.length);
        safeToDelete = true; // switched to false if there is an item remaining with amount > 0
        uint256 surplus = initialHoldings; // virtual funds available during calculation
        uint256 k = 0; // indexes the `indices` array

        // loop over allocations and decrease surplus
        for (uint256 i = 0; i < allocation.length; i++) {
            // copy destination part
            newAllocation[i].destination = allocation[i].destination;
            // compute new amount part
            uint256 affordsForDestination = min(allocation[i].amount, surplus);
            if ((indices.length == 0) || ((k < indices.length) && (indices[k] == i))) {
                // found a match
                // reduce the current allocationItem.amount
                newAllocation[i].amount = allocation[i].amount - affordsForDestination;
                // increase the relevant payout
                payouts[k] = affordsForDestination;
                totalPayouts += affordsForDestination;
                // move on to the next supplied index
                ++k;
            } else {
                newAllocation[i].amount = allocation[i].amount;
            }
            if (newAllocation[i].amount != 0) safeToDelete = false;
            // decrease surplus by the current amount if possible, else surplus goes to zero
            surplus -= affordsForDestination;
        }
    }

    /**
     * @notice Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. Does not check allocationBytes against on chain storage.
     * @dev Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries. Does not check allocationBytes against on chain storage.
     * @param fromChannelId Unique identifier for state channel to transfer funds *from*.
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation
     * @param indices Array with each entry denoting the index of a destination to transfer funds to. Should be in increasing order.
     */
    function _transfer(
        bytes32 fromChannelId,
        bytes memory allocationBytes,
        uint256[] memory indices
    ) internal {
        Outcome.AllocationItem[] memory allocation = abi.decode(
            allocationBytes,
            (Outcome.AllocationItem[])
        );
        uint256 initialHoldings = holdings[fromChannelId];

        (
            Outcome.AllocationItem[] memory newAllocation,
            bool safeToDelete,
            uint256[] memory payouts,
            uint256 totalPayouts
        ) = _computeNewAllocation(initialHoldings, allocation, indices);

        // *******
        // EFFECTS
        // *******

        holdings[fromChannelId] = initialHoldings.sub(totalPayouts); // expect gas rebate if this is set to 0

        if (safeToDelete) {
            delete assetOutcomeHashes[fromChannelId];
        } else {
            assetOutcomeHashes[fromChannelId] = keccak256(
                abi.encode(
                    Outcome.AssetOutcome(
                        uint8(Outcome.AssetOutcomeType.Allocation),
                        abi.encode(newAllocation)
                    )
                )
            );
        }

        // *******
        // INTERACTIONS
        // *******

        for (uint256 j = 0; j < payouts.length; j++) {
            if (payouts[j] > 0) {
                bytes32 destination = allocation[indices.length > 0 ? indices[j] : j].destination;
                // storage updated BEFORE external contracts called (prevent reentrancy attacks)
                if (_isExternalDestination(destination)) {
                    _transferAsset(_bytes32ToAddress(destination), payouts[j]);
                } else {
                    holdings[destination] += payouts[j];
                }
                // Event emitted
                emit AssetTransferred(fromChannelId, destination, payouts[j]);
            }
        }
    }

    /**
     * @notice Transfers as many funds escrowed against `guarantorChannelId` as can be afforded for a specific destination in the beneficiaries of the __target__ of that channel.  Does not check allocationBytes or guarantee against on chain storage.
     * @dev Transfers as many funds escrowed against `guarantorChannelId` as can be afforded for a specific destination in the beneficiaries of the __target__ of that channel.  Does not check allocationBytes or guarantee against on chain storage.
     * @param guarantorChannelId Unique identifier for a guarantor state channel.
     * @param guarantee The guarantee
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation for the __target__
     * @param destination External destination or channel to transfer funds *to*.
     */
    function _claim(
        bytes32 guarantorChannelId,
        Outcome.Guarantee memory guarantee,
        bytes memory allocationBytes,
        bytes32 destination
    ) internal {
        Outcome.AllocationItem[] memory allocation = abi.decode(
            allocationBytes,
            (Outcome.AllocationItem[])
        );
        uint256 balance = holdings[guarantorChannelId];
        uint256 affordsForDestination;
        uint256 residualAllocationAmount;
        uint256 i; // indexes target allocations

        for (uint256 j = 0; j < guarantee.destinations.length; j++) {
            if (balance == 0) {
                revert('_claim : guarantorChannel affords 0 for destination');
            }
            // for each destination in the guarantee,
            // find the first corresponding allocationItem in the target allocation
            bytes32 guaranteeDestination = guarantee.destinations[j];
            for (i = 0; i < allocation.length; i++) {
                if (allocation[i].destination == guaranteeDestination) {
                    // decrease balance
                    uint256 _amount = allocation[i].amount;
                    if (balance < _amount) {
                        if (guaranteeDestination == destination) {
                            affordsForDestination = balance;
                            residualAllocationAmount = _amount - balance;
                            break;
                            // i will point to index that should be modified or removed in the target outcome
                        }
                        balance = 0; // this isn't used after we break
                    } else {
                        if (guaranteeDestination == destination) {
                            affordsForDestination = _amount;
                            residualAllocationAmount = 0;
                            break;
                            // i will point to index that should be modified or removed in the target outcome
                        }
                        balance = balance.sub(_amount); // this isn't used after we break
                    }
                    break;
                }
            }
            if (affordsForDestination > 0) {
                // stop lopping as soon as we found the destination in both outcomes such that we can pay something out
                break;
            }
        }

        require(affordsForDestination > 0, '_claim | guarantor affords 0 for destination');

        // effects
        holdings[guarantorChannelId] -= affordsForDestination;

        // construct new outcome for target
        if (residualAllocationAmount > 0) {
            // new allocation identical save for a single entry
            Outcome.AllocationItem[] memory newAllocation = new Outcome.AllocationItem[](
                allocation.length
            );
            for (uint256 k = 0; k < allocation.length; k++) {
                newAllocation[k] = allocation[k];
                if (k == i) {
                    newAllocation[k].amount = residualAllocationAmount;
                    break;
                }
            }
            assetOutcomeHashes[guarantee.targetChannelId] = keccak256(
                abi.encode(
                    Outcome.AssetOutcome(
                        uint8(Outcome.AssetOutcomeType.Allocation),
                        abi.encode(newAllocation)
                    )
                )
            );
        }

        if (residualAllocationAmount == 0) {
            // We want to splice a shorter outcome
            if (allocation.length == 1) {
                // special case there are no allocations left in the target's outcome
                delete assetOutcomeHashes[guarantee.targetChannelId];
                delete assetOutcomeHashes[guarantorChannelId];
            } else {
                Outcome.AllocationItem[] memory splicedAllocation = new Outcome.AllocationItem[](
                    allocation.length - 1
                );
                for (uint256 k = 0; k < i; k++) {
                    splicedAllocation[k] = allocation[k];
                }
                for (uint256 k = i + 1; k < allocation.length; k++) {
                    splicedAllocation[k - 1] = allocation[k];
                }
                assetOutcomeHashes[guarantee.targetChannelId] = keccak256(
                    abi.encode(
                        Outcome.AssetOutcome(
                            uint8(Outcome.AssetOutcomeType.Allocation),
                            abi.encode(splicedAllocation)
                        )
                    )
                );
            }
        }

        // storage updated BEFORE external contracts called (prevent reentrancy attacks)
        if (_isExternalDestination(destination)) {
            _transferAsset(_bytes32ToAddress(destination), affordsForDestination);
        } else {
            holdings[destination] += affordsForDestination;
        }
        // Event emitted
        emit AssetTransferred(guarantorChannelId, destination, affordsForDestination);
    }

    /**
     * @notice Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel. Does not check allocationBytes or guarantee against on chain storage.
     * @dev Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel. Does not check allocationBytes or guarantee against on chain storage.
     * @param guarantorChannelId Unique identifier for a guarantor state channel.
     * @param guarantee The guarantee
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation for the __target__
     */
    function _claimAll(
        bytes32 guarantorChannelId,
        Outcome.Guarantee memory guarantee,
        bytes memory allocationBytes
    ) internal {
        uint256 balance = holdings[guarantorChannelId];

        Outcome.AllocationItem[] memory allocation = abi.decode(
            allocationBytes,
            (Outcome.AllocationItem[])
        ); // this remains constant length

        uint256[] memory payouts = new uint256[](allocation.length);
        uint256 newAllocationLength = allocation.length;

        // first increase payouts according to guarantee
        for (uint256 i = 0; i < guarantee.destinations.length; i++) {
            if (balance == 0) {
                break;
            }
            // for each destination in the guarantee
            bytes32 _destination = guarantee.destinations[i];
            for (uint256 j = 0; j < allocation.length; j++) {
                if (balance == 0) {
                    break;
                }
                if (_destination == allocation[j].destination) {
                    // find amount allocated to that destination (if it exists in channel alllocation)
                    uint256 _amount = allocation[j].amount;
                    if (_amount > 0) {
                        if (balance >= _amount) {
                            balance = balance.sub(_amount);
                            allocation[j].amount = 0; // subtract _amount;
                            newAllocationLength = newAllocationLength.sub(1);
                            payouts[j] += _amount;
                            break;
                        } else {
                            allocation[j].amount = _amount.sub(balance);
                            payouts[j] += balance;
                            balance = 0;
                            break;
                        }
                    }
                }
            }
        }

        // next, increase payouts according to original allocation order
        // this block only has an effect if balance > 0
        for (uint256 j = 0; j < allocation.length; j++) {
            // for each entry in the target channel's outcome
            if (balance == 0) {
                break;
            }
            uint256 _amount = allocation[j].amount;
            if (_amount > 0) {
                if (balance >= _amount) {
                    balance = balance.sub(_amount);
                    allocation[j].amount = 0; // subtract _amount;
                    newAllocationLength = newAllocationLength.sub(1);
                    payouts[j] += _amount;
                } else {
                    allocation[j].amount = _amount.sub(balance);
                    payouts[j] += balance;
                    balance = 0;
                }
            }
        }

        // EFFECTS
        holdings[guarantorChannelId] = balance;

        // at this point have payouts array of uint256s, each corresponding to original destinations
        // and allocations has some zero amounts which we want to prune
        Outcome.AllocationItem[] memory newAllocation;
        if (newAllocationLength > 0) {
            newAllocation = new Outcome.AllocationItem[](newAllocationLength);
        }

        uint256 k = 0;
        for (uint256 j = 0; j < allocation.length; j++) {
            // for each destination in the target channel's allocation
            if (allocation[j].amount > 0) {
                newAllocation[k] = allocation[j];
                k++;
            }
        }
        assert(k == newAllocationLength);

        if (newAllocationLength > 0) {
            // store hash
            assetOutcomeHashes[guarantee.targetChannelId] = keccak256(
                abi.encode(
                    Outcome.AssetOutcome(
                        uint8(Outcome.AssetOutcomeType.Allocation),
                        abi.encode(newAllocation)
                    )
                )
            );
        } else {
            delete assetOutcomeHashes[guarantorChannelId];
            delete assetOutcomeHashes[guarantee.targetChannelId];
        }

        // INTERACTIONS
        for (uint256 j = 0; j < allocation.length; j++) {
            // for each destination in the target channel's allocation
            if (payouts[j] > 0) {
                if (_isExternalDestination(allocation[j].destination)) {
                    _transferAsset(_bytes32ToAddress(allocation[j].destination), payouts[j]);
                } else {
                    holdings[allocation[j].destination] += payouts[j];
                }
                emit AssetTransferred(guarantorChannelId, allocation[j].destination, payouts[j]);
            }
        }
    }

    /**
     * @notice Sets the given assetOutcomeHash for the given channelId in the assetOutcomeHashes storage mapping
     * @dev Sets the given assetOutcomeHash for the given channelId in the assetOutcomeHashes storage mapping
     * @param channelId Unique identifier for a state channel.
     * @param assetOutcomeHash The keccak256 of the abi.encode of the Outcome.
     */
    function _setAssetOutcomeHash(bytes32 channelId, bytes32 assetOutcomeHash) internal {
        require(assetOutcomeHashes[channelId] == bytes32(0), 'Outcome hash already exists');
        assetOutcomeHashes[channelId] = assetOutcomeHash;
    }

    /**
     * @notice Transfers the given amount of this AssetHolders's asset type to a supplied ethereum address.
     * @dev Transfers the given amount of this AssetHolders's asset type to a supplied ethereum address.
     * @param destination ethereum address to be credited.
     * @param amount Quantity of assets to be transferred.
     */
    function _transferAsset(address payable destination, uint256 amount) internal virtual {} // solhint-disable-line no-empty-blocks

    /**
     * @notice Checks if a given destination is external (and can therefore have assets transferred to it) or not.
     * @dev Checks if a given destination is external (and can therefore have assets transferred to it) or not.
     * @param destination Destination to be checked.
     * @return True if the destination is external, false otherwise.
     */
    function _isExternalDestination(bytes32 destination) internal pure returns (bool) {
        return uint96(bytes12(destination)) == 0;
    }

    /**
     * @notice Converts an ethereum address to a nitro external destination.
     * @dev Converts an ethereum address to a nitro external destination.
     * @param participant The address to be converted.
     * @return The input address left-padded with zeros.
     */
    function _addressToBytes32(address participant) internal pure returns (bytes32) {
        return bytes32(uint256(participant));
    }

    /**
     * @notice Converts a nitro destination to an ethereum address.
     * @dev Converts a nitro destination to an ethereum address.
     * @param destination The destination to be converted.
     * @return The rightmost 160 bits of the input string.
     */
    function _bytes32ToAddress(bytes32 destination) internal pure returns (address payable) {
        return address(uint160(uint256(destination)));
    }

    // **************
    // Requirers
    // **************

    function _requireCorrectAllocationHash(bytes32 channelId, bytes memory allocationBytes)
        internal
        view
    {
        require(
            assetOutcomeHashes[channelId] ==
                keccak256(
                    abi.encode(
                        Outcome.AssetOutcome(
                            uint8(Outcome.AssetOutcomeType.Allocation),
                            allocationBytes
                        )
                    )
                ),
            'AssetHolder | submitted allocationBytes data does not match stored assetOutcomeHash'
        );
    }

    function _requireCorrectGuaranteeHash(bytes32 guarantorChannelId, bytes memory guaranteeBytes)
        internal
        view
    {
        require(
            assetOutcomeHashes[guarantorChannelId] ==
                keccak256(
                    abi.encode(
                        Outcome.AssetOutcome(
                            uint8(Outcome.AssetOutcomeType.Guarantee),
                            guaranteeBytes
                        )
                    )
                ),
            'AssetHolder | submitted guaranteeBytes data does not match stored assetOutcomeHash'
        );
    }

    function _requireIncreasingIndices(uint256[] memory indices) internal pure {
        for (uint256 i = 0; i < indices.length - 1; i++) {
            require(indices[i] < indices[i + 1], 'Indices must be sorted');
        }
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? b : a;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

import './IForceMoveApp.sol';

/**
 * @dev The IForceMove interface defines the interface that an implementation of ForceMove should implement. ForceMove protocol allows state channels to be adjudicated and finalized.
 */
interface IForceMove {
    struct Signature {
        uint8 v;
        bytes32 r;
        bytes32 s;
    }

    struct FixedPart {
        uint256 chainId;
        address[] participants;
        uint48 channelNonce;
        address appDefinition;
        uint48 challengeDuration;
    }

    struct State {
        // participants sign the hash of this
        uint48 turnNum;
        bool isFinal;
        bytes32 channelId; // keccack(chainId,participants,channelNonce)
        bytes32 appPartHash;
        //     keccak256(abi.encode(
        //         fixedPart.challengeDuration,
        //         fixedPart.appDefinition,
        //         variablePart.appData
        //     )
        // )
        bytes32 outcomeHash;
    }

    struct ChannelData {
        uint48 turnNumRecord;
        uint48 finalizesAt;
        bytes32 stateHash; // keccak256(abi.encode(State))
        address challengerAddress;
        bytes32 outcomeHash;
    }

    enum ChannelMode {Open, Challenge, Finalized}

    /**
     * @notice Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time.
     * @dev Registers a challenge against a state channel. A challenge will either prompt another participant into clearing the challenge (via one of the other methods), or cause the channel to finalize at a specific time.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update.
     * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param challengerSig The signature of a participant on the keccak256 of the abi.encode of (supportedStateHash, 'forceMove').
     */
    function challenge(
        FixedPart calldata fixedPart,
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] calldata variableParts,
        uint8 isFinalCount, // how many of the states are final
        Signature[] calldata sigs,
        uint8[] calldata whoSignedWhat,
        Signature calldata challengerSig
    ) external;

    /**
     * @notice Repsonds to an ongoing challenge registered against a state channel.
     * @dev Repsonds to an ongoing challenge registered against a state channel.
     * @param challenger The address of the participant whom registered the challenge.
     * @param isFinalAB An pair of booleans describing if the challenge state and/or the response state have the `isFinal` property set to `true`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param variablePartAB An pair of structs, each decribing the properties of the state channel that may change with each state update (for the challenge state and for the response state).
     * @param sig The responder's signature on the `responseStateHash`.
     */
    function respond(
        address challenger,
        bool[2] calldata isFinalAB,
        FixedPart calldata fixedPart,
        IForceMoveApp.VariablePart[2] calldata variablePartAB,
        // variablePartAB[0] = challengeVariablePart
        // variablePartAB[1] = responseVariablePart
        Signature calldata sig
    ) external;

    /**
     * @notice Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant.
     * @dev Overwrites the `turnNumRecord` stored against a channel by providing a state with higher turn number, supported by a signature from each participant.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update.
     * @param isFinalCount Describes how many of the submitted states have the `isFinal` property set to `true`. It is implied that the rightmost `isFinalCount` states are final, and the rest are not final.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     */
    function checkpoint(
        FixedPart calldata fixedPart,
        uint48 largestTurnNum,
        IForceMoveApp.VariablePart[] calldata variableParts,
        uint8 isFinalCount, // how many of the states are final
        Signature[] calldata sigs,
        uint8[] calldata whoSignedWhat
    ) external;

    /**
     * @notice Finalizes a channel by providing a finalization proof.
     * @dev Finalizes a channel by providing a finalization proof.
     * @param largestTurnNum The largest turn number of the submitted states; will overwrite the stored value of `turnNumRecord`.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param appPartHash The keccak256 of the abi.encode of `(challengeDuration, appDefinition, appData)`. Applies to all states in the finalization proof.
     * @param outcomeHash The keccak256 of the abi.encode of the `outcome`. Applies to all stats in the finalization proof.
     * @param numStates The number of states in the finalization proof.
     * @param whoSignedWhat An array denoting which participant has signed which state: `participant[i]` signed the state with index `whoSignedWhat[i]`.
     * @param sigs An array of signatures that support the state with the `largestTurnNum`.
     */
    function conclude(
        uint48 largestTurnNum,
        FixedPart calldata fixedPart,
        bytes32 appPartHash,
        bytes32 outcomeHash,
        uint8 numStates,
        uint8[] calldata whoSignedWhat,
        Signature[] calldata sigs
    ) external;

    // events

    /**
     * @dev Indicates that a challenge has been registered against `channelId`.
     * @param channelId Unique identifier for a state channel.
     * @param turnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant.
     * @param finalizesAt The unix timestamp when `channelId` will finalize.
     * @param challenger The address of the participant whom registered the challenge.
     * @param isFinal Boolean denoting whether the challenge state is final.
     * @param fixedPart Data describing properties of the state channel that do not change with state updates.
     * @param variableParts An ordered array of structs, each decribing the properties of the state channel that may change with each state update.
     * @param sigs A list of Signatures that supported the challenge
     * @param whoSignedWhat Indexing information to identify which signature was by which participant
     */
    event ChallengeRegistered(
        bytes32 indexed channelId,
        // everything needed to respond or checkpoint
        uint48 turnNumRecord,
        uint48 finalizesAt,
        address challenger,
        bool isFinal,
        FixedPart fixedPart,
        IForceMoveApp.VariablePart[] variableParts,
        Signature[] sigs,
        uint8[] whoSignedWhat
    );

    /**
     * @dev Indicates that a challenge, previously registered against `channelId`, has been cleared.
     * @param channelId Unique identifier for a state channel.
     * @param newTurnNumRecord A turnNum that (the adjudicator knows) is supported by a signature from each participant.
     */
    event ChallengeCleared(bytes32 indexed channelId, uint48 newTurnNumRecord);

    /**
     * @dev Indicates that a challenge has been registered against `channelId`.
     * @param channelId Unique identifier for a state channel.
     * @param finalizesAt The unix timestamp when `channelId` finalized.
     */
    event Concluded(bytes32 indexed channelId, uint48 finalizesAt);
}

// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

/**
 * @dev The IForceMoveApp interface calls for its children to implement an application-specific validTransition function, defining the state machine of a ForceMove state channel DApp.
 */
interface IForceMoveApp {
    struct VariablePart {
        bytes outcome;
        bytes appData;
    }

    /**
     * @notice Encodes application-specific rules for a particular ForceMove-compliant state channel.
     * @dev Encodes application-specific rules for a particular ForceMove-compliant state channel.
     * @param a State being transitioned from.
     * @param b State being transitioned to.
     * @param turnNumB Turn number being transitioned to.
     * @param nParticipants Number of participants in this state channel.
     * @return true if the transition conforms to this application's rules, false otherwise
     */
    function validTransition(
        VariablePart calldata a,
        VariablePart calldata b,
        uint48 turnNumB,
        uint256 nParticipants
    ) external pure returns (bool);
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

// SPDX-License-Identifier: MIT
pragma solidity 0.7.4;
pragma experimental ABIEncoderV2;

/**
 * @dev The IAssetHolder interface calls for functions that allow assets to be transferred from one channel to other channel and/or external destinations, as well as for guarantees to be claimed.
 */
interface IAssetHolder {
    /**
     * @notice Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries.
     * @dev Transfers as many funds escrowed against `channelId` as can be afforded for a specific destination. Assumes no repeated entries.
     * @param fromChannelId Unique identifier for state channel to transfer funds *from*.
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation
     * @param indices Array with each entry denoting the index of a destination to transfer funds to.
     */
    function transfer(
        bytes32 fromChannelId,
        bytes calldata allocationBytes,
        uint256[] memory indices
    ) external;

    /**
     * @notice Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel.
     * @dev Transfers the funds escrowed against `guarantorChannelId` to the beneficiaries of the __target__ of that channel.
     * @param guarantorChannelId Unique identifier for a guarantor state channel.
     * @param guaranteeBytes The abi.encode of Outcome.Guarantee
     * @param allocationBytes The abi.encode of AssetOutcome.Allocation for the __target__
     */
    function claimAll(
        bytes32 guarantorChannelId,
        bytes calldata guaranteeBytes,
        bytes calldata allocationBytes
    ) external;

    /**
     * @dev Indicates that `amountDeposited` has been deposited into `destination`.
     * @param destination The channel being deposited into.
     * @param amountDeposited The amount being deposited.
     * @param destinationHoldings The new holdings for `destination`.
     */
    event Deposited(
        bytes32 indexed destination,
        uint256 amountDeposited,
        uint256 destinationHoldings
    );

    /**
     * @dev Indicates that `amount` assets have been transferred (internally or externally) to the destination denoted by `destination`.
     * @param channelId The channelId of the funds being withdrawn.
     * @param destination An internal destination (channelId) of external destination (padded ethereum address)
     * @param amount Number of assets transferred (wei or tokens).
     */
    event AssetTransferred(bytes32 indexed channelId, bytes32 indexed destination, uint256 amount);
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"uint48","name":"newTurnNumRecord","type":"uint48"}],"name":"ChallengeCleared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"uint48","name":"turnNumRecord","type":"uint48"},{"indexed":false,"internalType":"uint48","name":"finalizesAt","type":"uint48"},{"indexed":false,"internalType":"address","name":"challenger","type":"address"},{"indexed":false,"internalType":"bool","name":"isFinal","type":"bool"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"indexed":false,"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"components":[{"internalType":"bytes","name":"outcome","type":"bytes"},{"internalType":"bytes","name":"appData","type":"bytes"}],"indexed":false,"internalType":"struct IForceMoveApp.VariablePart[]","name":"variableParts","type":"tuple[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"indexed":false,"internalType":"struct IForceMove.Signature[]","name":"sigs","type":"tuple[]"},{"indexed":false,"internalType":"uint8[]","name":"whoSignedWhat","type":"uint8[]"}],"name":"ChallengeRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"channelId","type":"bytes32"},{"indexed":false,"internalType":"uint48","name":"finalizesAt","type":"uint48"}],"name":"Concluded","type":"event"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"internalType":"uint48","name":"largestTurnNum","type":"uint48"},{"components":[{"internalType":"bytes","name":"outcome","type":"bytes"},{"internalType":"bytes","name":"appData","type":"bytes"}],"internalType":"struct IForceMoveApp.VariablePart[]","name":"variableParts","type":"tuple[]"},{"internalType":"uint8","name":"isFinalCount","type":"uint8"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature[]","name":"sigs","type":"tuple[]"},{"internalType":"uint8[]","name":"whoSignedWhat","type":"uint8[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature","name":"challengerSig","type":"tuple"}],"name":"challenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"channelStorageHashes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"internalType":"uint48","name":"largestTurnNum","type":"uint48"},{"components":[{"internalType":"bytes","name":"outcome","type":"bytes"},{"internalType":"bytes","name":"appData","type":"bytes"}],"internalType":"struct IForceMoveApp.VariablePart[]","name":"variableParts","type":"tuple[]"},{"internalType":"uint8","name":"isFinalCount","type":"uint8"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature[]","name":"sigs","type":"tuple[]"},{"internalType":"uint8[]","name":"whoSignedWhat","type":"uint8[]"}],"name":"checkpoint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"largestTurnNum","type":"uint48"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"internalType":"bytes32","name":"appPartHash","type":"bytes32"},{"internalType":"bytes32","name":"outcomeHash","type":"bytes32"},{"internalType":"uint8","name":"numStates","type":"uint8"},{"internalType":"uint8[]","name":"whoSignedWhat","type":"uint8[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature[]","name":"sigs","type":"tuple[]"}],"name":"conclude","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint48","name":"largestTurnNum","type":"uint48"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"internalType":"bytes32","name":"appPartHash","type":"bytes32"},{"internalType":"bytes","name":"outcomeBytes","type":"bytes"},{"internalType":"uint8","name":"numStates","type":"uint8"},{"internalType":"uint8[]","name":"whoSignedWhat","type":"uint8[]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature[]","name":"sigs","type":"tuple[]"}],"name":"concludePushOutcomeAndTransferAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getChainID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"}],"name":"getChannelStorage","outputs":[{"internalType":"uint48","name":"turnNumRecord","type":"uint48"},{"internalType":"uint48","name":"finalizesAt","type":"uint48"},{"internalType":"uint160","name":"fingerprint","type":"uint160"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"uint48","name":"turnNumRecord","type":"uint48"},{"internalType":"uint48","name":"finalizesAt","type":"uint48"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"address","name":"challengerAddress","type":"address"},{"internalType":"bytes","name":"outcomeBytes","type":"bytes"}],"name":"pushOutcome","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"channelId","type":"bytes32"},{"internalType":"uint48","name":"turnNumRecord","type":"uint48"},{"internalType":"uint48","name":"finalizesAt","type":"uint48"},{"internalType":"bytes32","name":"stateHash","type":"bytes32"},{"internalType":"address","name":"challengerAddress","type":"address"},{"internalType":"bytes","name":"outcomeBytes","type":"bytes"}],"name":"pushOutcomeAndTransferAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"numParticipants","type":"uint256"},{"internalType":"uint256","name":"numStates","type":"uint256"},{"internalType":"uint256","name":"numSigs","type":"uint256"},{"internalType":"uint256","name":"numWhoSignedWhats","type":"uint256"}],"name":"requireValidInput","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"challenger","type":"address"},{"internalType":"bool[2]","name":"isFinalAB","type":"bool[2]"},{"components":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address[]","name":"participants","type":"address[]"},{"internalType":"uint48","name":"channelNonce","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"},{"internalType":"uint48","name":"challengeDuration","type":"uint48"}],"internalType":"struct IForceMove.FixedPart","name":"fixedPart","type":"tuple"},{"components":[{"internalType":"bytes","name":"outcome","type":"bytes"},{"internalType":"bytes","name":"appData","type":"bytes"}],"internalType":"struct IForceMoveApp.VariablePart[2]","name":"variablePartAB","type":"tuple[2]"},{"components":[{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct IForceMove.Signature","name":"sig","type":"tuple"}],"name":"respond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nParticipants","type":"uint256"},{"internalType":"bool[2]","name":"isFinalAB","type":"bool[2]"},{"components":[{"internalType":"bytes","name":"outcome","type":"bytes"},{"internalType":"bytes","name":"appData","type":"bytes"}],"internalType":"struct IForceMoveApp.VariablePart[2]","name":"ab","type":"tuple[2]"},{"internalType":"uint48","name":"turnNumB","type":"uint48"},{"internalType":"address","name":"appDefinition","type":"address"}],"name":"validTransition","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"}]

608060405234801561001057600080fd5b50612d72806100206000396000f3fe608060405234801561001057600080fd5b50600436106100b45760003560e01c80637ff6a982116100715780637ff6a98214610145578063be5c2a3114610158578063eb0265141461016b578063f198bea91461017e578063fe9e5db914610191578063ff8ceb32146101b3576100b4565b80630149b762146100b9578063564b81ef146100ce5780635a04d456146100ec5780636775b173146100ff5780636f65e87d1461011f57806374ce052a14610132575b600080fd5b6100cc6100c7366004611d58565b6101c6565b005b6100d661021e565b6040516100e39190612290565b60405180910390f35b6100cc6100fa366004611c4d565b610222565b61011261010d366004611eed565b610350565b6040516100e39190612285565b6100d661012d366004611c35565b61036b565b6100cc610140366004611c4d565b61037d565b6100cc610153366004611f99565b6103e5565b610112610166366004611f68565b6103fe565b6100cc610179366004612055565b61048b565b6100cc61018c366004611e12565b6104af565b6101a461019f366004611c35565b610631565b6040516100e393929190612c52565b6100cc6101c1366004611aa3565b61064c565b6101da8660200151518551845184516103fe565b5060006101e6876107a8565b90506101f18161080f565b6101fb8187610846565b61020a868686848b8888610889565b5061021581876108ef565b50505050505050565b4690565b61022b8661097d565b6000818051906020012090506102806040518060a001604052808865ffffffffffff1681526020018765ffffffffffff168152602001868152602001856001600160a01b0316815260200183815250886109b0565b6060828060200190518101906102969190611b3a565b905060005b8151811015610345578181815181106102b057fe5b6020026020010151600001516001600160a01b031663a3c863a38a8484815181106102d757fe5b602002602001015160200151805190602001206040518363ffffffff1660e01b8152600401610307929190612299565b600060405180830381600087803b15801561032157600080fd5b505af1158015610335573d6000803e3d6000fd5b50506001909201915061029b9050565b505050505050505050565b600061035f86868686866109ea565b90505b95945050505050565b60006020819052908152604090205481565b6103868661097d565b6000818051906020012090506103db6040518060a001604052808865ffffffffffff1681526020018765ffffffffffff168152602001868152602001856001600160a01b0316815260200183815250886109b0565b6102158783610abd565b6103f487878787878787610bc7565b5050505050505050565b60008385101580156104105750600084115b6104355760405162461bcd60e51b815260040161042c90612982565b60405180910390fd5b848314801561044357508482145b61045f5760405162461bcd60e51b815260040161042c90612566565b60ff851061047f5760405162461bcd60e51b815260040161042c906125e9565b5060015b949350505050565b8351602085012060006104a389898985898989610bc7565b90506103458187610abd565b6104c38760200151518651855185516103fe565b5060006104cf886107a8565b905060006104dc82610de0565b60028111156104e757fe5b14156104fc576104f78188610e2b565b61052b565b600161050782610de0565b600281111561051257fe5b1415610522576104f78188610846565b61052b8161080f565b600061053c888888858d8a8a610889565b9050600061054f828b6020015186610e6a565b9050827f1f9f029de8ab3f81b5381a9bc066b421d0f215db28cc8160ec346bc6f0463c6e8a8c6080015142018460008c60ff16118f8e8d8d60405161059b989796959493929190612b85565b60405180910390a26106136040518060a001604052808b65ffffffffffff1681526020018c60800151420165ffffffffffff168152602001848152602001836001600160a01b031681526020018a60018c5103815181106105f857fe5b60200260200101516000015180519060200120815250610ecb565b60009384526020849052604090932092909255505050505050505050565b600080600061063f84610f30565b9196909550909350915050565b6000610657846107a8565b905060008061066583610f30565b508651518051602091820120818901515180519201919091208a51939550919350916000906106a4908690888c8c865b60200201516020015188610f4e565b905060006106c26001808801908d906020020151898d8d6001610695565b905061070d6040518060a001604052808865ffffffffffff1681526020018765ffffffffffff1681526020018481526020018e6001600160a01b031681526020018681525088610fe5565b60208a0151805165ffffffffffff60018901168161072757fe5b068151811061073257fe5b60200260200101516001600160a01b031661074d828a610ff8565b6001600160a01b0316146107735760405162461bcd60e51b815260040161042c906129f8565b61078c8a60200151518c8b896001018e606001516109ea565b5061079a87876001016108ef565b505050505050505050505050565b60006107b261021e565b8251146107d15760405162461bcd60e51b815260040161042c90612472565b6107d961021e565b60208084015160408086015190516107f2949301612b0f565b604051602081830303815290604052805190602001209050919050565b600261081a82610de0565b600281111561082557fe5b14156108435760405162461bcd60e51b815260040161042c9061249d565b50565b600061085183610f30565b505090508065ffffffffffff168265ffffffffffff16116108845760405162461bcd60e51b815260040161042c906123cf565b505050565b6000606061089a89898989896110b4565b90506108ad898660200151838787611285565b6108c95760405162461bcd60e51b815260040161042c90612662565b806001825103815181106108d957fe5b6020026020010151915050979650505050505050565b6040805160a08101825265ffffffffffff8316815260006020820181905291810182905260608101829052608081019190915261092b90610ecb565b60008084815260200190815260200160002081905550817f07da0a0674fb921e484018c8b81d80e292745e5d8ed134b580c8b9c631c5e9e0826040516109719190612b40565b60405180910390a25050565b600261098882610de0565b600281111561099357fe5b146108435760405162461bcd60e51b815260040161042c90612952565b6000818152602081905260409020546109ca90839061135b565b6109e65760405162461bcd60e51b815260040161042c90612884565b5050565b6000806109f98787878761136f565b90506001816001811115610a0957fe5b1415610ab0578451602086015160405163fd7a2f6560e01b81526001600160a01b0386169263fd7a2f6592610a449289908d90600401612ace565b60206040518083038186803b158015610a5c57600080fd5b505afa158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a949190611c19565b610ab05760405162461bcd60e51b815260040161042c90612500565b5060019695505050505050565b606081806020019051810190610ad39190611b3a565b905060005b8151811015610bc157610ae96115ca565b828281518110610af557fe5b602002602001015160200151806020019051810190610b149190611ccd565b805190915060ff16610ba057828281518110610b2c57fe5b6020026020010151600001516001600160a01b031663022cbbe88683602001516040518363ffffffff1660e01b8152600401610b699291906122a7565b600060405180830381600087803b158015610b8357600080fd5b505af1158015610b97573d6000803e3d6000fd5b50505050610bb8565b60405162461bcd60e51b815260040161042c90612406565b50600101610ad8565b50505050565b6000610bd2876107a8565b9050610bdd8161080f565b610bf38760200151518560ff16845186516103fe565b508360ff168860010165ffffffffffff161015610c225760405162461bcd60e51b815260040161042c90612372565b610c2b876107a8565b9050610c368161080f565b60608460ff166001600160401b0381118015610c5157600080fd5b50604051908082528060200260200182016040528015610c7b578160200160208202803683370190505b50905060005b8560ff168165ffffffffffff161015610d1d576040518060a001604052808760ff16836001018d010365ffffffffffff16815260200160011515815260200184815260200189815260200188815250604051602001610ce09190612a8a565b60405160208183030381529060405280519060200120828265ffffffffffff1681518110610d0a57fe5b6020908102919091010152600101610c81565b50610d2f898960200151838688611285565b610d4b5760405162461bcd60e51b815260040161042c906128d2565b6040805160a08101825260008082524265ffffffffffff166020830152918101829052606081019190915260808101879052610d8690610ecb565b60008084815260200190815260200160002081905550817f4f465027a3d06ea73dd12be0f5c5fc0a34e21f19d6eaed4834a7a944edabc90142604051610dcc9190612b40565b60405180910390a250979650505050505050565b600080610dec83610f30565b5091505065ffffffffffff8116610e07576000915050610e26565b428165ffffffffffff1611610e20576002915050610e26565b60019150505b919050565b6000610e3683610f30565b505090508065ffffffffffff168265ffffffffffff1610156108845760405162461bcd60e51b815260040161042c906124c9565b6000610e9c84604051602001610e8091906122c0565b6040516020818303038152906040528051906020012083610ff8565b9050610ea88184611453565b610ec45760405162461bcd60e51b815260040161042c9061262b565b9392505050565b805160208083015160405160009360d01b6001600160d01b03191660a092831b65ffffffffffff60a01b161792610f0491869101612a3f565b60408051601f1981840301815291905280516020909101206001600160a01b0316919091179392505050565b60009081526020819052604090205460d081901c9160a082901c9190565b60006040518060a001604052808865ffffffffffff16815260200187151581526020018681526020018560800151866060015186604051602001610f9493929190612b53565b60405160208183030381529060405280519060200120815260200183815250604051602001610fc39190612a8a565b6040516020818303038152906040528051906020012090509695505050505050565b610fef82826109b0565b6109e6816114a9565b6000808360405160200161100c9190612254565b60405160208183030381529060405280519060200120905060006001828560000151866020015187604001516040516000815260200160405260405161105594939291906122ea565b6020604051602081039080840390855afa158015611077573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166110aa5760405162461bcd60e51b815260040161042c9061276d565b9150505b92915050565b60608085516001600160401b03811180156110ce57600080fd5b506040519080825280602002602001820160405280156110f8578160200160208202803683370190505b509050600160ff86168803016000805b88518165ffffffffffff161015611277578089518b0360010101915061118a828465ffffffffffff168465ffffffffffff16101589898d8665ffffffffffff168151811061115257fe5b6020026020010151602001518e8765ffffffffffff168151811061117257fe5b60200260200101516000015180519060200120610f4e565b848265ffffffffffff168151811061119e57fe5b6020026020010181815250508965ffffffffffff168265ffffffffffff16101561126f5761126d86602001515160405180604001604052808665ffffffffffff168665ffffffffffff1610151515151581526020018665ffffffffffff168660010165ffffffffffff1610151515151581525060405180604001604052808d8665ffffffffffff168151811061123057fe5b602002602001015181526020018d8660010165ffffffffffff168151811061125457fe5b6020026020010151815250856001018a606001516109ea565b505b600101611108565b509198975050505050505050565b8351835160009190611299848984846114dc565b6112b55760405162461bcd60e51b815260040161042c9061291d565b60005b8281101561134c576000611308888784815181106112d257fe5b602002602001015160ff16815181106112e757fe5b60200260200101518884815181106112fb57fe5b6020026020010151610ff8565b905088828151811061131657fe5b60200260200101516001600160a01b0316816001600160a01b031614611343576000945050505050610362565b506001016112b8565b50600198975050505050505050565b60008161136784610ecb565b149392505050565b6020830151600090156113b2576113918360015b602002015151845151611566565b6113ad5760405162461bcd60e51b815260040161042c90612809565b611448565b8351156113d15760405162461bcd60e51b815260040161042c90612798565b846002028265ffffffffffff161015611440576113ef836001611383565b61140b5760405162461bcd60e51b815260040161042c9061268e565b6020838101518101518451909101516114249190611566565b6113ad5760405162461bcd60e51b815260040161042c90612308565b506001610483565b506000949350505050565b6000805b825181101561149f5782818151811061146c57fe5b60200260200101516001600160a01b0316846001600160a01b031614156114975760019150506110ae565b600101611457565b5060009392505050565b60016114b482610de0565b60028111156114bf57fe5b146108435760405162461bcd60e51b815260040161042c90612537565b6000828551146114fe5760405162461bcd60e51b815260040161042c90612700565b60005b8381101561155a57600084828765ffffffffffff168701038161152057fe5b069050838188848151811061153157fe5b602002602001015160ff1601600101101561155157600092505050610483565b50600101611501565b50600195945050505050565b81518151600091600191811480831461158257600092506115c0565b600160208701838101602088015b6002848385100114156115bb5780518351146115af5760009650600093505b60209283019201611590565b505050505b5090949350505050565b60408051808201909152600081526060602082015290565b8035610e2681612d0a565b600082601f8301126115fd578081fd5b604051604081018181106001600160401b038211171561161957fe5b8060405250809150828460408501111561163257600080fd5b60005b600281101561165e57813561164981612d1f565b83526020928301929190910190600101611635565b50505092915050565b600082601f830112611677578081fd5b813561168a61168582612ca0565b612c7d565b81815291506020808301908481016060808502870183018810156116ad57600080fd5b60005b858110156116d4576116c289846119a3565b855293830193918101916001016116b0565b50505050505092915050565b600082601f8301126116f0578081fd5b604051604081018181106001600160401b038211171561170c57fe5b6040529050808260005b600281101561165e5761172c8683358701611a00565b83526020928301929190910190600101611716565b600082601f830112611751578081fd5b813561175f61168582612ca0565b818152915060208083019084810160005b8481101561179957611787888484358a0101611a00565b84529282019290820190600101611770565b505050505092915050565b600082601f8301126117b4578081fd5b81356117c261168582612ca0565b8181529150602080830190848101818402860182018710156117e357600080fd5b60005b848110156117995781356117f981612d2d565b845292820192908201906001016117e6565b600082601f83011261181b578081fd5b813561182961168582612cbd565b915080825283602082850101111561184057600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112611869578081fd5b815161187761168582612cbd565b915080825283602082850101111561188e57600080fd5b61189f816020840160208601612cde565b5092915050565b600060a082840312156118b7578081fd5b60405160a081016001600160401b0382821081831117156118d457fe5b81604052829350843583526020915081850135818111156118f457600080fd5b85019050601f8101861361190757600080fd5b803561191561168582612ca0565b81815283810190838501858402850186018a101561193257600080fd5b600094505b8385101561195e57803561194a81612d0a565b835260019490940193918501918501611937565b508085870152505050505061197560408401611a82565b6040820152611986606084016115e2565b606082015261199760808401611a82565b60808201525092915050565b6000606082840312156119b4578081fd5b604051606081018181106001600160401b03821117156119d057fe5b60405290508082356119e181612d2d565b8082525060208301356020820152604083013560408201525092915050565b600060408284031215611a11578081fd5b604051604081016001600160401b038282108183111715611a2e57fe5b816040528293508435915080821115611a4657600080fd5b611a528683870161180b565b83526020850135915080821115611a6857600080fd5b50611a758582860161180b565b6020830152505092915050565b803565ffffffffffff81168114610e2657600080fd5b8035610e2681612d2d565b60008060008060006101008688031215611abb578081fd5b8535611ac681612d0a565b9450611ad587602088016115ed565b935060608601356001600160401b0380821115611af0578283fd5b611afc89838a016118a6565b94506080880135915080821115611b11578283fd5b50611b1e888289016116e0565b925050611b2e8760a088016119a3565b90509295509295909350565b60006020808385031215611b4c578182fd5b82516001600160401b0380821115611b62578384fd5b818501915085601f830112611b75578384fd5b8151611b8361168582612ca0565b81815284810190848601875b84811015611c0a5781518701604080601f19838f03011215611baf578a8bfd5b80518181018181108a82111715611bc257fe5b8252828b0151611bd181612d0a565b8152908201519088821115611be4578b8cfd5b611bf28e8c84860101611859565b818c0152865250509287019290870190600101611b8f565b50909998505050505050505050565b600060208284031215611c2a578081fd5b8151610ec481612d1f565b600060208284031215611c46578081fd5b5035919050565b60008060008060008060c08789031215611c65578384fd5b86359550611c7560208801611a82565b9450611c8360408801611a82565b9350606087013592506080870135611c9a81612d0a565b915060a08701356001600160401b03811115611cb4578182fd5b611cc089828a0161180b565b9150509295509295509295565b600060208284031215611cde578081fd5b81516001600160401b0380821115611cf4578283fd5b9083019060408286031215611d07578283fd5b604051604081018181108382111715611d1c57fe5b6040528251611d2a81612d2d565b8152602083015182811115611d3d578485fd5b611d4987828601611859565b60208301525095945050505050565b60008060008060008060c08789031215611d70578384fd5b86356001600160401b0380821115611d86578586fd5b611d928a838b016118a6565b9750611da060208a01611a82565b96506040890135915080821115611db5578586fd5b611dc18a838b01611741565b9550611dcf60608a01611a98565b94506080890135915080821115611de4578384fd5b611df08a838b01611667565b935060a0890135915080821115611e05578283fd5b50611cc089828a016117a4565b6000806000806000806000610120888a031215611e2d578485fd5b87356001600160401b0380821115611e43578687fd5b611e4f8b838c016118a6565b9850611e5d60208b01611a82565b975060408a0135915080821115611e72578687fd5b611e7e8b838c01611741565b9650611e8c60608b01611a98565b955060808a0135915080821115611ea1578283fd5b611ead8b838c01611667565b945060a08a0135915080821115611ec2578283fd5b50611ecf8a828b016117a4565b925050611edf8960c08a016119a3565b905092959891949750929550565b600080600080600060c08688031215611f04578283fd5b85359450611f1587602088016115ed565b935060608601356001600160401b03811115611f2f578384fd5b611f3b888289016116e0565b935050611f4a60808701611a82565b915060a0860135611f5a81612d0a565b809150509295509295909350565b60008060008060808587031215611f7d578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600080600060e0888a031215611fb3578081fd5b611fbc88611a82565b965060208801356001600160401b0380821115611fd7578283fd5b611fe38b838c016118a6565b975060408a0135965060608a0135955060808a0135915061200382612d2d565b90935060a08901359080821115612018578283fd5b6120248b838c016117a4565b935060c08a0135915080821115612039578283fd5b506120468a828b01611667565b91505092959891949750929550565b600080600080600080600060e0888a03121561206f578081fd5b61207888611a82565b965060208801356001600160401b0380821115612093578283fd5b61209f8b838c016118a6565b975060408a0135965060608a01359150808211156120bb578283fd5b6120c78b838c0161180b565b95506120d560808b01611a98565b945060a08a0135915080821115612018578283fd5b6000815180845260208085019450808401835b838110156121225781516001600160a01b0316875295820195908201906001016120fd565b509495945050505050565b6000815180845260208085019450808401835b83811015612122578151805160ff16885283810151848901526040908101519088015260609096019590820190600101612140565b6000815180845260208085018081965082840281019150828601855b858110156121bb5782840389526121a9848351612226565b98850198935090840190600101612191565b5091979650505050505050565b6000815180845260208085019450808401835b8381101561212257815160ff16875295820195908201906001016121db565b60008151808452612212816020860160208601612cde565b601f01601f19169290920160200192915050565b600081516040845261223b60408501826121fa565b90506020830151848203602086015261036282826121fa565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b901515815260200190565b90815260200190565b918252602082015260400190565b60008382526040602083015261048360408301846121fa565b90815260406020820181905260099082015268666f7263654d6f766560b81b606082015260800190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526044908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206360408201527f68616e676520746865206170704461746120647572696e6720736574757020706060820152636861736560e01b608082015260a00190565b6020808252603d908201527f6c6172676573745475726e4e756d202b2031206d75737420626520677265617460408201527f6572207468616e206f7220657175616c20746f206e756d537461746573000000606082015260800190565b6020808252601c908201527f7475726e4e756d5265636f7264206e6f7420696e637265617365642e00000000604082015260600190565b60208082526046908201527f5f7472616e73666572416c6c46726f6d416c6c4173736574486f6c646572733a60408201527f2041737365744f7574636f6d6554797065206973206e6f7420616e20616c6c6f60608201526531b0ba34b7b760d11b608082015260a00190565b602080825260119082015270125b98dbdc9c9958dd0818da185a5b9259607a1b604082015260600190565b60208082526012908201527121b430b73732b6103334b730b634bd32b21760711b604082015260600190565b60208082526018908201527f7475726e4e756d5265636f7264206465637265617365642e0000000000000000604082015260600190565b6020808252601f908201527f496e76616c696420466f7263654d6f7665417070205472616e736974696f6e00604082015260600190565b60208082526015908201527427379037b733b7b4b7339031b430b63632b733b29760591b604082015260600190565b6020808252605e908201527f466f7263654d6f7665207c20526571756972652065786163746c79203120736960408201527f676e617475726520706572207061727469636970616e7420262077686f20736960608201527f676e6564207768617420666f7220616c6c207061727469636970616e74730000608082015260a00190565b60208082526022908201527f466f7263654d6f7665207c20546f6f206d616e79207061727469636970616e74604082015261732160f01b606082015260800190565b6020808252601f908201527f4368616c6c656e676572206973206e6f742061207061727469636970616e7400604082015260600190565b602080825260129082015271496e76616c6964207369676e61747572657360701b604082015260600190565b6020808252604c908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206360408201527f68616e6765207468652064656661756c74206f7574636f6d6520647572696e6760608201526b20736574757020706861736560a01b608082015260a00190565b60208082526047908201527f5f76616c69645369676e6174757265733a2077686f5369676e6564576861742060408201527f6d757374206265207468652073616d65206c656e677468206173207061727469606082015266636970616e747360c81b608082015260a00190565b602080825260119082015270496e76616c6964207369676e617475726560781b604082015260600190565b6020808252604b908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206d60408201527f6f76652066726f6d20612066696e616c20737461746520746f2061206e6f6e2060608201526a66696e616c20737461746560a81b608082015260a00190565b60208082526055908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206d60408201527f6f766520746f20612066696e616c2073746174652077697468206120646966666060820152746572656e742064656661756c74206f7574636f6d6560581b608082015260a00190565b6020808252602e908201527f4368616e6e656c2073746f7261676520646f6573206e6f74206d61746368207360408201526d3a37b932b2103b32b939b4b7b71760911b606082015260800190565b6020808252602b908201527f496e76616c6964207369676e617475726573204f5220697346696e616c3d747260408201526a1d5948195e1c1958dd195960aa1b606082015260800190565b6020808252818101527f556e61636365707461626c652077686f5369676e656457686174206172726179604082015260600190565b60208082526016908201527521b430b73732b6103737ba103334b730b634bd32b21760511b604082015260600190565b60208082526050908201527f466f7263654d6f7665207c20596f75206d757374207375626d6974206174206c60408201527f65617374206f6e6520627574206e6f206d6f7265207468616e206e756d50617260608201526f7469636970616e74732073746174657360801b608082015260a00190565b60208082526027908201527f526573706f6e7365206e6f74207369676e656420627920617574686f72697a65604082015266321036b7bb32b960c91b606082015260800190565b815165ffffffffffff908116825260208084015190911690820152604080830151908201526060808301516001600160a01b0316908201526080918201519181019190915260a00190565b600060a08201905065ffffffffffff835116825260208301511515602083015260408301516040830152606083015160608301526080830151608083015292915050565b600060808252612ae16080830187612226565b8281036020840152612af38187612226565b65ffffffffffff95909516604084015250506060015292915050565b600084825260606020830152612b2860608301856120ea565b905065ffffffffffff83166040830152949350505050565b65ffffffffffff91909116815260200190565b65ffffffffffff841681526001600160a01b0383166020820152606060408201819052600090610362908301846121fa565b600061010065ffffffffffff808c168452808b16602085015260018060a01b03808b16604086015289151560608601528260808601528851838601526020890151925060a0610120860152612bde6101a08601846120ea565b92508160408a0151166101408601528060608a01511661016086015250806080890151166101808501525082810360a0840152612c1b8187612175565b905082810360c0840152612c2f818661212d565b905082810360e0840152612c4381856121c8565b9b9a5050505050505050505050565b65ffffffffffff93841681529190921660208201526001600160a01b03909116604082015260600190565b6040518181016001600160401b0381118282101715612c9857fe5b604052919050565b60006001600160401b03821115612cb357fe5b5060209081020190565b60006001600160401b03821115612cd057fe5b50601f01601f191660200190565b60005b83811015612cf9578181015183820152602001612ce1565b83811115610bc15750506000910152565b6001600160a01b038116811461084357600080fd5b801515811461084357600080fd5b60ff8116811461084357600080fdfea264697066735822122096b5a3db9cbf7cb6026375eaf24030a4e0682cf549a6833f9101bae2b88a961c64736f6c63430007040033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100b45760003560e01c80637ff6a982116100715780637ff6a98214610145578063be5c2a3114610158578063eb0265141461016b578063f198bea91461017e578063fe9e5db914610191578063ff8ceb32146101b3576100b4565b80630149b762146100b9578063564b81ef146100ce5780635a04d456146100ec5780636775b173146100ff5780636f65e87d1461011f57806374ce052a14610132575b600080fd5b6100cc6100c7366004611d58565b6101c6565b005b6100d661021e565b6040516100e39190612290565b60405180910390f35b6100cc6100fa366004611c4d565b610222565b61011261010d366004611eed565b610350565b6040516100e39190612285565b6100d661012d366004611c35565b61036b565b6100cc610140366004611c4d565b61037d565b6100cc610153366004611f99565b6103e5565b610112610166366004611f68565b6103fe565b6100cc610179366004612055565b61048b565b6100cc61018c366004611e12565b6104af565b6101a461019f366004611c35565b610631565b6040516100e393929190612c52565b6100cc6101c1366004611aa3565b61064c565b6101da8660200151518551845184516103fe565b5060006101e6876107a8565b90506101f18161080f565b6101fb8187610846565b61020a868686848b8888610889565b5061021581876108ef565b50505050505050565b4690565b61022b8661097d565b6000818051906020012090506102806040518060a001604052808865ffffffffffff1681526020018765ffffffffffff168152602001868152602001856001600160a01b0316815260200183815250886109b0565b6060828060200190518101906102969190611b3a565b905060005b8151811015610345578181815181106102b057fe5b6020026020010151600001516001600160a01b031663a3c863a38a8484815181106102d757fe5b602002602001015160200151805190602001206040518363ffffffff1660e01b8152600401610307929190612299565b600060405180830381600087803b15801561032157600080fd5b505af1158015610335573d6000803e3d6000fd5b50506001909201915061029b9050565b505050505050505050565b600061035f86868686866109ea565b90505b95945050505050565b60006020819052908152604090205481565b6103868661097d565b6000818051906020012090506103db6040518060a001604052808865ffffffffffff1681526020018765ffffffffffff168152602001868152602001856001600160a01b0316815260200183815250886109b0565b6102158783610abd565b6103f487878787878787610bc7565b5050505050505050565b60008385101580156104105750600084115b6104355760405162461bcd60e51b815260040161042c90612982565b60405180910390fd5b848314801561044357508482145b61045f5760405162461bcd60e51b815260040161042c90612566565b60ff851061047f5760405162461bcd60e51b815260040161042c906125e9565b5060015b949350505050565b8351602085012060006104a389898985898989610bc7565b90506103458187610abd565b6104c38760200151518651855185516103fe565b5060006104cf886107a8565b905060006104dc82610de0565b60028111156104e757fe5b14156104fc576104f78188610e2b565b61052b565b600161050782610de0565b600281111561051257fe5b1415610522576104f78188610846565b61052b8161080f565b600061053c888888858d8a8a610889565b9050600061054f828b6020015186610e6a565b9050827f1f9f029de8ab3f81b5381a9bc066b421d0f215db28cc8160ec346bc6f0463c6e8a8c6080015142018460008c60ff16118f8e8d8d60405161059b989796959493929190612b85565b60405180910390a26106136040518060a001604052808b65ffffffffffff1681526020018c60800151420165ffffffffffff168152602001848152602001836001600160a01b031681526020018a60018c5103815181106105f857fe5b60200260200101516000015180519060200120815250610ecb565b60009384526020849052604090932092909255505050505050505050565b600080600061063f84610f30565b9196909550909350915050565b6000610657846107a8565b905060008061066583610f30565b508651518051602091820120818901515180519201919091208a51939550919350916000906106a4908690888c8c865b60200201516020015188610f4e565b905060006106c26001808801908d906020020151898d8d6001610695565b905061070d6040518060a001604052808865ffffffffffff1681526020018765ffffffffffff1681526020018481526020018e6001600160a01b031681526020018681525088610fe5565b60208a0151805165ffffffffffff60018901168161072757fe5b068151811061073257fe5b60200260200101516001600160a01b031661074d828a610ff8565b6001600160a01b0316146107735760405162461bcd60e51b815260040161042c906129f8565b61078c8a60200151518c8b896001018e606001516109ea565b5061079a87876001016108ef565b505050505050505050505050565b60006107b261021e565b8251146107d15760405162461bcd60e51b815260040161042c90612472565b6107d961021e565b60208084015160408086015190516107f2949301612b0f565b604051602081830303815290604052805190602001209050919050565b600261081a82610de0565b600281111561082557fe5b14156108435760405162461bcd60e51b815260040161042c9061249d565b50565b600061085183610f30565b505090508065ffffffffffff168265ffffffffffff16116108845760405162461bcd60e51b815260040161042c906123cf565b505050565b6000606061089a89898989896110b4565b90506108ad898660200151838787611285565b6108c95760405162461bcd60e51b815260040161042c90612662565b806001825103815181106108d957fe5b6020026020010151915050979650505050505050565b6040805160a08101825265ffffffffffff8316815260006020820181905291810182905260608101829052608081019190915261092b90610ecb565b60008084815260200190815260200160002081905550817f07da0a0674fb921e484018c8b81d80e292745e5d8ed134b580c8b9c631c5e9e0826040516109719190612b40565b60405180910390a25050565b600261098882610de0565b600281111561099357fe5b146108435760405162461bcd60e51b815260040161042c90612952565b6000818152602081905260409020546109ca90839061135b565b6109e65760405162461bcd60e51b815260040161042c90612884565b5050565b6000806109f98787878761136f565b90506001816001811115610a0957fe5b1415610ab0578451602086015160405163fd7a2f6560e01b81526001600160a01b0386169263fd7a2f6592610a449289908d90600401612ace565b60206040518083038186803b158015610a5c57600080fd5b505afa158015610a70573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610a949190611c19565b610ab05760405162461bcd60e51b815260040161042c90612500565b5060019695505050505050565b606081806020019051810190610ad39190611b3a565b905060005b8151811015610bc157610ae96115ca565b828281518110610af557fe5b602002602001015160200151806020019051810190610b149190611ccd565b805190915060ff16610ba057828281518110610b2c57fe5b6020026020010151600001516001600160a01b031663022cbbe88683602001516040518363ffffffff1660e01b8152600401610b699291906122a7565b600060405180830381600087803b158015610b8357600080fd5b505af1158015610b97573d6000803e3d6000fd5b50505050610bb8565b60405162461bcd60e51b815260040161042c90612406565b50600101610ad8565b50505050565b6000610bd2876107a8565b9050610bdd8161080f565b610bf38760200151518560ff16845186516103fe565b508360ff168860010165ffffffffffff161015610c225760405162461bcd60e51b815260040161042c90612372565b610c2b876107a8565b9050610c368161080f565b60608460ff166001600160401b0381118015610c5157600080fd5b50604051908082528060200260200182016040528015610c7b578160200160208202803683370190505b50905060005b8560ff168165ffffffffffff161015610d1d576040518060a001604052808760ff16836001018d010365ffffffffffff16815260200160011515815260200184815260200189815260200188815250604051602001610ce09190612a8a565b60405160208183030381529060405280519060200120828265ffffffffffff1681518110610d0a57fe5b6020908102919091010152600101610c81565b50610d2f898960200151838688611285565b610d4b5760405162461bcd60e51b815260040161042c906128d2565b6040805160a08101825260008082524265ffffffffffff166020830152918101829052606081019190915260808101879052610d8690610ecb565b60008084815260200190815260200160002081905550817f4f465027a3d06ea73dd12be0f5c5fc0a34e21f19d6eaed4834a7a944edabc90142604051610dcc9190612b40565b60405180910390a250979650505050505050565b600080610dec83610f30565b5091505065ffffffffffff8116610e07576000915050610e26565b428165ffffffffffff1611610e20576002915050610e26565b60019150505b919050565b6000610e3683610f30565b505090508065ffffffffffff168265ffffffffffff1610156108845760405162461bcd60e51b815260040161042c906124c9565b6000610e9c84604051602001610e8091906122c0565b6040516020818303038152906040528051906020012083610ff8565b9050610ea88184611453565b610ec45760405162461bcd60e51b815260040161042c9061262b565b9392505050565b805160208083015160405160009360d01b6001600160d01b03191660a092831b65ffffffffffff60a01b161792610f0491869101612a3f565b60408051601f1981840301815291905280516020909101206001600160a01b0316919091179392505050565b60009081526020819052604090205460d081901c9160a082901c9190565b60006040518060a001604052808865ffffffffffff16815260200187151581526020018681526020018560800151866060015186604051602001610f9493929190612b53565b60405160208183030381529060405280519060200120815260200183815250604051602001610fc39190612a8a565b6040516020818303038152906040528051906020012090509695505050505050565b610fef82826109b0565b6109e6816114a9565b6000808360405160200161100c9190612254565b60405160208183030381529060405280519060200120905060006001828560000151866020015187604001516040516000815260200160405260405161105594939291906122ea565b6020604051602081039080840390855afa158015611077573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166110aa5760405162461bcd60e51b815260040161042c9061276d565b9150505b92915050565b60608085516001600160401b03811180156110ce57600080fd5b506040519080825280602002602001820160405280156110f8578160200160208202803683370190505b509050600160ff86168803016000805b88518165ffffffffffff161015611277578089518b0360010101915061118a828465ffffffffffff168465ffffffffffff16101589898d8665ffffffffffff168151811061115257fe5b6020026020010151602001518e8765ffffffffffff168151811061117257fe5b60200260200101516000015180519060200120610f4e565b848265ffffffffffff168151811061119e57fe5b6020026020010181815250508965ffffffffffff168265ffffffffffff16101561126f5761126d86602001515160405180604001604052808665ffffffffffff168665ffffffffffff1610151515151581526020018665ffffffffffff168660010165ffffffffffff1610151515151581525060405180604001604052808d8665ffffffffffff168151811061123057fe5b602002602001015181526020018d8660010165ffffffffffff168151811061125457fe5b6020026020010151815250856001018a606001516109ea565b505b600101611108565b509198975050505050505050565b8351835160009190611299848984846114dc565b6112b55760405162461bcd60e51b815260040161042c9061291d565b60005b8281101561134c576000611308888784815181106112d257fe5b602002602001015160ff16815181106112e757fe5b60200260200101518884815181106112fb57fe5b6020026020010151610ff8565b905088828151811061131657fe5b60200260200101516001600160a01b0316816001600160a01b031614611343576000945050505050610362565b506001016112b8565b50600198975050505050505050565b60008161136784610ecb565b149392505050565b6020830151600090156113b2576113918360015b602002015151845151611566565b6113ad5760405162461bcd60e51b815260040161042c90612809565b611448565b8351156113d15760405162461bcd60e51b815260040161042c90612798565b846002028265ffffffffffff161015611440576113ef836001611383565b61140b5760405162461bcd60e51b815260040161042c9061268e565b6020838101518101518451909101516114249190611566565b6113ad5760405162461bcd60e51b815260040161042c90612308565b506001610483565b506000949350505050565b6000805b825181101561149f5782818151811061146c57fe5b60200260200101516001600160a01b0316846001600160a01b031614156114975760019150506110ae565b600101611457565b5060009392505050565b60016114b482610de0565b60028111156114bf57fe5b146108435760405162461bcd60e51b815260040161042c90612537565b6000828551146114fe5760405162461bcd60e51b815260040161042c90612700565b60005b8381101561155a57600084828765ffffffffffff168701038161152057fe5b069050838188848151811061153157fe5b602002602001015160ff1601600101101561155157600092505050610483565b50600101611501565b50600195945050505050565b81518151600091600191811480831461158257600092506115c0565b600160208701838101602088015b6002848385100114156115bb5780518351146115af5760009650600093505b60209283019201611590565b505050505b5090949350505050565b60408051808201909152600081526060602082015290565b8035610e2681612d0a565b600082601f8301126115fd578081fd5b604051604081018181106001600160401b038211171561161957fe5b8060405250809150828460408501111561163257600080fd5b60005b600281101561165e57813561164981612d1f565b83526020928301929190910190600101611635565b50505092915050565b600082601f830112611677578081fd5b813561168a61168582612ca0565b612c7d565b81815291506020808301908481016060808502870183018810156116ad57600080fd5b60005b858110156116d4576116c289846119a3565b855293830193918101916001016116b0565b50505050505092915050565b600082601f8301126116f0578081fd5b604051604081018181106001600160401b038211171561170c57fe5b6040529050808260005b600281101561165e5761172c8683358701611a00565b83526020928301929190910190600101611716565b600082601f830112611751578081fd5b813561175f61168582612ca0565b818152915060208083019084810160005b8481101561179957611787888484358a0101611a00565b84529282019290820190600101611770565b505050505092915050565b600082601f8301126117b4578081fd5b81356117c261168582612ca0565b8181529150602080830190848101818402860182018710156117e357600080fd5b60005b848110156117995781356117f981612d2d565b845292820192908201906001016117e6565b600082601f83011261181b578081fd5b813561182961168582612cbd565b915080825283602082850101111561184057600080fd5b8060208401602084013760009082016020015292915050565b600082601f830112611869578081fd5b815161187761168582612cbd565b915080825283602082850101111561188e57600080fd5b61189f816020840160208601612cde565b5092915050565b600060a082840312156118b7578081fd5b60405160a081016001600160401b0382821081831117156118d457fe5b81604052829350843583526020915081850135818111156118f457600080fd5b85019050601f8101861361190757600080fd5b803561191561168582612ca0565b81815283810190838501858402850186018a101561193257600080fd5b600094505b8385101561195e57803561194a81612d0a565b835260019490940193918501918501611937565b508085870152505050505061197560408401611a82565b6040820152611986606084016115e2565b606082015261199760808401611a82565b60808201525092915050565b6000606082840312156119b4578081fd5b604051606081018181106001600160401b03821117156119d057fe5b60405290508082356119e181612d2d565b8082525060208301356020820152604083013560408201525092915050565b600060408284031215611a11578081fd5b604051604081016001600160401b038282108183111715611a2e57fe5b816040528293508435915080821115611a4657600080fd5b611a528683870161180b565b83526020850135915080821115611a6857600080fd5b50611a758582860161180b565b6020830152505092915050565b803565ffffffffffff81168114610e2657600080fd5b8035610e2681612d2d565b60008060008060006101008688031215611abb578081fd5b8535611ac681612d0a565b9450611ad587602088016115ed565b935060608601356001600160401b0380821115611af0578283fd5b611afc89838a016118a6565b94506080880135915080821115611b11578283fd5b50611b1e888289016116e0565b925050611b2e8760a088016119a3565b90509295509295909350565b60006020808385031215611b4c578182fd5b82516001600160401b0380821115611b62578384fd5b818501915085601f830112611b75578384fd5b8151611b8361168582612ca0565b81815284810190848601875b84811015611c0a5781518701604080601f19838f03011215611baf578a8bfd5b80518181018181108a82111715611bc257fe5b8252828b0151611bd181612d0a565b8152908201519088821115611be4578b8cfd5b611bf28e8c84860101611859565b818c0152865250509287019290870190600101611b8f565b50909998505050505050505050565b600060208284031215611c2a578081fd5b8151610ec481612d1f565b600060208284031215611c46578081fd5b5035919050565b60008060008060008060c08789031215611c65578384fd5b86359550611c7560208801611a82565b9450611c8360408801611a82565b9350606087013592506080870135611c9a81612d0a565b915060a08701356001600160401b03811115611cb4578182fd5b611cc089828a0161180b565b9150509295509295509295565b600060208284031215611cde578081fd5b81516001600160401b0380821115611cf4578283fd5b9083019060408286031215611d07578283fd5b604051604081018181108382111715611d1c57fe5b6040528251611d2a81612d2d565b8152602083015182811115611d3d578485fd5b611d4987828601611859565b60208301525095945050505050565b60008060008060008060c08789031215611d70578384fd5b86356001600160401b0380821115611d86578586fd5b611d928a838b016118a6565b9750611da060208a01611a82565b96506040890135915080821115611db5578586fd5b611dc18a838b01611741565b9550611dcf60608a01611a98565b94506080890135915080821115611de4578384fd5b611df08a838b01611667565b935060a0890135915080821115611e05578283fd5b50611cc089828a016117a4565b6000806000806000806000610120888a031215611e2d578485fd5b87356001600160401b0380821115611e43578687fd5b611e4f8b838c016118a6565b9850611e5d60208b01611a82565b975060408a0135915080821115611e72578687fd5b611e7e8b838c01611741565b9650611e8c60608b01611a98565b955060808a0135915080821115611ea1578283fd5b611ead8b838c01611667565b945060a08a0135915080821115611ec2578283fd5b50611ecf8a828b016117a4565b925050611edf8960c08a016119a3565b905092959891949750929550565b600080600080600060c08688031215611f04578283fd5b85359450611f1587602088016115ed565b935060608601356001600160401b03811115611f2f578384fd5b611f3b888289016116e0565b935050611f4a60808701611a82565b915060a0860135611f5a81612d0a565b809150509295509295909350565b60008060008060808587031215611f7d578182fd5b5050823594602084013594506040840135936060013592509050565b600080600080600080600060e0888a031215611fb3578081fd5b611fbc88611a82565b965060208801356001600160401b0380821115611fd7578283fd5b611fe38b838c016118a6565b975060408a0135965060608a0135955060808a0135915061200382612d2d565b90935060a08901359080821115612018578283fd5b6120248b838c016117a4565b935060c08a0135915080821115612039578283fd5b506120468a828b01611667565b91505092959891949750929550565b600080600080600080600060e0888a03121561206f578081fd5b61207888611a82565b965060208801356001600160401b0380821115612093578283fd5b61209f8b838c016118a6565b975060408a0135965060608a01359150808211156120bb578283fd5b6120c78b838c0161180b565b95506120d560808b01611a98565b945060a08a0135915080821115612018578283fd5b6000815180845260208085019450808401835b838110156121225781516001600160a01b0316875295820195908201906001016120fd565b509495945050505050565b6000815180845260208085019450808401835b83811015612122578151805160ff16885283810151848901526040908101519088015260609096019590820190600101612140565b6000815180845260208085018081965082840281019150828601855b858110156121bb5782840389526121a9848351612226565b98850198935090840190600101612191565b5091979650505050505050565b6000815180845260208085019450808401835b8381101561212257815160ff16875295820195908201906001016121db565b60008151808452612212816020860160208601612cde565b601f01601f19169290920160200192915050565b600081516040845261223b60408501826121fa565b90506020830151848203602086015261036282826121fa565b7f19457468657265756d205369676e6564204d6573736167653a0a3332000000008152601c810191909152603c0190565b901515815260200190565b90815260200190565b918252602082015260400190565b60008382526040602083015261048360408301846121fa565b90815260406020820181905260099082015268666f7263654d6f766560b81b606082015260800190565b93845260ff9290921660208401526040830152606082015260800190565b60208082526044908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206360408201527f68616e676520746865206170704461746120647572696e6720736574757020706060820152636861736560e01b608082015260a00190565b6020808252603d908201527f6c6172676573745475726e4e756d202b2031206d75737420626520677265617460408201527f6572207468616e206f7220657175616c20746f206e756d537461746573000000606082015260800190565b6020808252601c908201527f7475726e4e756d5265636f7264206e6f7420696e637265617365642e00000000604082015260600190565b60208082526046908201527f5f7472616e73666572416c6c46726f6d416c6c4173736574486f6c646572733a60408201527f2041737365744f7574636f6d6554797065206973206e6f7420616e20616c6c6f60608201526531b0ba34b7b760d11b608082015260a00190565b602080825260119082015270125b98dbdc9c9958dd0818da185a5b9259607a1b604082015260600190565b60208082526012908201527121b430b73732b6103334b730b634bd32b21760711b604082015260600190565b60208082526018908201527f7475726e4e756d5265636f7264206465637265617365642e0000000000000000604082015260600190565b6020808252601f908201527f496e76616c696420466f7263654d6f7665417070205472616e736974696f6e00604082015260600190565b60208082526015908201527427379037b733b7b4b7339031b430b63632b733b29760591b604082015260600190565b6020808252605e908201527f466f7263654d6f7665207c20526571756972652065786163746c79203120736960408201527f676e617475726520706572207061727469636970616e7420262077686f20736960608201527f676e6564207768617420666f7220616c6c207061727469636970616e74730000608082015260a00190565b60208082526022908201527f466f7263654d6f7665207c20546f6f206d616e79207061727469636970616e74604082015261732160f01b606082015260800190565b6020808252601f908201527f4368616c6c656e676572206973206e6f742061207061727469636970616e7400604082015260600190565b602080825260129082015271496e76616c6964207369676e61747572657360701b604082015260600190565b6020808252604c908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206360408201527f68616e6765207468652064656661756c74206f7574636f6d6520647572696e6760608201526b20736574757020706861736560a01b608082015260a00190565b60208082526047908201527f5f76616c69645369676e6174757265733a2077686f5369676e6564576861742060408201527f6d757374206265207468652073616d65206c656e677468206173207061727469606082015266636970616e747360c81b608082015260a00190565b602080825260119082015270496e76616c6964207369676e617475726560781b604082015260600190565b6020808252604b908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206d60408201527f6f76652066726f6d20612066696e616c20737461746520746f2061206e6f6e2060608201526a66696e616c20737461746560a81b608082015260a00190565b60208082526055908201527f496e76616c69645472616e736974696f6e4572726f723a2043616e6e6f74206d60408201527f6f766520746f20612066696e616c2073746174652077697468206120646966666060820152746572656e742064656661756c74206f7574636f6d6560581b608082015260a00190565b6020808252602e908201527f4368616e6e656c2073746f7261676520646f6573206e6f74206d61746368207360408201526d3a37b932b2103b32b939b4b7b71760911b606082015260800190565b6020808252602b908201527f496e76616c6964207369676e617475726573204f5220697346696e616c3d747260408201526a1d5948195e1c1958dd195960aa1b606082015260800190565b6020808252818101527f556e61636365707461626c652077686f5369676e656457686174206172726179604082015260600190565b60208082526016908201527521b430b73732b6103737ba103334b730b634bd32b21760511b604082015260600190565b60208082526050908201527f466f7263654d6f7665207c20596f75206d757374207375626d6974206174206c60408201527f65617374206f6e6520627574206e6f206d6f7265207468616e206e756d50617260608201526f7469636970616e74732073746174657360801b608082015260a00190565b60208082526027908201527f526573706f6e7365206e6f74207369676e656420627920617574686f72697a65604082015266321036b7bb32b960c91b606082015260800190565b815165ffffffffffff908116825260208084015190911690820152604080830151908201526060808301516001600160a01b0316908201526080918201519181019190915260a00190565b600060a08201905065ffffffffffff835116825260208301511515602083015260408301516040830152606083015160608301526080830151608083015292915050565b600060808252612ae16080830187612226565b8281036020840152612af38187612226565b65ffffffffffff95909516604084015250506060015292915050565b600084825260606020830152612b2860608301856120ea565b905065ffffffffffff83166040830152949350505050565b65ffffffffffff91909116815260200190565b65ffffffffffff841681526001600160a01b0383166020820152606060408201819052600090610362908301846121fa565b600061010065ffffffffffff808c168452808b16602085015260018060a01b03808b16604086015289151560608601528260808601528851838601526020890151925060a0610120860152612bde6101a08601846120ea565b92508160408a0151166101408601528060608a01511661016086015250806080890151166101808501525082810360a0840152612c1b8187612175565b905082810360c0840152612c2f818661212d565b905082810360e0840152612c4381856121c8565b9b9a5050505050505050505050565b65ffffffffffff93841681529190921660208201526001600160a01b03909116604082015260600190565b6040518181016001600160401b0381118282101715612c9857fe5b604052919050565b60006001600160401b03821115612cb357fe5b5060209081020190565b60006001600160401b03821115612cd057fe5b50601f01601f191660200190565b60005b83811015612cf9578181015183820152602001612ce1565b83811115610bc15750506000910152565b6001600160a01b038116811461084357600080fd5b801515811461084357600080fd5b60ff8116811461084357600080fdfea264697066735822122096b5a3db9cbf7cb6026375eaf24030a4e0682cf549a6833f9101bae2b88a961c64736f6c63430007040033

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.