ETH Price: $3,317.35 (-0.33%)

Contract

0xb8901acB165ed027E32754E0FFe830802919727f
 

Overview

ETH Balance

6,651.883156801750120887 ETH

Eth Value

$22,066,613.76 (@ $3,317.35/ETH)

Token Holdings

Transaction Hash
Method
Block
From
To
Bond Withdrawal214631992024-12-23 5:48:1112 secs ago1734932891IN
Hop Protocol: Ethereum Bridge
0 ETH0.000420173.63991227
Bond Withdrawal214631982024-12-23 5:47:5924 secs ago1734932879IN
Hop Protocol: Ethereum Bridge
0 ETH0.000506553.60702767
Bond Withdrawal214631942024-12-23 5:47:111 min ago1734932831IN
Hop Protocol: Ethereum Bridge
0 ETH0.000444553.85074618
Settle Bonded Wi...214631792024-12-23 5:44:114 mins ago1734932651IN
Hop Protocol: Ethereum Bridge
0 ETH0.015663883.55479328
Bond Transfer Ro...214630962024-12-23 5:27:3520 mins ago1734931655IN
Hop Protocol: Ethereum Bridge
0 ETH0.000760774.39720996
Bond Withdrawal214630852024-12-23 5:24:5923 mins ago1734931499IN
Hop Protocol: Ethereum Bridge
0 ETH0.000588834.1929346
Bond Withdrawal214630352024-12-23 5:14:5933 mins ago1734930899IN
Hop Protocol: Ethereum Bridge
0 ETH0.000651684.64046328
Bond Withdrawal214630332024-12-23 5:14:3533 mins ago1734930875IN
Hop Protocol: Ethereum Bridge
0 ETH0.000554174.80021536
Bond Withdrawal214630302024-12-23 5:13:5934 mins ago1734930839IN
Hop Protocol: Ethereum Bridge
0 ETH0.000521044.51327233
Bond Withdrawal214630292024-12-23 5:13:4734 mins ago1734930827IN
Hop Protocol: Ethereum Bridge
0 ETH0.000637424.53815966
Bond Withdrawal214630222024-12-23 5:12:2336 mins ago1734930743IN
Hop Protocol: Ethereum Bridge
0 ETH0.000482274.17747275
Bond Withdrawal214630152024-12-23 5:10:5937 mins ago1734930659IN
Hop Protocol: Ethereum Bridge
0 ETH0.000559693.98510078
Bond Withdrawal214630132024-12-23 5:10:3537 mins ago1734930635IN
Hop Protocol: Ethereum Bridge
0 ETH0.000460633.99001975
Bond Withdrawal214630102024-12-23 5:09:5938 mins ago1734930599IN
Hop Protocol: Ethereum Bridge
0 ETH0.000461343.99620409
Bond Withdrawal214630092024-12-23 5:09:4738 mins ago1734930587IN
Hop Protocol: Ethereum Bridge
0 ETH0.000476554.12836307
Bond Withdrawal214630082024-12-23 5:09:3538 mins ago1734930575IN
Hop Protocol: Ethereum Bridge
0 ETH0.000472474.09260103
Bond Withdrawal214630072024-12-23 5:09:2339 mins ago1734930563IN
Hop Protocol: Ethereum Bridge
0 ETH0.000592624.21953398
Bond Withdrawal214630012024-12-23 5:08:1140 mins ago1734930491IN
Hop Protocol: Ethereum Bridge
0 ETH0.000484194.19407098
Bond Withdrawal214629982024-12-23 5:07:3540 mins ago1734930455IN
Hop Protocol: Ethereum Bridge
0 ETH0.000483284.18621895
Bond Withdrawal214629972024-12-23 5:07:2341 mins ago1734930443IN
Hop Protocol: Ethereum Bridge
0 ETH0.000470674.07701305
Bond Transfer Ro...214629902024-12-23 5:05:5942 mins ago1734930359IN
Hop Protocol: Ethereum Bridge
0 ETH0.001255314.04262491
Bond Withdrawal214629872024-12-23 5:05:2343 mins ago1734930323IN
Hop Protocol: Ethereum Bridge
0 ETH0.000544144.71432307
Bond Withdrawal214629852024-12-23 5:04:5943 mins ago1734930299IN
Hop Protocol: Ethereum Bridge
0 ETH0.00066534.73703859
Bond Withdrawal214629742024-12-23 5:02:4745 mins ago1734930167IN
Hop Protocol: Ethereum Bridge
0 ETH0.000558474.83753206
Bond Withdrawal214629662024-12-23 5:01:1147 mins ago1734930071IN
Hop Protocol: Ethereum Bridge
0 ETH0.000538684.66609246
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
214631992024-12-23 5:48:1112 secs ago1734932891
Hop Protocol: Ethereum Bridge
0.00066509 ETH
214631992024-12-23 5:48:1112 secs ago1734932891
Hop Protocol: Ethereum Bridge
0.09835574 ETH
214631982024-12-23 5:47:5924 secs ago1734932879
Hop Protocol: Ethereum Bridge
0.00067646 ETH
214631982024-12-23 5:47:5924 secs ago1734932879
Hop Protocol: Ethereum Bridge
0.00229416 ETH
214631942024-12-23 5:47:111 min ago1734932831
Hop Protocol: Ethereum Bridge
0.00063962 ETH
214631942024-12-23 5:47:111 min ago1734932831
Hop Protocol: Ethereum Bridge
0.00235034 ETH
214631502024-12-23 5:38:2310 mins ago1734932303
Hop Protocol: Ethereum Bridge
0.03899694 ETH
214630852024-12-23 5:24:5923 mins ago1734931499
Hop Protocol: Ethereum Bridge
0.0007049 ETH
214630852024-12-23 5:24:5923 mins ago1734931499
Hop Protocol: Ethereum Bridge
0.00328172 ETH
214630352024-12-23 5:14:5933 mins ago1734930899
Hop Protocol: Ethereum Bridge
0.00074978 ETH
214630352024-12-23 5:14:5933 mins ago1734930899
Hop Protocol: Ethereum Bridge
0.00523015 ETH
214630332024-12-23 5:14:3533 mins ago1734930875
Hop Protocol: Ethereum Bridge
0.0007359 ETH
214630332024-12-23 5:14:3533 mins ago1734930875
Hop Protocol: Ethereum Bridge
0.00315027 ETH
214630302024-12-23 5:13:5934 mins ago1734930839
Hop Protocol: Ethereum Bridge
0.00074961 ETH
214630302024-12-23 5:13:5934 mins ago1734930839
Hop Protocol: Ethereum Bridge
0.0012312 ETH
214630292024-12-23 5:13:4734 mins ago1734930827
Hop Protocol: Ethereum Bridge
0.00069597 ETH
214630292024-12-23 5:13:4734 mins ago1734930827
Hop Protocol: Ethereum Bridge
0.10824931 ETH
214630222024-12-23 5:12:2336 mins ago1734930743
Hop Protocol: Ethereum Bridge
0.00071377 ETH
214630222024-12-23 5:12:2336 mins ago1734930743
Hop Protocol: Ethereum Bridge
0.0707706 ETH
214630152024-12-23 5:10:5937 mins ago1734930659
Hop Protocol: Ethereum Bridge
0.00067809 ETH
214630152024-12-23 5:10:5937 mins ago1734930659
Hop Protocol: Ethereum Bridge
0.00099222 ETH
214630132024-12-23 5:10:3537 mins ago1734930635
Hop Protocol: Ethereum Bridge
0.00067809 ETH
214630132024-12-23 5:10:3537 mins ago1734930635
Hop Protocol: Ethereum Bridge
0.00075479 ETH
214630102024-12-23 5:09:5938 mins ago1734930599
Hop Protocol: Ethereum Bridge
0.00069384 ETH
214630102024-12-23 5:09:5938 mins ago1734930599
Hop Protocol: Ethereum Bridge
0.00409981 ETH
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
L1_ETH_Bridge

Compiler Version
v0.6.12+commit.27d51765

Optimization Enabled:
Yes with 50000 runs

Other Settings:
default evmVersion
File 1 of 8 : L1_ETH_Bridge.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./L1_Bridge.sol";

/**
 * @dev A L1_Bridge that uses an ETH as the canonical token
 */

contract L1_ETH_Bridge is L1_Bridge {
    constructor (address[] memory bonders, address _governance) public L1_Bridge(bonders, _governance) {}

    /* ========== Override Functions ========== */

    function _transferFromBridge(address recipient, uint256 amount) internal override {
        (bool success, ) = recipient.call{value: amount}(new bytes(0));
        require(success, 'L1_ETH_BRG: ETH transfer failed');
    }

    function _transferToBridge(address /*from*/, uint256 amount) internal override {
        require(msg.value == amount, "L1_ETH_BRG: Value does not match amount");
    }
}

File 2 of 8 : L1_Bridge.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./Bridge.sol";
import "../interfaces/IMessengerWrapper.sol";

/**
 * @dev L1_Bridge is responsible for the bonding and challenging of TransferRoots. All TransferRoots
 * originate in the L1_Bridge through `bondTransferRoot` and are propagated up to destination L2s.
 */

abstract contract L1_Bridge is Bridge {

    struct TransferBond {
        address bonder;
        uint256 createdAt;
        uint256 totalAmount;
        uint256 challengeStartTime;
        address challenger;
        bool challengeResolved;
    }

    /* ========== State ========== */

    mapping(uint256 => mapping(bytes32 => uint256)) public transferRootCommittedAt;
    mapping(bytes32 => TransferBond) public transferBonds;
    mapping(uint256 => mapping(address => uint256)) public timeSlotToAmountBonded;
    mapping(uint256 => uint256) public chainBalance;

    /* ========== Config State ========== */

    address public governance;
    mapping(uint256 => IMessengerWrapper) public crossDomainMessengerWrappers;
    mapping(uint256 => bool) public isChainIdPaused;
    uint256 public challengePeriod = 1 days;
    uint256 public challengeResolutionPeriod = 10 days;
    uint256 public minTransferRootBondDelay = 15 minutes;
    
    uint256 public constant CHALLENGE_AMOUNT_DIVISOR = 10;
    uint256 public constant TIME_SLOT_SIZE = 4 hours;

    /* ========== Events ========== */

    event TransferSentToL2(
        uint256 indexed chainId,
        address indexed recipient,
        uint256 amount,
        uint256 amountOutMin,
        uint256 deadline,
        address indexed relayer,
        uint256 relayerFee
    );

    event TransferRootBonded (
        bytes32 indexed root,
        uint256 amount
    );

    event TransferRootConfirmed(
        uint256 indexed originChainId,
        uint256 indexed destinationChainId,
        bytes32 indexed rootHash,
        uint256 totalAmount
    );

    event TransferBondChallenged(
        bytes32 indexed transferRootId,
        bytes32 indexed rootHash,
        uint256 originalAmount
    );

    event ChallengeResolved(
        bytes32 indexed transferRootId,
        bytes32 indexed rootHash,
        uint256 originalAmount
    );

    /* ========== Modifiers ========== */

    modifier onlyL2Bridge(uint256 chainId) {
        IMessengerWrapper messengerWrapper = crossDomainMessengerWrappers[chainId];
        messengerWrapper.verifySender(msg.sender, msg.data);
        _;
    }

    constructor (address[] memory bonders, address _governance) public Bridge(bonders) {
        governance = _governance;
    }

    /* ========== Send Functions ========== */

    /**
     * @notice `amountOutMin` and `deadline` should be 0 when no swap is intended at the destination.
     * @notice `amount` is the total amount the user wants to send including the relayer fee
     * @dev Send tokens to a supported layer-2 to mint hToken and optionally swap the hToken in the
     * AMM at the destination.
     * @param chainId The chainId of the destination chain
     * @param recipient The address receiving funds at the destination
     * @param amount The amount being sent
     * @param amountOutMin The minimum amount received after attempting to swap in the destination
     * AMM market. 0 if no swap is intended.
     * @param deadline The deadline for swapping in the destination AMM market. 0 if no
     * swap is intended.
     * @param relayer The address of the relayer at the destination.
     * @param relayerFee The amount distributed to the relayer at the destination. This is subtracted from the `amount`.
     */
    function sendToL2(
        uint256 chainId,
        address recipient,
        uint256 amount,
        uint256 amountOutMin,
        uint256 deadline,
        address relayer,
        uint256 relayerFee
    )
        external
        payable
    {
        IMessengerWrapper messengerWrapper = crossDomainMessengerWrappers[chainId];
        require(messengerWrapper != IMessengerWrapper(0), "L1_BRG: chainId not supported");
        require(isChainIdPaused[chainId] == false, "L1_BRG: Sends to this chainId are paused");
        require(amount > 0, "L1_BRG: Must transfer a non-zero amount");
        require(amount >= relayerFee, "L1_BRG: Relayer fee cannot exceed amount");

        _transferToBridge(msg.sender, amount);

        bytes memory message = abi.encodeWithSignature(
            "distribute(address,uint256,uint256,uint256,address,uint256)",
            recipient,
            amount,
            amountOutMin,
            deadline,
            relayer,
            relayerFee
        );

        chainBalance[chainId] = chainBalance[chainId].add(amount);
        messengerWrapper.sendCrossDomainMessage(message);

        emit TransferSentToL2(
            chainId,
            recipient,
            amount,
            amountOutMin,
            deadline,
            relayer,
            relayerFee
        );
    }

    /* ========== TransferRoot Functions ========== */

    /**
     * @dev Setting a TransferRoot is a two step process.
     * @dev   1. The TransferRoot is bonded with `bondTransferRoot`. Withdrawals can now begin on L1
     * @dev      and recipient L2's
     * @dev   2. The TransferRoot is confirmed after `confirmTransferRoot` is called by the l2 bridge
     * @dev      where the TransferRoot originated.
     */

    /**
     * @dev Used by the Bonder to bond a TransferRoot and propagate it up to destination L2s
     * @param rootHash The Merkle root of the TransferRoot Merkle tree
     * @param destinationChainId The id of the destination chain
     * @param totalAmount The amount destined for the destination chain
     */
    function bondTransferRoot(
        bytes32 rootHash,
        uint256 destinationChainId,
        uint256 totalAmount
    )
        external
        onlyBonder
        requirePositiveBalance
    {
        bytes32 transferRootId = getTransferRootId(rootHash, totalAmount);
        require(transferRootCommittedAt[destinationChainId][transferRootId] == 0, "L1_BRG: TransferRoot has already been confirmed");
        require(transferBonds[transferRootId].createdAt == 0, "L1_BRG: TransferRoot has already been bonded");

        uint256 currentTimeSlot = getTimeSlot(block.timestamp);
        uint256 bondAmount = getBondForTransferAmount(totalAmount);
        timeSlotToAmountBonded[currentTimeSlot][msg.sender] = timeSlotToAmountBonded[currentTimeSlot][msg.sender].add(bondAmount);

        transferBonds[transferRootId] = TransferBond(
            msg.sender,
            block.timestamp,
            totalAmount,
            uint256(0),
            address(0),
            false
        );

        _distributeTransferRoot(rootHash, destinationChainId, totalAmount);

        emit TransferRootBonded(rootHash, totalAmount);
    }

    /**
     * @dev Used by an L2 bridge to confirm a TransferRoot via cross-domain message. Once a TransferRoot
     * has been confirmed, any challenge against that TransferRoot can be resolved as unsuccessful.
     * @param originChainId The id of the origin chain
     * @param rootHash The Merkle root of the TransferRoot Merkle tree
     * @param destinationChainId The id of the destination chain
     * @param totalAmount The amount destined for each destination chain
     * @param rootCommittedAt The block timestamp when the TransferRoot was committed on its origin chain
     */
    function confirmTransferRoot(
        uint256 originChainId,
        bytes32 rootHash,
        uint256 destinationChainId,
        uint256 totalAmount,
        uint256 rootCommittedAt
    )
        external
        onlyL2Bridge(originChainId)
    {
        bytes32 transferRootId = getTransferRootId(rootHash, totalAmount);
        require(transferRootCommittedAt[destinationChainId][transferRootId] == 0, "L1_BRG: TransferRoot already confirmed");
        require(rootCommittedAt > 0, "L1_BRG: rootCommittedAt must be greater than 0");
        transferRootCommittedAt[destinationChainId][transferRootId] = rootCommittedAt;
        chainBalance[originChainId] = chainBalance[originChainId].sub(totalAmount, "L1_BRG: Amount exceeds chainBalance. This indicates a layer-2 failure.");

        // If the TransferRoot was never bonded, distribute the TransferRoot.
        TransferBond storage transferBond = transferBonds[transferRootId];
        if (transferBond.createdAt == 0) {
            _distributeTransferRoot(rootHash, destinationChainId, totalAmount);
        }

        emit TransferRootConfirmed(originChainId, destinationChainId, rootHash, totalAmount);
    }

    function _distributeTransferRoot(
        bytes32 rootHash,
        uint256 chainId,
        uint256 totalAmount
    )
        internal
    {
        // Set TransferRoot on recipient Bridge
        if (chainId == getChainId()) {
            // Set L1 TransferRoot
            _setTransferRoot(rootHash, totalAmount);
        } else {
            chainBalance[chainId] = chainBalance[chainId].add(totalAmount);

            IMessengerWrapper messengerWrapper = crossDomainMessengerWrappers[chainId];
            require(messengerWrapper != IMessengerWrapper(0), "L1_BRG: chainId not supported");

            // Set L2 TransferRoot
            bytes memory setTransferRootMessage = abi.encodeWithSignature(
                "setTransferRoot(bytes32,uint256)",
                rootHash,
                totalAmount
            );
            messengerWrapper.sendCrossDomainMessage(setTransferRootMessage);
        }
    }

    /* ========== External TransferRoot Challenges ========== */

    /**
     * @dev Challenge a TransferRoot believed to be fraudulent
     * @param rootHash The Merkle root of the TransferRoot Merkle tree
     * @param originalAmount The total amount bonded for this TransferRoot
     * @param destinationChainId The id of the destination chain
     */
    function challengeTransferBond(bytes32 rootHash, uint256 originalAmount, uint256 destinationChainId) external payable {
        bytes32 transferRootId = getTransferRootId(rootHash, originalAmount);
        TransferBond storage transferBond = transferBonds[transferRootId];

        require(transferRootCommittedAt[destinationChainId][transferRootId] == 0, "L1_BRG: TransferRoot has already been confirmed");
        require(transferBond.createdAt != 0, "L1_BRG: TransferRoot has not been bonded");
        uint256 challengePeriodEnd = transferBond.createdAt.add(challengePeriod);
        require(challengePeriodEnd >= block.timestamp, "L1_BRG: TransferRoot cannot be challenged after challenge period");
        require(transferBond.challengeStartTime == 0, "L1_BRG: TransferRoot already challenged");

        transferBond.challengeStartTime = block.timestamp;
        transferBond.challenger = msg.sender;

        // Move amount from timeSlotToAmountBonded to debit
        uint256 timeSlot = getTimeSlot(transferBond.createdAt);
        uint256 bondAmount = getBondForTransferAmount(originalAmount);
        address bonder = transferBond.bonder;
        timeSlotToAmountBonded[timeSlot][bonder] = timeSlotToAmountBonded[timeSlot][bonder].sub(bondAmount);

        _addDebit(transferBond.bonder, bondAmount);

        // Get stake for challenge
        uint256 challengeStakeAmount = getChallengeAmountForTransferAmount(originalAmount);
        _transferToBridge(msg.sender, challengeStakeAmount);

        emit TransferBondChallenged(transferRootId, rootHash, originalAmount);
    }

    /**
     * @dev Resolve a challenge after the `challengeResolutionPeriod` has passed
     * @param rootHash The Merkle root of the TransferRoot Merkle tree
     * @param originalAmount The total amount originally bonded for this TransferRoot
     * @param destinationChainId The id of the destination chain
     */
    function resolveChallenge(bytes32 rootHash, uint256 originalAmount, uint256 destinationChainId) external {
        bytes32 transferRootId = getTransferRootId(rootHash, originalAmount);
        TransferBond storage transferBond = transferBonds[transferRootId];

        require(transferBond.challengeStartTime != 0, "L1_BRG: TransferRoot has not been challenged");
        require(block.timestamp > transferBond.challengeStartTime.add(challengeResolutionPeriod), "L1_BRG: Challenge period has not ended");
        require(transferBond.challengeResolved == false, "L1_BRG: TransferRoot already resolved");
        transferBond.challengeResolved = true;

        uint256 challengeStakeAmount = getChallengeAmountForTransferAmount(originalAmount);

        if (transferRootCommittedAt[destinationChainId][transferRootId] > 0) {
            // Invalid challenge

            if (transferBond.createdAt > transferRootCommittedAt[destinationChainId][transferRootId].add(minTransferRootBondDelay)) {
                // Credit the bonder back with the bond amount plus the challenger's stake
                _addCredit(transferBond.bonder, getBondForTransferAmount(originalAmount).add(challengeStakeAmount));
            } else {
                // If the TransferRoot was bonded before it was committed, the challenger and Bonder
                // get their stake back. This discourages Bonders from tricking challengers into
                // challenging a valid TransferRoots that haven't yet been committed. It also ensures
                // that Bonders are not punished if a TransferRoot is bonded too soon in error.

                // Return the challenger's stake
                _addCredit(transferBond.challenger, challengeStakeAmount);
                // Credit the bonder back with the bond amount
                _addCredit(transferBond.bonder, getBondForTransferAmount(originalAmount));
            }
        } else {
            // Valid challenge
            // Burn 25% of the challengers stake
            _transferFromBridge(address(0xdead), challengeStakeAmount.mul(1).div(4));
            // Reward challenger with the remaining 75% of their stake plus 100% of the Bonder's stake
            _addCredit(transferBond.challenger, challengeStakeAmount.mul(7).div(4));
        }

        emit ChallengeResolved(transferRootId, rootHash, originalAmount);
    }

    /* ========== Override Functions ========== */

    function _additionalDebit(address bonder) internal view override returns (uint256) {
        uint256 currentTimeSlot = getTimeSlot(block.timestamp);
        uint256 bonded = 0;

        uint256 numTimeSlots = challengePeriod / TIME_SLOT_SIZE;
        for (uint256 i = 0; i < numTimeSlots; i++) {
            bonded = bonded.add(timeSlotToAmountBonded[currentTimeSlot - i][bonder]);
        }

        return bonded;
    }

    function _requireIsGovernance() internal override {
        require(governance == msg.sender, "L1_BRG: Caller is not the owner");
    }

    /* ========== External Config Management Setters ========== */

    function setGovernance(address _newGovernance) external onlyGovernance {
        require(_newGovernance != address(0), "L1_BRG: _newGovernance cannot be address(0)");
        governance = _newGovernance;
    }

    function setCrossDomainMessengerWrapper(uint256 chainId, IMessengerWrapper _crossDomainMessengerWrapper) external onlyGovernance {
        crossDomainMessengerWrappers[chainId] = _crossDomainMessengerWrapper;
    }

    function setChainIdDepositsPaused(uint256 chainId, bool isPaused) external onlyGovernance {
        isChainIdPaused[chainId] = isPaused;
    }

    function setChallengePeriod(uint256 _challengePeriod) external onlyGovernance {
        require(_challengePeriod % TIME_SLOT_SIZE == 0, "L1_BRG: challengePeriod must be divisible by TIME_SLOT_SIZE");

        challengePeriod = _challengePeriod;
    }

    function setChallengeResolutionPeriod(uint256 _challengeResolutionPeriod) external onlyGovernance {
        challengeResolutionPeriod = _challengeResolutionPeriod;
    }

    function setMinTransferRootBondDelay(uint256 _minTransferRootBondDelay) external onlyGovernance {
        minTransferRootBondDelay = _minTransferRootBondDelay;
    }

    /* ========== Public Getters ========== */

    function getBondForTransferAmount(uint256 amount) public pure returns (uint256) {
        // Bond covers amount plus a bounty to pay a potential challenger
        return amount.add(getChallengeAmountForTransferAmount(amount));
    }

    function getChallengeAmountForTransferAmount(uint256 amount) public pure returns (uint256) {
        // Bond covers amount plus a bounty to pay a potential challenger
        return amount.div(CHALLENGE_AMOUNT_DIVISOR);
    }

    function getTimeSlot(uint256 time) public pure returns (uint256) {
        return time / TIME_SLOT_SIZE;
    }
}

File 3 of 8 : Bridge.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "./Accounting.sol";
import "../libraries/Lib_MerkleTree.sol";

/**
 * @dev Bridge extends the accounting system and encapsulates the logic that is shared by both the
 * L1 and L2 Bridges. It allows to TransferRoots to be set by parent contracts and for those
 * TransferRoots to be withdrawn against. It also allows the bonder to bond and withdraw Transfers
 * directly through `bondWithdrawal` and then settle those bonds against their TransferRoot once it
 * has been set.
 */

abstract contract Bridge is Accounting {
    using Lib_MerkleTree for bytes32;

    struct TransferRoot {
        uint256 total;
        uint256 amountWithdrawn;
        uint256 createdAt;
    }

    /* ========== Events ========== */

    event Withdrew(
        bytes32 indexed transferId,
        address indexed recipient,
        uint256 amount,
        bytes32 transferNonce
    );

    event WithdrawalBonded(
        bytes32 indexed transferId,
        uint256 amount
    );

    event WithdrawalBondSettled(
        address indexed bonder,
        bytes32 indexed transferId,
        bytes32 indexed rootHash
    );

    event MultipleWithdrawalsSettled(
        address indexed bonder,
        bytes32 indexed rootHash,
        uint256 totalBondsSettled
    );

    event TransferRootSet(
        bytes32 indexed rootHash,
        uint256 totalAmount
    );

    /* ========== State ========== */

    mapping(bytes32 => TransferRoot) private _transferRoots;
    mapping(bytes32 => bool) private _spentTransferIds;
    mapping(address => mapping(bytes32 => uint256)) private _bondedWithdrawalAmounts;

    uint256 constant RESCUE_DELAY = 8 weeks;

    constructor(address[] memory bonders) public Accounting(bonders) {}

    /* ========== Public Getters ========== */

    /**
     * @dev Get the hash that represents an individual Transfer.
     * @param chainId The id of the destination chain
     * @param recipient The address receiving the Transfer
     * @param amount The amount being transferred including the `_bonderFee`
     * @param transferNonce Used to avoid transferId collisions
     * @param bonderFee The amount paid to the address that withdraws the Transfer
     * @param amountOutMin The minimum amount received after attempting to swap in the destination
     * AMM market. 0 if no swap is intended.
     * @param deadline The deadline for swapping in the destination AMM market. 0 if no
     * swap is intended.
     */
    function getTransferId(
        uint256 chainId,
        address recipient,
        uint256 amount,
        bytes32 transferNonce,
        uint256 bonderFee,
        uint256 amountOutMin,
        uint256 deadline
    )
        public
        pure
        returns (bytes32)
    {
        return keccak256(abi.encode(
            chainId,
            recipient,
            amount,
            transferNonce,
            bonderFee,
            amountOutMin,
            deadline
        ));
    }

    /**
     * @notice getChainId can be overridden by subclasses if needed for compatibility or testing purposes.
     * @dev Get the current chainId
     * @return chainId The current chainId
     */
    function getChainId() public virtual view returns (uint256 chainId) {
        this; // Silence state mutability warning without generating any additional byte code
        assembly {
            chainId := chainid()
        }
    }

    /**
     * @dev Get the TransferRoot id for a given rootHash and totalAmount
     * @param rootHash The Merkle root of the TransferRoot
     * @param totalAmount The total of all Transfers in the TransferRoot
     * @return The calculated transferRootId
     */
    function getTransferRootId(bytes32 rootHash, uint256 totalAmount) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(rootHash, totalAmount));
    }

    /**
     * @dev Get the TransferRoot for a given rootHash and totalAmount
     * @param rootHash The Merkle root of the TransferRoot
     * @param totalAmount The total of all Transfers in the TransferRoot
     * @return The TransferRoot with the calculated transferRootId
     */
    function getTransferRoot(bytes32 rootHash, uint256 totalAmount) public view returns (TransferRoot memory) {
        return _transferRoots[getTransferRootId(rootHash, totalAmount)];
    }

    /**
     * @dev Get the amount bonded for the withdrawal of a transfer
     * @param bonder The Bonder of the withdrawal
     * @param transferId The Transfer's unique identifier
     * @return The amount bonded for a Transfer withdrawal
     */
    function getBondedWithdrawalAmount(address bonder, bytes32 transferId) external view returns (uint256) {
        return _bondedWithdrawalAmounts[bonder][transferId];
    }

    /**
     * @dev Get the spent status of a transfer ID
     * @param transferId The transfer's unique identifier
     * @return True if the transferId has been spent
     */
    function isTransferIdSpent(bytes32 transferId) external view returns (bool) {
        return _spentTransferIds[transferId];
    }

    /* ========== User/Relayer External Functions ========== */

    /**
     * @notice Can be called by anyone (recipient or relayer)
     * @dev Withdraw a Transfer from its destination bridge
     * @param recipient The address receiving the Transfer
     * @param amount The amount being transferred including the `_bonderFee`
     * @param transferNonce Used to avoid transferId collisions
     * @param bonderFee The amount paid to the address that withdraws the Transfer
     * @param amountOutMin The minimum amount received after attempting to swap in the destination
     * AMM market. 0 if no swap is intended. (only used to calculate `transferId` in this function)
     * @param deadline The deadline for swapping in the destination AMM market. 0 if no
     * swap is intended. (only used to calculate `transferId` in this function)
     * @param rootHash The Merkle root of the TransferRoot
     * @param transferRootTotalAmount The total amount being transferred in a TransferRoot
     * @param transferIdTreeIndex The index of the transferId in the Merkle tree
     * @param siblings The siblings of the transferId in the Merkle tree
     * @param totalLeaves The total number of leaves in the Merkle tree
     */
    function withdraw(
        address recipient,
        uint256 amount,
        bytes32 transferNonce,
        uint256 bonderFee,
        uint256 amountOutMin,
        uint256 deadline,
        bytes32 rootHash,
        uint256 transferRootTotalAmount,
        uint256 transferIdTreeIndex,
        bytes32[] calldata siblings,
        uint256 totalLeaves
    )
        external
        nonReentrant
    {
        bytes32 transferId = getTransferId(
            getChainId(),
            recipient,
            amount,
            transferNonce,
            bonderFee,
            amountOutMin,
            deadline
        );

        require(
            rootHash.verify(
                transferId,
                transferIdTreeIndex,
                siblings,
                totalLeaves
            )
        , "BRG: Invalid transfer proof");
        bytes32 transferRootId = getTransferRootId(rootHash, transferRootTotalAmount);
        _addToAmountWithdrawn(transferRootId, amount);
        _fulfillWithdraw(transferId, recipient, amount, uint256(0));

        emit Withdrew(transferId, recipient, amount, transferNonce);
    }

    /**
     * @dev Allows the bonder to bond individual withdrawals before their TransferRoot has been committed.
     * @param recipient The address receiving the Transfer
     * @param amount The amount being transferred including the `_bonderFee`
     * @param transferNonce Used to avoid transferId collisions
     * @param bonderFee The amount paid to the address that withdraws the Transfer
     */
    function bondWithdrawal(
        address recipient,
        uint256 amount,
        bytes32 transferNonce,
        uint256 bonderFee
    )
        external
        onlyBonder
        requirePositiveBalance
        nonReentrant
    {
        bytes32 transferId = getTransferId(
            getChainId(),
            recipient,
            amount,
            transferNonce,
            bonderFee,
            0,
            0
        );

        _bondWithdrawal(transferId, amount);
        _fulfillWithdraw(transferId, recipient, amount, bonderFee);
    }

    /**
     * @dev Refunds the Bonder's stake from a bonded withdrawal and counts that withdrawal against
     * its TransferRoot.
     * @param bonder The Bonder of the withdrawal
     * @param transferId The Transfer's unique identifier
     * @param rootHash The Merkle root of the TransferRoot
     * @param transferRootTotalAmount The total amount being transferred in a TransferRoot
     * @param transferIdTreeIndex The index of the transferId in the Merkle tree
     * @param siblings The siblings of the transferId in the Merkle tree
     * @param totalLeaves The total number of leaves in the Merkle tree
     */
    function settleBondedWithdrawal(
        address bonder,
        bytes32 transferId,
        bytes32 rootHash,
        uint256 transferRootTotalAmount,
        uint256 transferIdTreeIndex,
        bytes32[] calldata siblings,
        uint256 totalLeaves
    )
        external
    {
        require(
            rootHash.verify(
                transferId,
                transferIdTreeIndex,
                siblings,
                totalLeaves
            )
        , "BRG: Invalid transfer proof");
        bytes32 transferRootId = getTransferRootId(rootHash, transferRootTotalAmount);

        uint256 amount = _bondedWithdrawalAmounts[bonder][transferId];
        require(amount > 0, "L2_BRG: transferId has no bond");

        _bondedWithdrawalAmounts[bonder][transferId] = 0;
        _addToAmountWithdrawn(transferRootId, amount);
        _addCredit(bonder, amount);

        emit WithdrawalBondSettled(bonder, transferId, rootHash);
    }

    /**
     * @dev Refunds the Bonder for all withdrawals that they bonded in a TransferRoot.
     * @param bonder The address of the Bonder being refunded
     * @param transferIds All transferIds in the TransferRoot in order
     * @param totalAmount The totalAmount of the TransferRoot
     */
    function settleBondedWithdrawals(
        address bonder,
        // transferIds _must_ be calldata or it will be mutated by Lib_MerkleTree.getMerkleRoot
        bytes32[] calldata transferIds,
        uint256 totalAmount
    )
        external
    {
        bytes32 rootHash = Lib_MerkleTree.getMerkleRoot(transferIds);
        bytes32 transferRootId = getTransferRootId(rootHash, totalAmount);

        uint256 totalBondsSettled = 0;
        for(uint256 i = 0; i < transferIds.length; i++) {
            uint256 transferBondAmount = _bondedWithdrawalAmounts[bonder][transferIds[i]];
            if (transferBondAmount > 0) {
                totalBondsSettled = totalBondsSettled.add(transferBondAmount);
                _bondedWithdrawalAmounts[bonder][transferIds[i]] = 0;
            }
        }

        _addToAmountWithdrawn(transferRootId, totalBondsSettled);
        _addCredit(bonder, totalBondsSettled);

        emit MultipleWithdrawalsSettled(bonder, rootHash, totalBondsSettled);
    }

    /* ========== External TransferRoot Rescue ========== */

    /**
     * @dev Allows governance to withdraw the remaining amount from a TransferRoot after the rescue delay has passed.
     * @param rootHash the Merkle root of the TransferRoot
     * @param originalAmount The TransferRoot's recorded total
     * @param recipient The address receiving the remaining balance
     */
    function rescueTransferRoot(bytes32 rootHash, uint256 originalAmount, address recipient) external onlyGovernance {
        bytes32 transferRootId = getTransferRootId(rootHash, originalAmount);
        TransferRoot memory transferRoot = getTransferRoot(rootHash, originalAmount);

        require(transferRoot.createdAt != 0, "BRG: TransferRoot not found");
        assert(transferRoot.total == originalAmount);
        uint256 rescueDelayEnd = transferRoot.createdAt.add(RESCUE_DELAY);
        require(block.timestamp >= rescueDelayEnd, "BRG: TransferRoot cannot be rescued before the Rescue Delay");

        uint256 remainingAmount = transferRoot.total.sub(transferRoot.amountWithdrawn);
        _addToAmountWithdrawn(transferRootId, remainingAmount);
        _transferFromBridge(recipient, remainingAmount);
    }

    /* ========== Internal Functions ========== */

    function _markTransferSpent(bytes32 transferId) internal {
        require(!_spentTransferIds[transferId], "BRG: The transfer has already been withdrawn");
        _spentTransferIds[transferId] = true;
    }

    function _addToAmountWithdrawn(bytes32 transferRootId, uint256 amount) internal {
        TransferRoot storage transferRoot = _transferRoots[transferRootId];
        require(transferRoot.total > 0, "BRG: Transfer root not found");

        uint256 newAmountWithdrawn = transferRoot.amountWithdrawn.add(amount);
        require(newAmountWithdrawn <= transferRoot.total, "BRG: Withdrawal exceeds TransferRoot total");

        transferRoot.amountWithdrawn = newAmountWithdrawn;
    }

    function _setTransferRoot(bytes32 rootHash, uint256 totalAmount) internal {
        bytes32 transferRootId = getTransferRootId(rootHash, totalAmount);
        require(_transferRoots[transferRootId].total == 0, "BRG: Transfer root already set");
        require(totalAmount > 0, "BRG: Cannot set TransferRoot totalAmount of 0");

        _transferRoots[transferRootId] = TransferRoot(totalAmount, 0, block.timestamp);

        emit TransferRootSet(rootHash, totalAmount);
    }

    function _bondWithdrawal(bytes32 transferId, uint256 amount) internal {
        require(_bondedWithdrawalAmounts[msg.sender][transferId] == 0, "BRG: Withdrawal has already been bonded");
        _addDebit(msg.sender, amount);
        _bondedWithdrawalAmounts[msg.sender][transferId] = amount;

        emit WithdrawalBonded(transferId, amount);
    }

    /* ========== Private Functions ========== */

    /// @dev Completes the Transfer, distributes the Bonder fee and marks the Transfer as spent.
    function _fulfillWithdraw(
        bytes32 transferId,
        address recipient,
        uint256 amount,
        uint256 bonderFee
    ) private {
        _markTransferSpent(transferId);
        _transferFromBridge(recipient, amount.sub(bonderFee));
        if (bonderFee > 0) {
            _transferFromBridge(msg.sender, bonderFee);
        }
    }
}

File 4 of 8 : IMessengerWrapper.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.12 <0.8.0;
pragma experimental ABIEncoderV2;

interface IMessengerWrapper {
    function sendCrossDomainMessage(bytes memory _calldata) external;
    function verifySender(address l1BridgeCaller, bytes memory _data) external;
}

File 5 of 8 : Accounting.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;

import "@openzeppelin/contracts/math/SafeMath.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

/**
 * @dev Accounting is an abstract contract that encapsulates the most critical logic in the Hop contracts.
 * The accounting system works by using two balances that can only increase `_credit` and `_debit`.
 * A bonder's available balance is the total credit minus the total debit. The contract exposes
 * two external functions that allows a bonder to stake and unstake and exposes two internal
 * functions to its child contracts that allow the child contract to add to the credit 
 * and debit balance. In addition, child contracts can override `_additionalDebit` to account
 * for any additional debit balance in an alternative way. Lastly, it exposes a modifier,
 * `requirePositiveBalance`, that can be used by child contracts to ensure the bonder does not
 * use more than its available stake.
 */

abstract contract Accounting is ReentrancyGuard {
    using SafeMath for uint256;

    mapping(address => bool) private _isBonder;

    mapping(address => uint256) private _credit;
    mapping(address => uint256) private _debit;

    event Stake (
        address indexed account,
        uint256 amount
    );

    event Unstake (
        address indexed account,
        uint256 amount
    );

    event BonderAdded (
        address indexed newBonder
    );

    event BonderRemoved (
        address indexed previousBonder
    );

    /* ========== Modifiers ========== */

    modifier onlyBonder {
        require(_isBonder[msg.sender], "ACT: Caller is not bonder");
        _;
    }

    modifier onlyGovernance {
        _requireIsGovernance();
        _;
    }

    /// @dev Used by parent contract to ensure that the Bonder is solvent at the end of the transaction.
    modifier requirePositiveBalance {
        _;
        require(getCredit(msg.sender) >= getDebitAndAdditionalDebit(msg.sender), "ACT: Not enough available credit");
    }

    /// @dev Sets the Bonder addresses
    constructor(address[] memory bonders) public {
        for (uint256 i = 0; i < bonders.length; i++) {
            require(_isBonder[bonders[i]] == false, "ACT: Cannot add duplicate bonder");
            _isBonder[bonders[i]] = true;
            emit BonderAdded(bonders[i]);
        }
    }

    /* ========== Virtual functions ========== */
    /**
     * @dev The following functions are overridden in L1_Bridge and L2_Bridge
     */
    function _transferFromBridge(address recipient, uint256 amount) internal virtual;
    function _transferToBridge(address from, uint256 amount) internal virtual;
    function _requireIsGovernance() internal virtual;

    /**
     * @dev This function can be optionally overridden by a parent contract to track any additional
     * debit balance in an alternative way.
     */
    function _additionalDebit(address /*bonder*/) internal view virtual returns (uint256) {
        this; // Silence state mutability warning without generating any additional byte code
        return 0;
    }

    /* ========== Public/external getters ========== */

    /**
     * @dev Check if address is a Bonder
     * @param maybeBonder The address being checked
     * @return true if address is a Bonder
     */
    function getIsBonder(address maybeBonder) public view returns (bool) {
        return _isBonder[maybeBonder];
    }

    /**
     * @dev Get the Bonder's credit balance
     * @param bonder The owner of the credit balance being checked
     * @return The credit balance for the Bonder
     */
    function getCredit(address bonder) public view returns (uint256) {
        return _credit[bonder];
    }

    /**
     * @dev Gets the debit balance tracked by `_debit` and does not include `_additionalDebit()`
     * @param bonder The owner of the debit balance being checked
     * @return The debit amount for the Bonder
     */
    function getRawDebit(address bonder) external view returns (uint256) {
        return _debit[bonder];
    }

    /**
     * @dev Get the Bonder's total debit
     * @param bonder The owner of the debit balance being checked
     * @return The Bonder's total debit balance
     */
    function getDebitAndAdditionalDebit(address bonder) public view returns (uint256) {
        return _debit[bonder].add(_additionalDebit(bonder));
    }

    /* ========== Bonder external functions ========== */

    /** 
     * @dev Allows the Bonder to deposit tokens and increase its credit balance
     * @param bonder The address being staked on
     * @param amount The amount being staked
     */
    function stake(address bonder, uint256 amount) external payable nonReentrant {
        require(_isBonder[bonder] == true, "ACT: Address is not bonder");
        _transferToBridge(msg.sender, amount);
        _addCredit(bonder, amount);

        emit Stake(bonder, amount);
    }

    /**
     * @dev Allows the caller to withdraw any available balance and add to their debit balance
     * @param amount The amount being unstaked
     */
    function unstake(uint256 amount) external requirePositiveBalance nonReentrant {
        _addDebit(msg.sender, amount);
        _transferFromBridge(msg.sender, amount);

        emit Unstake(msg.sender, amount);
    }

    /**
     * @dev Add Bonder to allowlist
     * @param bonder The address being added as a Bonder
     */
    function addBonder(address bonder) external onlyGovernance {
        require(_isBonder[bonder] == false, "ACT: Address is already bonder");
        _isBonder[bonder] = true;

        emit BonderAdded(bonder);
    }

    /**
     * @dev Remove Bonder from allowlist
     * @param bonder The address being removed as a Bonder
     */
    function removeBonder(address bonder) external onlyGovernance {
        require(_isBonder[bonder] == true, "ACT: Address is not bonder");
        _isBonder[bonder] = false;

        emit BonderRemoved(bonder);
    }

    /* ========== Internal functions ========== */

    function _addCredit(address bonder, uint256 amount) internal {
        _credit[bonder] = _credit[bonder].add(amount);
    }

    function _addDebit(address bonder, uint256 amount) internal {
        _debit[bonder] = _debit[bonder].add(amount);
    }
}

File 6 of 8 : Lib_MerkleTree.sol
// SPDX-License-Identifier: MIT
pragma solidity >0.5.0 <0.8.0;

/**
 * @title Lib_MerkleTree
 * @author River Keefer
 */
library Lib_MerkleTree {

    /**********************
     * Internal Functions *
     **********************/

    /**
     * Calculates a merkle root for a list of 32-byte leaf hashes.  WARNING: If the number
     * of leaves passed in is not a power of two, it pads out the tree with zero hashes.
     * If you do not know the original length of elements for the tree you are verifying,
     * then this may allow empty leaves past _elements.length to pass a verification check down the line.
     * Note that the _elements argument is modified, therefore it must not be used again afterwards
     * @param _elements Array of hashes from which to generate a merkle root.
     * @return Merkle root of the leaves, with zero hashes for non-powers-of-two (see above).
     */
    function getMerkleRoot(
        bytes32[] memory _elements
    )
        internal
        pure
        returns (
            bytes32
        )
    {
        require(
            _elements.length > 0,
            "Lib_MerkleTree: Must provide at least one leaf hash."
        );

        if (_elements.length == 1) {
            return _elements[0];
        }

        uint256[16] memory defaults = [
            0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563,
            0x633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d,
            0x890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d,
            0x3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd8,
            0xecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da,
            0xdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da5,
            0x617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d7,
            0x292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead,
            0xe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e10,
            0x7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f82,
            0xe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e83636516,
            0x3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c,
            0xad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e,
            0xa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab,
            0x4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c862,
            0x2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf10
        ];

        // Reserve memory space for our hashes.
        bytes memory buf = new bytes(64);

        // We'll need to keep track of left and right siblings.
        bytes32 leftSibling;
        bytes32 rightSibling;

        // Number of non-empty nodes at the current depth.
        uint256 rowSize = _elements.length;

        // Current depth, counting from 0 at the leaves
        uint256 depth = 0;

        // Common sub-expressions
        uint256 halfRowSize;         // rowSize / 2
        bool rowSizeIsOdd;           // rowSize % 2 == 1

        while (rowSize > 1) {
            halfRowSize = rowSize / 2;
            rowSizeIsOdd = rowSize % 2 == 1;

            for (uint256 i = 0; i < halfRowSize; i++) {
                leftSibling  = _elements[(2 * i)    ];
                rightSibling = _elements[(2 * i) + 1];
                assembly {
                    mstore(add(buf, 32), leftSibling )
                    mstore(add(buf, 64), rightSibling)
                }

                _elements[i] = keccak256(buf);
            }

            if (rowSizeIsOdd) {
                leftSibling  = _elements[rowSize - 1];
                rightSibling = bytes32(defaults[depth]);
                assembly {
                    mstore(add(buf, 32), leftSibling)
                    mstore(add(buf, 64), rightSibling)
                }

                _elements[halfRowSize] = keccak256(buf);
            }

            rowSize = halfRowSize + (rowSizeIsOdd ? 1 : 0);
            depth++;
        }

        return _elements[0];
    }

    /**
     * Verifies a merkle branch for the given leaf hash.  Assumes the original length
     * of leaves generated is a known, correct input, and does not return true for indices
     * extending past that index (even if _siblings would be otherwise valid.)
     * @param _root The Merkle root to verify against.
     * @param _leaf The leaf hash to verify inclusion of.
     * @param _index The index in the tree of this leaf.
     * @param _siblings Array of sibline nodes in the inclusion proof, starting from depth 0 (bottom of the tree).
     * @param _totalLeaves The total number of leaves originally passed into.
     * @return Whether or not the merkle branch and leaf passes verification.
     */
    function verify(
        bytes32 _root,
        bytes32 _leaf,
        uint256 _index,
        bytes32[] memory _siblings,
        uint256 _totalLeaves
    )
        internal
        pure
        returns (
            bool
        )
    {
        require(
            _totalLeaves > 0,
            "Lib_MerkleTree: Total leaves must be greater than zero."
        );

        require(
            _index < _totalLeaves,
            "Lib_MerkleTree: Index out of bounds."
        );

        require(
            _siblings.length == _ceilLog2(_totalLeaves),
            "Lib_MerkleTree: Total siblings does not correctly correspond to total leaves."
        );

        bytes32 computedRoot = _leaf;

        for (uint256 i = 0; i < _siblings.length; i++) {
            if ((_index & 1) == 1) {
                computedRoot = keccak256(
                    abi.encodePacked(
                        _siblings[i],
                        computedRoot
                    )
                );
            } else {
                computedRoot = keccak256(
                    abi.encodePacked(
                        computedRoot,
                        _siblings[i]
                    )
                );
            }

            _index >>= 1;
        }

        return _root == computedRoot;
    }


    /*********************
     * Private Functions *
     *********************/

    /**
     * Calculates the integer ceiling of the log base 2 of an input.
     * @param _in Unsigned input to calculate the log.
     * @return ceil(log_base_2(_in))
     */
    function _ceilLog2(
        uint256 _in
    )
        private
        pure
        returns (
            uint256
        )
    {
        require(
            _in > 0,
            "Lib_MerkleTree: Cannot compute ceil(log_2) of 0."
        );

        if (_in == 1) {
            return 0;
        }

        // Find the highest set bit (will be floor(log_2)).
        // Borrowed with <3 from https://github.com/ethereum/solidity-examples
        uint256 val = _in;
        uint256 highest = 0;
        for (uint256 i = 128; i >= 1; i >>= 1) {
            if (val & (uint(1) << i) - 1 << i != 0) {
                highest += i;
                val >>= i;
            }
        }

        // Increment by one if this is not a perfect logarithm.
        if ((uint(1) << highest) != _in) {
            highest += 1;
        }

        return highest;
    }
}

File 7 of 8 : SafeMath.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <0.8.0;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        uint256 c = a + b;
        if (c < a) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the substraction of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b > a) return (false, 0);
        return (true, a - b);
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     *
     * _Available since v3.4._
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) return (true, 0);
        uint256 c = a * b;
        if (c / a != b) return (false, 0);
        return (true, c);
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a / b);
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     *
     * _Available since v3.4._
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        if (b == 0) return (false, 0);
        return (true, a % b);
    }

    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     *
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");
        return c;
    }

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

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     *
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) return 0;
        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");
        return c;
    }

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

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

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {trySub}.
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     *
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        return a - b;
    }

    /**
     * @dev Returns the integer division of two unsigned integers, reverting with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryDiv}.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a / b;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * reverting with custom message when dividing by zero.
     *
     * CAUTION: This function is deprecated because it requires allocating memory for the error
     * message unnecessarily. For custom revert reasons use {tryMod}.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     *
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b > 0, errorMessage);
        return a % b;
    }
}

File 8 of 8 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT

pragma solidity >=0.6.0 <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 () internal {
        _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 make 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;
    }
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address[]","name":"bonders","type":"address[]"},{"internalType":"address","name":"_governance","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"newBonder","type":"address"}],"name":"BonderAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousBonder","type":"address"}],"name":"BonderRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferRootId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"originalAmount","type":"uint256"}],"name":"ChallengeResolved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bonder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"totalBondsSettled","type":"uint256"}],"name":"MultipleWithdrawalsSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferRootId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"originalAmount","type":"uint256"}],"name":"TransferBondChallenged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"root","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TransferRootBonded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"originChainId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"TransferRootConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"TransferRootSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"chainId","type":"uint256"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"deadline","type":"uint256"},{"indexed":true,"internalType":"address","name":"relayer","type":"address"},{"indexed":false,"internalType":"uint256","name":"relayerFee","type":"uint256"}],"name":"TransferSentToL2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Unstake","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"bonder","type":"address"},{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"rootHash","type":"bytes32"}],"name":"WithdrawalBondSettled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"WithdrawalBonded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"transferId","type":"bytes32"},{"indexed":true,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"transferNonce","type":"bytes32"}],"name":"Withdrew","type":"event"},{"inputs":[],"name":"CHALLENGE_AMOUNT_DIVISOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TIME_SLOT_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"}],"name":"addBonder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"bondTransferRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"transferNonce","type":"bytes32"},{"internalType":"uint256","name":"bonderFee","type":"uint256"}],"name":"bondWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"chainBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengePeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"challengeResolutionPeriod","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"originalAmount","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"name":"challengeTransferBond","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"originChainId","type":"uint256"},{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"rootCommittedAt","type":"uint256"}],"name":"confirmTransferRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"crossDomainMessengerWrappers","outputs":[{"internalType":"contract IMessengerWrapper","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getBondForTransferAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"getBondedWithdrawalAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getChainId","outputs":[{"internalType":"uint256","name":"chainId","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getChallengeAmountForTransferAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"}],"name":"getCredit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"}],"name":"getDebitAndAdditionalDebit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maybeBonder","type":"address"}],"name":"getIsBonder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"}],"name":"getRawDebit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"time","type":"uint256"}],"name":"getTimeSlot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"transferNonce","type":"bytes32"},{"internalType":"uint256","name":"bonderFee","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"getTransferId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"getTransferRoot","outputs":[{"components":[{"internalType":"uint256","name":"total","type":"uint256"},{"internalType":"uint256","name":"amountWithdrawn","type":"uint256"},{"internalType":"uint256","name":"createdAt","type":"uint256"}],"internalType":"struct Bridge.TransferRoot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"getTransferRootId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isChainIdPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"transferId","type":"bytes32"}],"name":"isTransferIdSpent","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"minTransferRootBondDelay","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"}],"name":"removeBonder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"originalAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"rescueTransferRoot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"originalAmount","type":"uint256"},{"internalType":"uint256","name":"destinationChainId","type":"uint256"}],"name":"resolveChallenge","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"address","name":"relayer","type":"address"},{"internalType":"uint256","name":"relayerFee","type":"uint256"}],"name":"sendToL2","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"bool","name":"isPaused","type":"bool"}],"name":"setChainIdDepositsPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengePeriod","type":"uint256"}],"name":"setChallengePeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_challengeResolutionPeriod","type":"uint256"}],"name":"setChallengeResolutionPeriod","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"contract IMessengerWrapper","name":"_crossDomainMessengerWrapper","type":"address"}],"name":"setCrossDomainMessengerWrapper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernance","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_minTransferRootBondDelay","type":"uint256"}],"name":"setMinTransferRootBondDelay","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"},{"internalType":"bytes32","name":"transferId","type":"bytes32"},{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"transferRootTotalAmount","type":"uint256"},{"internalType":"uint256","name":"transferIdTreeIndex","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"},{"internalType":"uint256","name":"totalLeaves","type":"uint256"}],"name":"settleBondedWithdrawal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"},{"internalType":"bytes32[]","name":"transferIds","type":"bytes32[]"},{"internalType":"uint256","name":"totalAmount","type":"uint256"}],"name":"settleBondedWithdrawals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"bonder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"timeSlotToAmountBonded","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transferBonds","outputs":[{"internalType":"address","name":"bonder","type":"address"},{"internalType":"uint256","name":"createdAt","type":"uint256"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"challengeStartTime","type":"uint256"},{"internalType":"address","name":"challenger","type":"address"},{"internalType":"bool","name":"challengeResolved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"transferRootCommittedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"transferNonce","type":"bytes32"},{"internalType":"uint256","name":"bonderFee","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bytes32","name":"rootHash","type":"bytes32"},{"internalType":"uint256","name":"transferRootTotalAmount","type":"uint256"},{"internalType":"uint256","name":"transferIdTreeIndex","type":"uint256"},{"internalType":"bytes32[]","name":"siblings","type":"bytes32[]"},{"internalType":"uint256","name":"totalLeaves","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405262015180600e55620d2f00600f556103846010553480156200002557600080fd5b5060405162004af838038062004af88339810160408190526200004891620001b2565b81818180600160008190555060005b81518110156200016657600160008383815181106200007257fe5b6020908102919091018101516001600160a01b031682528101919091526040016000205460ff1615620000c25760405162461bcd60e51b8152600401620000b9906200027d565b60405180910390fd5b6001806000848481518110620000d457fe5b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff0219169083151502179055508181815181106200012057fe5b60200260200101516001600160a01b03167f2cec73b7434d3b91198ad1a618f63e6a0761ce281af5ec9ec76606d948d03e2360405160405180910390a260010162000057565b5050600b80546001600160a01b0319166001600160a01b03939093169290921790915550620002d992505050565b80516001600160a01b0381168114620001ac57600080fd5b92915050565b60008060408385031215620001c5578182fd5b82516001600160401b0380821115620001dc578384fd5b818501915085601f830112620001f0578384fd5b815181811115620001ff578485fd5b6020915081810262000213838201620002b2565b8281528381019085850183870186018b10156200022e578889fd5b8896505b848710156200025c57620002478b8262000194565b83526001969096019591850191850162000232565b5080975050505050620002728682870162000194565b925050509250929050565b6020808252818101527f4143543a2043616e6e6f7420616464206475706c696361746520626f6e646572604082015260600190565b6040518181016001600160401b0381118282101715620002d157600080fd5b604052919050565b61480f80620002e96000396000f3fe6080604052600436106102f25760003560e01c806381707b801161018f578063cbd1642e116100e1578063eecd57e61161008a578063fa2a69a311610064578063fa2a69a314610814578063fc110b6714610834578063ffa9286c14610854576102f2565b8063eecd57e6146107bf578063ef6ebe5e146107df578063f3f480d9146107ff576102f2565b8063d5ef7551116100bb578063d5ef75511461076c578063deace8f51461078c578063e19be1501461079f576102f2565b8063cbd1642e146106ff578063ce803b4f1461071f578063d44481631461074c576102f2565b8063a35962f311610143578063af215f941161011d578063af215f941461069f578063b162717e146106bf578063c7525dd3146106df576102f2565b8063a35962f31461064c578063ab033ea91461066c578063adc9772e1461068c576102f2565b8063960a7afa11610174578063960a7afa146105f757806398c4f76d14610617578063a239f5ee1461062c576102f2565b806381707b80146105b75780638d8798bf146105d7576102f2565b80633a7af631116102485780635a7e1083116101fc5780636cff06a7116101d65780636cff06a71461056d5780637398d28214610582578063767631d5146105a2576102f2565b80635a7e1083146104f95780635aa6e6751461052b5780635d475fdd1461054d576102f2565b80634de8c6e61161022d5780634de8c6e6146104a45780635325937f146104b957806357344e6f146104d9576102f2565b80633a7af631146104575780633b8fea2814610484576102f2565b806323c452cd116102aa578063302830ab11610284578063302830ab146104025780633408e4701461042257806339ada66914610437576102f2565b806323c452cd146103a25780632b85dcc9146103c25780632e17de78146103e2576102f2565b806313948c76116102db57806313948c7614610339578063149420241461036f5780631bbe15ea1461038f576102f2565b806304e6c2c0146102f75780630f7aadb714610319575b600080fd5b34801561030357600080fd5b506103176103123660046133ac565b610874565b005b34801561032557600080fd5b50610317610334366004613509565b61095e565b34801561034557600080fd5b506103596103543660046133ac565b610abf565b6040516103669190613943565b60405180910390f35b34801561037b57600080fd5b5061031761038a366004613747565b610aeb565b61031761039d36600461362d565b610b31565b3480156103ae57600080fd5b506103176103bd3660046134cf565b610d9b565b3480156103ce57600080fd5b506103596103dd3660046135bc565b610ead565b3480156103ee57600080fd5b506103176103fd3660046135bc565b610eb5565b34801561040e57600080fd5b5061035961041d366004613422565b610fab565b34801561042e57600080fd5b50610359610fe3565b34801561044357600080fd5b506103176104523660046135bc565b610fe7565b34801561046357600080fd5b506104776104723660046135bc565b610ff4565b6040516103669190613938565b34801561049057600080fd5b5061035961049f3660046135d4565b611009565b3480156104b057600080fd5b50610359611026565b3480156104c557600080fd5b506103176104d43660046133ac565b61102c565b3480156104e557600080fd5b506103596104f43660046133ac565b61110e565b34801561050557600080fd5b506105196105143660046135bc565b611136565b604051610366969594939291906138a8565b34801561053757600080fd5b5061054061119a565b604051610366919061381d565b34801561055957600080fd5b506103176105683660046135bc565b6111b6565b34801561057957600080fd5b506103596111ff565b34801561058e57600080fd5b5061035961059d366004613658565b611205565b3480156105ae57600080fd5b50610359611222565b3480156105c357600080fd5b506103176105d236600461362d565b611228565b3480156105e357600080fd5b506103176105f236600461362d565b6114dc565b34801561060357600080fd5b506103596106123660046135d4565b6117aa565b34801561062357600080fd5b506103596117dd565b34801561063857600080fd5b506103596106473660046135bc565b6117e2565b34801561065857600080fd5b506105406106673660046135bc565b6117ef565b34801561067857600080fd5b506103176106873660046133ac565b611817565b61031761069a366004613422565b6118b3565b3480156106ab57600080fd5b506103596106ba366004613687565b6119c4565b3480156106cb57600080fd5b506103176106da3660046133c8565b611a06565b3480156106eb57600080fd5b506103176106fa36600461344d565b611b83565b34801561070b57600080fd5b5061031761071a3660046135f5565b611d0a565b34801561072b57600080fd5b5061073f61073a3660046135d4565b611e01565b60405161036691906146c3565b34801561075857600080fd5b50610317610767366004613658565b611e56565b34801561077857600080fd5b506104776107873660046133ac565b611eb1565b61031761079a3660046136df565b611edc565b3480156107ab57600080fd5b506103596107ba3660046135bc565b6121b9565b3480156107cb57600080fd5b506103176107da3660046135bc565b6121ce565b3480156107eb57600080fd5b506103176107fa36600461376f565b6121db565b34801561080b57600080fd5b506103596123c4565b34801561082057600080fd5b5061047761082f3660046135bc565b6123ca565b34801561084057600080fd5b5061035961084f3660046135bc565b6123df565b34801561086057600080fd5b5061035961086f3660046133ac565b6123f1565b61087c61242b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602081905260409091205460ff161515146108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d0e565b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f4234ba611d325b3ba434c4e1b037967b955b1274d4185ee9847b7491111a48ff9190a250565b6002600054141561099b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b600260009081556109b86109ad610fe3565b8e8e8e8e8e8e6119c4565b90506109fe81868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d95949392508891505061247e565b610a34576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061428c565b6000610a4088886117aa565b9050610a4c818e6125e8565b610a59828f8f6000612688565b8d73ffffffffffffffffffffffffffffffffffffffff16827f9475cdbde5fc71fe2ccd413c82878ee54d061b9f74f9e2e1a03ff1178821502c8f8f604051610aa29291906137f3565b60405180910390a350506001600055505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260409020545b919050565b610af361242b565b6000918252600d602052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6000610b3d84846117aa565b600081815260086020908152604080832086845260078352818420858552909252909120549192509015610b9d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614109565b6001810154610bd8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613a87565b6000610bf3600e5483600101546126af90919063ffffffff16565b905042811015610c2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906142c3565b600382015415610c6b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613c54565b4260038301556004820180547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790556001820154600090610cae90610ead565b90506000610cbb876121b9565b8454600084815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff9094168084529390915290205491925090610cfe90836126f5565b600084815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff80871685529252909120919091558554610d3f911683612737565b6000610d4a896117e2565b9050610d563382612794565b89877fec2697dcba539a0ac947cdf1f6d0b6314c065429eca8be2435859b10209d4c278b604051610d879190613943565b60405180910390a350505050505050505050565b3360009081526001602052604090205460ff16610de4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614255565b60026000541415610e21576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b60026000908155610e3f610e33610fe3565b868686866000806119c4565b9050610e4b81856127d1565b610e5781868685612688565b506001600055610e66336123f1565b610e6f3361110e565b1015610ea7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b50505050565b613840900490565b60026000541415610ef2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b6002600055610f013382612737565b610f0b3382612888565b3373ffffffffffffffffffffffffffffffffffffffff167f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd82604051610f519190613943565b60405180910390a26001600055610f67336123f1565b610f703361110e565b1015610fa8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b50565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602090815260408083208484529091529020545b92915050565b4690565b610fef61242b565b601055565b60009081526005602052604090205460ff1690565b600760209081526000928352604080842090915290825290205481565b61384081565b61103461242b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604090205460ff1615611094576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b52565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155517f2cec73b7434d3b91198ad1a618f63e6a0761ce281af5ec9ec76606d948d03e239190a250565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205490565b6008602052600090815260409020805460018201546002830154600384015460049094015473ffffffffffffffffffffffffffffffffffffffff93841694929391929181169074010000000000000000000000000000000000000000900460ff1686565b600b5473ffffffffffffffffffffffffffffffffffffffff1681565b6111be61242b565b6138408106156111fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906139f3565b600e55565b60105481565b600960209081526000928352604080842090915290825290205481565b600f5481565b600061123484846117aa565b6000818152600860205260409020600381015491925090611281576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061445e565b600f546003820154611292916126af565b42116112ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614321565b600481015474010000000000000000000000000000000000000000900460ff1615611321576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613bf7565b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055600061136d856117e2565b6000858152600760209081526040808320878452909152902054909150156114485760105460008581526007602090815260408083208784529091529020546113b5916126af565b826001015411156113f95781546113f49073ffffffffffffffffffffffffffffffffffffffff166113ef836113e9896121b9565b906126af565b61293c565b611443565b600482015461141e9073ffffffffffffffffffffffffffffffffffffffff168261293c565b81546114439073ffffffffffffffffffffffffffffffffffffffff166113ef876121b9565b61149b565b61146961dead611464600461145e856001612999565b906129ed565b612888565b60048083015461149b9173ffffffffffffffffffffffffffffffffffffffff909116906113ef9061145e856007612999565b85837f4a99228a8a6d774d261be57ab0ed833bb1bae1f22bbbd3d4767b75ad03fdddf7876040516114cc9190613943565b60405180910390a3505050505050565b3360009081526001602052604090205460ff16611525576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614255565b600061153184836117aa565b600084815260076020908152604080832084845290915290205490915015611585576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614109565b600081815260086020526040902060010154156115ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614609565b60006115d942610ead565b905060006115e6846121b9565b600083815260096020908152604080832033845290915290205490915061160d90826126af565b60008381526009602090815260408083203380855290835281842094909455805160c08101825293845242848301908152848201898152606086018581526080870186815260a088018781528b88526008909652939095209551865473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161788559251600188015590516002870155935160038601559051600490940180549251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff95909416929091169190911792909216179055611720868686612a39565b857fa57b3e1f3af9eca02201028629700658608222c365064584cfe65d9630ef4f7b856040516117509190613943565b60405180910390a2505050611764336123f1565b61176d3361110e565b10156117a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b505050565b600082826040516020016117bf9291906137f3565b60405160208183030381529060405280519060200120905092915050565b600a81565b6000610fdd82600a6129ed565b600c6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61181f61242b565b73ffffffffffffffffffffffffffffffffffffffff811661186c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061454f565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600260005414156118f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b6002600090815573ffffffffffffffffffffffffffffffffffffffff831681526001602081905260409091205460ff16151514611959576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d0e565b6119633382612794565b61196d828261293c565b8173ffffffffffffffffffffffffffffffffffffffff167febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a826040516119b39190613943565b60405180910390a250506001600055565b6000878787878787876040516020016119e397969594939291906146e4565b604051602081830303815290604052805190602001209050979650505050505050565b6000611a44848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612bef92505050565b90506000611a5282846117aa565b90506000805b85811015611b165773ffffffffffffffffffffffffffffffffffffffff8816600090815260066020526040812081898985818110611a9257fe5b9050602002013581526020019081526020016000205490506000811115611b0d57611abd83826126af565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260066020526040812091945090818a8a86818110611af357fe5b905060200201358152602001908152602001600020819055505b50600101611a58565b50611b2182826125e8565b611b2b878261293c565b828773ffffffffffffffffffffffffffffffffffffffff167f78e830d08be9d5f957414c84d685c061ecbd8467be98b42ebb64f0118b57d2ff83604051611b729190613943565b60405180910390a350505050505050565b611bc787858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c95949392508791505061247e565b611bfd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061428c565b6000611c0987876117aa565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526006602090815260408083208c845290915290205490915080611c74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613ae4565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526006602090815260408083208c8452909152812055611caf82826125e8565b611cb98a8261293c565b87898b73ffffffffffffffffffffffffffffffffffffffff167f84eb21b24c31b27a3bc67dde4a598aad06db6e9415cd66544492b9616996143c60405160405180910390a450505050505050505050565b611d1261242b565b6000611d1e84846117aa565b9050611d28613323565b611d328585611e01565b9050806040015160001415611d73576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b89565b80518414611d7d57fe5b6040810151600090611d92906249d4006126af565b905080421015611dce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613cb1565b60208201518251600091611de291906126f5565b9050611dee84826125e8565b611df88582612888565b50505050505050565b611e09613323565b60046000611e1785856117aa565b81526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905092915050565b611e5e61242b565b6000918252600c602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205460ff1690565b6000878152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611f38576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f84565b6000888152600d602052604090205460ff1615611f81576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d45565b60008611611fbb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061395f565b81861015611ff5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614666565b611fff3387612794565b606087878787878760405160240161201c969594939291906138f0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcc29a3060000000000000000000000000000000000000000000000000000000017905260008c8152600a90915220549091506120ac90886126af565b60008a8152600a60205260409081902091909155517f419cb55000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063419cb5509061211090849060040161394c565b600060405180830381600087803b15801561212a57600080fd5b505af115801561213e573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff168a7f0a0607688c86ec1775abcdbab7b33a3a35a6c9cde677c9be880150c231cc6b0b8a8a8a896040516121a6949392919061472a565b60405180910390a4505050505050505050565b6000610fdd6121c7836117e2565b83906126af565b6121d661242b565b600f55565b6000858152600c60205260408082205490517f99178dd8000000000000000000000000000000000000000000000000000000008152879273ffffffffffffffffffffffffffffffffffffffff9092169182916399178dd89161224491339190369060040161383e565b600060405180830381600087803b15801561225e57600080fd5b505af1158015612272573d6000803e3d6000fd5b50505050600061228287866117aa565b6000878152600760209081526040808320848452909152902054909150156122d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061404f565b60008411612310576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613dd9565b600086815260076020908152604080832084845282529182902086905581516080810190925260468083526123619288929091906147949083013960008b8152600a60205260409020549190613026565b6000898152600a60209081526040808320939093558382526008905220600181015461239257612392888888612a39565b87878a7ffdfb0eefa96935b8a8c0edf528e125dc6f3934fdbbfce31b38967e8ff413dccd896040516121a69190613943565b600e5481565b600d6020526000908152604090205460ff1681565b600a6020526000908152604090205481565b6000610fdd6123ff8361306c565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040902054906126af565b600b5473ffffffffffffffffffffffffffffffffffffffff16331461247c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613a50565b565b60008082116124b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614166565b8184106124f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f27565b6124fb826130ea565b835114612534576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061437e565b8460005b84518110156125db5785600116600114156125905784818151811061255957fe5b6020026020010151826040516020016125739291906137f3565b6040516020818303038152906040528051906020012091506125cf565b8185828151811061259d57fe5b60200260200101516040516020016125b69291906137f3565b6040516020818303038152906040528051906020012091505b600195861c9501612538565b5090951495945050505050565b6000828152600460205260409020805461262e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b1b565b600181015460009061264090846126af565b825490915081111561267e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906144bb565b6001909101555050565b61269184613199565b61269f8361146484846126f5565b8015610ea757610ea73382612888565b6000828201838110156126ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613bc0565b9392505050565b600082821115612731576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613da2565b50900390565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205461276790826126af565b73ffffffffffffffffffffffffffffffffffffffff90921660009081526003602052604090209190915550565b8034146127cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613eca565b5050565b33600090815260066020908152604080832085845290915290205415612823576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614401565b61282d3382612737565b336000908152600660209081526040808320858452909152908190208290555182907f0c3d250c7831051e78aa6a56679e590374c7c424415ffe4aa474491def2fe7059061287c908490613943565b60405180910390a25050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040516128bf9190613801565b60006040518083038185875af1925050503d80600081146128fc576040519150601f19603f3d011682016040523d82523d6000602084013e612901565b606091505b50509050806117a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906139bc565b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205461296c90826126af565b73ffffffffffffffffffffffffffffffffffffffff90921660009081526002602052604090209190915550565b6000826129a857506000610fdd565b828202828482816129b557fe5b04146126ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906140ac565b6000808211612a28576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613e36565b818381612a3157fe5b049392505050565b612a41610fe3565b821415612a5757612a52838261321b565b6117a5565b6000828152600a6020526040902054612a7090826126af565b6000838152600a6020908152604080832093909355600c9052205473ffffffffffffffffffffffffffffffffffffffff1680612ad8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f84565b60608483604051602401612aed9291906137f3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ffd31c5ba00000000000000000000000000000000000000000000000000000000179052517f419cb55000000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff83169063419cb55090612bb690849060040161394c565b600060405180830381600087803b158015612bd057600080fd5b505af1158015612be4573d6000803e3d6000fd5b505050505050505050565b600080825111612c2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906145ac565b815160011415612c515781600081518110612c4257fe5b60200260200101519050610ae6565b612c59613344565b5060408051610200810182527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381527f633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d60208201527f890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d818301527f3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd86060808301919091527fecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da60808301527fdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da560a08301527f617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d760c08301527f292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead60e08301527fe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e106101008301527f7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f826101208301527fe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e836365166101408301527f3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c6101608301527fad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e6101808301527fa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab6101a08301527f4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c8626101c08301527f2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf106101e0830152825183815280820184529192909190602082018180368337505085519192506000918291508180805b60018411156130025750506002820460018084161460005b82811015612f7e578a8160020281518110612f2557fe5b602002602001015196508a8160020260010181518110612f4157fe5b6020026020010151955086602089015285604089015287805190602001208b8281518110612f6b57fe5b6020908102919091010152600101612f0e565b508015612fe157896001850381518110612f9457fe5b60200260200101519550878360108110612faa57fe5b602002015160001b945085602088015284604088015286805190602001208a8381518110612fd457fe5b6020026020010181815250505b80612fed576000612ff0565b60015b60ff1682019350600190920191612ef6565b8960008151811061300f57fe5b602002602001015198505050505050505050919050565b60008184841115613064576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1919061394c565b505050900390565b60008061307842610ead565b9050600080613840600e548161308a57fe5b04905060005b818110156130e057808403600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8a1684529091529020546130d69084906126af565b9250600101613090565b5090949350505050565b6000808211613125576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613fbb565b816001141561313657506000610ae6565b81600060805b60018110613184577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001821b01811b83161561317c5791821c91908101905b60011c61313c565b506001811b84146126ee576001019392505050565b60008181526005602052604090205460ff16156131e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613e6d565b600090815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600061322783836117aa565b60008181526004602052604090205490915015613270576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614018565b600082116132aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141f8565b6040805160608101825283815260006020808301828152428486019081528684526004909252918490209251835590516001830155516002909101555183907fb33d2162aead99dab59e77a7a67ea025b776bf8ca8079e132afdf9b23e03bd4290613316908590613943565b60405180910390a2505050565b60405180606001604052806000815260200160008152602001600081525090565b6040518061020001604052806010906020820280368337509192915050565b60008083601f840112613374578182fd5b50813567ffffffffffffffff81111561338b578182fd5b60208301915083602080830285010111156133a557600080fd5b9250929050565b6000602082840312156133bd578081fd5b81356126ee81614771565b600080600080606085870312156133dd578283fd5b84356133e881614771565b9350602085013567ffffffffffffffff811115613403578384fd5b61340f87828801613363565b9598909750949560400135949350505050565b60008060408385031215613434578182fd5b823561343f81614771565b946020939093013593505050565b60008060008060008060008060e0898b031215613468578384fd5b883561347381614771565b97506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff8111156134aa578384fd5b6134b68b828c01613363565b999c989b50969995989497949560c00135949350505050565b600080600080608085870312156134e4578384fd5b84356134ef81614771565b966020860135965060408601359560600135945092505050565b6000806000806000806000806000806000806101608d8f03121561352b578384fd5b6135358d35614771565b8c359b5060208d01359a5060408d0135995060608d0135985060808d0135975060a08d0135965060c08d0135955060e08d013594506101008d0135935067ffffffffffffffff6101208e0135111561358b578283fd5b61359c8e6101208f01358f01613363565b81945080935050506101408d013590509295989b509295989b509295989b565b6000602082840312156135cd578081fd5b5035919050565b600080604083850312156135e6578182fd5b50508035926020909101359150565b600080600060608486031215613609578283fd5b8335925060208401359150604084013561362281614771565b809150509250925092565b600080600060608486031215613641578081fd5b505081359360208301359350604090920135919050565b6000806040838503121561366a578182fd5b82359150602083013561367c81614771565b809150509250929050565b600080600080600080600060e0888a0312156136a1578081fd5b8735965060208801356136b381614771565b96999698505050506040850135946060810135946080820135945060a0820135935060c0909101359150565b600080600080600080600060e0888a0312156136f9578081fd5b87359650602088013561370b81614771565b955060408801359450606088013593506080880135925060a088013561373081614771565b8092505060c0880135905092959891949750929550565b60008060408385031215613759578182fd5b823591506020830135801515811461367c578182fd5b600080600080600060a08688031215613786578283fd5b505083359560208501359550604085013594606081013594506080013592509050565b600081518084526137c1816020860160208601614745565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b918252602082015260400190565b60008251613813818460208701614745565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff851682526040602083015282604083015282846060840137818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b73ffffffffffffffffffffffffffffffffffffffff9687168152602081019590955260408501939093526060840191909152909216608082015290151560a082015260c00190565b73ffffffffffffffffffffffffffffffffffffffff9687168152602081019590955260408501939093526060840191909152909216608082015260a081019190915260c00190565b901515815260200190565b90815260200190565b6000602082526126ee60208301846137a9565b60208082526027908201527f4c315f4252473a204d757374207472616e736665722061206e6f6e2d7a65726f60408201527f20616d6f756e7400000000000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f4c315f4554485f4252473a20455448207472616e73666572206661696c656400604082015260600190565b6020808252603b908201527f4c315f4252473a206368616c6c656e6765506572696f64206d7573742062652060408201527f646976697369626c652062792054494d455f534c4f545f53495a450000000000606082015260800190565b6020808252601f908201527f4c315f4252473a2043616c6c6572206973206e6f7420746865206f776e657200604082015260600190565b60208082526028908201527f4c315f4252473a205472616e73666572526f6f7420686173206e6f742062656560408201527f6e20626f6e646564000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f4c325f4252473a207472616e73666572496420686173206e6f20626f6e640000604082015260600190565b6020808252601c908201527f4252473a205472616e7366657220726f6f74206e6f7420666f756e6400000000604082015260600190565b6020808252601e908201527f4143543a204164647265737320697320616c726561647920626f6e6465720000604082015260600190565b6020808252601b908201527f4252473a205472616e73666572526f6f74206e6f7420666f756e640000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526025908201527f4c315f4252473a205472616e73666572526f6f7420616c72656164792072657360408201527f6f6c766564000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526027908201527f4c315f4252473a205472616e73666572526f6f7420616c72656164792063686160408201527f6c6c656e67656400000000000000000000000000000000000000000000000000606082015260800190565b6020808252603b908201527f4252473a205472616e73666572526f6f742063616e6e6f74206265207265736360408201527f756564206265666f726520746865205265736375652044656c61790000000000606082015260800190565b6020808252601a908201527f4143543a2041646472657373206973206e6f7420626f6e646572000000000000604082015260600190565b60208082526028908201527f4c315f4252473a2053656e647320746f207468697320636861696e496420617260408201527f6520706175736564000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252602e908201527f4c315f4252473a20726f6f74436f6d6d69747465644174206d7573742062652060408201527f67726561746572207468616e2030000000000000000000000000000000000000606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252602c908201527f4252473a20546865207472616e736665722068617320616c726561647920626560408201527f656e2077697468647261776e0000000000000000000000000000000000000000606082015260800190565b60208082526027908201527f4c315f4554485f4252473a2056616c756520646f6573206e6f74206d6174636860408201527f20616d6f756e7400000000000000000000000000000000000000000000000000606082015260800190565b60208082526024908201527f4c69625f4d65726b6c65547265653a20496e646578206f7574206f6620626f7560408201527f6e64732e00000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601d908201527f4c315f4252473a20636861696e4964206e6f7420737570706f72746564000000604082015260600190565b60208082526030908201527f4c69625f4d65726b6c65547265653a2043616e6e6f7420636f6d70757465206360408201527f65696c286c6f675f3229206f6620302e00000000000000000000000000000000606082015260800190565b6020808252601e908201527f4252473a205472616e7366657220726f6f7420616c7265616479207365740000604082015260600190565b60208082526026908201527f4c315f4252473a205472616e73666572526f6f7420616c726561647920636f6e60408201527f6669726d65640000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f4c315f4252473a205472616e73666572526f6f742068617320616c726561647960408201527f206265656e20636f6e6669726d65640000000000000000000000000000000000606082015260800190565b60208082526037908201527f4c69625f4d65726b6c65547265653a20546f74616c206c6561766573206d757360408201527f742062652067726561746572207468616e207a65726f2e000000000000000000606082015260800190565b6020808252818101527f4143543a204e6f7420656e6f75676820617661696c61626c6520637265646974604082015260600190565b6020808252602d908201527f4252473a2043616e6e6f7420736574205472616e73666572526f6f7420746f7460408201527f616c416d6f756e74206f66203000000000000000000000000000000000000000606082015260800190565b60208082526019908201527f4143543a2043616c6c6572206973206e6f7420626f6e64657200000000000000604082015260600190565b6020808252601b908201527f4252473a20496e76616c6964207472616e736665722070726f6f660000000000604082015260600190565b602080825260409082018190527f4c315f4252473a205472616e73666572526f6f742063616e6e6f742062652063908201527f68616c6c656e676564206166746572206368616c6c656e676520706572696f64606082015260800190565b60208082526026908201527f4c315f4252473a204368616c6c656e676520706572696f6420686173206e6f7460408201527f20656e6465640000000000000000000000000000000000000000000000000000606082015260800190565b6020808252604d908201527f4c69625f4d65726b6c65547265653a20546f74616c207369626c696e6773206460408201527f6f6573206e6f7420636f72726563746c7920636f72726573706f6e6420746f2060608201527f746f74616c206c65617665732e00000000000000000000000000000000000000608082015260a00190565b60208082526027908201527f4252473a205769746864726177616c2068617320616c7265616479206265656e60408201527f20626f6e64656400000000000000000000000000000000000000000000000000606082015260800190565b6020808252602c908201527f4c315f4252473a205472616e73666572526f6f7420686173206e6f742062656560408201527f6e206368616c6c656e6765640000000000000000000000000000000000000000606082015260800190565b6020808252602a908201527f4252473a205769746864726177616c2065786365656473205472616e7366657260408201527f526f6f7420746f74616c00000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252602b908201527f4c315f4252473a205f6e6577476f7665726e616e63652063616e6e6f7420626560408201527f2061646472657373283029000000000000000000000000000000000000000000606082015260800190565b60208082526034908201527f4c69625f4d65726b6c65547265653a204d7573742070726f766964652061742060408201527f6c65617374206f6e65206c65616620686173682e000000000000000000000000606082015260800190565b6020808252602c908201527f4c315f4252473a205472616e73666572526f6f742068617320616c726561647960408201527f206265656e20626f6e6465640000000000000000000000000000000000000000606082015260800190565b60208082526028908201527f4c315f4252473a2052656c61796572206665652063616e6e6f7420657863656560408201527f6420616d6f756e74000000000000000000000000000000000000000000000000606082015260800190565b81518152602080830151908201526040918201519181019190915260600190565b96875273ffffffffffffffffffffffffffffffffffffffff95909516602087015260408601939093526060850191909152608084015260a083015260c082015260e00190565b93845260208401929092526040830152606082015260800190565b60005b83811015614760578181015183820152602001614748565b83811115610ea75750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114610fa857600080fdfe4c315f4252473a20416d6f756e74206578636565647320636861696e42616c616e63652e205468697320696e646963617465732061206c617965722d32206661696c7572652ea2646970667358221220059efbacfa8e4391e713a70ec9b5c2c2563c7f47558e9ce3c7e1c29a5888cbe664736f6c634300060c00330000000000000000000000000000000000000000000000000000000000000040000000000000000000000000f56e305024b195383245a075737d16dbdb8487fb00000000000000000000000000000000000000000000000000000000000000020000000000000000000000002a6303e6b99d451df3566068ebb110708335658f0000000000000000000000009137a628546e2b1bc26f60a5d1262fb6d58ea44a

Deployed Bytecode

0x6080604052600436106102f25760003560e01c806381707b801161018f578063cbd1642e116100e1578063eecd57e61161008a578063fa2a69a311610064578063fa2a69a314610814578063fc110b6714610834578063ffa9286c14610854576102f2565b8063eecd57e6146107bf578063ef6ebe5e146107df578063f3f480d9146107ff576102f2565b8063d5ef7551116100bb578063d5ef75511461076c578063deace8f51461078c578063e19be1501461079f576102f2565b8063cbd1642e146106ff578063ce803b4f1461071f578063d44481631461074c576102f2565b8063a35962f311610143578063af215f941161011d578063af215f941461069f578063b162717e146106bf578063c7525dd3146106df576102f2565b8063a35962f31461064c578063ab033ea91461066c578063adc9772e1461068c576102f2565b8063960a7afa11610174578063960a7afa146105f757806398c4f76d14610617578063a239f5ee1461062c576102f2565b806381707b80146105b75780638d8798bf146105d7576102f2565b80633a7af631116102485780635a7e1083116101fc5780636cff06a7116101d65780636cff06a71461056d5780637398d28214610582578063767631d5146105a2576102f2565b80635a7e1083146104f95780635aa6e6751461052b5780635d475fdd1461054d576102f2565b80634de8c6e61161022d5780634de8c6e6146104a45780635325937f146104b957806357344e6f146104d9576102f2565b80633a7af631146104575780633b8fea2814610484576102f2565b806323c452cd116102aa578063302830ab11610284578063302830ab146104025780633408e4701461042257806339ada66914610437576102f2565b806323c452cd146103a25780632b85dcc9146103c25780632e17de78146103e2576102f2565b806313948c76116102db57806313948c7614610339578063149420241461036f5780631bbe15ea1461038f576102f2565b806304e6c2c0146102f75780630f7aadb714610319575b600080fd5b34801561030357600080fd5b506103176103123660046133ac565b610874565b005b34801561032557600080fd5b50610317610334366004613509565b61095e565b34801561034557600080fd5b506103596103543660046133ac565b610abf565b6040516103669190613943565b60405180910390f35b34801561037b57600080fd5b5061031761038a366004613747565b610aeb565b61031761039d36600461362d565b610b31565b3480156103ae57600080fd5b506103176103bd3660046134cf565b610d9b565b3480156103ce57600080fd5b506103596103dd3660046135bc565b610ead565b3480156103ee57600080fd5b506103176103fd3660046135bc565b610eb5565b34801561040e57600080fd5b5061035961041d366004613422565b610fab565b34801561042e57600080fd5b50610359610fe3565b34801561044357600080fd5b506103176104523660046135bc565b610fe7565b34801561046357600080fd5b506104776104723660046135bc565b610ff4565b6040516103669190613938565b34801561049057600080fd5b5061035961049f3660046135d4565b611009565b3480156104b057600080fd5b50610359611026565b3480156104c557600080fd5b506103176104d43660046133ac565b61102c565b3480156104e557600080fd5b506103596104f43660046133ac565b61110e565b34801561050557600080fd5b506105196105143660046135bc565b611136565b604051610366969594939291906138a8565b34801561053757600080fd5b5061054061119a565b604051610366919061381d565b34801561055957600080fd5b506103176105683660046135bc565b6111b6565b34801561057957600080fd5b506103596111ff565b34801561058e57600080fd5b5061035961059d366004613658565b611205565b3480156105ae57600080fd5b50610359611222565b3480156105c357600080fd5b506103176105d236600461362d565b611228565b3480156105e357600080fd5b506103176105f236600461362d565b6114dc565b34801561060357600080fd5b506103596106123660046135d4565b6117aa565b34801561062357600080fd5b506103596117dd565b34801561063857600080fd5b506103596106473660046135bc565b6117e2565b34801561065857600080fd5b506105406106673660046135bc565b6117ef565b34801561067857600080fd5b506103176106873660046133ac565b611817565b61031761069a366004613422565b6118b3565b3480156106ab57600080fd5b506103596106ba366004613687565b6119c4565b3480156106cb57600080fd5b506103176106da3660046133c8565b611a06565b3480156106eb57600080fd5b506103176106fa36600461344d565b611b83565b34801561070b57600080fd5b5061031761071a3660046135f5565b611d0a565b34801561072b57600080fd5b5061073f61073a3660046135d4565b611e01565b60405161036691906146c3565b34801561075857600080fd5b50610317610767366004613658565b611e56565b34801561077857600080fd5b506104776107873660046133ac565b611eb1565b61031761079a3660046136df565b611edc565b3480156107ab57600080fd5b506103596107ba3660046135bc565b6121b9565b3480156107cb57600080fd5b506103176107da3660046135bc565b6121ce565b3480156107eb57600080fd5b506103176107fa36600461376f565b6121db565b34801561080b57600080fd5b506103596123c4565b34801561082057600080fd5b5061047761082f3660046135bc565b6123ca565b34801561084057600080fd5b5061035961084f3660046135bc565b6123df565b34801561086057600080fd5b5061035961086f3660046133ac565b6123f1565b61087c61242b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602081905260409091205460ff161515146108ea576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d0e565b60405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff811660008181526001602052604080822080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055517f4234ba611d325b3ba434c4e1b037967b955b1274d4185ee9847b7491111a48ff9190a250565b6002600054141561099b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b600260009081556109b86109ad610fe3565b8e8e8e8e8e8e6119c4565b90506109fe81868686808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d95949392508891505061247e565b610a34576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061428c565b6000610a4088886117aa565b9050610a4c818e6125e8565b610a59828f8f6000612688565b8d73ffffffffffffffffffffffffffffffffffffffff16827f9475cdbde5fc71fe2ccd413c82878ee54d061b9f74f9e2e1a03ff1178821502c8f8f604051610aa29291906137f3565b60405180910390a350506001600055505050505050505050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260409020545b919050565b610af361242b565b6000918252600d602052604090912080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016911515919091179055565b6000610b3d84846117aa565b600081815260086020908152604080832086845260078352818420858552909252909120549192509015610b9d576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614109565b6001810154610bd8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613a87565b6000610bf3600e5483600101546126af90919063ffffffff16565b905042811015610c2f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906142c3565b600382015415610c6b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613c54565b4260038301556004820180547fffffffffffffffffffffffff000000000000000000000000000000000000000016331790556001820154600090610cae90610ead565b90506000610cbb876121b9565b8454600084815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff9094168084529390915290205491925090610cfe90836126f5565b600084815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff80871685529252909120919091558554610d3f911683612737565b6000610d4a896117e2565b9050610d563382612794565b89877fec2697dcba539a0ac947cdf1f6d0b6314c065429eca8be2435859b10209d4c278b604051610d879190613943565b60405180910390a350505050505050505050565b3360009081526001602052604090205460ff16610de4576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614255565b60026000541415610e21576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b60026000908155610e3f610e33610fe3565b868686866000806119c4565b9050610e4b81856127d1565b610e5781868685612688565b506001600055610e66336123f1565b610e6f3361110e565b1015610ea7576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b50505050565b613840900490565b60026000541415610ef2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b6002600055610f013382612737565b610f0b3382612888565b3373ffffffffffffffffffffffffffffffffffffffff167f85082129d87b2fe11527cb1b3b7a520aeb5aa6913f88a3d8757fe40d1db02fdd82604051610f519190613943565b60405180910390a26001600055610f67336123f1565b610f703361110e565b1015610fa8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b50565b73ffffffffffffffffffffffffffffffffffffffff821660009081526006602090815260408083208484529091529020545b92915050565b4690565b610fef61242b565b601055565b60009081526005602052604090205460ff1690565b600760209081526000928352604080842090915290825290205481565b61384081565b61103461242b565b73ffffffffffffffffffffffffffffffffffffffff811660009081526001602052604090205460ff1615611094576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b52565b73ffffffffffffffffffffffffffffffffffffffff8116600081815260016020819052604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016909217909155517f2cec73b7434d3b91198ad1a618f63e6a0761ce281af5ec9ec76606d948d03e239190a250565b73ffffffffffffffffffffffffffffffffffffffff1660009081526002602052604090205490565b6008602052600090815260409020805460018201546002830154600384015460049094015473ffffffffffffffffffffffffffffffffffffffff93841694929391929181169074010000000000000000000000000000000000000000900460ff1686565b600b5473ffffffffffffffffffffffffffffffffffffffff1681565b6111be61242b565b6138408106156111fa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906139f3565b600e55565b60105481565b600960209081526000928352604080842090915290825290205481565b600f5481565b600061123484846117aa565b6000818152600860205260409020600381015491925090611281576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061445e565b600f546003820154611292916126af565b42116112ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614321565b600481015474010000000000000000000000000000000000000000900460ff1615611321576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613bf7565b6004810180547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055600061136d856117e2565b6000858152600760209081526040808320878452909152902054909150156114485760105460008581526007602090815260408083208784529091529020546113b5916126af565b826001015411156113f95781546113f49073ffffffffffffffffffffffffffffffffffffffff166113ef836113e9896121b9565b906126af565b61293c565b611443565b600482015461141e9073ffffffffffffffffffffffffffffffffffffffff168261293c565b81546114439073ffffffffffffffffffffffffffffffffffffffff166113ef876121b9565b61149b565b61146961dead611464600461145e856001612999565b906129ed565b612888565b60048083015461149b9173ffffffffffffffffffffffffffffffffffffffff909116906113ef9061145e856007612999565b85837f4a99228a8a6d774d261be57ab0ed833bb1bae1f22bbbd3d4767b75ad03fdddf7876040516114cc9190613943565b60405180910390a3505050505050565b3360009081526001602052604090205460ff16611525576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614255565b600061153184836117aa565b600084815260076020908152604080832084845290915290205490915015611585576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614109565b600081815260086020526040902060010154156115ce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614609565b60006115d942610ead565b905060006115e6846121b9565b600083815260096020908152604080832033845290915290205490915061160d90826126af565b60008381526009602090815260408083203380855290835281842094909455805160c08101825293845242848301908152848201898152606086018581526080870186815260a088018781528b88526008909652939095209551865473ffffffffffffffffffffffffffffffffffffffff9182167fffffffffffffffffffffffff00000000000000000000000000000000000000009182161788559251600188015590516002870155935160038601559051600490940180549251151574010000000000000000000000000000000000000000027fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff95909416929091169190911792909216179055611720868686612a39565b857fa57b3e1f3af9eca02201028629700658608222c365064584cfe65d9630ef4f7b856040516117509190613943565b60405180910390a2505050611764336123f1565b61176d3361110e565b10156117a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141c3565b505050565b600082826040516020016117bf9291906137f3565b60405160208183030381529060405280519060200120905092915050565b600a81565b6000610fdd82600a6129ed565b600c6020526000908152604090205473ffffffffffffffffffffffffffffffffffffffff1681565b61181f61242b565b73ffffffffffffffffffffffffffffffffffffffff811661186c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061454f565b600b80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b600260005414156118f0576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614518565b6002600090815573ffffffffffffffffffffffffffffffffffffffff831681526001602081905260409091205460ff16151514611959576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d0e565b6119633382612794565b61196d828261293c565b8173ffffffffffffffffffffffffffffffffffffffff167febedb8b3c678666e7f36970bc8f57abf6d8fa2e828c0da91ea5b75bf68ed101a826040516119b39190613943565b60405180910390a250506001600055565b6000878787878787876040516020016119e397969594939291906146e4565b604051602081830303815290604052805190602001209050979650505050505050565b6000611a44848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250612bef92505050565b90506000611a5282846117aa565b90506000805b85811015611b165773ffffffffffffffffffffffffffffffffffffffff8816600090815260066020526040812081898985818110611a9257fe5b9050602002013581526020019081526020016000205490506000811115611b0d57611abd83826126af565b73ffffffffffffffffffffffffffffffffffffffff8a16600090815260066020526040812091945090818a8a86818110611af357fe5b905060200201358152602001908152602001600020819055505b50600101611a58565b50611b2182826125e8565b611b2b878261293c565b828773ffffffffffffffffffffffffffffffffffffffff167f78e830d08be9d5f957414c84d685c061ecbd8467be98b42ebb64f0118b57d2ff83604051611b729190613943565b60405180910390a350505050505050565b611bc787858585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508c95949392508791505061247e565b611bfd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061428c565b6000611c0987876117aa565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526006602090815260408083208c845290915290205490915080611c74576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613ae4565b73ffffffffffffffffffffffffffffffffffffffff8a1660009081526006602090815260408083208c8452909152812055611caf82826125e8565b611cb98a8261293c565b87898b73ffffffffffffffffffffffffffffffffffffffff167f84eb21b24c31b27a3bc67dde4a598aad06db6e9415cd66544492b9616996143c60405160405180910390a450505050505050505050565b611d1261242b565b6000611d1e84846117aa565b9050611d28613323565b611d328585611e01565b9050806040015160001415611d73576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b89565b80518414611d7d57fe5b6040810151600090611d92906249d4006126af565b905080421015611dce576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613cb1565b60208201518251600091611de291906126f5565b9050611dee84826125e8565b611df88582612888565b50505050505050565b611e09613323565b60046000611e1785856117aa565b81526020019081526020016000206040518060600160405290816000820154815260200160018201548152602001600282015481525050905092915050565b611e5e61242b565b6000918252600c602052604090912080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff909216919091179055565b73ffffffffffffffffffffffffffffffffffffffff1660009081526001602052604090205460ff1690565b6000878152600c602052604090205473ffffffffffffffffffffffffffffffffffffffff1680611f38576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f84565b6000888152600d602052604090205460ff1615611f81576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613d45565b60008611611fbb576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061395f565b81861015611ff5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614666565b611fff3387612794565b606087878787878760405160240161201c969594939291906138f0565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fcc29a3060000000000000000000000000000000000000000000000000000000017905260008c8152600a90915220549091506120ac90886126af565b60008a8152600a60205260409081902091909155517f419cb55000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063419cb5509061211090849060040161394c565b600060405180830381600087803b15801561212a57600080fd5b505af115801561213e573d6000803e3d6000fd5b505050508373ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff168a7f0a0607688c86ec1775abcdbab7b33a3a35a6c9cde677c9be880150c231cc6b0b8a8a8a896040516121a6949392919061472a565b60405180910390a4505050505050505050565b6000610fdd6121c7836117e2565b83906126af565b6121d661242b565b600f55565b6000858152600c60205260408082205490517f99178dd8000000000000000000000000000000000000000000000000000000008152879273ffffffffffffffffffffffffffffffffffffffff9092169182916399178dd89161224491339190369060040161383e565b600060405180830381600087803b15801561225e57600080fd5b505af1158015612272573d6000803e3d6000fd5b50505050600061228287866117aa565b6000878152600760209081526040808320848452909152902054909150156122d6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061404f565b60008411612310576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613dd9565b600086815260076020908152604080832084845282529182902086905581516080810190925260468083526123619288929091906147949083013960008b8152600a60205260409020549190613026565b6000898152600a60209081526040808320939093558382526008905220600181015461239257612392888888612a39565b87878a7ffdfb0eefa96935b8a8c0edf528e125dc6f3934fdbbfce31b38967e8ff413dccd896040516121a69190613943565b600e5481565b600d6020526000908152604090205460ff1681565b600a6020526000908152604090205481565b6000610fdd6123ff8361306c565b73ffffffffffffffffffffffffffffffffffffffff8416600090815260036020526040902054906126af565b600b5473ffffffffffffffffffffffffffffffffffffffff16331461247c576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613a50565b565b60008082116124b9576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614166565b8184106124f2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f27565b6124fb826130ea565b835114612534576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e19061437e565b8460005b84518110156125db5785600116600114156125905784818151811061255957fe5b6020026020010151826040516020016125739291906137f3565b6040516020818303038152906040528051906020012091506125cf565b8185828151811061259d57fe5b60200260200101516040516020016125b69291906137f3565b6040516020818303038152906040528051906020012091505b600195861c9501612538565b5090951495945050505050565b6000828152600460205260409020805461262e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613b1b565b600181015460009061264090846126af565b825490915081111561267e576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906144bb565b6001909101555050565b61269184613199565b61269f8361146484846126f5565b8015610ea757610ea73382612888565b6000828201838110156126ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613bc0565b9392505050565b600082821115612731576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613da2565b50900390565b73ffffffffffffffffffffffffffffffffffffffff821660009081526003602052604090205461276790826126af565b73ffffffffffffffffffffffffffffffffffffffff90921660009081526003602052604090209190915550565b8034146127cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613eca565b5050565b33600090815260066020908152604080832085845290915290205415612823576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614401565b61282d3382612737565b336000908152600660209081526040808320858452909152908190208290555182907f0c3d250c7831051e78aa6a56679e590374c7c424415ffe4aa474491def2fe7059061287c908490613943565b60405180910390a25050565b6040805160008082526020820190925273ffffffffffffffffffffffffffffffffffffffff84169083906040516128bf9190613801565b60006040518083038185875af1925050503d80600081146128fc576040519150601f19603f3d011682016040523d82523d6000602084013e612901565b606091505b50509050806117a5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906139bc565b73ffffffffffffffffffffffffffffffffffffffff821660009081526002602052604090205461296c90826126af565b73ffffffffffffffffffffffffffffffffffffffff90921660009081526002602052604090209190915550565b6000826129a857506000610fdd565b828202828482816129b557fe5b04146126ee576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906140ac565b6000808211612a28576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613e36565b818381612a3157fe5b049392505050565b612a41610fe3565b821415612a5757612a52838261321b565b6117a5565b6000828152600a6020526040902054612a7090826126af565b6000838152600a6020908152604080832093909355600c9052205473ffffffffffffffffffffffffffffffffffffffff1680612ad8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613f84565b60608483604051602401612aed9291906137f3565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167ffd31c5ba00000000000000000000000000000000000000000000000000000000179052517f419cb55000000000000000000000000000000000000000000000000000000000815290915073ffffffffffffffffffffffffffffffffffffffff83169063419cb55090612bb690849060040161394c565b600060405180830381600087803b158015612bd057600080fd5b505af1158015612be4573d6000803e3d6000fd5b505050505050505050565b600080825111612c2b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906145ac565b815160011415612c515781600081518110612c4257fe5b60200260200101519050610ae6565b612c59613344565b5060408051610200810182527f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e56381527f633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d60208201527f890740a8eb06ce9be422cb8da5cdafc2b58c0a5e24036c578de2a433c828ff7d818301527f3b8ec09e026fdc305365dfc94e189a81b38c7597b3d941c279f042e8206e0bd86060808301919091527fecd50eee38e386bd62be9bedb990706951b65fe053bd9d8a521af753d139e2da60808301527fdefff6d330bb5403f63b14f33b578274160de3a50df4efecf0e0db73bcdd3da560a08301527f617bdd11f7c0a11f49db22f629387a12da7596f9d1704d7465177c63d88ec7d760c08301527f292c23a9aa1d8bea7e2435e555a4a60e379a5a35f3f452bae60121073fb6eead60e08301527fe1cea92ed99acdcb045a6726b2f87107e8a61620a232cf4d7d5b5766b3952e106101008301527f7ad66c0a68c72cb89e4fb4303841966e4062a76ab97451e3b9fb526a5ceb7f826101208301527fe026cc5a4aed3c22a58cbd3d2ac754c9352c5436f638042dca99034e836365166101408301527f3d04cffd8b46a874edf5cfae63077de85f849a660426697b06a829c70dd1409c6101608301527fad676aa337a485e4728a0b240d92b3ef7b3c372d06d189322bfd5f61f1e7203e6101808301527fa2fca4a49658f9fab7aa63289c91b7c7b6c832a6d0e69334ff5b0a3483d09dab6101a08301527f4ebfd9cd7bca2505f7bef59cc1c12ecc708fff26ae4af19abe852afe9e20c8626101c08301527f2def10d13dd169f550f578bda343d9717a138562e0093b380a1120789d53cf106101e0830152825183815280820184529192909190602082018180368337505085519192506000918291508180805b60018411156130025750506002820460018084161460005b82811015612f7e578a8160020281518110612f2557fe5b602002602001015196508a8160020260010181518110612f4157fe5b6020026020010151955086602089015285604089015287805190602001208b8281518110612f6b57fe5b6020908102919091010152600101612f0e565b508015612fe157896001850381518110612f9457fe5b60200260200101519550878360108110612faa57fe5b602002015160001b945085602088015284604088015286805190602001208a8381518110612fd457fe5b6020026020010181815250505b80612fed576000612ff0565b60015b60ff1682019350600190920191612ef6565b8960008151811061300f57fe5b602002602001015198505050505050505050919050565b60008184841115613064576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1919061394c565b505050900390565b60008061307842610ead565b9050600080613840600e548161308a57fe5b04905060005b818110156130e057808403600090815260096020908152604080832073ffffffffffffffffffffffffffffffffffffffff8a1684529091529020546130d69084906126af565b9250600101613090565b5090949350505050565b6000808211613125576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613fbb565b816001141561313657506000610ae6565b81600060805b60018110613184577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6001821b01811b83161561317c5791821c91908101905b60011c61313c565b506001811b84146126ee576001019392505050565b60008181526005602052604090205460ff16156131e2576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190613e6d565b600090815260056020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b600061322783836117aa565b60008181526004602052604090205490915015613270576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e190614018565b600082116132aa576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108e1906141f8565b6040805160608101825283815260006020808301828152428486019081528684526004909252918490209251835590516001830155516002909101555183907fb33d2162aead99dab59e77a7a67ea025b776bf8ca8079e132afdf9b23e03bd4290613316908590613943565b60405180910390a2505050565b60405180606001604052806000815260200160008152602001600081525090565b6040518061020001604052806010906020820280368337509192915050565b60008083601f840112613374578182fd5b50813567ffffffffffffffff81111561338b578182fd5b60208301915083602080830285010111156133a557600080fd5b9250929050565b6000602082840312156133bd578081fd5b81356126ee81614771565b600080600080606085870312156133dd578283fd5b84356133e881614771565b9350602085013567ffffffffffffffff811115613403578384fd5b61340f87828801613363565b9598909750949560400135949350505050565b60008060408385031215613434578182fd5b823561343f81614771565b946020939093013593505050565b60008060008060008060008060e0898b031215613468578384fd5b883561347381614771565b97506020890135965060408901359550606089013594506080890135935060a089013567ffffffffffffffff8111156134aa578384fd5b6134b68b828c01613363565b999c989b50969995989497949560c00135949350505050565b600080600080608085870312156134e4578384fd5b84356134ef81614771565b966020860135965060408601359560600135945092505050565b6000806000806000806000806000806000806101608d8f03121561352b578384fd5b6135358d35614771565b8c359b5060208d01359a5060408d0135995060608d0135985060808d0135975060a08d0135965060c08d0135955060e08d013594506101008d0135935067ffffffffffffffff6101208e0135111561358b578283fd5b61359c8e6101208f01358f01613363565b81945080935050506101408d013590509295989b509295989b509295989b565b6000602082840312156135cd578081fd5b5035919050565b600080604083850312156135e6578182fd5b50508035926020909101359150565b600080600060608486031215613609578283fd5b8335925060208401359150604084013561362281614771565b809150509250925092565b600080600060608486031215613641578081fd5b505081359360208301359350604090920135919050565b6000806040838503121561366a578182fd5b82359150602083013561367c81614771565b809150509250929050565b600080600080600080600060e0888a0312156136a1578081fd5b8735965060208801356136b381614771565b96999698505050506040850135946060810135946080820135945060a0820135935060c0909101359150565b600080600080600080600060e0888a0312156136f9578081fd5b87359650602088013561370b81614771565b955060408801359450606088013593506080880135925060a088013561373081614771565b8092505060c0880135905092959891949750929550565b60008060408385031215613759578182fd5b823591506020830135801515811461367c578182fd5b600080600080600060a08688031215613786578283fd5b505083359560208501359550604085013594606081013594506080013592509050565b600081518084526137c1816020860160208601614745565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b918252602082015260400190565b60008251613813818460208701614745565b9190910192915050565b73ffffffffffffffffffffffffffffffffffffffff91909116815260200190565b600073ffffffffffffffffffffffffffffffffffffffff851682526040602083015282604083015282846060840137818301606090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016010192915050565b73ffffffffffffffffffffffffffffffffffffffff9687168152602081019590955260408501939093526060840191909152909216608082015290151560a082015260c00190565b73ffffffffffffffffffffffffffffffffffffffff9687168152602081019590955260408501939093526060840191909152909216608082015260a081019190915260c00190565b901515815260200190565b90815260200190565b6000602082526126ee60208301846137a9565b60208082526027908201527f4c315f4252473a204d757374207472616e736665722061206e6f6e2d7a65726f60408201527f20616d6f756e7400000000000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f4c315f4554485f4252473a20455448207472616e73666572206661696c656400604082015260600190565b6020808252603b908201527f4c315f4252473a206368616c6c656e6765506572696f64206d7573742062652060408201527f646976697369626c652062792054494d455f534c4f545f53495a450000000000606082015260800190565b6020808252601f908201527f4c315f4252473a2043616c6c6572206973206e6f7420746865206f776e657200604082015260600190565b60208082526028908201527f4c315f4252473a205472616e73666572526f6f7420686173206e6f742062656560408201527f6e20626f6e646564000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f4c325f4252473a207472616e73666572496420686173206e6f20626f6e640000604082015260600190565b6020808252601c908201527f4252473a205472616e7366657220726f6f74206e6f7420666f756e6400000000604082015260600190565b6020808252601e908201527f4143543a204164647265737320697320616c726561647920626f6e6465720000604082015260600190565b6020808252601b908201527f4252473a205472616e73666572526f6f74206e6f7420666f756e640000000000604082015260600190565b6020808252601b908201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604082015260600190565b60208082526025908201527f4c315f4252473a205472616e73666572526f6f7420616c72656164792072657360408201527f6f6c766564000000000000000000000000000000000000000000000000000000606082015260800190565b60208082526027908201527f4c315f4252473a205472616e73666572526f6f7420616c72656164792063686160408201527f6c6c656e67656400000000000000000000000000000000000000000000000000606082015260800190565b6020808252603b908201527f4252473a205472616e73666572526f6f742063616e6e6f74206265207265736360408201527f756564206265666f726520746865205265736375652044656c61790000000000606082015260800190565b6020808252601a908201527f4143543a2041646472657373206973206e6f7420626f6e646572000000000000604082015260600190565b60208082526028908201527f4c315f4252473a2053656e647320746f207468697320636861696e496420617260408201527f6520706175736564000000000000000000000000000000000000000000000000606082015260800190565b6020808252601e908201527f536166654d6174683a207375627472616374696f6e206f766572666c6f770000604082015260600190565b6020808252602e908201527f4c315f4252473a20726f6f74436f6d6d69747465644174206d7573742062652060408201527f67726561746572207468616e2030000000000000000000000000000000000000606082015260800190565b6020808252601a908201527f536166654d6174683a206469766973696f6e206279207a65726f000000000000604082015260600190565b6020808252602c908201527f4252473a20546865207472616e736665722068617320616c726561647920626560408201527f656e2077697468647261776e0000000000000000000000000000000000000000606082015260800190565b60208082526027908201527f4c315f4554485f4252473a2056616c756520646f6573206e6f74206d6174636860408201527f20616d6f756e7400000000000000000000000000000000000000000000000000606082015260800190565b60208082526024908201527f4c69625f4d65726b6c65547265653a20496e646578206f7574206f6620626f7560408201527f6e64732e00000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252601d908201527f4c315f4252473a20636861696e4964206e6f7420737570706f72746564000000604082015260600190565b60208082526030908201527f4c69625f4d65726b6c65547265653a2043616e6e6f7420636f6d70757465206360408201527f65696c286c6f675f3229206f6620302e00000000000000000000000000000000606082015260800190565b6020808252601e908201527f4252473a205472616e7366657220726f6f7420616c7265616479207365740000604082015260600190565b60208082526026908201527f4c315f4252473a205472616e73666572526f6f7420616c726561647920636f6e60408201527f6669726d65640000000000000000000000000000000000000000000000000000606082015260800190565b60208082526021908201527f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f60408201527f7700000000000000000000000000000000000000000000000000000000000000606082015260800190565b6020808252602f908201527f4c315f4252473a205472616e73666572526f6f742068617320616c726561647960408201527f206265656e20636f6e6669726d65640000000000000000000000000000000000606082015260800190565b60208082526037908201527f4c69625f4d65726b6c65547265653a20546f74616c206c6561766573206d757360408201527f742062652067726561746572207468616e207a65726f2e000000000000000000606082015260800190565b6020808252818101527f4143543a204e6f7420656e6f75676820617661696c61626c6520637265646974604082015260600190565b6020808252602d908201527f4252473a2043616e6e6f7420736574205472616e73666572526f6f7420746f7460408201527f616c416d6f756e74206f66203000000000000000000000000000000000000000606082015260800190565b60208082526019908201527f4143543a2043616c6c6572206973206e6f7420626f6e64657200000000000000604082015260600190565b6020808252601b908201527f4252473a20496e76616c6964207472616e736665722070726f6f660000000000604082015260600190565b602080825260409082018190527f4c315f4252473a205472616e73666572526f6f742063616e6e6f742062652063908201527f68616c6c656e676564206166746572206368616c6c656e676520706572696f64606082015260800190565b60208082526026908201527f4c315f4252473a204368616c6c656e676520706572696f6420686173206e6f7460408201527f20656e6465640000000000000000000000000000000000000000000000000000606082015260800190565b6020808252604d908201527f4c69625f4d65726b6c65547265653a20546f74616c207369626c696e6773206460408201527f6f6573206e6f7420636f72726563746c7920636f72726573706f6e6420746f2060608201527f746f74616c206c65617665732e00000000000000000000000000000000000000608082015260a00190565b60208082526027908201527f4252473a205769746864726177616c2068617320616c7265616479206265656e60408201527f20626f6e64656400000000000000000000000000000000000000000000000000606082015260800190565b6020808252602c908201527f4c315f4252473a205472616e73666572526f6f7420686173206e6f742062656560408201527f6e206368616c6c656e6765640000000000000000000000000000000000000000606082015260800190565b6020808252602a908201527f4252473a205769746864726177616c2065786365656473205472616e7366657260408201527f526f6f7420746f74616c00000000000000000000000000000000000000000000606082015260800190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252602b908201527f4c315f4252473a205f6e6577476f7665726e616e63652063616e6e6f7420626560408201527f2061646472657373283029000000000000000000000000000000000000000000606082015260800190565b60208082526034908201527f4c69625f4d65726b6c65547265653a204d7573742070726f766964652061742060408201527f6c65617374206f6e65206c65616620686173682e000000000000000000000000606082015260800190565b6020808252602c908201527f4c315f4252473a205472616e73666572526f6f742068617320616c726561647960408201527f206265656e20626f6e6465640000000000000000000000000000000000000000606082015260800190565b60208082526028908201527f4c315f4252473a2052656c61796572206665652063616e6e6f7420657863656560408201527f6420616d6f756e74000000000000000000000000000000000000000000000000606082015260800190565b81518152602080830151908201526040918201519181019190915260600190565b96875273ffffffffffffffffffffffffffffffffffffffff95909516602087015260408601939093526060850191909152608084015260a083015260c082015260e00190565b93845260208401929092526040830152606082015260800190565b60005b83811015614760578181015183820152602001614748565b83811115610ea75750506000910152565b73ffffffffffffffffffffffffffffffffffffffff81168114610fa857600080fdfe4c315f4252473a20416d6f756e74206578636565647320636861696e42616c616e63652e205468697320696e646963617465732061206c617965722d32206661696c7572652ea2646970667358221220059efbacfa8e4391e713a70ec9b5c2c2563c7f47558e9ce3c7e1c29a5888cbe664736f6c634300060c0033

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

0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000f56e305024b195383245a075737d16dbdb8487fb00000000000000000000000000000000000000000000000000000000000000020000000000000000000000002a6303e6b99d451df3566068ebb110708335658f0000000000000000000000009137a628546e2b1bc26f60a5d1262fb6d58ea44a

-----Decoded View---------------
Arg [0] : bonders (address[]): 0x2A6303e6b99d451Df3566068EBb110708335658f,0x9137a628546e2b1bc26F60A5D1262fb6D58eA44A
Arg [1] : _governance (address): 0xF56e305024B195383245A075737d16dBdb8487Fb

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000040
Arg [1] : 000000000000000000000000f56e305024b195383245a075737d16dbdb8487fb
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [3] : 0000000000000000000000002a6303e6b99d451df3566068ebb110708335658f
Arg [4] : 0000000000000000000000009137a628546e2b1bc26f60a5d1262fb6d58ea44a


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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