ETH Price: $3,391.45 (+1.56%)

Contract

0x38dD48C3dBE8A9968aF34e05F1b4439990E8a4aB
 
Transaction Hash
Method
Block
From
To
Dispute Channel122063262021-04-09 15:03:271359 days ago1617980607IN
0x38dD48C3...990E8a4aB
0 ETH0.01877412125
Withdraw121029152021-03-24 17:23:591375 days ago1616606639IN
0x38dD48C3...990E8a4aB
0 ETH0.02527817193
Deposit Alice121029022021-03-24 17:20:581375 days ago1616606458IN
0x38dD48C3...990E8a4aB
0 ETH0.01242862193

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block
From
To
121028822021-03-24 17:16:041375 days ago1616606164  Contract Creation0 ETH
Loading...
Loading

Minimal Proxy Contract for 0xd105b6b42206dfa6db00e6a4823bc88efac00476

Contract Name:
ChannelMastercopy

Compiler Version
v0.7.1+commit.f4a555be

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 31 : ChannelMastercopy.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/IVectorChannel.sol";
import "./CMCCore.sol";
import "./CMCAsset.sol";
import "./CMCDeposit.sol";
import "./CMCWithdraw.sol";
import "./CMCAdjudicator.sol";

/// @title ChannelMastercopy
/// @author Connext <[email protected]>
/// @notice Contains the logic used by all Vector multisigs. A proxy to this
///         contract is deployed per-channel using the ChannelFactory.sol.
///         Supports channel adjudication logic, deposit logic, and arbitrary
///         calls when a commitment is double-signed.
contract ChannelMastercopy is
    CMCCore,
    CMCAsset,
    CMCDeposit,
    CMCWithdraw,
    CMCAdjudicator,
    IVectorChannel
{

}

File 2 of 31 : IVectorChannel.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./ICMCCore.sol";
import "./ICMCAsset.sol";
import "./ICMCDeposit.sol";
import "./ICMCWithdraw.sol";
import "./ICMCAdjudicator.sol";

interface IVectorChannel is
    ICMCCore,
    ICMCAsset,
    ICMCDeposit,
    ICMCWithdraw,
    ICMCAdjudicator
{}

File 3 of 31 : LibAsset.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./LibERC20.sol";
import "./LibUtils.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";


/// @title LibAsset
/// @author Connext <[email protected]>
/// @notice This library contains helpers for dealing with onchain transfers
///         of in-channel assets. It is designed to safely handle all asset
///         transfers out of channel in the event of an onchain dispute. Also
///         safely handles ERC20 transfers that may be non-compliant
library LibAsset {
    address constant ETHER_ASSETID = address(0);

    function isEther(address assetId) internal pure returns (bool) {
        return assetId == ETHER_ASSETID;
    }

    function getOwnBalance(address assetId) internal view returns (uint256) {
        return
            isEther(assetId)
                ? address(this).balance
                : IERC20(assetId).balanceOf(address(this));
    }

    function transferEther(address payable recipient, uint256 amount)
        internal
        returns (bool)
    {
        (bool success, bytes memory returnData) =
            recipient.call{value: amount}("");
        LibUtils.revertIfCallFailed(success, returnData);
        return true;
    }

    function transferERC20(
        address assetId,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        return LibERC20.transfer(assetId, recipient, amount);
    }

    // This function is a wrapper for transfers of Ether or ERC20 tokens,
    // both standard-compliant ones as well as tokens that exhibit the
    // missing-return-value bug.
    // Although it behaves very much like Solidity's `transfer` function
    // or the ERC20 `transfer` and is, in fact, designed to replace direct
    // usage of those, it is deliberately named `unregisteredTransfer`,
    // because we need to register every transfer out of the channel.
    // Therefore, it should normally not be used directly, with the single
    // exception of the `transferAsset` function in `CMCAsset.sol`,
    // which combines the "naked" unregistered transfer given below
    // with a registration.
    // USING THIS FUNCTION SOMEWHERE ELSE IS PROBABLY WRONG!
    function unregisteredTransfer(
        address assetId,
        address payable recipient,
        uint256 amount
    ) internal returns (bool) {
        return
            isEther(assetId)
                ? transferEther(recipient, amount)
                : transferERC20(assetId, recipient, amount);
    }
}

File 4 of 31 : LibERC20.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./LibUtils.sol";
import "@openzeppelin/contracts/utils/Address.sol";

/// @title LibERC20
/// @author Connext <[email protected]>
/// @notice This library provides several functions to safely handle
///         noncompliant tokens (i.e. does not return a boolean from
///         the transfer function)

library LibERC20 {
    function wrapCall(address assetId, bytes memory callData)
        internal
        returns (bool)
    {
        require(Address.isContract(assetId), "LibERC20: NO_CODE");
        (bool success, bytes memory returnData) = assetId.call(callData);
        LibUtils.revertIfCallFailed(success, returnData);
        return returnData.length == 0 || abi.decode(returnData, (bool));
    }

    function approve(
        address assetId,
        address spender,
        uint256 amount
    ) internal returns (bool) {
        return
            wrapCall(
                assetId,
                abi.encodeWithSignature(
                    "approve(address,uint256)",
                    spender,
                    amount
                )
            );
    }

    function transferFrom(
        address assetId,
        address sender,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        return
            wrapCall(
                assetId,
                abi.encodeWithSignature(
                    "transferFrom(address,address,uint256)",
                    sender,
                    recipient,
                    amount
                )
            );
    }

    function transfer(
        address assetId,
        address recipient,
        uint256 amount
    ) internal returns (bool) {
        return
            wrapCall(
                assetId,
                abi.encodeWithSignature(
                    "transfer(address,uint256)",
                    recipient,
                    amount
                )
            );
    }
}

File 5 of 31 : ICMCCore.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

interface ICMCCore {
    function setup(address _alice, address _bob) external;

    function getAlice() external view returns (address);

    function getBob() external view returns (address);
}

File 6 of 31 : ICMCAsset.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

interface ICMCAsset {
    function getTotalTransferred(address assetId)
        external
        view
        returns (uint256);

    function getExitableAmount(address assetId, address owner)
        external
        view
        returns (uint256);

    function exit(
        address assetId,
        address owner,
        address payable recipient
    ) external;
}

File 7 of 31 : ICMCDeposit.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

interface ICMCDeposit {
    event AliceDeposited(address assetId, uint256 amount);
    
    function getTotalDepositsAlice(address assetId)
        external
        view
        returns (uint256);

    function getTotalDepositsBob(address assetId)
        external
        view
        returns (uint256);

    function depositAlice(address assetId, uint256 amount) external payable;
}

File 8 of 31 : ICMCWithdraw.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

struct WithdrawData {
    address channelAddress;
    address assetId;
    address payable recipient;
    uint256 amount;
    uint256 nonce;
    address callTo;
    bytes callData;
}

interface ICMCWithdraw {
    function getWithdrawalTransactionRecord(WithdrawData calldata wd)
        external
        view
        returns (bool);

    function withdraw(
        WithdrawData calldata wd,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) external;
}

File 9 of 31 : ICMCAdjudicator.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./Types.sol";

interface ICMCAdjudicator {
    struct CoreChannelState {
        address channelAddress;
        address alice;
        address bob;
        address[] assetIds;
        Balance[] balances;
        uint256[] processedDepositsA;
        uint256[] processedDepositsB;
        uint256[] defundNonces;
        uint256 timeout;
        uint256 nonce;
        bytes32 merkleRoot;
    }

    struct CoreTransferState {
        address channelAddress;
        bytes32 transferId;
        address transferDefinition;
        address initiator;
        address responder;
        address assetId;
        Balance balance;
        uint256 transferTimeout;
        bytes32 initialStateHash;
    }

    struct ChannelDispute {
        bytes32 channelStateHash;
        uint256 nonce;
        bytes32 merkleRoot;
        uint256 consensusExpiry;
        uint256 defundExpiry;
    }

    struct TransferDispute {
        bytes32 transferStateHash;
        uint256 transferDisputeExpiry;
        bool isDefunded;
    }

    event ChannelDisputed(
        address disputer,
        CoreChannelState state,
        ChannelDispute dispute
    );

    event ChannelDefunded(
        address defunder,
        CoreChannelState state,
        ChannelDispute dispute,
        address[] assetIds
    );

    event TransferDisputed(
        address disputer,
        CoreTransferState state,
        TransferDispute dispute
    );

    event TransferDefunded(
        address defunder,
        CoreTransferState state,
        TransferDispute dispute,
        bytes encodedInitialState,
        bytes encodedResolver,
        Balance balance
    );

    function getChannelDispute() external view returns (ChannelDispute memory);

    function getDefundNonce(address assetId) external view returns (uint256);

    function getTransferDispute(bytes32 transferId)
        external
        view
        returns (TransferDispute memory);

    function disputeChannel(
        CoreChannelState calldata ccs,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) external;

    function defundChannel(
        CoreChannelState calldata ccs,
        address[] calldata assetIds,
        uint256[] calldata indices
    ) external;

    function disputeTransfer(
        CoreTransferState calldata cts,
        bytes32[] calldata merkleProofData
    ) external;

    function defundTransfer(
        CoreTransferState calldata cts,
        bytes calldata encodedInitialTransferState,
        bytes calldata encodedTransferResolver,
        bytes calldata responderSignature
    ) external;
}

File 10 of 31 : Types.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

struct Balance {
    uint256[2] amount; // [alice, bob] in channel, [initiator, responder] in transfer
    address payable[2] to; // [alice, bob] in channel, [initiator, responder] in transfer
}

File 11 of 31 : LibUtils.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

/// @title LibUtils
/// @author Connext <[email protected]>
/// @notice Contains a helper to revert if a call was not successfully
///         made
library LibUtils {
    // If success is false, reverts and passes on the revert string.
    function revertIfCallFailed(bool success, bytes memory returnData)
        internal
        pure
    {
        if (!success) {
            assembly {
                revert(add(returnData, 0x20), mload(returnData))
            }
        }
    }
}

File 12 of 31 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

File 13 of 31 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly { codehash := extcodehash(account) }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
        (bool success, ) = recipient.call{ value: amount }("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain`call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
      return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
        return _functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        return _functionCallWithValue(target, data, value, errorMessage);
    }

    function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) {
        require(isContract(target), "Address: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = target.call{ value: weiValue }(data);
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly

                // solhint-disable-next-line no-inline-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 14 of 31 : ERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

import "../../GSN/Context.sol";
import "./IERC20.sol";
import "../../math/SafeMath.sol";
import "../../utils/Address.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin guidelines: functions revert instead
 * of returning `false` on failure. This behavior is nonetheless conventional
 * and does not conflict with the expectations of ERC20 applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20 {
    using SafeMath for uint256;
    using Address for address;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;
    uint8 private _decimals;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * To select a different value for {decimals}, use {_setupDecimals}.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (string memory name, string memory symbol) {
        _name = name;
        _symbol = symbol;
        _decimals = 18;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(_msgSender(), recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        _approve(_msgSender(), spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
        _transfer(sender, recipient, amount);
        _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
        return true;
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Sets {decimals} to a value other than the default one of 18.
     *
     * WARNING: This function should only be called from the constructor. Most
     * applications that interact with token contracts will not expect
     * {decimals} to ever change, and may work incorrectly if it does.
     */
    function _setupDecimals(uint8 decimals_) internal {
        _decimals = decimals_;
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be to transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
}

File 15 of 31 : Context.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with GSN meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address payable) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes memory) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

File 16 of 31 : SafeMath.sol
// 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;
    }
}

File 17 of 31 : CMCDeposit.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/ICMCDeposit.sol";
import "./CMCCore.sol";
import "./CMCAsset.sol";
import "./lib/LibAsset.sol";
import "./lib/LibERC20.sol";

/// @title CMCDeposit
/// @author Connext <[email protected]>
/// @notice Contains logic supporting channel multisig deposits. Channel
///         funding is asymmetric, with `alice` having to call a deposit
///         function which tracks the total amount she has deposited so far,
///         and any other funds in the multisig being attributed to `bob`.

contract CMCDeposit is CMCCore, CMCAsset, ICMCDeposit {
    mapping(address => uint256) private depositsAlice;

    receive() external payable onlyViaProxy nonReentrant {}

    function getTotalDepositsAlice(address assetId)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (uint256)
    {
        return _getTotalDepositsAlice(assetId);
    }

    function _getTotalDepositsAlice(address assetId)
        internal
        view
        returns (uint256)
    {
        return depositsAlice[assetId];
    }

    function getTotalDepositsBob(address assetId)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (uint256)
    {
        return _getTotalDepositsBob(assetId);
    }

    // Calculated using invariant onchain properties. Note we DONT use safemath here
    function _getTotalDepositsBob(address assetId)
        internal
        view
        returns (uint256)
    {
        return
            LibAsset.getOwnBalance(assetId) +
            totalTransferred[assetId] -
            depositsAlice[assetId];
    }

    function depositAlice(address assetId, uint256 amount)
        external
        payable
        override
        onlyViaProxy
        nonReentrant
    {
        if (LibAsset.isEther(assetId)) {
            require(msg.value == amount, "CMCDeposit: VALUE_MISMATCH");
        } else {
            // If ETH is sent along, it will be attributed to bob
            require(msg.value == 0, "CMCDeposit: ETH_WITH_ERC_TRANSFER");
            require(
                LibERC20.transferFrom(
                    assetId,
                    msg.sender,
                    address(this),
                    amount
                ),
                "CMCDeposit: ERC20_TRANSFER_FAILED"
            );
        }
        // NOTE: explicitly do NOT use safemath here
        depositsAlice[assetId] += amount;
        emit AliceDeposited(assetId, amount);
    }
}

File 18 of 31 : CMCCore.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/ICMCCore.sol";
import "./ReentrancyGuard.sol";

/// @title CMCCore
/// @author Connext <[email protected]>
/// @notice Contains logic pertaining to the participants of a channel,
///         including setting and retrieving the participants and the
///         mastercopy.

contract CMCCore is ReentrancyGuard, ICMCCore {
    address private immutable mastercopyAddress;

    address internal alice;
    address internal bob;

    /// @notice Set invalid participants to block the mastercopy from being used directly
    ///         Nonzero address also prevents the mastercopy from being setup
    ///         Only setting alice is sufficient, setting bob too wouldn't change anything
    constructor() {
        mastercopyAddress = address(this);
    }

    // Prevents us from calling methods directly from the mastercopy contract
    modifier onlyViaProxy {
        require(
            address(this) != mastercopyAddress,
            "Mastercopy: ONLY_VIA_PROXY"
        );
        _;
    }

    /// @notice Contract constructor for Proxied copies
    /// @param _alice: Address representing user with function deposit
    /// @param _bob: Address representing user with multisig deposit
    function setup(address _alice, address _bob)
        external
        override
        onlyViaProxy
    {
        require(alice == address(0), "CMCCore: ALREADY_SETUP");
        require(
            _alice != address(0) && _bob != address(0),
            "CMCCore: INVALID_PARTICIPANT"
        );
        require(_alice != _bob, "CMCCore: IDENTICAL_PARTICIPANTS");
        ReentrancyGuard.setup();
        alice = _alice;
        bob = _bob;
    }

    /// @notice A getter function for the bob of the multisig
    /// @return Bob's signer address
    function getAlice()
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (address)
    {
        return alice;
    }

    /// @notice A getter function for the bob of the multisig
    /// @return Alice's signer address
    function getBob()
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (address)
    {
        return bob;
    }
}

File 19 of 31 : CMCAsset.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/ICMCAsset.sol";
import "./interfaces/Types.sol";
import "./CMCCore.sol";
import "./lib/LibAsset.sol";
import "./lib/LibMath.sol";
import "@openzeppelin/contracts/math/Math.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/// @title CMCAsset
/// @author Connext <[email protected]>
/// @notice Contains logic to safely transfer channel assets (even if they are
///         noncompliant). During adjudication, balances from defunding the
///         channel or defunding transfers are registered as withdrawable. Once
///         they are registered, the owner (or a watchtower on behalf of the
///         owner), may call `exit` to reclaim funds from the multisig.

contract CMCAsset is CMCCore, ICMCAsset {
    using SafeMath for uint256;
    using LibMath for uint256;

    mapping(address => uint256) internal totalTransferred;
    mapping(address => mapping(address => uint256))
        private exitableAmount;

    function registerTransfer(address assetId, uint256 amount) internal {
        totalTransferred[assetId] += amount;
    }

    function getTotalTransferred(address assetId)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (uint256)
    {
        return totalTransferred[assetId];
    }

    function makeExitable(
        address assetId,
        address recipient,
        uint256 amount
    ) internal {
        exitableAmount[assetId][
            recipient
        ] = exitableAmount[assetId][recipient].satAdd(amount);
    }

    function makeBalanceExitable(
        address assetId,
        Balance memory balance
    ) internal {
        for (uint256 i = 0; i < 2; i++) {
            uint256 amount = balance.amount[i];
            if (amount > 0) {
                makeExitable(assetId, balance.to[i], amount);
            }
        }
    }

    function getExitableAmount(address assetId, address owner)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (uint256)
    {
        return exitableAmount[assetId][owner];
    }

    function getAvailableAmount(address assetId, uint256 maxAmount)
        internal
        view
        returns (uint256)
    {
        // Taking the min protects against the case where the multisig
        // holds less than the amount that is trying to be withdrawn
        // while still allowing the total of the funds to be removed
        // without the transaction reverting.
        return Math.min(maxAmount, LibAsset.getOwnBalance(assetId));
    }

    function transferAsset(
        address assetId,
        address payable recipient,
        uint256 amount
    ) internal {
        registerTransfer(assetId, amount);
        require(
            LibAsset.unregisteredTransfer(assetId, recipient, amount),
            "CMCAsset: TRANSFER_FAILED"
        );
    }

    function exit(
        address assetId,
        address owner,
        address payable recipient
    ) external override onlyViaProxy nonReentrant {
        // Either the owner must be the recipient, or in control
        // of setting the recipient of the funds to whomever they
        // choose
        require(
            msg.sender == owner || owner == recipient,
            "CMCAsset: OWNER_MISMATCH"
        );

        uint256 amount =
            getAvailableAmount(
                assetId,
                exitableAmount[assetId][owner]
            );

        // Revert if amount is 0
        require(amount > 0, "CMCAsset: NO_OP");

        // Reduce the amount claimable from the multisig by the owner
        exitableAmount[assetId][
            owner
        ] = exitableAmount[assetId][owner].sub(amount);

        // Perform transfer
        transferAsset(assetId, recipient, amount);
    }
}

File 20 of 31 : ReentrancyGuard.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

/// @title CMCWithdraw
/// @author Connext <[email protected]>
/// @notice A "mutex" reentrancy guard, heavily influenced by OpenZeppelin.

contract ReentrancyGuard {
    uint256 private constant OPEN = 1;
    uint256 private constant LOCKED = 2;

    uint256 public lock;

    function setup() internal {
        lock = OPEN;
    }

    modifier nonReentrant() {
        require(lock == OPEN, "ReentrancyGuard: REENTRANT_CALL");
        lock = LOCKED;
        _;
        lock = OPEN;
    }

    modifier nonReentrantView() {
        require(lock == OPEN, "ReentrancyGuard: REENTRANT_CALL");
        _;
    }
}

File 21 of 31 : LibMath.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

/// @title LibMath
/// @author Connext <[email protected]>
/// @notice This library allows functions that would otherwise overflow and
///         revert if SafeMath was used to instead return the UINT_MAX. In the
///         adjudicator, this is used to ensure you can get the majority of
///         funds out in the event your balance > UINT_MAX and there is an
///         onchain dispute.
library LibMath {
    /// @dev Returns the maximum uint256 for an addition that would overflow
    ///      (saturation arithmetic)
    function satAdd(uint256 x, uint256 y) internal pure returns (uint256) {
        uint256 sum = x + y;
        return sum >= x ? sum : type(uint256).max;
    }
}

File 22 of 31 : Math.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a >= b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow, so we distribute
        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
    }
}

File 23 of 31 : CMCAdjudicator.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/Commitment.sol";
import "./interfaces/ICMCAdjudicator.sol";
import "./interfaces/ITransferDefinition.sol";
import "./interfaces/Types.sol";
import "./CMCCore.sol";
import "./CMCAsset.sol";
import "./CMCDeposit.sol";
import "./lib/LibChannelCrypto.sol";
import "./lib/LibMath.sol";
import "@openzeppelin/contracts/cryptography/MerkleProof.sol";
import "@openzeppelin/contracts/math/SafeMath.sol";

/// @title CMCAdjudicator
/// @author Connext <[email protected]>
/// @notice Contains logic for disputing a single channel and all active
///         transfers associated with the channel. Contains two major phases:
///         (1) consensus: settle on latest channel state
///         (2) defund: remove assets and dispute active transfers
contract CMCAdjudicator is CMCCore, CMCAsset, CMCDeposit, ICMCAdjudicator {
    using LibChannelCrypto for bytes32;
    using LibMath for uint256;
    using SafeMath for uint256;

    uint256 private constant INITIAL_DEFUND_NONCE = 1;

    ChannelDispute private channelDispute;
    mapping(address => uint256) private defundNonces;
    mapping(bytes32 => TransferDispute) private transferDisputes;

    modifier validateChannel(CoreChannelState calldata ccs) {
        require(
            ccs.channelAddress == address(this) &&
                ccs.alice == alice &&
                ccs.bob == bob,
            "CMCAdjudicator: INVALID_CHANNEL"
        );
        _;
    }

    modifier validateTransfer(CoreTransferState calldata cts) {
        require(
            cts.channelAddress == address(this),
            "CMCAdjudicator: INVALID_TRANSFER"
        );
        _;
    }

    function getChannelDispute()
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (ChannelDispute memory)
    {
        return channelDispute;
    }

    function getDefundNonce(address assetId)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (uint256)
    {
        return defundNonces[assetId];
    }

    function getTransferDispute(bytes32 transferId)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (TransferDispute memory)
    {
        return transferDisputes[transferId];
    }

    function disputeChannel(
        CoreChannelState calldata ccs,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) external override onlyViaProxy nonReentrant validateChannel(ccs) {
        // Generate hash
        bytes32 ccsHash = hashChannelState(ccs);

        // Verify Alice's and Bob's signature on the channel state
        verifySignaturesOnChannelStateHash(ccs, ccsHash, aliceSignature, bobSignature);

        // We cannot dispute a channel in its defund phase
        require(!inDefundPhase(), "CMCAdjudicator: INVALID_PHASE");

        // New nonce must be strictly greater than the stored one
        require(
            channelDispute.nonce < ccs.nonce,
            "CMCAdjudicator: INVALID_NONCE"
        );

        if (!inConsensusPhase()) {
            // We are not already in a dispute
            // Set expiries
            // TODO: offchain-ensure that there can't be an overflow
            channelDispute.consensusExpiry = block.timestamp.add(ccs.timeout);
            channelDispute.defundExpiry = block.timestamp.add(
                ccs.timeout.mul(2)
            );
        }

        // Store newer state
        channelDispute.channelStateHash = ccsHash;
        channelDispute.nonce = ccs.nonce;
        channelDispute.merkleRoot = ccs.merkleRoot;

        // Emit event
        emit ChannelDisputed(msg.sender, ccs, channelDispute);
    }

    function defundChannel(
        CoreChannelState calldata ccs,
        address[] calldata assetIds,
        uint256[] calldata indices
    ) external override onlyViaProxy nonReentrant validateChannel(ccs) {
        // These checks are not strictly necessary, but it's a bit cleaner this way
        require(assetIds.length > 0, "CMCAdjudicator: NO_ASSETS_GIVEN");
        require(
            indices.length <= assetIds.length,
            "CMCAdjudicator: WRONG_ARRAY_LENGTHS"
        );

        // Verify that the given channel state matches the stored one
        require(
            hashChannelState(ccs) == channelDispute.channelStateHash,
            "CMCAdjudicator: INVALID_CHANNEL_HASH"
        );

        // We need to be in defund phase for that
        require(inDefundPhase(), "CMCAdjudicator: INVALID_PHASE");

        // TODO SECURITY: Beware of reentrancy
        // TODO: offchain-ensure that all arrays have the same length:
        // assetIds, balances, processedDepositsA, processedDepositsB, defundNonces
        // Make sure there are no duplicates in the assetIds -- duplicates are often a source of double-spends

        // Defund all assets given
        for (uint256 i = 0; i < assetIds.length; i++) {
            address assetId = assetIds[i];

            // Verify or find the index of the assetId in the ccs.assetIds
            uint256 index;
            if (i < indices.length) {
                // The index was supposedly given -- we verify
                index = indices[i];
                require(
                    assetId == ccs.assetIds[index],
                    "CMCAdjudicator: INDEX_MISMATCH"
                );
            } else {
                // we search through the assets in ccs
                for (index = 0; index < ccs.assetIds.length; index++) {
                    if (assetId == ccs.assetIds[index]) {
                        break;
                    }
                }
            }

            // Now, if `index`  is equal to the number of assets in ccs,
            // then the current asset is not in ccs;
            // otherwise, `index` is the index in ccs for the current asset

            // Check the assets haven't already been defunded + update the
            // defundNonce for that asset
            {
                // Open a new block to avoid "stack too deep" error
                uint256 defundNonce =
                    (index == ccs.assetIds.length)
                        ? INITIAL_DEFUND_NONCE
                        : ccs.defundNonces[index];
                require(
                    defundNonces[assetId] < defundNonce,
                    "CMCAdjudicator: CHANNEL_ALREADY_DEFUNDED"
                );
                defundNonces[assetId] = defundNonce;
            }

            // Get total deposits
            uint256 tdAlice = _getTotalDepositsAlice(assetId);
            uint256 tdBob = _getTotalDepositsBob(assetId);

            Balance memory balance;

            if (index == ccs.assetIds.length) {
                // The current asset is not a part of ccs; refund what has been deposited
                balance = Balance({
                    amount: [tdAlice, tdBob],
                    to: [payable(ccs.alice), payable(ccs.bob)]
                });
            } else {
                // Start with the final balances in ccs
                balance = ccs.balances[index];
                // Add unprocessed deposits
                balance.amount[0] = balance.amount[0].satAdd(
                    tdAlice - ccs.processedDepositsA[index]
                );
                balance.amount[1] = balance.amount[1].satAdd(
                    tdBob - ccs.processedDepositsB[index]
                );
            }

            // Add result to exitable amounts
            makeBalanceExitable(assetId, balance);
        }

        emit ChannelDefunded(
            msg.sender,
            ccs,
            channelDispute,
            assetIds
        );
    }

    function disputeTransfer(
        CoreTransferState calldata cts,
        bytes32[] calldata merkleProofData
    ) external override onlyViaProxy nonReentrant validateTransfer(cts) {
        // Verify that the given transfer state is included in the "finalized" channel state
        bytes32 transferStateHash = hashTransferState(cts);
        verifyMerkleProof(
            merkleProofData,
            channelDispute.merkleRoot,
            transferStateHash
        );

        // The channel needs to be in defund phase for that, i.e. channel state is "finalized"
        require(inDefundPhase(), "CMCAdjudicator: INVALID_PHASE");

        // Get stored dispute for this transfer
        TransferDispute storage transferDispute =
            transferDisputes[cts.transferId];

        // Verify that this transfer has not been disputed before
        require(
            transferDispute.transferDisputeExpiry == 0,
            "CMCAdjudicator: TRANSFER_ALREADY_DISPUTED"
        );

        // Store transfer state and set expiry
        transferDispute.transferStateHash = transferStateHash;
        // TODO: offchain-ensure that there can't be an overflow
        transferDispute.transferDisputeExpiry = block.timestamp.add(
            cts.transferTimeout
        );

        emit TransferDisputed(
            msg.sender,
            cts,
            transferDispute
        );
    }

    function defundTransfer(
        CoreTransferState calldata cts,
        bytes calldata encodedInitialTransferState,
        bytes calldata encodedTransferResolver,
        bytes calldata responderSignature
    ) external override onlyViaProxy nonReentrant validateTransfer(cts) {
        // Get stored dispute for this transfer
        TransferDispute storage transferDispute =
            transferDisputes[cts.transferId];

        // Verify that a dispute for this transfer has already been started
        require(
            transferDispute.transferDisputeExpiry != 0,
            "CMCAdjudicator: TRANSFER_NOT_DISPUTED"
        );

        // Verify that the given transfer state matches the stored one
        require(
            hashTransferState(cts) == transferDispute.transferStateHash,
            "CMCAdjudicator: INVALID_TRANSFER_HASH"
        );

        // We can't defund twice
        require(
            !transferDispute.isDefunded,
            "CMCAdjudicator: TRANSFER_ALREADY_DEFUNDED"
        );
        transferDispute.isDefunded = true;

        Balance memory balance;

        if (block.timestamp < transferDispute.transferDisputeExpiry) {
            // Ensure the correct hash is provided
            require(
                keccak256(encodedInitialTransferState) == cts.initialStateHash,
                "CMCAdjudicator: INVALID_TRANSFER_HASH"
            );
            
            // Before dispute expiry, responder or responder-authorized
            // agent (i.e. watchtower) can resolve
            require(
                msg.sender == cts.responder || cts.initialStateHash.checkSignature(responderSignature, cts.responder),
                "CMCAdjudicator: INVALID_RESOLVER"
            );
            
            ITransferDefinition transferDefinition =
                ITransferDefinition(cts.transferDefinition);
            balance = transferDefinition.resolve(
                abi.encode(cts.balance),
                encodedInitialTransferState,
                encodedTransferResolver
            );
            // Verify that returned balances don't exceed initial balances
            require(
                balance.amount[0].add(balance.amount[1]) <=
                    cts.balance.amount[0].add(cts.balance.amount[1]),
                "CMCAdjudicator: INVALID_BALANCES"
            );
        } else {
            // After dispute expiry, if the responder hasn't resolved, we defund the initial balance
            balance = cts.balance;
        }

        // Depending on previous code path, defund either resolved or initial balance
        makeBalanceExitable(cts.assetId, balance);

        // Emit event
        emit TransferDefunded(
            msg.sender,
            cts,
            transferDispute,
            encodedInitialTransferState,
            encodedTransferResolver,
            balance
        );
    }

    function verifySignaturesOnChannelStateHash(
        CoreChannelState calldata ccs,
        bytes32 ccsHash,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) internal pure {
        bytes32 commitment =
            keccak256(abi.encode(CommitmentType.ChannelState, ccsHash));
        require(
            commitment.checkSignature(aliceSignature, ccs.alice),
            "CMCAdjudicator: INVALID_ALICE_SIG"
        );
        require(
            commitment.checkSignature(bobSignature, ccs.bob),
            "CMCAdjudicator: INVALID_BOB_SIG"
        );
    }

    function verifyMerkleProof(
        bytes32[] calldata proof,
        bytes32 root,
        bytes32 leaf
    ) internal pure {
        require(
            MerkleProof.verify(proof, root, leaf),
            "CMCAdjudicator: INVALID_MERKLE_PROOF"
        );
    }

    function inConsensusPhase() internal view returns (bool) {
        return block.timestamp < channelDispute.consensusExpiry;
    }

    function inDefundPhase() internal view returns (bool) {
        return
            channelDispute.consensusExpiry <= block.timestamp &&
            block.timestamp < channelDispute.defundExpiry;
    }

    function hashChannelState(CoreChannelState calldata ccs)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(ccs));
    }

    function hashTransferState(CoreTransferState calldata cts)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(cts));
    }
}

File 24 of 31 : Commitment.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

enum CommitmentType {ChannelState, WithdrawData}

File 25 of 31 : ITransferDefinition.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./ITransferRegistry.sol";
import "./Types.sol";

interface ITransferDefinition {
    // Validates the initial state of the transfer.
    // Called by validator.ts during `create` updates.
    function create(bytes calldata encodedBalance, bytes calldata)
        external
        view
        returns (bool);

    // Performs a state transition to resolve a transfer and returns final balances.
    // Called by validator.ts during `resolve` updates.
    function resolve(
        bytes calldata encodedBalance,
        bytes calldata,
        bytes calldata
    ) external view returns (Balance memory);

    // Should also have the following properties:
    // string public constant override Name = "...";
    // string public constant override StateEncoding = "...";
    // string public constant override ResolverEncoding = "...";
    // These properties are included on the transfer specifically
    // to make it easier for implementers to add new transfers by
    // only include a `.sol` file
    function Name() external view returns (string memory);

    function StateEncoding() external view returns (string memory);

    function ResolverEncoding() external view returns (string memory);

    function EncodedCancel() external view returns (bytes memory);

    function getRegistryInformation()
        external
        view
        returns (RegisteredTransfer memory);
}

File 26 of 31 : LibChannelCrypto.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/cryptography/ECDSA.sol";
		
/// @author Connext <[email protected]>		
/// @notice This library contains helpers for recovering signatures from a		
///         Vector commitments. Channels do not allow for arbitrary signing of		
///         messages to prevent misuse of private keys by injected providers,		
///         and instead only sign messages with a Vector channel prefix.
library LibChannelCrypto {
    function checkSignature(
        bytes32 hash,
        bytes memory signature,
        address allegedSigner
    ) internal pure returns (bool) {
        return recoverChannelMessageSigner(hash, signature) == allegedSigner;
    }

    function recoverChannelMessageSigner(bytes32 hash, bytes memory signature)
        internal
        pure
        returns (address)
    {
        bytes32 digest = toChannelSignedMessage(hash);
        return ECDSA.recover(digest, signature);
    }

    function toChannelSignedMessage(bytes32 hash)
        internal
        pure
        returns (bytes32)
    {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return
            keccak256(abi.encodePacked("\x16Vector Signed Message:\n32", hash));
    }

    function checkUtilitySignature(
        bytes32 hash,
        bytes memory signature,
        address allegedSigner
    ) internal pure returns (bool) {
        return recoverChannelMessageSigner(hash, signature) == allegedSigner;
    }

    function recoverUtilityMessageSigner(bytes32 hash, bytes memory signature)
        internal
        pure
        returns (address)
    {
        bytes32 digest = toUtilitySignedMessage(hash);
        return ECDSA.recover(digest, signature);
    }

    function toUtilitySignedMessage(bytes32 hash)
        internal
        pure
        returns (bytes32)
    {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return
            keccak256(abi.encodePacked("\x17Utility Signed Message:\n32", hash));
    }
}

File 27 of 31 : MerkleProof.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev These functions deal with verification of Merkle trees (hash trees),
 */
library MerkleProof {
    /**
     * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
     * defined by `root`. For this, a `proof` must be provided, containing
     * sibling hashes on the branch from the leaf to the root of the tree. Each
     * pair of leaves and each pair of pre-images are assumed to be sorted.
     */
    function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
        bytes32 computedHash = leaf;

        for (uint256 i = 0; i < proof.length; i++) {
            bytes32 proofElement = proof[i];

            if (computedHash <= proofElement) {
                // Hash(current computed hash + current element of the proof)
                computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
            } else {
                // Hash(current element of the proof + current computed hash)
                computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
            }
        }

        // Check if the computed hash (root) is equal to the provided root
        return computedHash == root;
    }
}

File 28 of 31 : ITransferRegistry.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental "ABIEncoderV2";

struct RegisteredTransfer {
    string name;
    address definition;
    string stateEncoding;
    string resolverEncoding;
    bytes encodedCancel;
}

interface ITransferRegistry {
    event TransferAdded(RegisteredTransfer transfer);

    event TransferRemoved(RegisteredTransfer transfer);

    // Should add a transfer definition to the registry
    // onlyOwner
    function addTransferDefinition(RegisteredTransfer memory transfer) external;

    // Should remove a transfer definition to the registry
    // onlyOwner
    function removeTransferDefinition(string memory name) external;

    // Should return all transfer defintions in registry
    function getTransferDefinitions()
        external
        view
        returns (RegisteredTransfer[] memory);
}

File 29 of 31 : ECDSA.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.7.0;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        // Check the signature length
        if (signature.length != 65) {
            revert("ECDSA: invalid signature length");
        }

        // Divide the signature in r, s and v variables
        bytes32 r;
        bytes32 s;
        uint8 v;

        // ecrecover takes the signature parameters, and the only way to get them
        // currently is to use assembly.
        // solhint-disable-next-line no-inline-assembly
        assembly {
            r := mload(add(signature, 0x20))
            s := mload(add(signature, 0x40))
            v := byte(0, mload(add(signature, 0x60)))
        }

        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            revert("ECDSA: invalid signature 's' value");
        }

        if (v != 27 && v != 28) {
            revert("ECDSA: invalid signature 'v' value");
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        require(signer != address(0), "ECDSA: invalid signature");

        return signer;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * replicates the behavior of the
     * https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
     * JSON-RPC method.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }
}

File 30 of 31 : CMCWithdraw.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./interfaces/Commitment.sol";
import "./interfaces/ICMCWithdraw.sol";
import "./interfaces/WithdrawHelper.sol";
import "./CMCCore.sol";
import "./CMCAsset.sol";
import "./lib/LibAsset.sol";
import "./lib/LibChannelCrypto.sol";
import "./lib/LibUtils.sol";

/// @title CMCWithdraw
/// @author Connext <[email protected]>
/// @notice Contains logic for all cooperative channel multisig withdrawals.
///         Cooperative withdrawal commitments must be signed by both channel
///         participants. As part of the channel withdrawals, an arbitrary
///         call can be made, which is extracted from the withdraw data.

contract CMCWithdraw is CMCCore, CMCAsset, ICMCWithdraw {
    using LibChannelCrypto for bytes32;

    mapping(bytes32 => bool) private isExecuted;

    modifier validateWithdrawData(WithdrawData calldata wd) {
        require(
            wd.channelAddress == address(this),
            "CMCWithdraw: CHANNEL_MISMATCH"
        );
        _;
    }

    function getWithdrawalTransactionRecord(WithdrawData calldata wd)
        external
        view
        override
        onlyViaProxy
        nonReentrantView
        returns (bool)
    {
        return isExecuted[hashWithdrawData(wd)];
    }

    /// @param wd The withdraw data consisting of
    /// semantic withdraw information, i.e. assetId, recipient, and amount;
    /// information to make an optional call in addition to the actual transfer,
    /// i.e. target address for the call and call payload;
    /// additional information, i.e. channel address and nonce.
    /// @param aliceSignature Signature of owner a
    /// @param bobSignature Signature of owner b
    function withdraw(
        WithdrawData calldata wd,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) external override onlyViaProxy nonReentrant validateWithdrawData(wd) {
        // Generate hash
        bytes32 wdHash = hashWithdrawData(wd);

        // Verify Alice's and Bob's signature on the withdraw data
        verifySignaturesOnWithdrawDataHash(wdHash, aliceSignature, bobSignature);

        // Replay protection
        require(!isExecuted[wdHash], "CMCWithdraw: ALREADY_EXECUTED");
        isExecuted[wdHash] = true;

        // Determine actually transferable amount
        uint256 actualAmount = getAvailableAmount(wd.assetId, wd.amount);

        // Revert if actualAmount is zero && callTo is 0
        require(
            actualAmount > 0 || wd.callTo != address(0),
            "CMCWithdraw: NO_OP"
        );

        // Register and execute the transfer
        transferAsset(wd.assetId, wd.recipient, actualAmount);

        // Do we have to make a call in addition to the actual transfer?
        if (wd.callTo != address(0)) {
            WithdrawHelper(wd.callTo).execute(wd, actualAmount);
        }
    }

    function verifySignaturesOnWithdrawDataHash(
        bytes32 wdHash,
        bytes calldata aliceSignature,
        bytes calldata bobSignature
    ) internal view {
        bytes32 commitment =
            keccak256(abi.encode(CommitmentType.WithdrawData, wdHash));
        require(
            commitment.checkSignature(aliceSignature, alice),
            "CMCWithdraw: INVALID_ALICE_SIG"
        );
        require(
            commitment.checkSignature(bobSignature, bob),
            "CMCWithdraw: INVALID_BOB_SIG"
        );
    }

    function hashWithdrawData(WithdrawData calldata wd)
        internal
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(wd));
    }
}

File 31 of 31 : WithdrawHelper.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.7.1;
pragma experimental ABIEncoderV2;

import "./ICMCWithdraw.sol";

interface WithdrawHelper {
    function execute(WithdrawData calldata wd, uint256 actualAmount) external;
}

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

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"assetId","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AliceDeposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"defunder","type":"address"},{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"},{"internalType":"address[]","name":"assetIds","type":"address[]"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance[]","name":"balances","type":"tuple[]"},{"internalType":"uint256[]","name":"processedDepositsA","type":"uint256[]"},{"internalType":"uint256[]","name":"processedDepositsB","type":"uint256[]"},{"internalType":"uint256[]","name":"defundNonces","type":"uint256[]"},{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"indexed":false,"internalType":"struct ICMCAdjudicator.CoreChannelState","name":"state","type":"tuple"},{"components":[{"internalType":"bytes32","name":"channelStateHash","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"consensusExpiry","type":"uint256"},{"internalType":"uint256","name":"defundExpiry","type":"uint256"}],"indexed":false,"internalType":"struct ICMCAdjudicator.ChannelDispute","name":"dispute","type":"tuple"},{"indexed":false,"internalType":"address[]","name":"assetIds","type":"address[]"}],"name":"ChannelDefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"disputer","type":"address"},{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"},{"internalType":"address[]","name":"assetIds","type":"address[]"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance[]","name":"balances","type":"tuple[]"},{"internalType":"uint256[]","name":"processedDepositsA","type":"uint256[]"},{"internalType":"uint256[]","name":"processedDepositsB","type":"uint256[]"},{"internalType":"uint256[]","name":"defundNonces","type":"uint256[]"},{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"indexed":false,"internalType":"struct ICMCAdjudicator.CoreChannelState","name":"state","type":"tuple"},{"components":[{"internalType":"bytes32","name":"channelStateHash","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"consensusExpiry","type":"uint256"},{"internalType":"uint256","name":"defundExpiry","type":"uint256"}],"indexed":false,"internalType":"struct ICMCAdjudicator.ChannelDispute","name":"dispute","type":"tuple"}],"name":"ChannelDisputed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"defunder","type":"address"},{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address","name":"transferDefinition","type":"address"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"responder","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance","name":"balance","type":"tuple"},{"internalType":"uint256","name":"transferTimeout","type":"uint256"},{"internalType":"bytes32","name":"initialStateHash","type":"bytes32"}],"indexed":false,"internalType":"struct ICMCAdjudicator.CoreTransferState","name":"state","type":"tuple"},{"components":[{"internalType":"bytes32","name":"transferStateHash","type":"bytes32"},{"internalType":"uint256","name":"transferDisputeExpiry","type":"uint256"},{"internalType":"bool","name":"isDefunded","type":"bool"}],"indexed":false,"internalType":"struct ICMCAdjudicator.TransferDispute","name":"dispute","type":"tuple"},{"indexed":false,"internalType":"bytes","name":"encodedInitialState","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"encodedResolver","type":"bytes"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"indexed":false,"internalType":"struct Balance","name":"balance","type":"tuple"}],"name":"TransferDefunded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"disputer","type":"address"},{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address","name":"transferDefinition","type":"address"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"responder","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance","name":"balance","type":"tuple"},{"internalType":"uint256","name":"transferTimeout","type":"uint256"},{"internalType":"bytes32","name":"initialStateHash","type":"bytes32"}],"indexed":false,"internalType":"struct ICMCAdjudicator.CoreTransferState","name":"state","type":"tuple"},{"components":[{"internalType":"bytes32","name":"transferStateHash","type":"bytes32"},{"internalType":"uint256","name":"transferDisputeExpiry","type":"uint256"},{"internalType":"bool","name":"isDefunded","type":"bool"}],"indexed":false,"internalType":"struct ICMCAdjudicator.TransferDispute","name":"dispute","type":"tuple"}],"name":"TransferDisputed","type":"event"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"},{"internalType":"address[]","name":"assetIds","type":"address[]"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance[]","name":"balances","type":"tuple[]"},{"internalType":"uint256[]","name":"processedDepositsA","type":"uint256[]"},{"internalType":"uint256[]","name":"processedDepositsB","type":"uint256[]"},{"internalType":"uint256[]","name":"defundNonces","type":"uint256[]"},{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct ICMCAdjudicator.CoreChannelState","name":"ccs","type":"tuple"},{"internalType":"address[]","name":"assetIds","type":"address[]"},{"internalType":"uint256[]","name":"indices","type":"uint256[]"}],"name":"defundChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address","name":"transferDefinition","type":"address"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"responder","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance","name":"balance","type":"tuple"},{"internalType":"uint256","name":"transferTimeout","type":"uint256"},{"internalType":"bytes32","name":"initialStateHash","type":"bytes32"}],"internalType":"struct ICMCAdjudicator.CoreTransferState","name":"cts","type":"tuple"},{"internalType":"bytes","name":"encodedInitialTransferState","type":"bytes"},{"internalType":"bytes","name":"encodedTransferResolver","type":"bytes"},{"internalType":"bytes","name":"responderSignature","type":"bytes"}],"name":"defundTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositAlice","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"alice","type":"address"},{"internalType":"address","name":"bob","type":"address"},{"internalType":"address[]","name":"assetIds","type":"address[]"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance[]","name":"balances","type":"tuple[]"},{"internalType":"uint256[]","name":"processedDepositsA","type":"uint256[]"},{"internalType":"uint256[]","name":"processedDepositsB","type":"uint256[]"},{"internalType":"uint256[]","name":"defundNonces","type":"uint256[]"},{"internalType":"uint256","name":"timeout","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct ICMCAdjudicator.CoreChannelState","name":"ccs","type":"tuple"},{"internalType":"bytes","name":"aliceSignature","type":"bytes"},{"internalType":"bytes","name":"bobSignature","type":"bytes"}],"name":"disputeChannel","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"address","name":"transferDefinition","type":"address"},{"internalType":"address","name":"initiator","type":"address"},{"internalType":"address","name":"responder","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"components":[{"internalType":"uint256[2]","name":"amount","type":"uint256[2]"},{"internalType":"address payable[2]","name":"to","type":"address[2]"}],"internalType":"struct Balance","name":"balance","type":"tuple"},{"internalType":"uint256","name":"transferTimeout","type":"uint256"},{"internalType":"bytes32","name":"initialStateHash","type":"bytes32"}],"internalType":"struct ICMCAdjudicator.CoreTransferState","name":"cts","type":"tuple"},{"internalType":"bytes32[]","name":"merkleProofData","type":"bytes32[]"}],"name":"disputeTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"}],"name":"exit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAlice","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getBob","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChannelDispute","outputs":[{"components":[{"internalType":"bytes32","name":"channelStateHash","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"uint256","name":"consensusExpiry","type":"uint256"},{"internalType":"uint256","name":"defundExpiry","type":"uint256"}],"internalType":"struct ICMCAdjudicator.ChannelDispute","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"getDefundNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"getExitableAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"getTotalDepositsAlice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"getTotalDepositsBob","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"assetId","type":"address"}],"name":"getTotalTransferred","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"getTransferDispute","outputs":[{"components":[{"internalType":"bytes32","name":"transferStateHash","type":"bytes32"},{"internalType":"uint256","name":"transferDisputeExpiry","type":"uint256"},{"internalType":"bool","name":"isDefunded","type":"bool"}],"internalType":"struct ICMCAdjudicator.TransferDispute","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct WithdrawData","name":"wd","type":"tuple"}],"name":"getWithdrawalTransactionRecord","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_alice","type":"address"},{"internalType":"address","name":"_bob","type":"address"}],"name":"setup","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"channelAddress","type":"address"},{"internalType":"address","name":"assetId","type":"address"},{"internalType":"address payable","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"address","name":"callTo","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"internalType":"struct WithdrawData","name":"wd","type":"tuple"},{"internalType":"bytes","name":"aliceSignature","type":"bytes"},{"internalType":"bytes","name":"bobSignature","type":"bytes"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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