Mumbai Testnet

Contract

0xE0165419e91B772dA6851184681bF383dC5E8df5

Overview

MATIC Balance

Polygon PoS Chain LogoPolygon PoS Chain LogoPolygon PoS Chain Logo0 MATIC

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Value
Withdraw Funds306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000201055.00000001
Withdraw Funds306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000201165.00000001
Withdraw From Ma...306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000217415.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000410745.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688322023-01-07 19:06:19446 days ago1673118379IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
Retract Offer306688272023-01-07 19:06:07446 days ago1673118367IN
0xE0165419...3dC5E8df5
0 MATIC0.000437095.00000001
View all transactions

Latest 25 internal transactions (View All)

Parent Txn Hash Block From To Value
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.18143188 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.18143188 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688322023-01-07 19:06:19446 days ago1673118379
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688272023-01-07 19:06:07446 days ago1673118367
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688272023-01-07 19:06:07446 days ago1673118367
0xE0165419...3dC5E8df5
0.00313896 MATIC
306688272023-01-07 19:06:07446 days ago1673118367
0xE0165419...3dC5E8df5
0.00313896 MATIC
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ExplicitKandel

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 21 : ExplicitKandel.sol
// SPDX-License-Identifier:	BSD-2-Clause

// Kandel.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {CoreKandel, IMangrove, IERC20, AbstractKandel, MgvLib, MgvStructs} from "./abstract/CoreKandel.sol";
import "mgv_src/strategies/utils/TransferLib.sol";
import {console} from "forge-std/console.sol";

contract ExplicitKandel is CoreKandel {
  ///@notice quote distribution: `baseOfIndex[i]` is the amount of base tokens Kandel must give or want at index i
  uint96[] _baseOfIndex;
  ///@notice quote distribution: `quoteOfIndex[i]` is the amount of quote tokens Kandel must give or want at index i
  uint96[] _quoteOfIndex;

  constructor(IMangrove mgv, IERC20 base, IERC20 quote, uint gasreq, uint16 nslots)
    CoreKandel(mgv, base, quote, gasreq, nslots)
  {
    _baseOfIndex = new uint96[](nslots);
    _quoteOfIndex = new uint96[](nslots);
  }

  function __reserve__(address) internal view override returns (address) {
    return address(this);
  }

  ///@notice sets the base/quote distribution that Kandel should follow using continuous slices
  ///@param from start index (included). Must be less than `to`.
  ///@param to end index (excluded). Must be less than `NSLOT`.
  ///@param slice slice[i][0/1] is the distribution of base/quote at index i.
  function setDistribution(uint from, uint to, uint[][2] calldata slice) external onlyAdmin {
    for (uint i = from; i < to; i++) {
      uint sliceIndex = i - from;
      require(uint96(slice[0][sliceIndex]) == slice[0][sliceIndex], "Kandel/baseOverflow");
      require(uint96(slice[1][sliceIndex]) == slice[1][sliceIndex], "Kandel/quoteOverflow");
      _baseOfIndex[i] = uint96(slice[0][sliceIndex]);
      _quoteOfIndex[i] = uint96(slice[1][sliceIndex]);
    }
  }

  ///@inheritdoc AbstractKandel
  function baseOfIndex(uint index) public view override returns (uint96) {
    return _baseOfIndex[index];
  }

  ///@inheritdoc AbstractKandel
  function quoteOfIndex(uint index) public view override returns (uint96) {
    return _quoteOfIndex[index];
  }

  function baseDist() external view onlyAdmin returns (uint96[] memory) {
    return _baseOfIndex;
  }

  function quoteDist() external view onlyAdmin returns (uint96[] memory) {
    return _quoteOfIndex;
  }

  ///@notice checks whether offer whose logic is being executed is currently the best on Mangove
  ///@param order the taker order that is being executed
  ///@dev `isBest` => `order.offer` is the best bid/ask of this strat (but the converse is not true in general).
  function _isBest(MgvLib.SingleOrder calldata order) internal view returns (bool) {
    uint lookup = MGV.offers(order.outbound_tkn, order.inbound_tkn, order.offerId).prev();
    return lookup == 0 || MGV.offers(order.outbound_tkn, order.inbound_tkn, lookup).gives() == 0;
  }

  ///@inheritdoc AbstractKandel
  function _transportLogic(OrderType ba, MgvLib.SingleOrder calldata order)
    internal
    virtual
    override
    returns (OrderType dualBa, uint dualIndex, OfferArgs memory args)
  {
    uint index = indexOfOfferId(ba, order.offerId);

    if (index == 0) {
      emit AllAsks(MGV, BASE, QUOTE);
    }
    if (index == NSLOTS - 1) {
      emit AllBids(MGV, BASE, QUOTE);
    }
    dualIndex = dual(ba, index);
    dualBa = dual(ba);

    (MgvStructs.OfferPacked dualOffer, MgvStructs.OfferDetailPacked dualOfferDetails) = getOffer(dualBa, dualIndex);

    // can repost (at max) what the current taker order gave
    uint maxDualGives = dualOffer.gives() + order.gives;

    // what the distribution says the dual order should ask/bid
    uint shouldGive = _givesOfIndex(dualBa, dualIndex);
    uint shouldWant = _wantsOfIndex(dualBa, dualIndex);

    args.outbound_tkn = IERC20(order.inbound_tkn);
    args.inbound_tkn = IERC20(order.outbound_tkn);

    // letting dual offer complements taker's liquidity with pending when current offer is not sniped.
    // Adding pending to compute dual offer's volume would allow taker to drain liquidity
    // by sniping an offer far from the mid price for a low quantity, dual offer would then only be posted for a
    // proportionally low volume if not complemented with pending.
    uint pending = _isBest(order) ? getPending(dualBa) : 0;

    if (shouldGive >= maxDualGives + pending) {
      if (dualBa == OrderType.Ask) {
        pendingBase -= uint128(pending);
      } else {
        pendingQuote -= uint128(pending);
      }
      args.gives = maxDualGives + pending;
    } else {
      // maxDualGives + pending > shouldGive
      args.gives = shouldGive;
      setPending(dualBa, maxDualGives + pending - shouldGive);
    }

    // note at this stage, maker's profit is `maxDualGives - args.gives`
    // those additional funds are just left on reserve, w/o being published.
    // if giving less volume than distribution, one must adapt wants to match distribution price
    args.wants = args.gives == shouldGive ? shouldWant : (maxDualGives * shouldWant) / shouldGive;
    args.fund = 0;
    args.noRevert = true;
    args.gasreq = dualOfferDetails.gasreq() == 0 ? offerGasreq() : dualOfferDetails.gasreq();
    args.gasprice = dualOfferDetails.gasprice() == 0 ? 0 : dualOfferDetails.gasprice();
    args.pivotId = dualOffer.gives() > 0 ? offerIdOfIndex(dualBa, dualIndex) : dualOffer.next();
  }

  function depositFunds(OrderType ba, uint amount) external {
    IERC20 token = ba == OrderType.Ask ? BASE : QUOTE;
    require(
      TransferLib.transferTokenFrom(token, msg.sender, address(this), amount)
      && push({token:token, amount: amount}) == amount,
       "Kandel/depositFailed"
      );
  }

  function withdrawFunds(OrderType ba, uint amount, address recipient) external onlyAdmin {
    IERC20 token = ba == OrderType.Ask ? BASE : QUOTE;
    require(
      pull({token: token, amount:amount, strict:true}) == amount
      && TransferLib.transferToken(token, recipient, amount)
      , "Kandel/NotEnoughFunds"
    );
  }
}

File 2 of 21 : console.sol
// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.9.0;

library console {
    address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);

    function _sendLogPayload(bytes memory payload) private view {
        uint256 payloadLength = payload.length;
        address consoleAddress = CONSOLE_ADDRESS;
        /// @solidity memory-safe-assembly
        assembly {
            let payloadStart := add(payload, 32)
            let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
        }
    }

    function log() internal view {
        _sendLogPayload(abi.encodeWithSignature("log()"));
    }

    function logInt(int p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
    }

    function logUint(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function logString(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function logBool(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function logAddress(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function logBytes(bytes memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
    }

    function logBytes1(bytes1 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
    }

    function logBytes2(bytes2 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
    }

    function logBytes3(bytes3 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
    }

    function logBytes4(bytes4 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
    }

    function logBytes5(bytes5 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
    }

    function logBytes6(bytes6 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
    }

    function logBytes7(bytes7 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
    }

    function logBytes8(bytes8 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
    }

    function logBytes9(bytes9 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
    }

    function logBytes10(bytes10 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
    }

    function logBytes11(bytes11 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
    }

    function logBytes12(bytes12 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
    }

    function logBytes13(bytes13 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
    }

    function logBytes14(bytes14 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
    }

    function logBytes15(bytes15 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
    }

    function logBytes16(bytes16 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
    }

    function logBytes17(bytes17 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
    }

    function logBytes18(bytes18 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
    }

    function logBytes19(bytes19 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
    }

    function logBytes20(bytes20 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
    }

    function logBytes21(bytes21 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
    }

    function logBytes22(bytes22 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
    }

    function logBytes23(bytes23 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
    }

    function logBytes24(bytes24 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
    }

    function logBytes25(bytes25 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
    }

    function logBytes26(bytes26 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
    }

    function logBytes27(bytes27 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
    }

    function logBytes28(bytes28 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
    }

    function logBytes29(bytes29 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
    }

    function logBytes30(bytes30 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
    }

    function logBytes31(bytes31 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
    }

    function logBytes32(bytes32 p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
    }

    function log(uint p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
    }

    function log(string memory p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
    }

    function log(bool p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
    }

    function log(address p0) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
    }

    function log(uint p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
    }

    function log(uint p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
    }

    function log(uint p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
    }

    function log(uint p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
    }

    function log(string memory p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
    }

    function log(string memory p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
    }

    function log(string memory p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
    }

    function log(string memory p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
    }

    function log(bool p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
    }

    function log(bool p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
    }

    function log(bool p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
    }

    function log(bool p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
    }

    function log(address p0, uint p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
    }

    function log(address p0, string memory p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
    }

    function log(address p0, bool p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
    }

    function log(address p0, address p1) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
    }

    function log(uint p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
    }

    function log(uint p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
    }

    function log(uint p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
    }

    function log(uint p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
    }

    function log(uint p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
    }

    function log(uint p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
    }

    function log(uint p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
    }

    function log(uint p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
    }

    function log(uint p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
    }

    function log(uint p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
    }

    function log(uint p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
    }

    function log(uint p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
    }

    function log(uint p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
    }

    function log(string memory p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
    }

    function log(string memory p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
    }

    function log(string memory p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
    }

    function log(string memory p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
    }

    function log(string memory p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
    }

    function log(string memory p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
    }

    function log(string memory p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
    }

    function log(bool p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
    }

    function log(bool p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
    }

    function log(bool p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
    }

    function log(bool p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
    }

    function log(bool p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
    }

    function log(bool p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
    }

    function log(bool p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
    }

    function log(bool p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
    }

    function log(bool p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
    }

    function log(bool p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
    }

    function log(bool p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
    }

    function log(bool p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
    }

    function log(bool p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
    }

    function log(address p0, uint p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
    }

    function log(address p0, uint p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
    }

    function log(address p0, uint p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
    }

    function log(address p0, uint p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
    }

    function log(address p0, string memory p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
    }

    function log(address p0, string memory p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
    }

    function log(address p0, string memory p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
    }

    function log(address p0, string memory p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
    }

    function log(address p0, bool p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
    }

    function log(address p0, bool p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
    }

    function log(address p0, bool p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
    }

    function log(address p0, bool p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
    }

    function log(address p0, address p1, uint p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
    }

    function log(address p0, address p1, string memory p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
    }

    function log(address p0, address p1, bool p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
    }

    function log(address p0, address p1, address p2) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
    }

    function log(uint p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
    }

    function log(uint p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
    }

    function log(string memory p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
    }

    function log(bool p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, uint p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, string memory p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, bool p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, uint p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, string memory p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, bool p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, uint p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, string memory p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, bool p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
    }

    function log(address p0, address p1, address p2, address p3) internal view {
        _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
    }

}

File 3 of 21 : IERC20.sol
// SPDX-License-Identifier: Unlicense
pragma solidity >=0.6.2;

interface IERC20 {
  function totalSupply() external view returns (uint);

  function balanceOf(address account) external view returns (uint);

  function transfer(address recipient, uint amount) external returns (bool);

  function allowance(address owner, address spender) external view returns (uint);

  function approve(address spender, uint amount) external returns (bool);

  function transferFrom(address sender, address recipient, uint amount) external returns (bool);

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

  event Transfer(address indexed from, address indexed to, uint value);
  event Approval(address indexed owner, address indexed spender, uint value);

  function decimals() external view returns (uint8);

  function name() external view returns (string memory);
}

File 4 of 21 : IMangrove.sol
// SPDX-License-Identifier: UNLICENSED
// This file was manually adapted from a file generated by abi-to-sol. It must
// be kept up-to-date with the actual Mangrove interface. Fully automatic
// generation is not yet possible due to user-generated types in the external
// interface lost in the abi generation.

pragma solidity >=0.7.0 <0.9.0;

pragma experimental ABIEncoderV2;

import {MgvLib, MgvStructs, IMaker} from "./MgvLib.sol";

interface IMangrove {
  event Approval(address indexed outbound_tkn, address indexed inbound_tkn, address owner, address spender, uint value);
  event Credit(address indexed maker, uint amount);
  event Debit(address indexed maker, uint amount);
  event Kill();
  event NewMgv();
  event OfferFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id,
    address taker,
    uint takerWants,
    uint takerGives,
    bytes32 mgvData
  );
  event OfferRetract(address indexed outbound_tkn, address indexed inbound_tkn, uint id);
  event OfferSuccess(
    address indexed outbound_tkn, address indexed inbound_tkn, uint id, address taker, uint takerWants, uint takerGives
  );
  event OfferWrite(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address maker,
    uint wants,
    uint gives,
    uint gasprice,
    uint gasreq,
    uint id,
    uint prev
  );
  event OrderComplete(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address indexed taker,
    uint takerGot,
    uint takerGave,
    uint penalty,
    uint feePaid
  );
  event OrderStart();
  event PosthookFail(address indexed outbound_tkn, address indexed inbound_tkn, uint offerId, bytes32 posthookData);
  event SetActive(address indexed outbound_tkn, address indexed inbound_tkn, bool value);
  event SetDensity(address indexed outbound_tkn, address indexed inbound_tkn, uint value);
  event SetFee(address indexed outbound_tkn, address indexed inbound_tkn, uint value);
  event SetGasbase(address indexed outbound_tkn, address indexed inbound_tkn, uint offer_gasbase);
  event SetGasmax(uint value);
  event SetGasprice(uint value);
  event SetGovernance(address value);
  event SetMonitor(address value);
  event SetNotify(bool value);
  event SetUseOracle(bool value);
  event SetVault(address value);

  function DOMAIN_SEPARATOR() external view returns (bytes32);

  function PERMIT_TYPEHASH() external view returns (bytes32);

  function activate(address outbound_tkn, address inbound_tkn, uint fee, uint density, uint offer_gasbase) external;

  function allowances(address, address, address, address) external view returns (uint);

  function approve(address outbound_tkn, address inbound_tkn, address spender, uint value) external returns (bool);

  function balanceOf(address) external view returns (uint);

  function best(address outbound_tkn, address inbound_tkn) external view returns (uint);

  function config(address outbound_tkn, address inbound_tkn)
    external
    view
    returns (MgvStructs.GlobalPacked, MgvStructs.LocalPacked);

  function configInfo(address outbound_tkn, address inbound_tkn)
    external
    view
    returns (MgvStructs.GlobalUnpacked memory global, MgvStructs.LocalUnpacked memory local);

  function deactivate(address outbound_tkn, address inbound_tkn) external;

  function flashloan(MgvLib.SingleOrder memory sor, address taker) external returns (uint gasused);

  function fund(address maker) external payable;

  function fund() external payable;

  function governance() external view returns (address);

  function isLive(MgvStructs.OfferPacked offer) external pure returns (bool);

  function kill() external;

  function locked(address outbound_tkn, address inbound_tkn) external view returns (bool);

  function marketOrder(address outbound_tkn, address inbound_tkn, uint takerWants, uint takerGives, bool fillWants)
    external
    returns (uint takerGot, uint takerGave, uint bounty, uint fee);

  function marketOrderFor(
    address outbound_tkn,
    address inbound_tkn,
    uint takerWants,
    uint takerGives,
    bool fillWants,
    address taker
  ) external returns (uint takerGot, uint takerGave, uint bounty, uint fee);

  function newOffer(
    address outbound_tkn,
    address inbound_tkn,
    uint wants,
    uint gives,
    uint gasreq,
    uint gasprice,
    uint pivotId
  ) external payable returns (uint);

  function nonces(address) external view returns (uint);

  function offerDetails(address, address, uint) external view returns (MgvStructs.OfferDetailPacked);

  function offerInfo(address outbound_tkn, address inbound_tkn, uint offerId)
    external
    view
    returns (MgvStructs.OfferUnpacked memory offer, MgvStructs.OfferDetailUnpacked memory offerDetail);

  function offers(address, address, uint) external view returns (MgvStructs.OfferPacked);

  function permit(
    address outbound_tkn,
    address inbound_tkn,
    address owner,
    address spender,
    uint value,
    uint deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;

  function retractOffer(address outbound_tkn, address inbound_tkn, uint offerId, bool deprovision)
    external
    returns (uint provision);

  function setDensity(address outbound_tkn, address inbound_tkn, uint density) external;

  function setFee(address outbound_tkn, address inbound_tkn, uint fee) external;

  function setGasbase(address outbound_tkn, address inbound_tkn, uint offer_gasbase) external;

  function setGasmax(uint gasmax) external;

  function setGasprice(uint gasprice) external;

  function setGovernance(address governanceAddress) external;

  function setMonitor(address monitor) external;

  function setNotify(bool notify) external;

  function setUseOracle(bool useOracle) external;

  function setVault(address vaultAddress) external;

  function snipes(address outbound_tkn, address inbound_tkn, uint[4][] memory targets, bool fillWants)
    external
    returns (uint successes, uint takerGot, uint takerGave, uint bounty, uint fee);

  function snipesFor(address outbound_tkn, address inbound_tkn, uint[4][] memory targets, bool fillWants, address taker)
    external
    returns (uint successes, uint takerGot, uint takerGave, uint bounty, uint fee);

  function updateOffer(
    address outbound_tkn,
    address inbound_tkn,
    uint wants,
    uint gives,
    uint gasreq,
    uint gasprice,
    uint pivotId,
    uint offerId
  ) external payable;

  function vault() external view returns (address);

  function withdraw(uint amount) external returns (bool noRevert);

  receive() external payable;
}

// THIS FILE WAS AUTOGENERATED FROM THE FOLLOWING ABI JSON:
/*
[{"inputs":[{"internalType":"address","name":"governance","type":"address"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256","name":"gasmax","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Credit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Debit","type":"event"},{"anonymous":false,"inputs":[],"name":"Kill","type":"event"},{"anonymous":false,"inputs":[],"name":"NewMgv","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerWants","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerGives","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"mgvData","type":"bytes32"}],"name":"OfferFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"}],"name":"OfferRetract","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerWants","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerGives","type":"uint256"}],"name":"OfferSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"address","name":"maker","type":"address"},{"indexed":false,"internalType":"uint256","name":"wants","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gives","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasprice","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gasreq","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"prev","type":"uint256"}],"name":"OfferWrite","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"uint256","name":"takerGot","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"takerGave","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"penalty","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feePaid","type":"uint256"}],"name":"OrderComplete","type":"event"},{"anonymous":false,"inputs":[],"name":"OrderStart","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"offerId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"posthookData","type":"bytes32"}],"name":"PosthookFail","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"SetActive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetDensity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"address","name":"inbound_tkn","type":"address"},{"indexed":false,"internalType":"uint256","name":"offer_gasbase","type":"uint256"}],"name":"SetGasbase","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetGasmax","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"SetGasprice","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"SetGovernance","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"SetMonitor","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"SetNotify","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"value","type":"bool"}],"name":"SetUseOracle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"value","type":"address"}],"name":"SetVault","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"density","type":"uint256"},{"internalType":"uint256","name":"offer_gasbase","type":"uint256"}],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"}],"name":"best","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"}],"name":"config","outputs":[{"internalType":"GlobalPacked","name":"_global","type":"uint256"},{"internalType":"LocalPacked","name":"_local","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"}],"name":"configInfo","outputs":[{"components":[{"internalType":"address","name":"monitor","type":"address"},{"internalType":"bool","name":"useOracle","type":"bool"},{"internalType":"bool","name":"notify","type":"bool"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256","name":"gasmax","type":"uint256"},{"internalType":"bool","name":"dead","type":"bool"}],"internalType":"structGlobalUnpacked","name":"global","type":"tuple"},{"components":[{"internalType":"bool","name":"active","type":"bool"},{"internalType":"uint256","name":"fee","type":"uint256"},{"internalType":"uint256","name":"density","type":"uint256"},{"internalType":"uint256","name":"offer_gasbase","type":"uint256"},{"internalType":"bool","name":"lock","type":"bool"},{"internalType":"uint256","name":"best","type":"uint256"},{"internalType":"uint256","name":"last","type":"uint256"}],"internalType":"structLocalUnpacked","name":"local","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"}],"name":"deactivate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"},{"internalType":"OfferPacked","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"OfferDetailPacked","name":"offerDetail","type":"uint256"},{"internalType":"GlobalPacked","name":"global","type":"uint256"},{"internalType":"LocalPacked","name":"local","type":"uint256"}],"internalType":"structMgvLib.SingleOrder","name":"sor","type":"tuple"},{"internalType":"address","name":"taker","type":"address"}],"name":"flashloan","outputs":[{"internalType":"uint256","name":"gasused","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"}],"name":"fund","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fund","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"governance","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"OfferPacked","name":"offer","type":"uint256"}],"name":"isLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"}],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"takerWants","type":"uint256"},{"internalType":"uint256","name":"takerGives","type":"uint256"},{"internalType":"bool","name":"fillWants","type":"bool"}],"name":"marketOrder","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"takerWants","type":"uint256"},{"internalType":"uint256","name":"takerGives","type":"uint256"},{"internalType":"bool","name":"fillWants","type":"bool"},{"internalType":"address","name":"taker","type":"address"}],"name":"marketOrderFor","outputs":[{"internalType":"uint256","name":"takerGot","type":"uint256"},{"internalType":"uint256","name":"takerGave","type":"uint256"},{"internalType":"uint256","name":"bounty","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"uint256","name":"gasreq","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256","name":"pivotId","type":"uint256"}],"name":"newOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"offerDetails","outputs":[{"internalType":"OfferDetailPacked","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"offerInfo","outputs":[{"components":[{"internalType":"uint256","name":"prev","type":"uint256"},{"internalType":"uint256","name":"next","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"}],"internalType":"structOfferUnpacked","name":"offer","type":"tuple"},{"components":[{"internalType":"address","name":"maker","type":"address"},{"internalType":"uint256","name":"gasreq","type":"uint256"},{"internalType":"uint256","name":"offer_gasbase","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"}],"internalType":"structOfferDetailUnpacked","name":"offerDetail","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"offers","outputs":[{"internalType":"OfferPacked","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"},{"internalType":"bool","name":"deprovision","type":"bool"}],"name":"retractOffer","outputs":[{"internalType":"uint256","name":"provision","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"density","type":"uint256"}],"name":"setDensity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"fee","type":"uint256"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offer_gasbase","type":"uint256"}],"name":"setGasbase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasmax","type":"uint256"}],"name":"setGasmax","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasprice","type":"uint256"}],"name":"setGasprice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"governanceAddress","type":"address"}],"name":"setGovernance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"monitor","type":"address"}],"name":"setMonitor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"notify","type":"bool"}],"name":"setNotify","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"useOracle","type":"bool"}],"name":"setUseOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"vaultAddress","type":"address"}],"name":"setVault","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256[4][]","name":"targets","type":"uint256[4][]"},{"internalType":"bool","name":"fillWants","type":"bool"}],"name":"snipes","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256[4][]","name":"targets","type":"uint256[4][]"},{"internalType":"bool","name":"fillWants","type":"bool"},{"internalType":"address","name":"taker","type":"address"}],"name":"snipesFor","outputs":[{"internalType":"uint256","name":"successes","type":"uint256"},{"internalType":"uint256","name":"takerGot","type":"uint256"},{"internalType":"uint256","name":"takerGave","type":"uint256"},{"internalType":"uint256","name":"bounty","type":"uint256"},{"internalType":"uint256","name":"feePaid","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"uint256","name":"gasreq","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256","name":"pivotId","type":"uint256"},{"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"updateOffer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"vault","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[{"internalType":"bool","name":"noRevert","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
*/

File 5 of 21 : MgvLib.sol
// SPDX-License-Identifier: Unlicense

// MgvLib.sol

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

/* `MgvLib` contains data structures returned by external calls to Mangrove and the interfaces it uses for its own external calls. */

pragma solidity ^0.8.10;

import "./preprocessed/MgvStructs.post.sol" as MgvStructs;
import {IERC20} from "./IERC20.sol";

/* # Structs
The structs defined in `structs.js` have their counterpart as solidity structs that are easy to manipulate for outside contracts / callers of view functions. */

library MgvLib {
  /*
   Some miscellaneous data types useful to `Mangrove` and external contracts */
  //+clear+

  /* `SingleOrder` holds data about an order-offer match in a struct. Used by `marketOrder` and `internalSnipes` (and some of their nested functions) to avoid stack too deep errors. */
  struct SingleOrder {
    address outbound_tkn;
    address inbound_tkn;
    uint offerId;
    MgvStructs.OfferPacked offer;
    /* `wants`/`gives` mutate over execution. Initially the `wants`/`gives` from the taker's pov, then actual `wants`/`gives` adjusted by offer's price and volume. */
    uint wants;
    uint gives;
    /* `offerDetail` is only populated when necessary. */
    MgvStructs.OfferDetailPacked offerDetail;
    MgvStructs.GlobalPacked global;
    MgvStructs.LocalPacked local;
  }

  /* <a id="MgvLib/OrderResult"></a> `OrderResult` holds additional data for the maker and is given to them _after_ they fulfilled an offer. It gives them their own returned data from the previous call, and an `mgvData` specifying whether Mangrove encountered an error. */

  struct OrderResult {
    /* `makerdata` holds a message that was either returned by the maker or passed as revert message at the end of the trade execution*/
    bytes32 makerData;
    /* `mgvData` is an [internal Mangrove status code](#MgvOfferTaking/statusCodes) code. */
    bytes32 mgvData;
  }
}

/* # Events
The events emitted for use by bots are listed here: */
contract HasMgvEvents {
  /* * Emitted at the creation of the new Mangrove contract on the pair (`inbound_tkn`, `outbound_tkn`)*/
  event NewMgv();

  /* Mangrove adds or removes wei from `maker`'s account */
  /* * Credit event occurs when an offer is removed from Mangrove or when the `fund` function is called*/
  event Credit(address indexed maker, uint amount);
  /* * Debit event occurs when an offer is posted or when the `withdraw` function is called */
  event Debit(address indexed maker, uint amount);

  /* * Mangrove reconfiguration */
  event SetActive(address indexed outbound_tkn, address indexed inbound_tkn, bool value);
  event SetFee(address indexed outbound_tkn, address indexed inbound_tkn, uint value);
  event SetGasbase(address indexed outbound_tkn, address indexed inbound_tkn, uint offer_gasbase);
  event SetGovernance(address value);
  event SetMonitor(address value);
  event SetVault(address value);
  event SetUseOracle(bool value);
  event SetNotify(bool value);
  event SetGasmax(uint value);
  event SetDensity(address indexed outbound_tkn, address indexed inbound_tkn, uint value);
  event SetGasprice(uint value);

  /* Market order execution */
  event OrderStart();
  event OrderComplete(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address indexed taker,
    uint takerGot,
    uint takerGave,
    uint penalty,
    uint feePaid
  );

  /* * Offer execution */
  event OfferSuccess(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id,
    // `maker` is not logged because it can be retrieved from the state using `(outbound_tkn,inbound_tkn,id)`.
    address taker,
    uint takerWants,
    uint takerGives
  );

  /* Log information when a trade execution reverts or returns a non empty bytes32 word */
  event OfferFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint id,
    // `maker` is not logged because it can be retrieved from the state using `(outbound_tkn,inbound_tkn,id)`.
    address taker,
    uint takerWants,
    uint takerGives,
    // `mgvData` may only be `"mgv/makerRevert"`, `"mgv/makerTransferFail"` or `"mgv/makerReceiveFail"`
    bytes32 mgvData
  );

  /* Log information when a posthook reverts */
  event PosthookFail(address indexed outbound_tkn, address indexed inbound_tkn, uint offerId, bytes32 posthookData);

  /* * After `permit` and `approve` */
  event Approval(address indexed outbound_tkn, address indexed inbound_tkn, address owner, address spender, uint value);

  /* * Mangrove closure */
  event Kill();

  /* * An offer was created or updated.
  A few words about why we include a `prev` field, and why we don't include a
  `next` field: in theory clients should need neither `prev` nor a `next` field.
  They could just 1. Read the order book state at a given block `b`.  2. On
  every event, update a local copy of the orderbook.  But in practice, we do not
  want to force clients to keep a copy of the *entire* orderbook. There may be a
  long tail of spam. Now if they only start with the first $N$ offers and
  receive a new offer that goes to the end of the book, they cannot tell if
  there are missing offers between the new offer and the end of the local copy
  of the book.
  
  So we add a prev pointer so clients with only a prefix of the book can receive
  out-of-prefix offers and know what to do with them. The `next` pointer is an
  optimization useful in Solidity (we traverse fewer memory locations) but
  useless in client code.
  */
  event OfferWrite(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    address maker,
    uint wants,
    uint gives,
    uint gasprice,
    uint gasreq,
    uint id,
    uint prev
  );

  /* * `offerId` was present and is now removed from the book. */
  event OfferRetract(address indexed outbound_tkn, address indexed inbound_tkn, uint id);
}

/* # IMaker interface */
interface IMaker {
  /* Called upon offer execution. 
  - If the call throws, Mangrove will not try to transfer funds and the first 32 bytes of revert reason are passed to `makerPosthook` as `makerData`
  - If the call returns normally, returndata is passed to `makerPosthook` as `makerData` and Mangrove will attempt to transfer the funds.
  */
  function makerExecute(MgvLib.SingleOrder calldata order) external returns (bytes32);

  /* Called after all offers of an order have been executed. Posthook of the last executed order is called first and full reentrancy into Mangrove is enabled at this time. `order` recalls key arguments of the order that was processed and `result` recalls important information for updating the current offer. (see [above](#MgvLib/OrderResult))*/
  function makerPosthook(MgvLib.SingleOrder calldata order, MgvLib.OrderResult calldata result) external;
}

/* # ITaker interface */
interface ITaker {
  /* Inverted mangrove only: call to taker after loans went through */
  function takerTrade(
    address outbound_tkn,
    address inbound_tkn,
    // total amount of outbound_tkn token that was flashloaned to the taker
    uint totalGot,
    // total amount of inbound_tkn token that should be made available
    uint totalGives
  ) external;
}

/* # Monitor interface
If enabled, the monitor receives notification after each offer execution and is read for each pair's `gasprice` and `density`. */
interface IMgvMonitor {
  function notifySuccess(MgvLib.SingleOrder calldata sor, address taker) external;

  function notifyFail(MgvLib.SingleOrder calldata sor, address taker) external;

  function read(address outbound_tkn, address inbound_tkn) external view returns (uint gasprice, uint density);
}

File 6 of 21 : MgvGlobal.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

// fields are of the form [name,bits,type]

// struct_defs are of the form [name,obj]

/* ************************************************** *
            GENERATED FILE. DO NOT EDIT.
 * ************************************************** */

/* since you can't convert bool to uint in an expression without conditionals,
 * we add a file-level function and rely on compiler optimization
 */
function uint_of_bool(bool b) pure returns (uint u) {
  assembly { u := b }
}

struct GlobalUnpacked {
  address monitor;
  bool useOracle;
  bool notify;
  uint gasprice;
  uint gasmax;
  bool dead;
}

//some type safety for each struct
type GlobalPacked is uint;
using Library for GlobalPacked global;

uint constant monitor_bits   = 160;
uint constant useOracle_bits = 8;
uint constant notify_bits    = 8;
uint constant gasprice_bits  = 16;
uint constant gasmax_bits    = 24;
uint constant dead_bits      = 8;

uint constant monitor_before   = 0;
uint constant useOracle_before = monitor_before   + monitor_bits  ;
uint constant notify_before    = useOracle_before + useOracle_bits;
uint constant gasprice_before  = notify_before    + notify_bits   ;
uint constant gasmax_before    = gasprice_before  + gasprice_bits ;
uint constant dead_before      = gasmax_before    + gasmax_bits   ;

uint constant monitor_mask   = 0x0000000000000000000000000000000000000000ffffffffffffffffffffffff;
uint constant useOracle_mask = 0xffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff;
uint constant notify_mask    = 0xffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffff;
uint constant gasprice_mask  = 0xffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffff;
uint constant gasmax_mask    = 0xffffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffff;
uint constant dead_mask      = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff;

library Library {
  function to_struct(GlobalPacked __packed) internal pure returns (GlobalUnpacked memory __s) { unchecked {
    __s.monitor = address(uint160((GlobalPacked.unwrap(__packed) << monitor_before) >> (256-monitor_bits)));
    __s.useOracle = (((GlobalPacked.unwrap(__packed) << useOracle_before) >> (256-useOracle_bits)) > 0);
    __s.notify = (((GlobalPacked.unwrap(__packed) << notify_before) >> (256-notify_bits)) > 0);
    __s.gasprice = (GlobalPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
    __s.gasmax = (GlobalPacked.unwrap(__packed) << gasmax_before) >> (256-gasmax_bits);
    __s.dead = (((GlobalPacked.unwrap(__packed) << dead_before) >> (256-dead_bits)) > 0);
  }}

  function eq(GlobalPacked __packed1, GlobalPacked __packed2) internal pure returns (bool) { unchecked {
    return GlobalPacked.unwrap(__packed1) == GlobalPacked.unwrap(__packed2);
  }}

  function unpack(GlobalPacked __packed) internal pure returns (address __monitor, bool __useOracle, bool __notify, uint __gasprice, uint __gasmax, bool __dead) { unchecked {
    __monitor = address(uint160((GlobalPacked.unwrap(__packed) << monitor_before) >> (256-monitor_bits)));
    __useOracle = (((GlobalPacked.unwrap(__packed) << useOracle_before) >> (256-useOracle_bits)) > 0);
    __notify = (((GlobalPacked.unwrap(__packed) << notify_before) >> (256-notify_bits)) > 0);
    __gasprice = (GlobalPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
    __gasmax = (GlobalPacked.unwrap(__packed) << gasmax_before) >> (256-gasmax_bits);
    __dead = (((GlobalPacked.unwrap(__packed) << dead_before) >> (256-dead_bits)) > 0);
  }}

  function monitor(GlobalPacked __packed) internal pure returns(address) { unchecked {
    return address(uint160((GlobalPacked.unwrap(__packed) << monitor_before) >> (256-monitor_bits)));
  }}
  function monitor(GlobalPacked __packed,address val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & monitor_mask)
                                | ((uint(uint160(val)) << (256-monitor_bits) >> monitor_before)));
  }}
  function useOracle(GlobalPacked __packed) internal pure returns(bool) { unchecked {
    return (((GlobalPacked.unwrap(__packed) << useOracle_before) >> (256-useOracle_bits)) > 0);
  }}
  function useOracle(GlobalPacked __packed,bool val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & useOracle_mask)
                                | ((uint_of_bool(val) << (256-useOracle_bits) >> useOracle_before)));
  }}
  function notify(GlobalPacked __packed) internal pure returns(bool) { unchecked {
    return (((GlobalPacked.unwrap(__packed) << notify_before) >> (256-notify_bits)) > 0);
  }}
  function notify(GlobalPacked __packed,bool val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & notify_mask)
                                | ((uint_of_bool(val) << (256-notify_bits) >> notify_before)));
  }}
  function gasprice(GlobalPacked __packed) internal pure returns(uint) { unchecked {
    return (GlobalPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
  }}
  function gasprice(GlobalPacked __packed,uint val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & gasprice_mask)
                                | ((val << (256-gasprice_bits) >> gasprice_before)));
  }}
  function gasmax(GlobalPacked __packed) internal pure returns(uint) { unchecked {
    return (GlobalPacked.unwrap(__packed) << gasmax_before) >> (256-gasmax_bits);
  }}
  function gasmax(GlobalPacked __packed,uint val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & gasmax_mask)
                                | ((val << (256-gasmax_bits) >> gasmax_before)));
  }}
  function dead(GlobalPacked __packed) internal pure returns(bool) { unchecked {
    return (((GlobalPacked.unwrap(__packed) << dead_before) >> (256-dead_bits)) > 0);
  }}
  function dead(GlobalPacked __packed,bool val) internal pure returns(GlobalPacked) { unchecked {
    return GlobalPacked.wrap((GlobalPacked.unwrap(__packed) & dead_mask)
                                | ((uint_of_bool(val) << (256-dead_bits) >> dead_before)));
  }}
}

function t_of_struct(GlobalUnpacked memory __s) pure returns (GlobalPacked) { unchecked {
  return pack(__s.monitor, __s.useOracle, __s.notify, __s.gasprice, __s.gasmax, __s.dead);
}}

function pack(address __monitor, bool __useOracle, bool __notify, uint __gasprice, uint __gasmax, bool __dead) pure returns (GlobalPacked) { unchecked {
  return GlobalPacked.wrap(((((((0
                              | ((uint(uint160(__monitor)) << (256-monitor_bits)) >> monitor_before))
                              | ((uint_of_bool(__useOracle) << (256-useOracle_bits)) >> useOracle_before))
                              | ((uint_of_bool(__notify) << (256-notify_bits)) >> notify_before))
                              | ((__gasprice << (256-gasprice_bits)) >> gasprice_before))
                              | ((__gasmax << (256-gasmax_bits)) >> gasmax_before))
                              | ((uint_of_bool(__dead) << (256-dead_bits)) >> dead_before)));
}}

File 7 of 21 : MgvLocal.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

// fields are of the form [name,bits,type]

// struct_defs are of the form [name,obj]

/* ************************************************** *
            GENERATED FILE. DO NOT EDIT.
 * ************************************************** */

/* since you can't convert bool to uint in an expression without conditionals,
 * we add a file-level function and rely on compiler optimization
 */
function uint_of_bool(bool b) pure returns (uint u) {
  assembly { u := b }
}

struct LocalUnpacked {
  bool active;
  uint fee;
  uint density;
  uint offer_gasbase;
  bool lock;
  uint best;
  uint last;
}

//some type safety for each struct
type LocalPacked is uint;
using Library for LocalPacked global;

uint constant active_bits        = 8;
uint constant fee_bits           = 16;
uint constant density_bits       = 112;
uint constant offer_gasbase_bits = 24;
uint constant lock_bits          = 8;
uint constant best_bits          = 32;
uint constant last_bits          = 32;

uint constant active_before        = 0;
uint constant fee_before           = active_before        + active_bits       ;
uint constant density_before       = fee_before           + fee_bits          ;
uint constant offer_gasbase_before = density_before       + density_bits      ;
uint constant lock_before          = offer_gasbase_before + offer_gasbase_bits;
uint constant best_before          = lock_before          + lock_bits         ;
uint constant last_before          = best_before          + best_bits         ;

uint constant active_mask        = 0x00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
uint constant fee_mask           = 0xff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
uint constant density_mask       = 0xffffff0000000000000000000000000000ffffffffffffffffffffffffffffff;
uint constant offer_gasbase_mask = 0xffffffffffffffffffffffffffffffffff000000ffffffffffffffffffffffff;
uint constant lock_mask          = 0xffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffff;
uint constant best_mask          = 0xffffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffff;
uint constant last_mask          = 0xffffffffffffffffffffffffffffffffffffffffffffffffff00000000ffffff;

library Library {
  function to_struct(LocalPacked __packed) internal pure returns (LocalUnpacked memory __s) { unchecked {
    __s.active = (((LocalPacked.unwrap(__packed) << active_before) >> (256-active_bits)) > 0);
    __s.fee = (LocalPacked.unwrap(__packed) << fee_before) >> (256-fee_bits);
    __s.density = (LocalPacked.unwrap(__packed) << density_before) >> (256-density_bits);
    __s.offer_gasbase = (LocalPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __s.lock = (((LocalPacked.unwrap(__packed) << lock_before) >> (256-lock_bits)) > 0);
    __s.best = (LocalPacked.unwrap(__packed) << best_before) >> (256-best_bits);
    __s.last = (LocalPacked.unwrap(__packed) << last_before) >> (256-last_bits);
  }}

  function eq(LocalPacked __packed1, LocalPacked __packed2) internal pure returns (bool) { unchecked {
    return LocalPacked.unwrap(__packed1) == LocalPacked.unwrap(__packed2);
  }}

  function unpack(LocalPacked __packed) internal pure returns (bool __active, uint __fee, uint __density, uint __offer_gasbase, bool __lock, uint __best, uint __last) { unchecked {
    __active = (((LocalPacked.unwrap(__packed) << active_before) >> (256-active_bits)) > 0);
    __fee = (LocalPacked.unwrap(__packed) << fee_before) >> (256-fee_bits);
    __density = (LocalPacked.unwrap(__packed) << density_before) >> (256-density_bits);
    __offer_gasbase = (LocalPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __lock = (((LocalPacked.unwrap(__packed) << lock_before) >> (256-lock_bits)) > 0);
    __best = (LocalPacked.unwrap(__packed) << best_before) >> (256-best_bits);
    __last = (LocalPacked.unwrap(__packed) << last_before) >> (256-last_bits);
  }}

  function active(LocalPacked __packed) internal pure returns(bool) { unchecked {
    return (((LocalPacked.unwrap(__packed) << active_before) >> (256-active_bits)) > 0);
  }}
  function active(LocalPacked __packed,bool val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & active_mask)
                                | ((uint_of_bool(val) << (256-active_bits) >> active_before)));
  }}
  function fee(LocalPacked __packed) internal pure returns(uint) { unchecked {
    return (LocalPacked.unwrap(__packed) << fee_before) >> (256-fee_bits);
  }}
  function fee(LocalPacked __packed,uint val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & fee_mask)
                                | ((val << (256-fee_bits) >> fee_before)));
  }}
  function density(LocalPacked __packed) internal pure returns(uint) { unchecked {
    return (LocalPacked.unwrap(__packed) << density_before) >> (256-density_bits);
  }}
  function density(LocalPacked __packed,uint val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & density_mask)
                                | ((val << (256-density_bits) >> density_before)));
  }}
  function offer_gasbase(LocalPacked __packed) internal pure returns(uint) { unchecked {
    return (LocalPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
  }}
  function offer_gasbase(LocalPacked __packed,uint val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & offer_gasbase_mask)
                                | ((val << (256-offer_gasbase_bits) >> offer_gasbase_before)));
  }}
  function lock(LocalPacked __packed) internal pure returns(bool) { unchecked {
    return (((LocalPacked.unwrap(__packed) << lock_before) >> (256-lock_bits)) > 0);
  }}
  function lock(LocalPacked __packed,bool val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & lock_mask)
                                | ((uint_of_bool(val) << (256-lock_bits) >> lock_before)));
  }}
  function best(LocalPacked __packed) internal pure returns(uint) { unchecked {
    return (LocalPacked.unwrap(__packed) << best_before) >> (256-best_bits);
  }}
  function best(LocalPacked __packed,uint val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & best_mask)
                                | ((val << (256-best_bits) >> best_before)));
  }}
  function last(LocalPacked __packed) internal pure returns(uint) { unchecked {
    return (LocalPacked.unwrap(__packed) << last_before) >> (256-last_bits);
  }}
  function last(LocalPacked __packed,uint val) internal pure returns(LocalPacked) { unchecked {
    return LocalPacked.wrap((LocalPacked.unwrap(__packed) & last_mask)
                                | ((val << (256-last_bits) >> last_before)));
  }}
}

function t_of_struct(LocalUnpacked memory __s) pure returns (LocalPacked) { unchecked {
  return pack(__s.active, __s.fee, __s.density, __s.offer_gasbase, __s.lock, __s.best, __s.last);
}}

function pack(bool __active, uint __fee, uint __density, uint __offer_gasbase, bool __lock, uint __best, uint __last) pure returns (LocalPacked) { unchecked {
  return LocalPacked.wrap((((((((0
                              | ((uint_of_bool(__active) << (256-active_bits)) >> active_before))
                              | ((__fee << (256-fee_bits)) >> fee_before))
                              | ((__density << (256-density_bits)) >> density_before))
                              | ((__offer_gasbase << (256-offer_gasbase_bits)) >> offer_gasbase_before))
                              | ((uint_of_bool(__lock) << (256-lock_bits)) >> lock_before))
                              | ((__best << (256-best_bits)) >> best_before))
                              | ((__last << (256-last_bits)) >> last_before)));
}}

File 8 of 21 : MgvOffer.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

// fields are of the form [name,bits,type]

// struct_defs are of the form [name,obj]

/* ************************************************** *
            GENERATED FILE. DO NOT EDIT.
 * ************************************************** */

/* since you can't convert bool to uint in an expression without conditionals,
 * we add a file-level function and rely on compiler optimization
 */
function uint_of_bool(bool b) pure returns (uint u) {
  assembly { u := b }
}

struct OfferUnpacked {
  uint prev;
  uint next;
  uint wants;
  uint gives;
}

//some type safety for each struct
type OfferPacked is uint;
using Library for OfferPacked global;

uint constant prev_bits  = 32;
uint constant next_bits  = 32;
uint constant wants_bits = 96;
uint constant gives_bits = 96;

uint constant prev_before  = 0;
uint constant next_before  = prev_before  + prev_bits ;
uint constant wants_before = next_before  + next_bits ;
uint constant gives_before = wants_before + wants_bits;

uint constant prev_mask  = 0x00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
uint constant next_mask  = 0xffffffff00000000ffffffffffffffffffffffffffffffffffffffffffffffff;
uint constant wants_mask = 0xffffffffffffffff000000000000000000000000ffffffffffffffffffffffff;
uint constant gives_mask = 0xffffffffffffffffffffffffffffffffffffffff000000000000000000000000;

library Library {
  function to_struct(OfferPacked __packed) internal pure returns (OfferUnpacked memory __s) { unchecked {
    __s.prev = (OfferPacked.unwrap(__packed) << prev_before) >> (256-prev_bits);
    __s.next = (OfferPacked.unwrap(__packed) << next_before) >> (256-next_bits);
    __s.wants = (OfferPacked.unwrap(__packed) << wants_before) >> (256-wants_bits);
    __s.gives = (OfferPacked.unwrap(__packed) << gives_before) >> (256-gives_bits);
  }}

  function eq(OfferPacked __packed1, OfferPacked __packed2) internal pure returns (bool) { unchecked {
    return OfferPacked.unwrap(__packed1) == OfferPacked.unwrap(__packed2);
  }}

  function unpack(OfferPacked __packed) internal pure returns (uint __prev, uint __next, uint __wants, uint __gives) { unchecked {
    __prev = (OfferPacked.unwrap(__packed) << prev_before) >> (256-prev_bits);
    __next = (OfferPacked.unwrap(__packed) << next_before) >> (256-next_bits);
    __wants = (OfferPacked.unwrap(__packed) << wants_before) >> (256-wants_bits);
    __gives = (OfferPacked.unwrap(__packed) << gives_before) >> (256-gives_bits);
  }}

  function prev(OfferPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferPacked.unwrap(__packed) << prev_before) >> (256-prev_bits);
  }}
  function prev(OfferPacked __packed,uint val) internal pure returns(OfferPacked) { unchecked {
    return OfferPacked.wrap((OfferPacked.unwrap(__packed) & prev_mask)
                                | ((val << (256-prev_bits) >> prev_before)));
  }}
  function next(OfferPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferPacked.unwrap(__packed) << next_before) >> (256-next_bits);
  }}
  function next(OfferPacked __packed,uint val) internal pure returns(OfferPacked) { unchecked {
    return OfferPacked.wrap((OfferPacked.unwrap(__packed) & next_mask)
                                | ((val << (256-next_bits) >> next_before)));
  }}
  function wants(OfferPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferPacked.unwrap(__packed) << wants_before) >> (256-wants_bits);
  }}
  function wants(OfferPacked __packed,uint val) internal pure returns(OfferPacked) { unchecked {
    return OfferPacked.wrap((OfferPacked.unwrap(__packed) & wants_mask)
                                | ((val << (256-wants_bits) >> wants_before)));
  }}
  function gives(OfferPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferPacked.unwrap(__packed) << gives_before) >> (256-gives_bits);
  }}
  function gives(OfferPacked __packed,uint val) internal pure returns(OfferPacked) { unchecked {
    return OfferPacked.wrap((OfferPacked.unwrap(__packed) & gives_mask)
                                | ((val << (256-gives_bits) >> gives_before)));
  }}
}

function t_of_struct(OfferUnpacked memory __s) pure returns (OfferPacked) { unchecked {
  return pack(__s.prev, __s.next, __s.wants, __s.gives);
}}

function pack(uint __prev, uint __next, uint __wants, uint __gives) pure returns (OfferPacked) { unchecked {
  return OfferPacked.wrap(((((0
                              | ((__prev << (256-prev_bits)) >> prev_before))
                              | ((__next << (256-next_bits)) >> next_before))
                              | ((__wants << (256-wants_bits)) >> wants_before))
                              | ((__gives << (256-gives_bits)) >> gives_before)));
}}

File 9 of 21 : MgvOfferDetail.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

// fields are of the form [name,bits,type]

// struct_defs are of the form [name,obj]

/* ************************************************** *
            GENERATED FILE. DO NOT EDIT.
 * ************************************************** */

/* since you can't convert bool to uint in an expression without conditionals,
 * we add a file-level function and rely on compiler optimization
 */
function uint_of_bool(bool b) pure returns (uint u) {
  assembly { u := b }
}

struct OfferDetailUnpacked {
  address maker;
  uint gasreq;
  uint offer_gasbase;
  uint gasprice;
}

//some type safety for each struct
type OfferDetailPacked is uint;
using Library for OfferDetailPacked global;

uint constant maker_bits         = 160;
uint constant gasreq_bits        = 24;
uint constant offer_gasbase_bits = 24;
uint constant gasprice_bits      = 16;

uint constant maker_before         = 0;
uint constant gasreq_before        = maker_before         + maker_bits        ;
uint constant offer_gasbase_before = gasreq_before        + gasreq_bits       ;
uint constant gasprice_before      = offer_gasbase_before + offer_gasbase_bits;

uint constant maker_mask         = 0x0000000000000000000000000000000000000000ffffffffffffffffffffffff;
uint constant gasreq_mask        = 0xffffffffffffffffffffffffffffffffffffffff000000ffffffffffffffffff;
uint constant offer_gasbase_mask = 0xffffffffffffffffffffffffffffffffffffffffffffff000000ffffffffffff;
uint constant gasprice_mask      = 0xffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffff;

library Library {
  function to_struct(OfferDetailPacked __packed) internal pure returns (OfferDetailUnpacked memory __s) { unchecked {
    __s.maker = address(uint160((OfferDetailPacked.unwrap(__packed) << maker_before) >> (256-maker_bits)));
    __s.gasreq = (OfferDetailPacked.unwrap(__packed) << gasreq_before) >> (256-gasreq_bits);
    __s.offer_gasbase = (OfferDetailPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __s.gasprice = (OfferDetailPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
  }}

  function eq(OfferDetailPacked __packed1, OfferDetailPacked __packed2) internal pure returns (bool) { unchecked {
    return OfferDetailPacked.unwrap(__packed1) == OfferDetailPacked.unwrap(__packed2);
  }}

  function unpack(OfferDetailPacked __packed) internal pure returns (address __maker, uint __gasreq, uint __offer_gasbase, uint __gasprice) { unchecked {
    __maker = address(uint160((OfferDetailPacked.unwrap(__packed) << maker_before) >> (256-maker_bits)));
    __gasreq = (OfferDetailPacked.unwrap(__packed) << gasreq_before) >> (256-gasreq_bits);
    __offer_gasbase = (OfferDetailPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __gasprice = (OfferDetailPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
  }}

  function maker(OfferDetailPacked __packed) internal pure returns(address) { unchecked {
    return address(uint160((OfferDetailPacked.unwrap(__packed) << maker_before) >> (256-maker_bits)));
  }}
  function maker(OfferDetailPacked __packed,address val) internal pure returns(OfferDetailPacked) { unchecked {
    return OfferDetailPacked.wrap((OfferDetailPacked.unwrap(__packed) & maker_mask)
                                | ((uint(uint160(val)) << (256-maker_bits) >> maker_before)));
  }}
  function gasreq(OfferDetailPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferDetailPacked.unwrap(__packed) << gasreq_before) >> (256-gasreq_bits);
  }}
  function gasreq(OfferDetailPacked __packed,uint val) internal pure returns(OfferDetailPacked) { unchecked {
    return OfferDetailPacked.wrap((OfferDetailPacked.unwrap(__packed) & gasreq_mask)
                                | ((val << (256-gasreq_bits) >> gasreq_before)));
  }}
  function offer_gasbase(OfferDetailPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferDetailPacked.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
  }}
  function offer_gasbase(OfferDetailPacked __packed,uint val) internal pure returns(OfferDetailPacked) { unchecked {
    return OfferDetailPacked.wrap((OfferDetailPacked.unwrap(__packed) & offer_gasbase_mask)
                                | ((val << (256-offer_gasbase_bits) >> offer_gasbase_before)));
  }}
  function gasprice(OfferDetailPacked __packed) internal pure returns(uint) { unchecked {
    return (OfferDetailPacked.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
  }}
  function gasprice(OfferDetailPacked __packed,uint val) internal pure returns(OfferDetailPacked) { unchecked {
    return OfferDetailPacked.wrap((OfferDetailPacked.unwrap(__packed) & gasprice_mask)
                                | ((val << (256-gasprice_bits) >> gasprice_before)));
  }}
}

function t_of_struct(OfferDetailUnpacked memory __s) pure returns (OfferDetailPacked) { unchecked {
  return pack(__s.maker, __s.gasreq, __s.offer_gasbase, __s.gasprice);
}}

function pack(address __maker, uint __gasreq, uint __offer_gasbase, uint __gasprice) pure returns (OfferDetailPacked) { unchecked {
  return OfferDetailPacked.wrap(((((0
                              | ((uint(uint160(__maker)) << (256-maker_bits)) >> maker_before))
                              | ((__gasreq << (256-gasreq_bits)) >> gasreq_before))
                              | ((__offer_gasbase << (256-offer_gasbase_bits)) >> offer_gasbase_before))
                              | ((__gasprice << (256-gasprice_bits)) >> gasprice_before)));
}}

File 10 of 21 : MgvStructs.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// MgvStructs.post.sol

// This is free and unencumbered software released into the public domain.

// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.

// In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// For more information, please refer to <https://unlicense.org/>

/* ************************************************** *
            GENERATED FILE. DO NOT EDIT.
 * ************************************************** */

// Note: can't do Type.Unpacked because typechain mixes up multiple 'Unpacked' structs under different namespaces. So for consistency we don't do Type.Packed either. We do TypeUnpacked and TypePacked.

import {OfferPacked, OfferUnpacked} from "./MgvOffer.post.sol";
import "./MgvOffer.post.sol" as Offer;
import {OfferDetailPacked, OfferDetailUnpacked} from "./MgvOfferDetail.post.sol";
import "./MgvOfferDetail.post.sol" as OfferDetail;
import {GlobalPacked, GlobalUnpacked} from "./MgvGlobal.post.sol";
import "./MgvGlobal.post.sol" as Global;
import {LocalPacked, LocalUnpacked} from "./MgvLocal.post.sol";
import "./MgvLocal.post.sol" as Local;

File 11 of 21 : MangroveOffer.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangroveOffer.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {AccessControlled} from "mgv_src/strategies/utils/AccessControlled.sol";
import {MangroveOfferStorage as MOS} from "./MangroveOfferStorage.sol";
import {IOfferLogic} from "mgv_src/strategies/interfaces/IOfferLogic.sol";
import {MgvLib, IERC20, MgvStructs} from "mgv_src/MgvLib.sol";
import {IMangrove} from "mgv_src/IMangrove.sol";
import {AbstractRouter} from "mgv_src/strategies/routers/AbstractRouter.sol";
import {console} from "forge-std/console.sol";

/// @title This contract is the basic building block for Mangrove strats.
/// @notice It contains the mandatory interface expected by Mangrove (`IOfferLogic` is `IMaker`) and enforces additional functions implementations (via `IOfferLogic`).
/// @dev Naming scheme:
/// `f() public`: can be used, as is, in all descendants of `this` contract
/// `_f() internal`: descendant of this contract should provide a public wrapper for this function, with necessary guards.
/// `__f__() virtual internal`: descendant of this contract should override this function to specialize it to the needs of the strat.

abstract contract MangroveOffer is AccessControlled, IOfferLogic {
  uint public immutable OFFER_GASREQ;
  IMangrove public immutable MGV;
  AbstractRouter public constant NO_ROUTER = AbstractRouter(address(0));
  bytes32 constant OUT_OF_FUNDS = keccak256("mgv/insufficientProvision");
  bytes32 constant BELOW_DENSITY = keccak256("mgv/writeOffer/density/tooLow");
  bytes32 constant REPOST_SUCCESS = "posthook/reposted";
  bytes32 constant REPOST_FAILED = "posthook/repostFailed";

  ///@notice guards for restricting a function call to either `MGV` or `admin()`.
  ///@dev When `msg.sender` is `MGV`, the function is being called either via `makerExecute` or `makerPosthook`.
  modifier mgvOrAdmin() {
    require(msg.sender == admin() || msg.sender == address(MGV), "mgvOffer/unauthorized");
    _;
  }

  ///@notice Mandatory function to allow `this` to receive native tokens from Mangrove after a call to `MGV.withdraw(...,deprovision:true)`
  ///@dev override this function if `this` contract needs to handle local accounting of user funds.
  receive() external payable virtual {}

  /**
   * @notice `MangroveOffer`'s constructor
   * @param mgv The Mangrove deployment that is allowed to call `this` for trade execution and posthook.
   * @param gasreq Gas requirement when posting offers via this strategy, excluding router requirement.
   */
  constructor(IMangrove mgv, uint gasreq) AccessControlled(msg.sender) {
    require(uint24(gasreq) == gasreq, "mgvOffer/gasreqOverflow");
    MGV = mgv;
    OFFER_GASREQ = gasreq;
  }

  /// @inheritdoc IOfferLogic
  function offerGasreq() public view returns (uint) {
    AbstractRouter router_ = router();
    if (router_ != NO_ROUTER) {
      return OFFER_GASREQ + router_.routerGasreq();
    } else {
      return OFFER_GASREQ;
    }
  }

  ///*****************************
  /// Mandatory callback functions
  ///*****************************

  ///@notice `makerExecute` is the callback function to execute all offers that were posted on Mangrove by `this` contract.
  ///@param order a data structure that recapitulates the taker order and the offer as it was posted on mangrove
  ///@return ret a bytes32 word to pass information (if needed) to the posthook
  ///@dev it may not be overriden although it can be customized using `__lastLook__`, `__put__` and `__get__` hooks.
  /// NB #1: if `makerExecute` reverts, the offer will be considered to be refusing the trade.
  /// NB #2: `makerExecute` may return a `bytes32` word to pass information to posthook w/o using storage reads/writes.
  /// NB #3: Reneging on trade will have the following effects:
  /// * Offer is removed from the Order Book
  /// * Offer bounty will be withdrawn from offer provision and sent to the offer taker. The remaining provision will be credited to the maker account on Mangrove
  function makerExecute(MgvLib.SingleOrder calldata order)
    external
    override
    onlyCaller(address(MGV))
    returns (bytes32 ret)
  {
    // Invoke hook that implements a last look check during execution - it may renege on trade by reverting.
    console.log('in makerexecute', gasleft(), order.offerId);
    ret = __lastLook__(order);
    console.log('passed lastlook', gasleft());
    // Invoke hook to put the inbound token, which are brought by the taker, into a specific reserve.
    require(__put__(order.gives, order) == 0, "mgvOffer/abort/putFailed");
    console.log('passed put', gasleft());
    // Invoke hook to fetch the outbound token, which are promised to the taker, from a specific reserve.
    require(__get__(order.wants, order) == 0, "mgvOffer/abort/getFailed");
    console.log('passed get', gasleft());
  }

  /// @notice `makerPosthook` is the callback function that is called by Mangrove *after* the offer execution.
  /// @notice reverting during its execution will not renege on trade. Revert reason (casted to 32 bytes) is then logged by Mangrove in event `PosthookFail`.
  /// @param order a data structure that recapitulates the taker order and the offer as it was posted on mangrove
  /// @param result a data structure that gathers information about trade execution
  /// @dev It cannot be overridden but can be customized via the hooks `__posthookSuccess__` and `__posthookFallback__` (see below).
  function makerPosthook(MgvLib.SingleOrder calldata order, MgvLib.OrderResult calldata result)
    external
    override
    onlyCaller(address(MGV))
  {
    if (result.mgvData == "mgv/tradeSuccess") {
      // top-level `__posthookSuccess__`'s return value is ignored.
      __posthookSuccess__(order, result.makerData);
    } else {
      // logging what went wrong during `makerExecute`
      emit LogIncident(
        MGV, IERC20(order.outbound_tkn), IERC20(order.inbound_tkn), order.offerId, result.makerData, result.mgvData
        );
      // calling strat specific todos in case of failure
      __posthookFallback__(order, result);
      __handleResidualProvision__(order);
    }
  }

  /// @inheritdoc IOfferLogic
  function setRouter(AbstractRouter router_) public override onlyAdmin {
    MOS.getStorage().router = router_;
    emit SetRouter(router_);
  }

  /// @inheritdoc IOfferLogic
  function router() public view returns (AbstractRouter) {
    return MOS.getStorage().router;
  }

  /// @inheritdoc IOfferLogic
  function approve(IERC20 token, address spender, uint amount) public override onlyAdmin returns (bool) {
    return token.approve(spender, amount);
  }

  /// @inheritdoc IOfferLogic
  function reserve(address maker) public view override returns (address) {
    return __reserve__(maker);
  }

  /// @notice hook to customize offer owner's reserve for the offer logic
  /// @param maker the offer owner's address whose address is being queried
  function __reserve__(address maker) internal view virtual returns (address) {
    return maker;
  }

  /// @inheritdoc IOfferLogic
  function activate(IERC20[] calldata tokens) external override onlyAdmin {
    for (uint i = 0; i < tokens.length; i++) {
      __activate__(tokens[i]);
    }
  }

  /// @inheritdoc IOfferLogic
  function checkList(IERC20[] calldata tokens) external view override {
    for (uint i = 0; i < tokens.length; i++) {
      __checkList__(tokens[i]);
    }
  }

  ///@dev override conservatively to define strat-specific additional activation steps.
  ///@param token the ERC20 one wishes this contract to trade on.
  ///@custom:hook overrides of this hook should be conservative and call `super.__activate__(token)`
  function __activate__(IERC20 token) internal virtual {
    AbstractRouter router_ = router();
    // all strat require `this` to approve Mangrove for pulling `token` at the end of `makerExecute`
    require(token.approve(address(MGV), type(uint).max), "mgvOffer/approveMangrove/Fail");
    if (router_ != NO_ROUTER) {
      // allowing router to pull `token` from this contract (for the `push` function of the router)
      require(token.approve(address(router_), type(uint).max), "mgvOffer/approveRouterFail");
      // letting router performs additional necessary approvals (if any)
      // this will only work if `this` is an authorized maker of the router (i.e. `router.bind(address(this))` has been called by router's admin).
      router_.activate(token);
    }
  }

  ///@dev override conservatively to define strat-specific additional check list
  ///@param token the ERC20 one wishes this contract to trade on.
  ///@custom:hook overrides of this hook should be conservative and call `super.__checkList__(token)`
  function __checkList__(IERC20 token) internal view virtual {
    AbstractRouter router_ = router();
    // checking `this` contract's approval
    require(token.allowance(address(this), address(MGV)) > 0, "mgvOffer/LogicMustApproveMangrove");
    // if contract has a router, checking router is allowed
    if (router_ != NO_ROUTER) {
      require(token.allowance(address(this), address(router_)) > 0, "mgvOffer/LogicMustApproveRouter");
      router_.checkList(token, reserve(msg.sender));
    }
  }

  /// @inheritdoc IOfferLogic
  function withdrawFromMangrove(uint amount, address payable receiver) external onlyAdmin {
    if (amount == type(uint).max) {
      amount = MGV.balanceOf(address(this));
    }
    // the require below is necessary if the `receive()` function is overriden
    require(MGV.withdraw(amount), "mgvOffer/withdrawFail");
    (bool noRevert,) = receiver.call{value: amount}("");
    // if `receiver` is actually not payable
    require(noRevert, "mgvOffer/weiTransferFail");
  }

  ///@notice Hook that implements where the inbound token, which are brought by the Offer Taker, should go during Taker Order's execution.
  ///@param amount of `inbound` tokens that are on `this` contract's balance and still need to be deposited somewhere
  ///@param order is a recall of the taker order that is at the origin of the current trade.
  ///@return missingPut (<=`amount`) is the amount of `inbound` tokens whose deposit location has not been decided (possibly because of a failure) during this function execution
  ///@dev if the last nested call to `__put__` returns a non zero value, trade execution will revert
  ///@custom:hook overrides of this hook should be conservative and call `super.__put__(missing, order)`
  function __put__(uint amount, MgvLib.SingleOrder calldata order) internal virtual returns (uint missingPut);

  ///@notice Hook that implements where the outbound token, which are promised to the taker, should be fetched from, during Taker Order's execution.
  ///@param amount of `outbound` tokens that still needs to be brought to the balance of `this` contract when entering this function
  ///@param order is a recall of the taker order that is at the origin of the current trade.
  ///@return missingGet (<=`amount`), which is the amount of `outbound` tokens still need to be fetched at the end of this function
  ///@dev if the last nested call to `__get__` returns a non zero value, trade execution will revert
  ///@custom:hook overrides of this hook should be conservative and call `super.__get__(missing, order)`
  function __get__(uint amount, MgvLib.SingleOrder calldata order) internal virtual returns (uint missingGet);

  /// @notice Hook that implements a last look check during Taker Order's execution.
  /// @param order is a recall of the taker order that is at the origin of the current trade.
  /// @return data is a message that will be passed to posthook provided `makerExecute` does not revert.
  /// @dev __lastLook__ should revert if trade is to be reneged on. If not, returned `bytes32` are passed to `makerPosthook` in the `makerData` field.
  /// @custom:hook overrides of this hook should be conservative and call `super.__lastLook__(order)`.
  function __lastLook__(MgvLib.SingleOrder calldata order) internal virtual returns (bytes32 data) {
    order; //shh
    return "mgvOffer/proceed";
  }

  ///@notice Post-hook that implements fallback behavior when Taker Order's execution failed unexpectedly.
  ///@param order is a recall of the taker order that is at the origin of the current trade.
  ///@param result contains information about trade.
  /**
   * @dev `result.mgvData` is Mangrove's verdict about trade success
   * `result.makerData` either contains the first 32 bytes of revert reason if `makerExecute` reverted or the returned `bytes32`.
   */
  /// @custom:hook overrides of this hook should be conservative and call `super.__posthookFallback__(order, result)`
  function __posthookFallback__(MgvLib.SingleOrder calldata order, MgvLib.OrderResult calldata result)
    internal
    virtual
    returns (bytes32)
  {
    order;
    result;
    return "";
  }

  ///@notice Given the current taker order that (partially) consumes an offer, this hook is used to declare how much `order.inbound_tkn` the offer wants after it is reposted.
  ///@param order is a recall of the taker order that is being treated.
  ///@return new_wants the new volume of `inbound_tkn` the offer will ask for on Mangrove
  ///@dev default is to require the original amount of tokens minus those that have been given by the taker during trade execution.
  function __residualWants__(MgvLib.SingleOrder calldata order) internal virtual returns (uint new_wants) {
    new_wants = order.offer.wants() - order.gives;
  }

  ///@notice Given the current taker order that (partially) consumes an offer, this hook is used to declare how much `order.outbound_tkn` the offer gives after it is reposted.
  ///@param order is a recall of the taker order that is being treated.
  ///@return new_gives the new volume of `outbound_tkn` the offer will give if fully taken.
  ///@dev default is to require the original amount of tokens minus those that have been sent to the taker during trade execution.
  function __residualGives__(MgvLib.SingleOrder calldata order) internal virtual returns (uint new_gives) {
    return order.offer.gives() - order.wants;
  }

  ///@notice Hook that defines what needs to be done to the part of an offer provision that was added to the balance of `this` on Mangrove after an offer has failed.
  ///@param order is a recal of the taker order that failed
  function __handleResidualProvision__(MgvLib.SingleOrder calldata order) internal virtual {
    order; //ssh
  }

  ///@notice Post-hook that implements default behavior when Taker Order's execution succeeded.
  ///@param order is a recall of the taker order that is at the origin of the current trade.
  ///@param maker_data is the returned value of the `__lastLook__` hook, triggered during trade execution. The special value `"lastLook/retract"` should be treated as an instruction not to repost the offer on the book.
  ///@return data can be:
  /// * `"posthook/filled"` when offer was completely filled
  /// * `"posthook/reposted"` when offer was partially filled and successfully reposted
  /// * Mangrove's revert reason (cast to a bytes32) when residual is below density or `this` balance on Mangrove is too low (and thus not reposted)
  /// @custom:hook overrides of this hook should be conservative and call `super.__posthookSuccess__(order, maker_data)`
  function __posthookSuccess__(MgvLib.SingleOrder calldata order, bytes32 maker_data)
    internal
    virtual
    returns (bytes32 data)
  {
    maker_data; // maker_data can be used in overrides to skip reposting for instance. It is ignored in the default behavior.
    // now trying to repost residual
    uint new_gives = __residualGives__(order);
    uint new_wants = __residualWants__(order);
    // Density check at each repost would be too gas costly.
    // We only treat the special case of `gives==0` or `wants==0` (total fill).
    // Offer below the density will cause Mangrove to throw so we encapsulate the call to `updateOffer` in order not to revert posthook for posting at dust level.
    if (new_gives == 0 || new_wants == 0) {
      return "posthook/filled";
    }
    data = _updateOffer(
      OfferArgs({
        outbound_tkn: IERC20(order.outbound_tkn),
        inbound_tkn: IERC20(order.inbound_tkn),
        wants: new_wants,
        gives: new_gives,
        gasreq: order.offerDetail.gasreq(),
        gasprice: order.offerDetail.gasprice(),
        pivotId: order.offer.next(), // using next as pivot since this offer is off the book
        noRevert: true,
        fund: 0
      }),
      order.offerId
    );
  }

  ///@notice template for start specific update offer function
  function _updateOffer(OfferArgs memory, uint) internal virtual returns (bytes32);

  ///@notice computes the provision that can be redeemed if deprovisioning a certain offer
  ///@param outbound_tkn the outbound token of the offer list
  ///@param inbound_tkn the inbound otken of the offer list
  ///@param offerId the id of the offer
  ///@return provision the provision that can be redeemed
  function _provisionOf(IERC20 outbound_tkn, IERC20 inbound_tkn, uint offerId) internal view returns (uint provision) {
    MgvStructs.OfferDetailPacked offerDetail = MGV.offerDetails(address(outbound_tkn), address(inbound_tkn), offerId);
    unchecked {
      provision = offerDetail.gasprice() * 10 ** 9 * (offerDetail.offer_gasbase() + offerDetail.gasreq());
    }
  }

  /// @inheritdoc IOfferLogic
  function getMissingProvision(IERC20 outbound_tkn, IERC20 inbound_tkn, uint gasreq, uint gasprice, uint offerId)
    public
    view
    returns (uint)
  {
    (MgvStructs.GlobalPacked globalData, MgvStructs.LocalPacked localData) =
      MGV.config(address(outbound_tkn), address(inbound_tkn));
    MgvStructs.OfferDetailPacked offerDetailData =
      MGV.offerDetails(address(outbound_tkn), address(inbound_tkn), offerId);
    uint gp;
    if (globalData.gasprice() > gasprice) {
      gp = globalData.gasprice();
    } else {
      gp = gasprice;
    }
    if (gasreq >= type(uint24).max) {
      gasreq = offerGasreq(); // this includes overhead of router if any
    }
    uint bounty = (gasreq + localData.offer_gasbase()) * gp * 10 ** 9; // in WEI
    // if `offerId` is not in the OfferList or deprovisioned, computed value below will be 0
    uint currentProvisionLocked =
      (offerDetailData.gasreq() + offerDetailData.offer_gasbase()) * offerDetailData.gasprice() * 10 ** 9;
    return (currentProvisionLocked >= bounty ? 0 : bounty - currentProvisionLocked);
  }
}

File 12 of 21 : MangroveOfferStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangroveOfferStorage.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import "mgv_src/strategies/interfaces/IOfferLogic.sol";

/// @title This is the storage part of a diamond storage scheme for `MangroveOffer` to reduce size of contracts.
library MangroveOfferStorage {
  /// @notice The layout of the storage.
  /// @param router the router to pull outbound tokens from contract's reserve to `this` and push inbound tokens to reserve.
  struct Layout {
    AbstractRouter router;
  }

  /// @notice Gets the `MangroveOffer` storage from a fixed slot.
  function getStorage() internal pure returns (Layout storage st) {
    // Unique slot within the contract
    bytes32 storagePosition = keccak256("Mangrove.MangroveOfferStorage");
    assembly {
      st.slot := storagePosition
    }
  }
}

File 13 of 21 : IOfferLogic.sol
// SPDX-License-Identifier:	BSD-2-Clause

// IOfferLogic.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pragma solidity >=0.8.0;

import {IMangrove} from "mgv_src/IMangrove.sol";
import {IERC20, IMaker} from "mgv_src/MgvLib.sol";
import {AbstractRouter} from "mgv_src/strategies/routers/AbstractRouter.sol";

///@title IOfferLogic interface for offer management
///@notice It is an IMaker for Mangrove.

interface IOfferLogic is IMaker {
  ///@notice Log incident (during post trade execution)
  event LogIncident(
    IMangrove mangrove,
    IERC20 indexed outbound_tkn,
    IERC20 indexed inbound_tkn,
    uint indexed offerId,
    bytes32 makerData,
    bytes32 mgvData
  );

  ///@notice Logging change of router address
  event SetRouter(AbstractRouter);

  ///@notice Actual gas requirement when posting offers via this strategy. Returned value may change if this contract's router is updated.
  ///@return total gas cost including router specific costs (if any).
  function offerGasreq() external view returns (uint total);

  ///@notice Computes missing provision to repost `offerId` at given `gasreq` and `gasprice` ignoring current contract's balance on Mangrove.
  ///@param outbound_tkn the outbound token used to identify the order book
  ///@param inbound_tkn the inbound token used to identify the order book
  ///@param gasreq the gas required by the offer. Give > type(uint24).max to use `this.offerGasreq()`
  ///@param gasprice the upper bound on gas price. Give 0 to use Mangrove's gasprice
  ///@param offerId the offer id. Set this to 0 if one is not reposting an offer
  ///@dev if `offerId` is not in the Order Book, will simply return how much is needed to post
  ///@return missingProvision to repost `offerId`.
  function getMissingProvision(IERC20 outbound_tkn, IERC20 inbound_tkn, uint gasreq, uint gasprice, uint offerId)
    external
    view
    returns (uint missingProvision);

  ///@notice sets a new router to pull outbound tokens from contract's reserve to `this` and push inbound tokens to reserve.
  ///@param router_ the new router contract that this contract should use. Use `NO_ROUTER` for no router.
  ///@dev new router needs to be approved by `this` to push funds to reserve (see `activate` function). It also needs to be approved by reserve to pull from it.
  function setRouter(AbstractRouter router_) external;

  ///@notice Approves a spender to transfer a certain amount of tokens on behalf of `this`.
  ///@param token the ERC20 token contract
  ///@param spender the approved spender
  ///@param amount the spending amount
  ///@dev admin may use this function to revoke specific approvals of `this` that are set after a call to `activate`.
  function approve(IERC20 token, address spender, uint amount) external returns (bool);

  ///@notice computes the amount of native tokens that can be redeemed when deprovisioning a given offer.
  ///@param outbound_tkn the outbound token of the offer list
  ///@param inbound_tkn the inbound token of the offer list
  ///@param offerId the identifier of the offer in the offer list
  ///@return provision the amount of native tokens that can be redeemed when deprovisioning the offer
  function provisionOf(IERC20 outbound_tkn, IERC20 inbound_tkn, uint offerId) external view returns (uint provision);

  ///@notice verifies that this contract's current state is ready to be used by `msg.sender` to post offers on Mangrove
  ///@dev throws with a reason if something (e.g. an approval) is missing.
  function checkList(IERC20[] calldata tokens) external view;

  /// @notice performs the required approvals so as to allow `this` to interact with Mangrove on a set of assets.
  /// @param tokens the ERC20 `this` will approve to be able to trade on Mangrove's corresponding markets.
  function activate(IERC20[] calldata tokens) external;

  ///@notice withdraws native tokens from `this` balance on Mangrove.
  ///@param amount the amount of WEI one wishes to withdraw.
  ///@param receiver the address of the receiver of the funds.
  ///@dev Since a call is made to the `receiver`, this function is subject to reentrancy.
  function withdrawFromMangrove(uint amount, address payable receiver) external;

  ///@notice Memory allocation for `_new/updateOffer`'s arguments.
  ///@param outbound_tkn outbound token of the offer list.
  ///@param inbound_tkn inbound token of the offer list.
  ///@param wants the amount of inbound tokens the maker wants for a complete fill.
  ///@param gives the amount of outbound tokens the maker gives for a complete fill.
  ///@param gasreq the amount of gas units that are required to execute the trade (use type(uint).max for using `this.offerGasReq()`)
  ///@param gasprice the gasprice used to compute offer's provision (use 0 to use Mangrove's gasprice)
  ///@param pivotId a best pivot estimate for cheap offer insertion in the offer list.
  ///@param fund WEIs in `this` contract's balance that are used to provision the offer.
  ///@param noRevert is set to true if calling function does not wish `_newOffer` to revert on error.
  ///@param owner the offer maker managing the offer.
  ///@dev `owner` is required in `Forwarder` logics, when `_newOffer` or `_updateOffer` in called in a hook (`msg.sender==MGV`).
  struct OfferArgs {
    IERC20 outbound_tkn;
    IERC20 inbound_tkn;
    uint wants;
    uint gives;
    uint gasreq;
    uint gasprice;
    uint pivotId;
    uint fund;
    bool noRevert;
  }

  ///@notice Retracts an offer from an Offer List of Mangrove.
  ///@param outbound_tkn the outbound token of the offer list.
  ///@param inbound_tkn the inbound token of the offer list.
  ///@param offerId the identifier of the offer in the (`outbound_tkn`,`inbound_tkn`) offer list
  ///@param deprovision positioned if `msg.sender` wishes to redeem the offer's provision.
  ///@return received the amount of native tokens (in WEI) that have been retrieved by retracting the offer.
  ///@dev An offer that is retracted without `deprovision` is retracted from the offer list, but still has its provisions locked by Mangrove.
  ///@dev Calling this function, with the `deprovision` flag, on an offer that is already retracted must be used to retrieve the locked provisions.
  function retractOffer(
    IERC20 outbound_tkn,
    IERC20 inbound_tkn,
    uint offerId,
    bool deprovision // if set to `true`, `this` will receive the remaining provision (in WEI) associated to `offerId`.
  ) external returns (uint received);

  /// @notice getter of the reserve address of `maker`.
  /// @param maker the address of the offer maker one wishes to know the reserve of.
  /// @return reserve_ the address of the offer maker's reserve of liquidity.
  /// @dev if no reserve is set for maker, default reserve is maker's address. Thus this function never returns `address(0)`.
  function reserve(address maker) external view returns (address);

  /// @notice Contract's router getter.
  /// @dev if contract has a no router, function returns `NO_ROUTER`.
  function router() external view returns (AbstractRouter);
}

File 14 of 21 : Direct.sol
// SPDX-License-Identifier:	BSD-2-Clause

// Direct.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {MangroveOffer} from "mgv_src/strategies/MangroveOffer.sol";
import {MgvLib, IERC20, MgvStructs} from "mgv_src/MgvLib.sol";
import {MangroveOfferStorage as MOS} from "mgv_src/strategies/MangroveOfferStorage.sol";
import {TransferLib} from "mgv_src/strategies/utils/TransferLib.sol";
import {IMangrove} from "mgv_src/IMangrove.sol";
import {AbstractRouter} from "mgv_src/strategies/routers/AbstractRouter.sol";
import {IOfferLogic} from "mgv_src/strategies/interfaces/IOfferLogic.sol";

/// `Direct` strats is an extension of MangroveOffer that allows contract's admin to manage offers on Mangrove.
abstract contract Direct is MangroveOffer {
  constructor(IMangrove mgv, AbstractRouter router_, uint gasreq) MangroveOffer(mgv, gasreq) {
    if (router_ != NO_ROUTER) {
      setRouter(router_);
    }
  }

  function __checkList__(IERC20 token) internal view virtual override {
    require(msg.sender == admin(), "Direct/onlyAdminCanOwnOffers");
    address adminReserve = reserve(admin());
    // if this contract does the routing by itself, it must be approved by the reserve to do so.
    if (router() == NO_ROUTER && adminReserve != address(this)) {
      require(token.allowance(adminReserve, address(this)) > 0, "Direct/reserveMustApproveMakerContract");
    }
    super.__checkList__(token);
  }

  function pull(IERC20 token, uint amount, bool strict) internal returns (uint) {
    AbstractRouter router_ = router();
    address adminReserve = reserve(admin());
    if (router_ == NO_ROUTER) {
      // noop if reserve == this and local balance >= amount
      bool success = TransferLib.transferTokenFrom(token, adminReserve, address(this), amount);
      return success ? amount : (token.balanceOf(address(this)));
    } else {
      // letting specific router pull the funds from reserve
      return router_.pull(token, adminReserve, amount, strict);
    }
  }

  function push(IERC20 token, uint amount) internal returns (uint) {
    AbstractRouter router_ = router();
    if (router_ == NO_ROUTER) {
      return amount; // nothing to do
    } else {
      // noop if reserve == address(this)
      return router_.push(token, reserve(admin()), amount);
    }
  }

  function flush(IERC20[] memory tokens) internal {
    AbstractRouter router_ = MOS.getStorage().router;
    address reserve_ = reserve(admin());
    if (router_ == NO_ROUTER) {
      for (uint i = 0; i < tokens.length; i++) {
        require(
          TransferLib.transferToken(tokens[i], reserve_, tokens[i].balanceOf(address(this))),
          "Direct/flush/transferFail"
        );
      }
      return;
    } else {
      router_.flush(tokens, reserve_);
    }
  }

  function _newOffer(OfferArgs memory args) internal returns (uint) {
    try MGV.newOffer{value: args.fund}(
      address(args.outbound_tkn),
      address(args.inbound_tkn),
      args.wants,
      args.gives,
      args.gasreq >= type(uint24).max ? offerGasreq() : args.gasreq,
      args.gasprice,
      args.pivotId
    ) returns (uint offerId) {
      return offerId;
    } catch Error(string memory reason) {
      require(args.noRevert, reason);
      return 0;
    }
  }

  function _updateOffer(OfferArgs memory args, uint offerId) internal override returns (bytes32) {
    if (args.gasreq >= type(uint24).max) {
      MgvStructs.OfferDetailPacked detail =
        MGV.offerDetails(address(args.outbound_tkn), address(args.inbound_tkn), offerId);
      args.gasreq = detail.gasreq();
    }
    try MGV.updateOffer{value: args.fund}(
      address(args.outbound_tkn),
      address(args.inbound_tkn),
      args.wants,
      args.gives,
      args.gasreq,
      args.gasprice,
      args.pivotId,
      offerId
    ) {
      return REPOST_SUCCESS;
    } catch Error(string memory reason) {
      require(args.noRevert, reason);
      return bytes32(bytes(reason));
    }
  }

  // Retracts `offerId` from the (`outbound_tkn`,`inbound_tkn`) Offer list of Mangrove.
  // Function call will throw if `this` contract is not the owner of `offerId`.
  // Returned value is the amount of ethers that have been credited to `this` contract balance on Mangrove (always 0 if `deprovision=false`)
  // NB `mgvOrAdmin` modifier guarantees that this function is either called by contract admin or (indirectly) during trade execution by Mangrove
  function retractOffer(
    IERC20 outbound_tkn,
    IERC20 inbound_tkn,
    uint offerId,
    bool deprovision // if set to `true`, `this` contract will receive the remaining provision (in WEI) associated to `offerId`.
  ) public override mgvOrAdmin returns (uint free_wei) {
    free_wei = MGV.retractOffer(address(outbound_tkn), address(inbound_tkn), offerId, deprovision);
    if (free_wei > 0) {
      require(MGV.withdraw(free_wei), "Direct/withdrawFail");
      // sending native tokens to `msg.sender` prevents reentrancy issues
      // (the context call of `retractOffer` could be coming from `makerExecute` and a different recipient of transfer than `msg.sender` could use this call to make offer fail)
      (bool noRevert,) = admin().call{value: free_wei}("");
      require(noRevert, "mgvOffer/weiTransferFail");
    }
  }

  ///@inheritdoc IOfferLogic
  function provisionOf(IERC20 outbound_tkn, IERC20 inbound_tkn, uint offerId)
    external
    view
    override
    returns (uint provision)
  {
    provision = _provisionOf(outbound_tkn, inbound_tkn, offerId);
  }

  function __put__(uint, /*amount*/ MgvLib.SingleOrder calldata) internal virtual override returns (uint missing) {
    // direct contract do not need to do anything specific with incoming funds during trade
    // one should override this function if one wishes to leverage taker's fund during trade execution
    // be aware that the incoming funds will be transferred back to the reserve in posthookSuccess using flush.
    // this is done in posthook, to accumulate all taken offers and transfer everything in one transfer.
    return 0;
  }

  // default `__get__` hook for `Direct` is to pull liquidity from `reserve(admin())`
  // letting router handle the specifics if any
  function __get__(uint amount, MgvLib.SingleOrder calldata order) internal virtual override returns (uint missing) {
    // pulling liquidity from reserve
    // depending on the router, this may result in pulling more/less liquidity than required
    // so one should check local balance to compute missing liquidity
    uint pulled = pull(IERC20(order.outbound_tkn), amount, false);
    missing = pulled >= amount ? 0 : amount - pulled;
  }

  function __posthookSuccess__(MgvLib.SingleOrder calldata order, bytes32 makerData)
    internal
    virtual
    override
    returns (bytes32)
  {
    IERC20[] memory tokens = new IERC20[](2);
    tokens[0] = IERC20(order.outbound_tkn); // flushing outbound tokens if this contract pulled more liquidity than required during `makerExecute`
    tokens[1] = IERC20(order.inbound_tkn); // flushing liquidity brought by taker
    // sends all tokens to the reserve (noop if reserve(admin()) == address(this))
    flush(tokens);
    // reposting offer residual if any
    return super.__posthookSuccess__(order, makerData);
  }
}

File 15 of 21 : AbstractKandel.sol
// SPDX-License-Identifier:	BSD-2-Clause

// AbstractKandel.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {Direct, IMangrove, IERC20, MgvLib} from "mgv_src/strategies/offer_maker/abstract/Direct.sol";

abstract contract AbstractKandel {
  ///@notice signals that the price has moved above Kandel's current price range
  event AllAsks(IMangrove indexed mgv, IERC20 indexed base, IERC20 indexed quote);
  ///@notice signals that the price has moved below Kandel's current price range
  event AllBids(IMangrove indexed mgv, IERC20 indexed base, IERC20 indexed quote);

  ///@notice a bid or an ask
  enum OrderType {
    Bid,
    Ask
  }

  ///@notice base distribution at given index
  ///@param index of the distribution of base tokens
  ///@return amount of base tokens that Kandel should give/want at `index`
  function baseOfIndex(uint index) public view virtual returns (uint96 amount);

  ///@notice quote distribution at given index
  ///@param index of the distribution of quote tokens
  ///@return amount of quote tokens that Kandel should give/want at `index`
  function quoteOfIndex(uint index) public view virtual returns (uint96 amount);

  ///@notice transport logic followed by Kandel
  ///@param ba whether the offer that was executed is a bid or an ask
  ///@param order a recap of the taker order (order.offer is the executed offer)
  ///@return dualBa the type of order implementing the transport
  ///@return dualIndex the distribution index where liquidity is transported
  ///@return args the argument for `populateIndex` specifying volume and price
  function _transportLogic(OrderType ba, MgvLib.SingleOrder calldata order)
    internal
    virtual
    returns (OrderType dualBa, uint dualIndex, Direct.OfferArgs memory args);
}

File 16 of 21 : CoreKandel.sol
// SPDX-License-Identifier:	BSD-2-Clause

// CoreKandel.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {
  MangroveOffer,
  Direct,
  IMangrove,
  IERC20,
  MgvLib,
  MgvStructs
} from "mgv_src/strategies/offer_maker/abstract/Direct.sol";
import {AbstractKandel} from "./AbstractKandel.sol";
import {console} from "forge-std/console.sol";

abstract contract CoreKandel is Direct, AbstractKandel {
  ///@notice number of offers managed by this strat
  uint16 public immutable NSLOTS;
  ///@notice base of the market Kandel is making
  IERC20 public immutable BASE;
  ///@notice quote of the market Kandel is making
  IERC20 public immutable QUOTE;
  ///@notice `pendingBase` is the amount of free (not promised) base tokens in reserve
  uint128 public pendingBase;
  ///@notice `pendingQuote` is the amount of free quote tokens in reserve
  uint128 public pendingQuote;

  ///@notice maps index to offer id on Mangrove
  uint[][2] public _offerIdOfIndex;
  mapping(OrderType => mapping(uint => uint)) public _indexOfOfferId;

  constructor(IMangrove mgv, IERC20 base, IERC20 quote, uint gasreq, uint16 nslots) Direct(mgv, NO_ROUTER, gasreq) {
    NSLOTS = nslots;
    BASE = base;
    QUOTE = quote;
    _offerIdOfIndex[uint(OrderType.Bid)] = new uint[](NSLOTS);
    _offerIdOfIndex[uint(OrderType.Ask)] = new uint[](NSLOTS);
    // approves Mangrove to pull base and quote token from this contract
    __activate__(base);
    __activate__(quote);
  }

  function getPending(OrderType ba) public view returns (uint pending) {
    pending = ba == OrderType.Ask ? pendingBase : pendingQuote;
  }

  function setPending(OrderType ba, uint amount) public mgvOrAdmin {
    require(uint128(amount) == amount, "Kandel/pendingOverflow");
    if (ba == OrderType.Ask) {
      pendingBase = uint128(amount);
    } else {
      pendingQuote = uint128(amount);
    }
  }

  function offerIdOfIndex(OrderType ba, uint index) public view returns (uint) {
    return _offerIdOfIndex[uint(ba)][index];
  }

  function indexOfOfferId(OrderType ba, uint offerId) public view returns (uint) {
    return _indexOfOfferId[ba][offerId];
  }

  ///@notice how much price and volume distribution Kandel should give at given index
  ///@param ba whether Kandel is asking or bidding at this index
  ///@param index the distribution index
  function _givesOfIndex(OrderType ba, uint index) internal view returns (uint) {
    return ba == OrderType.Bid ? quoteOfIndex(index) : baseOfIndex(index);
  }

  ///@notice how much price and volume distribution Kandel should want at given index
  ///@param ba whether Kandel is asking or bidding at this index
  ///@param index the distribution index
  function _wantsOfIndex(OrderType ba, uint index) internal view returns (uint) {
    return ba == OrderType.Bid ? baseOfIndex(index) : quoteOfIndex(index);
  }

  ///@notice turns an order type into an (outbound, inbound) pair identifying an offer list
  ///@param ba whether one wishes to access the offer lists where asks or bids are posted
  function _tokenPairOfOrderType(OrderType ba) internal view returns (IERC20, IERC20) {
    return ba == OrderType.Bid ? (QUOTE, BASE) : (BASE, QUOTE);
  }

  ///@notice returns the Kandel order type of the offer list whose outbound token is given in argument
  ///@param outbound_tkn the outbound token of the offer list
  function _orderTypeOfOutbound(IERC20 outbound_tkn) internal view returns (OrderType) {
    return outbound_tkn == BASE ? OrderType.Ask : OrderType.Bid;
  }

  ///@notice retracts the order at given index from Mangrove
  ///@param ba the order type
  ///@param index the index of the order
  ///@param deprovision whether one wishes to be credited free wei's on Mangrove's balance
  function retractOffer(OrderType ba, uint index, bool deprovision) public mgvOrAdmin returns (uint) {
    (IERC20 outbound_tkn, IERC20 inbound_tkn) = _tokenPairOfOrderType(ba);
    uint offerId = offerIdOfIndex(ba, index);
    return retractOffer(outbound_tkn, inbound_tkn, offerId, deprovision);
  }

  ///@notice retrieve offer data on Mangrove
  ///@param ba the order type
  ///@param index the distribution index of the offer
  function getOffer(OrderType ba, uint index)
    public
    view
    returns (MgvStructs.OfferPacked, MgvStructs.OfferDetailPacked)
  {
    (IERC20 outbound_tkn, IERC20 inbound_tkn) = _tokenPairOfOrderType(ba);
    uint offerId = offerIdOfIndex(ba, index);
    return (
      MGV.offers(address(outbound_tkn), address(inbound_tkn), offerId),
      MGV.offerDetails(address(outbound_tkn), address(inbound_tkn), offerId)
    );
  }

  ///@notice check whether given order is live on Mangrove
  ///@param ba the order type
  ///@param index the price index of the order
  ///@return live is true if the order is live on Mangrove
  function isLive(OrderType ba, uint index) public view returns (bool live) {
    (IERC20 outbound_tkn, IERC20 inbound_tkn) = _tokenPairOfOrderType(ba);
    uint offerId = offerIdOfIndex(ba, index);
    return offerId > 0 && MGV.isLive(MGV.offers(address(outbound_tkn), address(inbound_tkn), offerId));
  }

  ///@notice returns the dual order type
  ///@param ba whether the order is an ask or a bid
  ///@return dualBa is the dual order type (ask for bid and conversely)
  function dual(OrderType ba) public pure returns (OrderType dualBa) {
    return OrderType((uint(ba) + 1) % 2);
  }

  ///@notice returns next index if order is an ask, and previous price index if order is a bid
  ///@param ba whether the order is an ask or a bid
  ///@param index the price index of the order
  ///@return dualIndex the index of the dual order
  ///@dev `ba == Ask => index > 0` and `ba == Bid => index < NSLOT-1`
  function dual(OrderType ba, uint index) public pure returns (uint dualIndex) {
    return ba == OrderType.Ask ? index - 1 : index + 1;
  }

  ///@notice publishes (by either creating or updating) a bid/ask at a given price index
  ///@param ba whether the offer is a bid or an ask
  ///@param index the index of the distribution
  ///@param args the argument of the offer.
  ///@dev args.wants/gives must match the distribution at index
  function _populateIndex(OrderType ba, uint index, OfferArgs memory args) internal returns (bytes32) {
    uint offerId = offerIdOfIndex(ba, index);
    if (isLive(dual(ba), index)) {
      // not populating index as this would cross the OB
      // storing pending liquidity
      setPending(ba, args.gives);
      return "populate/crossed";
    }
    if (offerId == 0 && args.gives > 0) {
      offerId = _newOffer(args);
      if (offerId == 0) {
        //FIXME `_newOffer` should return Mangrove's error message if `noRevert` is set
        return "newOffer/Failed";
      } else {
        _offerIdOfIndex[uint(ba)][index] = offerId;
        _indexOfOfferId[ba][offerId] = index;
        return REPOST_SUCCESS;
      }
    } else {
      if (offerId == 0) {
        //offerId && gives are 0
        return "";
      }
      if (args.gives == 0) {
        retractOffer(args.outbound_tkn, args.inbound_tkn, offerId, false);
        return "populate/retracted";
      } else {
        return _updateOffer(args, offerId);
      }
    }
  }

  ///@notice publishes bids/asks in the distribution interval `[to,from[`
  ///@param from start index
  ///@param to end index
  ///@param lastBidIndex the index after which offer should be an Ask
  ///@param gasprice that should be used to compute the offer's provision
  ///@param pivotIds `pivotIds[i]` is the pivot to be used for offer at index `from+i`.
  function populate(uint from, uint to, uint lastBidIndex, uint gasprice, uint[] calldata pivotIds)
    external
    payable
    onlyAdmin
  {
    if (msg.value > 0) {
      MGV.fund{value: msg.value}();
    }
    for (uint index = from; index < to; index++) {
      OfferArgs memory args;
      OrderType ba = index <= lastBidIndex ? OrderType.Bid : OrderType.Ask;
      (args.outbound_tkn, args.inbound_tkn) = _tokenPairOfOrderType(ba);
      args.gives = _givesOfIndex(ba, index);
      args.wants = _wantsOfIndex(ba, index);
      args.fund = 0;
      args.noRevert = false;
      args.gasreq = offerGasreq();
      args.gasprice = gasprice;
      args.pivotId = pivotIds[index - from];
      _populateIndex(ba, index, args);
    }
  }

  ///@notice retracts and deprovisions offers of the distribution interval `[from, to[`
  ///@param from the start index
  ///@param to the end index
  ///@dev this simply provisions this contract's balance on Mangrove.
  ///@dev use in conjunction of `withdrawFromMangrove` if the user wishes to redeem the available WEIs
  function retractOffers(uint from, uint to) external onlyAdmin {
    uint collected;
    for (uint index = from; index < to; index++) {
      (IERC20 outbound_tkn, IERC20 inbound_tkn) = _tokenPairOfOrderType(OrderType.Ask);
      collected +=
        MGV.retractOffer(address(outbound_tkn), address(inbound_tkn), offerIdOfIndex(OrderType.Ask, index), true);
      (outbound_tkn, inbound_tkn) = _tokenPairOfOrderType(OrderType.Bid);
      collected +=
        MGV.retractOffer(address(outbound_tkn), address(inbound_tkn), offerIdOfIndex(OrderType.Bid, index), true);
    }
  }

  ///@notice takes care of reposting residual offer in case of a partial fill and logging potential issues.
  ///@param order a recap of the taker order
  ///@param makerData generated during `makerExecute` so as to log it if necessary
  ///@return notPublished the amount of liquidity that failed to be published on mangrove
  function _handleResidual(MgvLib.SingleOrder calldata order, bytes32 makerData) internal returns (uint notPublished) {
    bytes32 repostStatus = super.__posthookSuccess__(order, makerData);
    // Offer failed to repost for bad reason, logging the incident
    if (repostStatus == "posthook/filled" || repostStatus == REPOST_SUCCESS) {
      return 0;
    }
    if (repostStatus == "mgv/writeOffer/density/tooLow") {
      return __residualGives__(order);
    } else {
      emit LogIncident(
        MGV, IERC20(order.outbound_tkn), IERC20(order.inbound_tkn), order.offerId, makerData, repostStatus
        );
      return __residualGives__(order);
    }
  }

  ///@notice repost residual offer and dual offer according to transport logic
  ///@inheritdoc MangroveOffer
  function __posthookSuccess__(MgvLib.SingleOrder calldata order, bytes32 makerData)
    internal
    override
    returns (bytes32)
  {
    OrderType ba = _orderTypeOfOutbound(IERC20(order.outbound_tkn));
    // adds any unpublished liquidity to pending[Base/Quote]
    setPending(ba, _handleResidual(order, makerData));
    // preparing arguments for the dual maker order
    (OrderType dualBa, uint dualIndex, OfferArgs memory args) = _transportLogic(ba, order);
    return _populateIndex(dualBa, dualIndex, args);
  }

  ///@notice In case an offer failed to deliver, promised liquidity becomes pending, but offer is not reposted.
  ///@inheritdoc MangroveOffer
  function __posthookFallback__(MgvLib.SingleOrder calldata order, MgvLib.OrderResult calldata)
    internal
    override
    returns (bytes32)
  {
    OrderType ba = _orderTypeOfOutbound(IERC20(order.outbound_tkn));
    setPending(ba, order.offer.gives());
    return "";
  }
}

File 17 of 21 : AbstractRouter.sol
// SPDX-License-Identifier:	BSD-2-Clause

//AbstractRouter.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pragma solidity ^0.8.10;

import {AccessControlled} from "mgv_src/strategies/utils/AccessControlled.sol";
import {AbstractRouterStorage as ARSt} from "./AbstractRouterStorage.sol";
import {IERC20} from "mgv_src/MgvLib.sol";

/// @title AbstractRouter
/// @notice Partial implementation and requirements for liquidity routers.

abstract contract AbstractRouter is AccessControlled {
  uint24 immutable ROUTER_GASREQ;

  ///@notice This modifier verifies that `msg.sender` an allowed caller of this router.
  modifier onlyMakers() {
    require(makers(msg.sender), "Router/unauthorized");
    _;
  }

  ///@notice This modifier verifies that `msg.sender` is the admin or an allowed caller of this router.
  modifier makersOrAdmin() {
    require(msg.sender == admin() || makers(msg.sender), "Router/unauthorized");
    _;
  }

  ///@notice constructor for abstract routers.
  ///@param routerGasreq_ is the amount of gas that is required for this router to be able to perform a `pull` and a `push`.
  constructor(uint routerGasreq_) AccessControlled(msg.sender) {
    require(uint24(routerGasreq_) == routerGasreq_, "Router/gasreqTooHigh");
    ROUTER_GASREQ = uint24(routerGasreq_);
  }

  ///@notice getter for the `makers: addr => bool` mapping
  ///@param mkr the address of a maker
  ///@return true if `mkr` is authorized to call this router.
  function makers(address mkr) public view returns (bool) {
    return ARSt.getStorage().makers[mkr];
  }

  ///@notice view for gas overhead of this router.
  ///@return overhead the added (overapproximated) gas cost of `push` and `pull`.
  function routerGasreq() public view returns (uint overhead) {
    return ROUTER_GASREQ;
  }

  ///@notice pulls liquidity from an offer maker's reserve to `msg.sender`'s balance
  ///@param token is the ERC20 managing the pulled asset
  ///@param reserve where `amount` of `token` should be pulled from
  ///@param amount of `token` the maker contract wishes to get
  ///@param strict when the calling maker contract accepts to receive more `token` than required (this may happen for gas optimization)
  function pull(IERC20 token, address reserve, uint amount, bool strict) external onlyMakers returns (uint pulled) {
    pulled = __pull__({token: token, reserve: reserve, maker: msg.sender, amount: amount, strict: strict});
  }

  ///@notice router-dependant implementation of the `pull` function
  function __pull__(IERC20 token, address reserve, address maker, uint amount, bool strict)
    internal
    virtual
    returns (uint);

  ///@notice pushes assets from maker contract's balance to the specified reserve
  ///@param token is the asset the maker is pushing
  ///@param reserve is the address identifying where the transferred assets should be placed to
  ///@param amount is the amount of asset that should be transferred from the calling maker contract
  ///@return pushed fraction of `amount` that was successfully pushed to reserve.
  function push(IERC20 token, address reserve, uint amount) external onlyMakers returns (uint pushed) {
    return __push__({token: token, reserve: reserve, maker: msg.sender, amount: amount});
  }

  ///@notice router-dependant implementation of the `push` function
  function __push__(IERC20 token, address reserve, address maker, uint amount) internal virtual returns (uint);

  ///@notice iterative `push` in a single call
  function flush(IERC20[] calldata tokens, address reserve) external onlyMakers {
    for (uint i = 0; i < tokens.length; i++) {
      uint amount = tokens[i].balanceOf(msg.sender);
      if (amount > 0) {
        require(__push__(tokens[i], reserve, msg.sender, amount) == amount, "router/pushFailed");
      }
    }
  }

  ///@notice returns the amount of `token`s that can be made available for pulling by the maker contract
  ///@dev when this router is pulling from a lender, this must return the amount of asset that can be withdrawn from reserve
  ///@param token is the asset one wishes to know the balance of
  ///@param reserve is the address identifying the location of the assets
  function reserveBalance(IERC20 token, address reserve) external view virtual returns (uint);

  ///@notice adds a maker contract address to the allowed makers of this router
  ///@dev this function is callable by router's admin to bootstrap, but later on an allowed maker contract can add another address
  ///@param maker the maker contract address
  function bind(address maker) public onlyAdmin {
    ARSt.getStorage().makers[maker] = true;
  }

  ///@notice removes a maker contract address from the allowed makers of this router
  ///@param maker the maker contract address
  function unbind(address maker) public onlyAdmin {
    ARSt.getStorage().makers[maker] = false;
  }

  ///@notice removes `msg.sender` from the allowed makers of this router
  function unbind() external onlyMakers {
    ARSt.getStorage().makers[msg.sender] = false;
  }

  ///@notice verifies all required approval involving `this` router (either as a spender or owner)
  ///@dev `checkList` returns normally if all needed approval are strictly positive. It reverts otherwise with a reason.
  ///@param token is the asset (and possibly its overlyings) whose approval must be checked
  ///@param reserve the reserve that requires asset pulling/pushing
  function checkList(IERC20 token, address reserve) external view {
    require(ARSt.getStorage().makers[msg.sender], "Router/CallerIsNotAnApprovedMakerContract");
    // checking maker contract has approved this for token transfer (in order to push to reserve)
    require(token.allowance(msg.sender, address(this)) > 0, "Router/NotApprovedByMakerContract");
    // pulling from reserve might require a special approval if `reserve` is some account on a protocol (e.g a lender) which requires a custom redeem call.
    __checkList__(token, reserve);
  }

  ///@notice router-dependent implementation of the `checkList` function
  function __checkList__(IERC20 token, address reserve) internal view virtual;

  ///@notice performs necessary approval to activate router function on a particular asset
  ///@param token the asset one wishes to use the router for
  function activate(IERC20 token) external makersOrAdmin {
    __activate__(token);
  }

  ///@notice router-dependent implementation of the `activate` function
  function __activate__(IERC20 token) internal virtual {
    token; //ssh
  }
}

File 18 of 21 : AbstractRouterStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

//AbstractRouterStorage.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pragma solidity ^0.8.10;

/// @title This is the storage part of a diamond storage scheme for `AbstractRouter` to reduce size of contracts.
library AbstractRouterStorage {
  /// @notice The layout of the storage.
  /// @param makers maker contract addresses allowed to call this router.
  /// @param gasOverhead the gas overhead of this router.
  struct Layout {
    mapping(address => bool) makers;
  }

  /// @notice Gets the `AbstractRouter` storage from a fixed slot.
  function getStorage() internal pure returns (Layout storage st) {
    // Unique slot within the contract
    bytes32 storagePosition = keccak256("Mangrove.AbstractRouterStorage");
    assembly {
      st.slot := storagePosition
    }
  }
}

File 19 of 21 : AccessControlled.sol
// SPDX-License-Identifier:	BSD-2-Clause

// AccessControlled.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {AccessControlledStorage as ACS} from "./AccessControlledStorage.sol";

/// @title This contract is used to restrict access to privileged functions of inheriting contracts through modifiers.
/// @notice The contract stores an admin address which is checked against `msg.sender` in the `onlyAdmin` modifier.
/// @notice Additionally, a specific `msg.sender` can be verified with the `onlyCaller` modifier.
contract AccessControlled {
  /// @notice logs new `admin` of `this`
  event SetAdmin(address admin);

  /**
   * @notice `AccessControlled`'s constructor
   * @param admin_ The address of the admin that can access privileged functions and also allowed to change the admin. Cannot be `address(0)`.
   */
  constructor(address admin_) {
    require(admin_ != address(0), "AccessControlled/0xAdmin");
    ACS.getStorage().admin = admin_;
  }

  /**
   * @notice This modifier verifies that `msg.sender` is the caller.
   * @param caller The address of the caller that can access the modified function.
   */
  modifier onlyCaller(address caller) {
    require(msg.sender == caller, "AccessControlled/Invalid");
    _;
  }

  /**
   * @notice Retrieves the current admin.
   */
  function admin() public view returns (address) {
    return ACS.getStorage().admin;
  }

  /**
   * @notice This modifier verifies that `msg.sender` is the admin.
   */
  modifier onlyAdmin() {
    require(msg.sender == admin(), "AccessControlled/Invalid");
    _;
  }

  /**
   * @notice This sets the admin. Only the current admin can change the admin.
   * @param admin_ The new admin. Cannot be `address(0)`.
   */
  function setAdmin(address admin_) public onlyAdmin {
    require(admin_ != address(0), "AccessControlled/0xAdmin");
    ACS.getStorage().admin = admin_;
    emit SetAdmin(admin_);
  }
}

File 20 of 21 : AccessControlledStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

// AccessControlledStorage.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

/// @title This is the storage part of a diamond storage scheme for `AccessControlled` to reduce size of contracts.
library AccessControlledStorage {
  /// @notice The layout of the storage.
  /// @param admin the admin of the access controlled contract.
  struct Layout {
    address admin;
  }

  /// @notice Gets the `AccessControlled` storage from a fixed slot.
  function getStorage() internal pure returns (Layout storage st) {
    // Unique slot within the contract
    bytes32 storagePosition = keccak256("Mangrove.AccessControlledStorage");
    assembly {
      st.slot := storagePosition
    }
  }
}

File 21 of 21 : TransferLib.sol
// SPDX-License-Identifier:	BSD-2-Clause

// TransferLib.sol

// Copyright (c) 2022 ADDMA. All rights reserved.

// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pragma solidity ^0.8.10;

import {IERC20} from "mgv_src/MgvLib.sol";

///@title This library helps with safely interacting with ERC20 tokens
///@notice Transferring 0 or to self will be skipped.
///@notice ERC20 tokens returning bool instead of reverting are handled.
library TransferLib {
  ///@notice This transfer amount of token to recipient address
  ///@param token Token to be transferred
  ///@param recipient Address of the recipient the tokens will be transferred to
  ///@param amount The amount of tokens to be transferred
  function transferToken(IERC20 token, address recipient, uint amount) internal returns (bool) {
    if (amount == 0) {
      return true;
    }
    if (recipient == address(this)) {
      return token.balanceOf(recipient) >= amount;
    }
    return _transferToken(token, recipient, amount);
  }

  function _transferToken(IERC20 token, address recipient, uint amount) private returns (bool) {
    // This low level call will not revert but instead return success=false if callee reverts, so we
    // verify that it does not revert by checking success, but we also have to check
    // the returned data if any since some ERC20 tokens to not strictly follow the standard of reverting
    // but instead return false.
    (bool success, bytes memory data) =
      address(token).call(abi.encodeWithSelector(token.transfer.selector, recipient, amount));
    return (success && (data.length == 0 || abi.decode(data, (bool))));
  }

  ///@notice This transfer amount of token to recipient address from spender address
  ///@param token Token to be transferred
  ///@param spender Address of the spender, where the tokens will be transferred from
  ///@param recipient Address of the recipient, where the tokens will be transferred to
  ///@param amount The amount of tokens to be transferred
  ///@return true if transfer was successful; otherwise, false.
  function transferTokenFrom(IERC20 token, address spender, address recipient, uint amount) internal returns (bool) {
    if (amount == 0) {
      return true;
    }
    if (spender == recipient) {
      return token.balanceOf(spender) >= amount;
    }
    // optimization to avoid requiring contract to approve itself
    if (spender == address(this)) {
      return _transferToken(token, recipient, amount);
    }
    return _transferTokenFrom(token, spender, recipient, amount);
  }

  function _transferTokenFrom(IERC20 token, address spender, address recipient, uint amount) private returns (bool) {
    // This low level call will not revert but instead return success=false if callee reverts, so we
    // verify that it does not revert by checking success, but we also have to check
    // the returned data if there since some ERC20 tokens to not strictly follow the standard of reverting
    // but instead return false.
    (bool success, bytes memory data) =
      address(token).call(abi.encodeWithSelector(token.transferFrom.selector, spender, recipient, amount));
    return (success && (data.length == 0 || abi.decode(data, (bool))));
  }
}

Settings
{
  "remappings": [
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "mgv_lib/=lib/",
    "mgv_script/=script/",
    "mgv_src/=src/",
    "mgv_test/=test/",
    "src/=src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "london",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"contract IMangrove","name":"mgv","type":"address"},{"internalType":"contract IERC20","name":"base","type":"address"},{"internalType":"contract IERC20","name":"quote","type":"address"},{"internalType":"uint256","name":"gasreq","type":"uint256"},{"internalType":"uint16","name":"nslots","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IMangrove","name":"mgv","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"base","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"AllAsks","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IMangrove","name":"mgv","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"base","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"quote","type":"address"}],"name":"AllBids","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IMangrove","name":"mangrove","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"indexed":true,"internalType":"contract IERC20","name":"inbound_tkn","type":"address"},{"indexed":true,"internalType":"uint256","name":"offerId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"makerData","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"mgvData","type":"bytes32"}],"name":"LogIncident","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"SetAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract AbstractRouter","name":"","type":"address"}],"name":"SetRouter","type":"event"},{"inputs":[],"name":"BASE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MGV","outputs":[{"internalType":"contract IMangrove","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NO_ROUTER","outputs":[{"internalType":"contract AbstractRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NSLOTS","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"OFFER_GASREQ","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"QUOTE","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"","type":"uint8"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"_indexOfOfferId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"_offerIdOfIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"activate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"baseDist","outputs":[{"internalType":"uint96[]","name":"","type":"uint96[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"baseOfIndex","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"checkList","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"}],"name":"dual","outputs":[{"internalType":"enum AbstractKandel.OrderType","name":"dualBa","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"dual","outputs":[{"internalType":"uint256","name":"dualIndex","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"internalType":"contract IERC20","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"gasreq","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"getMissingProvision","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"getOffer","outputs":[{"internalType":"OfferPacked","name":"","type":"uint256"},{"internalType":"OfferDetailPacked","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"}],"name":"getPending","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"indexOfOfferId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"isLive","outputs":[{"internalType":"bool","name":"live","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"},{"internalType":"OfferPacked","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"OfferDetailPacked","name":"offerDetail","type":"uint256"},{"internalType":"GlobalPacked","name":"global","type":"uint256"},{"internalType":"LocalPacked","name":"local","type":"uint256"}],"internalType":"struct MgvLib.SingleOrder","name":"order","type":"tuple"}],"name":"makerExecute","outputs":[{"internalType":"bytes32","name":"ret","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"outbound_tkn","type":"address"},{"internalType":"address","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"},{"internalType":"OfferPacked","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"OfferDetailPacked","name":"offerDetail","type":"uint256"},{"internalType":"GlobalPacked","name":"global","type":"uint256"},{"internalType":"LocalPacked","name":"local","type":"uint256"}],"internalType":"struct MgvLib.SingleOrder","name":"order","type":"tuple"},{"components":[{"internalType":"bytes32","name":"makerData","type":"bytes32"},{"internalType":"bytes32","name":"mgvData","type":"bytes32"}],"internalType":"struct MgvLib.OrderResult","name":"result","type":"tuple"}],"name":"makerPosthook","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"offerGasreq","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"offerIdOfIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingBase","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingQuote","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"},{"internalType":"uint256","name":"lastBidIndex","type":"uint256"},{"internalType":"uint256","name":"gasprice","type":"uint256"},{"internalType":"uint256[]","name":"pivotIds","type":"uint256[]"}],"name":"populate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"internalType":"contract IERC20","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"}],"name":"provisionOf","outputs":[{"internalType":"uint256","name":"provision","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"quoteDist","outputs":[{"internalType":"uint96[]","name":"","type":"uint96[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"quoteOfIndex","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"maker","type":"address"}],"name":"reserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"internalType":"contract IERC20","name":"inbound_tkn","type":"address"},{"internalType":"uint256","name":"offerId","type":"uint256"},{"internalType":"bool","name":"deprovision","type":"bool"}],"name":"retractOffer","outputs":[{"internalType":"uint256","name":"free_wei","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"bool","name":"deprovision","type":"bool"}],"name":"retractOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"retractOffers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"router","outputs":[{"internalType":"contract AbstractRouter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"admin_","type":"address"}],"name":"setAdmin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"},{"internalType":"uint256[][2]","name":"slice","type":"uint256[][2]"}],"name":"setDistribution","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"setPending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AbstractRouter","name":"router_","type":"address"}],"name":"setRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address payable","name":"receiver","type":"address"}],"name":"withdrawFromMangrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum AbstractKandel.OrderType","name":"ba","type":"uint8"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"withdrawFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b5060405162005701380380620057018339810160408190526200003591620007a7565b84848484848460008382813380620000945760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e000000000000000060448201526064015b60405180910390fd5b80620000aa6200030b60201b6200258d1760201c565b80546001600160a01b0319166001600160a01b03929092169190911790555062ffffff811681146200011f5760405162461bcd60e51b815260206004820152601760248201527f6d67764f666665722f6761737265714f766572666c6f7700000000000000000060448201526064016200008b565b6001600160a01b0391821660a052608052821615620001435762000143826200032f565b50505061ffff811660c08190526001600160a01b0380861660e0528416610100526001600160401b038111156200017e576200017e62000821565b604051908082528060200260200182016040528015620001a8578160200160208202803683370190505b508051620001bf9160019160209091019062000672565b5060c05161ffff166001600160401b03811115620001e157620001e162000821565b6040519080825280602002602001820160405280156200020b578160200160208202803683370190505b508051620002229160029160209091019062000672565b506200022e8462000403565b620002398362000403565b50505050508061ffff166001600160401b038111156200025d576200025d62000821565b60405190808252806020026020018201604052801562000287578160200160208202803683370190505b5080516200029e91600491602090910190620006c2565b508061ffff166001600160401b03811115620002be57620002be62000821565b604051908082528060200260200182016040528015620002e8578160200160208202803683370190505b508051620002ff91600591602090910190620006c2565b50505050505062000862565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b6200033962000611565b6001600160a01b0316336001600160a01b0316146200039b5760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f496e76616c6964000000000000000060448201526064016200008b565b80620003b16200063760201b620025b11760201c565b80546001600160a01b0319166001600160a01b0392831617905560405190821681527f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e54559060200160405180910390a150565b60006200040f6200065b565b60a05160405163095ea7b360e01b81526001600160a01b039182166004820152600019602482015291925083169063095ea7b3906044016020604051808303816000875af115801562000466573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906200048c919062000837565b620004da5760405162461bcd60e51b815260206004820152601d60248201527f6d67764f666665722f617070726f76654d616e67726f76652f4661696c00000060448201526064016200008b565b6001600160a01b038116156200060d5760405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015283169063095ea7b3906044016020604051808303816000875af11580156200053b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000561919062000837565b620005af5760405162461bcd60e51b815260206004820152601a60248201527f6d67764f666665722f617070726f7665526f757465724661696c00000000000060448201526064016200008b565b604051630716a76760e21b81526001600160a01b038381166004830152821690631c5a9d9c90602401600060405180830381600087803b158015620005f357600080fd5b505af115801562000608573d6000803e3d6000fd5b505050505b5050565b6000620006286200030b60201b6200258d1760201c565b546001600160a01b0316919050565b7fae7e31c3220e851db9f204a28b279dfe52b973600b0a456991089c220ae7222490565b6000620006286200063760201b620025b11760201c565b828054828255906000526020600020908101928215620006b0579160200282015b82811115620006b057825182559160200191906001019062000693565b50620006be92915062000777565b5090565b82805482825590600052602060002090600101600290048101928215620006b05791602002820160005b838211156200073857835183826101000a8154816001600160601b0302191690836001600160601b031602179055509260200192600c01602081600b01049283019260010302620006ec565b80156200076d5782816101000a8154906001600160601b030219169055600c01602081600b0104928301926001030262000738565b5050620006be9291505b5b80821115620006be576000815560010162000778565b6001600160a01b0381168114620007a457600080fd5b50565b600080600080600060a08688031215620007c057600080fd5b8551620007cd816200078e565b6020870151909550620007e0816200078e565b6040870151909450620007f3816200078e565b60608701516080880151919450925061ffff811681146200081357600080fd5b809150509295509295909350565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156200084a57600080fd5b815180151581146200085b57600080fd5b9392505050565b60805160a05160c05160e05161010051614d1f620009e260003960008181610582015281816117bb01528181611da901528181612791015281816127b7015281816138b40152613994015260008181610843015281816117e101528181611dcf01528181612770015281816127d801528181613725015281816138de01526139be01526000818161072c015261396401526000818161054e0152818161094901528181610ae501528181610b9301528181610cb101528181610e2a015281816110e7015281816111730152818161130301528181611394015281816118bd0152818161198001528181611afe01528181611b5301528181611bef01528181611f5c01528181612140015281816123060152818161237a01528181612ab101528181612d6c015281816131b3015281816133ca0152818161355b015281816136540152818161382401528181613908015281816139e801528181613f56015261401901526000818161062b0152818161209801526120c40152614d1f6000f3fe6080604052600436106102605760003560e01c8063a2e241af11610144578063d4a1da08116100b6578063e75179a41161007a578063e75179a4146107f1578063ea0f394d14610811578063ec342ad014610831578063f851a44014610865578063f887ea401461087a578063fe96911f1461088f57600080fd5b8063d4a1da081461071a578063d761914114610761578063df937eb814610791578063e1f21c67146107b1578063e4c34f84146107d157600080fd5b8063bfc353f911610108578063bfc353f91461064d578063c0d786551461066d578063c4738d041461068d578063cac2f29b146106ad578063cfcd2679146106e5578063d000cb60146106fa57600080fd5b8063a2e241af146105a4578063a8c0bdb7146105c4578063ad97db1b146105d9578063b36f8498146105f9578063b9021a4d1461061957600080fd5b80636c49c32c116101dd57806382d1983c116101a157806382d1983c1461049d5780638dbb84e0146104bd5780638de30bb5146104fc578063900bf07f1461051c57806399fa5e2d1461053c5780639c5798391461057057600080fd5b80636c49c32c146103e6578063704b6c02146104065780637144df24146104265780637692c328146104465780637a1168b11461047b57600080fd5b80634f234d45116102245780634f234d451461032c57806350302efb1461035957806351943ce5146103795780635293840d146103995780635570db1d146103b957600080fd5b806303eb17e21461026c57806314b715cb1461028e57806314d44d76146102d957806331d02d30146102ec5780633d3d130d1461030c57600080fd5b3661026757005b600080fd5b34801561027857600080fd5b5061028c610287366004614421565b6108af565b005b34801561029a57600080fd5b506102c66102a9366004614472565b600360209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b61028c6102e736600461449c565b610900565b3480156102f857600080fd5b506102c6610307366004614506565b610a94565b34801561031857600080fd5b5061028c610327366004614534565b610ae3565b34801561033857600080fd5b5061034c610347366004614506565b610c05565b6040516102d0919061458d565b34801561036557600080fd5b506102c6610374366004614472565b610c47565b34801561038557600080fd5b5061028c610394366004614472565b610c84565b3480156103a557600080fd5b5061028c6103b4366004614421565b610da2565b3480156103c557600080fd5b506103ce600081565b6040516001600160a01b0390911681526020016102d0565b3480156103f257600080fd5b506102c66104013660046145b5565b610e26565b34801561041257600080fd5b5061028c6104213660046145e7565b610fa7565b34801561043257600080fd5b5061028c610441366004614604565b611091565b34801561045257600080fd5b50610466610461366004614472565b6112ca565b604080519283526020830191909152016102d0565b34801561048757600080fd5b5061049061141d565b6040516102d09190614634565b3480156104a957600080fd5b5061028c6104b8366004614681565b6114e0565b3480156104c957600080fd5b506000546104e490600160801b90046001600160801b031681565b6040516001600160801b0390911681526020016102d0565b34801561050857600080fd5b506102c66105173660046146d8565b611789565b34801561052857600080fd5b5061028c610537366004614472565b61179e565b34801561054857600080fd5b506103ce7f000000000000000000000000000000000000000000000000000000000000000081565b34801561057c57600080fd5b506103ce7f000000000000000000000000000000000000000000000000000000000000000081565b3480156105b057600080fd5b5061028c6105bf366004614719565b611866565b3480156105d057600080fd5b50610490611a37565b3480156105e557600080fd5b506102c66105f4366004614749565b611acf565b34801561060557600080fd5b5061028c61061436600461479c565b611d54565b34801561062557600080fd5b506102c67f000000000000000000000000000000000000000000000000000000000000000081565b34801561065957600080fd5b506102c6610668366004614472565b611e55565b34801561067957600080fd5b5061028c6106883660046145e7565b611ea0565b34801561069957600080fd5b506102c66106a83660046147d1565b611f2d565b3480156106b957600080fd5b506106cd6106c8366004614806565b611fcf565b6040516001600160601b0390911681526020016102d0565b3480156106f157600080fd5b506102c6612014565b34801561070657600080fd5b506106cd610715366004614806565b6120e9565b34801561072657600080fd5b5061074e7f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff90911681526020016102d0565b34801561076d57600080fd5b5061078161077c366004614472565b6120fe565b60405190151581526020016102d0565b34801561079d57600080fd5b506000546104e4906001600160801b031681565b3480156107bd57600080fd5b506107816107cc3660046146d8565b61222b565b3480156107dd57600080fd5b506102c66107ec36600461481f565b6122d8565b3480156107fd57600080fd5b506103ce61080c3660046145e7565b6124dd565b34801561081d57600080fd5b506102c661082c366004614472565b6124e5565b34801561083d57600080fd5b506103ce7f000000000000000000000000000000000000000000000000000000000000000081565b34801561087157600080fd5b506103ce612536565b34801561088657600080fd5b506103ce61254f565b34801561089b57600080fd5b506102c66108aa366004614719565b612559565b60005b818110156108fb576108e98383838181106108cf576108cf614870565b90506020020160208101906108e491906145e7565b6125d5565b806108f38161489c565b9150506108b2565b505050565b610908612536565b6001600160a01b0316336001600160a01b0316146109415760405162461bcd60e51b8152600401610938906148b5565b60405180910390fd5b34156109bc577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663b60d4288346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109a257600080fd5b505af11580156109b6573d6000803e3d6000fd5b50505050505b855b85811015610a8b576109ce61437c565b6000868311156109df5760016109e2565b60005b90506109ed81612753565b6001600160a01b039081166020850152168252610a0a8184612801565b6060830152610a198184612842565b6040830152600060e08301819052610100830152610a35612014565b608083015260a082018690528484610a4d8b866148ec565b818110610a5c57610a5c614870565b602002919091013560c084015250610a7581848461286e565b5050508080610a839061489c565b9150506109be565b50505050505050565b60006001826001811115610aaa57610aaa614577565b14610ac757600054600160801b90046001600160801b0316610ad4565b6000546001600160801b03165b6001600160801b031692915050565b7f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610b2c5760405162461bcd60e51b8152600401610938906148b5565b81602001356f6d67762f74726164655375636365737360801b03610b5b57610b55838335612a0f565b50505050565b60408301803590610b6f90602086016145e7565b6001600160a01b0316610b8560208601866145e7565b604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528735602080840191909152880135928201929092529116907f84caca153d4896fd9d59ff942e5b76657222a696bf5b2acc0257867e05ef32819060600160405180910390a4610b558383612a57565b60006002826001811115610c1b57610c1b614577565b610c269060016148ff565b610c309190614928565b6001811115610c4157610c41614577565b92915050565b60006001836001811115610c5d57610c5d614577565b14610c7257610c6d8260016148ff565b610c7d565b610c7d6001836148ec565b9392505050565b610c8c612536565b6001600160a01b0316336001600160a01b03161480610cd35750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b610cef5760405162461bcd60e51b81526004016109389061493c565b80816001600160801b031614610d405760405162461bcd60e51b81526020600482015260166024820152754b616e64656c2f70656e64696e674f766572666c6f7760501b6044820152606401610938565b6001826001811115610d5457610d54614577565b03610d8357600080546001600160801b0383166fffffffffffffffffffffffffffffffff199091161790555050565b600080546001600160801b03808416600160801b0291161790555b5050565b610daa612536565b6001600160a01b0316336001600160a01b031614610dda5760405162461bcd60e51b8152600401610938906148b5565b60005b818110156108fb57610e14838383818110610dfa57610dfa614870565b9050602002016020810190610e0f91906145e7565b612a90565b80610e1e8161489c565b915050610ddd565b60007f0000000000000000000000000000000000000000000000000000000000000000336001600160a01b03821614610e715760405162461bcd60e51b8152600401610938906148b5565b610ea76040518060400160405280600f81526020016e696e206d616b65726578656375746560881b8152505a8560400135612cac565b6f1b59dd93d999995c8bdc1c9bd8d9595960821b9150610eee6040518060400160405280600f81526020016e706173736564206c6173746c6f6f6b60881b8152505a612cf3565b610f1a6040518060400160405280600a8152602001691c185cdcd959081c1d5d60b21b8152505a612cf3565b610f28836080013584612d38565b15610f755760405162461bcd60e51b815260206004820152601860248201527f6d67764f666665722f61626f72742f6765744661696c656400000000000000006044820152606401610938565b610fa16040518060400160405280600a8152602001691c185cdcd9590819d95d60b21b8152505a612cf3565b50919050565b610faf612536565b6001600160a01b0316336001600160a01b031614610fdf5760405162461bcd60e51b8152600401610938906148b5565b6001600160a01b0381166110355760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e00000000000000006044820152606401610938565b8061103e61258d565b80546001600160a01b0319166001600160a01b0392831617905560405190821681527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a1906020015b60405180910390a150565b611099612536565b6001600160a01b0316336001600160a01b0316146110c95760405162461bcd60e51b8152600401610938906148b5565b600019820361115d576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a919061496b565b91505b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024016020604051808303816000875af11580156111c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e89190614984565b61122c5760405162461bcd60e51b81526020600482015260156024820152741b59dd93d999995c8bddda5d1a191c985dd1985a5b605a1b6044820152606401610938565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114611279576040519150601f19603f3d011682016040523d82523d6000602084013e61127e565b606091505b50509050806108fb5760405162461bcd60e51b81526020600482015260186024820152771b59dd93d999995c8bddd95a551c985b9cd9995c91985a5b60421b6044820152606401610938565b6000806000806112d986612753565b9150915060006112e98787611e55565b6040516368c13d6b60e01b81529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906368c13d6b9061133c908690869086906004016149a1565b602060405180830381865afa158015611359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137d919061496b565b604051635722647b60e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690635722647b906113cd908790879087906004016149a1565b602060405180830381865afa1580156113ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140e919061496b565b945094505050505b9250929050565b6060611427612536565b6001600160a01b0316336001600160a01b0316146114575760405162461bcd60e51b8152600401610938906148b5565b60058054806020026020016040519081016040528092919081815260200182805480156114d557602002820191906000526020600020906000905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116114925790505b505050505090505b90565b6114e8612536565b6001600160a01b0316336001600160a01b0316146115185760405162461bcd60e51b8152600401610938906148b5565b825b82811015610b5557600061152e85836148ec565b905061153a83806149c5565b8281811061154a5761154a614870565b905060200201358360006002811061156457611564614870565b60200281019061157491906149c5565b8381811061158457611584614870565b905060200201356001600160601b0316146115d75760405162461bcd60e51b81526020600482015260136024820152724b616e64656c2f626173654f766572666c6f7760681b6044820152606401610938565b6115e460208401846149c5565b828181106115f4576115f4614870565b905060200201358360016002811061160e5761160e614870565b60200281019061161e91906149c5565b8381811061162e5761162e614870565b905060200201356001600160601b0316146116825760405162461bcd60e51b81526020600482015260146024820152734b616e64656c2f71756f74654f766572666c6f7760601b6044820152606401610938565b61168c83806149c5565b8281811061169c5761169c614870565b90506020020135600483815481106116b6576116b6614870565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055508260016002811061170257611702614870565b60200281019061171291906149c5565b8281811061172257611722614870565b905060200201356005838154811061173c5761173c614870565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055505080806117819061489c565b91505061151a565b6000611796848484612d67565b949350505050565b600060018360018111156117b4576117b4614577565b146117df577f0000000000000000000000000000000000000000000000000000000000000000611801565b7f00000000000000000000000000000000000000000000000000000000000000005b905061180f81333085612e2b565b80156118235750816118218284612f03565b145b6108fb5760405162461bcd60e51b815260206004820152601460248201527312d85b99195b0bd9195c1bdcda5d11985a5b195960621b6044820152606401610938565b61186e612536565b6001600160a01b0316336001600160a01b03161461189e5760405162461bcd60e51b8152600401610938906148b5565b6000825b82811015610b55576000806118b76001612753565b915091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad97db1b83836118f7600188611e55565b60016040518563ffffffff1660e01b81526004016119189493929190614a0f565b6020604051808303816000875af1158015611937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195b919061496b565b61196590856148ff565b93506119716000612753565b90925090506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663ad97db1b83836119b2600088611e55565b60016040518563ffffffff1660e01b81526004016119d39493929190614a0f565b6020604051808303816000875af11580156119f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a16919061496b565b611a2090856148ff565b935050508080611a2f9061489c565b9150506118a2565b6060611a41612536565b6001600160a01b0316336001600160a01b031614611a715760405162461bcd60e51b8152600401610938906148b5565b60048054806020026020016040519081016040528092919081815260200182805480156114d557600091825260209182902080546001600160601b031684529082028301929091600c91018084116114925790505050505050905090565b6000611ad9612536565b6001600160a01b0316336001600160a01b03161480611b205750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b611b3c5760405162461bcd60e51b81526004016109389061493c565b60405163ad97db1b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063ad97db1b90611b8e908890889088908890600401614a0f565b6020604051808303816000875af1158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd1919061496b565b9050801561179657604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024016020604051808303816000875af1158015611c40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c649190614984565b611ca65760405162461bcd60e51b8152602060048201526013602482015272111a5c9958dd0bddda5d1a191c985dd1985a5b606a1b6044820152606401610938565b6000611cb0612536565b6001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cfa576040519150601f19603f3d011682016040523d82523d6000602084013e611cff565b606091505b5050905080611d4b5760405162461bcd60e51b81526020600482015260186024820152771b59dd93d999995c8bddd95a551c985b9cd9995c91985a5b60421b6044820152606401610938565b50949350505050565b611d5c612536565b6001600160a01b0316336001600160a01b031614611d8c5760405162461bcd60e51b8152600401610938906148b5565b60006001846001811115611da257611da2614577565b14611dcd577f0000000000000000000000000000000000000000000000000000000000000000611def565b7f00000000000000000000000000000000000000000000000000000000000000005b905082611dfe82856001612fb3565b148015611e115750611e118183856130e9565b610b555760405162461bcd60e51b81526020600482015260156024820152744b616e64656c2f4e6f74456e6f75676846756e647360581b6044820152606401610938565b60006001836001811115611e6b57611e6b614577565b60028110611e7b57611e7b614870565b018281548110611e8d57611e8d614870565b9060005260206000200154905092915050565b611ea8612536565b6001600160a01b0316336001600160a01b031614611ed85760405162461bcd60e51b8152600401610938906148b5565b80611ee16125b1565b80546001600160a01b0319166001600160a01b0392831617905560405190821681527f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e545590602001611086565b6000611f37612536565b6001600160a01b0316336001600160a01b03161480611f7e5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b611f9a5760405162461bcd60e51b81526004016109389061493c565b600080611fa686612753565b915091506000611fb68787611e55565b9050611fc483838388611acf565b979650505050505050565b600060048281548110611fe457611fe4614870565b9060005260206000209060029182820401919006600c029054906101000a90046001600160601b03169050919050565b60008061201f61254f565b90506001600160a01b038116156120c257806001600160a01b0316633fd25eab6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561206e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612092919061496b565b6120bc907f00000000000000000000000000000000000000000000000000000000000000006148ff565b91505090565b7f000000000000000000000000000000000000000000000000000000000000000091505090565b600060058281548110611fe457611fe4614870565b600080600061210c85612753565b91509150600061211c8686611e55565b905060008111801561222157506040516368c13d6b60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063275074589082906368c13d6b90612181908890889088906004016149a1565b602060405180830381865afa15801561219e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c2919061496b565b6040518263ffffffff1660e01b81526004016121e091815260200190565b602060405180830381865afa1580156121fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122219190614984565b9695505050505050565b6000612235612536565b6001600160a01b0316336001600160a01b0316146122655760405162461bcd60e51b8152600401610938906148b5565b60405163095ea7b360e01b81526001600160a01b0384811660048301526024820184905285169063095ea7b3906044016020604051808303816000875af11580156122b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117969190614984565b6040516365fbae4d60e11b81526001600160a01b0386811660048301528581166024830152600091829182917f00000000000000000000000000000000000000000000000000000000000000009091169063cbf75c9a906044016040805180830381865afa15801561234e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123729190614a38565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635722647b8a8a886040518463ffffffff1660e01b81526004016123c8939291906149a1565b602060405180830381865afa1580156123e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612409919061496b565b9050600086604085901c61ffff16111561242c575061ffff604084901c1661242f565b50855b62ffffff881061244457612441612014565b97505b60008161245a62ffffff606087901c168b6148ff565b6124649190614a5c565b61247290633b9aca00614a5c565b9050600061ffff602085901c1661249962ffffff603087901c811690604888901c166148ff565b6124a39190614a5c565b6124b190633b9aca00614a5c565b9050818110156124ca576124c581836148ec565b6124cd565b60005b9c9b505050505050505050505050565b600030610c41565b6000600360008460018111156124fd576124fd614577565b600181111561250e5761250e614577565b8152602001908152602001600020600083815260200190815260200160002054905092915050565b600061254061258d565b546001600160a01b0316919050565b60006125406125b1565b6001826002811061256957600080fd5b01818154811061257857600080fd5b90600052602060002001600091509150505481565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7fae7e31c3220e851db9f204a28b279dfe52b973600b0a456991089c220ae7222490565b6125dd612536565b6001600160a01b0316336001600160a01b03161461263d5760405162461bcd60e51b815260206004820152601c60248201527f4469726563742f6f6e6c7941646d696e43616e4f776e4f6666657273000000006044820152606401610938565b600061264a61080c612536565b9050600061265661254f565b6001600160a01b031614801561267557506001600160a01b0381163014155b1561274a57604051636eb1769f60e11b81526001600160a01b0382811660048301523060248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156126ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ee919061496b565b1161274a5760405162461bcd60e51b815260206004820152602660248201527f4469726563742f726573657276654d757374417070726f76654d616b6572436f6044820152651b9d1c9858dd60d21b6064820152608401610938565b610d9e8261318c565b6000808083600181111561276957612769614577565b146127b5577f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006127f8565b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000005b91509150915091565b60008083600181111561281657612816614577565b146128295761282482611fcf565b612832565b612832826120e9565b6001600160601b03169392505050565b60008083600181111561285757612857614577565b1461286557612824826120e9565b61283282611fcf565b60008061287b8585611e55565b905061288f61288986610c05565b856120fe565b156128be576128a2858460600151610c84565b6f1c1bdc1d5b185d194bd8dc9bdcdcd95960821b915050610c7d565b801580156128d0575060008360600151115b156129ab576128de836133c6565b905080600003612903576e1b995dd3d999995c8bd1985a5b1959608a1b915050610c7d565b80600186600181111561291857612918614577565b6002811061292857612928614870565b01858154811061293a5761293a614870565b9060005260206000200181905550836003600087600181111561295f5761295f614577565b600181111561297057612970614577565b815260208082019290925260409081016000908120948152939091529091205550701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b610c7d565b806000036129bd576000915050610c7d565b82606001516000036129fd576129de83600001518460200151836000611acf565b50711c1bdc1d5b185d194bdc995d1c9858dd195960721b915050610c7d565b612a078382613528565b915050610c7d565b600080612a27612a2260208601866145e7565b613721565b9050612a3781610394868661376b565b6000806000612a46848861388d565b925092509250611fc483838361286e565b600080612a6a612a2260208601866145e7565b9050612a83816001600160601b03606087013516610c84565b5060009392505050565b50565b6000612a9a61254f565b60405163095ea7b360e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116600483015260001960248301529192509083169063095ea7b3906044016020604051808303816000875af1158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614984565b612b7e5760405162461bcd60e51b815260206004820152601d60248201527f6d67764f666665722f617070726f76654d616e67726f76652f4661696c0000006044820152606401610938565b6001600160a01b03811615610d9e5760405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015283169063095ea7b3906044016020604051808303816000875af1158015612bdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c019190614984565b612c4d5760405162461bcd60e51b815260206004820152601a60248201527f6d67764f666665722f617070726f7665526f757465724661696c0000000000006044820152606401610938565b604051630716a76760e21b81526001600160a01b038381166004830152821690631c5a9d9c90602401600060405180830381600087803b158015612c9057600080fd5b505af1158015612ca4573d6000803e3d6000fd5b505050505050565b6108fb838383604051602401612cc493929190614ac3565b60408051601f198184030181529190526020810180516001600160e01b031663969cdd0360e01b179052613cb3565b610d9e8282604051602401612d09929190614ae8565b60408051601f198184030181529190526020810180516001600160e01b03166309710a9d60e41b179052613cb3565b600080612d53612d4b60208501856145e7565b856000612fb3565b905083811015612a835761179681856148ec565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635722647b8686866040518463ffffffff1660e01b8152600401612dba939291906149a1565b602060405180830381865afa158015612dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dfb919061496b565b9050604881901c62ffffff16603082901c62ffffff1601602082901c61ffff1602633b9aca000295945050505050565b600081600003612e3d57506001611796565b826001600160a01b0316846001600160a01b031603612ecc576040516370a0823160e01b81526001600160a01b0385811660048301528391908716906370a0823190602401602060405180830381865afa158015612e9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec3919061496b565b10159050611796565b306001600160a01b03851603612eee57612ee7858484613cd4565b9050611796565b612efa85858585613d9e565b95945050505050565b600080612f0e61254f565b90506001600160a01b038116612f275782915050610c41565b806001600160a01b03166326e8eda285612f4261080c612536565b866040518463ffffffff1660e01b8152600401612f61939291906149a1565b6020604051808303816000875af1158015612f80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa4919061496b565b915050610c41565b5092915050565b600080612fbe61254f565b90506000612fcd61080c612536565b90506001600160a01b03821661306b576000612feb87833089612e2b565b90508061305f576040516370a0823160e01b81523060048201526001600160a01b038816906370a0823190602401602060405180830381865afa158015613036573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305a919061496b565b613061565b855b9350505050610c7d565b60405163333dbb0d60e01b81526001600160a01b0383169063333dbb0d9061309d90899085908a908a90600401614a0f565b6020604051808303816000875af11580156130bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e0919061496b565b92505050610c7d565b6000816000036130fb57506001610c7d565b306001600160a01b03841603613181576040516370a0823160e01b81526001600160a01b0384811660048301528391908616906370a0823190602401602060405180830381865afa158015613154573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613178919061496b565b10159050610c7d565b611796848484613cd4565b600061319661254f565b604051636eb1769f60e11b81523060048201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116602483015291925060009184169063dd62ed3e90604401602060405180830381865afa158015613208573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322c919061496b565b116132835760405162461bcd60e51b815260206004820152602160248201527f6d67764f666665722f4c6f6769634d757374417070726f76654d616e67726f766044820152606560f81b6064820152608401610938565b6001600160a01b03811615610d9e57604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156132e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613306919061496b565b116133535760405162461bcd60e51b815260206004820152601f60248201527f6d67764f666665722f4c6f6769634d757374417070726f7665526f75746572006044820152606401610938565b806001600160a01b031663a01dccd88361336c336124dd565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160006040518083038186803b1580156133b257600080fd5b505afa158015612ca4573d6000803e3d6000fd5b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349f6d2dc8360e00151846000015185602001518660400151876060015162ffffff80168960800151101561342b578860800151613433565b613433612014565b60a08a015160c08b01516040516001600160e01b031960e08b901b1681526001600160a01b03978816600482015296909516602487015260448601939093526064850191909152608484015260a483015260c482015260e40160206040518083038185885af1935050505080156134c7575060408051601f3d908101601f191682019092526134c49181019061496b565b60015b610c41576134d3614b0a565b806308c379a00361351757506134e7614b60565b806134f25750613519565b8261010001518190612a835760405162461bcd60e51b81526004016109389190614bea565b505b3d6000803e3d6000fd5b919050565b600062ffffff80168360800151106135e25782516020840151604051635722647b60e01b81526000926001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001692635722647b9261359292919088906004016149a1565b602060405180830381865afa1580156135af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135d3919061496b565b60481c62ffffff166080850152505b60e0830151835160208501516040808701516060880151608089015160a08a015160c08b01519451636a4f769160e01b81526001600160a01b039788166004820152958716602487015260448601939093526064850191909152608484015260a483015260c482015260e481018590527f000000000000000000000000000000000000000000000000000000000000000090911691636a4f769191610104016000604051808303818588803b15801561369a57600080fd5b505af1935050505080156136ac575060015b613706576136b8614b0a565b806308c379a00361351757506136cc614b60565b806136d75750613519565b83610100015181906136fc5760405162461bcd60e51b81526004016109389190614bea565b50612fa481614bfd565b50701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b610c41565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b031614613763576000610c41565b600192915050565b6000806137788484613e74565b9050806e1c1bdcdd1a1bdbdacbd99a5b1b1959608a1b14806137ad5750701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b81145b156137bc576000915050610c41565b807f6d67762f77726974654f666665722f64656e736974792f746f6f4c6f77000000036137ec57612fa484613f26565b6040840180359061380090602087016145e7565b6001600160a01b031661381660208701876145e7565b604080516001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081168252602082018990529181018690529116907f84caca153d4896fd9d59ff942e5b76657222a696bf5b2acc0257867e05ef32819060600160405180910390a4612fa484613f26565b60008061389861437c565b60006138a88686604001356124e5565b90508060000361395d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f2a0fe70ee27d259c6c232d71a08eeb8ab7dc475a38295a6e61f1a067a2eca01260405160405180910390a45b61398860017f0000000000000000000000000000000000000000000000000000000000000000614c21565b61ffff168103613a3d577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f087e90f7a19362124034af535f0d62fb8f3f318897be3126306cd99f8a2b478660405160405180910390a45b613a478682610c47565b9250613a5286610c05565b9350600080613a6186866112ca565b9150915060008760a00135613a7c846001600160601b031690565b613a8691906148ff565b90506000613a948888612801565b90506000613aa28989612842565b9050613ab460408b0160208c016145e7565b6001600160a01b03168752613acc60208b018b6145e7565b6001600160a01b031660208801526000613ae58b613f46565b613af0576000613af9565b613af98a610a94565b9050613b0581856148ff565b8310613bc75760018a6001811115613b1f57613b1f614577565b03613b6a57600080548291908190613b419084906001600160801b0316614c3c565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550613bb3565b80600060108282829054906101000a90046001600160801b0316613b8e9190614c3c565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b613bbd81856148ff565b6060890152613be7565b60608801839052613be78a84613bdd84886148ff565b61039491906148ec565b82886060015114613c0c5782613bfd8386614a5c565b613c079190614c5c565b613c0e565b815b6040890152600060e08901526001610100890152604885901c62ffffff1615613c4057604885901c62ffffff16613c48565b613c48612014565b6080890152602085901c61ffff1615613c6957602085901c61ffff16613c6c565b60005b60a089015260006001600160601b03871611613c925760c086901c63ffffffff16613c9c565b613c9c8a8a611e55565b8860c0018181525050505050505050509250925092565b80516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392839291881691613d329190614c70565b6000604051808303816000865af19150503d8060008114613d6f576040519150601f19603f3d011682016040523d82523d6000602084013e613d74565b606091505b50915091508180156122215750805115806122215750808060200190518101906122219190614984565b6000806000866001600160a01b03166323b872dd60e01b878787604051602401613dca939291906149a1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e089190614c70565b6000604051808303816000865af19150503d8060008114613e45576040519150601f19603f3d011682016040523d82523d6000602084013e613e4a565b606091505b5091509150818015611fc4575080511580611fc4575080806020019051810190611fc49190614984565b60408051600280825260608201835260009283929190602083019080368337019050509050613ea660208501856145e7565b81600081518110613eb957613eb9614870565b6001600160a01b03909216602092830291909101820152613ee090604086019086016145e7565b81600181518110613ef357613ef3614870565b60200260200101906001600160a01b031690816001600160a01b031681525050613f1c816140cf565b6117968484614271565b600060808201356001600160601b036060840135165b610c4191906148ec565b6000806140026001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166368c13d6b613f8860208701876145e7565b613f9860408801602089016145e7565b87604001356040518463ffffffff1660e01b8152600401613fbb939291906149a1565b602060405180830381865afa158015613fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ffc919061496b565b60e01c90565b9050801580610c7d57506140c76001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166368c13d6b61404b60208701876145e7565b61405b60408801602089016145e7565b856040518463ffffffff1660e01b815260040161407a939291906149a1565b602060405180830381865afa158015614097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140bb919061496b565b6001600160601b031690565b159392505050565b60006140d96125b1565b546001600160a01b0316905060006140f261080c612536565b90506001600160a01b0382166142155760005b8351811015610b55576141b784828151811061412357614123614870565b60200260200101518386848151811061413e5761413e614870565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561418e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b2919061496b565b6130e9565b6142035760405162461bcd60e51b815260206004820152601960248201527f4469726563742f666c7573682f7472616e736665724661696c000000000000006044820152606401610938565b8061420d8161489c565b915050614105565b604051633e142a0760e21b81526001600160a01b0383169063f850a81c906142439086908590600401614c8c565b600060405180830381600087803b15801561425d57600080fd5b505af1158015610a8b573d6000803e3d6000fd5b60008061427d84613f26565b9050600061428a8561435f565b9050811580614297575080155b156142b8576e1c1bdcdd1a1bdbdacbd99a5b1b1959608a1b92505050610c41565b604080516101208101909152612efa90806142d660208901896145e7565b6001600160a01b031681526020018760200160208101906142f791906145e7565b6001600160a01b03168152602081018490526040810185905260600160c088013560481c62ffffff16815260209081019060c0890135901c61ffff168152602001606088013560c01c63ffffffff168152600060208201526001604091820152870135613528565b600060a0820135606080840135901c6001600160601b0316613f3c565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b60008083601f8401126143ee57600080fd5b50813567ffffffffffffffff81111561440657600080fd5b6020830191508360208260051b850101111561141657600080fd5b6000806020838503121561443457600080fd5b823567ffffffffffffffff81111561444b57600080fd5b614457858286016143dc565b90969095509350505050565b80356002811061352357600080fd5b6000806040838503121561448557600080fd5b61448e83614463565b946020939093013593505050565b60008060008060008060a087890312156144b557600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156144e857600080fd5b6144f489828a016143dc565b979a9699509497509295939492505050565b60006020828403121561451857600080fd5b610c7d82614463565b60006101208284031215610fa157600080fd5b60008082840361016081121561454957600080fd5b6145538585614521565b9250604061011f198201121561456857600080fd5b50610120830190509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600283106145af57634e487b7160e01b600052602160045260246000fd5b91905290565b600061012082840312156145c857600080fd5b610c7d8383614521565b6001600160a01b0381168114612a8d57600080fd5b6000602082840312156145f957600080fd5b8135610c7d816145d2565b6000806040838503121561461757600080fd5b823591506020830135614629816145d2565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156146755783516001600160601b031683529284019291840191600101614650565b50909695505050505050565b60008060006060848603121561469657600080fd5b8335925060208401359150604084013567ffffffffffffffff8111156146bb57600080fd5b8401604081018610156146cd57600080fd5b809150509250925092565b6000806000606084860312156146ed57600080fd5b83356146f8816145d2565b92506020840135614708816145d2565b929592945050506040919091013590565b6000806040838503121561472c57600080fd5b50508035926020909101359150565b8015158114612a8d57600080fd5b6000806000806080858703121561475f57600080fd5b843561476a816145d2565b9350602085013561477a816145d2565b92506040850135915060608501356147918161473b565b939692955090935050565b6000806000606084860312156147b157600080fd5b6147ba84614463565b92506020840135915060408401356146cd816145d2565b6000806000606084860312156147e657600080fd5b6147ef84614463565b92506020840135915060408401356146cd8161473b565b60006020828403121561481857600080fd5b5035919050565b600080600080600060a0868803121561483757600080fd5b8535614842816145d2565b94506020860135614852816145d2565b94979496505050506040830135926060810135926080909101359150565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016148ae576148ae614886565b5060010190565b60208082526018908201527f416363657373436f6e74726f6c6c65642f496e76616c69640000000000000000604082015260600190565b81810381811115610c4157610c41614886565b80820180821115610c4157610c41614886565b634e487b7160e01b600052601260045260246000fd5b60008261493757614937614912565b500690565b6020808252601590820152741b59dd93d999995c8bdd5b985d5d1a1bdc9a5e9959605a1b604082015260600190565b60006020828403121561497d57600080fd5b5051919050565b60006020828403121561499657600080fd5b8151610c7d8161473b565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000808335601e198436030181126149dc57600080fd5b83018035915067ffffffffffffffff8211156149f757600080fd5b6020019150600581901b360382131561141657600080fd5b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b60008060408385031215614a4b57600080fd5b505080516020909101519092909150565b8082028115828204841417610c4157610c41614886565b60005b83811015614a8e578181015183820152602001614a76565b50506000910152565b60008151808452614aaf816020860160208601614a73565b601f01601f19169290920160200192915050565b606081526000614ad66060830186614a97565b60208301949094525060400152919050565b604081526000614afb6040830185614a97565b90508260208301529392505050565b600060033d11156114dd5760046000803e5060005160e01c90565b601f8201601f1916810167ffffffffffffffff81118282101715614b5957634e487b7160e01b600052604160045260246000fd5b6040525050565b600060443d1015614b6e5790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715614b9e57505050505090565b8285019150815181811115614bb65750505050505090565b843d8701016020828501011115614bd05750505050505090565b614bdf60208286010187614b25565b509095945050505050565b602081526000610c7d6020830184614a97565b80516020808301519190811015610fa15760001960209190910360031b1b16919050565b61ffff828116828216039080821115612fac57612fac614886565b6001600160801b03828116828216039080821115612fac57612fac614886565b600082614c6b57614c6b614912565b500490565b60008251614c82818460208701614a73565b9190910192915050565b604080825283519082018190526000906020906060840190828701845b82811015614cce5781516001600160a01b031684529284019290840190600101614ca9565b5050506001600160a01b03949094169201919091525091905056fea264697066735822122059d5bbaffa63c3cbdca8df922d93438968c6259438ec359062022dbeb33a63f764736f6c63430008110033000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd700000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca0000000000000000000000000000000000000000000000000000000000030d40000000000000000000000000000000000000000000000000000000000000012e

Deployed Bytecode

0x6080604052600436106102605760003560e01c8063a2e241af11610144578063d4a1da08116100b6578063e75179a41161007a578063e75179a4146107f1578063ea0f394d14610811578063ec342ad014610831578063f851a44014610865578063f887ea401461087a578063fe96911f1461088f57600080fd5b8063d4a1da081461071a578063d761914114610761578063df937eb814610791578063e1f21c67146107b1578063e4c34f84146107d157600080fd5b8063bfc353f911610108578063bfc353f91461064d578063c0d786551461066d578063c4738d041461068d578063cac2f29b146106ad578063cfcd2679146106e5578063d000cb60146106fa57600080fd5b8063a2e241af146105a4578063a8c0bdb7146105c4578063ad97db1b146105d9578063b36f8498146105f9578063b9021a4d1461061957600080fd5b80636c49c32c116101dd57806382d1983c116101a157806382d1983c1461049d5780638dbb84e0146104bd5780638de30bb5146104fc578063900bf07f1461051c57806399fa5e2d1461053c5780639c5798391461057057600080fd5b80636c49c32c146103e6578063704b6c02146104065780637144df24146104265780637692c328146104465780637a1168b11461047b57600080fd5b80634f234d45116102245780634f234d451461032c57806350302efb1461035957806351943ce5146103795780635293840d146103995780635570db1d146103b957600080fd5b806303eb17e21461026c57806314b715cb1461028e57806314d44d76146102d957806331d02d30146102ec5780633d3d130d1461030c57600080fd5b3661026757005b600080fd5b34801561027857600080fd5b5061028c610287366004614421565b6108af565b005b34801561029a57600080fd5b506102c66102a9366004614472565b600360209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b61028c6102e736600461449c565b610900565b3480156102f857600080fd5b506102c6610307366004614506565b610a94565b34801561031857600080fd5b5061028c610327366004614534565b610ae3565b34801561033857600080fd5b5061034c610347366004614506565b610c05565b6040516102d0919061458d565b34801561036557600080fd5b506102c6610374366004614472565b610c47565b34801561038557600080fd5b5061028c610394366004614472565b610c84565b3480156103a557600080fd5b5061028c6103b4366004614421565b610da2565b3480156103c557600080fd5b506103ce600081565b6040516001600160a01b0390911681526020016102d0565b3480156103f257600080fd5b506102c66104013660046145b5565b610e26565b34801561041257600080fd5b5061028c6104213660046145e7565b610fa7565b34801561043257600080fd5b5061028c610441366004614604565b611091565b34801561045257600080fd5b50610466610461366004614472565b6112ca565b604080519283526020830191909152016102d0565b34801561048757600080fd5b5061049061141d565b6040516102d09190614634565b3480156104a957600080fd5b5061028c6104b8366004614681565b6114e0565b3480156104c957600080fd5b506000546104e490600160801b90046001600160801b031681565b6040516001600160801b0390911681526020016102d0565b34801561050857600080fd5b506102c66105173660046146d8565b611789565b34801561052857600080fd5b5061028c610537366004614472565b61179e565b34801561054857600080fd5b506103ce7f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd781565b34801561057c57600080fd5b506103ce7f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca81565b3480156105b057600080fd5b5061028c6105bf366004614719565b611866565b3480156105d057600080fd5b50610490611a37565b3480156105e557600080fd5b506102c66105f4366004614749565b611acf565b34801561060557600080fd5b5061028c61061436600461479c565b611d54565b34801561062557600080fd5b506102c67f0000000000000000000000000000000000000000000000000000000000030d4081565b34801561065957600080fd5b506102c6610668366004614472565b611e55565b34801561067957600080fd5b5061028c6106883660046145e7565b611ea0565b34801561069957600080fd5b506102c66106a83660046147d1565b611f2d565b3480156106b957600080fd5b506106cd6106c8366004614806565b611fcf565b6040516001600160601b0390911681526020016102d0565b3480156106f157600080fd5b506102c6612014565b34801561070657600080fd5b506106cd610715366004614806565b6120e9565b34801561072657600080fd5b5061074e7f000000000000000000000000000000000000000000000000000000000000012e81565b60405161ffff90911681526020016102d0565b34801561076d57600080fd5b5061078161077c366004614472565b6120fe565b60405190151581526020016102d0565b34801561079d57600080fd5b506000546104e4906001600160801b031681565b3480156107bd57600080fd5b506107816107cc3660046146d8565b61222b565b3480156107dd57600080fd5b506102c66107ec36600461481f565b6122d8565b3480156107fd57600080fd5b506103ce61080c3660046145e7565b6124dd565b34801561081d57600080fd5b506102c661082c366004614472565b6124e5565b34801561083d57600080fd5b506103ce7f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e81565b34801561087157600080fd5b506103ce612536565b34801561088657600080fd5b506103ce61254f565b34801561089b57600080fd5b506102c66108aa366004614719565b612559565b60005b818110156108fb576108e98383838181106108cf576108cf614870565b90506020020160208101906108e491906145e7565b6125d5565b806108f38161489c565b9150506108b2565b505050565b610908612536565b6001600160a01b0316336001600160a01b0316146109415760405162461bcd60e51b8152600401610938906148b5565b60405180910390fd5b34156109bc577f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b031663b60d4288346040518263ffffffff1660e01b81526004016000604051808303818588803b1580156109a257600080fd5b505af11580156109b6573d6000803e3d6000fd5b50505050505b855b85811015610a8b576109ce61437c565b6000868311156109df5760016109e2565b60005b90506109ed81612753565b6001600160a01b039081166020850152168252610a0a8184612801565b6060830152610a198184612842565b6040830152600060e08301819052610100830152610a35612014565b608083015260a082018690528484610a4d8b866148ec565b818110610a5c57610a5c614870565b602002919091013560c084015250610a7581848461286e565b5050508080610a839061489c565b9150506109be565b50505050505050565b60006001826001811115610aaa57610aaa614577565b14610ac757600054600160801b90046001600160801b0316610ad4565b6000546001600160801b03165b6001600160801b031692915050565b7f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7336001600160a01b03821614610b2c5760405162461bcd60e51b8152600401610938906148b5565b81602001356f6d67762f74726164655375636365737360801b03610b5b57610b55838335612a0f565b50505050565b60408301803590610b6f90602086016145e7565b6001600160a01b0316610b8560208601866145e7565b604080516001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7811682528735602080840191909152880135928201929092529116907f84caca153d4896fd9d59ff942e5b76657222a696bf5b2acc0257867e05ef32819060600160405180910390a4610b558383612a57565b60006002826001811115610c1b57610c1b614577565b610c269060016148ff565b610c309190614928565b6001811115610c4157610c41614577565b92915050565b60006001836001811115610c5d57610c5d614577565b14610c7257610c6d8260016148ff565b610c7d565b610c7d6001836148ec565b9392505050565b610c8c612536565b6001600160a01b0316336001600160a01b03161480610cd35750336001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd716145b610cef5760405162461bcd60e51b81526004016109389061493c565b80816001600160801b031614610d405760405162461bcd60e51b81526020600482015260166024820152754b616e64656c2f70656e64696e674f766572666c6f7760501b6044820152606401610938565b6001826001811115610d5457610d54614577565b03610d8357600080546001600160801b0383166fffffffffffffffffffffffffffffffff199091161790555050565b600080546001600160801b03808416600160801b0291161790555b5050565b610daa612536565b6001600160a01b0316336001600160a01b031614610dda5760405162461bcd60e51b8152600401610938906148b5565b60005b818110156108fb57610e14838383818110610dfa57610dfa614870565b9050602002016020810190610e0f91906145e7565b612a90565b80610e1e8161489c565b915050610ddd565b60007f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7336001600160a01b03821614610e715760405162461bcd60e51b8152600401610938906148b5565b610ea76040518060400160405280600f81526020016e696e206d616b65726578656375746560881b8152505a8560400135612cac565b6f1b59dd93d999995c8bdc1c9bd8d9595960821b9150610eee6040518060400160405280600f81526020016e706173736564206c6173746c6f6f6b60881b8152505a612cf3565b610f1a6040518060400160405280600a8152602001691c185cdcd959081c1d5d60b21b8152505a612cf3565b610f28836080013584612d38565b15610f755760405162461bcd60e51b815260206004820152601860248201527f6d67764f666665722f61626f72742f6765744661696c656400000000000000006044820152606401610938565b610fa16040518060400160405280600a8152602001691c185cdcd9590819d95d60b21b8152505a612cf3565b50919050565b610faf612536565b6001600160a01b0316336001600160a01b031614610fdf5760405162461bcd60e51b8152600401610938906148b5565b6001600160a01b0381166110355760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e00000000000000006044820152606401610938565b8061103e61258d565b80546001600160a01b0319166001600160a01b0392831617905560405190821681527f5a272403b402d892977df56625f4164ccaf70ca3863991c43ecfe76a6905b0a1906020015b60405180910390a150565b611099612536565b6001600160a01b0316336001600160a01b0316146110c95760405162461bcd60e51b8152600401610938906148b5565b600019820361115d576040516370a0823160e01b81523060048201527f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b0316906370a0823190602401602060405180830381865afa158015611136573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061115a919061496b565b91505b604051632e1a7d4d60e01b8152600481018390527f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b031690632e1a7d4d906024016020604051808303816000875af11580156111c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111e89190614984565b61122c5760405162461bcd60e51b81526020600482015260156024820152741b59dd93d999995c8bddda5d1a191c985dd1985a5b605a1b6044820152606401610938565b6000816001600160a01b03168360405160006040518083038185875af1925050503d8060008114611279576040519150601f19603f3d011682016040523d82523d6000602084013e61127e565b606091505b50509050806108fb5760405162461bcd60e51b81526020600482015260186024820152771b59dd93d999995c8bddd95a551c985b9cd9995c91985a5b60421b6044820152606401610938565b6000806000806112d986612753565b9150915060006112e98787611e55565b6040516368c13d6b60e01b81529091506001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd716906368c13d6b9061133c908690869086906004016149a1565b602060405180830381865afa158015611359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061137d919061496b565b604051635722647b60e01b81526001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd71690635722647b906113cd908790879087906004016149a1565b602060405180830381865afa1580156113ea573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061140e919061496b565b945094505050505b9250929050565b6060611427612536565b6001600160a01b0316336001600160a01b0316146114575760405162461bcd60e51b8152600401610938906148b5565b60058054806020026020016040519081016040528092919081815260200182805480156114d557602002820191906000526020600020906000905b82829054906101000a90046001600160601b03166001600160601b0316815260200190600c0190602082600b010492830192600103820291508084116114925790505b505050505090505b90565b6114e8612536565b6001600160a01b0316336001600160a01b0316146115185760405162461bcd60e51b8152600401610938906148b5565b825b82811015610b5557600061152e85836148ec565b905061153a83806149c5565b8281811061154a5761154a614870565b905060200201358360006002811061156457611564614870565b60200281019061157491906149c5565b8381811061158457611584614870565b905060200201356001600160601b0316146115d75760405162461bcd60e51b81526020600482015260136024820152724b616e64656c2f626173654f766572666c6f7760681b6044820152606401610938565b6115e460208401846149c5565b828181106115f4576115f4614870565b905060200201358360016002811061160e5761160e614870565b60200281019061161e91906149c5565b8381811061162e5761162e614870565b905060200201356001600160601b0316146116825760405162461bcd60e51b81526020600482015260146024820152734b616e64656c2f71756f74654f766572666c6f7760601b6044820152606401610938565b61168c83806149c5565b8281811061169c5761169c614870565b90506020020135600483815481106116b6576116b6614870565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055508260016002811061170257611702614870565b60200281019061171291906149c5565b8281811061172257611722614870565b905060200201356005838154811061173c5761173c614870565b9060005260206000209060029182820401919006600c026101000a8154816001600160601b0302191690836001600160601b031602179055505080806117819061489c565b91505061151a565b6000611796848484612d67565b949350505050565b600060018360018111156117b4576117b4614577565b146117df577f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca611801565b7f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e5b905061180f81333085612e2b565b80156118235750816118218284612f03565b145b6108fb5760405162461bcd60e51b815260206004820152601460248201527312d85b99195b0bd9195c1bdcda5d11985a5b195960621b6044820152606401610938565b61186e612536565b6001600160a01b0316336001600160a01b03161461189e5760405162461bcd60e51b8152600401610938906148b5565b6000825b82811015610b55576000806118b76001612753565b915091507f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b031663ad97db1b83836118f7600188611e55565b60016040518563ffffffff1660e01b81526004016119189493929190614a0f565b6020604051808303816000875af1158015611937573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061195b919061496b565b61196590856148ff565b93506119716000612753565b90925090506001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd71663ad97db1b83836119b2600088611e55565b60016040518563ffffffff1660e01b81526004016119d39493929190614a0f565b6020604051808303816000875af11580156119f2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a16919061496b565b611a2090856148ff565b935050508080611a2f9061489c565b9150506118a2565b6060611a41612536565b6001600160a01b0316336001600160a01b031614611a715760405162461bcd60e51b8152600401610938906148b5565b60048054806020026020016040519081016040528092919081815260200182805480156114d557600091825260209182902080546001600160601b031684529082028301929091600c91018084116114925790505050505050905090565b6000611ad9612536565b6001600160a01b0316336001600160a01b03161480611b205750336001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd716145b611b3c5760405162461bcd60e51b81526004016109389061493c565b60405163ad97db1b60e01b81526001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7169063ad97db1b90611b8e908890889088908890600401614a0f565b6020604051808303816000875af1158015611bad573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bd1919061496b565b9050801561179657604051632e1a7d4d60e01b8152600481018290527f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b031690632e1a7d4d906024016020604051808303816000875af1158015611c40573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c649190614984565b611ca65760405162461bcd60e51b8152602060048201526013602482015272111a5c9958dd0bddda5d1a191c985dd1985a5b606a1b6044820152606401610938565b6000611cb0612536565b6001600160a01b03168260405160006040518083038185875af1925050503d8060008114611cfa576040519150601f19603f3d011682016040523d82523d6000602084013e611cff565b606091505b5050905080611d4b5760405162461bcd60e51b81526020600482015260186024820152771b59dd93d999995c8bddd95a551c985b9cd9995c91985a5b60421b6044820152606401610938565b50949350505050565b611d5c612536565b6001600160a01b0316336001600160a01b031614611d8c5760405162461bcd60e51b8152600401610938906148b5565b60006001846001811115611da257611da2614577565b14611dcd577f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca611def565b7f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e5b905082611dfe82856001612fb3565b148015611e115750611e118183856130e9565b610b555760405162461bcd60e51b81526020600482015260156024820152744b616e64656c2f4e6f74456e6f75676846756e647360581b6044820152606401610938565b60006001836001811115611e6b57611e6b614577565b60028110611e7b57611e7b614870565b018281548110611e8d57611e8d614870565b9060005260206000200154905092915050565b611ea8612536565b6001600160a01b0316336001600160a01b031614611ed85760405162461bcd60e51b8152600401610938906148b5565b80611ee16125b1565b80546001600160a01b0319166001600160a01b0392831617905560405190821681527f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e545590602001611086565b6000611f37612536565b6001600160a01b0316336001600160a01b03161480611f7e5750336001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd716145b611f9a5760405162461bcd60e51b81526004016109389061493c565b600080611fa686612753565b915091506000611fb68787611e55565b9050611fc483838388611acf565b979650505050505050565b600060048281548110611fe457611fe4614870565b9060005260206000209060029182820401919006600c029054906101000a90046001600160601b03169050919050565b60008061201f61254f565b90506001600160a01b038116156120c257806001600160a01b0316633fd25eab6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561206e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612092919061496b565b6120bc907f0000000000000000000000000000000000000000000000000000000000030d406148ff565b91505090565b7f0000000000000000000000000000000000000000000000000000000000030d4091505090565b600060058281548110611fe457611fe4614870565b600080600061210c85612753565b91509150600061211c8686611e55565b905060008111801561222157506040516368c13d6b60e01b81526001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7169063275074589082906368c13d6b90612181908890889088906004016149a1565b602060405180830381865afa15801561219e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c2919061496b565b6040518263ffffffff1660e01b81526004016121e091815260200190565b602060405180830381865afa1580156121fd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122219190614984565b9695505050505050565b6000612235612536565b6001600160a01b0316336001600160a01b0316146122655760405162461bcd60e51b8152600401610938906148b5565b60405163095ea7b360e01b81526001600160a01b0384811660048301526024820184905285169063095ea7b3906044016020604051808303816000875af11580156122b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117969190614984565b6040516365fbae4d60e11b81526001600160a01b0386811660048301528581166024830152600091829182917f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd79091169063cbf75c9a906044016040805180830381865afa15801561234e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123729190614a38565b9150915060007f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b0316635722647b8a8a886040518463ffffffff1660e01b81526004016123c8939291906149a1565b602060405180830381865afa1580156123e5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612409919061496b565b9050600086604085901c61ffff16111561242c575061ffff604084901c1661242f565b50855b62ffffff881061244457612441612014565b97505b60008161245a62ffffff606087901c168b6148ff565b6124649190614a5c565b61247290633b9aca00614a5c565b9050600061ffff602085901c1661249962ffffff603087901c811690604888901c166148ff565b6124a39190614a5c565b6124b190633b9aca00614a5c565b9050818110156124ca576124c581836148ec565b6124cd565b60005b9c9b505050505050505050505050565b600030610c41565b6000600360008460018111156124fd576124fd614577565b600181111561250e5761250e614577565b8152602001908152602001600020600083815260200190815260200160002054905092915050565b600061254061258d565b546001600160a01b0316919050565b60006125406125b1565b6001826002811061256957600080fd5b01818154811061257857600080fd5b90600052602060002001600091509150505481565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7fae7e31c3220e851db9f204a28b279dfe52b973600b0a456991089c220ae7222490565b6125dd612536565b6001600160a01b0316336001600160a01b03161461263d5760405162461bcd60e51b815260206004820152601c60248201527f4469726563742f6f6e6c7941646d696e43616e4f776e4f6666657273000000006044820152606401610938565b600061264a61080c612536565b9050600061265661254f565b6001600160a01b031614801561267557506001600160a01b0381163014155b1561274a57604051636eb1769f60e11b81526001600160a01b0382811660048301523060248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156126ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ee919061496b565b1161274a5760405162461bcd60e51b815260206004820152602660248201527f4469726563742f726573657276654d757374417070726f76654d616b6572436f6044820152651b9d1c9858dd60d21b6064820152608401610938565b610d9e8261318c565b6000808083600181111561276957612769614577565b146127b5577f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e7f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca6127f8565b7f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca7f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e5b91509150915091565b60008083600181111561281657612816614577565b146128295761282482611fcf565b612832565b612832826120e9565b6001600160601b03169392505050565b60008083600181111561285757612857614577565b1461286557612824826120e9565b61283282611fcf565b60008061287b8585611e55565b905061288f61288986610c05565b856120fe565b156128be576128a2858460600151610c84565b6f1c1bdc1d5b185d194bd8dc9bdcdcd95960821b915050610c7d565b801580156128d0575060008360600151115b156129ab576128de836133c6565b905080600003612903576e1b995dd3d999995c8bd1985a5b1959608a1b915050610c7d565b80600186600181111561291857612918614577565b6002811061292857612928614870565b01858154811061293a5761293a614870565b9060005260206000200181905550836003600087600181111561295f5761295f614577565b600181111561297057612970614577565b815260208082019290925260409081016000908120948152939091529091205550701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b610c7d565b806000036129bd576000915050610c7d565b82606001516000036129fd576129de83600001518460200151836000611acf565b50711c1bdc1d5b185d194bdc995d1c9858dd195960721b915050610c7d565b612a078382613528565b915050610c7d565b600080612a27612a2260208601866145e7565b613721565b9050612a3781610394868661376b565b6000806000612a46848861388d565b925092509250611fc483838361286e565b600080612a6a612a2260208601866145e7565b9050612a83816001600160601b03606087013516610c84565b5060009392505050565b50565b6000612a9a61254f565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd78116600483015260001960248301529192509083169063095ea7b3906044016020604051808303816000875af1158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614984565b612b7e5760405162461bcd60e51b815260206004820152601d60248201527f6d67764f666665722f617070726f76654d616e67726f76652f4661696c0000006044820152606401610938565b6001600160a01b03811615610d9e5760405163095ea7b360e01b81526001600160a01b038281166004830152600019602483015283169063095ea7b3906044016020604051808303816000875af1158015612bdd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c019190614984565b612c4d5760405162461bcd60e51b815260206004820152601a60248201527f6d67764f666665722f617070726f7665526f757465724661696c0000000000006044820152606401610938565b604051630716a76760e21b81526001600160a01b038381166004830152821690631c5a9d9c90602401600060405180830381600087803b158015612c9057600080fd5b505af1158015612ca4573d6000803e3d6000fd5b505050505050565b6108fb838383604051602401612cc493929190614ac3565b60408051601f198184030181529190526020810180516001600160e01b031663969cdd0360e01b179052613cb3565b610d9e8282604051602401612d09929190614ae8565b60408051601f198184030181529190526020810180516001600160e01b03166309710a9d60e41b179052613cb3565b600080612d53612d4b60208501856145e7565b856000612fb3565b905083811015612a835761179681856148ec565b6000807f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b0316635722647b8686866040518463ffffffff1660e01b8152600401612dba939291906149a1565b602060405180830381865afa158015612dd7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612dfb919061496b565b9050604881901c62ffffff16603082901c62ffffff1601602082901c61ffff1602633b9aca000295945050505050565b600081600003612e3d57506001611796565b826001600160a01b0316846001600160a01b031603612ecc576040516370a0823160e01b81526001600160a01b0385811660048301528391908716906370a0823190602401602060405180830381865afa158015612e9f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612ec3919061496b565b10159050611796565b306001600160a01b03851603612eee57612ee7858484613cd4565b9050611796565b612efa85858585613d9e565b95945050505050565b600080612f0e61254f565b90506001600160a01b038116612f275782915050610c41565b806001600160a01b03166326e8eda285612f4261080c612536565b866040518463ffffffff1660e01b8152600401612f61939291906149a1565b6020604051808303816000875af1158015612f80573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612fa4919061496b565b915050610c41565b5092915050565b600080612fbe61254f565b90506000612fcd61080c612536565b90506001600160a01b03821661306b576000612feb87833089612e2b565b90508061305f576040516370a0823160e01b81523060048201526001600160a01b038816906370a0823190602401602060405180830381865afa158015613036573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061305a919061496b565b613061565b855b9350505050610c7d565b60405163333dbb0d60e01b81526001600160a01b0383169063333dbb0d9061309d90899085908a908a90600401614a0f565b6020604051808303816000875af11580156130bc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130e0919061496b565b92505050610c7d565b6000816000036130fb57506001610c7d565b306001600160a01b03841603613181576040516370a0823160e01b81526001600160a01b0384811660048301528391908616906370a0823190602401602060405180830381865afa158015613154573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613178919061496b565b10159050610c7d565b611796848484613cd4565b600061319661254f565b604051636eb1769f60e11b81523060048201526001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd78116602483015291925060009184169063dd62ed3e90604401602060405180830381865afa158015613208573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061322c919061496b565b116132835760405162461bcd60e51b815260206004820152602160248201527f6d67764f666665722f4c6f6769634d757374417070726f76654d616e67726f766044820152606560f81b6064820152608401610938565b6001600160a01b03811615610d9e57604051636eb1769f60e11b81523060048201526001600160a01b0382811660248301526000919084169063dd62ed3e90604401602060405180830381865afa1580156132e2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613306919061496b565b116133535760405162461bcd60e51b815260206004820152601f60248201527f6d67764f666665722f4c6f6769634d757374417070726f7665526f75746572006044820152606401610938565b806001600160a01b031663a01dccd88361336c336124dd565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160006040518083038186803b1580156133b257600080fd5b505afa158015612ca4573d6000803e3d6000fd5b60007f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b03166349f6d2dc8360e00151846000015185602001518660400151876060015162ffffff80168960800151101561342b578860800151613433565b613433612014565b60a08a015160c08b01516040516001600160e01b031960e08b901b1681526001600160a01b03978816600482015296909516602487015260448601939093526064850191909152608484015260a483015260c482015260e40160206040518083038185885af1935050505080156134c7575060408051601f3d908101601f191682019092526134c49181019061496b565b60015b610c41576134d3614b0a565b806308c379a00361351757506134e7614b60565b806134f25750613519565b8261010001518190612a835760405162461bcd60e51b81526004016109389190614bea565b505b3d6000803e3d6000fd5b919050565b600062ffffff80168360800151106135e25782516020840151604051635722647b60e01b81526000926001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd71692635722647b9261359292919088906004016149a1565b602060405180830381865afa1580156135af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135d3919061496b565b60481c62ffffff166080850152505b60e0830151835160208501516040808701516060880151608089015160a08a015160c08b01519451636a4f769160e01b81526001600160a01b039788166004820152958716602487015260448601939093526064850191909152608484015260a483015260c482015260e481018590527f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd790911691636a4f769191610104016000604051808303818588803b15801561369a57600080fd5b505af1935050505080156136ac575060015b613706576136b8614b0a565b806308c379a00361351757506136cc614b60565b806136d75750613519565b83610100015181906136fc5760405162461bcd60e51b81526004016109389190614bea565b50612fa481614bfd565b50701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b610c41565b60007f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e6001600160a01b0316826001600160a01b031614613763576000610c41565b600192915050565b6000806137788484613e74565b9050806e1c1bdcdd1a1bdbdacbd99a5b1b1959608a1b14806137ad5750701c1bdcdd1a1bdbdacbdc995c1bdcdd1959607a1b81145b156137bc576000915050610c41565b807f6d67762f77726974654f666665722f64656e736974792f746f6f4c6f77000000036137ec57612fa484613f26565b6040840180359061380090602087016145e7565b6001600160a01b031661381660208701876145e7565b604080516001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd781168252602082018990529181018690529116907f84caca153d4896fd9d59ff942e5b76657222a696bf5b2acc0257867e05ef32819060600160405180910390a4612fa484613f26565b60008061389861437c565b60006138a88686604001356124e5565b90508060000361395d577f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca6001600160a01b03167f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e6001600160a01b03167f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b03167f2a0fe70ee27d259c6c232d71a08eeb8ab7dc475a38295a6e61f1a067a2eca01260405160405180910390a45b61398860017f000000000000000000000000000000000000000000000000000000000000012e614c21565b61ffff168103613a3d577f000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca6001600160a01b03167f00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e6001600160a01b03167f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd76001600160a01b03167f087e90f7a19362124034af535f0d62fb8f3f318897be3126306cd99f8a2b478660405160405180910390a45b613a478682610c47565b9250613a5286610c05565b9350600080613a6186866112ca565b9150915060008760a00135613a7c846001600160601b031690565b613a8691906148ff565b90506000613a948888612801565b90506000613aa28989612842565b9050613ab460408b0160208c016145e7565b6001600160a01b03168752613acc60208b018b6145e7565b6001600160a01b031660208801526000613ae58b613f46565b613af0576000613af9565b613af98a610a94565b9050613b0581856148ff565b8310613bc75760018a6001811115613b1f57613b1f614577565b03613b6a57600080548291908190613b419084906001600160801b0316614c3c565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550613bb3565b80600060108282829054906101000a90046001600160801b0316613b8e9190614c3c565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b613bbd81856148ff565b6060890152613be7565b60608801839052613be78a84613bdd84886148ff565b61039491906148ec565b82886060015114613c0c5782613bfd8386614a5c565b613c079190614c5c565b613c0e565b815b6040890152600060e08901526001610100890152604885901c62ffffff1615613c4057604885901c62ffffff16613c48565b613c48612014565b6080890152602085901c61ffff1615613c6957602085901c61ffff16613c6c565b60005b60a089015260006001600160601b03871611613c925760c086901c63ffffffff16613c9c565b613c9c8a8a611e55565b8860c0018181525050505050505050509250925092565b80516a636f6e736f6c652e6c6f67602083016000808483855afa5050505050565b604080516001600160a01b038481166024830152604480830185905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b17905291516000928392839291881691613d329190614c70565b6000604051808303816000865af19150503d8060008114613d6f576040519150601f19603f3d011682016040523d82523d6000602084013e613d74565b606091505b50915091508180156122215750805115806122215750808060200190518101906122219190614984565b6000806000866001600160a01b03166323b872dd60e01b878787604051602401613dca939291906149a1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051613e089190614c70565b6000604051808303816000865af19150503d8060008114613e45576040519150601f19603f3d011682016040523d82523d6000602084013e613e4a565b606091505b5091509150818015611fc4575080511580611fc4575080806020019051810190611fc49190614984565b60408051600280825260608201835260009283929190602083019080368337019050509050613ea660208501856145e7565b81600081518110613eb957613eb9614870565b6001600160a01b03909216602092830291909101820152613ee090604086019086016145e7565b81600181518110613ef357613ef3614870565b60200260200101906001600160a01b031690816001600160a01b031681525050613f1c816140cf565b6117968484614271565b600060808201356001600160601b036060840135165b610c4191906148ec565b6000806140026001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7166368c13d6b613f8860208701876145e7565b613f9860408801602089016145e7565b87604001356040518463ffffffff1660e01b8152600401613fbb939291906149a1565b602060405180830381865afa158015613fd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ffc919061496b565b60e01c90565b9050801580610c7d57506140c76001600160a01b037f000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7166368c13d6b61404b60208701876145e7565b61405b60408801602089016145e7565b856040518463ffffffff1660e01b815260040161407a939291906149a1565b602060405180830381865afa158015614097573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906140bb919061496b565b6001600160601b031690565b159392505050565b60006140d96125b1565b546001600160a01b0316905060006140f261080c612536565b90506001600160a01b0382166142155760005b8351811015610b55576141b784828151811061412357614123614870565b60200260200101518386848151811061413e5761413e614870565b60209081029190910101516040516370a0823160e01b81523060048201526001600160a01b03909116906370a0823190602401602060405180830381865afa15801561418e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906141b2919061496b565b6130e9565b6142035760405162461bcd60e51b815260206004820152601960248201527f4469726563742f666c7573682f7472616e736665724661696c000000000000006044820152606401610938565b8061420d8161489c565b915050614105565b604051633e142a0760e21b81526001600160a01b0383169063f850a81c906142439086908590600401614c8c565b600060405180830381600087803b15801561425d57600080fd5b505af1158015610a8b573d6000803e3d6000fd5b60008061427d84613f26565b9050600061428a8561435f565b9050811580614297575080155b156142b8576e1c1bdcdd1a1bdbdacbd99a5b1b1959608a1b92505050610c41565b604080516101208101909152612efa90806142d660208901896145e7565b6001600160a01b031681526020018760200160208101906142f791906145e7565b6001600160a01b03168152602081018490526040810185905260600160c088013560481c62ffffff16815260209081019060c0890135901c61ffff168152602001606088013560c01c63ffffffff168152600060208201526001604091820152870135613528565b600060a0820135606080840135901c6001600160601b0316613f3c565b60405180610120016040528060006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001600081526020016000815260200160008152602001600081526020016000151581525090565b60008083601f8401126143ee57600080fd5b50813567ffffffffffffffff81111561440657600080fd5b6020830191508360208260051b850101111561141657600080fd5b6000806020838503121561443457600080fd5b823567ffffffffffffffff81111561444b57600080fd5b614457858286016143dc565b90969095509350505050565b80356002811061352357600080fd5b6000806040838503121561448557600080fd5b61448e83614463565b946020939093013593505050565b60008060008060008060a087890312156144b557600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff8111156144e857600080fd5b6144f489828a016143dc565b979a9699509497509295939492505050565b60006020828403121561451857600080fd5b610c7d82614463565b60006101208284031215610fa157600080fd5b60008082840361016081121561454957600080fd5b6145538585614521565b9250604061011f198201121561456857600080fd5b50610120830190509250929050565b634e487b7160e01b600052602160045260246000fd5b60208101600283106145af57634e487b7160e01b600052602160045260246000fd5b91905290565b600061012082840312156145c857600080fd5b610c7d8383614521565b6001600160a01b0381168114612a8d57600080fd5b6000602082840312156145f957600080fd5b8135610c7d816145d2565b6000806040838503121561461757600080fd5b823591506020830135614629816145d2565b809150509250929050565b6020808252825182820181905260009190848201906040850190845b818110156146755783516001600160601b031683529284019291840191600101614650565b50909695505050505050565b60008060006060848603121561469657600080fd5b8335925060208401359150604084013567ffffffffffffffff8111156146bb57600080fd5b8401604081018610156146cd57600080fd5b809150509250925092565b6000806000606084860312156146ed57600080fd5b83356146f8816145d2565b92506020840135614708816145d2565b929592945050506040919091013590565b6000806040838503121561472c57600080fd5b50508035926020909101359150565b8015158114612a8d57600080fd5b6000806000806080858703121561475f57600080fd5b843561476a816145d2565b9350602085013561477a816145d2565b92506040850135915060608501356147918161473b565b939692955090935050565b6000806000606084860312156147b157600080fd5b6147ba84614463565b92506020840135915060408401356146cd816145d2565b6000806000606084860312156147e657600080fd5b6147ef84614463565b92506020840135915060408401356146cd8161473b565b60006020828403121561481857600080fd5b5035919050565b600080600080600060a0868803121561483757600080fd5b8535614842816145d2565b94506020860135614852816145d2565b94979496505050506040830135926060810135926080909101359150565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600182016148ae576148ae614886565b5060010190565b60208082526018908201527f416363657373436f6e74726f6c6c65642f496e76616c69640000000000000000604082015260600190565b81810381811115610c4157610c41614886565b80820180821115610c4157610c41614886565b634e487b7160e01b600052601260045260246000fd5b60008261493757614937614912565b500690565b6020808252601590820152741b59dd93d999995c8bdd5b985d5d1a1bdc9a5e9959605a1b604082015260600190565b60006020828403121561497d57600080fd5b5051919050565b60006020828403121561499657600080fd5b8151610c7d8161473b565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000808335601e198436030181126149dc57600080fd5b83018035915067ffffffffffffffff8211156149f757600080fd5b6020019150600581901b360382131561141657600080fd5b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b60008060408385031215614a4b57600080fd5b505080516020909101519092909150565b8082028115828204841417610c4157610c41614886565b60005b83811015614a8e578181015183820152602001614a76565b50506000910152565b60008151808452614aaf816020860160208601614a73565b601f01601f19169290920160200192915050565b606081526000614ad66060830186614a97565b60208301949094525060400152919050565b604081526000614afb6040830185614a97565b90508260208301529392505050565b600060033d11156114dd5760046000803e5060005160e01c90565b601f8201601f1916810167ffffffffffffffff81118282101715614b5957634e487b7160e01b600052604160045260246000fd5b6040525050565b600060443d1015614b6e5790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715614b9e57505050505090565b8285019150815181811115614bb65750505050505090565b843d8701016020828501011115614bd05750505050505090565b614bdf60208286010187614b25565b509095945050505050565b602081526000610c7d6020830184614a97565b80516020808301519190811015610fa15760001960209190910360031b1b16919050565b61ffff828116828216039080821115612fac57612fac614886565b6001600160801b03828116828216039080821115612fac57612fac614886565b600082614c6b57614c6b614912565b500490565b60008251614c82818460208701614a73565b9190910192915050565b604080825283519082018190526000906020906060840190828701845b82811015614cce5781516001600160a01b031684529284019290840190600101614ca9565b5050506001600160a01b03949094169201919091525091905056fea264697066735822122059d5bbaffa63c3cbdca8df922d93438968c6259438ec359062022dbeb33a63f764736f6c63430008110033

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

000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd700000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca0000000000000000000000000000000000000000000000000000000000030d40000000000000000000000000000000000000000000000000000000000000012e

-----Decoded View---------------
Arg [0] : mgv (address): 0x823701dD29451766d5B9eF6b54ef42642F545cd7
Arg [1] : base (address): 0x63E537A69b3f5B03F4f46c5765c82861BD874b6e
Arg [2] : quote (address): 0xC87385b5E62099f92d490750Fcd6C901a524BBcA
Arg [3] : gasreq (uint256): 200000
Arg [4] : nslots (uint16): 302

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000823701dd29451766d5b9ef6b54ef42642f545cd7
Arg [1] : 00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e
Arg [2] : 000000000000000000000000c87385b5e62099f92d490750fcd6c901a524bbca
Arg [3] : 0000000000000000000000000000000000000000000000000000000000030d40
Arg [4] : 000000000000000000000000000000000000000000000000000000000000012e


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ 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.