Contract 0x5e875d57536227be30abf7dd5d12f23be88a9523

Contract Overview

Balance:
0 MATIC
Txn Hash
Method
Block
From
To
Value [Txn Fee]
0x8e6e3c3cf22c1926744a2fb4e6f09ba0a105dde8fbcb19ae2f4e2c6ffce590e10x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001198167004 3.000000011
0x196f59acba04a5e47d2b45e195f76dea14c748cc70bbf51a0c91c92ae4b395540x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001331238004 3.000000011
0x80cf079904b7aaa77ddc38670f999568ae6dbb3e00199df33983c537f167febf0x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001521837005 3.000000011
0x77c5d7f206b395ae7279307d8d7f60c52ed4917e29d154e42c3e0144b3cc23100x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001521837005 3.000000011
0xbc3e14a685cd66d6ef1ee4705f385eec96d540e691d577717ecf71bbce24343e0x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001598898005 3.000000011
0x712938b30971ea1a0150f27736cafdf59fe100613b3edfe76a8f1c8cb7b1c7d30x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001692294006 3.000000011
0x9c31b73ede0665f04bbc9b77836c72f7befb766f333cf64d66ab3539b47c9a4c0x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001521897005 3.000000011
0x61b7ad159b876a1b532a6e437fa8598b952d7826961296cc84882d947f44e1840x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001394823005 3.000000011
0x4824be9ada2cab80a0dc74835a93a4933e08b1c85bc4b1820452cbe650521bfe0x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001198227004 3.000000011
0xe22b2b4ad25748ceead3fdeee3aa1796bbe49fa402acde9896de6524301b2fb60x553e9f32281178552022-09-15 15:20:21193 days 16 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001181847004 3.000000011
0x1614e9b7507901d32f05ac94fd89d71aca6f6054a00d9ed1c9db564c589e84ac0x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001483821006 3.000000014
0x7f2bd19518150075c31542b983e2c0693ba4ca0a0acc3550b4d57ab4956f02a70x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001644498007 3.000000014
0xb7a2553d4d77ece189741f83dc3156cd87ab852e97baa57501478668a399495b0x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001835097008 3.000000014
0xd35921f8bcb1de1a912c33b4ce15d7933afbb93b36fa549a0dc00e8c687086a30x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001835097008 3.000000014
0x47aee70efe8962fc1f7d4e1ae18d1cc6ae1e7982d9a892013651e9d2b06555d60x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001824801008 3.000000014
0x955d59ac17db609cc12cbbea46d5f97c94f7c5ee8a01b47f89d3d2508fe757d70x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001799097008 3.000000014
0xd1140189ad850df43f77a61b08345716a486decec7d93d44065e7a2b621cdc4b0x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001799097008 3.000000014
0xfa7b6f22af7d05498211740dcfa908abc2e398f833374235d7e29795c772a6c00x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001672023007 3.000000014
0x90e27d9957a904f8a95d4b1e3677aebdf6185102b524bdceaf3ea8733c01fc050x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001475427006 3.000000014
0xde3d7294953b17d67af3e2e83e86b8cfb9af03b74e5197b6a49c8834930886ec0x553e9f32281174732022-09-15 14:48:25193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001457253006 3.000000014
0x601313eb14ba31e0c7d91b285db5e3c26f9e145ed3949d1c4ff10efd63652708Retract Offers281174462022-09-15 14:46:10193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.007753272038 3.000000015
0x335e001a0edfef5f2d461b05dcf38199339b054e451cff06e5be294be1b372c40x553e9f32281173902022-09-15 14:41:29193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001739436011 3.00000002
0x6cfc8d7b332002d690b258dac815fcb3a739e39ad3aa3b05033e334c3f1f9f430x553e9f32281173902022-09-15 14:41:29193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001679538011 3.00000002
0xc5171fd004a217fc7c3efe2d2bec2ad9d10a2d82f546685054d84b09a47c60bb0x553e9f32281173902022-09-15 14:41:29193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001870137012 3.00000002
0xf032e7ffa7311386eee96b4d5c1e129b9e8b5add4154657ce4bc679a9f461c050x553e9f32281173902022-09-15 14:41:29193 days 17 hrs ago0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54 IN  0x5e875d57536227be30abf7dd5d12f23be88a95230 MATIC0.001870137012 3.00000002
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x601313eb14ba31e0c7d91b285db5e3c26f9e145ed3949d1c4ff10efd63652708281174462022-09-15 14:46:10193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0x601313eb14ba31e0c7d91b285db5e3c26f9e145ed3949d1c4ff10efd63652708281174462022-09-15 14:46:10193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0x0c5e55d9d5fe827e37b72924a3c46db53675653bcecb65fbb6e996d01dc39701281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.089408 MATIC
0x0c5e55d9d5fe827e37b72924a3c46db53675653bcecb65fbb6e996d01dc39701281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.089408 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8 0x5e875d57536227be30abf7dd5d12f23be88a95230.001016 MATIC
0xe8e7d386577461e7ec8aad25ea91fc061172b5d5bb13df852e386e35de08b5c9281173542022-09-15 14:38:28193 days 17 hrs ago 0x5e875d57536227be30abf7dd5d12f23be88a95230x5a6272e5d8690ad47df72bbf7fb08ce1851b8f540.001016 MATIC
[ Download CSV Export 
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Mango

Compiler Version
v0.8.14+commit.80d49f37

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 22 : Mango.sol
// SPDX-License-Identifier:	BSD-2-Clause

// Mango.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;
import "./MangoStorage.sol";
import "./MangoImplementation.sol";
import "../../abstract/Persistent.sol";
import "../../../routers/AbstractRouter.sol";
import "../../../routers/SimpleRouter.sol";

/** Discrete automated market making strat */
/** This AMM is headless (no price model) and market makes on `NSLOTS` price ranges*/
/** current `Pmin` is the price of an offer at position `0`, current `Pmax` is the price of an offer at position `NSLOTS-1`*/
/** Initially `Pmin = P(0) = QUOTE_0/BASE_0` and the general term is P(i) = __quote_progression__(i)/BASE_0 */
/** NB `__quote_progression__` is a hook that defines how price increases with positions and is by default an arithmetic progression, i.e __quote_progression__(i) = QUOTE_0 + `delta`*i */
/** When one of its offer is matched on Mangrove, the headless strat does the following: */
/** Each time this strat receives b `BASE` tokens (bid was taken) at price position i, it increases the offered (`BASE`) volume of the ask at position i+1 of 'b'*/
/** Each time this strat receives q `QUOTE` tokens (ask was taken) at price position i, it increases the offered (`QUOTE`) volume of the bid at position i-1 of 'q'*/
/** In case of a partial fill of an offer at position i, the offer residual is reposted (see `Persistent` strat class)*/

contract Mango is Persistent {
  // emitted when init function has been called and AMM becomes active
  event Initialized(uint from, uint to);

  address private immutable IMPLEMENTATION;

  uint public immutable NSLOTS;
  IERC20 public immutable BASE;
  IERC20 public immutable QUOTE;

  // Asks and bids offer Ids are stored in `ASKS` and `BIDS` arrays respectively.

  constructor(
    IMangrove mgv,
    IERC20 base,
    IERC20 quote,
    uint base_0,
    uint quote_0,
    uint nslots,
    uint price_incr,
    address deployer
  )
    Persistent(
      mgv,
      250_000, // gas cost for trade execution (w/o taking routing specific gas cost)
      new SimpleRouter() // routes liqudity from (to) reserve to (from) this contract
    )
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    // sanity check
    require(
      nslots > 0 &&
        address(mgv) != address(0) &&
        uint16(nslots) == nslots &&
        uint96(base_0) == base_0 &&
        uint96(quote_0) == quote_0,
      "Mango/constructor/invalidArguments"
    );

    NSLOTS = nslots;

    // implementation should have correct immutables
    IMPLEMENTATION = address(
      new MangoImplementation(
        mgv,
        base,
        quote,
        uint96(base_0),
        uint96(quote_0),
        nslots
      )
    );
    BASE = base;
    QUOTE = quote;
    // setting local storage
    mStr.asks = new uint[](nslots);
    mStr.bids = new uint[](nslots);
    mStr.delta = price_incr;
    // logs `BID/ASKatMin/MaxPosition` events when only 1 slot remains
    mStr.min_buffer = 1;

    // activates Mango on `quote` and `base`
    __activate__(base);
    __activate__(quote);

    // in order to let deployer's EOA have control over liquidity
    set_reserve(deployer);

    // `this` deployed the router, letting admin take control over it.
    router().set_admin(deployer);

    // setting admin of contract if a static address deployment was used
    if (deployer != msg.sender) {
      set_admin(deployer);
    }
  }

  // populate mangrove order book with bids or/and asks in the price range R = [`from`, `to`[
  // tokenAmounts are always expressed `gives`units, i.e in BASE when asking and in QUOTE when bidding
  function initialize(
    bool reset,
    uint lastBidPosition, // if `lastBidPosition` is in R, then all offers before `lastBidPosition` (included) will be bids, offers strictly after will be asks.
    uint from, // first price position to be populated
    uint to, // last price position to be populated
    uint[][2] calldata pivotIds, // `pivotIds[0][i]` ith pivots for bids, `pivotIds[1][i]` ith pivot for asks
    uint[] calldata tokenAmounts // `tokenAmounts[i]` is the amount of `BASE` or `QUOTE` tokens (dePENDING on `withBase` flag) that is used to fixed one parameter of the price at position `from+i`.
  ) external onlyAdmin {
    // making sure a router has been defined between deployment and initialization
    require(address(router()) != address(0), "Mango/initialize/0xRouter");

    (bool success, bytes memory retdata) = IMPLEMENTATION.delegatecall(
      abi.encodeWithSelector(
        MangoImplementation.$initialize.selector,
        reset,
        lastBidPosition,
        from,
        to,
        pivotIds,
        tokenAmounts,
        ofr_gasreq()
      )
    );
    if (!success) {
      MangoStorage.revertWithData(retdata);
    } else {
      emit Initialized({from: from, to: to});
    }
  }

  function reset_pending() external onlyAdmin {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    mStr.pending_base = 0;
    mStr.pending_quote = 0;
  }

  /** Setters and getters */
  function delta() external view onlyAdmin returns (uint) {
    return MangoStorage.get_storage().delta;
  }

  function set_delta(uint _delta) public mgvOrAdmin {
    MangoStorage.get_storage().delta = _delta;
  }

  function shift() external view onlyAdmin returns (int) {
    return MangoStorage.get_storage().shift;
  }

  function pending() external view onlyAdmin returns (uint[2] memory) {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    return [mStr.pending_base, mStr.pending_quote];
  }

  // with ba=0:bids only, ba=1: asks only ba>1 all
  function retractOffers(
    uint ba,
    uint from,
    uint to
  ) external onlyAdmin returns (uint collected) {
    // with ba=0:bids only, ba=1: asks only ba>1 all
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    for (uint i = from; i < to; i++) {
      if (ba > 0) {
        // asks or bids+asks
        collected += mStr.asks[i] > 0
          ? retractOffer(BASE, QUOTE, mStr.asks[i], true)
          : 0;
      }
      if (ba == 0 || ba > 1) {
        // bids or bids + asks
        collected += mStr.bids[i] > 0
          ? retractOffer(QUOTE, BASE, mStr.bids[i], true)
          : 0;
      }
    }
  }

  /** Shift the price (induced by quote amount) of n slots down or up */
  /** price at position i will be shifted (up or down dePENDING on the sign of `shift`) */
  /** New positions 0<= i < s are initialized with amount[i] in base tokens if `withBase`. In quote tokens otherwise*/
  function set_shift(
    int s,
    bool withBase,
    uint[] calldata amounts
  ) public mgvOrAdmin {
    (bool success, bytes memory retdata) = IMPLEMENTATION.delegatecall(
      abi.encodeWithSelector(
        MangoImplementation.$set_shift.selector,
        s,
        withBase,
        amounts,
        ofr_gasreq()
      )
    );
    if (!success) {
      MangoStorage.revertWithData(retdata);
    }
  }

  function set_min_offer_type(uint m) external mgvOrAdmin {
    MangoStorage.get_storage().min_buffer = m;
  }

  function _staticdelegatecall(bytes calldata data)
    external
    onlyCaller(address(this))
  {
    (bool success, bytes memory retdata) = IMPLEMENTATION.delegatecall(data);
    if (!success) {
      MangoStorage.revertWithData(retdata);
    }
    assembly {
      return(add(retdata, 32), returndatasize())
    }
  }

  // return Mango offer Ids on Mangrove. If `liveOnly` will only return offer Ids that are live (0 otherwise).
  function get_offers(bool liveOnly)
    external
    view
    returns (uint[][2] memory offers)
  {
    (bool success, bytes memory retdata) = address(this).staticcall(
      abi.encodeWithSelector(
        this._staticdelegatecall.selector,
        abi.encodeWithSelector(
          MangoImplementation.$get_offers.selector,
          liveOnly
        )
      )
    );
    if (!success) {
      MangoStorage.revertWithData(retdata);
    } else {
      return abi.decode(retdata, (uint[][2]));
    }
  }

  // starts reneging all offers
  // NB reneged offers will not be reposted
  function pause() public mgvOrAdmin {
    MangoStorage.get_storage().paused = true;
  }

  function restart() external onlyAdmin {
    MangoStorage.get_storage().paused = false;
  }

  function is_paused() external view returns (bool) {
    return MangoStorage.get_storage().paused;
  }

  // this overrides is read during `makerExecute` call (see `MangroveOffer`)
  function __lastLook__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (bool proceed)
  {
    order; //shh
    proceed = !MangoStorage.get_storage().paused;
  }

  // residual gives is default (i.e offer.gives - order.wants) + PENDING
  // this overrides the corresponding function in `Persistent`
  function __residualGives__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (uint)
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    if (order.outbound_tkn == address(BASE)) {
      // Ask offer
      return super.__residualGives__(order) + mStr.pending_base;
    } else {
      // Bid offer
      return super.__residualGives__(order) + mStr.pending_quote;
    }
  }

  // for reposting partial filled offers one always gives the residual (default behavior)
  // and adapts wants to the new price (if different).
  // this overrides the corresponding function in `Persistent`
  function __residualWants__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (uint)
  {
    uint residual = __residualGives__(order);
    if (residual == 0) {
      return 0;
    }
    // computes residualWants in order to respect price imposed by residualGives computed above
    (bool success, bytes memory retdata) = IMPLEMENTATION.delegatecall(
      abi.encodeWithSelector(
        MangoImplementation.$residualWants.selector,
        order,
        residual
      )
    );
    if (!success) {
      MangoStorage.revertWithData(retdata);
    } else {
      return abi.decode(retdata, (uint));
    }
  }

  function __posthookSuccess__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (bool)
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    // reposting residual of offer following Persistent strategy
    // NB __residualWants/Gives__ is overriden by Mango strat to take into account potential pending tokens
    bool reposted = super.__posthookSuccess__(order);

    if (order.outbound_tkn == address(BASE)) {
      if (!reposted) {
        // residual could not be reposted --either below density or Mango went out of provision on Mangrove
        mStr.pending_base = __residualGives__(order); // this includes previous `pending_base`
      } else {
        mStr.pending_base = 0;
      }
    } else {
      if (!reposted) {
        // residual could not be reposted --either below density or Mango went out of provision on Mangrove
        mStr.pending_quote = __residualGives__(order); // this includes previous `pending_base`
      } else {
        mStr.pending_quote = 0;
      }
    }
    // Now that residual was taken care of, Mango publishes new liquidit as a dual offer (a bid if an ask was taken and conversly)
    (bool success, bytes memory retdata) = IMPLEMENTATION.delegatecall(
      abi.encodeWithSelector(
        MangoImplementation.$postDualOffer.selector,
        order,
        ofr_gasreq()
      )
    );
    if (!success) {
      MangoStorage.revertWithData(retdata);
    } else {
      return abi.decode(retdata, (bool));
    }
  }
}

File 2 of 22 : MangoStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangoStorage.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

import "mgv_src/strategies/routers/AbstractRouter.sol";

library MangoStorage {
  /** Strat specific events */

  struct Layout {
    uint[] asks;
    uint[] bids;
    // amount of base (resp quote) tokens that failed to be published on the Market
    uint pending_base;
    uint pending_quote;
    // offerId -> index in ASKS/BIDS maps
    mapping(uint => uint) index_of_bid; // bidId -> index
    mapping(uint => uint) index_of_ask; // askId -> index
    // Price shift is in number of price increments (or decrements when shift < 0) since deployment of the strat.
    // e.g. for arithmetic progression, `shift = -3` indicates that Pmin is now (`QUOTE_0` - 3*`delta`)/`BASE_0`
    int shift;
    // parameter for price progression
    // NB for arithmetic progression, price(i+1) = price(i) + delta/`BASE_0`
    uint delta; // quote increment
    // triggers `__boundariesReached__` whenever amounts of bids/asks is below `min_buffer`
    uint min_buffer;
    // puts the strat into a (cancellable) state where it reneges on all incoming taker orders.
    // NB reneged offers are removed from Mangrove's OB
    bool paused;
    // Base and quote router contract
    AbstractRouter router;
    // reserve address for the router (external treasury -e.g EOA-, Mango or the router itself)
    // if the router is lender based, this is the location of the overlying
    address reserve;
  }

  function get_storage() internal pure returns (Layout storage st) {
    bytes32 storagePosition = keccak256("Mangrove.MangoStorage.Layout");
    assembly {
      st.slot := storagePosition
    }
  }

  function revertWithData(bytes memory retdata) internal pure {
    if (retdata.length == 0) {
      revert("MangoStorage/revertNoReason");
    }
    assembly {
      revert(add(retdata, 32), mload(retdata))
    }
  }

  function quote_price_jumps(
    uint delta,
    uint position,
    uint quote_min
  ) internal pure returns (uint) {
    return delta * position + quote_min;
  }
}

File 3 of 22 : MangoImplementation.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangoImplementation.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;
import "./MangoStorage.sol";
import "../../abstract/Persistent.sol";
import "mgv_src/strategies/utils/TransferLib.sol";

//import "../routers/AbstractRouter.sol";

/** Discrete automated market making strat */
/** This AMM is headless (no price model) and market makes on `NSLOTS` price ranges*/
/** current `Pmin` is the price of an offer at position `0`, current `Pmax` is the price of an offer at position `NSLOTS-1`*/
/** Initially `Pmin = P(0) = QUOTE_0/BASE_0` and the general term is P(i) = __quote_progression__(i)/BASE_0 */
/** NB `__quote_progression__` is a hook that defines how price increases with positions and is by default an arithmetic progression, i.e __quote_progression__(i) = QUOTE_0 + `delta`*i */
/** When one of its offer is matched on Mangrove, the headless strat does the following: */
/** Each time this strat receives b `BASE` tokens (bid was taken) at price position i, it increases the offered (`BASE`) volume of the ask at position i+1 of 'b'*/
/** Each time this strat receives q `QUOTE` tokens (ask was taken) at price position i, it increases the offered (`QUOTE`) volume of the bid at position i-1 of 'q'*/
/** In case of a partial fill of an offer at position i, the offer residual is reposted (see `Persistent` strat class)*/

contract MangoImplementation {
  event BidAtMaxPosition();
  // emitted when strat has reached max amount of Asks and needs rebalancing (should shift of x<0 positions in order to have ask prices that are better for the taker)
  event AskAtMinPosition();

  modifier delegated() {
    require(address(this) == PROXY, "MangoImplementation/invalidCall");
    _;
  }

  // total number of Asks (resp. Bids)
  uint immutable NSLOTS;
  // initial min price given by `QUOTE_0/BASE_0`
  uint96 immutable BASE_0;
  uint96 immutable QUOTE_0;
  // Market on which Mango will be acting
  IERC20 immutable BASE;
  IERC20 immutable QUOTE;

  address immutable PROXY;
  IMangrove immutable MGV;

  constructor(
    IMangrove mgv,
    IERC20 base,
    IERC20 quote,
    uint96 base_0,
    uint96 quote_0,
    uint nslots
  ) {
    // setting immutable fields to match those of `Mango`
    MGV = mgv;
    BASE = base;
    QUOTE = quote;
    NSLOTS = nslots;
    BASE_0 = base_0;
    QUOTE_0 = quote_0;
    PROXY = msg.sender;
  }

  // populate mangrove order book with bids or/and asks in the price range R = [`from`, `to`[
  // tokenAmounts are always expressed `gives`units, i.e in BASE when asking and in QUOTE when bidding
  function $initialize(
    bool reset,
    uint lastBidPosition, // if `lastBidPosition` is in R, then all offers before `lastBidPosition` (included) will be bids, offers strictly after will be asks.
    uint from, // first price position to be populated
    uint to, // last price position to be populated
    uint[][2] calldata pivotIds, // `pivotIds[0][i]` ith pivots for bids, `pivotIds[1][i]` ith pivot for asks
    uint[] calldata tokenAmounts, // `tokenAmounts[i]` is the amount of `BASE` or `QUOTE` tokens (dePENDING on `withBase` flag) that is used to fixed one parameter of the price at position `from+i`.
    uint gasreq // gas required for new offers
  ) external delegated {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    /** Initializing Asks and Bids */
    /** NB we assume Mangrove is already provisioned for posting NSLOTS asks and NSLOTS bids*/
    /** NB cannot post newOffer with infinite gasreq since fallback ofr_gasreq is not defined yet (and default is likely wrong) */
    require(to > from, "Mango/initialize/invalidSlice");
    require(
      tokenAmounts.length == NSLOTS &&
        pivotIds.length == 2 &&
        pivotIds[0].length == NSLOTS &&
        pivotIds[1].length == NSLOTS,
      "Mango/initialize/invalidArrayLength"
    );
    require(lastBidPosition < NSLOTS - 1, "Mango/initialize/NoSlotForAsks"); // bidding => slice doesn't fill the book
    uint pos;
    for (pos = from; pos < to; pos++) {
      // if shift is not 0, must convert
      uint i = index_of_position(pos);

      if (pos <= lastBidPosition) {
        uint bidPivot = pivotIds[0][pos];
        bidPivot = bidPivot > 0
          ? bidPivot // taking pivot from the user
          : pos > 0
          ? mStr.bids[index_of_position(pos - 1)]
          : 0; // otherwise getting last inserted offer as pivot
        updateBid({
          index: i,
          reset: reset, // overwrites old value
          amount: tokenAmounts[pos],
          pivotId: bidPivot,
          gasreq: gasreq
        });
        if (mStr.asks[i] > 0) {
          // if an ASK is also positioned, remove it to prevent spread crossing
          // (should not happen if this is the first initialization of the strat)
          MGV.retractOffer(address(BASE), address(QUOTE), mStr.asks[i], false);
        }
      } else {
        uint askPivot = pivotIds[1][pos];
        askPivot = askPivot > 0
          ? askPivot // taking pivot from the user
          : pos > 0
          ? mStr.asks[index_of_position(pos - 1)]
          : 0; // otherwise getting last inserted offer as pivot
        updateAsk({
          index: i,
          reset: reset,
          amount: tokenAmounts[pos],
          pivotId: askPivot,
          gasreq: gasreq
        });
        if (mStr.bids[i] > 0) {
          // if a BID is also positioned, remove it to prevent spread crossing
          // (should not happen if this is the first initialization of the strat)
          MGV.retractOffer(address(QUOTE), address(BASE), mStr.bids[i], false);
        }
      }
    }
  }

  /** Shift the price (induced by quote amount) of n slots down or up */
  /** price at position i will be shifted (up or down dePENDING on the sign of `shift`) */
  /** New positions 0<= i < s are initialized with amount[i] in base tokens if `withBase`. In quote tokens otherwise*/
  function $set_shift(
    int s,
    bool withBase,
    uint[] calldata amounts,
    uint gasreq
  ) external delegated {
    require(
      amounts.length == (s < 0 ? uint(-s) : uint(s)),
      "Mango/set_shift/notEnoughAmounts"
    );
    if (s < 0) {
      negative_shift(uint(-s), withBase, amounts, gasreq);
    } else {
      positive_shift(uint(s), withBase, amounts, gasreq);
    }
  }

  // return Mango offer Ids on Mangrove. If `liveOnly` will only return offer Ids that are live (0 otherwise).
  function $get_offers(bool liveOnly)
    external
    view
    returns (uint[][2] memory offers)
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    offers[0] = new uint[](NSLOTS);
    offers[1] = new uint[](NSLOTS);
    for (uint i = 0; i < NSLOTS; i++) {
      uint askId = mStr.asks[index_of_position(i)];
      uint bidId = mStr.bids[index_of_position(i)];

      offers[0][i] = (MGV.offers(address(QUOTE), address(BASE), bidId).gives() >
        0 ||
        !liveOnly)
        ? mStr.bids[index_of_position(i)]
        : 0;
      offers[1][i] = (MGV.offers(address(BASE), address(QUOTE), askId).gives() >
        0 ||
        !liveOnly)
        ? mStr.asks[index_of_position(i)]
        : 0;
    }
  }

  struct WriteData {
    uint index;
    uint wants;
    uint gives;
    uint ofr_gr;
    uint pivotId;
  }

  // posts or updates ask at position of `index`
  // returns the amount of `BASE` tokens that failed to be published at that position
  // `writeOffer` is split into `writeAsk` and `writeBid` to avoid stack too deep exception
  function writeAsk(WriteData memory wd) internal returns (uint) {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    if (mStr.asks[wd.index] == 0) {
      // offer slot not initialized yet
      try
        MGV.newOffer({
          outbound_tkn: address(BASE),
          inbound_tkn: address(QUOTE),
          wants: wd.wants,
          gives: wd.gives,
          gasreq: wd.ofr_gr,
          gasprice: 0,
          pivotId: wd.pivotId
        })
      returns (uint offerId) {
        mStr.asks[wd.index] = offerId;
        mStr.index_of_ask[mStr.asks[wd.index]] = wd.index;
        return 0;
      } catch {
        // `newOffer` can fail when Mango is underprovisioned or if `offer.gives` is below density
        return wd.gives;
      }
    } else {
      try
        MGV.updateOffer({
          outbound_tkn: address(BASE),
          inbound_tkn: address(QUOTE),
          wants: wd.wants,
          gives: wd.gives,
          gasreq: wd.ofr_gr,
          gasprice: 0,
          pivotId: wd.pivotId,
          offerId: mStr.asks[wd.index]
        })
      {
        // updateOffer succeeded
        return 0;
      } catch {
        // update offer might fail because residual is below density (this is OK)
        // it may also fail because there is not enough provision on Mangrove (this is Not OK so we log)
        // updateOffer failed but `offer` might still be live (i.e with `offer.gives>0`)
        uint oldGives = MGV
          .offers(address(BASE), address(QUOTE), mStr.asks[wd.index])
          .gives();
        // if not during initialize we necessarily have gives > oldGives
        // otherwise we are trying to reset the offer and oldGives is irrelevant
        return (wd.gives > oldGives) ? wd.gives - oldGives : wd.gives;
      }
    }
  }

  function writeBid(WriteData memory wd) internal returns (uint) {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    if (mStr.bids[wd.index] == 0) {
      try
        MGV.newOffer({
          outbound_tkn: address(QUOTE),
          inbound_tkn: address(BASE),
          wants: wd.wants,
          gives: wd.gives,
          gasreq: wd.ofr_gr,
          gasprice: 0,
          pivotId: wd.pivotId
        })
      returns (uint offerId) {
        mStr.bids[wd.index] = offerId;
        mStr.index_of_bid[mStr.bids[wd.index]] = wd.index;
        return 0;
      } catch {
        return wd.gives;
      }
    } else {
      try
        MGV.updateOffer({
          outbound_tkn: address(QUOTE),
          inbound_tkn: address(BASE),
          wants: wd.wants,
          gives: wd.gives,
          gasreq: wd.ofr_gr,
          gasprice: 0,
          pivotId: wd.pivotId,
          offerId: mStr.bids[wd.index]
        })
      {
        return 0;
      } catch {
        // updateOffer failed but `offer` might still be live (i.e with `offer.gives>0`)
        uint oldGives = MGV
          .offers(address(QUOTE), address(BASE), mStr.bids[wd.index])
          .gives();
        // if not during initialize we necessarily have gives > oldGives
        // otherwise we are trying to reset the offer and oldGives is irrelevant
        return (wd.gives > oldGives) ? wd.gives - oldGives : wd.gives;
      }
    }
  }

  /** Writes (creates or updates) a maker offer on Mangrove's order book*/
  function safeWriteOffer(
    uint index,
    IERC20 outbound_tkn,
    uint wants,
    uint gives,
    uint ofr_gr,
    bool withPending, // whether `gives` amount includes current pending tokens
    uint pivotId
  ) internal {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    if (outbound_tkn == BASE) {
      uint not_published = writeAsk(
        WriteData({
          index: index,
          wants: wants,
          gives: gives,
          ofr_gr: ofr_gr,
          pivotId: pivotId
        })
      );
      if (not_published > 0) {
        // Ask could not be written on the book (density or provision issue)
        mStr.pending_base = withPending
          ? not_published
          : (mStr.pending_base + not_published);
      } else {
        if (withPending) {
          mStr.pending_base = 0;
        }
      }
    } else {
      uint not_published = writeBid(
        WriteData({
          index: index,
          wants: wants,
          gives: gives,
          ofr_gr: ofr_gr,
          pivotId: pivotId
        })
      );
      if (not_published > 0) {
        mStr.pending_quote = withPending
          ? not_published
          : (mStr.pending_quote + not_published);
      } else {
        if (withPending) {
          mStr.pending_quote = 0;
        }
      }
    }
  }

  // returns the value of x in the ring [0,m]
  // i.e if x>=0 this is just x % m
  // if x<0 this is m + (x % m)
  function modulo(int x, uint m) internal pure returns (uint) {
    if (x >= 0) {
      return uint(x) % m;
    } else {
      return uint(int(m) + (x % int(m)));
    }
  }

  /** Minimal amount of quotes for the general term of the `quote_progression` */
  /** If min price was not shifted this is just `QUOTE_0` */
  /** In general this is QUOTE_0 + shift*delta */
  function quote_min() internal view returns (uint) {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    int qm = int(uint(QUOTE_0)) + mStr.shift * int(mStr.delta);
    require(qm > 0, "Mango/quote_min/ShiftUnderflow");
    return (uint(qm));
  }

  /** Returns the price position in the order book of the offer associated to this index `i` */
  function position_of_index(uint i) internal view returns (uint) {
    // position(i) = (i+shift) % N
    return modulo(int(i) - MangoStorage.get_storage().shift, NSLOTS);
  }

  /** Returns the index in the ring of offers at which the offer Id at position `p` in the book is stored */
  function index_of_position(uint p) internal view returns (uint) {
    return modulo(int(p) + MangoStorage.get_storage().shift, NSLOTS);
  }

  /**Next index in the ring of offers */
  function next_index(uint i) internal view returns (uint) {
    return (i + 1) % NSLOTS;
  }

  /**Previous index in the ring of offers */
  function prev_index(uint i) internal view returns (uint) {
    return i > 0 ? i - 1 : NSLOTS - 1;
  }

  /** Function that determines the amount of quotes that are offered at position i of the OB dePENDING on initial_price and paramater delta*/
  /** Here the default is an arithmetic progression */
  function quote_progression(uint position) internal view returns (uint) {
    return
      MangoStorage.quote_price_jumps(
        MangoStorage.get_storage().delta,
        position,
        quote_min()
      );
  }

  /** Returns the quantity of quote tokens for an offer at position `p` given an amount of Base tokens (eq. 2)*/
  function quotes_of_position(uint p, uint base_amount)
    internal
    view
    returns (uint)
  {
    return (quote_progression(p) * base_amount) / BASE_0;
  }

  /** Returns the quantity of base tokens for an offer at position `p` given an amount of quote tokens (eq. 3)*/
  function bases_of_position(uint p, uint quote_amount)
    internal
    view
    returns (uint)
  {
    return (quote_amount * BASE_0) / quote_progression(p);
  }

  /** Recenter the order book by shifting min price up `s` positions in the book */
  /** As a consequence `s` Bids will be cancelled and `s` new asks will be posted */
  function positive_shift(
    uint s,
    bool withBase,
    uint[] calldata amounts,
    uint gasreq
  ) internal {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    require(s < NSLOTS, "Mango/shift/positiveShiftTooLarge");
    uint index = index_of_position(0);
    mStr.shift += int(s); // updating new shift
    // Warning: from now on position_of_index reflects the new shift
    // One must progress relative to index when retracting offers
    uint cpt = 0;
    while (cpt < s) {
      // slots occupied by [Bids[index],..,Bids[index+`s` % N]] are retracted
      if (mStr.bids[index] != 0) {
        MGV.retractOffer({
          outbound_tkn: address(QUOTE),
          inbound_tkn: address(BASE),
          offerId: mStr.bids[index],
          deprovision: false
        });
      }

      // slots are replaced by `s` Asks.
      // NB the price of Ask[index] is computed given the new position associated to `index`
      // because the shift has been updated above

      // `pos` is the offer position in the OB (not the array)
      uint pos = position_of_index(index);
      uint new_gives;
      uint new_wants;
      if (withBase) {
        // posting new ASKS with base amount fixed
        new_gives = amounts[cpt];
        new_wants = quotes_of_position(pos, amounts[cpt]);
      } else {
        // posting new ASKS with quote amount fixed
        new_wants = amounts[cpt];
        new_gives = bases_of_position(pos, amounts[cpt]);
      }
      safeWriteOffer({
        index: index,
        outbound_tkn: BASE,
        wants: new_wants,
        gives: new_gives,
        ofr_gr: gasreq,
        withPending: false, // don't add pending liqudity in new offers (they are far from mid price)
        pivotId: pos > 0 ? mStr.asks[index_of_position(pos - 1)] : 0
      });
      cpt++;
      index = next_index(index);
    }
  }

  /** Recenter the order book by shifting max price down `s` positions in the book */
  /** As a consequence `s` Asks will be cancelled and `s` new Bids will be posted */
  function negative_shift(
    uint s,
    bool withBase,
    uint[] calldata amounts,
    uint gasreq
  ) internal {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    require(s < NSLOTS, "Mango/shift/NegativeShiftTooLarge");
    uint index = index_of_position(NSLOTS - 1);
    mStr.shift -= int(s); // updating new shift
    // Warning: from now on position_of_index reflects the new shift
    // One must progress relative to index when retracting offers
    uint cpt;
    while (cpt < s) {
      // slots occupied by [Asks[index-`s` % N],..,Asks[index]] are retracted
      if (mStr.asks[index] != 0) {
        MGV.retractOffer({
          outbound_tkn: address(BASE),
          inbound_tkn: address(QUOTE),
          offerId: mStr.asks[index],
          deprovision: false
        });
      }
      // slots are replaced by `s` Bids.
      // NB the price of Bids[index] is computed given the new position associated to `index`
      // because the shift has been updated above

      // `pos` is the offer position in the OB (not the array)
      uint pos = position_of_index(index);
      uint new_gives;
      uint new_wants;
      if (withBase) {
        // amounts in base
        new_wants = amounts[cpt];
        new_gives = quotes_of_position(pos, amounts[cpt]);
      } else {
        // amounts in quote
        new_wants = bases_of_position(pos, amounts[cpt]);
        new_gives = amounts[cpt];
      }
      safeWriteOffer({
        index: index,
        outbound_tkn: QUOTE,
        wants: new_wants,
        gives: new_gives,
        ofr_gr: gasreq,
        withPending: false,
        pivotId: pos < NSLOTS - 1 ? mStr.bids[index_of_position(pos + 1)] : 0
      });
      cpt++;
      index = prev_index(index);
    }
  }

  function $residualWants(ML.SingleOrder calldata order, uint residual)
    external
    view
    returns (uint)
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    if (order.outbound_tkn == address(BASE)) {
      // Ask offer (wants QUOTE)
      uint index = mStr.index_of_ask[order.offerId];
      return quotes_of_position(position_of_index(index), residual);
    } else {
      // Bid order (wants BASE)
      uint index = mStr.index_of_bid[order.offerId];
      return bases_of_position(position_of_index(index), residual);
    }
  }

  // TODO add LogIncident and Bid/AskatMax logs
  function $postDualOffer(ML.SingleOrder calldata order, uint gasreq)
    external
    delegated
    returns (bool success)
  {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();

    // reposting residual of offer using override `__newWants__` and `__newGives__` for new price
    if (order.outbound_tkn == address(BASE)) {
      //// Posting dual bid offer
      uint index = mStr.index_of_ask[order.offerId];

      uint pos = position_of_index(index);
      // bid for some BASE token with the received QUOTE tokens @ pos-1
      if (pos > 0) {
        // updateBid will include PENDING_QUOTES if any
        updateBid({
          index: index_of_position(pos - 1),
          reset: false, // top up old value with received amount
          amount: order.gives, // in QUOTES
          pivotId: 0,
          gasreq: gasreq
        });
        if (pos - 1 <= mStr.min_buffer) {
          emit BidAtMaxPosition();
        }
        return true;
      } else {
        // Ask cannot be at Pmin unless a shift has eliminated all bids
        revert("Mango/BidOutOfRange");
      }
    } else {
      // Bid offer (`this` contract just bought some BASE)

      uint index = mStr.index_of_bid[order.offerId];
      // offer was not posted using newOffer
      uint pos = position_of_index(index);
      // ask for some QUOTE tokens in exchange of the received BASE tokens @ pos+1
      if (pos < NSLOTS - 1) {
        // updateAsk will include mStr.pending_baseS if any
        updateAsk({
          index: index_of_position(pos + 1),
          reset: false, // top up old value with received amount
          amount: order.gives, // in BASE
          pivotId: 0,
          gasreq: gasreq
        });
        if (pos + 1 >= NSLOTS - mStr.min_buffer) {
          emit AskAtMinPosition();
        }
        return true;
      } else {
        revert("Mango/AskOutOfRange");
      }
    }
  }

  function updateBid(
    uint index,
    bool reset, // whether this call is part of an `initialize` procedure
    uint amount, // in QUOTE tokens
    uint pivotId,
    uint gasreq
  ) internal {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    // outbound : QUOTE, inbound: BASE
    P.Offer.t offer = MGV.offers(
      address(QUOTE),
      address(BASE),
      mStr.bids[index]
    );

    uint position = position_of_index(index);

    uint new_gives = reset
      ? amount
      : (amount + offer.gives() + mStr.pending_quote);
    uint new_wants = bases_of_position(position, new_gives);

    uint pivot;
    if (offer.gives() == 0) {
      // offer was not live
      if (pivotId != 0) {
        pivot = pivotId;
      } else {
        if (position > 0) {
          pivot = mStr.bids[index_of_position(position - 1)]; // if this offer is no longer in the book will start form best
        } else {
          pivot = offer.prev(); // trying previous offer on Mangrove as a pivot
        }
      }
    } else {
      // offer is live, so reusing its id for pivot
      pivot = mStr.bids[index];
    }
    safeWriteOffer({
      index: index,
      outbound_tkn: QUOTE,
      wants: new_wants,
      gives: new_gives,
      ofr_gr: gasreq,
      withPending: !reset,
      pivotId: pivot
    });
  }

  function updateAsk(
    uint index,
    bool reset, // whether this call is part of an `initialize` procedure
    uint amount, // in BASE tokens
    uint pivotId,
    uint gasreq
  ) internal {
    MangoStorage.Layout storage mStr = MangoStorage.get_storage();
    // outbound : BASE, inbound: QUOTE
    P.Offer.t offer = MGV.offers(
      address(BASE),
      address(QUOTE),
      mStr.asks[index]
    );
    uint position = position_of_index(index);

    uint new_gives = reset
      ? amount
      : (amount + offer.gives() + mStr.pending_base); // in BASE
    uint new_wants = quotes_of_position(position, new_gives);

    uint pivot;
    if (offer.gives() == 0) {
      // offer was not live
      if (pivotId != 0) {
        pivot = pivotId;
      } else {
        if (position > 0) {
          pivot = mStr.asks[index_of_position(position - 1)]; // if this offer is no longer in the book will start form best
        } else {
          pivot = offer.prev(); // trying previous offer on Mangrove as a pivot
        }
      }
    } else {
      // offer is live, so reusing its id for pivot
      pivot = mStr.asks[index];
    }
    safeWriteOffer({
      index: index,
      outbound_tkn: BASE,
      wants: new_wants,
      gives: new_gives,
      ofr_gr: gasreq,
      withPending: !reset,
      pivotId: pivot
    });
  }
}

File 4 of 22 : Persistent.sol
// SPDX-License-Identifier:	BSD-2-Clause

// Persistent.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;
import "./SingleUser.sol";

/** Strat class with specialized hooks that repost offer residual after a partial fill */
/** (Single user variant) */

abstract contract Persistent is SingleUser {
  constructor(
    IMangrove _mgv,
    uint strat_gasreq,
    AbstractRouter _router
  ) SingleUser(_mgv, strat_gasreq, _router) {}

  /** Persistent class specific hooks. */

  // Hook that defines how much inbound tokens the residual offer should ask for when repositing itself on the Offer List.
  // default is to repost the old amount minus the partial fill
  function __residualWants__(ML.SingleOrder calldata order)
    internal
    virtual
    returns (uint)
  {
    return order.offer.wants() - order.gives;
  }

  // Hook that defines how much outbound tokens the residual offer should promise for when repositing itself on the Offer List.
  // default is to repost the old required amount minus the partial fill
  // NB this could produce an offer below the density. Offer Maker should perform a density check at repost time if not willing to fail reposting.
  function __residualGives__(ML.SingleOrder calldata order)
    internal
    virtual
    returns (uint)
  {
    return order.offer.gives() - order.wants;
  }

  // Specializing this hook to repost offer residual when trade was a success
  function __posthookSuccess__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (bool)
  {
    // flushing inbound and remaining outbound tokens to reserve
    super.__posthookSuccess__(order);

    // now trying to repost residual
    uint new_gives = __residualGives__(order);
    // Density check would be too gas costly.
    // We only treat the special case of `gives==0` (total fill).
    // Offer below the density will cause Mangrove to throw (revert is catched to log information)
    if (new_gives == 0) {
      return true;
    }
    uint new_wants = __residualWants__(order);
    try
      MGV.updateOffer(
        order.outbound_tkn,
        order.inbound_tkn,
        new_wants,
        new_gives,
        order.offerDetail.gasreq(),
        order.offerDetail.gasprice(),
        order.offer.next(),
        order.offerId
      )
    {
      return true;
    } catch (bytes memory reason) {
      // `newOffer` can fail when Mango is under provisioned or if `offer.gives` is below density
      // Log incident only if under provisioned
      if (keccak256(reason) == keccak256("mgv/insufficientProvision")) {
        emit LogIncident(
          MGV,
          IERC20(order.outbound_tkn),
          IERC20(order.inbound_tkn),
          order.offerId,
          "Persistent/hook/outOfProvision"
        );
      }
      return false;
    }
  }
}

File 5 of 22 : AbstractRouter.sol
// SPDX-License-Identifier:	BSD-2-Clause

//AbstractRouter.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

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

abstract contract AbstractRouter is AccessControlled {
  modifier onlyMakers() {
    require(makers(msg.sender), "Router/unauthorized");
    _;
  }
  modifier makersOrAdmin() {
    require(msg.sender == admin() || makers(msg.sender), "Router/unauthorized");
    _;
  }

  constructor(uint overhead) AccessControlled(msg.sender) {
    require(uint24(overhead) == overhead, "Router/overheadTooHigh");
    ARSt.get_storage().gas_overhead = overhead;
  }

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

  ///@notice the amount of gas that will be added to `gasreq` of any maker contract using this router
  function gas_overhead() public view returns (uint) {
    return ARSt.get_storage().gas_overhead;
  }

  ///@notice pulls `amount` of `token`s from reserve to calling maker contract's balance
  ///@param token is the ERC20 managing the pulled asset
  ///@param reserve is the address identifying 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) {
    uint buffer = token.balanceOf(msg.sender);
    if (buffer >= amount) {
      return 0;
    } else {
      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 transfered assets should be placed to
  ///@param amount is the amount of asset that should be transfered from the calling maker contract
  function push(
    IERC20 token,
    address reserve,
    uint amount
  ) external onlyMakers {
    __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;

  ///@notice gas saving implementation of an iterative `push`
  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) {
        __push__(tokens[i], reserve, msg.sender, amount);
      }
    }
  }

  ///@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 withdraws `amount` of reserve tokens and sends them to `recipient`
  ///@dev this is called by maker's contract when originator wishes to withdraw funds from it.
  /// this function is necessary because the maker contract is agnostic w.r.t reserve management
  function withdrawToken(
    IERC20 token,
    address reserve,
    address recipient,
    uint amount
  ) public onlyMakers returns (bool) {
    return __withdrawToken__(token, reserve, recipient, amount);
  }

  ///@notice router-dependant implementation of the `withdrawToken` function
  function __withdrawToken__(
    IERC20 token,
    address reserve,
    address to,
    uint amount
  ) internal virtual returns (bool);

  ///@notice adds a maker contract address to the allowed callers 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
  function bind(address maker) public makersOrAdmin {
    ARSt.get_storage().makers[maker] = true;
  }

  ///@notice removes a maker contract address from the allowed callers of this router
  function unbind(address maker) public makersOrAdmin {
    ARSt.get_storage().makers[maker] = 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 {
    // checking basic requirement
    require(
      token.allowance(msg.sender, address(this)) > 0,
      "Router/NotApprovedByMakerContract"
    );
    __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 6 of 22 : SimpleRouter.sol
// SPDX-License-Identifier:	BSD-2-Clause

//SimpleRouter.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

import "mgv_src/strategies/utils/AccessControlled.sol";
import "mgv_src/strategies/utils/TransferLib.sol";
import "./AbstractRouter.sol";

///@notice `SimpleRouter` instances pull (push) liquidity direclty from (to) the reserve
/// If called by a `SingleUser` contract instance this will be the vault of the contract
/// If called by a `MultiUser` instance, this will be the address of a contract user (typically an EOA)
///@dev Maker contracts using this router must make sur that reserve approves the router for all asset that will be pulled (outbound tokens)
/// Thus contract using a vault that is not an EOA must make sure this vault has approval capacities.

contract SimpleRouter is AbstractRouter(50_000) {
  // requires approval of `reserve`
  function __pull__(
    IERC20 token,
    address reserve,
    address maker,
    uint amount,
    bool strict
  ) internal virtual override returns (uint pulled) {
    strict; // this pull strategy is only strict
    if (TransferLib.transferTokenFrom(token, reserve, maker, amount)) {
      return amount;
    } else {
      return 0;
    }
  }

  // requires approval of Maker
  function __push__(
    IERC20 token,
    address reserve,
    address maker,
    uint amount
  ) internal virtual override {
    require(
      TransferLib.transferTokenFrom(token, maker, reserve, amount),
      "SimpleRouter/push/transferFail"
    );
  }

  function __withdrawToken__(
    IERC20 token,
    address reserve,
    address to,
    uint amount
  ) internal virtual override returns (bool) {
    return TransferLib.transferTokenFrom(token, reserve, to, amount);
  }

  function reserveBalance(IERC20 token, address reserve)
    external
    view
    override
    returns (uint)
  {
    return token.balanceOf(reserve);
  }

  function __checkList__(IERC20 token, address reserve)
    internal
    view
    virtual
    override
  {
    // verifying that `this` router can withdraw tokens from reserve (required for `withdrawToken` and `pull`)
    require(
      reserve == address(this) || token.allowance(reserve, address(this)) > 0,
      "SimpleRouter/NotApprovedByReserve"
    );
  }
}

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

// TransferLib.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

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

// TODO-foundry-merge explain what this contract does

library TransferLib {
  // utils
  function transferToken(
    IERC20 token,
    address recipient,
    uint amount
  ) internal returns (bool) {
    if (amount == 0 || recipient == address(this)) {
      return true;
    }
    (bool success, bytes memory data) = address(token).call(
      abi.encodeWithSelector(token.transfer.selector, recipient, amount)
    );
    return (success && (data.length == 0 || abi.decode(data, (bool))));
  }

  function transferTokenFrom(
    IERC20 token,
    address spender,
    address recipient,
    uint amount
  ) internal returns (bool) {
    if (amount == 0 || spender == recipient) {
      return true;
    }
    // optim to avoid requiring contract to approve itself
    if (spender == address(this)) {
      return transferToken(token, recipient, amount);
    }
    (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))));
  }
}

File 8 of 22 : SingleUser.sol
// SPDX-License-Identifier:	BSD-2-Clause

// SingleUser.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

import "../../MangroveOffer.sol";
import "mgv_src/strategies/utils/TransferLib.sol";

/// MangroveOffer is the basic building block to implement a reactive offer that interfaces with the Mangrove
abstract contract SingleUser is MangroveOffer {
  constructor(
    IMangrove _mgv,
    uint strat_gasreq,
    AbstractRouter _router
  ) MangroveOffer(_mgv, strat_gasreq) {
    // default reserve is router's address if router is defined
    // if not then default reserve is `this` contract
    if (address(_router) == address(0)) {
      set_reserve(address(this));
    } else {
      set_reserve(address(_router));
      set_router(_router);
    }
  }

  function reserve() public view override returns (address) {
    return _reserve(address(this));
  }

  function set_reserve(address __reserve) public override onlyAdmin {
    _set_reserve(address(this), __reserve);
  }

  function withdrawToken(
    IERC20 token,
    address receiver,
    uint amount
  ) external override onlyAdmin returns (bool success) {
    require(receiver != address(0), "SingleUser/withdrawToken/0xReceiver");
    if (!has_router()) {
      return TransferLib.transferToken(IERC20(token), receiver, amount);
    } else {
      return router().withdrawToken(token, reserve(), receiver, amount);
    }
  }

  function pull(
    IERC20 outbound_tkn,
    uint amount,
    bool strict
  ) internal returns (uint) {
    AbstractRouter _router = MOS.get_storage().router;
    if (address(_router) == address(0)) {
      return 0; // nothing to do
    } else {
      // letting specific router pull the funds from reserve
      return _router.pull(outbound_tkn, reserve(), amount, strict);
    }
  }

  function push(IERC20 token, uint amount) internal {
    AbstractRouter _router = MOS.get_storage().router;
    if (address(_router) == address(0)) {
      return; // nothing to do
    } else {
      // noop if reserve == address(this)
      _router.push(token, reserve(), amount);
    }
  }

  function tokenBalance(IERC20 token) external view override returns (uint) {
    AbstractRouter _router = MOS.get_storage().router;
    return
      address(_router) == address(0)
        ? token.balanceOf(reserve())
        : _router.reserveBalance(token, reserve());
  }

  function flush(IERC20[] memory tokens) internal {
    AbstractRouter _router = MOS.get_storage().router;
    if (address(_router) == address(0)) {
      return; // nothing to do
    } else {
      _router.flush(tokens, reserve());
    }
  }

  // Posting a new offer on the (`outbound_tkn,inbound_tkn`) Offer List of Mangrove.
  // NB #1: Offer maker maker MUST:
  // * Approve Mangrove for at least `gives` amount of `outbound_tkn`.
  // * Make sure that `this` contract has enough WEI provision on Mangrove to cover for the new offer bounty (function is payable so that caller can increase provision prior to posting the new offer)
  // * Make sure that `gasreq` and `gives` yield a sufficient offer density
  // NB #2: This function will revert when the above points are not met
  function newOffer(MakerOrder memory mko)
    external
    payable
    override
    onlyAdmin
    returns (uint)
  {
    mko.offerId = MGV.newOffer{value: msg.value}(
      address(mko.outbound_tkn),
      address(mko.inbound_tkn),
      mko.wants,
      mko.gives,
      mko.gasreq >= type(uint24).max ? ofr_gasreq() : mko.gasreq,
      mko.gasprice,
      mko.pivotId
    );
    return mko.offerId;
  }

  // Updates offer `offerId` on the (`outbound_tkn,inbound_tkn`) Offer List of Mangrove.
  // NB #1: Offer maker MUST:
  // * Make sure that offer maker has enough WEI provision on Mangrove to cover for the new offer bounty in case Mangrove gasprice has increased (function is payable so that caller can increase provision prior to updating the offer)
  // * Make sure that `gasreq` and `gives` yield a sufficient offer density
  // NB #2: This function will revert when the above points are not met
  function updateOffer(MakerOrder memory mko)
    external
    payable
    override
    onlyAdmin
  {
    return
      MGV.updateOffer{value: msg.value}(
        address(mko.outbound_tkn),
        address(mko.inbound_tkn),
        mko.wants,
        mko.gives,
        mko.gasreq > type(uint24).max ? ofr_gasreq() : mko.gasreq,
        mko.gasprice,
        mko.pivotId,
        mko.offerId
      );
  }

  // 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 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),
        "SingleUser/withdrawFromMgv/withdrawFail"
      );
      (bool noRevert, ) = msg.sender.call{value: free_wei}("");
      require(noRevert, "SingleUser/weiTransferFail");
    }
  }

  function __put__(
    uint, /*amount*/
    ML.SingleOrder calldata
  ) internal virtual override returns (uint missing) {
    // singleUser contract do not need to do anything specific with incoming funds during trade
    // one should overrides this function if one wishes to leverage taker's fund during trade execution
    return 0;
  }

  // default `__get__` hook for `SingleUser` is to pull liquidity from immutable `reserve()`
  // letting router handle the specifics if any
  function __get__(uint amount, ML.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);
    if (pulled >= amount) {
      return 0;
    } else {
      uint local_balance = IERC20(order.outbound_tkn).balanceOf(address(this));
      return local_balance >= amount ? 0 : amount - local_balance;
    }
  }

  ////// Customizable post-hooks.

  // Override this post-hook to implement what `this` contract should do when called back after a successfully executed order.
  // In this posthook, contract will flush its liquidity towards the reserve (noop if reserve is this contract)
  function __posthookSuccess__(ML.SingleOrder calldata order)
    internal
    virtual
    override
    returns (bool success)
  {
    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() == address(this))
    flush(tokens);
    success = true;
  }

  function __checkList__(IERC20 token) internal view virtual override {
    if (has_router()) {
      router().checkList(token, reserve());
    }
    super.__checkList__(token);
  }
}

File 9 of 22 : AccessControlled.sol
// SPDX-License-Identifier:	BSD-2-Clause

// AccessedControlled.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;
import {AccessControlledStorage as ACS} from "./AccessControlledStorage.sol";

// TODO-foundry-merge explain what this contract does

contract AccessControlled {
  constructor(address admin_) {
    require(admin_ != address(0), "accessControlled/0xAdmin");
    ACS.get_storage().admin = admin_;
  }

  modifier onlyCaller(address caller) {
    require(
      caller == address(0) || msg.sender == caller,
      "AccessControlled/Invalid"
    );
    _;
  }

  function admin() public view returns (address) {
    return ACS.get_storage().admin;
  }

  modifier onlyAdmin() {
    require(msg.sender == admin(), "AccessControlled/Invalid");
    _;
  }

  function set_admin(address _admin) public onlyAdmin {
    require(_admin != address(0), "AccessControlled/0xAdmin");
    ACS.get_storage().admin = _admin;
  }
}

File 10 of 22 : AbstractRouterStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

//AbstractRouterStorage.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

library AbstractRouterStorage {
  struct Layout {
    mapping(address => bool) makers;
    uint gas_overhead;
  }

  function get_storage() internal pure returns (Layout storage st) {
    bytes32 storagePosition = keccak256(
      "Mangrove.AbstractRouterStorageLib.Layout"
    );
    assembly {
      st.slot := storagePosition
    }
  }
}

File 11 of 22 : 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;
pragma abicoder v2;

import "./preprocessed/MgvPack.post.sol" as P;

/* # 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;
    P.Offer.t 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. */
    P.OfferDetail.t offerDetail;
    P.Global.t global;
    P.Local.t 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 the 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 the 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 fails, Mangrove will not try to transfer funds.
  - If the call succeeds but returndata's first 32 bytes are not 0, Mangrove will not try to transfer funds either.
  - If the call succeeds and returndata's first 32 bytes are 0, Mangrove will try to transfer funds.
  In other words, you may declare failure by reverting or by returning nonzero data. In both cases, those 32 first bytes will be passed back to you during the call to `makerPosthook` in the `result.mgvData` field.
     ```
     function tradeRevert(bytes32 data) internal pure {
       bytes memory revData = new bytes(32);
         assembly {
           mstore(add(revData, 32), data)
           revert(add(revData, 32), 32)
         }
     }
     ```
     */
  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 the 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);
}

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

  /// for wETH contract
  function decimals() external view returns (uint8);
}

File 12 of 22 : MangroveOffer.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangroveOffer.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

import "mgv_src/strategies/utils/AccessControlled.sol";
import {MangroveOfferStorage as MOS} from "./MangroveOfferStorage.sol";
import "mgv_src/strategies/interfaces/IOfferLogic.sol";
import "mgv_src/IMangrove.sol";

// 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 of this function
// `__f__() virtual internal`: descendant of this contract may override this function to specialize the strat

/// MangroveOffer is the basic building block to implement a reactive offer that interfaces with the Mangrove
abstract contract MangroveOffer is AccessControlled, IOfferLogic {
  // immutable does not impact storage layout
  IMangrove public immutable MGV;
  // `this` contract entypoint is `makerExecute` or `makerPosthook` if `msg.sender == address(MGV)`
  // `this` contract was called on an admin function iff `msg.sender = admin`

  modifier mgvOrAdmin() {
    require(
      msg.sender == admin() || msg.sender == address(MGV),
      "AccessControlled/Invalid"
    );
    _;
  }

  // necessary function to withdraw funds from Mangrove
  receive() external payable virtual {}

  constructor(IMangrove _mgv, uint strat_gasreq) AccessControlled(msg.sender) {
    require(
      strat_gasreq == uint24(strat_gasreq),
      "MangroveOffer/gasreqTooHigh"
    );
    MGV = _mgv;
    MOS.get_storage().ofr_gasreq = strat_gasreq;
  }

  function ofr_gasreq() public view returns (uint) {
    if (has_router()) {
      return MOS.get_storage().ofr_gasreq + router().gas_overhead();
    } else {
      return MOS.get_storage().ofr_gasreq;
    }
  }

  /////// Mandatory callback functions

  // `makerExecute` is the callback function to execute all offers that were posted on Mangrove by `this` contract.
  // it may not be overriden although it can be customized using `__lastLook__`, `__put__` and `__get__` hooks.
  // NB #1: When overriding the above hooks, the Offer Makers should make sure they do not revert in order if they wish to post logs in case of bad executions.
  // NB #2: if `makerExecute` does revert, the offer will be considered to be refusing the trade.
  // NB #3: `makerExecute` must return the empty bytes to signal to MGV it wishes to perform the trade. Any other returned byes will signal to MGV that `this` contract does not wish to proceed with the trade
  // NB #4: Reneging on trade by either reverting or returning non empty bytes 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(ML.SingleOrder calldata order)
    external
    override
    onlyCaller(address(MGV))
    returns (bytes32 ret)
  {
    if (!__lastLook__(order)) {
      // hook to check order details and decide whether `this` contract should renege on the offer.
      revert("mgvOffer/abort/reneged");
    }
    if (__put__(order.gives, order) > 0) {
      revert("mgvOffer/abort/putFailed");
    }
    if (__get__(order.wants, order) > 0) {
      revert("mgvOffer/abort/getFailed");
    }
    return ret;
  }

  // `makerPosthook` is the callback function that is called by Mangrove *after* the offer execution.
  // It may not be overriden although it can be customized via the post-hooks `__posthookSuccess__` and `__posthookFallback__` (see below).
  // Offer Maker SHOULD make sure the overriden posthooks do not revert in order to be able to post logs in case of bad executions.
  function makerPosthook(
    ML.SingleOrder calldata order,
    ML.OrderResult calldata result
  ) external override onlyCaller(address(MGV)) {
    if (result.mgvData == "mgv/tradeSuccess") {
      // toplevel posthook may ignore returned value which is only usefull for (vertical) compositionality
      __posthookSuccess__(order);
    } else {
      emit LogIncident(
        MGV,
        IERC20(order.outbound_tkn),
        IERC20(order.inbound_tkn),
        order.offerId,
        result.makerData
      );
      __posthookFallback__(order, result);
    }
  }

  // sets default gasreq for `new/updateOffer`
  function set_gasreq(uint gasreq) public override mgvOrAdmin {
    require(uint24(gasreq) == gasreq, "mgvOffer/gasreq/overflow");
    MOS.get_storage().ofr_gasreq = gasreq;
    emit SetGasreq(gasreq);
  }

  /** Sets the account from which base (resp. quote) tokens need to be fetched or put during trade execution*/
  /** */
  /** NB Router might need further approval to work as intended*/
  /** `this` contract must be admin of router to do this */
  function set_router(AbstractRouter router_) public override mgvOrAdmin {
    require(address(router_) != address(0), "mgvOffer/set_router/0xRouter");
    MOS.get_storage().router = router_;
    router_.bind(address(this));
    emit SetRouter(router_);
  }

  // maker contract need to approve router for reserve push and pull
  function approveRouter(IERC20 token) public {
    require(
      token.approve(address(router()), type(uint).max),
      "mgvOffer/approveRouter/Fail"
    );
  }

  function has_router() public view returns (bool) {
    return address(MOS.get_storage().router) != address(0);
  }

  function router() public view returns (AbstractRouter) {
    AbstractRouter router_ = MOS.get_storage().router;
    require(address(router_) != address(0), "mgvOffer/0xRouter");
    return router_;
  }

  function _reserve(address maker) internal view returns (address) {
    return MOS.get_storage().reserves[maker];
  }

  function _set_reserve(address maker, address __reserve) internal {
    require(__reserve != address(0), "SingleUser/0xReserve");
    MOS.get_storage().reserves[maker] = __reserve;
  }

  /// `this` contract needs to approve Mangrove to let it perform outbound token transfer at the end of the `makerExecute` function
  /// NB if anyone can call this function someone could reset it to 0 for griefing
  function approveMangrove(IERC20 outbound_tkn) public {
    require(
      outbound_tkn.approve(address(MGV), type(uint).max),
      "mgvOffer/approveMangrove/Fail"
    );
  }

  ///@notice gas efficient external call to activate several tokens in a single transaction
  function activate(IERC20[] calldata tokens) external override onlyAdmin {
    for (uint i = 0; i < tokens.length; i++) {
      __activate__(tokens[i]);
    }
  }

  ///@notice allows this contract to be a liquidity provider for a particular asset by performing the necessary approvals
  ///@param token the ERC20 one wishes this contract to be a provider of
  function __activate__(IERC20 token) internal virtual {
    // approves Mangrove for pulling funds at the end of `makerExecute`
    approveMangrove(token);
    if (has_router()) {
      // allowing router to pull `token` from this contract (for the `push` function of the router)
      approveRouter(token);
      // letting router performs additional necessary approvals (if any)
      router().activate(token);
    }
  }

  ///@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 when there is a missing approval
  function checkList(IERC20[] calldata tokens) external view override {
    for (uint i = 0; i < tokens.length; i++) {
      __checkList__(tokens[i]);
    }
  }

  function __checkList__(IERC20 token) internal view virtual {
    require(
      token.allowance(address(this), address(MGV)) > 0,
      "MangroveOffer/AdminMustApproveMangrove"
    );
  }

  ///@notice withdraws ETH from the provision account on Mangrove and sends collected WEIs to `receiver`
  ///@dev for multi user strats, the contract provision account on Mangrove is pooled amongst offer owners so admin should only call this function to recover WEIs (e.g. that were erroneously transferred to Mangrove using `MGV.fund()`)
  /// This contract's balance on Mangrove may contain deprovisioned WEIs after an offer has failed (complement between provision and the bounty that was sent to taker)
  /// those free WEIs can be retrieved by offer owners by calling `retractOffer` with the `deprovsion` flag. Not by calling this function which is admin only.

  function withdrawFromMangrove(uint amount, address payable receiver)
    external
    onlyAdmin
  {
    if (amount == type(uint).max) {
      amount = MGV.balanceOf(address(this));
      if (amount == 0) {
        return; // optim
      }
    }
    require(MGV.withdraw(amount), "mgvOffer/withdrawFromMgv/withdrawFail");
    (bool noRevert, ) = receiver.call{value: amount}("");
    require(noRevert, "mgvOffer/withdrawFromMgv/payableCallFail");
  }

  ////// Default Customizable hooks for Taker Order'execution

  // Define this hook to describe where the inbound token, which are brought by the Offer Taker, should go during Taker Order's execution.
  // Usage of this hook is the following:
  // * `amount` is the amount of `inbound` tokens whose deposit location is to be defined when entering this function
  // * `order` is a recall of the taker order that is at the origin of the current trade.
  // * Function must return `missingPut` (<=`amount`), which is the amount of `inbound` tokens whose deposit location has not been decided (possibly because of a failure) during this function execution
  // NB in case of preceding executions of descendant specific `__put__` implementations, `amount` might be lower than `order.gives` (how much `inbound` tokens the taker gave)
  function __put__(uint amount, ML.SingleOrder calldata order)
    internal
    virtual
    returns (uint missingPut);

  // Define this hook to implement fetching `amount` of outbound tokens, possibly from another source than `this` contract during Taker Order's execution.
  // Usage of this hook is the following:
  // * `amount` is the amount of `outbound` tokens that still needs to be brought to the balance of `this` contract when entering this function
  // * `order` is a recall of the taker order that is at the origin of the current trade.
  // * Function must return `missingGet` (<=`amount`), which is the amount of `outbound` tokens still need to be fetched at the end of this function
  // NB in case of preceding executions of descendant specific `__get__` implementations, `amount` might be lower than `order.wants` (how much `outbound` tokens the taker wants)
  function __get__(uint amount, ML.SingleOrder calldata order)
    internal
    virtual
    returns (uint missingGet);

  // Override this hook to implement a last look check during Taker Order's execution.
  // Return value should be `true` if Taker Order is acceptable.
  // Returning `false` will cause `MakerExecute` to return the "RENEGED" bytes, which are interpreted by MGV as a signal that `this` contract wishes to cancel the trade
  function __lastLook__(ML.SingleOrder calldata order)
    internal
    virtual
    returns (bool proceed)
  {
    order; //shh
    proceed = true;
  }

  //utils
  function $(IERC20 token) internal pure returns (address) {
    return address(token);
  }

  // Override this post-hook to implement fallback behavior when Taker Order's execution failed unexpectedly. Information from Mangrove is accessible in `result.mgvData` for logging purpose.
  function __posthookFallback__(
    ML.SingleOrder calldata order,
    ML.OrderResult calldata result
  ) internal virtual returns (bool success) {
    order;
    result;
    return true;
  }

  function __posthookSuccess__(ML.SingleOrder calldata order)
    internal
    virtual
    returns (bool)
  {
    order;
    return true;
  }

  // returns missing provision to repost `offerId` at given `gasreq` and `gasprice`
  // if `offerId` is not in the Order Book, will simply return how much is needed to post
  // NB in the case of a multi user contract, this function does not take into account a potential partition of the provision of `this` amongst offer owners
  function getMissingProvision(
    IERC20 outbound_tkn,
    IERC20 inbound_tkn,
    uint gasreq, // give > type(uint24).max to use `this.ofr_gasreq()`
    uint gasprice, // give 0 to use Mangrove's gasprice
    uint offerId // set this to 0 if one is not reposting an offer
  ) public view returns (uint) {
    (P.Global.t globalData, P.Local.t localData) = MGV.config(
      $(outbound_tkn),
      $(inbound_tkn)
    );
    P.OfferDetail.t offerDetailData = MGV.offerDetails(
      $(outbound_tkn),
      $(inbound_tkn),
      offerId
    );
    uint _gp;
    if (globalData.gasprice() > gasprice) {
      _gp = globalData.gasprice();
    } else {
      _gp = gasprice;
    }
    if (gasreq >= type(uint24).max) {
      gasreq = ofr_gasreq(); // 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, all returned values will be 0
    uint currentProvisionLocked = (offerDetailData.gasreq() +
      offerDetailData.offer_gasbase()) *
      offerDetailData.gasprice() *
      10**9;
    uint currentProvision = currentProvisionLocked +
      MGV.balanceOf(address(this));
    return (currentProvision >= bounty ? 0 : bounty - currentProvision);
  }
}

File 13 of 22 : AccessControlledStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

// AccessedControlled.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

// TODO-foundry-merge explain what this contract does

library AccessControlledStorage {
  struct Layout {
    address admin;
  }

  function get_storage() internal pure returns (Layout storage st) {
    bytes32 storagePosition = keccak256("Mangrove.AccessControlledStorage");
    assembly {
      st.slot := storagePosition
    }
  }
}

File 14 of 22 : MgvPack.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// MgvPack.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.
 * ************************************************** */

import "./MgvStructs.post.sol";

import "./MgvOffer.post.sol" as Offer;
import "./MgvOfferDetail.post.sol" as OfferDetail;
import "./MgvGlobal.post.sol" as Global;
import "./MgvLocal.post.sol" as Local;

File 15 of 22 : MangroveOfferStorage.sol
// SPDX-License-Identifier:	BSD-2-Clause

// MangroveOffer.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;

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

// 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 of this function
// `__f__() virtual internal`: descendant of this contract may override this function to specialize the strat

/// MangroveOffer is the basic building block to implement a reactive offer that interfaces with the Mangrove
library MangroveOfferStorage {
  struct Layout {
    // default values
    uint ofr_gasreq;
    AbstractRouter router;
    mapping(address => address) reserves;
  }

  function get_storage() internal pure returns (Layout storage st) {
    bytes32 storagePosition = keccak256("Mangrove.MangroveOfferStorage");
    assembly {
      st.slot := storagePosition
    }
  }
}

File 16 of 22 : IOfferLogic.sol
// SPDX-License-Identifier:	BSD-2-Clause

// IOfferLogic.sol

// Copyright (c) 2021 Giry SAS. 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;
pragma abicoder v2;
import "mgv_src/IMangrove.sol";
import {IERC20} from "mgv_src/MgvLib.sol";
import "mgv_src/strategies/routers/AbstractRouter.sol";

interface IOfferLogic is IMaker {
  ///////////////////
  // MangroveOffer //
  ///////////////////

  /** @notice Events */

  // Log incident (during post trade execution)
  event LogIncident(
    IMangrove mangrove,
    IERC20 indexed outbound_tkn,
    IERC20 indexed inbound_tkn,
    uint indexed offerId,
    bytes32 reason
  );

  // Logging change of router address
  event SetRouter(AbstractRouter);
  // Logging change in default gasreq
  event SetGasreq(uint);

  // Offer logic default gas required --value is used in update and new offer if maxUint is given
  function ofr_gasreq() external returns (uint);

  // returns missing provision on Mangrove, should `offerId` be reposted using `gasreq` and `gasprice` parameters
  // if `offerId` is not in the `outbound_tkn,inbound_tkn` offer list, the totality of the necessary provision is returned
  function getMissingProvision(
    IERC20 outbound_tkn,
    IERC20 inbound_tkn,
    uint gasreq,
    uint gasprice,
    uint offerId
  ) external view returns (uint);

  // Changing ofr_gasreq of the logic
  function set_gasreq(uint gasreq) external;

  // changing liqudity router of the logic
  function set_router(AbstractRouter router) external;

  // maker contract approves router for push and pull operations
  function approveRouter(IERC20 token) external;

  // withdraw `amount` `token` form the contract's (owner) reserve and sends them to `receiver`'s balance
  function withdrawToken(
    IERC20 token,
    address receiver,
    uint amount
  ) external returns (bool success);

  ///@notice throws if this maker contract is missing approval to be used by caller to trade on the given asset
  ///@param tokens the assets the caller wishes to trade
  function checkList(IERC20[] calldata tokens) external view;

  ///@return balance the  `token` amount that `msg.sender` has in the contract's reserve
  function tokenBalance(IERC20 token) external returns (uint balance);

  // allow this contract to act as a LP for Mangrove on `outbound_tkn`
  function approveMangrove(IERC20 outbound_tkn) external;

  // contract's activation sequence for a specific ERC
  function activate(IERC20[] calldata tokens) external;

  // pulls available free wei from Mangrove balance to `this`
  function withdrawFromMangrove(uint amount, address payable receiver) external;

  struct MakerOrder {
    IERC20 outbound_tkn; // address of the ERC20 contract managing outbound tokens
    IERC20 inbound_tkn; // address of the ERC20 contract managing outbound tokens
    uint wants; // amount of `inbound_tkn` required for full delivery
    uint gives; // max amount of `outbound_tkn` promised by the offer
    uint gasreq; // max gas required by the offer when called. If maxUint256 is used here, default `ofr_gasreq` will be considered instead
    uint gasprice; // gasprice that should be consider to compute the bounty (Mangrove's gasprice will be used if this value is lower)
    uint pivotId;
    uint offerId; // 0 if new offer order
  }

  function newOffer(MakerOrder memory mko)
    external
    payable
    returns (uint offerId);

  //returns 0 if updateOffer failed (for instance if offer is underprovisioned) otherwise returns `offerId`
  function updateOffer(MakerOrder memory mko) external payable;

  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`.
  ) external returns (uint received);

  // returns the address of the vault holding maker's liquidity
  // for single user maker is simply `this` contract
  // for multi users, the maker is `msg.sender`
  function reserve() external view returns (address);

  // allow one to change the reserve holding maker's liquidity
  function set_reserve(address reserve) external;

  function router() external view returns (AbstractRouter);
}

File 17 of 22 : 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 as ML, P, 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
  );
  event OrderStart();
  event PosthookFail(
    address indexed outbound_tkn,
    address indexed inbound_tkn,
    uint offerId
  );
  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 (P.Global.t, P.Local.t);

  function configInfo(address outbound_tkn, address inbound_tkn)
    external
    view
    returns (P.GlobalStruct memory global, P.LocalStruct memory local);

  function deactivate(address outbound_tkn, address inbound_tkn) external;

  function flashloan(ML.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(P.Offer.t 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 (P.OfferDetail.t);

  function offerInfo(
    address outbound_tkn,
    address inbound_tkn,
    uint offerId
  )
    external
    view
    returns (
      P.OfferStruct memory offer,
      P.OfferDetailStruct memory offerDetail
    );

  function offers(
    address,
    address,
    uint
  ) external view returns (P.Offer.t);

  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"}],"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"}],"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":"Global.t","name":"_global","type":"uint256"},{"internalType":"Local.t","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":"struct GlobalStruct","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":"struct LocalStruct","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":"Offer.t","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"OfferDetail.t","name":"offerDetail","type":"uint256"},{"internalType":"Global.t","name":"global","type":"uint256"},{"internalType":"Local.t","name":"local","type":"uint256"}],"internalType":"struct MgvLib.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":"Offer.t","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"}],"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"}],"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":"OfferDetail.t","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":"struct OfferStruct","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":"struct OfferDetailStruct","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":"Offer.t","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"}],"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"}],"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 18 of 22 : MgvStructs.post.sol
pragma solidity ^0.8.13;

// SPDX-License-Identifier: Unlicense

// MgvPack.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.
 * ************************************************** */

/* 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_defs are of the form [name,obj]

// before: Can't put all structs under a 'Structs' library due to bad variable shadowing rules in Solidity
// (would generate lots of spurious warnings about a nameclash between Structs.Offer and library Offer for instance)
// now: Won't put all structs under a 'Structs' namespace because Mangrove & peripheral code now uses the current namespacing.
struct OfferStruct {
  uint prev;
  uint next;
  uint wants;
  uint gives;
}

// before: Can't put all structs under a 'Structs' library due to bad variable shadowing rules in Solidity
// (would generate lots of spurious warnings about a nameclash between Structs.Offer and library Offer for instance)
// now: Won't put all structs under a 'Structs' namespace because Mangrove & peripheral code now uses the current namespacing.
struct OfferDetailStruct {
  address maker;
  uint gasreq;
  uint offer_gasbase;
  uint gasprice;
}

// before: Can't put all structs under a 'Structs' library due to bad variable shadowing rules in Solidity
// (would generate lots of spurious warnings about a nameclash between Structs.Offer and library Offer for instance)
// now: Won't put all structs under a 'Structs' namespace because Mangrove & peripheral code now uses the current namespacing.
struct GlobalStruct {
  address monitor;
  bool useOracle;
  bool notify;
  uint gasprice;
  uint gasmax;
  bool dead;
}

// before: Can't put all structs under a 'Structs' library due to bad variable shadowing rules in Solidity
// (would generate lots of spurious warnings about a nameclash between Structs.Offer and library Offer for instance)
// now: Won't put all structs under a 'Structs' namespace because Mangrove & peripheral code now uses the current namespacing.
struct LocalStruct {
  bool active;
  uint fee;
  uint density;
  uint offer_gasbase;
  bool lock;
  uint best;
  uint last;
}

File 19 of 22 : 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]

import "./MgvStructs.post.sol";

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

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

//some type safety for each struct
type t is uint;
using Library for t 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(t __packed) internal pure returns (OfferStruct memory __s) { unchecked {
    __s.prev = (t.unwrap(__packed) << prev_before) >> (256-prev_bits);
    __s.next = (t.unwrap(__packed) << next_before) >> (256-next_bits);
    __s.wants = (t.unwrap(__packed) << wants_before) >> (256-wants_bits);
    __s.gives = (t.unwrap(__packed) << gives_before) >> (256-gives_bits);
  }}

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

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

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

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

function pack(uint __prev, uint __next, uint __wants, uint __gives) pure returns (t) { unchecked {
  return t.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 20 of 22 : 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]

import "./MgvStructs.post.sol";

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

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

//some type safety for each struct
type t is uint;
using Library for t 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(t __packed) internal pure returns (OfferDetailStruct memory __s) { unchecked {
    __s.maker = address(uint160((t.unwrap(__packed) << maker_before) >> (256-maker_bits)));
    __s.gasreq = (t.unwrap(__packed) << gasreq_before) >> (256-gasreq_bits);
    __s.offer_gasbase = (t.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __s.gasprice = (t.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
  }}

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

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

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

function t_of_struct(OfferDetailStruct memory __s) pure returns (t) { 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 (t) { unchecked {
  return t.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 21 of 22 : 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]

import "./MgvStructs.post.sol";

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

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

//some type safety for each struct
type t is uint;
using Library for t 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(t __packed) internal pure returns (GlobalStruct memory __s) { unchecked {
    __s.monitor = address(uint160((t.unwrap(__packed) << monitor_before) >> (256-monitor_bits)));
    __s.useOracle = (((t.unwrap(__packed) << useOracle_before) >> (256-useOracle_bits)) > 0);
    __s.notify = (((t.unwrap(__packed) << notify_before) >> (256-notify_bits)) > 0);
    __s.gasprice = (t.unwrap(__packed) << gasprice_before) >> (256-gasprice_bits);
    __s.gasmax = (t.unwrap(__packed) << gasmax_before) >> (256-gasmax_bits);
    __s.dead = (((t.unwrap(__packed) << dead_before) >> (256-dead_bits)) > 0);
  }}

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

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

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

function t_of_struct(GlobalStruct memory __s) pure returns (t) { 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 (t) { unchecked {
  return t.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 22 of 22 : 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]

import "./MgvStructs.post.sol";

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

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

//some type safety for each struct
type t is uint;
using Library for t 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(t __packed) internal pure returns (LocalStruct memory __s) { unchecked {
    __s.active = (((t.unwrap(__packed) << active_before) >> (256-active_bits)) > 0);
    __s.fee = (t.unwrap(__packed) << fee_before) >> (256-fee_bits);
    __s.density = (t.unwrap(__packed) << density_before) >> (256-density_bits);
    __s.offer_gasbase = (t.unwrap(__packed) << offer_gasbase_before) >> (256-offer_gasbase_bits);
    __s.lock = (((t.unwrap(__packed) << lock_before) >> (256-lock_bits)) > 0);
    __s.best = (t.unwrap(__packed) << best_before) >> (256-best_bits);
    __s.last = (t.unwrap(__packed) << last_before) >> (256-last_bits);
  }}

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

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

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

function t_of_struct(LocalStruct memory __s) pure returns (t) { 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 (t) { unchecked {
  return t.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)));
}}

Settings
{
  "remappings": [
    "ds-test/=packages/mangrove-solidity/lib/forge-std-vendored/lib/ds-test/src/",
    "forge-std-vendored/=packages/mangrove-solidity/lib/forge-std-vendored/src/",
    "forge-std/=packages/mangrove-solidity/lib/forge-std-vendored/src/",
    "mgv_script/=packages/mangrove-solidity/script/",
    "mgv_src/=packages/mangrove-solidity/src/",
    "mgv_test/=packages/mangrove-solidity/test/"
  ],
  "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":"base_0","type":"uint256"},{"internalType":"uint256","name":"quote_0","type":"uint256"},{"internalType":"uint256","name":"nslots","type":"uint256"},{"internalType":"uint256","name":"price_incr","type":"uint256"},{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"from","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"to","type":"uint256"}],"name":"Initialized","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":"reason","type":"bytes32"}],"name":"LogIncident","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"SetGasreq","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":"NSLOTS","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":"bytes","name":"data","type":"bytes"}],"name":"_staticdelegatecall","outputs":[],"stateMutability":"nonpayable","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":"outbound_tkn","type":"address"}],"name":"approveMangrove","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"approveRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"}],"name":"checkList","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delta","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","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":"bool","name":"liveOnly","type":"bool"}],"name":"get_offers","outputs":[{"internalType":"uint256[][2]","name":"offers","type":"uint256[][2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"has_router","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"reset","type":"bool"},{"internalType":"uint256","name":"lastBidPosition","type":"uint256"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"},{"internalType":"uint256[][2]","name":"pivotIds","type":"uint256[][2]"},{"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"is_paused","outputs":[{"internalType":"bool","name":"","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":"t","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"t","name":"offerDetail","type":"uint256"},{"internalType":"t","name":"global","type":"uint256"},{"internalType":"t","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":"t","name":"offer","type":"uint256"},{"internalType":"uint256","name":"wants","type":"uint256"},{"internalType":"uint256","name":"gives","type":"uint256"},{"internalType":"t","name":"offerDetail","type":"uint256"},{"internalType":"t","name":"global","type":"uint256"},{"internalType":"t","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":[{"components":[{"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"internalType":"contract IERC20","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"}],"internalType":"struct IOfferLogic.MakerOrder","name":"mko","type":"tuple"}],"name":"newOffer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"ofr_gasreq","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pending","outputs":[{"internalType":"uint256[2]","name":"","type":"uint256[2]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reserve","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reset_pending","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"restart","outputs":[],"stateMutability":"nonpayable","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":"uint256","name":"ba","type":"uint256"},{"internalType":"uint256","name":"from","type":"uint256"},{"internalType":"uint256","name":"to","type":"uint256"}],"name":"retractOffers","outputs":[{"internalType":"uint256","name":"collected","type":"uint256"}],"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":"set_admin","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_delta","type":"uint256"}],"name":"set_delta","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"gasreq","type":"uint256"}],"name":"set_gasreq","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"m","type":"uint256"}],"name":"set_min_offer_type","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"__reserve","type":"address"}],"name":"set_reserve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract AbstractRouter","name":"router_","type":"address"}],"name":"set_router","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"s","type":"int256"},{"internalType":"bool","name":"withBase","type":"bool"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"set_shift","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shift","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"}],"name":"tokenBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20","name":"outbound_tkn","type":"address"},{"internalType":"contract IERC20","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"}],"internalType":"struct IOfferLogic.MakerOrder","name":"mko","type":"tuple"}],"name":"updateOffer","outputs":[],"stateMutability":"payable","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":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawToken","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

6101206040523480156200001257600080fd5b5060405162008b2538038062008b25833981016040819052620000359162000c18565b876203d090604051620000489062000b7f565b604051809103906000f08015801562000065573d6000803e3d6000fd5b5082828282823380620000bf5760405162461bcd60e51b815260206004820152601860248201527f616363657373436f6e74726f6c6c65642f307841646d696e000000000000000060448201526064015b60405180910390fd5b80620000d56200048360201b6200275e1760201c565b80546001600160a01b0319166001600160a01b03929092169190911790555062ffffff811681146200014a5760405162461bcd60e51b815260206004820152601b60248201527f4d616e67726f76654f666665722f676173726571546f6f4869676800000000006044820152606401620000b6565b6001600160a01b038216608052806200016e620004a7602090811b6200278217901c565b5550506001600160a01b03811662000191576200018b30620004cb565b620001a7565b6200019c81620004cb565b620001a78162000535565b5050505050506000620001c4620006ce60201b620027a61760201c565b9050600084118015620001df57506001600160a01b03891615155b8015620001ef5750838461ffff16145b801562000204575085866001600160601b0316145b801562000219575084856001600160601b0316145b620002725760405162461bcd60e51b815260206004820152602260248201527f4d616e676f2f636f6e7374727563746f722f696e76616c6964417267756d656e604482015261747360f01b6064820152608401620000b6565b8360c081815250508888888888886040516200028e9062000b8d565b6001600160a01b03968716815294861660208601529490921660408401526001600160601b03908116606084015216608082015260a081019190915260c001604051809103906000f080158015620002ea573d6000803e3d6000fd5b506001600160a01b0390811660a05288811660e052871661010052836001600160401b0381111562000320576200032062000caa565b6040519080825280602002602001820160405280156200034a578160200160208202803683370190505b5080516200036091839160209091019062000b9b565b50836001600160401b038111156200037c576200037c62000caa565b604051908082528060200260200182016040528015620003a6578160200160208202803683370190505b508051620003bf91600184019160209091019062000b9b565b506007810183905560016008820155620003d988620006f2565b620003e487620006f2565b620003ef82620004cb565b620003f962000784565b60405163e9333fab60e01b81526001600160a01b038481166004830152919091169063e9333fab90602401600060405180830381600087803b1580156200043f57600080fd5b505af115801562000454573d6000803e3d6000fd5b505050506001600160a01b038216331462000474576200047482620007f3565b50505050505050505062000ceb565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7fae7e31c3220e851db9f204a28b279dfe52b973600b0a456991089c220ae7222490565b620004d5620008dd565b6001600160a01b0316336001600160a01b031614620005265760405162461bcd60e51b8152602060048201526018602482015260008051602062008b058339815191526044820152606401620000b6565b62000532308262000903565b50565b6200053f620008dd565b6001600160a01b0316336001600160a01b031614806200057257506080516001600160a01b0316336001600160a01b0316145b620005af5760405162461bcd60e51b8152602060048201526018602482015260008051602062008b058339815191526044820152606401620000b6565b6001600160a01b038116620006075760405162461bcd60e51b815260206004820152601c60248201527f6d67764f666665722f7365745f726f757465722f3078526f75746572000000006044820152606401620000b6565b806200061d620004a760201b620027821760201c565b60010180546001600160a01b0319166001600160a01b039283161790556040516381bac14f60e01b8152306004820152908216906381bac14f90602401600060405180830381600087803b1580156200067557600080fd5b505af11580156200068a573d6000803e3d6000fd5b50506040516001600160a01b03841681527f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e54559250602001905060405180910390a150565b7f416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb8190565b620006fd81620009a5565b6200070762000a6e565b156200053257620007188162000aa3565b6200072262000784565b604051630716a76760e21b81526001600160a01b0383811660048301529190911690631c5a9d9c90602401600060405180830381600087803b1580156200076857600080fd5b505af11580156200077d573d6000803e3d6000fd5b5050505050565b6000806200079c620004a760201b620027821760201c565b600101546001600160a01b0316905080620007ee5760405162461bcd60e51b815260206004820152601160248201527036b3bb27b33332b917983c2937baba32b960791b6044820152606401620000b6565b919050565b620007fd620008dd565b6001600160a01b0316336001600160a01b0316146200084e5760405162461bcd60e51b8152602060048201526018602482015260008051602062008b058339815191526044820152606401620000b6565b6001600160a01b038116620008a65760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e00000000000000006044820152606401620000b6565b80620008bc6200048360201b6200275e1760201c565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000620008f46200048360201b6200275e1760201c565b546001600160a01b0316919050565b6001600160a01b0381166200095b5760405162461bcd60e51b815260206004820152601460248201527f53696e676c65557365722f3078526573657276650000000000000000000000006044820152606401620000b6565b8062000971620004a760201b620027821760201c565b6001600160a01b0393841660009081526002919091016020526040902080546001600160a01b031916919093161790915550565b60805160405163095ea7b360e01b81526001600160a01b03918216600482015260001960248201529082169063095ea7b3906044016020604051808303816000875af1158015620009fa573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000a20919062000cc0565b620005325760405162461bcd60e51b815260206004820152601d60248201527f6d67764f666665722f617070726f76654d616e67726f76652f4661696c0000006044820152606401620000b6565b6000806001600160a01b031662000a8f620004a760201b620027821760201c565b600101546001600160a01b03161415919050565b6001600160a01b03811663095ea7b362000abc62000784565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af115801562000b0b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b31919062000cc0565b620005325760405162461bcd60e51b815260206004820152601b60248201527f6d67764f666665722f617070726f7665526f757465722f4661696c00000000006044820152606401620000b6565b6110048062004de883390190565b612d198062005dec83390190565b82805482825590600052602060002090810192821562000bd9579160200282015b8281111562000bd957825182559160200191906001019062000bbc565b5062000be792915062000beb565b5090565b5b8082111562000be7576000815560010162000bec565b6001600160a01b03811681146200053257600080fd5b600080600080600080600080610100898b03121562000c3657600080fd5b885162000c438162000c02565b60208a015190985062000c568162000c02565b60408a015190975062000c698162000c02565b80965050606089015194506080890151935060a0890151925060c0890151915060e089015162000c998162000c02565b809150509295985092959890939650565b634e487b7160e01b600052604160045260246000fd5b60006020828403121562000cd357600080fd5b8151801515811462000ce457600080fd5b9392505050565b60805160a05160c05160e05161010051613fd162000e17600039600081816104ca01528181611c7e0152611d160152600081816106a801528181611c5d01528181611d37015281816129d101526130bc015260006105dd015260008181610ff401528181611153015281816115db01528181612a5d01526132bb01526000818161047e0152818161094901528181610c1b01528181610cd901528181610e3f015281816111e90152818161134a015281816113dc01528181611590015281816116e101528181611775015281816117f0015281816118e80152818161195c015281816119e701528181611b8601528181611ebd0152818161208401528181612121015281816122970152818161269201528181612d9d01528181612eb101526130260152613fd16000f3fe60806040526004361061023f5760003560e01c80639d4ddea21161012e578063db11851e116100ab578063eedc966a1161006f578063eedc966a146106ca578063f259cd27146106ea578063f851a4401461070a578063f887ea401461071f578063fc488a381461073457600080fd5b8063db11851e14610614578063e20ccec314610634578063e4c34f8414610656578063e9333fab14610676578063ec342ad01461069657600080fd5b8063ccbbcfc2116100f2578063ccbbcfc214610581578063cd3293de146105a1578063d1baa1ef146105b6578063d4a1da08146105cb578063d5c39721146105ff57600080fd5b80639d4ddea2146104ec5780639d4f8aa91461050c5780639f2211cb14610521578063ad97db1b14610541578063c5dbec381461056157600080fd5b80635486c95f116101bc578063815502671161018057806381550267146104225780638456cb591461044257806384b627f91461045757806399fa5e2d1461046c5780639c579839146104b857600080fd5b80635486c95f1461038f578063553e9f32146103a25780635a3e9618146103c25780636c49c32c146103e25780637144df241461040257600080fd5b80631ef3755d116102035780631ef3755d146102ed5780631efa880b146103025780633d3d130d1461032f5780633d77fcde1461034f5780635293840d1461036f57600080fd5b806301e336671461024b57806303eb17e21461028057806310aded60146102a257806312b495a8146102b557806312fc41ca146102d857600080fd5b3661024657005b600080fd5b34801561025757600080fd5b5061026b6102663660046134b1565b610754565b60405190151581526020015b60405180910390f35b34801561028c57600080fd5b506102a061029b36600461353e565b6108be565b005b6102a06102b03660046135f0565b61090f565b3480156102c157600080fd5b506102ca610a15565b604051908152602001610277565b3480156102e457600080fd5b506102ca610a60565b3480156102f957600080fd5b506102a0610aab565b34801561030e57600080fd5b5061032261031d3660046136a1565b610b01565b60405161027791906136be565b34801561033b57600080fd5b506102a061034a366004613746565b610c19565b34801561035b57600080fd5b506102a061036a366004613789565b610d3d565b34801561037b57600080fd5b506102a061038a36600461353e565b610d7f565b6102ca61039d3660046135f0565b610e03565b3480156103ae57600080fd5b506102a06103bd3660046137a6565b610f4f565b3480156103ce57600080fd5b506102a06103dd366004613849565b61111c565b3480156103ee57600080fd5b506102ca6103fd3660046138bb565b6111e5565b34801561040e57600080fd5b506102a061041d3660046138d8565b6112f4565b34801561042e57600080fd5b506102a061043d366004613908565b611563565b34801561044e57600080fd5b506102a06116b4565b34801561046357600080fd5b5061026b611729565b34801561047857600080fd5b506104a07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610277565b3480156104c457600080fd5b506104a07f000000000000000000000000000000000000000000000000000000000000000081565b3480156104f857600080fd5b506102a0610507366004613964565b611748565b34801561051857600080fd5b5061026b6117c3565b34801561052d57600080fd5b506102a061053c366004613789565b6117d9565b34801561054d57600080fd5b506102ca61055c36600461397d565b6118b9565b34801561056d57600080fd5b506102a061057c366004613964565b611b59565b34801561058d57600080fd5b506102ca61059c3660046139d0565b611bd4565b3480156105ad57600080fd5b506104a0611d93565b3480156105c257600080fd5b506102ca611da3565b3480156105d757600080fd5b506102ca7f000000000000000000000000000000000000000000000000000000000000000081565b34801561060b57600080fd5b506102a0611e3c565b34801561062057600080fd5b506102a061062f366004613789565b611e90565b34801561064057600080fd5b5061064961200a565b60405161027791906139fc565b34801561066257600080fd5b506102ca610671366004613a2d565b612076565b34801561068257600080fd5b506102a0610691366004613789565b612339565b3480156106a257600080fd5b506104a07f000000000000000000000000000000000000000000000000000000000000000081565b3480156106d657600080fd5b506102ca6106e5366004613789565b6123f1565b3480156106f657600080fd5b506102a0610705366004613789565b61251c565b34801561071657600080fd5b506104a06125f1565b34801561072b57600080fd5b506104a061260a565b34801561074057600080fd5b506102a061074f366004613964565b612665565b600061075e6125f1565b6001600160a01b0316336001600160a01b0316146107975760405162461bcd60e51b815260040161078e90613a7e565b60405180910390fd5b6001600160a01b0383166107f95760405162461bcd60e51b815260206004820152602360248201527f53696e676c65557365722f7769746864726177546f6b656e2f307852656365696044820152623b32b960e91b606482015260840161078e565b610801611729565b610817576108108484846127ca565b90506108b7565b61081f61260a565b6001600160a01b03166321754d9e85610836611d93565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015290821660248201529086166044820152606481018590526084016020604051808303816000875af1158015610893573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108109190613ab5565b9392505050565b60005b8181101561090a576108f88383838181106108de576108de613ad2565b90506020020160208101906108f39190613789565b6128c0565b8061090281613afe565b9150506108c1565b505050565b6109176125f1565b6001600160a01b0316336001600160a01b0316146109475760405162461bcd60e51b815260040161078e90613a7e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a4f769134836000015184602001518560400151866060015162ffffff80168860800151116109a55787608001516109ad565b6109ad611da3565b8860a001518960c001518a60e001516040518a63ffffffff1660e01b81526004016109df989796959493929190613b17565b6000604051808303818588803b1580156109f857600080fd5b505af1158015610a0c573d6000803e3d6000fd5b50505050505b50565b6000610a1f6125f1565b6001600160a01b0316336001600160a01b031614610a4f5760405162461bcd60e51b815260040161078e90613a7e565b610a576127a6565b60070154905090565b6000610a6a6125f1565b6001600160a01b0316336001600160a01b031614610a9a5760405162461bcd60e51b815260040161078e90613a7e565b610aa26127a6565b60060154905090565b610ab36125f1565b6001600160a01b0316336001600160a01b031614610ae35760405162461bcd60e51b815260040161078e90613a7e565b6000610aed6127a6565b600901805460ff1916911515919091179055565b610b0961344c565b60408051831515602480830191909152825180830382018152604490920183526020820180516001600160e01b031663198f4b8360e21b179052915160009283923092630b47d2c360e31b92610b60929101613b87565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051610b9e9190613bba565b600060405180830381855afa9150503d8060008114610bd9576040519150601f19603f3d011682016040523d82523d6000602084013e610bde565b606091505b509150915081610bf657610bf181612954565b610c12565b80806020019051810190610c0a9190613bd6565b949350505050565b5050919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381161580610c585750336001600160a01b038216145b610c745760405162461bcd60e51b815260040161078e90613a7e565b81602001356f6d67762f74726164655375636365737360801b03610ca157610c9b836129ad565b50505050565b60408301803590610cb59060208601613789565b6001600160a01b0316610ccb6020860186613789565b604080516001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811682528735602083015292909216917f736a3993b9f8b1c5603896c76376792887f376b1fe7fc981e09a16530bf1e4e0910160405180910390a4610c9b8383612b52565b610d456125f1565b6001600160a01b0316336001600160a01b031614610d755760405162461bcd60e51b815260040161078e90613a7e565b610a123082612b5b565b610d876125f1565b6001600160a01b0316336001600160a01b031614610db75760405162461bcd60e51b815260040161078e90613a7e565b60005b8181101561090a57610df1838383818110610dd757610dd7613ad2565b9050602002016020810190610dec9190613789565b612be5565b80610dfb81613afe565b915050610dba565b6000610e0d6125f1565b6001600160a01b0316336001600160a01b031614610e3d5760405162461bcd60e51b815260040161078e90613a7e565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349f6d2dc34846000015185602001518660400151876060015162ffffff801689608001511015610e9c578860800151610ea4565b610ea4611da3565b60a08a015160c08b01516040516001600160e01b031960e08b901b1681526001600160a01b03978816600482015296909516602487015260448601939093526064850191909152608484015260a483015260c482015260e40160206040518083038185885af1158015610f1b573d6000803e3d6000fd5b50505050506040513d601f19601f82011682018060405250810190610f409190613cd7565b60e0830181905290505b919050565b610f576125f1565b6001600160a01b0316336001600160a01b031614610f875760405162461bcd60e51b815260040161078e90613a7e565b6000610f9161260a565b6001600160a01b031603610fe75760405162461bcd60e51b815260206004820152601960248201527f4d616e676f2f696e697469616c697a652f3078526f7574657200000000000000604482015260640161078e565b6000806001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001662c8d3f760e61b8a8a8a8a8a8a8a61102a611da3565b604051602401611041989796959493929190613d26565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161107f9190613bba565b600060405180830381855af49150503d80600081146110ba576040519150601f19603f3d011682016040523d82523d6000602084013e6110bf565b606091505b5091509150816110d7576110d281612954565b611111565b60408051888152602081018890527f997896709b4e932ee42750e2e14ed1f7ab6c60bd911ff567aa2485cf0b20051b910160405180910390a15b505050505050505050565b308015806111325750336001600160a01b038216145b61114e5760405162461bcd60e51b815260040161078e90613a7e565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316858560405161118b929190613dfb565b600060405180830381855af49150503d80600081146111c6576040519150601f19603f3d011682016040523d82523d6000602084013e6111cb565b606091505b5091509150816111de576111de81612954565b3d60208201f35b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03811615806112265750336001600160a01b038216145b6112425760405162461bcd60e51b815260040161078e90613a7e565b61124b83612c6c565b6112905760405162461bcd60e51b81526020600482015260166024820152751b59dd93d999995c8bd8589bdc9d0bdc995b9959d95960521b604482015260640161078e565b60006112a0846080013585612c84565b11156112ee5760405162461bcd60e51b815260206004820152601860248201527f6d67764f666665722f61626f72742f6765744661696c65640000000000000000604482015260640161078e565b50919050565b6112fc6125f1565b6001600160a01b0316336001600160a01b03161461132c5760405162461bcd60e51b815260040161078e90613a7e565b60001982036113c6576040516370a0823160e01b81523060048201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa158015611399573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113bd9190613cd7565b9150811561155f575b604051632e1a7d4d60e01b8152600481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024016020604051808303816000875af115801561142d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114519190613ab5565b6114ab5760405162461bcd60e51b815260206004820152602560248201527f6d67764f666665722f776974686472617746726f6d4d67762f776974686472616044820152641dd1985a5b60da1b606482015260840161078e565b6000816001600160a01b03168360405160006040518083038185875af1925050503d80600081146114f8576040519150601f19603f3d011682016040523d82523d6000602084013e6114fd565b606091505b505090508061090a5760405162461bcd60e51b815260206004820152602860248201527f6d67764f666665722f776974686472617746726f6d4d67762f70617961626c6560448201526710d85b1b11985a5b60c21b606482015260840161078e565b5050565b61156b6125f1565b6001600160a01b0316336001600160a01b031614806115b25750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6115ce5760405162461bcd60e51b815260040161078e90613a7e565b6000806001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663b61dce5960e01b8787878761160f611da3565b604051602401611623959493929190613e0b565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b03199094169390931790925290516116619190613bba565b600060405180830381855af49150503d806000811461169c576040519150601f19603f3d011682016040523d82523d6000602084013e6116a1565b606091505b509150915081610a0c57610a0c81612954565b6116bc6125f1565b6001600160a01b0316336001600160a01b031614806117035750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b61171f5760405162461bcd60e51b815260040161078e90613a7e565b6001610aed6127a6565b600080611734612782565b600101546001600160a01b03161415919050565b6117506125f1565b6001600160a01b0316336001600160a01b031614806117975750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6117b35760405162461bcd60e51b815260040161078e90613a7e565b806117bc6127a6565b6008015550565b60006117cd6127a6565b6009015460ff16919050565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152600019602483015282169063095ea7b3906044016020604051808303816000875af1158015611849573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061186d9190613ab5565b610a125760405162461bcd60e51b815260206004820152601d60248201527f6d67764f666665722f617070726f76654d616e67726f76652f4661696c000000604482015260640161078e565b60006118c36125f1565b6001600160a01b0316336001600160a01b0316148061190a5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6119265760405162461bcd60e51b815260040161078e90613a7e565b60405163ad97db1b60e01b81526001600160a01b03868116600483015285811660248301526044820185905283151560648301527f0000000000000000000000000000000000000000000000000000000000000000169063ad97db1b906084016020604051808303816000875af11580156119a5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119c99190613cd7565b90508015610c0a57604051632e1a7d4d60e01b8152600481018290527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690632e1a7d4d906024016020604051808303816000875af1158015611a38573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a5c9190613ab5565b611ab85760405162461bcd60e51b815260206004820152602760248201527f53696e676c65557365722f776974686472617746726f6d4d67762f77697468646044820152661c985dd1985a5b60ca1b606482015260840161078e565b604051600090339083908381818185875af1925050503d8060008114611afa576040519150601f19603f3d011682016040523d82523d6000602084013e611aff565b606091505b5050905080611b505760405162461bcd60e51b815260206004820152601a60248201527f53696e676c65557365722f7765695472616e736665724661696c000000000000604482015260640161078e565b50949350505050565b611b616125f1565b6001600160a01b0316336001600160a01b03161480611ba85750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b611bc45760405162461bcd60e51b815260040161078e90613a7e565b80611bcd6127a6565b6007015550565b6000611bde6125f1565b6001600160a01b0316336001600160a01b031614611c0e5760405162461bcd60e51b815260040161078e90613a7e565b6000611c186127a6565b9050835b83811015611d8a578515611cd1576000826000018281548110611c4157611c41613ad2565b906000526020600020015411611c58576000611cc4565b611cc47f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000846000018481548110611cb257611cb2613ad2565b906000526020600020015460016118b9565b611cce9084613e3f565b92505b851580611cde5750600186115b15611d78576000826001018281548110611cfa57611cfa613ad2565b906000526020600020015411611d11576000611d6b565b611d6b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000846001018481548110611cb257611cb2613ad2565b611d759084613e3f565b92505b80611d8281613afe565b915050611c1c565b50509392505050565b6000611d9e30612d50565b905090565b6000611dad611729565b15611e2e57611dba61260a565b6001600160a01b0316630417ffda6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611df7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e1b9190613cd7565b611e23612782565b54611d9e9190613e3f565b611e36612782565b54919050565b611e446125f1565b6001600160a01b0316336001600160a01b031614611e745760405162461bcd60e51b815260040161078e90613a7e565b6000611e7e6127a6565b60006002820181905560039091015550565b611e986125f1565b6001600160a01b0316336001600160a01b03161480611edf5750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b611efb5760405162461bcd60e51b815260040161078e90613a7e565b6001600160a01b038116611f515760405162461bcd60e51b815260206004820152601c60248201527f6d67764f666665722f7365745f726f757465722f3078526f7574657200000000604482015260640161078e565b80611f5a612782565b60010180546001600160a01b0319166001600160a01b039283161790556040516381bac14f60e01b8152306004820152908216906381bac14f90602401600060405180830381600087803b158015611fb157600080fd5b505af1158015611fc5573d6000803e3d6000fd5b50506040516001600160a01b03841681527f6de4326a8b9054d72d9dbab97d27bc4edffadee7d966f5af9cc4eafdaf8e5455925060200190505b60405180910390a150565b612012613473565b61201a6125f1565b6001600160a01b0316336001600160a01b03161461204a5760405162461bcd60e51b815260040161078e90613a7e565b60006120546127a6565b6040805180820190915260028201548152600390910154602082015291505090565b600080806001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001663cbf75c9a89896040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044016040805180830381865afa1580156120f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121199190613e57565b9150915060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316635722647b6121558b90565b8a6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101889052606401602060405180830381865afa1580156121a8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121cc9190613cd7565b9050600086604085901c61ffff1611156121ef575061ffff604084901c166121f2565b50855b62ffffff881061220757612204611da3565b97505b60008161221d62ffffff606087901c168b613e3f565b6122279190613e7b565b61223590633b9aca00613e7b565b9050600061ffff602085901c1661225c62ffffff603087901c811690604888901c16613e3f565b6122669190613e7b565b61227490633b9aca00613e7b565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa1580156122de573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123029190613cd7565b61230c9083613e3f565b905082811015612325576123208184613e9a565b612328565b60005b9d9c50505050505050505050505050565b6123416125f1565b6001600160a01b0316336001600160a01b0316146123715760405162461bcd60e51b815260040161078e90613a7e565b6001600160a01b0381166123c75760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e0000000000000000604482015260640161078e565b806123d061275e565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6000806123fc612782565b600101546001600160a01b03169050801561249d57806001600160a01b03166305684fde84612429611d93565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604401602060405180830381865afa158015612474573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124989190613cd7565b6108b7565b826001600160a01b03166370a082316124b4611d93565b6040516001600160e01b031960e084901b1681526001600160a01b039091166004820152602401602060405180830381865afa1580156124f8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b79190613cd7565b806001600160a01b031663095ea7b361253361260a565b6040516001600160e01b031960e084901b1681526001600160a01b03909116600482015260001960248201526044016020604051808303816000875af1158015612581573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125a59190613ab5565b610a125760405162461bcd60e51b815260206004820152601b60248201527f6d67764f666665722f617070726f7665526f757465722f4661696c0000000000604482015260640161078e565b60006125fb61275e565b546001600160a01b0316919050565b600080612615612782565b600101546001600160a01b0316905080610f4a5760405162461bcd60e51b815260206004820152601160248201527036b3bb27b33332b917983c2937baba32b960791b604482015260640161078e565b61266d6125f1565b6001600160a01b0316336001600160a01b031614806126b45750336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016145b6126d05760405162461bcd60e51b815260040161078e90613a7e565b808162ffffff16146127245760405162461bcd60e51b815260206004820152601860248201527f6d67764f666665722f6761737265712f6f766572666c6f770000000000000000604482015260640161078e565b8061272d612782565b556040518181527fafef3ad374c0b972e3c793be825735801fa05cc4c67157d98d9a111b4027988d90602001611fff565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7fae7e31c3220e851db9f204a28b279dfe52b973600b0a456991089c220ae7222490565b7f416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb8190565b60008115806127e157506001600160a01b03831630145b156127ee575060016108b7565b604080516001600160a01b038581166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b179052915160009283929088169161284a9190613bba565b6000604051808303816000865af19150503d8060008114612887576040519150601f19603f3d011682016040523d82523d6000602084013e61288c565b606091505b50915091508180156128b65750805115806128b65750808060200190518101906128b69190613ab5565b9695505050505050565b6128c8611729565b1561294b576128d561260a565b6001600160a01b031663a01dccd8826128ec611d93565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260440160006040518083038186803b15801561293257600080fd5b505afa158015612946573d6000803e3d6000fd5b505050505b610a1281612d80565b80516000036129a55760405162461bcd60e51b815260206004820152601b60248201527f4d616e676f53746f726167652f7265766572744e6f526561736f6e0000000000604482015260640161078e565b805160208201fd5b6000806129b86127a6565b905060006129c584612e70565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166129fe6020860186613789565b6001600160a01b031603612a305780612a2457612a1a846130a5565b6002830155612a50565b60006002830155612a50565b80612a4857612a3e846130a5565b6003830155612a50565b600060038301555b6000806001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166311b1025960e01b87612a8e611da3565b604051602401612a9f929190613eb1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b0319909416939093179092529051612add9190613bba565b600060405180830381855af49150503d8060008114612b18576040519150601f19603f3d011682016040523d82523d6000602084013e612b1d565b606091505b509150915081612b3557612b3081612954565b612b49565b808060200190518101906128b69190613ab5565b50505050919050565b60015b92915050565b6001600160a01b038116612ba85760405162461bcd60e51b815260206004820152601460248201527353696e676c65557365722f30785265736572766560601b604482015260640161078e565b80612bb1612782565b6001600160a01b0393841660009081526002919091016020526040902080546001600160a01b031916919093161790915550565b612bee816117d9565b612bf6611729565b15610a1257612c048161251c565b612c0c61260a565b604051630716a76760e21b81526001600160a01b0383811660048301529190911690631c5a9d9c90602401600060405180830381600087803b158015612c5157600080fd5b505af1158015612c65573d6000803e3d6000fd5b5050505050565b6000612c766127a6565b6009015460ff161592915050565b600080612c9f612c976020850185613789565b85600061311d565b9050838110612cb2576000915050612b55565b6000612cc16020850185613789565b6040516370a0823160e01b81523060048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015612d07573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d2b9190613cd7565b905084811015612d4457612d3f8186613e9a565b612d47565b60005b92505050612b55565b6000612d5a612782565b6001600160a01b0392831660009081526002919091016020526040902054909116919050565b604051636eb1769f60e11b81523060048201526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660248301526000919083169063dd62ed3e90604401602060405180830381865afa158015612df0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e149190613cd7565b11610a125760405162461bcd60e51b815260206004820152602660248201527f4d616e67726f76654f666665722f41646d696e4d757374417070726f76654d616044820152656e67726f766560d01b606482015260840161078e565b6000612e7b826131e6565b506000612e87836130a5565b905080600003612e9a5750600192915050565b6000612ea584613297565b90506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016636a4f7691612ee36020870187613789565b612ef36040880160208901613789565b848660c08a013560481c62ffffff1660c08b013560201c61ffff1660608c013560c01c63ffffffff168c604001356040518963ffffffff1660e01b8152600401612f44989796959493929190613b17565b600060405180830381600087803b158015612f5e57600080fd5b505af1925050508015612f6f575060015b61309b573d808015612f9d576040519150601f19603f3d011682016040523d82523d6000602084013e612fa2565b606091505b50805160208201207fc5fc8c2459087ad4f0e957e465df485864a3b1a379c2653ffe7c554981ede670016130905760408501803590612fe49060208801613789565b6001600160a01b0316612ffa6020880188613789565b6001600160a01b03167f736a3993b9f8b1c5603896c76376792887f376b1fe7fc981e09a16530bf1e4e07f000000000000000000000000000000000000000000000000000000000000000060405161308791906001600160a01b039190911681527f50657273697374656e742f686f6f6b2f6f75744f6650726f766973696f6e0000602082015260400190565b60405180910390a45b506000949350505050565b5060019392505050565b6000806130b06127a6565b90506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166130e96020850185613789565b6001600160a01b03160361310f578060020154613105846133b9565b6108b79190613e3f565b8060030154613105846133b9565b600080613128612782565b600101546001600160a01b03169050806131465760009150506108b7565b806001600160a01b031663333dbb0d8661315e611d93565b6040516001600160e01b031960e085901b1681526001600160a01b039283166004820152911660248201526044810187905285151560648201526084016020604051808303816000875af11580156131ba573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906131de9190613cd7565b9150506108b7565b604080516002808252606082018352600092839291906020830190803683370190505090506132186020840184613789565b8160008151811061322b5761322b613ad2565b6001600160a01b039092166020928302919091018201526132529060408501908501613789565b8160018151811061326557613265613ad2565b60200260200101906001600160a01b031690816001600160a01b03168152505061328e816133db565b50600192915050565b6000806132a3836130a5565b9050806000036132b65750600092915050565b6000807f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316631f92a31960e01b86856040516024016132fe929190613eb1565b60408051601f198184030181529181526020820180516001600160e01b03166001600160e01b031990941693909317909252905161333c9190613bba565b600060405180830381855af49150503d8060008114613377576040519150601f19603f3d011682016040523d82523d6000602084013e61337c565b606091505b5091509150816133945761338f81612954565b6133b1565b808060200190518101906133a89190613cd7565b95945050505050565b505050919050565b6000612b55608083013560608401356bffffffffffffffffffffffff16613e9a565b60006133e5612782565b600101546001600160a01b03169050806133fd575050565b806001600160a01b031663f850a81c83613415611d93565b6040518363ffffffff1660e01b8152600401613432929190613f3e565b600060405180830381600087803b1580156109f857600080fd5b60405180604001604052806002905b606081526020019060019003908161345b5790505090565b60405180604001604052806002906020820280368337509192915050565b6001600160a01b0381168114610a1257600080fd5b8035610f4a81613491565b6000806000606084860312156134c657600080fd5b83356134d181613491565b925060208401356134e181613491565b929592945050506040919091013590565b60008083601f84011261350457600080fd5b50813567ffffffffffffffff81111561351c57600080fd5b6020830191508360208260051b850101111561353757600080fd5b9250929050565b6000806020838503121561355157600080fd5b823567ffffffffffffffff81111561356857600080fd5b613574858286016134f2565b90969095509350505050565b634e487b7160e01b600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156135b9576135b9613580565b60405290565b604051601f8201601f1916810167ffffffffffffffff811182821017156135e8576135e8613580565b604052919050565b600061010080838503121561360457600080fd5b6040519081019067ffffffffffffffff8211818310171561362757613627613580565b816040528335915061363882613491565b818152613647602085016134a6565b602082015260408401356040820152606084013560608201526080840135608082015260a084013560a082015260c084013560c082015260e084013560e0820152809250505092915050565b8015158114610a1257600080fd5b6000602082840312156136b357600080fd5b81356108b781613693565b6020808252600090606083018382018584805b600281101561372657878503601f19018452825180518087529087019087870190845b81811015613710578351835292890192918901916001016136f4565b50909650505092850192918501916001016136d1565b5092979650505050505050565b600061012082840312156112ee57600080fd5b60008082840361016081121561375b57600080fd5b6137658585613733565b9250604061011f198201121561377a57600080fd5b50610120830190509250929050565b60006020828403121561379b57600080fd5b81356108b781613491565b600080600080600080600060c0888a0312156137c157600080fd5b87356137cc81613693565b9650602088013595506040880135945060608801359350608088013567ffffffffffffffff808211156137fe57600080fd5b818a0191508a60408301111561381357600080fd5b90935060a0890135908082111561382957600080fd5b506138368a828b016134f2565b989b979a50959850939692959293505050565b6000806020838503121561385c57600080fd5b823567ffffffffffffffff8082111561387457600080fd5b818501915085601f83011261388857600080fd5b81358181111561389757600080fd5b8660208285010111156138a957600080fd5b60209290920196919550909350505050565b600061012082840312156138ce57600080fd5b6108b78383613733565b600080604083850312156138eb57600080fd5b8235915060208301356138fd81613491565b809150509250929050565b6000806000806060858703121561391e57600080fd5b84359350602085013561393081613693565b9250604085013567ffffffffffffffff81111561394c57600080fd5b613958878288016134f2565b95989497509550505050565b60006020828403121561397657600080fd5b5035919050565b6000806000806080858703121561399357600080fd5b843561399e81613491565b935060208501356139ae81613491565b92506040850135915060608501356139c581613693565b939692955090935050565b6000806000606084860312156139e557600080fd5b505081359360208301359350604090920135919050565b60408101818360005b6002811015613a24578151835260209283019290910190600101613a05565b50505092915050565b600080600080600060a08688031215613a4557600080fd5b8535613a5081613491565b94506020860135613a6081613491565b94979496505050506040830135926060810135926080909101359150565b60208082526018908201527f416363657373436f6e74726f6c6c65642f496e76616c69640000000000000000604082015260600190565b600060208284031215613ac757600080fd5b81516108b781613693565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201613b1057613b10613ae8565b5060010190565b6001600160a01b03988916815296909716602087015260408601949094526060850192909252608084015260a083015260c082015260e08101919091526101000190565b60005b83811015613b76578181015183820152602001613b5e565b83811115610c9b5750506000910152565b6020815260008251806020840152613ba6816040850160208701613b5b565b601f01601f19169190910160400192915050565b60008251613bcc818460208701613b5b565b9190910192915050565b60006020808385031215613be957600080fd5b825167ffffffffffffffff80821115613c0157600080fd5b8185019150601f8681840112613c1657600080fd5b613c1e613596565b806040850189811115613c3057600080fd5b855b81811015613cc857805186811115613c4a5760008081fd5b87018581018c13613c5b5760008081fd5b805187811115613c6d57613c6d613580565b8060051b613c7c8b82016135bf565b9182528281018b01918b8101908f841115613c9957600092508283fd5b938c01935b83851015613cb75784518252938c0193908c0190613c9e565b885250505093880193508701613c32565b50909998505050505050505050565b600060208284031215613ce957600080fd5b5051919050565b81835260006001600160fb1b03831115613d0957600080fd5b8260051b8083602087013760009401602001938452509192915050565b600060e082018a1515835260208a8185015289604085015288606085015260e0608085015281829050610120850192508860005b6002811015613dce5786850360df190183528135368c9003601e19018112613d8157600080fd5b8b01848101903567ffffffffffffffff811115613d9d57600080fd5b8060051b3603821315613daf57600080fd5b613dba878284613cf0565b965050509183019190830190600101613d5a565b5050505082810360a0840152613de5818688613cf0565b9150508260c08301529998505050505050505050565b8183823760009101908152919050565b8581528415156020820152608060408201526000613e2d608083018587613cf0565b90508260608301529695505050505050565b60008219821115613e5257613e52613ae8565b500190565b60008060408385031215613e6a57600080fd5b505080516020909101519092909150565b6000816000190483118215151615613e9557613e95613ae8565b500290565b600082821015613eac57613eac613ae8565b500390565b61014081018335613ec181613491565b6001600160a01b03168252613ed8602085016134a6565b6001600160a01b03811660208401525060408401356040830152606084013560608301526080840135608083015260a084013560a083015260c084013560c083015260e084013560e0830152610100808501358184015250826101208301529392505050565b604080825283519082018190526000906020906060840190828701845b82811015613f805781516001600160a01b031684529284019290840190600101613f5b565b5050506001600160a01b03949094169201919091525091905056fea2646970667358221220eda5a761176852a8ab329af824a2d47f03b0814b39149756abb1553bda55eafb64736f6c634300080e0033608060405234801561001057600080fd5b5061c35033806100675760405162461bcd60e51b815260206004820152601860248201527f616363657373436f6e74726f6c6c65642f307841646d696e000000000000000060448201526064015b60405180910390fd5b8061007a61010a60201b6107e51760201c565b80546001600160a01b0319166001600160a01b03929092169190911790555062ffffff811681146100ed5760405162461bcd60e51b815260206004820152601660248201527f526f757465722f6f76657268656164546f6f4869676800000000000000000000604482015260640161005e565b8061010061012e60201b6108091760201c565b6001015550610152565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7ff2910982afb88211fa9894801aaf0314409ca240a0a8904897b9f5ba323ca53390565b610ea3806101616000396000f3fe608060405234801561001057600080fd5b50600436106100cf5760003560e01c8063362aecb11161008c578063cf5e7bd311610066578063cf5e7bd314610199578063e9333fab146101ac578063f850a81c146101bf578063f851a440146101d257600080fd5b8063362aecb11461016057806381bac14f14610173578063a01dccd81461018657600080fd5b80630417ffda146100d457806305684fde146100ef5780631c5a9d9c1461010257806321754d9e1461011757806326e8eda21461013a578063333dbb0d1461014d575b600080fd5b6100dc6101f2565b6040519081526020015b60405180910390f35b6100dc6100fd366004610bc3565b610205565b610115610110366004610bfc565b61027a565b005b61012a610125366004610c19565b6102cd565b60405190151581526020016100e6565b610115610148366004610c6a565b61030b565b6100dc61015b366004610cb9565b610341565b61012a61016e366004610bfc565b6103fd565b610115610181366004610bfc565b610429565b610115610194366004610bc3565b6104a7565b6101156101a7366004610bfc565b61057d565b6101156101ba366004610bfc565b6105ce565b6101156101cd366004610d0c565b6106b6565b6101da6107cc565b6040516001600160a01b0390911681526020016100e6565b60006101fc610809565b60010154905090565b6040516370a0823160e01b81526001600160a01b038281166004830152600091908416906370a0823190602401602060405180830381865afa15801561024f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102739190610d92565b9392505050565b6102826107cc565b6001600160a01b0316336001600160a01b031614806102a557506102a5336103fd565b6102ca5760405162461bcd60e51b81526004016102c190610dab565b60405180910390fd5b50565b60006102d8336103fd565b6102f45760405162461bcd60e51b81526004016102c190610dab565b6103008585858561082d565b90505b949350505050565b610314336103fd565b6103305760405162461bcd60e51b81526004016102c190610dab565b61033c8383338461083b565b505050565b600061034c336103fd565b6103685760405162461bcd60e51b81526004016102c190610dab565b6040516370a0823160e01b81523360048201526000906001600160a01b038716906370a0823190602401602060405180830381865afa1580156103af573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103d39190610d92565b90508381106103e6576000915050610303565b6103f38686338787610893565b9695505050505050565b6000610407610809565b6001600160a01b03909216600090815260209290925250604090205460ff1690565b6104316107cc565b6001600160a01b0316336001600160a01b031614806104545750610454336103fd565b6104705760405162461bcd60e51b81526004016102c190610dab565b600161047a610809565b6001600160a01b039290921660009081526020929092526040909120805460ff1916911515919091179055565b604051636eb1769f60e11b81523360048201523060248201526000906001600160a01b0384169063dd62ed3e90604401602060405180830381865afa1580156104f4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105189190610d92565b1161056f5760405162461bcd60e51b815260206004820152602160248201527f526f757465722f4e6f74417070726f76656442794d616b6572436f6e747261636044820152601d60fa1b60648201526084016102c1565b61057982826108ba565b5050565b6105856107cc565b6001600160a01b0316336001600160a01b031614806105a857506105a8336103fd565b6105c45760405162461bcd60e51b81526004016102c190610dab565b600061047a610809565b6105d66107cc565b6001600160a01b0316336001600160a01b0316146106365760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f496e76616c6964000000000000000060448201526064016102c1565b6001600160a01b03811661068c5760405162461bcd60e51b815260206004820152601860248201527f416363657373436f6e74726f6c6c65642f307841646d696e000000000000000060448201526064016102c1565b806106956107e5565b80546001600160a01b0319166001600160a01b039290921691909117905550565b6106bf336103fd565b6106db5760405162461bcd60e51b81526004016102c190610dab565b60005b828110156107c65760008484838181106106fa576106fa610dd8565b905060200201602081019061070f9190610bfc565b6040516370a0823160e01b81523360048201526001600160a01b0391909116906370a0823190602401602060405180830381865afa158015610755573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107799190610d92565b905080156107b3576107b385858481811061079657610796610dd8565b90506020020160208101906107ab9190610bfc565b84338461083b565b50806107be81610dee565b9150506106de565b50505050565b60006107d66107e5565b546001600160a01b0316919050565b7f7d382ebca3e46505071795e192d28166a3d4bd0685585591bc6c5b8df6769fd290565b7ff2910982afb88211fa9894801aaf0314409ca240a0a8904897b9f5ba323ca53390565b600061030085858585610998565b61084784838584610998565b6107c65760405162461bcd60e51b815260206004820152601e60248201527f53696d706c65526f757465722f707573682f7472616e736665724661696c000060448201526064016102c1565b60006108a186868686610998565b156108ad5750816108b1565b5060005b95945050505050565b6001600160a01b0381163014806109425750604051636eb1769f60e11b81526001600160a01b0382811660048301523060248301526000919084169063dd62ed3e90604401602060405180830381865afa15801561091c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109409190610d92565b115b6105795760405162461bcd60e51b815260206004820152602160248201527f53696d706c65526f757465722f4e6f74417070726f76656442795265736572766044820152606560f81b60648201526084016102c1565b60008115806109b85750826001600160a01b0316846001600160a01b0316145b156109c557506001610303565b306001600160a01b038516036109e7576109e0858484610ac2565b9050610303565b604080516001600160a01b0386811660248301528581166044830152606480830186905283518084039091018152608490920183526020820180516001600160e01b03166323b872dd60e01b1790529151600092839290891691610a4b9190610e15565b6000604051808303816000865af19150503d8060008114610a88576040519150601f19603f3d011682016040523d82523d6000602084013e610a8d565b606091505b5091509150818015610ab7575080511580610ab7575080806020019051810190610ab79190610e50565b979650505050505050565b6000811580610ad957506001600160a01b03831630145b15610ae657506001610273565b604080516001600160a01b038581166024830152604480830186905283518084039091018152606490920183526020820180516001600160e01b031663a9059cbb60e01b1790529151600092839290881691610b429190610e15565b6000604051808303816000865af19150503d8060008114610b7f576040519150601f19603f3d011682016040523d82523d6000602084013e610b84565b606091505b50915091508180156103f35750805115806103f35750808060200190518101906103f39190610e50565b6001600160a01b03811681146102ca57600080fd5b60008060408385031215610bd657600080fd5b8235610be181610bae565b91506020830135610bf181610bae565b809150509250929050565b600060208284031215610c0e57600080fd5b813561027381610bae565b60008060008060808587031215610c2f57600080fd5b8435610c3a81610bae565b93506020850135610c4a81610bae565b92506040850135610c5a81610bae565b9396929550929360600135925050565b600080600060608486031215610c7f57600080fd5b8335610c8a81610bae565b92506020840135610c9a81610bae565b929592945050506040919091013590565b80151581146102ca57600080fd5b60008060008060808587031215610ccf57600080fd5b8435610cda81610bae565b93506020850135610cea81610bae565b9250604085013591506060850135610d0181610cab565b939692955090935050565b600080600060408486031215610d2157600080fd5b833567ffffffffffffffff80821115610d3957600080fd5b818601915086601f830112610d4d57600080fd5b813581811115610d5c57600080fd5b8760208260051b8501011115610d7157600080fd5b60209283019550935050840135610d8781610bae565b809150509250925092565b600060208284031215610da457600080fd5b5051919050565b602080825260139082015272149bdd5d195c8bdd5b985d5d1a1bdc9a5e9959606a1b604082015260600190565b634e487b7160e01b600052603260045260246000fd5b600060018201610e0e57634e487b7160e01b600052601160045260246000fd5b5060010190565b6000825160005b81811015610e365760208186018101518583015201610e1c565b81811115610e45576000828501525b509190910192915050565b600060208284031215610e6257600080fd5b815161027381610cab56fea26469706673582212201a5909cf162cba146fb1ddb06cb563c76c816c7430eb8e8f45d62b5cb8ea878a64736f6c634300080e00336101606040523480156200001257600080fd5b5060405162002d1938038062002d198339810160408190526200003591620000ab565b6001600160a01b039586166101405293851660e05291909316610100526080919091526001600160601b0391821660a0521660c05233610120526200012b565b6001600160a01b03811681146200008b57600080fd5b50565b80516001600160601b0381168114620000a657600080fd5b919050565b60008060008060008060c08789031215620000c557600080fd5b8651620000d28162000075565b6020880151909650620000e58162000075565b6040880151909550620000f88162000075565b935062000108606088016200008e565b925062000118608088016200008e565b915060a087015190509295509295509295565b60805160a05160c05160e0516101005161012051610140516129d46200034560003960008181610735015281816108f101528181610b7201528181610cb201528181610f1f01528181611140015281816114cf0152818161180201528181611c1701528181611d7101528181611e7301528181611fb7015281816120f401526121f601526000818160fa0152818161044c0152610dc50152600081816107850152818161092001528181610ba101528181610d0201528181610f4e015281816110f2015281816111900152818161151f015281816116640152818161183101528181611c6701528181611dc101528181611ec301528181611fe6015281816121230152612225015260008181610151015281816103a9015281816107640152818161094101528181610bc201528181610ce101528181610f6f0152818161116f0152818161130e015281816114fe015281816118520152818161197f01528181611a2701528181611c4601528181611da001528181611ea201528181612007015281816121440152612246015260006122ee01526000818161133c01526113a1015260008181610293015281816102e9015281816104e90152818161051d01528181610553015281816105e201528181610a2001528181610a8501528181610af001528181610ec2015281816113d80152818161145b0152818161168f0152818161172f01528181611b710152611ba901526129d46000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c806311b102591461005c5780631f92a319146100845780633234fdc0146100a5578063663d2e0c146100ba578063b61dce59146100da575b600080fd5b61006f61006a3660046123a3565b6100ed565b60405190151581526020015b60405180910390f35b6100976100923660046123a3565b610396565b60405190815260200161007b565b6100b86100b3366004612436565b610441565b005b6100cd6100c83660046124de565b610a07565b60405161007b91906124f9565b6100b86100e836600461256e565b610dba565b6000306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146101405760405162461bcd60e51b8152600401610137906125d0565b60405180910390fd5b60008051602061297f8339815191527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166101866020860186612607565b6001600160a01b03160361026a5760408085013560009081526005830160205290812054906101b482610e9e565b9050801561022c576101e16101d26101cd600184612646565b610ee6565b60008860a00135600089610f08565b60088301546101f1600183612646565b11610220576040517f5ac608c951fb4eeda3d62e6a244a32d697d994fdcdf2ff4ca1ff1b5dde368a0d90600090a15b60019350505050610390565b60405162461bcd60e51b81526020600482015260136024820152724d616e676f2f4269644f75744f6652616e676560681b6044820152606401610137565b604080850135600090815260048301602052908120549061028a82610e9e565b90506102b760017f0000000000000000000000000000000000000000000000000000000000000000612646565b811015610352576102de6102cf6101cd83600161265d565b60008860a00135600089611129565b600883015461030d907f0000000000000000000000000000000000000000000000000000000000000000612646565b61031882600161265d565b10610220576040517f3c8e6c8b637216f202e5b335b54c0abfc6c1b6952a8a2511de149d2f3e5e7e9290600090a160019350505050610390565b60405162461bcd60e51b81526020600482015260136024820152724d616e676f2f41736b4f75744f6652616e676560681b6044820152606401610137565b92915050565b600060008051602061297f8339815191527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166103de6020860186612607565b6001600160a01b03160361041b57604080850135600090815260058301602052205461041261040c82610e9e565b85611338565b92505050610390565b604080850135600090815260048301602052205461041261043b82610e9e565b85611389565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146104895760405162461bcd60e51b8152600401610137906125d0565b60008051602061297f8339815191528686116104e75760405162461bcd60e51b815260206004820152601d60248201527f4d616e676f2f696e697469616c697a652f696e76616c6964536c6963650000006044820152606401610137565b7f000000000000000000000000000000000000000000000000000000000000000083148015610514575060015b801561054a57507f0000000000000000000000000000000000000000000000000000000000000000610546868061268b565b9050145b801561058357507f000000000000000000000000000000000000000000000000000000000000000061057f602087018761268b565b9050145b6105db5760405162461bcd60e51b815260206004820152602360248201527f4d616e676f2f696e697469616c697a652f696e76616c696441727261794c656e6044820152620cee8d60eb1b6064820152608401610137565b61060660017f0000000000000000000000000000000000000000000000000000000000000000612646565b88106106545760405162461bcd60e51b815260206004820152601e60248201527f4d616e676f2f696e697469616c697a652f4e6f536c6f74466f7241736b7300006044820152606401610137565b865b868110156109fb57600061066982610ee6565b905089821161083057600061067e888061268b565b8481811061068e5761068e612675565b905060200201359050600081116106e257600083116106ae5760006106e4565b836001016106c26001856101cd9190612646565b815481106106d2576106d2612675565b90600052602060002001546106e4565b805b905061070b828d8989878181106106fd576106fd612675565b905060200201358489610f08565b600084600001838154811061072257610722612675565b9060005260206000200154111561082a577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad97db1b7f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000008760000186815481106107b9576107b9612675565b906000526020600020015460006040518563ffffffff1660e01b81526004016107e594939291906126d5565b6020604051808303816000875af1158015610804573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061082891906126fe565b505b506109e8565b600061083f602089018961268b565b8481811061084f5761084f612675565b9050602002013590506000811161089e576000831161086f5760006108a0565b8361087e6101cd600186612646565b8154811061088e5761088e612675565b90600052602060002001546108a0565b805b90506108c7828d8989878181106108b9576108b9612675565b905060200201358489611129565b60008460010183815481106108de576108de612675565b906000526020600020015411156109e6577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad97db1b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000087600101868154811061097557610975612675565b906000526020600020015460006040518563ffffffff1660e01b81526004016109a194939291906126d5565b6020604051808303816000875af11580156109c0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e491906126fe565b505b505b50806109f381612717565b915050610656565b50505050505050505050565b610a0f61237c565b60008051602061297f8339815191527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff811115610a5757610a57612730565b604051908082528060200260200182016040528015610a80578160200160208202803683370190505b5082527f000000000000000000000000000000000000000000000000000000000000000067ffffffffffffffff811115610abc57610abc612730565b604051908082528060200260200182016040528015610ae5578160200160208202803683370190505b50602083015260005b7f0000000000000000000000000000000000000000000000000000000000000000811015610db357600082610b2283610ee6565b81548110610b3257610b32612675565b90600052602060002001549050600083600101610b4e84610ee6565b81548110610b5e57610b5e612675565b906000526020600020015490506000610c4d7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000866040518463ffffffff1660e01b8152600401610c0093929190612746565b602060405180830381865afa158015610c1d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c4191906126fe565b6001600160601b031690565b1180610c57575085155b610c62576000610c8b565b83600101610c6f84610ee6565b81548110610c7f57610c7f612675565b90600052602060002001545b8551805185908110610c9f57610c9f612675565b6020026020010181815250506000610d407f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000876040518463ffffffff1660e01b8152600401610c0093929190612746565b1180610d4a575085155b610d55576000610d7b565b83610d5f84610ee6565b81548110610d6f57610d6f612675565b90600052602060002001545b6020860151805185908110610d9257610d92612675565b60200260200101818152505050508080610dab90612717565b915050610aee565b5050919050565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610e025760405162461bcd60e51b8152600401610137906125d0565b60008512610e105784610e19565b610e198561276a565b8214610e675760405162461bcd60e51b815260206004820181905260248201527f4d616e676f2f7365745f73686966742f6e6f74456e6f756768416d6f756e74736044820152606401610137565b6000851215610e8a57610e85610e7c8661276a565b858585856113c7565b610e97565b610e97858585858561171e565b5050505050565b600061039060008051602061297f83398151915260060154610ec09084612786565b7f00000000000000000000000000000000000000000000000000000000000000006119e0565b600061039060008051602061297f83398151915260060154610ec090846127c5565b600060008051602061297f833981519152905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000856001018b81548110610fa357610fa3612675565b90600052602060002001546040518463ffffffff1660e01b8152600401610fcc93929190612746565b602060405180830381865afa158015610fe9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100d91906126fe565b9050600061101a88610e9e565b905060008761104a57600384015461103b6001600160601b0385168961265d565b611045919061265d565b61104c565b865b9050600061105a8383611389565b905060006001600160601b0385166000036110c957871561107c5750866110ec565b83156110b857856001016110966001866101cd9190612646565b815481106110a6576110a6612675565b906000526020600020015490506110ec565b6110c28560e01c90565b90506110ec565b856001018b815481106110de576110de612675565b906000526020600020015490505b61111c8b7f000000000000000000000000000000000000000000000000000000000000000084868b8f1587611a0e565b5050505050505050505050565b600060008051602061297f833981519152905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000856000018b815481106111c4576111c4612675565b90600052602060002001546040518463ffffffff1660e01b81526004016111ed93929190612746565b602060405180830381865afa15801561120a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061122e91906126fe565b9050600061123b88610e9e565b905060008761126b57600284015461125c6001600160601b0385168961265d565b611266919061265d565b61126d565b865b9050600061127b8383611338565b905060006001600160601b0385166000036112e557871561129d575086611308565b83156112d457856112b26101cd600187612646565b815481106112c2576112c2612675565b90600052602060002001549050611308565b6112de8560e01c90565b9050611308565b856000018b815481106112fa576112fa612675565b906000526020600020015490505b61111c8b7f000000000000000000000000000000000000000000000000000000000000000084868b8f1587611a0e565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160601b03168261136e85611b3b565b6113789190612806565b611382919061283b565b9392505050565b600061139483611b3b565b6113786001600160601b037f00000000000000000000000000000000000000000000000000000000000000001684612806565b60008051602061297f8339815191527f0000000000000000000000000000000000000000000000000000000000000000861061144f5760405162461bcd60e51b815260206004820152602160248201527f4d616e676f2f73686966742f4e656761746976655368696674546f6f4c6172676044820152606560f81b6064820152608401610137565b600061147f6101cd60017f0000000000000000000000000000000000000000000000000000000000000000612646565b9050868260060160008282546114959190612786565b90915550600090505b87811015611714578260000182815481106114bb576114bb612675565b90600052602060002001546000146115c4577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad97db1b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086600001868154811061155357611553612675565b906000526020600020015460006040518563ffffffff1660e01b815260040161157f94939291906126d5565b6020604051808303816000875af115801561159e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c291906126fe565b505b60006115cf83610e9e565b9050600080891561161e578888858181106115ec576115ec612675565b905060200201359050611617838a8a8781811061160b5761160b612675565b90506020020135611338565b915061165e565b611640838a8a8781811061163457611634612675565b90506020020135611389565b905088888581811061165457611654612675565b9050602002013591505b6116f4857f000000000000000000000000000000000000000000000000000000000000000083858b60006116b360017f0000000000000000000000000000000000000000000000000000000000000000612646565b8a106116c0576000611a0e565b8c6001016116d48b60016101cd919061265d565b815481106116e4576116e4612675565b9060005260206000200154611a0e565b836116fe81612717565b94505061170a85611b61565b945050505061149e565b5050505050505050565b60008051602061297f8339815191527f000000000000000000000000000000000000000000000000000000000000000086106117a65760405162461bcd60e51b815260206004820152602160248201527f4d616e676f2f73686966742f706f7369746976655368696674546f6f4c6172676044820152606560f81b6064820152608401610137565b60006117b26000610ee6565b9050868260060160008282546117c891906127c5565b90915550600090505b87811015611714578260010182815481106117ee576117ee612675565b90600052602060002001546000146118f7577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663ad97db1b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086600101868154811061188657611886612675565b906000526020600020015460006040518563ffffffff1660e01b81526004016118b294939291906126d5565b6020604051808303816000875af11580156118d1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118f591906126fe565b505b600061190283610e9e565b905060008089156119455788888581811061191f5761191f612675565b90506020020135915061193e838a8a8781811061160b5761160b612675565b9050611979565b88888581811061195757611957612675565b905060200201359050611976838a8a8781811061163457611634612675565b91505b6119c0857f000000000000000000000000000000000000000000000000000000000000000083858b6000808a116119b1576000611a0e565b8c6116d46101cd60018d612646565b836119ca81612717565b9450506119d685611ba5565b94505050506117d1565b60008083126119fa576119f3828461284f565b9050610390565b611a048284612863565b6119f390836127c5565b60008051602061297f8339815191526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811690881603611ac3576000611a816040518060a001604052808b815260200189815260200188815260200187815260200185815250611bdd565b90508015611aaf5783611aa357808260020154611a9e919061265d565b611aa5565b805b6002830155611abd565b8315611abd57600060028301555b50611714565b6000611af46040518060a001604052808b815260200189815260200188815260200187815260200185815250611f5c565b90508015611b225783611b1657808260030154611b11919061265d565b611b18565b805b6003830155611b30565b8315611b3057600060038301555b505050505050505050565b600061039060008051602061297f8339815191526007015483611b5c61227e565b612365565b6000808211611b9a57611b9560017f0000000000000000000000000000000000000000000000000000000000000000612646565b610390565b610390600183612646565b60007f0000000000000000000000000000000000000000000000000000000000000000611bd383600161265d565b610390919061284f565b805160008051602061297f833981519152805460009282918110611c0357611c03612675565b9060005260206000200154600003611d6f577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349f6d2dc7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086602001518760400151886060015160008a608001516040518863ffffffff1660e01b8152600401611cbe9796959493929190612877565b6020604051808303816000875af1925050508015611cf9575060408051601f3d908101601f19168201909252611cf6918101906126fe565b60015b611d065750506040015190565b83518254829184918110611d1c57611d1c612675565b60009182526020822001919091558451835490916005850191859084908110611d4757611d47612675565b9060005260206000200154815260200190815260200160002081905550600092505050919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a4f76917f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086602001518760400151886060015160008a60800151896000018c6000015181548110611e0f57611e0f612675565b90600052602060002001546040518963ffffffff1660e01b8152600401611e3d9897969594939291906128b5565b600060405180830381600087803b158015611e5757600080fd5b505af1925050508015611e68575060015b611f53576000611f247f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086600001896000015181548110611efb57611efb612675565b90600052602060002001546040518463ffffffff1660e01b8152600401610c0093929190612746565b905080846040015111611f3b578360400151611f4b565b808460400151611f4b9190612646565b949350505050565b50600092915050565b80517f416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb82805460009260008051602061297f83398151915292918110611fa357611fa3612675565b90600052602060002001546000036120f2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166349f6d2dc7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086602001518760400151886060015160008a608001516040518863ffffffff1660e01b815260040161205e9796959493929190612877565b6020604051808303816000875af1925050508015612099575060408051601f3d908101601f19168201909252612096918101906126fe565b60015b6120a65750506040015190565b80826001018560000151815481106120c0576120c0612675565b9060005260206000200181905550836000015182600401600084600101876000015181548110611d4757611d47612675565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316636a4f76917f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086602001518760400151886060015160008a60800151896001018c600001518154811061219257612192612675565b90600052602060002001546040518963ffffffff1660e01b81526004016121c09897969594939291906128b5565b600060405180830381600087803b1580156121da57600080fd5b505af19250505080156121eb575060015b611f53576000611f247f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166368c13d6b7f00000000000000000000000000000000000000000000000000000000000000007f000000000000000000000000000000000000000000000000000000000000000086600101896000015181548110611efb57611efb612675565b7f416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb88547f416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb875460009160008051602061297f8339815191529183916122e0916128f9565b612313906001600160601b037f0000000000000000000000000000000000000000000000000000000000000000166127c5565b9050600081136103905760405162461bcd60e51b815260206004820152601e60248201527f4d616e676f2f71756f74655f6d696e2f5368696674556e646572666c6f7700006044820152606401610137565b6000816123728486612806565b611f4b919061265d565b60405180604001604052806002905b606081526020019060019003908161238b5790505090565b6000808284036101408112156123b857600080fd5b610120808212156123c857600080fd5b9395938601359450505050565b803580151581146123e557600080fd5b919050565b60008083601f8401126123fc57600080fd5b50813567ffffffffffffffff81111561241457600080fd5b6020830191508360208260051b850101111561242f57600080fd5b9250929050565b60008060008060008060008060e0898b03121561245257600080fd5b61245b896123d5565b9750602089013596506040890135955060608901359450608089013567ffffffffffffffff8082111561248d57600080fd5b818b0191508b6040830111156124a257600080fd5b90945060a08a013590808211156124b857600080fd5b506124c58b828c016123ea565b999c989b50969995989497949560c00135949350505050565b6000602082840312156124f057600080fd5b611382826123d5565b6020808252600090606083018382018584805b600281101561256157878503601f19018452825180518087529087019087870190845b8181101561254b5783518352928901929189019160010161252f565b509096505050928501929185019160010161250c565b5092979650505050505050565b60008060008060006080868803121561258657600080fd5b85359450612596602087016123d5565b9350604086013567ffffffffffffffff8111156125b257600080fd5b6125be888289016123ea565b96999598509660600135949350505050565b6020808252601f908201527f4d616e676f496d706c656d656e746174696f6e2f696e76616c696443616c6c00604082015260600190565b60006020828403121561261957600080fd5b81356001600160a01b038116811461138257600080fd5b634e487b7160e01b600052601160045260246000fd5b60008282101561265857612658612630565b500390565b6000821982111561267057612670612630565b500190565b634e487b7160e01b600052603260045260246000fd5b6000808335601e198436030181126126a257600080fd5b83018035915067ffffffffffffffff8211156126bd57600080fd5b6020019150600581901b360382131561242f57600080fd5b6001600160a01b0394851681529290931660208301526040820152901515606082015260800190565b60006020828403121561271057600080fd5b5051919050565b60006001820161272957612729612630565b5060010190565b634e487b7160e01b600052604160045260246000fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000600160ff1b820161277f5761277f612630565b5060000390565b60008083128015600160ff1b8501841216156127a4576127a4612630565b6001600160ff1b03840183138116156127bf576127bf612630565b50500390565b600080821280156001600160ff1b03849003851316156127e7576127e7612630565b600160ff1b839003841281161561280057612800612630565b50500190565b600081600019048311821515161561282057612820612630565b500290565b634e487b7160e01b600052601260045260246000fd5b60008261284a5761284a612825565b500490565b60008261285e5761285e612825565b500690565b60008261287257612872612825565b500790565b6001600160a01b03978816815295909616602086015260408501939093526060840191909152608083015260a082015260c081019190915260e00190565b6001600160a01b03988916815296909716602087015260408601949094526060850192909252608084015260a083015260c082015260e08101919091526101000190565b60006001600160ff1b038184138284138082168684048611161561291f5761291f612630565b600160ff1b600087128281168783058912161561293e5761293e612630565b6000871292508782058712848416161561295a5761295a612630565b8785058712818416161561297057612970612630565b50505092909302939250505056fe416b48c48a967c2245e6ba6bc6efa281932950b502fea671117e4dfd7d3dfb81a26469706673582212204805650d72dd5d373acfe22a70c407af43e35403f616d987c257084ef74b618b64736f6c634300080e0033416363657373436f6e74726f6c6c65642f496e76616c69640000000000000000000000000000000000000000f3e339d8a0b989114412fa157cc846ebaf4bcbd800000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e000000000000000000000000f61cffd6071a8db7cd5e8df1d3a5450d9903cf1c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000001c9c3800000000000000000000000005a6272e5d8690ad47df72bbf7fb08ce1851b8f54

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

000000000000000000000000f3e339d8a0b989114412fa157cc846ebaf4bcbd800000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e000000000000000000000000f61cffd6071a8db7cd5e8df1d3a5450d9903cf1c0000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000bebc20000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000001c9c3800000000000000000000000005a6272e5d8690ad47df72bbf7fb08ce1851b8f54

-----Decoded View---------------
Arg [0] : mgv (address): 0xf3e339d8a0b989114412fa157cc846ebaf4bcbd8
Arg [1] : base (address): 0x63e537a69b3f5b03f4f46c5765c82861bd874b6e
Arg [2] : quote (address): 0xf61cffd6071a8db7cd5e8df1d3a5450d9903cf1c
Arg [3] : base_0 (uint256): 1000000000000000000
Arg [4] : quote_0 (uint256): 200000000
Arg [5] : nslots (uint256): 100
Arg [6] : price_incr (uint256): 30000000
Arg [7] : deployer (address): 0x5a6272e5d8690ad47df72bbf7fb08ce1851b8f54

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 000000000000000000000000f3e339d8a0b989114412fa157cc846ebaf4bcbd8
Arg [1] : 00000000000000000000000063e537a69b3f5b03f4f46c5765c82861bd874b6e
Arg [2] : 000000000000000000000000f61cffd6071a8db7cd5e8df1d3a5450d9903cf1c
Arg [3] : 0000000000000000000000000000000000000000000000000de0b6b3a7640000
Arg [4] : 000000000000000000000000000000000000000000000000000000000bebc200
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000064
Arg [6] : 0000000000000000000000000000000000000000000000000000000001c9c380
Arg [7] : 0000000000000000000000005a6272e5d8690ad47df72bbf7fb08ce1851b8f54


Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading