ETH Price: $2,952.85 (+1.39%)

Contract

0x7FC340B0CfbA6071374b777dE3ACb05eb4a91908

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To

There are no matching entries

1 Internal Transaction found.

Latest 1 internal transaction

Parent Transaction Hash Block From To
2791586832024-11-28 10:20:09422 days ago1732789209  Contract Creation0 ETH

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
UnicrowDispute

Compiler Version
v0.8.7+commit.e28d00a7

Optimization Enabled:
Yes with 1200 runs

Other Settings:
default evmVersion
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./interfaces/IUnicrowClaim.sol";
import "./interfaces/IUnicrowDispute.sol";
import "./interfaces/IUnicrowArbitrator.sol";
import "./Unicrow.sol";
import "./UnicrowTypes.sol";

contract UnicrowDispute is IUnicrowDispute, Context, ReentrancyGuard {
    using Address for address payable;

    /// Main Unicrow's escrow contract
    Unicrow public immutable unicrow;

    /// Reference to the contract that manages claims from the escrow
    IUnicrowClaim public immutable unicrowClaim;

    /// Reference to the Arbitration contract
    IUnicrowArbitrator public immutable unicrowArbitrator;

    /// Stores information about which address sent the latest offer to settle a particular escrow identified by its ID
    mapping(uint256 => address) public latestSettlementOfferBy;

    /// Stores information about the splits in the latest offer to settle an escrow identified by its ID
    mapping(uint256 => uint16[2]) public latestSettlementOffer;

    /**
     * @dev Emitted when a challenge is sent for an escrow
     * @param escrowId ID of the challenged escrow
     * @param blockTime Timestamp when the challenge was minted
     * @param escrow information about the challenged escrow
    */
    event Challenge(uint256 indexed escrowId, uint256 blockTime, Escrow escrow);

    /**
     * @dev Settlement offer (i.e. offer to split the escrow by defined shares) was sent by one of the parties
     * @param escrowId ID of the scrow for which a settlement was offered
     * @param blockTime Timestamp for when the offer was minted
     * @param latestSettlementOffer Splits [buyer's split, seller's split] as defined in the offer (in bips)
     * @param latestSettlementOfferBy address which sent the offer
     */
    event SettlementOffer(uint256 indexed escrowId, uint256 blockTime, uint16[2] latestSettlementOffer, address latestSettlementOfferBy);

    /**
     * @dev Settlement offer was approved and the escrow was settled and claimed
     * @param escrowId ID of the escrow
     * @param escrow Details of the escrow
     * @param latestSettlementOffer Splits (in bips) in the settlement offer that was approved
     * @param blockTime Timestamp of when the settlement was minted
     * @param amounts amounts (in token) sent to addresses that were eligible to any shares and fees from the escrow
     */
    event ApproveOffer(uint256 indexed escrowId, Escrow escrow, uint16[2] latestSettlementOffer,uint256 blockTime, uint256[5] amounts);

    /**
     * Constructor sets immutable references to the related Unicrow contracts
     */
    constructor(
        address unicrow_,
        address unicrowClaim_,
        address unicrowArbitrator_
    ) {
        unicrow = Unicrow(payable(unicrow_));
        unicrowClaim = IUnicrowClaim(payable(unicrowClaim_));
        unicrowArbitrator = IUnicrowArbitrator(unicrowArbitrator_);
    }

    /// @inheritdoc IUnicrowDispute
    function challenge(uint256 escrowId) external override nonReentrant {
        address sender = _msgSender();

        Escrow memory escrow = unicrow.getEscrow(escrowId);

        // Only the escrow's seller and buyer can challenge
        require(sender == escrow.seller || sender == escrow.buyer, "1-009");

        // The payment must be either in "Paid" or "Challenged" state
        require(
            escrow.consensus[WHO_SELLER] <= 0 ||
                escrow.consensus[WHO_BUYER] <= 0,
            "1-005"
        );

        // Check that the challenge period is running
        require(block.timestamp <= escrow.challengePeriodEnd, "1-016");
        require(block.timestamp > escrow.challengePeriodStart, "1-019");

        // Prevent reduntant challenge from seller's side
        require(
            sender != escrow.buyer ||
            escrow.consensus[WHO_BUYER] <= 0,
            "1-014"
        );

        // Prevent reduntant challenge from buyer's side
        require(
            sender != escrow.seller ||
            escrow.consensus[WHO_SELLER] <= 0,
            "1-015"
        );

        // Challenge does a few things:
        //   - sets split to 100/0% for the challenging party
        //   - sets the challenging party's consensus to positive and increases it by one
        //   - sets the challenged party consensus to negative
        // This way, if one of the parties has negative consensus, we know the payment is challenged
        //   and the absolute number keeps track of how many challenges have there been
        if (sender == escrow.buyer) {
            escrow.split[WHO_BUYER] = 10000;
            escrow.split[WHO_SELLER] = 0;
            escrow.consensus[WHO_BUYER] = abs8(escrow.consensus[WHO_BUYER]) + 1;
            escrow.consensus[WHO_SELLER] = -(abs8(escrow.consensus[WHO_SELLER]));
        } else if (sender == escrow.seller) {
            escrow.split[WHO_SELLER] = 10000;
            escrow.split[WHO_BUYER] = 0;
            escrow.consensus[WHO_BUYER] = -(abs8(escrow.consensus[WHO_BUYER]));
            escrow.consensus[WHO_SELLER] = abs8(escrow.consensus[WHO_SELLER]) + 1;
        }

        // The new challenge period starts at the end of the current period
        //   and is extended by the time set in the original payment
        uint64 periodStart = escrow.challengePeriodEnd;
        uint64 periodEnd = escrow.challengePeriodEnd + escrow.challengeExtension;

        // Execute the challenge in the main escrow contract
        unicrow.challenge(
            escrowId,
            escrow.split,
            escrow.consensus,
            periodStart,
            periodEnd
        );

        // Update the challenge periods for the returned event
        escrow.challengePeriodStart = periodStart;
        escrow.challengePeriodEnd = periodEnd;

        emit Challenge(escrowId, block.timestamp, escrow);
    }

    /// @inheritdoc IUnicrowDispute
    function offerSettlement(uint256 escrowId, uint16[2] calldata newSplit)
        external
        override
        nonReentrant
    {
        address sender = _msgSender();
        Escrow memory escrow = unicrow.getEscrow(escrowId);

        // Only buyer or seller can offer a settlement
        require(sender == escrow.buyer || sender == escrow.seller, "1-009");

        // Check that the payment has not been released, refunded, or settled already
        require(
            escrow.consensus[WHO_SELLER] <= 0 ||
                escrow.consensus[WHO_BUYER] <= 0,
            "1-005"
        );

        // Proposed splits should equal 100%
        require(newSplit[WHO_BUYER] + newSplit[WHO_SELLER] == 10000, "1-007");

        // Record the latest offer details
        latestSettlementOfferBy[escrowId] = sender;
        latestSettlementOffer[escrowId] = newSplit;

        emit SettlementOffer(escrowId, block.timestamp, newSplit, msg.sender);
    }

    /// @inheritdoc IUnicrowDispute
    function approveSettlement(
        uint256 escrowId,
        uint16[2] calldata validation
    ) external override {
        address sender = _msgSender();

        Escrow memory escrow = unicrow.getEscrow(escrowId);

        address latestSettlementOfferByAddress = latestSettlementOfferBy[escrowId];

        // Only buyer or seller can approve a settlement
        require(sender == escrow.buyer || sender == escrow.seller, "1-009");

        // Check that there's a prior settlement offer
        require(latestSettlementOfferByAddress != address(0), "1-017");

        // Only buyer can approve Seller's offer and vice versa
        require(sender != latestSettlementOfferByAddress, "1-020");

        uint16[2] memory latestOffer = latestSettlementOffer[escrowId];

        // Check that the splits sent for approval are the ones that were offered
        require(
            validation[WHO_BUYER] == latestOffer[WHO_BUYER] &&
            validation[WHO_SELLER] == latestOffer[WHO_SELLER],
            "1-018"
        );

        uint16[4] memory split = escrow.split;

        split[WHO_BUYER] = latestOffer[WHO_BUYER];
        split[WHO_SELLER] = latestOffer[WHO_SELLER];

        // Update buyer and seller consensus to positive numbers
        escrow.consensus[WHO_BUYER] = abs8(escrow.consensus[WHO_BUYER]) + 1;
        escrow.consensus[WHO_SELLER] = abs8(escrow.consensus[WHO_SELLER]);

        // Record the settlement in the main escrow contract
        unicrow.settle(
            escrowId,
            split,
            escrow.consensus
        );

        // Sent shares to all the parties and read the final amounts
        uint256[5] memory amounts = unicrowClaim.claim(escrowId);

        emit ApproveOffer(escrowId, escrow, latestOffer, block.timestamp, amounts);
    }

    /**
     * Get details about the latest settlement offer
     * @param escrowId Id of the escrow to get settlement offer details for
     * @return Returns zero values in the returned object's fields if there's been no offer
     */
    function getSettlementDetails(uint256 escrowId) external view returns (Settlement memory) {
       Settlement memory settlement = Settlement(latestSettlementOfferBy[escrowId], latestSettlementOffer[escrowId]);
       return settlement;
    }
}

File 2 of 15 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        // On the first call to nonReentrant, _notEntered will be true
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;

        _;

        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.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 Contracts guidelines: functions revert
 * instead 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, IERC20Metadata {
    mapping(address => uint256) private _balances;

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

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

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

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override 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 this function is
     * overridden;
     *
     * 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 virtual override returns (uint8) {
        return 18;
    }

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

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

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, 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}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, 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}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        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) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + 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) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `sender` to `recipient`.
     *
     * This 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:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
        }
        _balances[to] += amount;

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, 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:
     *
     * - `account` 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 += amount;
        _balances[account] += amount;
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(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);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
        }
        _totalSupply -= amount;

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(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 Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @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 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 {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been 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 _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @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
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @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");

        (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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.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 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) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)

pragma solidity ^0.8.0;

/**
 * @title Counters
 * @author Matt Condon (@shrugs)
 * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number
 * of elements in a mapping, issuing ERC721 ids, or counting request ids.
 *
 * Include with `using Counters for Counters.Counter;`
 */
library Counters {
    struct Counter {
        // This variable should never be directly accessed by users of the library: interactions must be restricted to
        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add
        // this feature: see https://github.com/ethereum/solidity/issues/4637
        uint256 _value; // default: 0
    }

    function current(Counter storage counter) internal view returns (uint256) {
        return counter._value;
    }

    function increment(Counter storage counter) internal {
        unchecked {
            counter._value += 1;
        }
    }

    function decrement(Counter storage counter) internal {
        uint256 value = counter._value;
        require(value > 0, "Counter: decrement overflow");
        unchecked {
            counter._value = value - 1;
        }
    }

    function reset(Counter storage counter) internal {
        counter._value = 0;
    }
}

// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.8.7;

import "../UnicrowTypes.sol";

interface IUnicrow {
  /**
   * @notice Deposit ETH or SafeERC20 to open a new escrow payment.
   * @notice We don't white- or black-list, but we strongly discourage users from using ERC777 tokens
   * @notice   and any ERC20 tokens which perform extra logic in their transfer functions. 
   * @notice If the balance claiming transaction fails due to the token's contract error or malicious behavior, 
   * @notice   it is not possible to try to claim the balance again.
   * @dev Escrow ID is generated automatically by the contract
   * @param sender An address from which the amount  will be deposited (it may be different to a buyer if e.g. another smart contract is paying on behalf of an end user)
   * @param input Escrow input (seller, marketplace, currency, and challenge period information)
   * @param arbitrator Arbitrator address (submit zero address to not set an arbitrator)
   * @param arbitratorFee Arbitrator Fee
   */
  function pay(
    address sender,
    EscrowInput memory input,
    address arbitrator,
    uint16 arbitratorFee
  ) external payable returns (uint256);

  /**
   * @notice Function called by UnicrowDispute to execute a challenge
   * @dev can be called by UnicrowDispute only
   * @param escrowId ID of the challenged escrow payment
   * @param split New split (bips)
   * @param consensus New consensus
   * @param challengeStart When the new challenge period starts
   * @param challengeEnd When the new challenge period ends
   */
  function challenge(
    uint256 escrowId,
    uint16[4] memory split,
    int16[2] memory consensus,
    uint64 challengeStart,
    uint64 challengeEnd
  ) external;

  /**
   * @notice Refund 100% of the buyer payment (all fees are waived).
   * @dev Can be called only by the Seller
   * @param escrowId ID of the escrow to be refunded
   */
  function refund(uint escrowId) external;

  /**
   * @notice Release the payment to the seller and to all other parties that charge a fee from it.
   * @dev Can be called by the Buyer only
   * @param escrowId ID of the escrow to be released
   */
  function release(uint escrowId) external;

  /**
   * @notice Settle a payment (i.e. split it with arbitrary shares between the buyer and the seller). Fees are reduced proportionally to the seller's share.
   * @dev Can be called only by UnicrowDispute
   * @param escrowId ID of the escrow to be settled
   * @param split New split in bips (total must equal 10000)
   * @param consensus New consensus
   */
  function settle(
    uint256 escrowId,
    uint16[4] memory split,
    int16[2] memory consensus
    ) external;

  /**
   * @notice Calculating the final splits (incl. fees) based on how the payment is concluded.
   * @dev The currentSplit is not expected to equal 100% in total. Buyer and seller splits should equal 100 based
   * on how the payment is settled, other splits represent fees which will get reduced and deducted accordingly
   * @param currentSplit Current splits in bips
   */
  function splitCalculation(
    uint16[5] calldata currentSplit
  ) external returns(uint16[5] memory);

  /**
   * @dev Get the escrow data (without arbitrator or settlement information)
   * @param escrowId ID of the escrow to retrieve information of
   */
  function getEscrow(
    uint256 escrowId
  ) external returns(Escrow memory);

  /**
   * @notice Set the escrow as claimed (i.e. that its balance has been sent to all the parties involved).
   * @dev Callable only by other Unicrow contracts
   * @param escrowId ID of the escrow to set as claimed
   */
  function setClaimed(uint escrowId) external;

  /**
   * @notice Update protocol fee (governance only, cannot be more than 1%)
   * @param fee New protocol fee (bips)
   */
  function updateEscrowFee(uint16 fee) external;

  /**
   * @notice Update governance contract address (governable)
   * @param governance New governance address
   */
  function updateGovernance(address governance) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

import "../UnicrowTypes.sol";

interface IUnicrowArbitrator {
    /**
     * Assigns an arbitrator to an escrow.
     * @dev Called by Unicrow.pay()
     * @param escrowId Id of the escrow
     * @param arbitrator Arbitrator's address
     * @param arbitratorFee Arbitrator fee in bips (can be 0)
      */
    function setArbitrator(uint256 escrowId, address arbitrator, uint16 arbitratorFee) external;

    /**
     * One of the parties (buyer or seller) can call this to propose an arbitrator
     * for an escrow that has no arbitrator defined
     * @param escrowId Id of the escrow
     * @param arbitrator Arbitrator's address
     * @param arbitratorFee Arbitrator fee in bips (can be 0)
      */
    function proposeArbitrator(uint256 escrowId, address arbitrator, uint16 arbitratorFee) external;

    /**
     * Approve an arbitrator proposed by another party (i.e. by seller if buyer proposed, by buyer if seller proposed).
     * @dev To ensure the user approves an arbitrator they wanted, it requires the same parameters as proposal
     * @param escrowId Id of an escrow
     * @param validationAddress Arbitrator's address - will be compared with the existing proposal
     * @param validation Arbitrator's Fee - will be compared with the existing proposal
    */
    function approveArbitrator(uint256 escrowId, address validationAddress, uint16 validation) external;

    /**
     * Arbitrate an payment - to be called only by an escrow's arbitrator
     * @param escrowId Id of an escrow
     * @param newSplit How the payment should be split between buyer [0] and seller [1]. [100, 0] will refund the payment to the buyer, [0, 100] will release it to the seller, anything in between will
     */
    function arbitrate(uint256 escrowId, uint16[2] memory newSplit) external returns (uint256[5] memory);

    /**
     * Get information about proposed or assigned arbitrator.
     * @dev buyerConsensus and sellerConsensus indicate if the arbitrator was only proposed by one of the parties or
     * @dev has been assigned by the mutual consensus
     * @return Arbitrator information.
     * @param escrowId ID of the escrow
     */
    function getArbitratorData(uint256 escrowId) external view returns(Arbitrator memory);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

interface IUnicrowClaim {
    /// @notice Claim multiple escrows.
    /// @dev To save everyone's gas costs, it claims balances and fees of all parties that are eligible for a share from the escrow
    /// @param escrows List of escrows to be claimed.
    function claimMultiple(uint[] memory escrows) external;

    /// @notice Claim a single escrow
    /// @dev To save everyone's gas costs, it claims balances and fees of all parties that are eligible for a share from the escrow
    /// @param escrowId escrow to be claimed
    function claim(uint escrowId) external returns(uint256[5] memory);

    // @notice Update rewards contract pointer (governable)
    // @param crowRewards_ New rewards address
    function updateCrowRewards(address crowRewards_) external;

    // @notice Update staking rewards contract pointer (governable)
    // @param stakingRewards_ New staking rewards address
    function updateStakingRewards(address crowRewards_) external;

    // @notice Update protocol fee collection address (governable)
    // @param protocolFeeAddress_ New protocol fee collection address
    function updateProtocolFeeAddress(address protocolFeeAddress_) external;
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "../UnicrowTypes.sol";

interface IUnicrowDispute {
  /**
   * Challenge a payment. If the challenge is successful (the criteria are met),
   * it sets whoever sent the challenge as a payee and sets a new challenge period
   * @param escrowId Id of the escrow that's being challenged
   */
  function challenge(uint256 escrowId) external;

  /**
   * Send an offer to settle the payment between the buyer and the seller
   * @param escrowId ID of the escrow for which the offer is sent
   * @param newSplit the new settlement proposal ([buyerSplit, sellerSplit] in bips, sum must equal 10000)
   */
  function offerSettlement(uint256 escrowId, uint16[2] memory newSplit) external;

  /**
   * Approve an offer to settle the payment between the buyer and the seller
   * @param escrowId ID of the escrow for which the offer is sent
   * @param validation the settlement proposal that must be equal to an offer sent by the other party
   */
  function approveSettlement(uint256 escrowId,uint16[2] memory validation) external;
}

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.7;

import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./interfaces/IUnicrow.sol";
import "./interfaces/IUnicrowClaim.sol";
import "./interfaces/IUnicrowArbitrator.sol";
import "./UnicrowDispute.sol";
import "./UnicrowTypes.sol";

/// @title The primary Unicrow contract
/// @notice Receives and distributes the payments, maintains and provides information about the escrow records, and allows basic operations
contract Unicrow is ReentrancyGuard, IUnicrow, Context {
    using Counters for Counters.Counter;

    /// Generates unique escrow ID in incremental order
    Counters.Counter public escrowIdCounter;

    /// @notice Arbitrator information and functionality for the escrows
    IUnicrowArbitrator public immutable unicrowArbitrator;

    /// @notice Withdraws payments from the escrows once the criteria are met
    IUnicrowClaim public immutable unicrowClaim;

    /// @notice Dispute resolution, incl. challenges and settlements
    UnicrowDispute public immutable unicrowDispute;

    /// @notice Escrow fee in bips (can never be higher than 100)
    uint16 public protocolFee;

    /// address of a governance contract (multisig initially, DAO governor eventually)
    address public governanceAddress;

    /// storage of the primary escrow data. The key is generated by the contract incrementally
    mapping(uint256 => Escrow) escrows;

    /**
     * @notice Emitted when the payment is deposited into the contract and an escrow record is created
     * @param escrowId Unique, contract-generated escrow record identifier
     * @param blockTime timestamp of the block in which the transaction was included
     * @param escrow Details of the escrow as stored in the contract
     * @param arbitrator Address of an arbitrator (zero is returned if no arbitrator was defined)
     * @param arbitratorFee Arbitrator's fee in bips
     * @param challengePeriod Initial challenge period in seconds
     */
    event Pay(uint256 indexed escrowId, uint256 blockTime, Escrow escrow, address arbitrator, uint256 arbitratorFee, uint256 challengePeriod);

    /**
     * @notice Emitted when the buyer releases the payment manually (regardless of the challenge period)
     * @param escrowId ID of the released escrow payment
     * @param blockTime Timestamp of the block in which the transaction was included
     * @param escrow Details of the released Escrow
     * @param amounts Amounts in token allocated to each party (incl. fees). See UnicrowTypes for mapping of each party (WHO_*)
     */
    event Release(uint256 indexed escrowId, uint256 blockTime, Escrow escrow, uint256[5] amounts);

    /**
     * @notice Emitted when seller fully refunds the payment. Detailed calculated values are not returned because the payment is refunded in full, all fees are waived
     * @param escrowId Id of the refunded payment
     * @param escrow Details of the refunded payment
     * @param blockTime Timestamp of the block in which the transaction was included
     */
    event Refund(uint256 indexed escrowId, Escrow escrow, uint256 blockTime);

    /// The contructor initiates immutable and governed references to other contracts
    constructor(
        address unicrowClaim_,
        address unicrowArbitrator_,
        address unicrowDispute_,
        address governanceAddress_,
        uint16 protocolFee_
    ) {
        unicrowArbitrator = IUnicrowArbitrator(unicrowArbitrator_);
        unicrowClaim = IUnicrowClaim(unicrowClaim_);
        unicrowDispute = UnicrowDispute(unicrowDispute_);
        governanceAddress = governanceAddress_;
        protocolFee = protocolFee_;

        escrowIdCounter.increment();
    }

    /// Check that the governance contract is calling this
    modifier onlyGovernance() {
        require(_msgSender() == governanceAddress);
        _;
    }

    /// Check that Unicrow's claimMultiple contract is calling this
    modifier onlyUnicrowClaim() {
        require(_msgSender() == address(unicrowClaim));
        _;
    }

    /// Check that arbitration or dispute contract is calling this
    modifier onlyUnicrowArbitratorOrDispute() {
        require(_msgSender() == address(unicrowArbitrator) || _msgSender() == address(unicrowDispute));
        _;
    }

    /// Check that dispute contract is calling this
    modifier onlyUnicrowDispute() {
        require(_msgSender() == address(unicrowDispute));
        _;
    }

    /// @inheritdoc IUnicrow
    function pay(
        address sender,
        EscrowInput calldata input,
        address arbitrator,
        uint16 arbitratorFee
    ) external payable override nonReentrant returns (uint256) {
        // Get current escrow id from the incremental counter
        uint256 escrowId = escrowIdCounter.current();

        address buyer = input.buyer;

        // Amount of the payment in ERC20 tokens
        uint amount = input.amount;

        // Make sure there's something left for the seller :-)
        require(arbitratorFee + input.marketplaceFee + protocolFee < 10000, "1-026");

        // Buyer cannot be empty
        require(buyer != address(0), "0-001");

        // Seller cannot be empty
        require(input.seller != address(0), "0-002");

        // Buyer cannot be seller
        require(buyer != input.seller, "0-003");

        // Payment amount must be greater than zero
        require(amount > 0, "0-011");

        // Buyer can't send ETH if currency is not ETH
        if(msg.value > 0) {
            require(input.currency == address(0), "0-010");
        }
        
        // Check if the payment was made in ETH 
        if (input.currency == address(0)) {
            // Amount in the payment metadata must match what was sent
            require(amount == msg.value);
        } else {
            uint balanceBefore = IERC20(input.currency).balanceOf(address(this));

            // If the payment was made in ERC20 and not ETH, execute the transfer
            SafeERC20.safeTransferFrom(
                IERC20(input.currency),
                sender,
                address(this),
                amount
            );

            uint balanceAfter = IERC20(input.currency).balanceOf(address(this));

            // Make sure that the input amount is the amount received
            amount = balanceAfter - balanceBefore;
        }

        // If a marketplace fee was set, ensure a marketplace address was set
        if(input.marketplaceFee > 0) {
            require(input.marketplace != address(0), "0-009");
        }

        // Check if the arbitrator was defined
        if (arbitrator != address(0)) {

            // Arbitrator can't be seller or buyer
            require(arbitrator != buyer && arbitrator != input.seller, "1-027");

            // Set the arbitrator in the arbitrator contract
            unicrowArbitrator.setArbitrator(escrowId, arbitrator, arbitratorFee);
        }

        // Split array is how Unicrow maintains information about seller's and buyer's shares, and the fees
        uint16[4] memory split = [0, 10000, input.marketplaceFee, protocolFee];
        
        // Set initial consensus to buyer = 0, seller = 1
        int16[2] memory consensus = [int16(0), int16(1)];

        // Create an Escrow object that will be stored in the contract
        Escrow memory escrow = Escrow({
            buyer: buyer,
            seller: input.seller,
            currency: input.currency,
            marketplace: input.marketplace,
            marketplaceFee: input.marketplaceFee,
            claimed: 0,
            split: split,
            consensus: consensus,
            challengeExtension: uint64(input.challengeExtension > 0 ? input.challengeExtension : input.challengePeriod),
            challengePeriodStart: uint64(block.timestamp), //challenge start
            challengePeriodEnd: uint64(block.timestamp + input.challengePeriod), //chalenge end
            amount: amount,
            paymentReference: input.paymentReference
        });

        // Store the escrow information
        escrows[escrowId] = escrow;

        // Increase the escrow id counter
        escrowIdCounter.increment();

        emit Pay(escrowId, block.timestamp, escrow, arbitrator, arbitratorFee, input.challengePeriod);
    
        return escrowId;
    }

    /// @inheritdoc IUnicrow
    function refund(uint256 escrowId) external override nonReentrant {
        address sender = _msgSender();

        // Get escrow information from the contract's storage
        Escrow memory escrow = escrows[escrowId];

        Arbitrator memory arbitrator = unicrowArbitrator.getArbitratorData(
            escrowId
        );

        // Only seller/arbitrator or a contract acting on behalf of seller/arbitrator can refund
        require(
            sender == escrow.seller ||
                tx.origin == escrow.seller ||
                sender == arbitrator.arbitrator ||
                tx.origin == arbitrator.arbitrator,
            "1-011"
        );

        // Check that the escrow is not claimed yet
        require(escrow.claimed == 0, "0-005");

        // Set split to 100% to buyer and waive the fees
        escrow.split[WHO_BUYER] = 10000;
        escrow.split[WHO_SELLER] = 0;
        escrow.split[WHO_MARKETPLACE] = 0;
        escrow.split[WHO_PROTOCOL] = 0;
        
        // Keep record of number of challenges (for reputation purposes)
        escrow.consensus[WHO_BUYER] = abs8(escrow.consensus[WHO_BUYER]) + 1;

        // Set escrow consensus based on the number of previous challenges (1 = no challenge)
        escrow.consensus[WHO_SELLER] = abs8(escrow.consensus[WHO_SELLER]);

        // Update splits and consensus information in the storage
        escrows[escrowId].split = escrow.split;
        escrows[escrowId].consensus = escrow.consensus;

        // Update the escrow as claimed in the storage and in the emitted event
        escrows[escrowId].claimed = 1;
        escrow.claimed = 1;

        // Withdraw the amount to the buyer
        if (address(escrow.currency) == address(0)) {
            (bool success, ) = escrow.buyer.call{value: escrow.amount}("");
            require(success, "1-012");
        } else {
            SafeERC20.safeTransfer(
                IERC20(escrow.currency),
                escrow.buyer,
                escrow.amount
            );
        }


        emit Refund(escrowId, escrow, block.timestamp);
    }

    /// @inheritdoc IUnicrow
    function release(uint256 escrowId) external override {
        address sender = _msgSender();
        Escrow memory escrow = escrows[escrowId];

        // Only buyer can release
        require(sender == escrow.buyer, "1-025");

        // Set buyer consensus to 1 or based on the number of previous challenges
        escrow.consensus[WHO_BUYER] = abs8(escrow.consensus[WHO_BUYER]) + 1;

        // Set seller's escrow consensus based on the number of previous challenges
        escrow.consensus[WHO_SELLER] = abs8(escrow.consensus[WHO_SELLER]);

        // Update consensus in the storage
        escrows[escrowId].consensus = escrow.consensus;

        // Claim the payment and fees and get the final amounts
        uint256[5] memory amounts = unicrowClaim.claim(escrowId);

        // Emit all the information including the amounts
        emit Release(escrowId, block.timestamp, escrow, amounts);
    }

    /// @inheritdoc IUnicrow
    function challenge(
        uint256 escrowId,
        uint16[4] calldata split,
        int16[2] calldata consensus,
        uint64 challengeStart,
        uint64 challengeEnd
    ) external override onlyUnicrowDispute {
        escrows[escrowId].split = split;
        escrows[escrowId].consensus = consensus;
        escrows[escrowId].challengePeriodStart = challengeStart;
        escrows[escrowId].challengePeriodEnd = challengeEnd;
    }

    /// @inheritdoc IUnicrow
    function updateEscrowFee(uint16 fee) external override onlyGovernance {
        require(fee <= 100, "0-008");
        protocolFee = fee;
    }

    /// @inheritdoc IUnicrow
    function updateGovernance(address governance) external override onlyGovernance {
        governanceAddress = governance;
    }

    /// @notice Return basic escrow information (excl. arbitration information, settlement offers, and token details)
    /// @param escrowId ID of the escrow to be returned
    function getEscrow(uint256 escrowId)
        external
        override
        view
        returns (Escrow memory)
    {
        return escrows[escrowId];
    }

    /// @notice Return all the escrow data (incl. arbitration information, settlement offers, and token details)
    /// @param escrowId ID of the escrow to be returned
    function getAllEscrowData(uint256 escrowId)
        external
        view
        returns (Data memory)
    {
        address currency = escrows[escrowId].currency;

        // Get information about the ERC20 token (or return ETH)
        Token memory token = Token({
            address_: currency,
            decimals: currency == address(0) ? 18 : ERC20(currency).decimals(),
            symbol: currency == address(0) ? "ETH" : ERC20(currency).symbol()
        });

        Arbitrator memory arbitrator = unicrowArbitrator.getArbitratorData(escrowId);
        Settlement memory settlement = unicrowDispute.getSettlementDetails(escrowId);

        return Data(
            escrows[escrowId],
            arbitrator,
            settlement,
            token
        );
    }

    /// @dev Transfer ether or token from this contract's treasury. Can be called only by Unicrow's Claim contract
    function sendEscrowShare(
        address to,
        uint256 amount,
        address currency
    ) public onlyUnicrowClaim {
         if(currency == address(0)) {
            to.call{value: amount, gas: 5000}("");
         } else {
           SafeERC20.safeTransfer(
                IERC20(currency),
                to,
                amount
            );
         }
     }

    /// @inheritdoc IUnicrow
    function settle(
        uint256 escrowId,
        uint16[4] calldata split,
        int16[2] calldata consensus
    ) external override onlyUnicrowArbitratorOrDispute {
        escrows[escrowId].split = split;
        escrows[escrowId].consensus = consensus;
    }

    /// @inheritdoc IUnicrow
    function splitCalculation(
        uint16[5] calldata currentSplit
    ) external pure override returns (uint16[5] memory) {
        uint16[5] memory split;

        uint16 calculatedArbitratorFee;

        // Discount the protocol fee based on seller's share
        if (currentSplit[WHO_PROTOCOL] > 0) {
            split[WHO_PROTOCOL] = uint16((
                uint256(currentSplit[WHO_PROTOCOL]) *
                    currentSplit[WHO_SELLER]) /
                    _100_PCT_IN_BIPS
            );
        }

        // Discount the marketplace fee based on the seller's share
        if (currentSplit[WHO_MARKETPLACE] > 0) {
            split[WHO_MARKETPLACE] = uint16(
                (uint256(currentSplit[WHO_MARKETPLACE]) *
                    currentSplit[WHO_SELLER]) /
                    _100_PCT_IN_BIPS
            );
        }

        // Calculate the arbitrator fee based on the seller's split
        if (currentSplit[WHO_ARBITRATOR] > 0) {
            calculatedArbitratorFee = uint16(
                (uint256(currentSplit[WHO_ARBITRATOR]) *
                    currentSplit[WHO_SELLER]) /
                    _100_PCT_IN_BIPS
            );
        }

        // Calculate seller's final share by substracting all the fees
        split[WHO_SELLER] = currentSplit[WHO_SELLER] - split[WHO_PROTOCOL] - split[WHO_MARKETPLACE] - calculatedArbitratorFee;
        split[WHO_BUYER] = currentSplit[WHO_BUYER];
        split[WHO_ARBITRATOR] = calculatedArbitratorFee;

        return split;
    }

    /// @inheritdoc IUnicrow
    function setClaimed(uint256 escrowId) external override onlyUnicrowClaim nonReentrant {
        escrows[escrowId].claimed = 1;
    }
}

File 15 of 15 : UnicrowTypes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

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

uint16 constant _100_PCT_IN_BIPS = 10000;

// these constants are used as keys for consensus and split arrays
uint8 constant WHO_BUYER = 0;
uint8 constant WHO_SELLER = 1;
uint8 constant WHO_MARKETPLACE = 2;
uint8 constant WHO_PROTOCOL = 3;
uint8 constant WHO_ARBITRATOR = 4;

/// @dev This is how information about each escrow is stored int he main contract, mapped to escrowId
struct Escrow {
    /// @dev Who sent the payment
    address buyer;

    /// @dev By how much will the challenge period get extended after a challenge (in seconds)
    uint64 challengeExtension;

    /// @dev Whom is the payment for
    address seller;

    /// @dev When does/has the current challenge period start(ed) (seconds in Unix epoch)
    uint64 challengePeriodStart;

    /// @dev Address of a marketplace that has facilitated the trade (0x000...00 if none)
    address marketplace;

    /// @dev Fee for the marketplace (can be 0 even if a marketplace was set but doesn't charge fee)
    uint256 marketplaceFee;

    /// @dev When does the current challenge period end (seconds in Unix epoch)
    uint64 challengePeriodEnd;

    /// @dev Token used in the payment (0x00..00 for ETH)
    address currency;

    /// @dev True if the payment was already withdrawn from the escrow
    uint16 claimed;

    /**
     * @dev Indicates status of the payment from buyer's and seller's side.
     * Negative value means that party was challenged.
     * Examples for various states:
     *  0, 1: Paid - If the payment is claimed after challenge period ends, consensus remains like this
     *  1, 1: Released by buyer
     *  1,-1: 1x Challenged by buyer - If the payment is claimed after CP ends, consensus remains like this
     * -1, 2: 1x Challenged by buyer and 1x by Seller
     *  2,-2: 2x Challenged by buyer, 1x by seller
     *  3, 2: Released, Refunded, or Settled. Deduct 1 from each consensus number to calculate number of challenges
     */
    int16[2] consensus;

    /**
     * @dev Buyer's and Seller's share, and fees, in bips
     * Example of a new payment with 5% marketplace fee, 5% arbitrator fee: [0, 10000, 500, 500]
     * If the payment is refunded: [10000, 0, 0, 0]
     * If the payment is settled (e.g. 20% discount for the buyer): [8000, 2000, 500, 500]
     *
     * Note, that the sum of all splits can equal to more than 100% here.
     * The actual fees and shares are re-calculated when the payment is finally claimed
     */
    uint16[4] split;

    /// @dev amount in the token
    uint256 amount;

    /// @dev Optional text reference can be used to identify the payment or provide information for an arbitrator
    string paymentReference;
}

/// @dev Escrow parameters to be sent along with the deposit
struct EscrowInput {
    /// @dev who's the buyer, i.e. who can release the payment or whom should a refund be sent to. Normally this would be msg.sender but if Unicrow.pay() is called is called via another contract it should be set explicitly to user's EOA. If set to address(0), it defaults to msg.sender
    address buyer;

    /// @dev who should receive the payment
    address seller;

    /// @dev address of a marketplace that has facilitated the payment
    address marketplace;

    /// @dev Fee for the marketplace (can be 0 even if a marketplace was set but doesn't charge fee)
    uint16 marketplaceFee;

    /// @dev Token used in the payment (0x00..00 for ETH)
    address currency;

    /// @dev Initial challenge period (in seconds)
    uint32 challengePeriod;

    /// @dev By how much will the challenge period get extended after a challenge (in seconds)
    uint32 challengeExtension;

    /// @dev Amount in token
    uint256 amount;

    /// @dev Optional text reference can be used to identify the payment or provide information for an arbitrator
    string paymentReference;
}

/// @dev Information about arbitrator proposed or assigned to an escrow.
/// @dev If both buyerConsensus and sellerConsensus are 1, the arbitrator is assigned, otherwise it's only been proposed by the party that has 1
struct Arbitrator {
    /// @dev Address of the arbitrator. 0x00..00 for no arbitrator
    address arbitrator;

    /// @dev Arbitrator's fee in bips. Can be 0
    uint16 arbitratorFee;

    /// @dev Seller's agreement on the arbitrator
    bool sellerConsensus;

    /// @dev Buyer's agreement on the arbitrator
    bool buyerConsensus;

    /// @dev Has the escrow been decided by the arbitrator
    bool arbitrated;
}

/// @dev Stores information about settlement, mapped to escrowId in UnicrowDispute contract
struct Settlement {
    /// @dev address of who sent the latest settlement offer. Returns 0x00..00 if no offer has been made
    address latestSettlementOfferBy;

    /// @dev how the payment was offered to be settled [buyer, seller] in bips
    uint16[2] latestSettlementOffer;
}

/// @dev Information about the token used in the payment is returned in this structure
struct Token {
    address address_;
    uint8 decimals;
    string symbol;
}

/// @dev Superstructure that includes all the information relevant to an escrow
struct Data {
    Escrow escrow;
    Arbitrator arbitrator;
    Settlement settlement;
    Token token;
}

function abs8(int16 x) pure returns (int16) {
    return x >= 0 ? x : -x;
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"unicrow_","type":"address"},{"internalType":"address","name":"unicrowClaim_","type":"address"},{"internalType":"address","name":"unicrowArbitrator_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"escrowId","type":"uint256"},{"components":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint64","name":"challengeExtension","type":"uint64"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint64","name":"challengePeriodStart","type":"uint64"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFee","type":"uint256"},{"internalType":"uint64","name":"challengePeriodEnd","type":"uint64"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"uint16","name":"claimed","type":"uint16"},{"internalType":"int16[2]","name":"consensus","type":"int16[2]"},{"internalType":"uint16[4]","name":"split","type":"uint16[4]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"paymentReference","type":"string"}],"indexed":false,"internalType":"struct Escrow","name":"escrow","type":"tuple"},{"indexed":false,"internalType":"uint16[2]","name":"latestSettlementOffer","type":"uint16[2]"},{"indexed":false,"internalType":"uint256","name":"blockTime","type":"uint256"},{"indexed":false,"internalType":"uint256[5]","name":"amounts","type":"uint256[5]"}],"name":"ApproveOffer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"escrowId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockTime","type":"uint256"},{"components":[{"internalType":"address","name":"buyer","type":"address"},{"internalType":"uint64","name":"challengeExtension","type":"uint64"},{"internalType":"address","name":"seller","type":"address"},{"internalType":"uint64","name":"challengePeriodStart","type":"uint64"},{"internalType":"address","name":"marketplace","type":"address"},{"internalType":"uint256","name":"marketplaceFee","type":"uint256"},{"internalType":"uint64","name":"challengePeriodEnd","type":"uint64"},{"internalType":"address","name":"currency","type":"address"},{"internalType":"uint16","name":"claimed","type":"uint16"},{"internalType":"int16[2]","name":"consensus","type":"int16[2]"},{"internalType":"uint16[4]","name":"split","type":"uint16[4]"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"paymentReference","type":"string"}],"indexed":false,"internalType":"struct Escrow","name":"escrow","type":"tuple"}],"name":"Challenge","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"escrowId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"blockTime","type":"uint256"},{"indexed":false,"internalType":"uint16[2]","name":"latestSettlementOffer","type":"uint16[2]"},{"indexed":false,"internalType":"address","name":"latestSettlementOfferBy","type":"address"}],"name":"SettlementOffer","type":"event"},{"inputs":[{"internalType":"uint256","name":"escrowId","type":"uint256"},{"internalType":"uint16[2]","name":"validation","type":"uint16[2]"}],"name":"approveSettlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"escrowId","type":"uint256"}],"name":"challenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"escrowId","type":"uint256"}],"name":"getSettlementDetails","outputs":[{"components":[{"internalType":"address","name":"latestSettlementOfferBy","type":"address"},{"internalType":"uint16[2]","name":"latestSettlementOffer","type":"uint16[2]"}],"internalType":"struct Settlement","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"latestSettlementOffer","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"latestSettlementOfferBy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"escrowId","type":"uint256"},{"internalType":"uint16[2]","name":"newSplit","type":"uint16[2]"}],"name":"offerSettlement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unicrow","outputs":[{"internalType":"contract Unicrow","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unicrowArbitrator","outputs":[{"internalType":"contract IUnicrowArbitrator","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unicrowClaim","outputs":[{"internalType":"contract IUnicrowClaim","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

60e06040523480156200001157600080fd5b5060405162001b2638038062001b2683398101604081905262000034916200007e565b60016000556001600160601b0319606093841b811660805291831b821660a05290911b1660c052620000c8565b80516001600160a01b03811681146200007957600080fd5b919050565b6000806000606084860312156200009457600080fd5b6200009f8462000061565b9250620000af6020850162000061565b9150620000bf6040850162000061565b90509250925092565b60805160601c60a05160601c60c05160601c6119fc6200012a600039600060d80152600081816101a20152610639015260008181610117015281816102480152818161059e0152818161078701528181610bdd0152610d2701526119fc6000f3fe608060405234801561001057600080fd5b50600436106100a35760003560e01c80639f8621b811610076578063c57086451161005b578063c57086451461018a578063e9db7d791461019d578063fe5e2969146101c457600080fd5b80639f8621b814610162578063ab82d9a01461017757600080fd5b8063325369f6146100a857806349c4920f146100d35780636e4e2934146101125780637e684d0514610139575b600080fd5b6100bb6100b636600461152c565b6101e4565b60405161ffff90911681526020015b60405180910390f35b6100fa7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016100ca565b6100fa7f000000000000000000000000000000000000000000000000000000000000000081565b6100fa6101473660046114e0565b6001602052600090815260409020546001600160a01b031681565b6101756101703660046114f9565b610221565b005b6101756101853660046114e0565b610708565b6101756101983660046114f9565b610ca8565b6100fa7f000000000000000000000000000000000000000000000000000000000000000081565b6101d76101d23660046114e0565b610f8e565b6040516100ca9190611778565b6002602052816000526040600020816002811061020057600080fd5b60109182820401919006600202915091509054906101000a900461ffff1681565b600033604051633e8cf2cb60e11b8152600481018590529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637d19e5969060240160006040518083038186803b15801561028a57600080fd5b505afa15801561029e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c69190810190611387565b60008581526001602052604090205481519192506001600160a01b03908116918482169116148061030c575081604001516001600160a01b0316836001600160a01b0316145b6103455760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b60448201526064015b60405180910390fd5b6001600160a01b03811661039b5760405162461bcd60e51b815260206004820152600560248201527f312d303137000000000000000000000000000000000000000000000000000000604482015260640161033c565b806001600160a01b0316836001600160a01b031614156103fd5760405162461bcd60e51b815260206004820152600560248201527f312d303230000000000000000000000000000000000000000000000000000000604482015260640161033c565b60008581526002602081905260408083208151808301928390529290918285855b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161041e57509495508594506000935061046892505050565b6020908102919091015161ffff1690610483908701876114bc565b61ffff161480156104b0575060208082015161ffff16906104aa90604088019088016114bc565b61ffff16145b6104fc5760405162461bcd60e51b815260206004820152600560248201527f312d303138000000000000000000000000000000000000000000000000000000604482015260640161033c565b610140830151815161ffff9081168252602080840151909116908201526101208401516105309060005b6020020151611024565b61053b9060016118ab565b61012085018051600192830b830b90525161055591610526565b61012085018051600192830b90920b602090920191909152516040517f64166e630000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016916364166e63916105d6918b918691906004016117f8565b600060405180830381600087803b1580156105f057600080fd5b505af1158015610604573d6000803e3d6000fd5b50506040517f379607f5000000000000000000000000000000000000000000000000000000008152600481018a9052600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316915063379607f59060240160a060405180830381600087803b15801561068657600080fd5b505af115801561069a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106be919061130c565b9050877fed011389cb4cfa123cd3830046c5049dd63f7a5844d377d7dfa16390eea03ec2868542856040516106f6949392919061171b565b60405180910390a25050505050505050565b6002600054141561075b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033c565b6002600090815533604051633e8cf2cb60e11b8152600481018490529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637d19e5969060240160006040518083038186803b1580156107c957600080fd5b505afa1580156107dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108059190810190611387565b905080604001516001600160a01b0316826001600160a01b03161480610837575080516001600160a01b038381169116145b61086b5760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b604482015260640161033c565b6101208101516000906001602002015160010b131580610898575061012081015151600060019190910b13155b6108cc5760405162461bcd60e51b8152602060048201526005602482015264312d30303560d81b604482015260640161033c565b8060c0015167ffffffffffffffff1642111561092a5760405162461bcd60e51b815260206004820152600560248201527f312d303136000000000000000000000000000000000000000000000000000000604482015260640161033c565b806060015167ffffffffffffffff1642116109875760405162461bcd60e51b815260206004820152600560248201527f312d303139000000000000000000000000000000000000000000000000000000604482015260640161033c565b80516001600160a01b0383811691161415806109b0575061012081015151600060019190910b13155b6109fc5760405162461bcd60e51b815260206004820152600560248201527f312d303134000000000000000000000000000000000000000000000000000000604482015260640161033c565b80604001516001600160a01b0316826001600160a01b0316141580610a3257506101208101516000906001602002015160010b13155b610a7e5760405162461bcd60e51b815260206004820152600560248201527f312d303135000000000000000000000000000000000000000000000000000000604482015260640161033c565b80516001600160a01b0383811691161415610b00576101408101805161271090525160006020909101819052610120820151610ab991610526565b610ac49060016118ab565b61012082018051600192830b830b905251610ade91610526565b610ae790611965565b610120820151600191820b90910b602090910152610b87565b80604001516001600160a01b0316826001600160a01b03161415610b87576101408101805161271060209091015251600090819052610120820151610b4491610526565b610b4d90611965565b61012082018051600192830b830b905251610b6791610526565b610b729060016118ab565b610120820151600191820b90910b6020909101525b60c08101516020820151600090610b9e9083611916565b6101408401516101208501516040517f0a6b25f20000000000000000000000000000000000000000000000000000000081529293506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692630a6b25f292610c16928a9288908890600401611821565b600060405180830381600087803b158015610c3057600080fd5b505af1158015610c44573d6000803e3d6000fd5b50505067ffffffffffffffff8084166060860152821660c08501525060405185907fe6805f4a09f40fe948bb4b24cc12090c9e4fa755b8329042ba916717f98a9d8f90610c949042908790611868565b60405180910390a250506001600055505050565b60026000541415610cfb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033c565b6002600090815533604051633e8cf2cb60e11b8152600481018590529091506000906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637d19e5969060240160006040518083038186803b158015610d6957600080fd5b505afa158015610d7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da59190810190611387565b905080600001516001600160a01b0316826001600160a01b03161480610de0575080604001516001600160a01b0316826001600160a01b0316145b610e145760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b604482015260640161033c565b6101208101516000906001602002015160010b131580610e41575061012081015151600060019190910b13155b610e755760405162461bcd60e51b8152602060048201526005602482015264312d30303560d81b604482015260640161033c565b610e8560408401602085016114bc565b610e9260208501856114bc565b610e9c91906118f0565b61ffff1661271014610ef05760405162461bcd60e51b815260206004820152600560248201527f312d303037000000000000000000000000000000000000000000000000000000604482015260640161033c565b600084815260016020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038716179055600291829052909120610f46918590611047565b50837fad77a7f72aee179b5a343e49e8b5cdf52d31d42bb43df14f33d26ccb08d0a66e428533604051610f7b939291906117a3565b60405180910390a2505060016000555050565b610f966110e1565b604080518082018252600084815260016020908152838220546001600160a01b031683528582526002808252848320855180870196879052939592850193929091908287855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fdc5750505092909352509195945050505050565b6000808260010b121561103f5761103a82611965565b611041565b815b92915050565b6001830191839082156110d15791602002820160005b838211156110a157833561ffff1683826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261105d565b80156110cf5782816101000a81549061ffff02191690556002016020816001010492830192600103026110a1565b505b506110dd929150611109565b5090565b604051806040016040528060006001600160a01b0316815260200161110461111e565b905290565b5b808211156110dd576000815560010161110a565b60405180604001604052806002906020820280368337509192915050565b80516001600160a01b038116811461115357600080fd5b919050565b600082601f83011261116957600080fd5b6040516040810181811067ffffffffffffffff8211171561118c5761118c61199d565b80604052508083856040860111156111a357600080fd5b6000805b60028110156111d55782518060010b81146111c0578283fd5b845260209384019392909201916001016111a7565b50929695505050505050565b600082601f8301126111f257600080fd5b6040516080810181811067ffffffffffffffff821117156112155761121561199d565b60405280836080810186101561122a57600080fd5b60005b6004811015611256578151611241816119b3565b8352602092830192919091019060010161122d565b509195945050505050565b600082601f83011261127257600080fd5b815167ffffffffffffffff8082111561128d5761128d61199d565b604051601f8301601f19908116603f011681019082821181831017156112b5576112b561199d565b816040528381528660208588010111156112ce57600080fd5b6112df846020830160208901611939565b9695505050505050565b8051611153816119b3565b805167ffffffffffffffff8116811461115357600080fd5b600060a0828403121561131e57600080fd5b82601f83011261132d57600080fd5b60405160a0810181811067ffffffffffffffff821117156113505761135061199d565b604052808360a0810186101561136557600080fd5b60005b6005811015611256578151835260209283019290910190600101611368565b60006020828403121561139957600080fd5b815167ffffffffffffffff808211156113b157600080fd5b9083019061022082860312156113c657600080fd5b6113ce611881565b6113d78361113c565b81526113e5602084016112f4565b60208201526113f66040840161113c565b6040820152611407606084016112f4565b60608201526114186080840161113c565b608082015260a083015160a082015261143360c084016112f4565b60c082015261144460e0840161113c565b60e08201526101006114578185016112e9565b9082015261012061146a87858301611158565b9082015261016061147d878583016111e1565b6101408301526101e084015190820152610200830151828111156114a057600080fd5b6114ac87828601611261565b6101808301525095945050505050565b6000602082840312156114ce57600080fd5b81356114d9816119b3565b9392505050565b6000602082840312156114f257600080fd5b5035919050565b6000806060838503121561150c57600080fd5b823591508360608401111561152057600080fd5b50926020919091019150565b6000806040838503121561153f57600080fd5b50508035926020909101359150565b8060005b6002811015611574578151600190810b85526020948501949092019101611552565b50505050565b8060005b600281101561157457815161ffff1684526020938401939091019060010161157e565b8060005b600481101561157457815161ffff168452602093840193909101906001016115a5565b600081518084526115e0816020860160208601611939565b601f01601f19169290920160200192915050565b80516001600160a01b0316825260006102206020830151611621602086018267ffffffffffffffff169052565b50604083015161163c60408601826001600160a01b03169052565b506060830151611658606086018267ffffffffffffffff169052565b50608083015161167360808601826001600160a01b03169052565b5060a083015160a085015260c083015161169960c086018267ffffffffffffffff169052565b5060e08301516116b460e08601826001600160a01b03169052565b506101008381015161ffff1690850152610120808401516116d78287018261154e565b50506101408301516101606116ee818701836115a1565b8401516101e0860152506101808301516102008501829052611712828601826115c8565b95945050505050565b600061012080835261172f818401886115f4565b91505060206117408184018761157a565b846060840152608083018460005b600581101561176b5781518352918301919083019060010161174e565b5050505095945050505050565b81516001600160a01b03168152602080830151606083019161179c9084018261157a565b5092915050565b8381526080810160208083018560005b60028110156117dd5781356117c7816119b3565b61ffff16835291830191908301906001016117b3565b505050506001600160a01b0383166060830152949350505050565b83815260e0810161180c60208301856115a1565b61181960a083018461154e565b949350505050565b858152610120810161183660208301876115a1565b61184360a083018661154e565b67ffffffffffffffff80851660e0840152808416610100840152509695505050505050565b82815260406020820152600061181960408301846115f4565b6040516101a0810167ffffffffffffffff811182821017156118a5576118a561199d565b60405290565b60008160010b8360010b6000821282617fff038213811516156118d0576118d0611987565b82617fff190382128116156118e7576118e7611987565b50019392505050565b600061ffff80831681851680830382111561190d5761190d611987565b01949350505050565b600067ffffffffffffffff80831681851680830382111561190d5761190d611987565b60005b8381101561195457818101518382015260200161193c565b838111156115745750506000910152565b60008160010b617fff1981141561197e5761197e611987565b60000392915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff811681146119c357600080fd5b5056fea264697066735822122039ec8fd8107cd4e0b60dd4bc92631730876e2d55706e3fe2fc3026c4e807a5db64736f6c63430008070033000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b0000000000000000000000003928c1389e47123238217f1b6d10e42aec516eaf0000000000000000000000003e454e8c0c14e605f93d6eeda474d12ec1daec75

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106100a35760003560e01c80639f8621b811610076578063c57086451161005b578063c57086451461018a578063e9db7d791461019d578063fe5e2969146101c457600080fd5b80639f8621b814610162578063ab82d9a01461017757600080fd5b8063325369f6146100a857806349c4920f146100d35780636e4e2934146101125780637e684d0514610139575b600080fd5b6100bb6100b636600461152c565b6101e4565b60405161ffff90911681526020015b60405180910390f35b6100fa7f0000000000000000000000003e454e8c0c14e605f93d6eeda474d12ec1daec7581565b6040516001600160a01b0390911681526020016100ca565b6100fa7f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b81565b6100fa6101473660046114e0565b6001602052600090815260409020546001600160a01b031681565b6101756101703660046114f9565b610221565b005b6101756101853660046114e0565b610708565b6101756101983660046114f9565b610ca8565b6100fa7f0000000000000000000000003928c1389e47123238217f1b6d10e42aec516eaf81565b6101d76101d23660046114e0565b610f8e565b6040516100ca9190611778565b6002602052816000526040600020816002811061020057600080fd5b60109182820401919006600202915091509054906101000a900461ffff1681565b600033604051633e8cf2cb60e11b8152600481018590529091506000906001600160a01b037f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b1690637d19e5969060240160006040518083038186803b15801561028a57600080fd5b505afa15801561029e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526102c69190810190611387565b60008581526001602052604090205481519192506001600160a01b03908116918482169116148061030c575081604001516001600160a01b0316836001600160a01b0316145b6103455760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b60448201526064015b60405180910390fd5b6001600160a01b03811661039b5760405162461bcd60e51b815260206004820152600560248201527f312d303137000000000000000000000000000000000000000000000000000000604482015260640161033c565b806001600160a01b0316836001600160a01b031614156103fd5760405162461bcd60e51b815260206004820152600560248201527f312d303230000000000000000000000000000000000000000000000000000000604482015260640161033c565b60008581526002602081905260408083208151808301928390529290918285855b82829054906101000a900461ffff1661ffff168152602001906002019060208260010104928301926001038202915080841161041e57509495508594506000935061046892505050565b6020908102919091015161ffff1690610483908701876114bc565b61ffff161480156104b0575060208082015161ffff16906104aa90604088019088016114bc565b61ffff16145b6104fc5760405162461bcd60e51b815260206004820152600560248201527f312d303138000000000000000000000000000000000000000000000000000000604482015260640161033c565b610140830151815161ffff9081168252602080840151909116908201526101208401516105309060005b6020020151611024565b61053b9060016118ab565b61012085018051600192830b830b90525161055591610526565b61012085018051600192830b90920b602090920191909152516040517f64166e630000000000000000000000000000000000000000000000000000000081526001600160a01b037f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b16916364166e63916105d6918b918691906004016117f8565b600060405180830381600087803b1580156105f057600080fd5b505af1158015610604573d6000803e3d6000fd5b50506040517f379607f5000000000000000000000000000000000000000000000000000000008152600481018a9052600092507f0000000000000000000000003928c1389e47123238217f1b6d10e42aec516eaf6001600160a01b0316915063379607f59060240160a060405180830381600087803b15801561068657600080fd5b505af115801561069a573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106be919061130c565b9050877fed011389cb4cfa123cd3830046c5049dd63f7a5844d377d7dfa16390eea03ec2868542856040516106f6949392919061171b565b60405180910390a25050505050505050565b6002600054141561075b5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033c565b6002600090815533604051633e8cf2cb60e11b8152600481018490529091506000906001600160a01b037f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b1690637d19e5969060240160006040518083038186803b1580156107c957600080fd5b505afa1580156107dd573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526108059190810190611387565b905080604001516001600160a01b0316826001600160a01b03161480610837575080516001600160a01b038381169116145b61086b5760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b604482015260640161033c565b6101208101516000906001602002015160010b131580610898575061012081015151600060019190910b13155b6108cc5760405162461bcd60e51b8152602060048201526005602482015264312d30303560d81b604482015260640161033c565b8060c0015167ffffffffffffffff1642111561092a5760405162461bcd60e51b815260206004820152600560248201527f312d303136000000000000000000000000000000000000000000000000000000604482015260640161033c565b806060015167ffffffffffffffff1642116109875760405162461bcd60e51b815260206004820152600560248201527f312d303139000000000000000000000000000000000000000000000000000000604482015260640161033c565b80516001600160a01b0383811691161415806109b0575061012081015151600060019190910b13155b6109fc5760405162461bcd60e51b815260206004820152600560248201527f312d303134000000000000000000000000000000000000000000000000000000604482015260640161033c565b80604001516001600160a01b0316826001600160a01b0316141580610a3257506101208101516000906001602002015160010b13155b610a7e5760405162461bcd60e51b815260206004820152600560248201527f312d303135000000000000000000000000000000000000000000000000000000604482015260640161033c565b80516001600160a01b0383811691161415610b00576101408101805161271090525160006020909101819052610120820151610ab991610526565b610ac49060016118ab565b61012082018051600192830b830b905251610ade91610526565b610ae790611965565b610120820151600191820b90910b602090910152610b87565b80604001516001600160a01b0316826001600160a01b03161415610b87576101408101805161271060209091015251600090819052610120820151610b4491610526565b610b4d90611965565b61012082018051600192830b830b905251610b6791610526565b610b729060016118ab565b610120820151600191820b90910b6020909101525b60c08101516020820151600090610b9e9083611916565b6101408401516101208501516040517f0a6b25f20000000000000000000000000000000000000000000000000000000081529293506001600160a01b037f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b1692630a6b25f292610c16928a9288908890600401611821565b600060405180830381600087803b158015610c3057600080fd5b505af1158015610c44573d6000803e3d6000fd5b50505067ffffffffffffffff8084166060860152821660c08501525060405185907fe6805f4a09f40fe948bb4b24cc12090c9e4fa755b8329042ba916717f98a9d8f90610c949042908790611868565b60405180910390a250506001600055505050565b60026000541415610cfb5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161033c565b6002600090815533604051633e8cf2cb60e11b8152600481018590529091506000906001600160a01b037f000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b1690637d19e5969060240160006040518083038186803b158015610d6957600080fd5b505afa158015610d7d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610da59190810190611387565b905080600001516001600160a01b0316826001600160a01b03161480610de0575080604001516001600160a01b0316826001600160a01b0316145b610e145760405162461bcd60e51b8152602060048201526005602482015264312d30303960d81b604482015260640161033c565b6101208101516000906001602002015160010b131580610e41575061012081015151600060019190910b13155b610e755760405162461bcd60e51b8152602060048201526005602482015264312d30303560d81b604482015260640161033c565b610e8560408401602085016114bc565b610e9260208501856114bc565b610e9c91906118f0565b61ffff1661271014610ef05760405162461bcd60e51b815260206004820152600560248201527f312d303037000000000000000000000000000000000000000000000000000000604482015260640161033c565b600084815260016020908152604080832080547fffffffffffffffffffffffff0000000000000000000000000000000000000000166001600160a01b038716179055600291829052909120610f46918590611047565b50837fad77a7f72aee179b5a343e49e8b5cdf52d31d42bb43df14f33d26ccb08d0a66e428533604051610f7b939291906117a3565b60405180910390a2505060016000555050565b610f966110e1565b604080518082018252600084815260016020908152838220546001600160a01b031683528582526002808252848320855180870196879052939592850193929091908287855b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610fdc5750505092909352509195945050505050565b6000808260010b121561103f5761103a82611965565b611041565b815b92915050565b6001830191839082156110d15791602002820160005b838211156110a157833561ffff1683826101000a81548161ffff021916908361ffff160217905550926020019260020160208160010104928301926001030261105d565b80156110cf5782816101000a81549061ffff02191690556002016020816001010492830192600103026110a1565b505b506110dd929150611109565b5090565b604051806040016040528060006001600160a01b0316815260200161110461111e565b905290565b5b808211156110dd576000815560010161110a565b60405180604001604052806002906020820280368337509192915050565b80516001600160a01b038116811461115357600080fd5b919050565b600082601f83011261116957600080fd5b6040516040810181811067ffffffffffffffff8211171561118c5761118c61199d565b80604052508083856040860111156111a357600080fd5b6000805b60028110156111d55782518060010b81146111c0578283fd5b845260209384019392909201916001016111a7565b50929695505050505050565b600082601f8301126111f257600080fd5b6040516080810181811067ffffffffffffffff821117156112155761121561199d565b60405280836080810186101561122a57600080fd5b60005b6004811015611256578151611241816119b3565b8352602092830192919091019060010161122d565b509195945050505050565b600082601f83011261127257600080fd5b815167ffffffffffffffff8082111561128d5761128d61199d565b604051601f8301601f19908116603f011681019082821181831017156112b5576112b561199d565b816040528381528660208588010111156112ce57600080fd5b6112df846020830160208901611939565b9695505050505050565b8051611153816119b3565b805167ffffffffffffffff8116811461115357600080fd5b600060a0828403121561131e57600080fd5b82601f83011261132d57600080fd5b60405160a0810181811067ffffffffffffffff821117156113505761135061199d565b604052808360a0810186101561136557600080fd5b60005b6005811015611256578151835260209283019290910190600101611368565b60006020828403121561139957600080fd5b815167ffffffffffffffff808211156113b157600080fd5b9083019061022082860312156113c657600080fd5b6113ce611881565b6113d78361113c565b81526113e5602084016112f4565b60208201526113f66040840161113c565b6040820152611407606084016112f4565b60608201526114186080840161113c565b608082015260a083015160a082015261143360c084016112f4565b60c082015261144460e0840161113c565b60e08201526101006114578185016112e9565b9082015261012061146a87858301611158565b9082015261016061147d878583016111e1565b6101408301526101e084015190820152610200830151828111156114a057600080fd5b6114ac87828601611261565b6101808301525095945050505050565b6000602082840312156114ce57600080fd5b81356114d9816119b3565b9392505050565b6000602082840312156114f257600080fd5b5035919050565b6000806060838503121561150c57600080fd5b823591508360608401111561152057600080fd5b50926020919091019150565b6000806040838503121561153f57600080fd5b50508035926020909101359150565b8060005b6002811015611574578151600190810b85526020948501949092019101611552565b50505050565b8060005b600281101561157457815161ffff1684526020938401939091019060010161157e565b8060005b600481101561157457815161ffff168452602093840193909101906001016115a5565b600081518084526115e0816020860160208601611939565b601f01601f19169290920160200192915050565b80516001600160a01b0316825260006102206020830151611621602086018267ffffffffffffffff169052565b50604083015161163c60408601826001600160a01b03169052565b506060830151611658606086018267ffffffffffffffff169052565b50608083015161167360808601826001600160a01b03169052565b5060a083015160a085015260c083015161169960c086018267ffffffffffffffff169052565b5060e08301516116b460e08601826001600160a01b03169052565b506101008381015161ffff1690850152610120808401516116d78287018261154e565b50506101408301516101606116ee818701836115a1565b8401516101e0860152506101808301516102008501829052611712828601826115c8565b95945050505050565b600061012080835261172f818401886115f4565b91505060206117408184018761157a565b846060840152608083018460005b600581101561176b5781518352918301919083019060010161174e565b5050505095945050505050565b81516001600160a01b03168152602080830151606083019161179c9084018261157a565b5092915050565b8381526080810160208083018560005b60028110156117dd5781356117c7816119b3565b61ffff16835291830191908301906001016117b3565b505050506001600160a01b0383166060830152949350505050565b83815260e0810161180c60208301856115a1565b61181960a083018461154e565b949350505050565b858152610120810161183660208301876115a1565b61184360a083018661154e565b67ffffffffffffffff80851660e0840152808416610100840152509695505050505050565b82815260406020820152600061181960408301846115f4565b6040516101a0810167ffffffffffffffff811182821017156118a5576118a561199d565b60405290565b60008160010b8360010b6000821282617fff038213811516156118d0576118d0611987565b82617fff190382128116156118e7576118e7611987565b50019392505050565b600061ffff80831681851680830382111561190d5761190d611987565b01949350505050565b600067ffffffffffffffff80831681851680830382111561190d5761190d611987565b60005b8381101561195457818101518382015260200161193c565b838111156115745750506000910152565b60008160010b617fff1981141561197e5761197e611987565b60000392915050565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b61ffff811681146119c357600080fd5b5056fea264697066735822122039ec8fd8107cd4e0b60dd4bc92631730876e2d55706e3fe2fc3026c4e807a5db64736f6c63430008070033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b0000000000000000000000003928c1389e47123238217f1b6d10e42aec516eaf0000000000000000000000003e454e8c0c14e605f93d6eeda474d12ec1daec75

-----Decoded View---------------
Arg [0] : unicrow_ (address): 0xDb815D9bEaAa8d3bdc714Be3a17dCBA5eCbe876B
Arg [1] : unicrowClaim_ (address): 0x3928C1389E47123238217F1B6D10e42Aec516EAF
Arg [2] : unicrowArbitrator_ (address): 0x3E454e8c0c14e605F93D6eEda474d12Ec1dAEc75

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000db815d9beaaa8d3bdc714be3a17dcba5ecbe876b
Arg [1] : 0000000000000000000000003928c1389e47123238217f1b6d10e42aec516eaf
Arg [2] : 0000000000000000000000003e454e8c0c14e605f93d6eeda474d12ec1daec75


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
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  ]

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.