ETH Price: $2,081.72 (-3.51%)

Transaction Decoder

Block:
8998671 at Nov-25-2019 01:11:10 PM +UTC
Transaction Fee:
0.003172457214 ETH $6.60
Gas Used:
158,607 Gas / 20.002 Gwei

Emitted Events:

113 Dai.Transfer( src=[Receiver] 0xa57bd00134b2850b2a1c55860c9e9ea100fdd6cf, dst=MatchingMarket, wad=21182265812504813313338 )
114 MatchingMarket.LogItemUpdate( id=625090 )
115 MatchingMarket.LogMake( id=00000000000000000000000000000000000000000000000000000000000989C2, pair=7BDA8B27E891F9687BD6D3312AB3F4F458E2CC91916429D721D617DF7AC29FB8, maker=[Receiver] 0xa57bd00134b2850b2a1c55860c9e9ea100fdd6cf, pay_gem=Dai, buy_gem=0xC02aaA39...83C756Cc2, pay_amt=21182265812504813313338, buy_amt=146231822042792003572, timestamp=1574687470 )
116 MatchingMarket.LogSortedOffer( id=625090 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...438691c04
0x0Bc4dAa6...aa822B29f
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x10586074...1D89E0959
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x39755357...a409AE24e
(Eth2Dai: Old Contract)
0x62c91d45...F0bdE3d40
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x6B175474...495271d0F
0xA220c455...2d0D97F7c
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
(MiningPoolHub: Old Address)
9,755.293718634206571507 Eth9,755.296891091420571507 Eth0.003172457214
0xD4e9AA76...8C99F0080
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0xF8c972D9...FC20531C1
0.36937303810945 Eth
Nonce: 1569
0.36620058089545 Eth
Nonce: 1570
0.003172457214
0xfD008501...693107F69
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0

Execution Trace

MEV Bot: 0xa57...6CF.1cff79cd( )
  • 0x2812bc7c99d157f9735192078841e96336bbd708.00000000( )
    • GasToken2.freeUpTo( value=6 ) => ( freed=6 )
      • 0x0bc4daa64081f470fb8714cd0a202b6aa822b29f.CALL( )
        • GasToken2.SELFDESTRUCT( )
        • 0xd4e9aa76d568210cb1787b2672684588c99f0080.CALL( )
          • GasToken2.SELFDESTRUCT( )
          • 0x62c91d456c19dbe8069bc6dce6f7de2f0bde3d40.CALL( )
            • GasToken2.SELFDESTRUCT( )
            • 0x10586074d91f78d16913407d33b6b251d89e0959.CALL( )
              • GasToken2.SELFDESTRUCT( )
              • 0xa220c455cf25c13b8a4dc924032025d2d0d97f7c.CALL( )
                • GasToken2.SELFDESTRUCT( )
                • 0xfd0085017db5294dc81fb56b908faa8693107f69.CALL( )
                  • GasToken2.SELFDESTRUCT( )
                  • MatchingMarket.offer( pay_amt=21182265812504813313338, pay_gem=0x6B175474E89094C44Da98b954EedeAC495271d0F, buy_amt=146231822042792003572, buy_gem=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, pos=624814 ) => ( 625090 )
                    • Dai.transferFrom( src=0xa57Bd00134B2850B2a1c55860c9e9ea100fDd6CF, dst=0x39755357759cE0d7f32dC8dC45414CCa409AE24e, wad=21182265812504813313338 ) => ( True )
                      File 1 of 3: MatchingMarket
                      /// matching_market.sol
                      
                      //
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU Affero General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      //
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU Affero General Public License for more details.
                      //
                      // You should have received a copy of the GNU Affero General Public License
                      // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.18;
                      
                      /// expiring_market.sol
                      
                      //
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU Affero General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      //
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU Affero General Public License for more details.
                      //
                      // You should have received a copy of the GNU Affero General Public License
                      // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.18;
                      
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU General Public License for more details.
                      
                      // You should have received a copy of the GNU General Public License
                      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.13;
                      
                      contract DSAuthority {
                          function canCall(
                              address src, address dst, bytes4 sig
                          ) public view returns (bool);
                      }
                      
                      contract DSAuthEvents {
                          event LogSetAuthority (address indexed authority);
                          event LogSetOwner     (address indexed owner);
                      }
                      
                      contract DSAuth is DSAuthEvents {
                          DSAuthority  public  authority;
                          address      public  owner;
                      
                          function DSAuth() public {
                              owner = msg.sender;
                              LogSetOwner(msg.sender);
                          }
                      
                          function setOwner(address owner_)
                              public
                              auth
                          {
                              owner = owner_;
                              LogSetOwner(owner);
                          }
                      
                          function setAuthority(DSAuthority authority_)
                              public
                              auth
                          {
                              authority = authority_;
                              LogSetAuthority(authority);
                          }
                      
                          modifier auth {
                              require(isAuthorized(msg.sender, msg.sig));
                              _;
                          }
                      
                          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
                              if (src == address(this)) {
                                  return true;
                              } else if (src == owner) {
                                  return true;
                              } else if (authority == DSAuthority(0)) {
                                  return false;
                              } else {
                                  return authority.canCall(src, this, sig);
                              }
                          }
                      }
                      
                      /// simple_market.sol
                      
                      //
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU Affero General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      //
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU Affero General Public License for more details.
                      //
                      // You should have received a copy of the GNU Affero General Public License
                      // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.18;
                      
                      /// math.sol -- mixin for inline numerical wizardry
                      
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU General Public License for more details.
                      
                      // You should have received a copy of the GNU General Public License
                      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.13;
                      
                      contract DSMath {
                          function add(uint x, uint y) internal pure returns (uint z) {
                              require((z = x + y) >= x);
                          }
                          function sub(uint x, uint y) internal pure returns (uint z) {
                              require((z = x - y) <= x);
                          }
                          function mul(uint x, uint y) internal pure returns (uint z) {
                              require(y == 0 || (z = x * y) / y == x);
                          }
                      
                          function min(uint x, uint y) internal pure returns (uint z) {
                              return x <= y ? x : y;
                          }
                          function max(uint x, uint y) internal pure returns (uint z) {
                              return x >= y ? x : y;
                          }
                          function imin(int x, int y) internal pure returns (int z) {
                              return x <= y ? x : y;
                          }
                          function imax(int x, int y) internal pure returns (int z) {
                              return x >= y ? x : y;
                          }
                      
                          uint constant WAD = 10 ** 18;
                          uint constant RAY = 10 ** 27;
                      
                          function wmul(uint x, uint y) internal pure returns (uint z) {
                              z = add(mul(x, y), WAD / 2) / WAD;
                          }
                          function rmul(uint x, uint y) internal pure returns (uint z) {
                              z = add(mul(x, y), RAY / 2) / RAY;
                          }
                          function wdiv(uint x, uint y) internal pure returns (uint z) {
                              z = add(mul(x, WAD), y / 2) / y;
                          }
                          function rdiv(uint x, uint y) internal pure returns (uint z) {
                              z = add(mul(x, RAY), y / 2) / y;
                          }
                      
                          // This famous algorithm is called "exponentiation by squaring"
                          // and calculates x^n with x as fixed-point and n as regular unsigned.
                          //
                          // It's O(log n), instead of O(n) for naive repeated multiplication.
                          //
                          // These facts are why it works:
                          //
                          //  If n is even, then x^n = (x^2)^(n/2).
                          //  If n is odd,  then x^n = x * x^(n-1),
                          //   and applying the equation for even x gives
                          //    x^n = x * (x^2)^((n-1) / 2).
                          //
                          //  Also, EVM division is flooring and
                          //    floor[(n-1) / 2] = floor[n / 2].
                          //
                          function rpow(uint x, uint n) internal pure returns (uint z) {
                              z = n % 2 != 0 ? x : RAY;
                      
                              for (n /= 2; n != 0; n /= 2) {
                                  x = rmul(x, x);
                      
                                  if (n % 2 != 0) {
                                      z = rmul(z, x);
                                  }
                              }
                          }
                      }
                      
                      /// erc20.sol -- API for the ERC20 token standard
                      
                      // See <https://github.com/ethereum/EIPs/issues/20>.
                      
                      // This file likely does not meet the threshold of originality
                      // required for copyright to apply.  As a result, this is free and
                      // unencumbered software belonging to the public domain.
                      
                      pragma solidity ^0.4.8;
                      
                      contract ERC20Events {
                          event Approval(address indexed src, address indexed guy, uint wad);
                          event Transfer(address indexed src, address indexed dst, uint wad);
                      }
                      
                      contract ERC20 is ERC20Events {
                          function totalSupply() public view returns (uint);
                          function balanceOf(address guy) public view returns (uint);
                          function allowance(address src, address guy) public view returns (uint);
                      
                          function approve(address guy, uint wad) public returns (bool);
                          function transfer(address dst, uint wad) public returns (bool);
                          function transferFrom(
                              address src, address dst, uint wad
                          ) public returns (bool);
                      }
                      
                      contract EventfulMarket {
                          event LogItemUpdate(uint id);
                          event LogTrade(uint pay_amt, address indexed pay_gem,
                                         uint buy_amt, address indexed buy_gem);
                      
                          event LogMake(
                              bytes32  indexed  id,
                              bytes32  indexed  pair,
                              address  indexed  maker,
                              ERC20             pay_gem,
                              ERC20             buy_gem,
                              uint128           pay_amt,
                              uint128           buy_amt,
                              uint64            timestamp
                          );
                      
                          event LogBump(
                              bytes32  indexed  id,
                              bytes32  indexed  pair,
                              address  indexed  maker,
                              ERC20             pay_gem,
                              ERC20             buy_gem,
                              uint128           pay_amt,
                              uint128           buy_amt,
                              uint64            timestamp
                          );
                      
                          event LogTake(
                              bytes32           id,
                              bytes32  indexed  pair,
                              address  indexed  maker,
                              ERC20             pay_gem,
                              ERC20             buy_gem,
                              address  indexed  taker,
                              uint128           take_amt,
                              uint128           give_amt,
                              uint64            timestamp
                          );
                      
                          event LogKill(
                              bytes32  indexed  id,
                              bytes32  indexed  pair,
                              address  indexed  maker,
                              ERC20             pay_gem,
                              ERC20             buy_gem,
                              uint128           pay_amt,
                              uint128           buy_amt,
                              uint64            timestamp
                          );
                      }
                      
                      contract SimpleMarket is EventfulMarket, DSMath {
                      
                          uint public last_offer_id;
                      
                          mapping (uint => OfferInfo) public offers;
                      
                          bool locked;
                      
                          struct OfferInfo {
                              uint     pay_amt;
                              ERC20    pay_gem;
                              uint     buy_amt;
                              ERC20    buy_gem;
                              address  owner;
                              uint64   timestamp;
                          }
                      
                          modifier can_buy(uint id) {
                              require(isActive(id));
                              _;
                          }
                      
                          modifier can_cancel(uint id) {
                              require(isActive(id));
                              require(getOwner(id) == msg.sender);
                              _;
                          }
                      
                          modifier can_offer {
                              _;
                          }
                      
                          modifier synchronized {
                              require(!locked);
                              locked = true;
                              _;
                              locked = false;
                          }
                      
                          function isActive(uint id) public constant returns (bool active) {
                              return offers[id].timestamp > 0;
                          }
                      
                          function getOwner(uint id) public constant returns (address owner) {
                              return offers[id].owner;
                          }
                      
                          function getOffer(uint id) public constant returns (uint, ERC20, uint, ERC20) {
                            var offer = offers[id];
                            return (offer.pay_amt, offer.pay_gem,
                                    offer.buy_amt, offer.buy_gem);
                          }
                      
                          // ---- Public entrypoints ---- //
                      
                          function bump(bytes32 id_)
                              public
                              can_buy(uint256(id_))
                          {
                              var id = uint256(id_);
                              LogBump(
                                  id_,
                                  keccak256(offers[id].pay_gem, offers[id].buy_gem),
                                  offers[id].owner,
                                  offers[id].pay_gem,
                                  offers[id].buy_gem,
                                  uint128(offers[id].pay_amt),
                                  uint128(offers[id].buy_amt),
                                  offers[id].timestamp
                              );
                          }
                      
                          // Accept given `quantity` of an offer. Transfers funds from caller to
                          // offer maker, and from market to caller.
                          function buy(uint id, uint quantity)
                              public
                              can_buy(id)
                              synchronized
                              returns (bool)
                          {
                              OfferInfo memory offer = offers[id];
                              uint spend = mul(quantity, offer.buy_amt) / offer.pay_amt;
                      
                              require(uint128(spend) == spend);
                              require(uint128(quantity) == quantity);
                      
                              // For backwards semantic compatibility.
                              if (quantity == 0 || spend == 0 ||
                                  quantity > offer.pay_amt || spend > offer.buy_amt)
                              {
                                  return false;
                              }
                      
                              offers[id].pay_amt = sub(offer.pay_amt, quantity);
                              offers[id].buy_amt = sub(offer.buy_amt, spend);
                              require( offer.buy_gem.transferFrom(msg.sender, offer.owner, spend) );
                              require( offer.pay_gem.transfer(msg.sender, quantity) );
                      
                              LogItemUpdate(id);
                              LogTake(
                                  bytes32(id),
                                  keccak256(offer.pay_gem, offer.buy_gem),
                                  offer.owner,
                                  offer.pay_gem,
                                  offer.buy_gem,
                                  msg.sender,
                                  uint128(quantity),
                                  uint128(spend),
                                  uint64(now)
                              );
                              LogTrade(quantity, offer.pay_gem, spend, offer.buy_gem);
                      
                              if (offers[id].pay_amt == 0) {
                                delete offers[id];
                              }
                      
                              return true;
                          }
                      
                          // Cancel an offer. Refunds offer maker.
                          function cancel(uint id)
                              public
                              can_cancel(id)
                              synchronized
                              returns (bool success)
                          {
                              // read-only offer. Modify an offer by directly accessing offers[id]
                              OfferInfo memory offer = offers[id];
                              delete offers[id];
                      
                              require( offer.pay_gem.transfer(offer.owner, offer.pay_amt) );
                      
                              LogItemUpdate(id);
                              LogKill(
                                  bytes32(id),
                                  keccak256(offer.pay_gem, offer.buy_gem),
                                  offer.owner,
                                  offer.pay_gem,
                                  offer.buy_gem,
                                  uint128(offer.pay_amt),
                                  uint128(offer.buy_amt),
                                  uint64(now)
                              );
                      
                              success = true;
                          }
                      
                          function kill(bytes32 id)
                              public
                          {
                              require(cancel(uint256(id)));
                          }
                      
                          function make(
                              ERC20    pay_gem,
                              ERC20    buy_gem,
                              uint128  pay_amt,
                              uint128  buy_amt
                          )
                              public
                              returns (bytes32 id)
                          {
                              return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
                          }
                      
                          // Make a new offer. Takes funds from the caller into market escrow.
                          function offer(uint pay_amt, ERC20 pay_gem, uint buy_amt, ERC20 buy_gem)
                              public
                              can_offer
                              synchronized
                              returns (uint id)
                          {
                              require(uint128(pay_amt) == pay_amt);
                              require(uint128(buy_amt) == buy_amt);
                              require(pay_amt > 0);
                              require(pay_gem != ERC20(0x0));
                              require(buy_amt > 0);
                              require(buy_gem != ERC20(0x0));
                              require(pay_gem != buy_gem);
                      
                              OfferInfo memory info;
                              info.pay_amt = pay_amt;
                              info.pay_gem = pay_gem;
                              info.buy_amt = buy_amt;
                              info.buy_gem = buy_gem;
                              info.owner = msg.sender;
                              info.timestamp = uint64(now);
                              id = _next_id();
                              offers[id] = info;
                      
                              require( pay_gem.transferFrom(msg.sender, this, pay_amt) );
                      
                              LogItemUpdate(id);
                              LogMake(
                                  bytes32(id),
                                  keccak256(pay_gem, buy_gem),
                                  msg.sender,
                                  pay_gem,
                                  buy_gem,
                                  uint128(pay_amt),
                                  uint128(buy_amt),
                                  uint64(now)
                              );
                          }
                      
                          function take(bytes32 id, uint128 maxTakeAmount)
                              public
                          {
                              require(buy(uint256(id), maxTakeAmount));
                          }
                      
                          function _next_id()
                              internal
                              returns (uint)
                          {
                              last_offer_id++; return last_offer_id;
                          }
                      }
                      
                      // Simple Market with a market lifetime. When the close_time has been reached,
                      // offers can only be cancelled (offer and buy will throw).
                      
                      contract ExpiringMarket is DSAuth, SimpleMarket {
                          uint64 public close_time;
                          bool public stopped;
                      
                          // after close_time has been reached, no new offers are allowed
                          modifier can_offer {
                              require(!isClosed());
                              _;
                          }
                      
                          // after close, no new buys are allowed
                          modifier can_buy(uint id) {
                              require(isActive(id));
                              require(!isClosed());
                              _;
                          }
                      
                          // after close, anyone can cancel an offer
                          modifier can_cancel(uint id) {
                              require(isActive(id));
                              require((msg.sender == getOwner(id)) || isClosed());
                              _;
                          }
                      
                          function ExpiringMarket(uint64 _close_time)
                              public
                          {
                              close_time = _close_time;
                          }
                      
                          function isClosed() public constant returns (bool closed) {
                              return stopped || getTime() > close_time;
                          }
                      
                          function getTime() public constant returns (uint64) {
                              return uint64(now);
                          }
                      
                          function stop() public auth {
                              stopped = true;
                          }
                      }
                      
                      /// note.sol -- the `note' modifier, for logging calls as events
                      
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU General Public License for more details.
                      
                      // You should have received a copy of the GNU General Public License
                      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                      
                      pragma solidity ^0.4.13;
                      
                      contract DSNote {
                          event LogNote(
                              bytes4   indexed  sig,
                              address  indexed  guy,
                              bytes32  indexed  foo,
                              bytes32  indexed  bar,
                              uint              wad,
                              bytes             fax
                          ) anonymous;
                      
                          modifier note {
                              bytes32 foo;
                              bytes32 bar;
                      
                              assembly {
                                  foo := calldataload(4)
                                  bar := calldataload(36)
                              }
                      
                              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
                      
                              _;
                          }
                      }
                      
                      contract MatchingEvents {
                          event LogBuyEnabled(bool isEnabled);
                          event LogMinSell(address pay_gem, uint min_amount);
                          event LogMatchingEnabled(bool isEnabled);
                          event LogUnsortedOffer(uint id);
                          event LogSortedOffer(uint id);
                          event LogInsert(address keeper, uint id);
                          event LogDelete(address keeper, uint id);
                      }
                      
                      contract MatchingMarket is MatchingEvents, ExpiringMarket, DSNote {
                          bool public buyEnabled = true;      //buy enabled
                          bool public matchingEnabled = true; //true: enable matching,
                                                               //false: revert to expiring market
                          struct sortInfo {
                              uint next;  //points to id of next higher offer
                              uint prev;  //points to id of previous lower offer
                              uint delb;  //the blocknumber where this entry was marked for delete
                          }
                          mapping(uint => sortInfo) public _rank;                     //doubly linked lists of sorted offer ids
                          mapping(address => mapping(address => uint)) public _best;  //id of the highest offer for a token pair
                          mapping(address => mapping(address => uint)) public _span;  //number of offers stored for token pair in sorted orderbook
                          mapping(address => uint) public _dust;                      //minimum sell amount for a token to avoid dust offers
                          mapping(uint => uint) public _near;         //next unsorted offer id
                          uint _head;                                 //first unsorted offer id
                          uint public dustId;                         // id of the latest offer marked as dust
                      
                      
                          function MatchingMarket(uint64 close_time) ExpiringMarket(close_time) public {
                          }
                      
                          // After close, anyone can cancel an offer
                          modifier can_cancel(uint id) {
                              require(isActive(id), "Offer was deleted or taken, or never existed.");
                              require(
                                  isClosed() || msg.sender == getOwner(id) || id == dustId,
                                  "Offer can not be cancelled because user is not owner, and market is open, and offer sells required amount of tokens."
                              );
                              _;
                          }
                      
                          // ---- Public entrypoints ---- //
                      
                          function make(
                              ERC20    pay_gem,
                              ERC20    buy_gem,
                              uint128  pay_amt,
                              uint128  buy_amt
                          )
                              public
                              returns (bytes32)
                          {
                              return bytes32(offer(pay_amt, pay_gem, buy_amt, buy_gem));
                          }
                      
                          function take(bytes32 id, uint128 maxTakeAmount) public {
                              require(buy(uint256(id), maxTakeAmount));
                          }
                      
                          function kill(bytes32 id) public {
                              require(cancel(uint256(id)));
                          }
                      
                          // Make a new offer. Takes funds from the caller into market escrow.
                          //
                          // If matching is enabled:
                          //     * creates new offer without putting it in
                          //       the sorted list.
                          //     * available to authorized contracts only!
                          //     * keepers should call insert(id,pos)
                          //       to put offer in the sorted list.
                          //
                          // If matching is disabled:
                          //     * calls expiring market's offer().
                          //     * available to everyone without authorization.
                          //     * no sorting is done.
                          //
                          function offer(
                              uint pay_amt,    //maker (ask) sell how much
                              ERC20 pay_gem,   //maker (ask) sell which token
                              uint buy_amt,    //taker (ask) buy how much
                              ERC20 buy_gem    //taker (ask) buy which token
                          )
                              public
                              returns (uint)
                          {
                              require(!locked, "Reentrancy attempt");
                              var fn = matchingEnabled ? _offeru : super.offer;
                              return fn(pay_amt, pay_gem, buy_amt, buy_gem);
                          }
                      
                          // Make a new offer. Takes funds from the caller into market escrow.
                          function offer(
                              uint pay_amt,    //maker (ask) sell how much
                              ERC20 pay_gem,   //maker (ask) sell which token
                              uint buy_amt,    //maker (ask) buy how much
                              ERC20 buy_gem,   //maker (ask) buy which token
                              uint pos         //position to insert offer, 0 should be used if unknown
                          )
                              public
                              can_offer
                              returns (uint)
                          {
                              return offer(pay_amt, pay_gem, buy_amt, buy_gem, pos, true);
                          }
                      
                          function offer(
                              uint pay_amt,    //maker (ask) sell how much
                              ERC20 pay_gem,   //maker (ask) sell which token
                              uint buy_amt,    //maker (ask) buy how much
                              ERC20 buy_gem,   //maker (ask) buy which token
                              uint pos,        //position to insert offer, 0 should be used if unknown
                              bool rounding    //match "close enough" orders?
                          )
                              public
                              can_offer
                              returns (uint)
                          {
                              require(!locked, "Reentrancy attempt");
                              require(_dust[pay_gem] <= pay_amt);
                      
                              if (matchingEnabled) {
                                return _matcho(pay_amt, pay_gem, buy_amt, buy_gem, pos, rounding);
                              }
                              return super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
                          }
                      
                          //Transfers funds from caller to offer maker, and from market to caller.
                          function buy(uint id, uint amount)
                              public
                              can_buy(id)
                              returns (bool)
                          {
                              require(!locked, "Reentrancy attempt");
                              var fn = matchingEnabled ? _buys : super.buy;
                              return fn(id, amount);
                          }
                      
                          // Cancel an offer. Refunds offer maker.
                          function cancel(uint id)
                              public
                              can_cancel(id)
                              returns (bool success)
                          {
                              require(!locked, "Reentrancy attempt");
                              if (matchingEnabled) {
                                  if (isOfferSorted(id)) {
                                      require(_unsort(id));
                                  } else {
                                      require(_hide(id));
                                  }
                              }
                              return super.cancel(id);    //delete the offer.
                          }
                      
                          //insert offer into the sorted list
                          //keepers need to use this function
                          function insert(
                              uint id,   //maker (ask) id
                              uint pos   //position to insert into
                          )
                              public
                              returns (bool)
                          {
                              require(!locked, "Reentrancy attempt");
                              require(!isOfferSorted(id));    //make sure offers[id] is not yet sorted
                              require(isActive(id));          //make sure offers[id] is active
                      
                              _hide(id);                      //remove offer from unsorted offers list
                              _sort(id, pos);                 //put offer into the sorted offers list
                              LogInsert(msg.sender, id);
                              return true;
                          }
                      
                          //deletes _rank [id]
                          //  Function should be called by keepers.
                          function del_rank(uint id)
                              public
                              returns (bool)
                          {
                              require(!locked, "Reentrancy attempt");
                              require(!isActive(id) && _rank[id].delb != 0 && _rank[id].delb < block.number - 10);
                              delete _rank[id];
                              LogDelete(msg.sender, id);
                              return true;
                          }
                      
                          //set the minimum sell amount for a token
                          //    Function is used to avoid "dust offers" that have
                          //    very small amount of tokens to sell, and it would
                          //    cost more gas to accept the offer, than the value
                          //    of tokens received.
                          function setMinSell(
                              ERC20 pay_gem,     //token to assign minimum sell amount to
                              uint dust          //maker (ask) minimum sell amount
                          )
                              public
                              auth
                              note
                              returns (bool)
                          {
                              _dust[pay_gem] = dust;
                              LogMinSell(pay_gem, dust);
                              return true;
                          }
                      
                          //returns the minimum sell amount for an offer
                          function getMinSell(
                              ERC20 pay_gem      //token for which minimum sell amount is queried
                          )
                              public
                              constant
                              returns (uint)
                          {
                              return _dust[pay_gem];
                          }
                      
                          //set buy functionality enabled/disabled
                          function setBuyEnabled(bool buyEnabled_) public auth returns (bool) {
                              buyEnabled = buyEnabled_;
                              LogBuyEnabled(buyEnabled);
                              return true;
                          }
                      
                          //set matching enabled/disabled
                          //    If matchingEnabled true(default), then inserted offers are matched.
                          //    Except the ones inserted by contracts, because those end up
                          //    in the unsorted list of offers, that must be later sorted by
                          //    keepers using insert().
                          //    If matchingEnabled is false then MatchingMarket is reverted to ExpiringMarket,
                          //    and matching is not done, and sorted lists are disabled.
                          function setMatchingEnabled(bool matchingEnabled_) public auth returns (bool) {
                              matchingEnabled = matchingEnabled_;
                              LogMatchingEnabled(matchingEnabled);
                              return true;
                          }
                      
                          //return the best offer for a token pair
                          //      the best offer is the lowest one if it's an ask,
                          //      and highest one if it's a bid offer
                          function getBestOffer(ERC20 sell_gem, ERC20 buy_gem) public constant returns(uint) {
                              return _best[sell_gem][buy_gem];
                          }
                      
                          //return the next worse offer in the sorted list
                          //      the worse offer is the higher one if its an ask,
                          //      a lower one if its a bid offer,
                          //      and in both cases the newer one if they're equal.
                          function getWorseOffer(uint id) public constant returns(uint) {
                              return _rank[id].prev;
                          }
                      
                          //return the next better offer in the sorted list
                          //      the better offer is in the lower priced one if its an ask,
                          //      the next higher priced one if its a bid offer
                          //      and in both cases the older one if they're equal.
                          function getBetterOffer(uint id) public constant returns(uint) {
                      
                              return _rank[id].next;
                          }
                      
                          //return the amount of better offers for a token pair
                          function getOfferCount(ERC20 sell_gem, ERC20 buy_gem) public constant returns(uint) {
                              return _span[sell_gem][buy_gem];
                          }
                      
                          //get the first unsorted offer that was inserted by a contract
                          //      Contracts can't calculate the insertion position of their offer because it is not an O(1) operation.
                          //      Their offers get put in the unsorted list of offers.
                          //      Keepers can calculate the insertion position offchain and pass it to the insert() function to insert
                          //      the unsorted offer into the sorted list. Unsorted offers will not be matched, but can be bought with buy().
                          function getFirstUnsortedOffer() public constant returns(uint) {
                              return _head;
                          }
                      
                          //get the next unsorted offer
                          //      Can be used to cycle through all the unsorted offers.
                          function getNextUnsortedOffer(uint id) public constant returns(uint) {
                              return _near[id];
                          }
                      
                          function isOfferSorted(uint id) public constant returns(bool) {
                              return _rank[id].next != 0
                                     || _rank[id].prev != 0
                                     || _best[offers[id].pay_gem][offers[id].buy_gem] == id;
                          }
                      
                          function sellAllAmount(ERC20 pay_gem, uint pay_amt, ERC20 buy_gem, uint min_fill_amount)
                              public
                              returns (uint fill_amt)
                          {
                              require(!locked, "Reentrancy attempt");
                              uint offerId;
                              while (pay_amt > 0) {                           //while there is amount to sell
                                  offerId = getBestOffer(buy_gem, pay_gem);   //Get the best offer for the token pair
                                  require(offerId != 0);                      //Fails if there are not more offers
                      
                                  // There is a chance that pay_amt is smaller than 1 wei of the other token
                                  if (pay_amt * 1 ether < wdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) {
                                      break;                                  //We consider that all amount is sold
                                  }
                                  if (pay_amt >= offers[offerId].buy_amt) {                       //If amount to sell is higher or equal than current offer amount to buy
                                      fill_amt = add(fill_amt, offers[offerId].pay_amt);          //Add amount bought to acumulator
                                      pay_amt = sub(pay_amt, offers[offerId].buy_amt);            //Decrease amount to sell
                                      take(bytes32(offerId), uint128(offers[offerId].pay_amt));   //We take the whole offer
                                  } else { // if lower
                                      var baux = rmul(pay_amt * 10 ** 9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) / 10 ** 9;
                                      fill_amt = add(fill_amt, baux);         //Add amount bought to acumulator
                                      take(bytes32(offerId), uint128(baux));  //We take the portion of the offer that we need
                                      pay_amt = 0;                            //All amount is sold
                                  }
                              }
                              require(fill_amt >= min_fill_amount);
                          }
                      
                          function buyAllAmount(ERC20 buy_gem, uint buy_amt, ERC20 pay_gem, uint max_fill_amount)
                              public
                              returns (uint fill_amt)
                          {
                              require(!locked, "Reentrancy attempt");
                              uint offerId;
                              while (buy_amt > 0) {                           //Meanwhile there is amount to buy
                                  offerId = getBestOffer(buy_gem, pay_gem);   //Get the best offer for the token pair
                                  require(offerId != 0);
                      
                                  // There is a chance that buy_amt is smaller than 1 wei of the other token
                                  if (buy_amt * 1 ether < wdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) {
                                      break;                                  //We consider that all amount is sold
                                  }
                                  if (buy_amt >= offers[offerId].pay_amt) {                       //If amount to buy is higher or equal than current offer amount to sell
                                      fill_amt = add(fill_amt, offers[offerId].buy_amt);          //Add amount sold to acumulator
                                      buy_amt = sub(buy_amt, offers[offerId].pay_amt);            //Decrease amount to buy
                                      take(bytes32(offerId), uint128(offers[offerId].pay_amt));   //We take the whole offer
                                  } else {                                                        //if lower
                                      fill_amt = add(fill_amt, rmul(buy_amt * 10 ** 9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) / 10 ** 9); //Add amount sold to acumulator
                                      take(bytes32(offerId), uint128(buy_amt));                   //We take the portion of the offer that we need
                                      buy_amt = 0;                                                //All amount is bought
                                  }
                              }
                              require(fill_amt <= max_fill_amount);
                          }
                      
                          function getBuyAmount(ERC20 buy_gem, ERC20 pay_gem, uint pay_amt) public constant returns (uint fill_amt) {
                              var offerId = getBestOffer(buy_gem, pay_gem);           //Get best offer for the token pair
                              while (pay_amt > offers[offerId].buy_amt) {
                                  fill_amt = add(fill_amt, offers[offerId].pay_amt);  //Add amount to buy accumulator
                                  pay_amt = sub(pay_amt, offers[offerId].buy_amt);    //Decrease amount to pay
                                  if (pay_amt > 0) {                                  //If we still need more offers
                                      offerId = getWorseOffer(offerId);               //We look for the next best offer
                                      require(offerId != 0);                          //Fails if there are not enough offers to complete
                                  }
                              }
                              fill_amt = add(fill_amt, rmul(pay_amt * 10 ** 9, rdiv(offers[offerId].pay_amt, offers[offerId].buy_amt)) / 10 ** 9); //Add proportional amount of last offer to buy accumulator
                          }
                      
                          function getPayAmount(ERC20 pay_gem, ERC20 buy_gem, uint buy_amt) public constant returns (uint fill_amt) {
                              var offerId = getBestOffer(buy_gem, pay_gem);           //Get best offer for the token pair
                              while (buy_amt > offers[offerId].pay_amt) {
                                  fill_amt = add(fill_amt, offers[offerId].buy_amt);  //Add amount to pay accumulator
                                  buy_amt = sub(buy_amt, offers[offerId].pay_amt);    //Decrease amount to buy
                                  if (buy_amt > 0) {                                  //If we still need more offers
                                      offerId = getWorseOffer(offerId);               //We look for the next best offer
                                      require(offerId != 0);                          //Fails if there are not enough offers to complete
                                  }
                              }
                              fill_amt = add(fill_amt, rmul(buy_amt * 10 ** 9, rdiv(offers[offerId].buy_amt, offers[offerId].pay_amt)) / 10 ** 9); //Add proportional amount of last offer to pay accumulator
                          }
                      
                          // ---- Internal Functions ---- //
                      
                          function _buys(uint id, uint amount)
                              internal
                              returns (bool)
                          {
                              require(buyEnabled);
                              if (amount == offers[id].pay_amt) {
                                  if (isOfferSorted(id)) {
                                      //offers[id] must be removed from sorted list because all of it is bought
                                      _unsort(id);
                                  }else{
                                      _hide(id);
                                  }
                              }
                              require(super.buy(id, amount));
                              // If offer has become dust during buy, we cancel it
                              if (isActive(id) && offers[id].pay_amt < _dust[offers[id].pay_gem]) {
                                  dustId = id; //enable current msg.sender to call cancel(id)
                                  cancel(id);
                              }
                              return true;
                          }
                      
                          //find the id of the next higher offer after offers[id]
                          function _find(uint id)
                              internal
                              view
                              returns (uint)
                          {
                              require( id > 0 );
                      
                              address buy_gem = address(offers[id].buy_gem);
                              address pay_gem = address(offers[id].pay_gem);
                              uint top = _best[pay_gem][buy_gem];
                              uint old_top = 0;
                      
                              // Find the larger-than-id order whose successor is less-than-id.
                              while (top != 0 && _isPricedLtOrEq(id, top)) {
                                  old_top = top;
                                  top = _rank[top].prev;
                              }
                              return old_top;
                          }
                      
                          //find the id of the next higher offer after offers[id]
                          function _findpos(uint id, uint pos)
                              internal
                              view
                              returns (uint)
                          {
                              require(id > 0);
                      
                              // Look for an active order.
                              while (pos != 0 && !isActive(pos)) {
                                  pos = _rank[pos].prev;
                              }
                      
                              if (pos == 0) {
                                  //if we got to the end of list without a single active offer
                                  return _find(id);
                      
                              } else {
                                  // if we did find a nearby active offer
                                  // Walk the order book down from there...
                                  if(_isPricedLtOrEq(id, pos)) {
                                      uint old_pos;
                      
                                      // Guaranteed to run at least once because of
                                      // the prior if statements.
                                      while (pos != 0 && _isPricedLtOrEq(id, pos)) {
                                          old_pos = pos;
                                          pos = _rank[pos].prev;
                                      }
                                      return old_pos;
                      
                                  // ...or walk it up.
                                  } else {
                                      while (pos != 0 && !_isPricedLtOrEq(id, pos)) {
                                          pos = _rank[pos].next;
                                      }
                                      return pos;
                                  }
                              }
                          }
                      
                          //return true if offers[low] priced less than or equal to offers[high]
                          function _isPricedLtOrEq(
                              uint low,   //lower priced offer's id
                              uint high   //higher priced offer's id
                          )
                              internal
                              view
                              returns (bool)
                          {
                              return mul(offers[low].buy_amt, offers[high].pay_amt)
                                >= mul(offers[high].buy_amt, offers[low].pay_amt);
                          }
                      
                          //these variables are global only because of solidity local variable limit
                      
                          //match offers with taker offer, and execute token transactions
                          function _matcho(
                              uint t_pay_amt,    //taker sell how much
                              ERC20 t_pay_gem,   //taker sell which token
                              uint t_buy_amt,    //taker buy how much
                              ERC20 t_buy_gem,   //taker buy which token
                              uint pos,          //position id
                              bool rounding      //match "close enough" orders?
                          )
                              internal
                              returns (uint id)
                          {
                              uint best_maker_id;    //highest maker id
                              uint t_buy_amt_old;    //taker buy how much saved
                              uint m_buy_amt;        //maker offer wants to buy this much token
                              uint m_pay_amt;        //maker offer wants to sell this much token
                      
                              // there is at least one offer stored for token pair
                              while (_best[t_buy_gem][t_pay_gem] > 0) {
                                  best_maker_id = _best[t_buy_gem][t_pay_gem];
                                  m_buy_amt = offers[best_maker_id].buy_amt;
                                  m_pay_amt = offers[best_maker_id].pay_amt;
                      
                                  // Ugly hack to work around rounding errors. Based on the idea that
                                  // the furthest the amounts can stray from their "true" values is 1.
                                  // Ergo the worst case has t_pay_amt and m_pay_amt at +1 away from
                                  // their "correct" values and m_buy_amt and t_buy_amt at -1.
                                  // Since (c - 1) * (d - 1) > (a + 1) * (b + 1) is equivalent to
                                  // c * d > a * b + a + b + c + d, we write...
                                  if (mul(m_buy_amt, t_buy_amt) > mul(t_pay_amt, m_pay_amt) +
                                      (rounding ? m_buy_amt + t_buy_amt + t_pay_amt + m_pay_amt : 0))
                                  {
                                      break;
                                  }
                                  // ^ The `rounding` parameter is a compromise borne of a couple days
                                  // of discussion.
                                  buy(best_maker_id, min(m_pay_amt, t_buy_amt));
                                  t_buy_amt_old = t_buy_amt;
                                  t_buy_amt = sub(t_buy_amt, min(m_pay_amt, t_buy_amt));
                                  t_pay_amt = mul(t_buy_amt, t_pay_amt) / t_buy_amt_old;
                      
                                  if (t_pay_amt == 0 || t_buy_amt == 0) {
                                      break;
                                  }
                              }
                      
                              if (t_buy_amt > 0 && t_pay_amt > 0 && t_pay_amt >= _dust[t_pay_gem]) {
                                  //new offer should be created
                                  id = super.offer(t_pay_amt, t_pay_gem, t_buy_amt, t_buy_gem);
                                  //insert offer into the sorted list
                                  _sort(id, pos);
                              }
                          }
                      
                          // Make a new offer without putting it in the sorted list.
                          // Takes funds from the caller into market escrow.
                          // ****Available to authorized contracts only!**********
                          // Keepers should call insert(id,pos) to put offer in the sorted list.
                          function _offeru(
                              uint pay_amt,      //maker (ask) sell how much
                              ERC20 pay_gem,     //maker (ask) sell which token
                              uint buy_amt,      //maker (ask) buy how much
                              ERC20 buy_gem      //maker (ask) buy which token
                          )
                              internal
                              returns (uint id)
                          {
                              require(_dust[pay_gem] <= pay_amt);
                              id = super.offer(pay_amt, pay_gem, buy_amt, buy_gem);
                              _near[id] = _head;
                              _head = id;
                              LogUnsortedOffer(id);
                          }
                      
                          //put offer into the sorted list
                          function _sort(
                              uint id,    //maker (ask) id
                              uint pos    //position to insert into
                          )
                              internal
                          {
                              require(isActive(id));
                      
                              address buy_gem = address(offers[id].buy_gem);
                              address pay_gem = address(offers[id].pay_gem);
                              uint prev_id;                                      //maker (ask) id
                      
                              pos = pos == 0 || offers[pos].pay_gem != pay_gem || offers[pos].buy_gem != buy_gem || !isOfferSorted(pos)
                              ?
                                  _find(id)
                              :
                                  _findpos(id, pos);
                      
                              if (pos != 0) {                                    //offers[id] is not the highest offer
                                  //requirement below is satisfied by statements above
                                  //require(_isPricedLtOrEq(id, pos));
                                  prev_id = _rank[pos].prev;
                                  _rank[pos].prev = id;
                                  _rank[id].next = pos;
                              } else {                                           //offers[id] is the highest offer
                                  prev_id = _best[pay_gem][buy_gem];
                                  _best[pay_gem][buy_gem] = id;
                              }
                      
                              if (prev_id != 0) {                               //if lower offer does exist
                                  //requirement below is satisfied by statements above
                                  //require(!_isPricedLtOrEq(id, prev_id));
                                  _rank[prev_id].next = id;
                                  _rank[id].prev = prev_id;
                              }
                      
                              _span[pay_gem][buy_gem]++;
                              LogSortedOffer(id);
                          }
                      
                          // Remove offer from the sorted list (does not cancel offer)
                          function _unsort(
                              uint id    //id of maker (ask) offer to remove from sorted list
                          )
                              internal
                              returns (bool)
                          {
                              address buy_gem = address(offers[id].buy_gem);
                              address pay_gem = address(offers[id].pay_gem);
                              require(_span[pay_gem][buy_gem] > 0);
                      
                              require(_rank[id].delb == 0 &&                    //assert id is in the sorted list
                                       isOfferSorted(id));
                      
                              if (id != _best[pay_gem][buy_gem]) {              // offers[id] is not the highest offer
                                  require(_rank[_rank[id].next].prev == id);
                                  _rank[_rank[id].next].prev = _rank[id].prev;
                              } else {                                          //offers[id] is the highest offer
                                  _best[pay_gem][buy_gem] = _rank[id].prev;
                              }
                      
                              if (_rank[id].prev != 0) {                        //offers[id] is not the lowest offer
                                  require(_rank[_rank[id].prev].next == id);
                                  _rank[_rank[id].prev].next = _rank[id].next;
                              }
                      
                              _span[pay_gem][buy_gem]--;
                              _rank[id].delb = block.number;                    //mark _rank[id] for deletion
                              return true;
                          }
                      
                          //Hide offer from the unsorted order book (does not cancel offer)
                          function _hide(
                              uint id     //id of maker offer to remove from unsorted list
                          )
                              internal
                              returns (bool)
                          {
                              uint uid = _head;               //id of an offer in unsorted offers list
                              uint pre = uid;                 //id of previous offer in unsorted offers list
                      
                              require(!isOfferSorted(id));    //make sure offer id is not in sorted offers list
                      
                              if (_head == id) {              //check if offer is first offer in unsorted offers list
                                  _head = _near[id];          //set head to new first unsorted offer
                                  _near[id] = 0;              //delete order from unsorted order list
                                  return true;
                              }
                              while (uid > 0 && uid != id) {  //find offer in unsorted order list
                                  pre = uid;
                                  uid = _near[uid];
                              }
                              if (uid != id) {                //did not find offer id in unsorted offers list
                                  return false;
                              }
                              _near[pre] = _near[id];         //set previous unsorted offer to point to offer after offer id
                              _near[id] = 0;                  //delete order from unsorted order list
                              return true;
                          }
                      }

                      File 2 of 3: Dai
                      // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
                      pragma solidity =0.5.12;
                      
                      ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU General Public License for more details.
                      
                      // You should have received a copy of the GNU General Public License
                      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                      
                      /* pragma solidity 0.5.12; */
                      
                      contract LibNote {
                          event LogNote(
                              bytes4   indexed  sig,
                              address  indexed  usr,
                              bytes32  indexed  arg1,
                              bytes32  indexed  arg2,
                              bytes             data
                          ) anonymous;
                      
                          modifier note {
                              _;
                              assembly {
                                  // log an 'anonymous' event with a constant 6 words of calldata
                                  // and four indexed topics: selector, caller, arg1 and arg2
                                  let mark := msize                         // end of memory ensures zero
                                  mstore(0x40, add(mark, 288))              // update free memory pointer
                                  mstore(mark, 0x20)                        // bytes type data offset
                                  mstore(add(mark, 0x20), 224)              // bytes size (padded)
                                  calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                                  log4(mark, 288,                           // calldata
                                       shl(224, shr(224, calldataload(0))), // msg.sig
                                       caller,                              // msg.sender
                                       calldataload(4),                     // arg1
                                       calldataload(36)                     // arg2
                                      )
                              }
                          }
                      }
                      
                      ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/dai.sol
                      // Copyright (C) 2017, 2018, 2019 dbrock, rain, mrchico
                      
                      // This program is free software: you can redistribute it and/or modify
                      // it under the terms of the GNU Affero General Public License as published by
                      // the Free Software Foundation, either version 3 of the License, or
                      // (at your option) any later version.
                      //
                      // This program is distributed in the hope that it will be useful,
                      // but WITHOUT ANY WARRANTY; without even the implied warranty of
                      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                      // GNU Affero General Public License for more details.
                      //
                      // You should have received a copy of the GNU Affero General Public License
                      // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                      
                      /* pragma solidity 0.5.12; */
                      
                      /* import "./lib.sol"; */
                      
                      contract Dai is LibNote {
                          // --- Auth ---
                          mapping (address => uint) public wards;
                          function rely(address guy) external note auth { wards[guy] = 1; }
                          function deny(address guy) external note auth { wards[guy] = 0; }
                          modifier auth {
                              require(wards[msg.sender] == 1, "Dai/not-authorized");
                              _;
                          }
                      
                          // --- ERC20 Data ---
                          string  public constant name     = "Dai Stablecoin";
                          string  public constant symbol   = "DAI";
                          string  public constant version  = "1";
                          uint8   public constant decimals = 18;
                          uint256 public totalSupply;
                      
                          mapping (address => uint)                      public balanceOf;
                          mapping (address => mapping (address => uint)) public allowance;
                          mapping (address => uint)                      public nonces;
                      
                          event Approval(address indexed src, address indexed guy, uint wad);
                          event Transfer(address indexed src, address indexed dst, uint wad);
                      
                          // --- Math ---
                          function add(uint x, uint y) internal pure returns (uint z) {
                              require((z = x + y) >= x);
                          }
                          function sub(uint x, uint y) internal pure returns (uint z) {
                              require((z = x - y) <= x);
                          }
                      
                          // --- EIP712 niceties ---
                          bytes32 public DOMAIN_SEPARATOR;
                          // bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address holder,address spender,uint256 nonce,uint256 expiry,bool allowed)");
                          bytes32 public constant PERMIT_TYPEHASH = 0xea2aa0a1be11a07ed86d755c93467f4f82362b452371d1ba94d1715123511acb;
                      
                          constructor(uint256 chainId_) public {
                              wards[msg.sender] = 1;
                              DOMAIN_SEPARATOR = keccak256(abi.encode(
                                  keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                                  keccak256(bytes(name)),
                                  keccak256(bytes(version)),
                                  chainId_,
                                  address(this)
                              ));
                          }
                      
                          // --- Token ---
                          function transfer(address dst, uint wad) external returns (bool) {
                              return transferFrom(msg.sender, dst, wad);
                          }
                          function transferFrom(address src, address dst, uint wad)
                              public returns (bool)
                          {
                              require(balanceOf[src] >= wad, "Dai/insufficient-balance");
                              if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
                                  require(allowance[src][msg.sender] >= wad, "Dai/insufficient-allowance");
                                  allowance[src][msg.sender] = sub(allowance[src][msg.sender], wad);
                              }
                              balanceOf[src] = sub(balanceOf[src], wad);
                              balanceOf[dst] = add(balanceOf[dst], wad);
                              emit Transfer(src, dst, wad);
                              return true;
                          }
                          function mint(address usr, uint wad) external auth {
                              balanceOf[usr] = add(balanceOf[usr], wad);
                              totalSupply    = add(totalSupply, wad);
                              emit Transfer(address(0), usr, wad);
                          }
                          function burn(address usr, uint wad) external {
                              require(balanceOf[usr] >= wad, "Dai/insufficient-balance");
                              if (usr != msg.sender && allowance[usr][msg.sender] != uint(-1)) {
                                  require(allowance[usr][msg.sender] >= wad, "Dai/insufficient-allowance");
                                  allowance[usr][msg.sender] = sub(allowance[usr][msg.sender], wad);
                              }
                              balanceOf[usr] = sub(balanceOf[usr], wad);
                              totalSupply    = sub(totalSupply, wad);
                              emit Transfer(usr, address(0), wad);
                          }
                          function approve(address usr, uint wad) external returns (bool) {
                              allowance[msg.sender][usr] = wad;
                              emit Approval(msg.sender, usr, wad);
                              return true;
                          }
                      
                          // --- Alias ---
                          function push(address usr, uint wad) external {
                              transferFrom(msg.sender, usr, wad);
                          }
                          function pull(address usr, uint wad) external {
                              transferFrom(usr, msg.sender, wad);
                          }
                          function move(address src, address dst, uint wad) external {
                              transferFrom(src, dst, wad);
                          }
                      
                          // --- Approve by signature ---
                          function permit(address holder, address spender, uint256 nonce, uint256 expiry,
                                          bool allowed, uint8 v, bytes32 r, bytes32 s) external
                          {
                              bytes32 digest =
                                  keccak256(abi.encodePacked(
                                      "\x19\x01",
                                      DOMAIN_SEPARATOR,
                                      keccak256(abi.encode(PERMIT_TYPEHASH,
                                                           holder,
                                                           spender,
                                                           nonce,
                                                           expiry,
                                                           allowed))
                              ));
                      
                              require(holder != address(0), "Dai/invalid-address-0");
                              require(holder == ecrecover(digest, v, r, s), "Dai/invalid-permit");
                              require(expiry == 0 || now <= expiry, "Dai/permit-expired");
                              require(nonce == nonces[holder]++, "Dai/invalid-nonce");
                              uint wad = allowed ? uint(-1) : 0;
                              allowance[holder][spender] = wad;
                              emit Approval(holder, spender, wad);
                          }
                      }

                      File 3 of 3: GasToken2
                      pragma solidity ^0.4.10;
                      
                      contract GasToken2 {
                          //////////////////////////////////////////////////////////////////////////
                          // RLP.sol
                          // Due to some unexplained bug, we get a slightly different bytecode if 
                          // we use an import, and are then unable to verify the code in Etherscan
                          //////////////////////////////////////////////////////////////////////////
                          
                          uint256 constant ADDRESS_BYTES = 20;
                          uint256 constant MAX_SINGLE_BYTE = 128;
                          uint256 constant MAX_NONCE = 256**9 - 1;
                      
                          // count number of bytes required to represent an unsigned integer
                          function count_bytes(uint256 n) constant internal returns (uint256 c) {
                              uint i = 0;
                              uint mask = 1;
                              while (n >= mask) {
                                  i += 1;
                                  mask *= 256;
                              }
                      
                              return i;
                          }
                      
                          function mk_contract_address(address a, uint256 n) constant internal returns (address rlp) {
                              /*
                               * make sure the RLP encoding fits in one word:
                               * total_length      1 byte
                               * address_length    1 byte
                               * address          20 bytes
                               * nonce_length      1 byte (or 0)
                               * nonce           1-9 bytes
                               *                ==========
                               *                24-32 bytes
                               */
                              require(n <= MAX_NONCE);
                      
                              // number of bytes required to write down the nonce
                              uint256 nonce_bytes;
                              // length in bytes of the RLP encoding of the nonce
                              uint256 nonce_rlp_len;
                      
                              if (0 < n && n < MAX_SINGLE_BYTE) {
                                  // nonce fits in a single byte
                                  // RLP(nonce) = nonce
                                  nonce_bytes = 1;
                                  nonce_rlp_len = 1;
                              } else {
                                  // RLP(nonce) = [num_bytes_in_nonce nonce]
                                  nonce_bytes = count_bytes(n);
                                  nonce_rlp_len = nonce_bytes + 1;
                              }
                      
                              // [address_length(1) address(20) nonce_length(0 or 1) nonce(1-9)]
                              uint256 tot_bytes = 1 + ADDRESS_BYTES + nonce_rlp_len;
                      
                              // concatenate all parts of the RLP encoding in the leading bytes of
                              // one 32-byte word
                              uint256 word = ((192 + tot_bytes) * 256**31) +
                                             ((128 + ADDRESS_BYTES) * 256**30) +
                                             (uint256(a) * 256**10);
                      
                              if (0 < n && n < MAX_SINGLE_BYTE) {
                                  word += n * 256**9;
                              } else {
                                  word += (128 + nonce_bytes) * 256**9;
                                  word += n * 256**(9 - nonce_bytes);
                              }
                      
                              uint256 hash;
                      
                              assembly {
                                  let mem_start := mload(0x40)        // get a pointer to free memory
                                  mstore(0x40, add(mem_start, 0x20))  // update the pointer
                      
                                  mstore(mem_start, word)             // store the rlp encoding
                                  hash := sha3(mem_start,
                                               add(tot_bytes, 1))     // hash the rlp encoding
                              }
                      
                              // interpret hash as address (20 least significant bytes)
                              return address(hash);
                          }
                          
                          //////////////////////////////////////////////////////////////////////////
                          // Generic ERC20
                          //////////////////////////////////////////////////////////////////////////
                      
                          // owner -> amount
                          mapping(address => uint256) s_balances;
                          // owner -> spender -> max amount
                          mapping(address => mapping(address => uint256)) s_allowances;
                      
                          event Transfer(address indexed from, address indexed to, uint256 value);
                      
                          event Approval(address indexed owner, address indexed spender, uint256 value);
                      
                          // Spec: Get the account balance of another account with address `owner`
                          function balanceOf(address owner) public constant returns (uint256 balance) {
                              return s_balances[owner];
                          }
                      
                          function internalTransfer(address from, address to, uint256 value) internal returns (bool success) {
                              if (value <= s_balances[from]) {
                                  s_balances[from] -= value;
                                  s_balances[to] += value;
                                  Transfer(from, to, value);
                                  return true;
                              } else {
                                  return false;
                              }
                          }
                      
                          // Spec: Send `value` amount of tokens to address `to`
                          function transfer(address to, uint256 value) public returns (bool success) {
                              address from = msg.sender;
                              return internalTransfer(from, to, value);
                          }
                      
                          // Spec: Send `value` amount of tokens from address `from` to address `to`
                          function transferFrom(address from, address to, uint256 value) public returns (bool success) {
                              address spender = msg.sender;
                              if(value <= s_allowances[from][spender] && internalTransfer(from, to, value)) {
                                  s_allowances[from][spender] -= value;
                                  return true;
                              } else {
                                  return false;
                              }
                          }
                      
                          // Spec: Allow `spender` to withdraw from your account, multiple times, up
                          // to the `value` amount. If this function is called again it overwrites the
                          // current allowance with `value`.
                          function approve(address spender, uint256 value) public returns (bool success) {
                              address owner = msg.sender;
                              if (value != 0 && s_allowances[owner][spender] != 0) {
                                  return false;
                              }
                              s_allowances[owner][spender] = value;
                              Approval(owner, spender, value);
                              return true;
                          }
                      
                          // Spec: Returns the `amount` which `spender` is still allowed to withdraw
                          // from `owner`.
                          // What if the allowance is higher than the balance of the `owner`?
                          // Callers should be careful to use min(allowance, balanceOf) to make sure
                          // that the allowance is actually present in the account!
                          function allowance(address owner, address spender) public constant returns (uint256 remaining) {
                              return s_allowances[owner][spender];
                          }
                      
                          //////////////////////////////////////////////////////////////////////////
                          // GasToken specifics
                          //////////////////////////////////////////////////////////////////////////
                      
                          uint8 constant public decimals = 2;
                          string constant public name = "Gastoken.io";
                          string constant public symbol = "GST2";
                      
                          // We build a queue of nonces at which child contracts are stored. s_head is
                          // the nonce at the head of the queue, s_tail is the nonce behind the tail
                          // of the queue. The queue grows at the head and shrinks from the tail.
                          // Note that when and only when a contract CREATEs another contract, the
                          // creating contract's nonce is incremented.
                          // The first child contract is created with nonce == 1, the second child
                          // contract is created with nonce == 2, and so on...
                          // For example, if there are child contracts at nonces [2,3,4],
                          // then s_head == 4 and s_tail == 1. If there are no child contracts,
                          // s_head == s_tail.
                          uint256 s_head;
                          uint256 s_tail;
                      
                          // totalSupply gives  the number of tokens currently in existence
                          // Each token corresponds to one child contract that can be SELFDESTRUCTed
                          // for a gas refund.
                          function totalSupply() public constant returns (uint256 supply) {
                              return s_head - s_tail;
                          }
                      
                          // Creates a child contract that can only be destroyed by this contract.
                          function makeChild() internal returns (address addr) {
                              assembly {
                                  // EVM assembler of runtime portion of child contract:
                                  //     ;; Pseudocode: if (msg.sender != 0x0000000000b3f879cb30fe243b4dfee438691c04) { throw; }
                                  //     ;;             suicide(msg.sender)
                                  //     PUSH15 0xb3f879cb30fe243b4dfee438691c04 ;; hardcoded address of this contract
                                  //     CALLER
                                  //     XOR
                                  //     PC
                                  //     JUMPI
                                  //     CALLER
                                  //     SELFDESTRUCT
                                  // Or in binary: 6eb3f879cb30fe243b4dfee438691c043318585733ff
                                  // Since the binary is so short (22 bytes), we can get away
                                  // with a very simple initcode:
                                  //     PUSH22 0x6eb3f879cb30fe243b4dfee438691c043318585733ff
                                  //     PUSH1 0
                                  //     MSTORE ;; at this point, memory locations mem[10] through
                                  //            ;; mem[31] contain the runtime portion of the child
                                  //            ;; contract. all that's left to do is to RETURN this
                                  //            ;; chunk of memory.
                                  //     PUSH1 22 ;; length
                                  //     PUSH1 10 ;; offset
                                  //     RETURN
                                  // Or in binary: 756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3
                                  // Almost done! All we have to do is put this short (31 bytes) blob into
                                  // memory and call CREATE with the appropriate offsets.
                                  let solidity_free_mem_ptr := mload(0x40)
                                  mstore(solidity_free_mem_ptr, 0x00756eb3f879cb30fe243b4dfee438691c043318585733ff6000526016600af3)
                                  addr := create(0, add(solidity_free_mem_ptr, 1), 31)
                              }
                          }
                      
                          // Mints `value` new sub-tokens (e.g. cents, pennies, ...) by creating `value`
                          // new child contracts. The minted tokens are owned by the caller of this
                          // function.
                          function mint(uint256 value) public {
                              for (uint256 i = 0; i < value; i++) {
                                  makeChild();
                              }
                              s_head += value;
                              s_balances[msg.sender] += value;
                          }
                      
                          // Destroys `value` child contracts and updates s_tail.
                          //
                          // This function is affected by an issue in solc: https://github.com/ethereum/solidity/issues/2999
                          // The `mk_contract_address(this, i).call();` doesn't forward all available gas, but only GAS - 25710.
                          // As a result, when this line is executed with e.g. 30000 gas, the callee will have less than 5000 gas
                          // available and its SELFDESTRUCT operation will fail leading to no gas refund occurring.
                          // The remaining ~29000 gas left after the call is enough to update s_tail and the caller's balance.
                          // Hence tokens will have been destroyed without a commensurate gas refund.
                          // Fortunately, there is a simple workaround:
                          // Whenever you call free, freeUpTo, freeFrom, or freeUpToFrom, ensure that you pass at least
                          // 25710 + `value` * (1148 + 5722 + 150) gas. (It won't all be used)
                          function destroyChildren(uint256 value) internal {
                              uint256 tail = s_tail;
                              // tail points to slot behind the last contract in the queue
                              for (uint256 i = tail + 1; i <= tail + value; i++) {
                                  mk_contract_address(this, i).call();
                              }
                      
                              s_tail = tail + value;
                          }
                      
                          // Frees `value` sub-tokens (e.g. cents, pennies, ...) belonging to the
                          // caller of this function by destroying `value` child contracts, which
                          // will trigger a partial gas refund.
                          // You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
                          // when calling this function. For details, see the comment above `destroyChilden`.
                          function free(uint256 value) public returns (bool success) {
                              uint256 from_balance = s_balances[msg.sender];
                              if (value > from_balance) {
                                  return false;
                              }
                      
                              destroyChildren(value);
                      
                              s_balances[msg.sender] = from_balance - value;
                      
                              return true;
                          }
                      
                          // Frees up to `value` sub-tokens. Returns how many tokens were freed.
                          // Otherwise, identical to free.
                          // You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
                          // when calling this function. For details, see the comment above `destroyChilden`.
                          function freeUpTo(uint256 value) public returns (uint256 freed) {
                              uint256 from_balance = s_balances[msg.sender];
                              if (value > from_balance) {
                                  value = from_balance;
                              }
                      
                              destroyChildren(value);
                      
                              s_balances[msg.sender] = from_balance - value;
                      
                              return value;
                          }
                      
                          // Frees `value` sub-tokens owned by address `from`. Requires that `msg.sender`
                          // has been approved by `from`.
                          // You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
                          // when calling this function. For details, see the comment above `destroyChilden`.
                          function freeFrom(address from, uint256 value) public returns (bool success) {
                              address spender = msg.sender;
                              uint256 from_balance = s_balances[from];
                              if (value > from_balance) {
                                  return false;
                              }
                      
                              mapping(address => uint256) from_allowances = s_allowances[from];
                              uint256 spender_allowance = from_allowances[spender];
                              if (value > spender_allowance) {
                                  return false;
                              }
                      
                              destroyChildren(value);
                      
                              s_balances[from] = from_balance - value;
                              from_allowances[spender] = spender_allowance - value;
                      
                              return true;
                          }
                      
                          // Frees up to `value` sub-tokens owned by address `from`. Returns how many tokens were freed.
                          // Otherwise, identical to `freeFrom`.
                          // You should ensure that you pass at least 25710 + `value` * (1148 + 5722 + 150) gas
                          // when calling this function. For details, see the comment above `destroyChilden`.
                          function freeFromUpTo(address from, uint256 value) public returns (uint256 freed) {
                              address spender = msg.sender;
                              uint256 from_balance = s_balances[from];
                              if (value > from_balance) {
                                  value = from_balance;
                              }
                      
                              mapping(address => uint256) from_allowances = s_allowances[from];
                              uint256 spender_allowance = from_allowances[spender];
                              if (value > spender_allowance) {
                                  value = spender_allowance;
                              }
                      
                              destroyChildren(value);
                      
                              s_balances[from] = from_balance - value;
                              from_allowances[spender] = spender_allowance - value;
                      
                              return value;
                          }
                      }