ETH Price: $1,862.24 (-0.57%)

Transaction Decoder

Block:
21506831 at Dec-29-2024 08:07:59 AM +UTC
Transaction Fee:
0.000321749208068782 ETH $0.60
Gas Used:
115,447 Gas / 2.786986306 Gwei

Emitted Events:

424 L1_ETH_Bridge.WithdrawalBonded( transferId=5624CED38BAECC00655C8081CB689CB439F2988DCAD27DA5DCC3338743108969, amount=21787278040769313 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
10.993932910139826138 Eth10.993939490618826138 Eth0.000006580479
0x4e5B3BfC...32c12F2cB 0.000109436498766 Eth0.021404384626301653 Eth0.021294948127535653
0x710bDa32...E7f81d564
(Hop Protocol: ETH Bonder)
50.345007615738796466 Eth
Nonce: 1204873
50.345178196443961344 Eth
Nonce: 1204874
0.000170580705164878
0xb8901acB...02919727f
(Hop Protocol: Ethereum Bridge)
6,518.467838035767383166 Eth6,518.446050757726613853 Eth0.021787278040769313

Execution Trace

L1_ETH_Bridge.bondWithdrawal( recipient=0x4e5B3BfC71871A6e34c4e4F70e7dA2b32c12F2cB, amount=21787278040769313, transferNonce=06F2D663F2BABFC7ABB66AD4ECABC4B76A608A386B32ADEFDEDBBB80ED4412A6, bonderFee=492329913233660 )
  • ETH 0.021294948127535653 0x4e5b3bfc71871a6e34c4e4f70e7da2b32c12f2cb.CALL( )
  • ETH 0.00049232991323366 Hop Protocol: ETH Bonder.CALL( )
    bondWithdrawal[Bridge (ln:549)]
    // 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");
        }
    }
    // 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;
        }
    }
    // 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);
            }
        }
    }
    // 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;
    }
    // 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);
        }
    }
    // 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;
        }
    }// 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;
        }
    }
    // 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;
        }
    }