ETH Price: $2,555.78 (+3.14%)

Transaction Decoder

Block:
8242525 at Jul-29-2019 01:08:32 AM +UTC
Transaction Fee:
0.00039226 ETH $1.00
Gas Used:
392,260 Gas / 1 Gwei

Emitted Events:

38 DSProxy.0x1cff79cd00000000000000000000000000000000000000000000000000000000( 0x1cff79cd00000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000007728d2b25371c2646fd87d28ade7c5fb0a48b753, 0x000000000000000000000000526af336d614ade5cc252a407062b8861af998f5, 0x0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 000000000000000000000000000000000000000000000000000001041cff79cd, 000000000000000000000000526af336d614ade5cc252a407062b8861af998f5, 0000000000000000000000000000000000000000000000000000000000000040, 0000000000000000000000000000000000000000000000000000000000000084, 8a9fc475000000000000000000000000448a5065aebb8e423f0896e6c5d525c0, 40f59af300000000000000000000000000000000000000000000000000000000, 0000606d00000000000000000000000000000000000000000000000006f05b59, d3b2000000000000000000000000000039755357759ce0d7f32dc8dc45414cca, 409ae24e00000000000000000000000000000000000000000000000000000000 )
39 DSToken.Transfer( src=[Sender] 0x7728d2b25371c2646fd87d28ade7c5fb0a48b753, dst=[Receiver] DSProxy, wad=500000000000000000 )
40 SaiTub.0x6f78ee0d00000000000000000000000000000000000000000000000000000000( 0x6f78ee0d00000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 000000000000000000000000000000000000000000000000000000246f78ee0d, 000000000000000000000000000000000000000000000000000000000000606d )
41 SaiTub.0x6f78ee0d00000000000000000000000000000000000000000000000000000000( 0x6f78ee0d00000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 000000000000000000000000000000000000000000000000000000246f78ee0d, 000000000000000000000000000000000000000000000000000000000000606d )
42 SaiTub.0xf7c8d63400000000000000000000000000000000000000000000000000000000( 0xf7c8d63400000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 00000000000000000000000000000000000000000000000000000024f7c8d634, 000000000000000000000000000000000000000000000000000000000000606d )
43 DSToken.Approval( src=[Receiver] DSProxy, guy=MatchingMarket, wad=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
44 DSToken.Transfer( src=[Sender] 0x7728d2b25371c2646fd87d28ade7c5fb0a48b753, dst=[Receiver] DSProxy, wad=369252356641355 )
45 DSToken.Transfer( src=[Receiver] DSProxy, dst=0xAe34FFe5BF622684a251A28D8a9b05bC8c850629, wad=369252356641355 )
46 DSToken.Transfer( from=MatchingMarket, to=[Receiver] DSProxy, value=608412778242 )
47 MatchingMarket.LogItemUpdate( id=363670 )
48 MatchingMarket.LogTake( id=0000000000000000000000000000000000000000000000000000000000058C96, pair=7509DEDA9E17580C94915865C0C0C56190CC733E6C835A6CA2E497C1E4A50A5D, maker=0xAe34FFe5BF622684a251A28D8a9b05bC8c850629, pay_gem=DSToken, buy_gem=DSToken, taker=[Receiver] DSProxy, take_amt=608412778242, give_amt=369252356641355, timestamp=1564362512 )
49 MatchingMarket.LogTrade( pay_amt=608412778242, pay_gem=DSToken, buy_amt=369252356641355, buy_gem=DSToken )
50 DSToken.Approval( src=[Receiver] DSProxy, guy=SaiTub, wad=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
51 DSToken.Approval( owner=[Receiver] DSProxy, spender=SaiTub, value=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
52 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
53 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
54 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
55 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
56 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
57 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
58 SaiTub.0x73b3810100000000000000000000000000000000000000000000000000000000( 0x73b3810100000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000004b40fa34319db5c6327ec5ac07b7d2f4e64a635a, 0x000000000000000000000000000000000000000000000000000000000000606d, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000004000000000, 0000000000000000000000000000000000000000000000000000004473b38101, 000000000000000000000000000000000000000000000000000000000000606d, 00000000000000000000000000000000000000000000000006f05b59d3b20000 )
59 DSToken.Burn( guy=[Receiver] DSProxy, wad=500000000000000000 )
60 DSToken.Transfer( from=[Receiver] DSProxy, to=GemPit, value=608412778242 )

Account State Difference:

  Address   Before After State Difference Code
0x39755357...a409AE24e
(Eth2Dai: Old Contract)
0x448a5065...040f59af3
(Sky: Contract 1)
0x7728d2B2...B0A48b753
0.0101976691 Eth
Nonce: 5
0.0098054091 Eth
Nonce: 6
0.00039226
0x89d24A6b...a23260359
0x9f8F72aA...cC3A579A2
24,037.305972835512256654 Eth24,037.306365095512256654 Eth0.00039226

Execution Trace

DSProxy.execute( _target=0x526af336D614adE5cc252A407062B8861aF998F5, _data=0x8A9FC475000000000000000000000000448A5065AEBB8E423F0896E6C5D525C040F59AF3000000000000000000000000000000000000000000000000000000000000606D00000000000000000000000000000000000000000000000006F05B59D3B2000000000000000000000000000039755357759CE0D7F32DC8DC45414CCA409AE24E ) => ( response=0000000000000000000000000000000000000000000000000000000000000000 )
  • SaiProxyCreateAndExecute.wipe( tub_=0x448a5065aeBB8E423F0896E6c5D525C040f59af3, cup=000000000000000000000000000000000000000000000000000000000000606D, wad=500000000000000000, otc_=0x39755357759cE0d7f32dC8dC45414CCa409AE24e )
    • SaiTub.CALL( )
    • DSToken.transferFrom( src=0x7728d2B25371C2646FD87d28AdE7C5fB0A48b753, dst=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, wad=500000000000000000 ) => ( True )
    • SaiTub.rap( cup=000000000000000000000000000000000000000000000000000000000000606D ) => ( 398319700806590 )
    • SaiTub.tab( cup=000000000000000000000000000000000000000000000000000000000000606D ) => ( 560000000000000000 )
    • SaiTub.CALL( )
    • OSM.CALL( )
    • SaiTub.CALL( )
    • SaiTub.CALL( )
    • MatchingMarket.getPayAmount( pay_gem=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359, buy_gem=0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, buy_amt=608412778242 ) => ( fill_amt=369252356641355 )
    • SaiTub.CALL( )
    • DSToken.allowance( src=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, guy=0x39755357759cE0d7f32dC8dC45414CCa409AE24e ) => ( 0 )
    • SaiTub.CALL( )
    • DSToken.approve( guy=0x39755357759cE0d7f32dC8dC45414CCa409AE24e, wad=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
    • SaiTub.CALL( )
    • DSToken.transferFrom( src=0x7728d2B25371C2646FD87d28AdE7C5fB0A48b753, dst=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, wad=369252356641355 ) => ( True )
    • SaiTub.CALL( )
    • SaiTub.CALL( )
    • MatchingMarket.buyAllAmount( buy_gem=0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2, buy_amt=608412778242, pay_gem=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359, max_fill_amount=369252356641355 ) => ( fill_amt=369252356641355 )
      • DSToken.transferFrom( src=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, dst=0xAe34FFe5BF622684a251A28D8a9b05bC8c850629, wad=369252356641355 ) => ( True )
      • DSToken.transfer( dst=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, wad=608412778242 ) => ( True )
      • SaiTub.CALL( )
      • DSToken.allowance( src=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, guy=0x448a5065aeBB8E423F0896E6c5D525C040f59af3 ) => ( 0 )
      • SaiTub.CALL( )
      • DSToken.approve( guy=0x448a5065aeBB8E423F0896E6c5D525C040f59af3, wad=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
      • SaiTub.CALL( )
      • DSToken.allowance( src=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, guy=0x448a5065aeBB8E423F0896E6c5D525C040f59af3 ) => ( 0 )
      • SaiTub.CALL( )
      • DSToken.approve( guy=0x448a5065aeBB8E423F0896E6c5D525C040f59af3, wad=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( True )
      • SaiTub.wipe( cup=000000000000000000000000000000000000000000000000000000000000606D, wad=500000000000000000 )
        • DSToken.burn( guy=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, wad=500000000000000000 )
          • DSGuard.canCall( src_=0x448a5065aeBB8E423F0896E6c5D525C040f59af3, dst_=0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359, sig=System.Byte[] ) => ( True )
          • OSM.CALL( )
          • DSToken.move( src=0x4b40FA34319db5c6327ec5aC07B7D2f4E64a635A, dst=0x69076e44a9C70a67D5b79d95795Aba299083c275, wad=608412778242 )
            File 1 of 9: DSProxy
            // proxy.sol - execute actions atomically through the proxy's identity
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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.23;
            
            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;
            
                constructor() public {
                    owner = msg.sender;
                    emit LogSetOwner(msg.sender);
                }
            
                function setOwner(address owner_)
                    public
                    auth
                {
                    owner = owner_;
                    emit LogSetOwner(owner);
                }
            
                function setAuthority(DSAuthority authority_)
                    public
                    auth
                {
                    authority = authority_;
                    emit 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);
                    }
                }
            }
            
            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)
                    }
            
                    emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
            
                    _;
                }
            }
            
            // DSProxy
            // Allows code execution using a persistant identity This can be very
            // useful to execute a sequence of atomic actions. Since the owner of
            // the proxy can be changed, this allows for dynamic ownership models
            // i.e. a multisig
            contract DSProxy is DSAuth, DSNote {
                DSProxyCache public cache;  // global cache for contracts
            
                constructor(address _cacheAddr) public {
                    require(setCache(_cacheAddr));
                }
            
                function() public payable {
                }
            
                // use the proxy to execute calldata _data on contract _code
                function execute(bytes _code, bytes _data)
                    public
                    payable
                    returns (address target, bytes32 response)
                {
                    target = cache.read(_code);
                    if (target == 0x0) {
                        // deploy contract & store its address in cache
                        target = cache.write(_code);
                    }
            
                    response = execute(target, _data);
                }
            
                function execute(address _target, bytes _data)
                    public
                    auth
                    note
                    payable
                    returns (bytes32 response)
                {
                    require(_target != 0x0);
            
                    // call contract in current context
                    assembly {
                        let succeeded := delegatecall(sub(gas, 5000), _target, add(_data, 0x20), mload(_data), 0, 32)
                        response := mload(0)      // load delegatecall output
                        switch iszero(succeeded)
                        case 1 {
                            // throw if delegatecall failed
                            revert(0, 0)
                        }
                    }
                }
            
                //set new cache
                function setCache(address _cacheAddr)
                    public
                    auth
                    note
                    returns (bool)
                {
                    require(_cacheAddr != 0x0);        // invalid cache address
                    cache = DSProxyCache(_cacheAddr);  // overwrite cache
                    return true;
                }
            }
            
            // DSProxyFactory
            // This factory deploys new proxy instances through build()
            // Deployed proxy addresses are logged
            contract DSProxyFactory {
                event Created(address indexed sender, address indexed owner, address proxy, address cache);
                mapping(address=>bool) public isProxy;
                DSProxyCache public cache = new DSProxyCache();
            
                // deploys a new proxy instance
                // sets owner of proxy to caller
                function build() public returns (DSProxy proxy) {
                    proxy = build(msg.sender);
                }
            
                // deploys a new proxy instance
                // sets custom owner of proxy
                function build(address owner) public returns (DSProxy proxy) {
                    proxy = new DSProxy(cache);
                    emit Created(msg.sender, owner, address(proxy), address(cache));
                    proxy.setOwner(owner);
                    isProxy[proxy] = true;
                }
            }
            
            // DSProxyCache
            // This global cache stores addresses of contracts previously deployed
            // by a proxy. This saves gas from repeat deployment of the same
            // contracts and eliminates blockchain bloat.
            
            // By default, all proxies deployed from the same factory store
            // contracts in the same cache. The cache a proxy instance uses can be
            // changed.  The cache uses the sha3 hash of a contract's bytecode to
            // lookup the address
            contract DSProxyCache {
                mapping(bytes32 => address) cache;
            
                function read(bytes _code) public view returns (address) {
                    bytes32 hash = keccak256(_code);
                    return cache[hash];
                }
            
                function write(bytes _code) public returns (address target) {
                    assembly {
                        target := create(0, add(_code, 0x20), mload(_code))
                        switch iszero(extcodesize(target))
                        case 1 {
                            // throw if contract failed to deploy
                            revert(0, 0)
                        }
                    }
                    bytes32 hash = keccak256(_code);
                    cache[hash] = target;
                }
            }

            File 2 of 9: DSToken
            pragma solidity ^0.4.13;
            
            ////// lib/ds-math/src/math.sol
            /// 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);
                        }
                    }
                }
            }
            
            ////// lib/ds-stop/lib/ds-auth/src/auth.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.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);
                    }
                }
            }
            
            ////// lib/ds-stop/lib/ds-note/src/note.sol
            /// 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);
            
                    _;
                }
            }
            
            ////// lib/ds-stop/src/stop.sol
            /// stop.sol -- mixin for enable/disable functionality
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-note/note.sol"; */
            
            contract DSStop is DSNote, DSAuth {
            
                bool public stopped;
            
                modifier stoppable {
                    require(!stopped);
                    _;
                }
                function stop() public auth note {
                    stopped = true;
                }
                function start() public auth note {
                    stopped = false;
                }
            
            }
            
            ////// lib/erc20/src/erc20.sol
            /// 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);
            }
            
            ////// src/base.sol
            /// base.sol -- basic ERC20 implementation
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "erc20/erc20.sol"; */
            /* import "ds-math/math.sol"; */
            
            contract DSTokenBase is ERC20, DSMath {
                uint256                                            _supply;
                mapping (address => uint256)                       _balances;
                mapping (address => mapping (address => uint256))  _approvals;
            
                function DSTokenBase(uint supply) public {
                    _balances[msg.sender] = supply;
                    _supply = supply;
                }
            
                function totalSupply() public view returns (uint) {
                    return _supply;
                }
                function balanceOf(address src) public view returns (uint) {
                    return _balances[src];
                }
                function allowance(address src, address guy) public view returns (uint) {
                    return _approvals[src][guy];
                }
            
                function transfer(address dst, uint wad) public returns (bool) {
                    return transferFrom(msg.sender, dst, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    returns (bool)
                {
                    if (src != msg.sender) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function approve(address guy, uint wad) public returns (bool) {
                    _approvals[msg.sender][guy] = wad;
            
                    Approval(msg.sender, guy, wad);
            
                    return true;
                }
            }
            
            ////// src/token.sol
            /// token.sol -- ERC20 implementation with minting and burning
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-stop/stop.sol"; */
            
            /* import "./base.sol"; */
            
            contract DSToken is DSTokenBase(0), DSStop {
            
                bytes32  public  symbol;
                uint256  public  decimals = 18; // standard token precision. override to customize
            
                function DSToken(bytes32 symbol_) public {
                    symbol = symbol_;
                }
            
                event Mint(address indexed guy, uint wad);
                event Burn(address indexed guy, uint wad);
            
                function approve(address guy) public stoppable returns (bool) {
                    return super.approve(guy, uint(-1));
                }
            
                function approve(address guy, uint wad) public stoppable returns (bool) {
                    return super.approve(guy, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    stoppable
                    returns (bool)
                {
                    if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function push(address dst, uint wad) public {
                    transferFrom(msg.sender, dst, wad);
                }
                function pull(address src, uint wad) public {
                    transferFrom(src, msg.sender, wad);
                }
                function move(address src, address dst, uint wad) public {
                    transferFrom(src, dst, wad);
                }
            
                function mint(uint wad) public {
                    mint(msg.sender, wad);
                }
                function burn(uint wad) public {
                    burn(msg.sender, wad);
                }
                function mint(address guy, uint wad) public auth stoppable {
                    _balances[guy] = add(_balances[guy], wad);
                    _supply = add(_supply, wad);
                    Mint(guy, wad);
                }
                function burn(address guy, uint wad) public auth stoppable {
                    if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
                        _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
                    }
            
                    _balances[guy] = sub(_balances[guy], wad);
                    _supply = sub(_supply, wad);
                    Burn(guy, wad);
                }
            
                // Optional token name
                bytes32   public  name = "";
            
                function setName(bytes32 name_) public auth {
                    name = name_;
                }
            }

            File 3 of 9: SaiTub
            // hevm: flattened sources of src/tub.sol
            pragma solidity ^0.4.18;
            
            ////// lib/ds-guard/lib/ds-auth/src/auth.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.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);
                    }
                }
            }
            
            ////// lib/ds-spell/lib/ds-note/src/note.sol
            /// 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);
            
                    _;
                }
            }
            
            ////// lib/ds-thing/lib/ds-math/src/math.sol
            /// 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);
                        }
                    }
                }
            }
            
            ////// lib/ds-thing/src/thing.sol
            // thing.sol - `auth` with handy mixins. your things should be DSThings
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import 'ds-auth/auth.sol'; */
            /* import 'ds-note/note.sol'; */
            /* import 'ds-math/math.sol'; */
            
            contract DSThing is DSAuth, DSNote, DSMath {
            
                function S(string s) internal pure returns (bytes4) {
                    return bytes4(keccak256(s));
                }
            
            }
            
            ////// lib/ds-token/lib/ds-stop/src/stop.sol
            /// stop.sol -- mixin for enable/disable functionality
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-note/note.sol"; */
            
            contract DSStop is DSNote, DSAuth {
            
                bool public stopped;
            
                modifier stoppable {
                    require(!stopped);
                    _;
                }
                function stop() public auth note {
                    stopped = true;
                }
                function start() public auth note {
                    stopped = false;
                }
            
            }
            
            ////// lib/ds-token/lib/erc20/src/erc20.sol
            /// 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);
            }
            
            ////// lib/ds-token/src/base.sol
            /// base.sol -- basic ERC20 implementation
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "erc20/erc20.sol"; */
            /* import "ds-math/math.sol"; */
            
            contract DSTokenBase is ERC20, DSMath {
                uint256                                            _supply;
                mapping (address => uint256)                       _balances;
                mapping (address => mapping (address => uint256))  _approvals;
            
                function DSTokenBase(uint supply) public {
                    _balances[msg.sender] = supply;
                    _supply = supply;
                }
            
                function totalSupply() public view returns (uint) {
                    return _supply;
                }
                function balanceOf(address src) public view returns (uint) {
                    return _balances[src];
                }
                function allowance(address src, address guy) public view returns (uint) {
                    return _approvals[src][guy];
                }
            
                function transfer(address dst, uint wad) public returns (bool) {
                    return transferFrom(msg.sender, dst, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    returns (bool)
                {
                    if (src != msg.sender) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function approve(address guy, uint wad) public returns (bool) {
                    _approvals[msg.sender][guy] = wad;
            
                    Approval(msg.sender, guy, wad);
            
                    return true;
                }
            }
            
            ////// lib/ds-token/src/token.sol
            /// token.sol -- ERC20 implementation with minting and burning
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-stop/stop.sol"; */
            
            /* import "./base.sol"; */
            
            contract DSToken is DSTokenBase(0), DSStop {
            
                bytes32  public  symbol;
                uint256  public  decimals = 18; // standard token precision. override to customize
            
                function DSToken(bytes32 symbol_) public {
                    symbol = symbol_;
                }
            
                event Mint(address indexed guy, uint wad);
                event Burn(address indexed guy, uint wad);
            
                function approve(address guy) public stoppable returns (bool) {
                    return super.approve(guy, uint(-1));
                }
            
                function approve(address guy, uint wad) public stoppable returns (bool) {
                    return super.approve(guy, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    stoppable
                    returns (bool)
                {
                    if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function push(address dst, uint wad) public {
                    transferFrom(msg.sender, dst, wad);
                }
                function pull(address src, uint wad) public {
                    transferFrom(src, msg.sender, wad);
                }
                function move(address src, address dst, uint wad) public {
                    transferFrom(src, dst, wad);
                }
            
                function mint(uint wad) public {
                    mint(msg.sender, wad);
                }
                function burn(uint wad) public {
                    burn(msg.sender, wad);
                }
                function mint(address guy, uint wad) public auth stoppable {
                    _balances[guy] = add(_balances[guy], wad);
                    _supply = add(_supply, wad);
                    Mint(guy, wad);
                }
                function burn(address guy, uint wad) public auth stoppable {
                    if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
                        _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
                    }
            
                    _balances[guy] = sub(_balances[guy], wad);
                    _supply = sub(_supply, wad);
                    Burn(guy, wad);
                }
            
                // Optional token name
                bytes32   public  name = "";
            
                function setName(bytes32 name_) public auth {
                    name = name_;
                }
            }
            
            ////// lib/ds-value/src/value.sol
            /// value.sol - a value is a simple thing, it can be get and set
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import 'ds-thing/thing.sol'; */
            
            contract DSValue is DSThing {
                bool    has;
                bytes32 val;
                function peek() public view returns (bytes32, bool) {
                    return (val,has);
                }
                function read() public view returns (bytes32) {
                    var (wut, haz) = peek();
                    assert(haz);
                    return wut;
                }
                function poke(bytes32 wut) public note auth {
                    val = wut;
                    has = true;
                }
                function void() public note auth {  // unset the value
                    has = false;
                }
            }
            
            ////// src/vox.sol
            /// vox.sol -- target price feed
            
            // Copyright (C) 2016, 2017  Nikolai Mushegian <[email protected]>
            // Copyright (C) 2016, 2017  Daniel Brockman <[email protected]>
            // Copyright (C) 2017        Rain Break <[email protected]>
            
            // 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.18; */
            
            /* import "ds-thing/thing.sol"; */
            
            contract SaiVox is DSThing {
                uint256  _par;
                uint256  _way;
            
                uint256  public  fix;
                uint256  public  how;
                uint256  public  tau;
            
                function SaiVox(uint par_) public {
                    _par = fix = par_;
                    _way = RAY;
                    tau  = era();
                }
            
                function era() public view returns (uint) {
                    return block.timestamp;
                }
            
                function mold(bytes32 param, uint val) public note auth {
                    if (param == 'way') _way = val;
                }
            
                // Dai Target Price (ref per dai)
                function par() public returns (uint) {
                    prod();
                    return _par;
                }
                function way() public returns (uint) {
                    prod();
                    return _way;
                }
            
                function tell(uint256 ray) public note auth {
                    fix = ray;
                }
                function tune(uint256 ray) public note auth {
                    how = ray;
                }
            
                function prod() public note {
                    var age = era() - tau;
                    if (age == 0) return;  // optimised
                    tau = era();
            
                    if (_way != RAY) _par = rmul(_par, rpow(_way, age));  // optimised
            
                    if (how == 0) return;  // optimised
                    var wag = int128(how * age);
                    _way = inj(prj(_way) + (fix < _par ? wag : -wag));
                }
            
                function inj(int128 x) internal pure returns (uint256) {
                    return x >= 0 ? uint256(x) + RAY
                        : rdiv(RAY, RAY + uint256(-x));
                }
                function prj(uint256 x) internal pure returns (int128) {
                    return x >= RAY ? int128(x - RAY)
                        : int128(RAY) - int128(rdiv(RAY, x));
                }
            }
            
            ////// src/tub.sol
            /// tub.sol -- simplified CDP engine (baby brother of `vat')
            
            // Copyright (C) 2017  Nikolai Mushegian <[email protected]>
            // Copyright (C) 2017  Daniel Brockman <[email protected]>
            // Copyright (C) 2017  Rain Break <[email protected]>
            
            // 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.18; */
            
            /* import "ds-thing/thing.sol"; */
            /* import "ds-token/token.sol"; */
            /* import "ds-value/value.sol"; */
            
            /* import "./vox.sol"; */
            
            contract SaiTubEvents {
                event LogNewCup(address indexed lad, bytes32 cup);
            }
            
            contract SaiTub is DSThing, SaiTubEvents {
                DSToken  public  sai;  // Stablecoin
                DSToken  public  sin;  // Debt (negative sai)
            
                DSToken  public  skr;  // Abstracted collateral
                ERC20    public  gem;  // Underlying collateral
            
                DSToken  public  gov;  // Governance token
            
                SaiVox   public  vox;  // Target price feed
                DSValue  public  pip;  // Reference price feed
                DSValue  public  pep;  // Governance price feed
            
                address  public  tap;  // Liquidator
                address  public  pit;  // Governance Vault
            
                uint256  public  axe;  // Liquidation penalty
                uint256  public  cap;  // Debt ceiling
                uint256  public  mat;  // Liquidation ratio
                uint256  public  tax;  // Stability fee
                uint256  public  fee;  // Governance fee
                uint256  public  gap;  // Join-Exit Spread
            
                bool     public  off;  // Cage flag
                bool     public  out;  // Post cage exit
            
                uint256  public  fit;  // REF per SKR (just before settlement)
            
                uint256  public  rho;  // Time of last drip
                uint256         _chi;  // Accumulated Tax Rates
                uint256         _rhi;  // Accumulated Tax + Fee Rates
                uint256  public  rum;  // Total normalised debt
            
                uint256                   public  cupi;
                mapping (bytes32 => Cup)  public  cups;
            
                struct Cup {
                    address  lad;      // CDP owner
                    uint256  ink;      // Locked collateral (in SKR)
                    uint256  art;      // Outstanding normalised debt (tax only)
                    uint256  ire;      // Outstanding normalised debt
                }
            
                function lad(bytes32 cup) public view returns (address) {
                    return cups[cup].lad;
                }
                function ink(bytes32 cup) public view returns (uint) {
                    return cups[cup].ink;
                }
                function tab(bytes32 cup) public returns (uint) {
                    return rmul(cups[cup].art, chi());
                }
                function rap(bytes32 cup) public returns (uint) {
                    return sub(rmul(cups[cup].ire, rhi()), tab(cup));
                }
            
                // Total CDP Debt
                function din() public returns (uint) {
                    return rmul(rum, chi());
                }
                // Backing collateral
                function air() public view returns (uint) {
                    return skr.balanceOf(this);
                }
                // Raw collateral
                function pie() public view returns (uint) {
                    return gem.balanceOf(this);
                }
            
                //------------------------------------------------------------------
            
                function SaiTub(
                    DSToken  sai_,
                    DSToken  sin_,
                    DSToken  skr_,
                    ERC20    gem_,
                    DSToken  gov_,
                    DSValue  pip_,
                    DSValue  pep_,
                    SaiVox   vox_,
                    address  pit_
                ) public {
                    gem = gem_;
                    skr = skr_;
            
                    sai = sai_;
                    sin = sin_;
            
                    gov = gov_;
                    pit = pit_;
            
                    pip = pip_;
                    pep = pep_;
                    vox = vox_;
            
                    axe = RAY;
                    mat = RAY;
                    tax = RAY;
                    fee = RAY;
                    gap = WAD;
            
                    _chi = RAY;
                    _rhi = RAY;
            
                    rho = era();
                }
            
                function era() public constant returns (uint) {
                    return block.timestamp;
                }
            
                //--Risk-parameter-config-------------------------------------------
            
                function mold(bytes32 param, uint val) public note auth {
                    if      (param == 'cap') cap = val;
                    else if (param == 'mat') { require(val >= RAY); mat = val; }
                    else if (param == 'tax') { require(val >= RAY); drip(); tax = val; }
                    else if (param == 'fee') { require(val >= RAY); drip(); fee = val; }
                    else if (param == 'axe') { require(val >= RAY); axe = val; }
                    else if (param == 'gap') { require(val >= WAD); gap = val; }
                    else return;
                }
            
                //--Price-feed-setters----------------------------------------------
            
                function setPip(DSValue pip_) public note auth {
                    pip = pip_;
                }
                function setPep(DSValue pep_) public note auth {
                    pep = pep_;
                }
                function setVox(SaiVox vox_) public note auth {
                    vox = vox_;
                }
            
                //--Tap-setter------------------------------------------------------
                function turn(address tap_) public note {
                    require(tap  == 0);
                    require(tap_ != 0);
                    tap = tap_;
                }
            
                //--Collateral-wrapper----------------------------------------------
            
                // Wrapper ratio (gem per skr)
                function per() public view returns (uint ray) {
                    return skr.totalSupply() == 0 ? RAY : rdiv(pie(), skr.totalSupply());
                }
                // Join price (gem per skr)
                function ask(uint wad) public view returns (uint) {
                    return rmul(wad, wmul(per(), gap));
                }
                // Exit price (gem per skr)
                function bid(uint wad) public view returns (uint) {
                    return rmul(wad, wmul(per(), sub(2 * WAD, gap)));
                }
                function join(uint wad) public note {
                    require(!off);
                    require(ask(wad) > 0);
                    require(gem.transferFrom(msg.sender, this, ask(wad)));
                    skr.mint(msg.sender, wad);
                }
                function exit(uint wad) public note {
                    require(!off || out);
                    require(gem.transfer(msg.sender, bid(wad)));
                    skr.burn(msg.sender, wad);
                }
            
                //--Stability-fee-accumulation--------------------------------------
            
                // Accumulated Rates
                function chi() public returns (uint) {
                    drip();
                    return _chi;
                }
                function rhi() public returns (uint) {
                    drip();
                    return _rhi;
                }
                function drip() public note {
                    if (off) return;
            
                    var rho_ = era();
                    var age = rho_ - rho;
                    if (age == 0) return;    // optimised
                    rho = rho_;
            
                    var inc = RAY;
            
                    if (tax != RAY) {  // optimised
                        var _chi_ = _chi;
                        inc = rpow(tax, age);
                        _chi = rmul(_chi, inc);
                        sai.mint(tap, rmul(sub(_chi, _chi_), rum));
                    }
            
                    // optimised
                    if (fee != RAY) inc = rmul(inc, rpow(fee, age));
                    if (inc != RAY) _rhi = rmul(_rhi, inc);
                }
            
            
                //--CDP-risk-indicator----------------------------------------------
            
                // Abstracted collateral price (ref per skr)
                function tag() public view returns (uint wad) {
                    return off ? fit : wmul(per(), uint(pip.read()));
                }
                // Returns true if cup is well-collateralized
                function safe(bytes32 cup) public returns (bool) {
                    var pro = rmul(tag(), ink(cup));
                    var con = rmul(vox.par(), tab(cup));
                    var min = rmul(con, mat);
                    return pro >= min;
                }
            
            
                //--CDP-operations--------------------------------------------------
            
                function open() public note returns (bytes32 cup) {
                    require(!off);
                    cupi = add(cupi, 1);
                    cup = bytes32(cupi);
                    cups[cup].lad = msg.sender;
                    LogNewCup(msg.sender, cup);
                }
                function give(bytes32 cup, address guy) public note {
                    require(msg.sender == cups[cup].lad);
                    require(guy != 0);
                    cups[cup].lad = guy;
                }
            
                function lock(bytes32 cup, uint wad) public note {
                    require(!off);
                    cups[cup].ink = add(cups[cup].ink, wad);
                    skr.pull(msg.sender, wad);
                    require(cups[cup].ink == 0 || cups[cup].ink > 0.005 ether);
                }
                function free(bytes32 cup, uint wad) public note {
                    require(msg.sender == cups[cup].lad);
                    cups[cup].ink = sub(cups[cup].ink, wad);
                    skr.push(msg.sender, wad);
                    require(safe(cup));
                    require(cups[cup].ink == 0 || cups[cup].ink > 0.005 ether);
                }
            
                function draw(bytes32 cup, uint wad) public note {
                    require(!off);
                    require(msg.sender == cups[cup].lad);
                    require(rdiv(wad, chi()) > 0);
            
                    cups[cup].art = add(cups[cup].art, rdiv(wad, chi()));
                    rum = add(rum, rdiv(wad, chi()));
            
                    cups[cup].ire = add(cups[cup].ire, rdiv(wad, rhi()));
                    sai.mint(cups[cup].lad, wad);
            
                    require(safe(cup));
                    require(sai.totalSupply() <= cap);
                }
                function wipe(bytes32 cup, uint wad) public note {
                    require(!off);
            
                    var owe = rmul(wad, rdiv(rap(cup), tab(cup)));
            
                    cups[cup].art = sub(cups[cup].art, rdiv(wad, chi()));
                    rum = sub(rum, rdiv(wad, chi()));
            
                    cups[cup].ire = sub(cups[cup].ire, rdiv(add(wad, owe), rhi()));
                    sai.burn(msg.sender, wad);
            
                    var (val, ok) = pep.peek();
                    if (ok && val != 0) gov.move(msg.sender, pit, wdiv(owe, uint(val)));
                }
            
                function shut(bytes32 cup) public note {
                    require(!off);
                    require(msg.sender == cups[cup].lad);
                    if (tab(cup) != 0) wipe(cup, tab(cup));
                    if (ink(cup) != 0) free(cup, ink(cup));
                    delete cups[cup];
                }
            
                function bite(bytes32 cup) public note {
                    require(!safe(cup) || off);
            
                    // Take on all of the debt, except unpaid fees
                    var rue = tab(cup);
                    sin.mint(tap, rue);
                    rum = sub(rum, cups[cup].art);
                    cups[cup].art = 0;
                    cups[cup].ire = 0;
            
                    // Amount owed in SKR, including liquidation penalty
                    var owe = rdiv(rmul(rmul(rue, axe), vox.par()), tag());
            
                    if (owe > cups[cup].ink) {
                        owe = cups[cup].ink;
                    }
            
                    skr.push(tap, owe);
                    cups[cup].ink = sub(cups[cup].ink, owe);
                }
            
                //------------------------------------------------------------------
            
                function cage(uint fit_, uint jam) public note auth {
                    require(!off && fit_ != 0);
                    off = true;
                    axe = RAY;
                    gap = WAD;
                    fit = fit_;         // ref per skr
                    require(gem.transfer(tap, jam));
                }
                function flow() public note auth {
                    require(off);
                    out = true;
                }
            }

            File 4 of 9: 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 5 of 9: DSToken
            // MKR Token
            
            // hevm: flattened sources of src/mkr-499.sol
            pragma solidity ^0.4.15;
            
            ////// lib/ds-roles/lib/ds-auth/src/auth.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.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);
                    }
                }
            }
            
            ////// lib/ds-thing/lib/ds-math/src/math.sol
            /// 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);
                        }
                    }
                }
            }
            
            ////// lib/ds-thing/lib/ds-note/src/note.sol
            /// 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);
            
                    _;
                }
            }
            
            ////// lib/ds-thing/src/thing.sol
            // thing.sol - `auth` with handy mixins. your things should be DSThings
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import 'ds-auth/auth.sol'; */
            /* import 'ds-note/note.sol'; */
            /* import 'ds-math/math.sol'; */
            
            contract DSThing is DSAuth, DSNote, DSMath {
            }
            
            ////// lib/ds-token/lib/ds-stop/src/stop.sol
            /// stop.sol -- mixin for enable/disable functionality
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-note/note.sol"; */
            
            contract DSStop is DSNote, DSAuth {
            
                bool public stopped;
            
                modifier stoppable {
                    require(!stopped);
                    _;
                }
                function stop() public auth note {
                    stopped = true;
                }
                function start() public auth note {
                    stopped = false;
                }
            
            }
            
            ////// lib/ds-token/lib/erc20/src/erc20.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.4.8; */
            
            // Token standard API
            // https://github.com/ethereum/EIPs/issues/20
            
            contract ERC20 {
                function totalSupply() public view returns (uint supply);
                function balanceOf( address who ) public view returns (uint value);
                function allowance( address owner, address spender ) public view returns (uint _allowance);
            
                function transfer( address to, uint value) public returns (bool ok);
                function transferFrom( address from, address to, uint value) public returns (bool ok);
                function approve( address spender, uint value ) public returns (bool ok);
            
                event Transfer( address indexed from, address indexed to, uint value);
                event Approval( address indexed owner, address indexed spender, uint value);
            }
            
            ////// lib/ds-token/src/base.sol
            /// base.sol -- basic ERC20 implementation
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "erc20/erc20.sol"; */
            /* import "ds-math/math.sol"; */
            
            contract DSTokenBase is ERC20, DSMath {
                uint256                                            _supply;
                mapping (address => uint256)                       _balances;
                mapping (address => mapping (address => uint256))  _approvals;
            
                function DSTokenBase(uint supply) public {
                    _balances[msg.sender] = supply;
                    _supply = supply;
                }
            
                function totalSupply() public view returns (uint) {
                    return _supply;
                }
                function balanceOf(address src) public view returns (uint) {
                    return _balances[src];
                }
                function allowance(address src, address guy) public view returns (uint) {
                    return _approvals[src][guy];
                }
            
                function transfer(address dst, uint wad) public returns (bool) {
                    return transferFrom(msg.sender, dst, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    returns (bool)
                {
                    if (src != msg.sender) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function approve(address guy, uint wad) public returns (bool) {
                    _approvals[msg.sender][guy] = wad;
            
                    Approval(msg.sender, guy, wad);
            
                    return true;
                }
            }
            
            ////// lib/ds-token/src/token.sol
            /// token.sol -- ERC20 implementation with minting and burning
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-stop/stop.sol"; */
            
            /* import "./base.sol"; */
            
            contract DSToken is DSTokenBase(0), DSStop {
            
                bytes32  public  symbol;
                uint256  public  decimals = 18; // standard token precision. override to customize
            
                function DSToken(bytes32 symbol_) public {
                    symbol = symbol_;
                }
            
                event Mint(address indexed guy, uint wad);
                event Burn(address indexed guy, uint wad);
            
                function approve(address guy) public stoppable returns (bool) {
                    return super.approve(guy, uint(-1));
                }
            
                function approve(address guy, uint wad) public stoppable returns (bool) {
                    return super.approve(guy, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    stoppable
                    returns (bool)
                {
                    if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function push(address dst, uint wad) public {
                    transferFrom(msg.sender, dst, wad);
                }
                function pull(address src, uint wad) public {
                    transferFrom(src, msg.sender, wad);
                }
                function move(address src, address dst, uint wad) public {
                    transferFrom(src, dst, wad);
                }
            
                function mint(uint wad) public {
                    mint(msg.sender, wad);
                }
                function burn(uint wad) public {
                    burn(msg.sender, wad);
                }
                function mint(address guy, uint wad) public auth stoppable {
                    _balances[guy] = add(_balances[guy], wad);
                    _supply = add(_supply, wad);
                    Mint(guy, wad);
                }
                function burn(address guy, uint wad) public auth stoppable {
                    if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
                        _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
                    }
            
                    _balances[guy] = sub(_balances[guy], wad);
                    _supply = sub(_supply, wad);
                    Burn(guy, wad);
                }
            
                // Optional token name
                bytes32   public  name = "";
            
                function setName(bytes32 name_) public auth {
                    name = name_;
                }
            }

            File 6 of 9: GemPit
            pragma solidity ^0.4.13;
            
            ////// lib/ds-math/src/math.sol
            /// 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);
                        }
                    }
                }
            }
            
            ////// lib/ds-stop/lib/ds-auth/src/auth.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.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);
                    }
                }
            }
            
            ////// lib/ds-stop/lib/ds-note/src/note.sol
            /// 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);
            
                    _;
                }
            }
            
            ////// lib/ds-stop/src/stop.sol
            /// stop.sol -- mixin for enable/disable functionality
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-note/note.sol"; */
            
            contract DSStop is DSNote, DSAuth {
            
                bool public stopped;
            
                modifier stoppable {
                    require(!stopped);
                    _;
                }
                function stop() public auth note {
                    stopped = true;
                }
                function start() public auth note {
                    stopped = false;
                }
            
            }
            
            ////// lib/erc20/src/erc20.sol
            /// 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);
            }
            
            ////// src/base.sol
            /// base.sol -- basic ERC20 implementation
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "erc20/erc20.sol"; */
            /* import "ds-math/math.sol"; */
            
            contract DSTokenBase is ERC20, DSMath {
                uint256                                            _supply;
                mapping (address => uint256)                       _balances;
                mapping (address => mapping (address => uint256))  _approvals;
            
                function DSTokenBase(uint supply) public {
                    _balances[msg.sender] = supply;
                    _supply = supply;
                }
            
                function totalSupply() public view returns (uint) {
                    return _supply;
                }
                function balanceOf(address src) public view returns (uint) {
                    return _balances[src];
                }
                function allowance(address src, address guy) public view returns (uint) {
                    return _approvals[src][guy];
                }
            
                function transfer(address dst, uint wad) public returns (bool) {
                    return transferFrom(msg.sender, dst, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    returns (bool)
                {
                    if (src != msg.sender) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function approve(address guy, uint wad) public returns (bool) {
                    _approvals[msg.sender][guy] = wad;
            
                    Approval(msg.sender, guy, wad);
            
                    return true;
                }
            }
            
            ////// src/token.sol
            /// token.sol -- ERC20 implementation with minting and burning
            
            // Copyright (C) 2015, 2016, 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-stop/stop.sol"; */
            
            /* import "./base.sol"; */
            
            contract DSToken is DSTokenBase(0), DSStop {
            
                bytes32  public  symbol;
                uint256  public  decimals = 18; // standard token precision. override to customize
            
                function DSToken(bytes32 symbol_) public {
                    symbol = symbol_;
                }
            
                event Mint(address indexed guy, uint wad);
                event Burn(address indexed guy, uint wad);
            
                function approve(address guy) public stoppable returns (bool) {
                    return super.approve(guy, uint(-1));
                }
            
                function approve(address guy, uint wad) public stoppable returns (bool) {
                    return super.approve(guy, wad);
                }
            
                function transferFrom(address src, address dst, uint wad)
                    public
                    stoppable
                    returns (bool)
                {
                    if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
                        _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
                    }
            
                    _balances[src] = sub(_balances[src], wad);
                    _balances[dst] = add(_balances[dst], wad);
            
                    Transfer(src, dst, wad);
            
                    return true;
                }
            
                function push(address dst, uint wad) public {
                    transferFrom(msg.sender, dst, wad);
                }
                function pull(address src, uint wad) public {
                    transferFrom(src, msg.sender, wad);
                }
                function move(address src, address dst, uint wad) public {
                    transferFrom(src, dst, wad);
                }
            
                function mint(uint wad) public {
                    mint(msg.sender, wad);
                }
                function burn(uint wad) public {
                    burn(msg.sender, wad);
                }
                function mint(address guy, uint wad) public auth stoppable {
                    _balances[guy] = add(_balances[guy], wad);
                    _supply = add(_supply, wad);
                    Mint(guy, wad);
                }
                function burn(address guy, uint wad) public auth stoppable {
                    if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
                        _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
                    }
            
                    _balances[guy] = sub(_balances[guy], wad);
                    _supply = sub(_supply, wad);
                    Burn(guy, wad);
                }
            
                // Optional token name
                bytes32   public  name = "";
            
                function setName(bytes32 name_) public auth {
                    name = name_;
                }
            }
            
            contract GemPit {
                function burn(DSToken gem) public {
                    gem.burn(gem.balanceOf(this));
                }
            }

            File 7 of 9: SaiProxyCreateAndExecute
            pragma solidity ^0.4.23;
            
            /// 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);
                        }
                    }
                }
            }
            
            contract TubInterface {
                function open() public returns (bytes32);
                function join(uint) public;
                function exit(uint) public;
                function lock(bytes32, uint) public;
                function free(bytes32, uint) public;
                function draw(bytes32, uint) public;
                function wipe(bytes32, uint) public;
                function give(bytes32, address) public;
                function shut(bytes32) public;
                function cups(bytes32) public view returns (address, uint, uint, uint);
                function gem() public view returns (TokenInterface);
                function gov() public view returns (TokenInterface);
                function skr() public view returns (TokenInterface);
                function sai() public view returns (TokenInterface);
                function mat() public view returns (uint);
                function ink(bytes32) public view returns (uint);
                function tab(bytes32) public view returns (uint);
                function rap(bytes32) public view returns (uint);
                function per() public view returns (uint);
                function pep() public view returns (PepInterface);
            }
            
            contract TokenInterface {
                function allowance(address, address) public view returns (uint);
                function balanceOf(address) public view returns (uint);
                function approve(address, uint) public;
                function transfer(address, uint) public returns (bool);
                function transferFrom(address, address, uint) public returns (bool);
                function deposit() public payable;
                function withdraw(uint) public;
            }
            
            contract PepInterface {
                function peek() public returns (bytes32, bool);
            }
            
            contract OtcInterface {
                function getPayAmount(address, address, uint) public view returns (uint);
                function buyAllAmount(address, uint, address pay_gem, uint) public returns (uint);
            }
            
            contract SaiProxy is DSMath {
                function open(address tub_) public returns (bytes32) {
                    return TubInterface(tub_).open();
                }
            
                function give(address tub_, bytes32 cup, address lad) public {
                    TubInterface(tub_).give(cup, lad);
                }
            
                function lock(address tub_, bytes32 cup) public payable {
                    if (msg.value > 0) {
                        TubInterface tub = TubInterface(tub_);
            
                        (address lad,,,) = tub.cups(cup);
                        require(lad == address(this), "cup-not-owned");
            
                        tub.gem().deposit.value(msg.value)();
            
                        uint ink = rdiv(msg.value, tub.per());
                        ink = rmul(ink, tub.per()) <= msg.value ? ink : ink - 1;
            
                        if (tub.gem().allowance(this, tub) != uint(-1)) {
                            tub.gem().approve(tub, uint(-1));
                        }
                        tub.join(ink);
            
                        if (tub.skr().allowance(this, tub) != uint(-1)) {
                            tub.skr().approve(tub, uint(-1));
                        }
                        tub.lock(cup, ink);
                    }
                }
            
                function draw(address tub_, bytes32 cup, uint wad) public {
                    if (wad > 0) {
                        TubInterface tub = TubInterface(tub_);
                        tub.draw(cup, wad);
                        tub.sai().transfer(msg.sender, wad);
                    }
                }
            
                function handleGovFee(TubInterface tub, uint saiDebtFee, address otc_) internal {
                    bytes32 val;
                    bool ok;
                    (val, ok) = tub.pep().peek();
                    if (ok && val != 0) {
                        uint govAmt = wdiv(saiDebtFee, uint(val));
                        if (otc_ != address(0)) {
                            uint saiGovAmt = OtcInterface(otc_).getPayAmount(tub.sai(), tub.gov(), govAmt);
                            if (tub.sai().allowance(this, otc_) != uint(-1)) {
                                tub.sai().approve(otc_, uint(-1));
                            }
                            tub.sai().transferFrom(msg.sender, this, saiGovAmt);
                            OtcInterface(otc_).buyAllAmount(tub.gov(), govAmt, tub.sai(), saiGovAmt);
                        } else {
                            tub.gov().transferFrom(msg.sender, this, govAmt);
                        }
                    }
                }
            
                function wipe(address tub_, bytes32 cup, uint wad, address otc_) public {
                    if (wad > 0) {
                        TubInterface tub = TubInterface(tub_);
            
                        tub.sai().transferFrom(msg.sender, this, wad);
                        handleGovFee(tub, rmul(wad, rdiv(tub.rap(cup), tub.tab(cup))), otc_);
            
                        if (tub.sai().allowance(this, tub) != uint(-1)) {
                            tub.sai().approve(tub, uint(-1));
                        }
                        if (tub.gov().allowance(this, tub) != uint(-1)) {
                            tub.gov().approve(tub, uint(-1));
                        }
                        tub.wipe(cup, wad);
                    }
                }
            
                function wipe(address tub_, bytes32 cup, uint wad) public {
                    wipe(tub_, cup, wad, address(0));
                }
            
                function free(address tub_, bytes32 cup, uint jam) public {
                    if (jam > 0) {
                        TubInterface tub = TubInterface(tub_);
                        uint ink = rdiv(jam, tub.per());
                        ink = rmul(ink, tub.per()) <= jam ? ink : ink - 1;
                        tub.free(cup, ink);
                        if (tub.skr().allowance(this, tub) != uint(-1)) {
                            tub.skr().approve(tub, uint(-1));
                        }
                        tub.exit(ink);
                        uint freeJam = tub.gem().balanceOf(this); // Withdraw possible previous stuck WETH as well
                        tub.gem().withdraw(freeJam);
                        address(msg.sender).transfer(freeJam);
                    }
                }
            
                function lockAndDraw(address tub_, bytes32 cup, uint wad) public payable {
                    lock(tub_, cup);
                    draw(tub_, cup, wad);
                }
            
                function lockAndDraw(address tub_, uint wad) public payable returns (bytes32 cup) {
                    cup = open(tub_);
                    lockAndDraw(tub_, cup, wad);
                }
            
                function wipeAndFree(address tub_, bytes32 cup, uint jam, uint wad) public payable {
                    wipe(tub_, cup, wad);
                    free(tub_, cup, jam);
                }
            
                function wipeAndFree(address tub_, bytes32 cup, uint jam, uint wad, address otc_) public payable {
                    wipe(tub_, cup, wad, otc_);
                    free(tub_, cup, jam);
                }
            
                function shut(address tub_, bytes32 cup) public {
                    TubInterface tub = TubInterface(tub_);
                    wipeAndFree(tub_, cup, rmul(tub.ink(cup), tub.per()), tub.tab(cup));
                    tub.shut(cup);
                }
            
                function shut(address tub_, bytes32 cup, address otc_) public {
                    TubInterface tub = TubInterface(tub_);
                    wipeAndFree(tub_, cup, rmul(tub.ink(cup), tub.per()), tub.tab(cup), otc_);
                    tub.shut(cup);
                }
            }
            
            contract ProxyRegistryInterface {
                function build(address) public returns (address);
            }
            
            contract SaiProxyCreateAndExecute is SaiProxy {
            
                // Create a DSProxy instance and open a cup
                function createAndOpen(address registry_, address tub_) public returns (address proxy, bytes32 cup) {
                    proxy = ProxyRegistryInterface(registry_).build(msg.sender);
                    cup = open(tub_);
                    TubInterface(tub_).give(cup, proxy);
                }
            
                // Create a DSProxy instance, open a cup, and lock collateral
                function createOpenAndLock(address registry_, address tub_) public payable returns (address proxy, bytes32 cup) {
                    proxy = ProxyRegistryInterface(registry_).build(msg.sender);
                    cup = open(tub_);
                    lock(tub_, cup);
                    TubInterface(tub_).give(cup, proxy);
                }
            
                // Create a DSProxy instance, open a cup, lock collateral, and draw DAI
                function createOpenLockAndDraw(address registry_, address tub_, uint wad) public payable returns (address proxy, bytes32 cup) {
                    proxy = ProxyRegistryInterface(registry_).build(msg.sender);
                    cup = open(tub_);
                    lockAndDraw(tub_, cup, wad);
                    TubInterface(tub_).give(cup, proxy);
                }
            }

            File 8 of 9: OSM
            // hevm: flattened sources of src/osm.sol
            pragma solidity ^0.4.24;
            
            ////// lib/ds-stop/lib/ds-auth/src/auth.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.4.23; */
            
            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;
            
                constructor() public {
                    owner = msg.sender;
                    emit LogSetOwner(msg.sender);
                }
            
                function setOwner(address owner_)
                    public
                    auth
                {
                    owner = owner_;
                    emit LogSetOwner(owner);
                }
            
                function setAuthority(DSAuthority authority_)
                    public
                    auth
                {
                    authority = authority_;
                    emit 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);
                    }
                }
            }
            
            ////// lib/ds-stop/lib/ds-note/src/note.sol
            /// 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.23; */
            
            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)
                    }
            
                    emit LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
            
                    _;
                }
            }
            
            ////// lib/ds-stop/src/stop.sol
            /// stop.sol -- mixin for enable/disable functionality
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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.23; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-note/note.sol"; */
            
            contract DSStop is DSNote, DSAuth {
            
                bool public stopped;
            
                modifier stoppable {
                    require(!stopped);
                    _;
                }
                function stop() public auth note {
                    stopped = true;
                }
                function start() public auth note {
                    stopped = false;
                }
            
            }
            
            ////// src/osm.sol
            /// osm.sol - oracle security module
            
            // Copyright (C) 2018  DappHub, LLC
            
            // 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.24; */
            
            /* import "ds-auth/auth.sol"; */
            /* import "ds-stop/stop.sol"; */
            // import "ds-value/value.sol";
            
            interface DSValue {
                function peek() external returns (bytes32,bool);
                function read() external returns (bytes32);
            }
            
            contract OSM is DSAuth, DSStop {
                DSValue public src;
                
                uint16 constant ONE_HOUR = uint16(3600);
            
                uint16 public hop = ONE_HOUR;
                uint64 public zzz;
            
                struct Feed {
                    uint128 val;
                    bool    has;
                }
            
                Feed cur;
                Feed nxt;
            
                event LogValue(bytes32 val);
                
                constructor (DSValue src_) public {
                    src = src_;
                    (bytes32 wut, bool ok) = src_.peek();
                    if (ok) {
                        cur = nxt = Feed(uint128(wut), ok);
                        zzz = prev(era());
                    }
                }
            
                function era() internal view returns (uint) {
                    return block.timestamp;
                }
            
                function prev(uint ts) internal view returns (uint64) {
                    return uint64(ts - (ts % hop));
                }
            
                function step(uint16 ts) external auth {
                    require(ts > 0);
                    hop = ts;
                }
            
                function void() external auth {
                    cur = nxt = Feed(0, false);
                    stopped = true;
                }
            
                function pass() public view returns (bool ok) {
                    return era() >= zzz + hop;
                }
            
                function poke() external stoppable {
                    require(pass());
                    (bytes32 wut, bool ok) = src.peek();
                    cur = nxt;
                    nxt = Feed(uint128(wut), ok);
                    zzz = prev(era());
                    emit LogValue(bytes32(cur.val));
                }
            
                function peek() external view returns (bytes32,bool) {
                    return (bytes32(cur.val), cur.has);
                }
            
                function peep() external view returns (bytes32,bool) {
                    return (bytes32(nxt.val), nxt.has);
                }
            
                function read() external view returns (bytes32) {
                    require(cur.has);
                    return (bytes32(cur.val));
                }
            }

            File 9 of 9: DSGuard
            // hevm: flattened sources of src/guard.sol
            pragma solidity ^0.4.13;
            
            ////// lib/ds-auth/src/auth.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.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);
                    }
                }
            }
            
            ////// src/guard.sol
            // guard.sol -- simple whitelist implementation of DSAuthority
            
            // Copyright (C) 2017  DappHub, LLC
            
            // 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; */
            
            /* import "ds-auth/auth.sol"; */
            
            contract DSGuardEvents {
                event LogPermit(
                    bytes32 indexed src,
                    bytes32 indexed dst,
                    bytes32 indexed sig
                );
            
                event LogForbid(
                    bytes32 indexed src,
                    bytes32 indexed dst,
                    bytes32 indexed sig
                );
            }
            
            contract DSGuard is DSAuth, DSAuthority, DSGuardEvents {
                bytes32 constant public ANY = bytes32(uint(-1));
            
                mapping (bytes32 => mapping (bytes32 => mapping (bytes32 => bool))) acl;
            
                function canCall(
                    address src_, address dst_, bytes4 sig
                ) public view returns (bool) {
                    var src = bytes32(src_);
                    var dst = bytes32(dst_);
            
                    return acl[src][dst][sig]
                        || acl[src][dst][ANY]
                        || acl[src][ANY][sig]
                        || acl[src][ANY][ANY]
                        || acl[ANY][dst][sig]
                        || acl[ANY][dst][ANY]
                        || acl[ANY][ANY][sig]
                        || acl[ANY][ANY][ANY];
                }
            
                function permit(bytes32 src, bytes32 dst, bytes32 sig) public auth {
                    acl[src][dst][sig] = true;
                    LogPermit(src, dst, sig);
                }
            
                function forbid(bytes32 src, bytes32 dst, bytes32 sig) public auth {
                    acl[src][dst][sig] = false;
                    LogForbid(src, dst, sig);
                }
            
                function permit(address src, address dst, bytes32 sig) public {
                    permit(bytes32(src), bytes32(dst), sig);
                }
                function forbid(address src, address dst, bytes32 sig) public {
                    forbid(bytes32(src), bytes32(dst), sig);
                }
            
            }
            
            contract DSGuardFactory {
                mapping (address => bool)  public  isGuard;
            
                function newGuard() public returns (DSGuard guard) {
                    guard = new DSGuard();
                    guard.setOwner(msg.sender);
                    isGuard[guard] = true;
                }
            }