ETH Price: $2,263.71 (-6.60%)

Transaction Decoder

Block:
9309221 at Jan-19-2020 03:02:43 AM +UTC
Transaction Fee:
0.000797043 ETH $1.80
Gas Used:
204,370 Gas / 3.9 Gwei

Emitted Events:

109 Dai.Transfer( src=Vyper_contract, dst=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, wad=333890232920294349791 )
110 Vyper_contract.TokenPurchase( buyer=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, eth_sold=1892146840188315457, tokens_bought=333890232920294349791 )
111 Dai.Transfer( src=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, dst=ScdMcdMigration, wad=333890232920294349791 )
112 Vat.0xbb35783b00000000000000000000000000000000000000000000000000000000( 0xbb35783b00000000000000000000000000000000000000000000000000000000, 0x0000000000000000000000009759a6ac90977b93b58547b4a71c78317f391a28, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x0000000000000000000000003a7c27e67b3a5f4d45ecea37f3d9ef8618000000, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, bb35783b0000000000000000000000009759a6ac90977b93b58547b4a71c7831, 7f391a28000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab8490000000000000000000000003a7c27e67b3a5f4d45ecea37f3d9ef86, 1800000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
113 Dai.Transfer( src=ScdMcdMigration, dst=0x0000000000000000000000000000000000000000, wad=333890232920294349791 )
114 DaiJoin.0x3b4da69f00000000000000000000000000000000000000000000000000000000( 0x3b4da69f00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x00000000000000000000000000000000000000000000001219a865d09294dbdf, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 3b4da69f000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab84900000000000000000000000000000000000000000000001219a865d0, 9294dbdf00000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
115 Vat.0x7608870300000000000000000000000000000000000000000000000000000000( 0x7608870300000000000000000000000000000000000000000000000000000000, 0x5341490000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7608870353414900000000000000000000000000000000000000000000000000, 00000000000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849ffffffffffffffffffffffffffffffffffffffffffffffede6579a2f, 6d6b2421ffffffffffffffffffffffffffffffffffffffffffffffede6579a2f, 6d6b242100000000000000000000000000000000000000000000000000000000 )
116 Vat.0x7cdd3fde00000000000000000000000000000000000000000000000000000000( 0x7cdd3fde00000000000000000000000000000000000000000000000000000000, 0x5341490000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0xffffffffffffffffffffffffffffffffffffffffffffffede6579a2f6d6b2421, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, 7cdd3fde53414900000000000000000000000000000000000000000000000000, 00000000000000000000000000000000c73e0383f3aff3215e6f04b0331d58ce, cf0ab849ffffffffffffffffffffffffffffffffffffffffffffffede6579a2f, 6d6b242100000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
117 DSToken.Transfer( src=AuthGemJoin, dst=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, wad=333890232920294349791 )
118 AuthGemJoin.0xef693bed00000000000000000000000000000000000000000000000000000000( 0xef693bed00000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000c73e0383f3aff3215e6f04b0331d58cecf0ab849, 0x00000000000000000000000053bba5c7872bfc4935cb4eee63c1ba9bfc68212a, 0x00000000000000000000000000000000000000000000001219a865d09294dbdf, 0000000000000000000000000000000000000000000000000000000000000020, 00000000000000000000000000000000000000000000000000000000000000e0, ef693bed00000000000000000000000053bba5c7872bfc4935cb4eee63c1ba9b, fc68212a00000000000000000000000000000000000000000000001219a865d0, 9294dbdf00000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000000 )
119 DSToken.Transfer( src=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, dst=Vyper_contract, wad=333890232920294349791 )
120 Vyper_contract.EthPurchase( buyer=[Receiver] 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a, tokens_sold=333890232920294349791, eth_bought=1893629219738547690 )
121 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a.0xf0f26da951e90d8b4c99110cadade2ca3b0115566d018c61e7cc163580b5b940( 0xf0f26da951e90d8b4c99110cadade2ca3b0115566d018c61e7cc163580b5b940, 0000000000000000000000000000000000000000000000000005443762838ea9 )

Account State Difference:

  Address   Before After State Difference Code
0x00000000...7ef99D8c5
(Mining Express)
16.902928386256211564 Eth16.903725429256211564 Eth0.000797043
0x09cabEC1...41712bE14 3,568.78902937904846528 Eth3,566.89540015930991759 Eth1.89362921973854769
0x295Ff5C0...a87DcFE12
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x2a1530C4...7b7158667 8,781.069548487262608946 Eth8,782.961695327450924403 Eth1.892146840188315457
0x35D1b3F3...259A0492B
(Sky: MCD Vat)
0x40E03D81...4d4c02815
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x47356191...C2Ead6542
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x53bba5c7...BfC68212A 37.842936803766309149 Eth37.844419183316541382 Eth0.001482379550232233
0x694E97ad...6A2EcBde1
2.00007495222236584 Eth
Nonce: 17777
1.99927790922236584 Eth
Nonce: 17778
0.000797043
0x6B175474...495271d0F
0x6B7b3872...7c6841245
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0x89d24A6b...a23260359
0xb25E470b...e76c1E738
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0xdA467201...a8058Ccad
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0xE2c51Ff4...3e4fD2264
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0
0xeD473d6f...96DbC8315
0 Eth
Nonce: 0
0 Eth
Nonce: 0
From: 0 To: 0

Execution Trace

0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a.0000006f( )
  • ScdMcdMigration.STATICCALL( )
  • Vat.urns( 5341490000000000000000000000000000000000000000000000000000000000, 0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849 ) => ( ink=1057318978925181487704430, art=1057318978925181487704430 )
  • ETH 1.892146840188315457 Vyper_contract.ethToTokenSwapInput( min_tokens=1, deadline=10000000000000000000000 ) => ( out=333890232920294349791 )
    • ETH 1.892146840188315457 Vyper_contract.ethToTokenSwapInput( min_tokens=1, deadline=10000000000000000000000 ) => ( out=333890232920294349791 )
      • Dai.balanceOf( 0x2a1530C4C41db0B0b2bB646CB5Eb1A67b7158667 ) => ( 1554513249394925354496010 )
      • Dai.transfer( dst=0x53bba5c7872BFC4935cb4EEe63c1bA9BfC68212A, wad=333890232920294349791 ) => ( True )
      • ScdMcdMigration.swapDaiToSai( wad=333890232920294349791 )
        • DaiJoin.CALL( )
        • Dai.transferFrom( src=0x53bba5c7872BFC4935cb4EEe63c1bA9BfC68212A, dst=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=333890232920294349791 ) => ( True )
        • DaiJoin.join( usr=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=333890232920294349791 )
          • Vat.move( src=0x9759A6Ac90977b93B58547b4A71c78317f391A28, dst=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, rad=333890232920294349791000000000000000000000000000 )
          • Dai.burn( usr=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=333890232920294349791 )
          • AuthGemJoin.CALL( )
          • Vat.frob( i=5341490000000000000000000000000000000000000000000000000000000000, u=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, v=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, w=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, dink=-333890232920294349791, dart=-333890232920294349791 )
          • AuthGemJoin.exit( usr=0x53bba5c7872BFC4935cb4EEe63c1bA9BfC68212A, wad=333890232920294349791 )
            • Vat.slip( ilk=5341490000000000000000000000000000000000000000000000000000000000, usr=0xc73e0383F3Aff3215E6f04B0331D58CeCf0Ab849, wad=-333890232920294349791 )
            • DSToken.transfer( dst=0x53bba5c7872BFC4935cb4EEe63c1bA9BfC68212A, wad=333890232920294349791 ) => ( True )
            • Vyper_contract.tokenToEthSwapInput( tokens_sold=333890232920294349791, min_eth=1, deadline=10000000000000000000000 ) => ( out=1893629219738547690 )
              • Vyper_contract.tokenToEthSwapInput( tokens_sold=333890232920294349791, min_eth=1, deadline=10000000000000000000000 ) => ( out=1893629219738547690 )
                • DSToken.balanceOf( src=0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14 ) => ( 627038635112302846829787 )
                • ETH 1.89362921973854769 0x53bba5c7872bfc4935cb4eee63c1ba9bfc68212a.CALL( )
                • DSToken.transferFrom( src=0x53bba5c7872BFC4935cb4EEe63c1bA9BfC68212A, dst=0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14, wad=333890232920294349791 ) => ( True )
                • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.000000d6( )
                  • 0xb25e470bb48e97b32639e72efd19dc5e76c1e738.CALL( )
                    • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                    • 0xda46720145fc54e8d2bd2fdbd2d5af0a8058ccad.CALL( )
                      • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                      • 0x295ff5c020553ee8635582fbe225be6a87dcfe12.CALL( )
                        • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                        • 0x40e03d81fde7758d921259f2d1db6254d4c02815.CALL( )
                          • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                          • 0xed473d6f3428d6f8dd5f3998931660096dbc8315.CALL( )
                            • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                            • 0x47356191a67116a4d51d5b09ce6b08ac2ead6542.CALL( )
                              • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                              • 0xe2c51ff49d8e1bd67ce4595d13edf1d3e4fd2264.CALL( )
                                • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                                • 0x6b7b3872dfa1fbabd0c0a53076516fe7c6841245.CALL( )
                                  • 0x000000000099bee67b9d593aa8ff5447ef99d8c5.SELFDESTRUCT( )
                                    File 1 of 9: Vyper_contract
                                    # @title Uniswap Exchange Interface V1
                                    # @notice Source code found at https://github.com/uniswap
                                    # @notice Use at your own risk
                                    
                                    contract Factory():
                                        def getExchange(token_addr: address) -> address: constant
                                    
                                    contract Exchange():
                                        def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant
                                        def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying
                                        def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying
                                    
                                    TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)})
                                    EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))})
                                    AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256})
                                    Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256})
                                    
                                    name: public(bytes32)                             # Uniswap V1
                                    symbol: public(bytes32)                           # UNI-V1
                                    decimals: public(uint256)                         # 18
                                    totalSupply: public(uint256)                      # total number of UNI in existence
                                    balances: uint256[address]                        # UNI balance of an address
                                    allowances: (uint256[address])[address]           # UNI allowance of one address on another
                                    token: address(ERC20)                             # address of the ERC20 token traded on this contract
                                    factory: Factory                                  # interface for the factory that created this contract
                                    
                                    # @dev This function acts as a contract constructor which is not currently supported in contracts deployed
                                    #      using create_with_code_of(). It is called once by the factory during contract creation.
                                    @public
                                    def setup(token_addr: address):
                                        assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS
                                        self.factory = msg.sender
                                        self.token = token_addr
                                        self.name = 0x556e697377617020563100000000000000000000000000000000000000000000
                                        self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000
                                        self.decimals = 18
                                    
                                    # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens.
                                    # @dev min_liquidity does nothing when total UNI supply is 0.
                                    # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0.
                                    # @param max_tokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of UNI minted.
                                    @public
                                    @payable
                                    def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256:
                                        assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        if total_liquidity > 0:
                                            assert min_liquidity > 0
                                            eth_reserve: uint256(wei) = self.balance - msg.value
                                            token_reserve: uint256 = self.token.balanceOf(self)
                                            token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1
                                            liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve
                                            assert max_tokens >= token_amount and liquidity_minted >= min_liquidity
                                            self.balances[msg.sender] += liquidity_minted
                                            self.totalSupply = total_liquidity + liquidity_minted
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted)
                                            return liquidity_minted
                                        else:
                                            assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000
                                            assert self.factory.getExchange(self.token) == self
                                            token_amount: uint256 = max_tokens
                                            initial_liquidity: uint256 = as_unitless_number(self.balance)
                                            self.totalSupply = initial_liquidity
                                            self.balances[msg.sender] = initial_liquidity
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity)
                                            return initial_liquidity
                                    
                                    # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio.
                                    # @param amount Amount of UNI burned.
                                    # @param min_eth Minimum ETH withdrawn.
                                    # @param min_tokens Minimum Tokens withdrawn.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of ETH and Tokens withdrawn.
                                    @public
                                    def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256):
                                        assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        assert total_liquidity > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_amount: uint256(wei) = amount * self.balance / total_liquidity
                                        token_amount: uint256 = amount * token_reserve / total_liquidity
                                        assert eth_amount >= min_eth and token_amount >= min_tokens
                                        self.balances[msg.sender] -= amount
                                        self.totalSupply = total_liquidity - amount
                                        send(msg.sender, eth_amount)
                                        assert self.token.transfer(msg.sender, token_amount)
                                        log.RemoveLiquidity(msg.sender, eth_amount, token_amount)
                                        log.Transfer(msg.sender, ZERO_ADDRESS, amount)
                                        return eth_amount, token_amount
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param input_amount Amount of ETH or Tokens being sold.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens bought.
                                    @private
                                    @constant
                                    def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        input_amount_with_fee: uint256 = input_amount * 997
                                        numerator: uint256 = input_amount_with_fee * output_reserve
                                        denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee
                                        return numerator / denominator
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param output_amount Amount of ETH or Tokens being bought.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens sold.
                                    @private
                                    @constant
                                    def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        numerator: uint256 = input_reserve * output_amount * 1000
                                        denominator: uint256 = (output_reserve - output_amount) * 997
                                        return numerator / denominator + 1
                                    
                                    @private
                                    def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve)
                                        assert tokens_bought >= min_tokens
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, eth_sold, tokens_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value).
                                    # @dev User cannot specify minimum output or deadline.
                                    @public
                                    @payable
                                    def __default__():
                                        self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value) and minimum output.
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies exact input (msg.value) and minimum output
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve)
                                        # Throws if eth_sold > max_eth
                                        eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei')
                                        if eth_refund > 0:
                                            send(buyer, eth_refund)
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei):
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth
                                        send(recipient, wei_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return wei_bought
                                    
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei):
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens >= tokens_sold
                                        send(recipient, eth_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    @private
                                    def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact input.
                                    # @param eth_sold Amount of ETH sold.
                                    # @return Amount of Tokens that can be bought with input ETH.
                                    @public
                                    @constant
                                    def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256:
                                        assert eth_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact output.
                                    # @param tokens_bought Amount of Tokens bought.
                                    # @return Amount of ETH needed to buy output Tokens.
                                    @public
                                    @constant
                                    def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei):
                                        assert tokens_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact input.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @return Amount of ETH that can be bought with input Tokens.
                                    @public
                                    @constant
                                    def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei):
                                        assert tokens_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        return as_wei_value(eth_bought, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact output.
                                    # @param eth_bought Amount of output ETH.
                                    # @return Amount of Tokens needed to buy output ETH.
                                    @public
                                    @constant
                                    def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256:
                                        assert eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                    
                                    # @return Address of Token that is sold on this exchange.
                                    @public
                                    @constant
                                    def tokenAddress() -> address:
                                        return self.token
                                    
                                    # @return Address of factory that created this exchange.
                                    @public
                                    @constant
                                    def factoryAddress() -> address(Factory):
                                        return self.factory
                                    
                                    # ERC20 compatibility for exchange liquidity modified from
                                    # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy
                                    @public
                                    @constant
                                    def balanceOf(_owner : address) -> uint256:
                                        return self.balances[_owner]
                                    
                                    @public
                                    def transfer(_to : address, _value : uint256) -> bool:
                                        self.balances[msg.sender] -= _value
                                        self.balances[_to] += _value
                                        log.Transfer(msg.sender, _to, _value)
                                        return True
                                    
                                    @public
                                    def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
                                        self.balances[_from] -= _value
                                        self.balances[_to] += _value
                                        self.allowances[_from][msg.sender] -= _value
                                        log.Transfer(_from, _to, _value)
                                        return True
                                    
                                    @public
                                    def approve(_spender : address, _value : uint256) -> bool:
                                        self.allowances[msg.sender][_spender] = _value
                                        log.Approval(msg.sender, _spender, _value)
                                        return True
                                    
                                    @public
                                    @constant
                                    def allowance(_owner : address, _spender : address) -> uint256:
                                        return self.allowances[_owner][_spender]

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

                                    File 3 of 9: ScdMcdMigration
                                    // hevm: flattened sources of /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/ScdMcdMigration.sol
                                    pragma solidity =0.5.12;
                                    
                                    ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/Interfaces.sol
                                    /* pragma solidity 0.5.12; */
                                    
                                    contract GemLike {
                                        function allowance(address, address) public returns (uint);
                                        function approve(address, uint) public;
                                        function transfer(address, uint) public returns (bool);
                                        function transferFrom(address, address, uint) public returns (bool);
                                    }
                                    
                                    contract ValueLike {
                                        function peek() public returns (uint, bool);
                                    }
                                    
                                    contract SaiTubLike {
                                        function skr() public view returns (GemLike);
                                        function gem() public view returns (GemLike);
                                        function gov() public view returns (GemLike);
                                        function sai() public view returns (GemLike);
                                        function pep() public view returns (ValueLike);
                                        function vox() public view returns (VoxLike);
                                        function bid(uint) public view returns (uint);
                                        function ink(bytes32) public view returns (uint);
                                        function tag() public view returns (uint);
                                        function tab(bytes32) public returns (uint);
                                        function rap(bytes32) public returns (uint);
                                        function draw(bytes32, uint) public;
                                        function shut(bytes32) public;
                                        function exit(uint) public;
                                        function give(bytes32, address) public;
                                    }
                                    
                                    contract VoxLike {
                                        function par() public returns (uint);
                                    }
                                    
                                    contract JoinLike {
                                        function ilk() public returns (bytes32);
                                        function gem() public returns (GemLike);
                                        function dai() public returns (GemLike);
                                        function join(address, uint) public;
                                        function exit(address, uint) public;
                                    }
                                    contract VatLike {
                                        function ilks(bytes32) public view returns (uint, uint, uint, uint, uint);
                                        function hope(address) public;
                                        function frob(bytes32, address, address, address, int, int) public;
                                    }
                                    
                                    contract ManagerLike {
                                        function vat() public view returns (address);
                                        function urns(uint) public view returns (address);
                                        function open(bytes32, address) public returns (uint);
                                        function frob(uint, int, int) public;
                                        function give(uint, address) public;
                                        function move(uint, address, uint) public;
                                    }
                                    
                                    contract OtcLike {
                                        function getPayAmount(address, address, uint) public view returns (uint);
                                        function buyAllAmount(address, uint, address, uint) public;
                                    }
                                    
                                    ////// /nix/store/nrmi9gk7q94ba1fbhq9bphlbpqd1y8hw-scd-mcd-migration-e730e63/src/ScdMcdMigration.sol
                                    /* pragma solidity 0.5.12; */
                                    
                                    /* import { JoinLike, ManagerLike, SaiTubLike, VatLike } from "./Interfaces.sol"; */
                                    
                                    contract ScdMcdMigration {
                                        SaiTubLike                  public tub;
                                        VatLike                     public vat;
                                        ManagerLike                 public cdpManager;
                                        JoinLike                    public saiJoin;
                                        JoinLike                    public wethJoin;
                                        JoinLike                    public daiJoin;
                                    
                                        constructor(
                                            address tub_,           // SCD tub contract address
                                            address cdpManager_,    // MCD manager contract address
                                            address saiJoin_,       // MCD SAI collateral adapter contract address
                                            address wethJoin_,      // MCD ETH collateral adapter contract address
                                            address daiJoin_        // MCD DAI adapter contract address
                                        ) public {
                                            tub = SaiTubLike(tub_);
                                            cdpManager = ManagerLike(cdpManager_);
                                            vat = VatLike(cdpManager.vat());
                                            saiJoin = JoinLike(saiJoin_);
                                            wethJoin = JoinLike(wethJoin_);
                                            daiJoin = JoinLike(daiJoin_);
                                    
                                            require(wethJoin.gem() == tub.gem(), "non-matching-weth");
                                            require(saiJoin.gem() == tub.sai(), "non-matching-sai");
                                    
                                            tub.gov().approve(address(tub), uint(-1));
                                            tub.skr().approve(address(tub), uint(-1));
                                            tub.sai().approve(address(tub), uint(-1));
                                            tub.sai().approve(address(saiJoin), uint(-1));
                                            wethJoin.gem().approve(address(wethJoin), uint(-1));
                                            daiJoin.dai().approve(address(daiJoin), uint(-1));
                                            vat.hope(address(daiJoin));
                                        }
                                    
                                        function add(uint x, uint y) internal pure returns (uint z) {
                                            require((z = x + y) >= x, "add-overflow");
                                        }
                                    
                                        function sub(uint x, uint y) internal pure returns (uint z) {
                                            require((z = x - y) <= x, "sub-underflow");
                                        }
                                    
                                        function mul(uint x, uint y) internal pure returns (uint z) {
                                            require(y == 0 || (z = x * y) / y == x, "mul-overflow");
                                        }
                                    
                                        function toInt(uint x) internal pure returns (int y) {
                                            y = int(x);
                                            require(y >= 0, "int-overflow");
                                        }
                                    
                                        // Function to swap SAI to DAI
                                        // This function is to be used by users that want to get new DAI in exchange of old one (aka SAI)
                                        // wad amount has to be <= the value pending to reach the debt ceiling (the minimum between general and ilk one)
                                        function swapSaiToDai(
                                            uint wad
                                        ) external {
                                            // Get wad amount of SAI from user's wallet:
                                            saiJoin.gem().transferFrom(msg.sender, address(this), wad);
                                            // Join the SAI wad amount to the `vat`:
                                            saiJoin.join(address(this), wad);
                                            // Lock the SAI wad amount to the CDP and generate the same wad amount of DAI
                                            vat.frob(saiJoin.ilk(), address(this), address(this), address(this), toInt(wad), toInt(wad));
                                            // Send DAI wad amount as a ERC20 token to the user's wallet
                                            daiJoin.exit(msg.sender, wad);
                                        }
                                    
                                        // Function to swap DAI to SAI
                                        // This function is to be used by users that want to get SAI in exchange of DAI
                                        // wad amount has to be <= the amount of SAI locked (and DAI generated) in the migration contract SAI CDP
                                        function swapDaiToSai(
                                            uint wad
                                        ) external {
                                            // Get wad amount of DAI from user's wallet:
                                            daiJoin.dai().transferFrom(msg.sender, address(this), wad);
                                            // Join the DAI wad amount to the vat:
                                            daiJoin.join(address(this), wad);
                                            // Payback the DAI wad amount and unlocks the same value of SAI collateral
                                            vat.frob(saiJoin.ilk(), address(this), address(this), address(this), -toInt(wad), -toInt(wad));
                                            // Send SAI wad amount as a ERC20 token to the user's wallet
                                            saiJoin.exit(msg.sender, wad);
                                        }
                                    
                                        // Function to migrate a SCD CDP to MCD one (needs to be used via a proxy so the code can be kept simpler). Check MigrationProxyActions.sol code for usage.
                                        // In order to use migrate function, SCD CDP debtAmt needs to be <= SAI previously deposited in the SAI CDP * (100% - Collateralization Ratio)
                                        function migrate(
                                            bytes32 cup
                                        ) external returns (uint cdp) {
                                            // Get values
                                            uint debtAmt = tub.tab(cup);    // CDP SAI debt
                                            uint pethAmt = tub.ink(cup);    // CDP locked collateral
                                            uint ethAmt = tub.bid(pethAmt); // CDP locked collateral equiv in ETH
                                    
                                            // Take SAI out from MCD SAI CDP. For this operation is necessary to have a very low collateralization ratio
                                            // This is not actually a problem as this ilk will only be accessed by this migration contract,
                                            // which will make sure to have the amounts balanced out at the end of the execution.
                                            vat.frob(
                                                bytes32(saiJoin.ilk()),
                                                address(this),
                                                address(this),
                                                address(this),
                                                -toInt(debtAmt),
                                                0
                                            );
                                            saiJoin.exit(address(this), debtAmt); // SAI is exited as a token
                                    
                                            // Shut SAI CDP and gets WETH back
                                            tub.shut(cup);      // CDP is closed using the SAI just exited and the MKR previously sent by the user (via the proxy call)
                                            tub.exit(pethAmt);  // Converts PETH to WETH
                                    
                                            // Open future user's CDP in MCD
                                            cdp = cdpManager.open(wethJoin.ilk(), address(this));
                                    
                                            // Join WETH to Adapter
                                            wethJoin.join(cdpManager.urns(cdp), ethAmt);
                                    
                                            // Lock WETH in future user's CDP and generate debt to compensate the SAI used to paid the SCD CDP
                                            (, uint rate,,,) = vat.ilks(wethJoin.ilk());
                                            cdpManager.frob(
                                                cdp,
                                                toInt(ethAmt),
                                                toInt(mul(debtAmt, 10 ** 27) / rate + 1) // To avoid rounding issues we add an extra wei of debt
                                            );
                                            // Move DAI generated to migration contract (to recover the used funds)
                                            cdpManager.move(cdp, address(this), mul(debtAmt, 10 ** 27));
                                            // Re-balance MCD SAI migration contract's CDP
                                            vat.frob(
                                                bytes32(saiJoin.ilk()),
                                                address(this),
                                                address(this),
                                                address(this),
                                                0,
                                                -toInt(debtAmt)
                                            );
                                    
                                            // Set ownership of CDP to the user
                                            cdpManager.give(cdp, msg.sender);
                                        }
                                    }

                                    File 4 of 9: Vat
                                    // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
                                    pragma solidity =0.5.12;
                                    
                                    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/vat.sol
                                    /// vat.sol -- Dai CDP database
                                    
                                    // Copyright (C) 2018 Rain <[email protected]>
                                    //
                                    // This program is free software: you can redistribute it and/or modify
                                    // it under the terms of the GNU Affero General Public License as published by
                                    // the Free Software Foundation, either version 3 of the License, or
                                    // (at your option) any later version.
                                    //
                                    // This program is distributed in the hope that it will be useful,
                                    // but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    // GNU Affero General Public License for more details.
                                    //
                                    // You should have received a copy of the GNU Affero General Public License
                                    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                                    
                                    /* pragma solidity 0.5.12; */
                                    
                                    contract Vat {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 1; }
                                        function deny(address usr) external note auth { require(live == 1, "Vat/not-live"); wards[usr] = 0; }
                                        modifier auth {
                                            require(wards[msg.sender] == 1, "Vat/not-authorized");
                                            _;
                                        }
                                    
                                        mapping(address => mapping (address => uint)) public can;
                                        function hope(address usr) external note { can[msg.sender][usr] = 1; }
                                        function nope(address usr) external note { can[msg.sender][usr] = 0; }
                                        function wish(address bit, address usr) internal view returns (bool) {
                                            return either(bit == usr, can[bit][usr] == 1);
                                        }
                                    
                                        // --- Data ---
                                        struct Ilk {
                                            uint256 Art;   // Total Normalised Debt     [wad]
                                            uint256 rate;  // Accumulated Rates         [ray]
                                            uint256 spot;  // Price with Safety Margin  [ray]
                                            uint256 line;  // Debt Ceiling              [rad]
                                            uint256 dust;  // Urn Debt Floor            [rad]
                                        }
                                        struct Urn {
                                            uint256 ink;   // Locked Collateral  [wad]
                                            uint256 art;   // Normalised Debt    [wad]
                                        }
                                    
                                        mapping (bytes32 => Ilk)                       public ilks;
                                        mapping (bytes32 => mapping (address => Urn )) public urns;
                                        mapping (bytes32 => mapping (address => uint)) public gem;  // [wad]
                                        mapping (address => uint256)                   public dai;  // [rad]
                                        mapping (address => uint256)                   public sin;  // [rad]
                                    
                                        uint256 public debt;  // Total Dai Issued    [rad]
                                        uint256 public vice;  // Total Unbacked Dai  [rad]
                                        uint256 public Line;  // Total Debt Ceiling  [rad]
                                        uint256 public live;  // Access Flag
                                    
                                        // --- Logs ---
                                        event LogNote(
                                            bytes4   indexed  sig,
                                            bytes32  indexed  arg1,
                                            bytes32  indexed  arg2,
                                            bytes32  indexed  arg3,
                                            bytes             data
                                        ) anonymous;
                                    
                                        modifier note {
                                            _;
                                            assembly {
                                                // log an 'anonymous' event with a constant 6 words of calldata
                                                // and four indexed topics: the selector and the first three args
                                                let mark := msize                         // end of memory ensures zero
                                                mstore(0x40, add(mark, 288))              // update free memory pointer
                                                mstore(mark, 0x20)                        // bytes type data offset
                                                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                                                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                                                log4(mark, 288,                           // calldata
                                                     shl(224, shr(224, calldataload(0))), // msg.sig
                                                     calldataload(4),                     // arg1
                                                     calldataload(36),                    // arg2
                                                     calldataload(68)                     // arg3
                                                    )
                                            }
                                        }
                                    
                                        // --- Init ---
                                        constructor() public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                        }
                                    
                                        // --- Math ---
                                        function add(uint x, int y) internal pure returns (uint z) {
                                            z = x + uint(y);
                                            require(y >= 0 || z <= x);
                                            require(y <= 0 || z >= x);
                                        }
                                        function sub(uint x, int y) internal pure returns (uint z) {
                                            z = x - uint(y);
                                            require(y <= 0 || z <= x);
                                            require(y >= 0 || z >= x);
                                        }
                                        function mul(uint x, int y) internal pure returns (int z) {
                                            z = int(x) * y;
                                            require(int(x) >= 0);
                                            require(y == 0 || z / y == int(x));
                                        }
                                        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);
                                        }
                                    
                                        // --- Administration ---
                                        function init(bytes32 ilk) external note auth {
                                            require(ilks[ilk].rate == 0, "Vat/ilk-already-init");
                                            ilks[ilk].rate = 10 ** 27;
                                        }
                                        function file(bytes32 what, uint data) external note auth {
                                            require(live == 1, "Vat/not-live");
                                            if (what == "Line") Line = data;
                                            else revert("Vat/file-unrecognized-param");
                                        }
                                        function file(bytes32 ilk, bytes32 what, uint data) external note auth {
                                            require(live == 1, "Vat/not-live");
                                            if (what == "spot") ilks[ilk].spot = data;
                                            else if (what == "line") ilks[ilk].line = data;
                                            else if (what == "dust") ilks[ilk].dust = data;
                                            else revert("Vat/file-unrecognized-param");
                                        }
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                    
                                        // --- Fungibility ---
                                        function slip(bytes32 ilk, address usr, int256 wad) external note auth {
                                            gem[ilk][usr] = add(gem[ilk][usr], wad);
                                        }
                                        function flux(bytes32 ilk, address src, address dst, uint256 wad) external note {
                                            require(wish(src, msg.sender), "Vat/not-allowed");
                                            gem[ilk][src] = sub(gem[ilk][src], wad);
                                            gem[ilk][dst] = add(gem[ilk][dst], wad);
                                        }
                                        function move(address src, address dst, uint256 rad) external note {
                                            require(wish(src, msg.sender), "Vat/not-allowed");
                                            dai[src] = sub(dai[src], rad);
                                            dai[dst] = add(dai[dst], rad);
                                        }
                                    
                                        function either(bool x, bool y) internal pure returns (bool z) {
                                            assembly{ z := or(x, y)}
                                        }
                                        function both(bool x, bool y) internal pure returns (bool z) {
                                            assembly{ z := and(x, y)}
                                        }
                                    
                                        // --- CDP Manipulation ---
                                        function frob(bytes32 i, address u, address v, address w, int dink, int dart) external note {
                                            // system is live
                                            require(live == 1, "Vat/not-live");
                                    
                                            Urn memory urn = urns[i][u];
                                            Ilk memory ilk = ilks[i];
                                            // ilk has been initialised
                                            require(ilk.rate != 0, "Vat/ilk-not-init");
                                    
                                            urn.ink = add(urn.ink, dink);
                                            urn.art = add(urn.art, dart);
                                            ilk.Art = add(ilk.Art, dart);
                                    
                                            int dtab = mul(ilk.rate, dart);
                                            uint tab = mul(ilk.rate, urn.art);
                                            debt     = add(debt, dtab);
                                    
                                            // either debt has decreased, or debt ceilings are not exceeded
                                            require(either(dart <= 0, both(mul(ilk.Art, ilk.rate) <= ilk.line, debt <= Line)), "Vat/ceiling-exceeded");
                                            // urn is either less risky than before, or it is safe
                                            require(either(both(dart <= 0, dink >= 0), tab <= mul(urn.ink, ilk.spot)), "Vat/not-safe");
                                    
                                            // urn is either more safe, or the owner consents
                                            require(either(both(dart <= 0, dink >= 0), wish(u, msg.sender)), "Vat/not-allowed-u");
                                            // collateral src consents
                                            require(either(dink <= 0, wish(v, msg.sender)), "Vat/not-allowed-v");
                                            // debt dst consents
                                            require(either(dart >= 0, wish(w, msg.sender)), "Vat/not-allowed-w");
                                    
                                            // urn has no debt, or a non-dusty amount
                                            require(either(urn.art == 0, tab >= ilk.dust), "Vat/dust");
                                    
                                            gem[i][v] = sub(gem[i][v], dink);
                                            dai[w]    = add(dai[w],    dtab);
                                    
                                            urns[i][u] = urn;
                                            ilks[i]    = ilk;
                                        }
                                        // --- CDP Fungibility ---
                                        function fork(bytes32 ilk, address src, address dst, int dink, int dart) external note {
                                            Urn storage u = urns[ilk][src];
                                            Urn storage v = urns[ilk][dst];
                                            Ilk storage i = ilks[ilk];
                                    
                                            u.ink = sub(u.ink, dink);
                                            u.art = sub(u.art, dart);
                                            v.ink = add(v.ink, dink);
                                            v.art = add(v.art, dart);
                                    
                                            uint utab = mul(u.art, i.rate);
                                            uint vtab = mul(v.art, i.rate);
                                    
                                            // both sides consent
                                            require(both(wish(src, msg.sender), wish(dst, msg.sender)), "Vat/not-allowed");
                                    
                                            // both sides safe
                                            require(utab <= mul(u.ink, i.spot), "Vat/not-safe-src");
                                            require(vtab <= mul(v.ink, i.spot), "Vat/not-safe-dst");
                                    
                                            // both sides non-dusty
                                            require(either(utab >= i.dust, u.art == 0), "Vat/dust-src");
                                            require(either(vtab >= i.dust, v.art == 0), "Vat/dust-dst");
                                        }
                                        // --- CDP Confiscation ---
                                        function grab(bytes32 i, address u, address v, address w, int dink, int dart) external note auth {
                                            Urn storage urn = urns[i][u];
                                            Ilk storage ilk = ilks[i];
                                    
                                            urn.ink = add(urn.ink, dink);
                                            urn.art = add(urn.art, dart);
                                            ilk.Art = add(ilk.Art, dart);
                                    
                                            int dtab = mul(ilk.rate, dart);
                                    
                                            gem[i][v] = sub(gem[i][v], dink);
                                            sin[w]    = sub(sin[w],    dtab);
                                            vice      = sub(vice,      dtab);
                                        }
                                    
                                        // --- Settlement ---
                                        function heal(uint rad) external note {
                                            address u = msg.sender;
                                            sin[u] = sub(sin[u], rad);
                                            dai[u] = sub(dai[u], rad);
                                            vice   = sub(vice,   rad);
                                            debt   = sub(debt,   rad);
                                        }
                                        function suck(address u, address v, uint rad) external note auth {
                                            sin[u] = add(sin[u], rad);
                                            dai[v] = add(dai[v], rad);
                                            vice   = add(vice,   rad);
                                            debt   = add(debt,   rad);
                                        }
                                    
                                        // --- Rates ---
                                        function fold(bytes32 i, address u, int rate) external note auth {
                                            require(live == 1, "Vat/not-live");
                                            Ilk storage ilk = ilks[i];
                                            ilk.rate = add(ilk.rate, rate);
                                            int rad  = mul(ilk.Art, rate);
                                            dai[u]   = add(dai[u], rad);
                                            debt     = add(debt,   rad);
                                        }
                                    }

                                    File 5 of 9: DaiJoin
                                    // hevm: flattened sources of /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol
                                    pragma solidity =0.5.12;
                                    
                                    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/lib.sol
                                    // This program is free software: you can redistribute it and/or modify
                                    // it under the terms of the GNU General Public License as published by
                                    // the Free Software Foundation, either version 3 of the License, or
                                    // (at your option) any later version.
                                    
                                    // This program is distributed in the hope that it will be useful,
                                    // but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    // GNU General Public License for more details.
                                    
                                    // You should have received a copy of the GNU General Public License
                                    // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                                    
                                    /* pragma solidity 0.5.12; */
                                    
                                    contract LibNote {
                                        event LogNote(
                                            bytes4   indexed  sig,
                                            address  indexed  usr,
                                            bytes32  indexed  arg1,
                                            bytes32  indexed  arg2,
                                            bytes             data
                                        ) anonymous;
                                    
                                        modifier note {
                                            _;
                                            assembly {
                                                // log an 'anonymous' event with a constant 6 words of calldata
                                                // and four indexed topics: selector, caller, arg1 and arg2
                                                let mark := msize                         // end of memory ensures zero
                                                mstore(0x40, add(mark, 288))              // update free memory pointer
                                                mstore(mark, 0x20)                        // bytes type data offset
                                                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                                                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                                                log4(mark, 288,                           // calldata
                                                     shl(224, shr(224, calldataload(0))), // msg.sig
                                                     caller,                              // msg.sender
                                                     calldataload(4),                     // arg1
                                                     calldataload(36)                     // arg2
                                                    )
                                            }
                                        }
                                    }
                                    
                                    ////// /nix/store/8xb41r4qd0cjb63wcrxf1qmfg88p0961-dss-6fd7de0/src/join.sol
                                    /// join.sol -- Basic token adapters
                                    
                                    // Copyright (C) 2018 Rain <[email protected]>
                                    //
                                    // This program is free software: you can redistribute it and/or modify
                                    // it under the terms of the GNU Affero General Public License as published by
                                    // the Free Software Foundation, either version 3 of the License, or
                                    // (at your option) any later version.
                                    //
                                    // This program is distributed in the hope that it will be useful,
                                    // but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    // GNU Affero General Public License for more details.
                                    //
                                    // You should have received a copy of the GNU Affero General Public License
                                    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                                    
                                    /* pragma solidity 0.5.12; */
                                    
                                    /* import "./lib.sol"; */
                                    
                                    contract GemLike {
                                        function decimals() public view returns (uint);
                                        function transfer(address,uint) external returns (bool);
                                        function transferFrom(address,address,uint) external returns (bool);
                                    }
                                    
                                    contract DSTokenLike {
                                        function mint(address,uint) external;
                                        function burn(address,uint) external;
                                    }
                                    
                                    contract VatLike {
                                        function slip(bytes32,address,int) external;
                                        function move(address,address,uint) external;
                                    }
                                    
                                    /*
                                        Here we provide *adapters* to connect the Vat to arbitrary external
                                        token implementations, creating a bounded context for the Vat. The
                                        adapters here are provided as working examples:
                                    
                                          - `GemJoin`: For well behaved ERC20 tokens, with simple transfer
                                                       semantics.
                                    
                                          - `ETHJoin`: For native Ether.
                                    
                                          - `DaiJoin`: For connecting internal Dai balances to an external
                                                       `DSToken` implementation.
                                    
                                        In practice, adapter implementations will be varied and specific to
                                        individual collateral types, accounting for different transfer
                                        semantics and token standards.
                                    
                                        Adapters need to implement two basic methods:
                                    
                                          - `join`: enter collateral into the system
                                          - `exit`: remove collateral from the system
                                    
                                    */
                                    
                                    contract GemJoin is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth {
                                            require(wards[msg.sender] == 1, "GemJoin/not-authorized");
                                            _;
                                        }
                                    
                                        VatLike public vat;
                                        bytes32 public ilk;
                                        GemLike public gem;
                                        uint    public dec;
                                        uint    public live;  // Access Flag
                                    
                                        constructor(address vat_, bytes32 ilk_, address gem_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                            gem = GemLike(gem_);
                                            dec = gem.decimals();
                                        }
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                        function join(address usr, uint wad) external note {
                                            require(live == 1, "GemJoin/not-live");
                                            require(int(wad) >= 0, "GemJoin/overflow");
                                            vat.slip(ilk, usr, int(wad));
                                            require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin/failed-transfer");
                                        }
                                        function exit(address usr, uint wad) external note {
                                            require(wad <= 2 ** 255, "GemJoin/overflow");
                                            vat.slip(ilk, msg.sender, -int(wad));
                                            require(gem.transfer(usr, wad), "GemJoin/failed-transfer");
                                        }
                                    }
                                    
                                    contract ETHJoin is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth {
                                            require(wards[msg.sender] == 1, "ETHJoin/not-authorized");
                                            _;
                                        }
                                    
                                        VatLike public vat;
                                        bytes32 public ilk;
                                        uint    public live;  // Access Flag
                                    
                                        constructor(address vat_, bytes32 ilk_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                        }
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                        function join(address usr) external payable note {
                                            require(live == 1, "ETHJoin/not-live");
                                            require(int(msg.value) >= 0, "ETHJoin/overflow");
                                            vat.slip(ilk, usr, int(msg.value));
                                        }
                                        function exit(address payable usr, uint wad) external note {
                                            require(int(wad) >= 0, "ETHJoin/overflow");
                                            vat.slip(ilk, msg.sender, -int(wad));
                                            usr.transfer(wad);
                                        }
                                    }
                                    
                                    contract DaiJoin is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth {
                                            require(wards[msg.sender] == 1, "DaiJoin/not-authorized");
                                            _;
                                        }
                                    
                                        VatLike public vat;
                                        DSTokenLike public dai;
                                        uint    public live;  // Access Flag
                                    
                                        constructor(address vat_, address dai_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            dai = DSTokenLike(dai_);
                                        }
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                        uint constant ONE = 10 ** 27;
                                        function mul(uint x, uint y) internal pure returns (uint z) {
                                            require(y == 0 || (z = x * y) / y == x);
                                        }
                                        function join(address usr, uint wad) external note {
                                            vat.move(address(this), usr, mul(ONE, wad));
                                            dai.burn(msg.sender, wad);
                                        }
                                        function exit(address usr, uint wad) external note {
                                            require(live == 1, "DaiJoin/not-live");
                                            vat.move(msg.sender, address(this), mul(ONE, wad));
                                            dai.mint(usr, wad);
                                        }
                                    }

                                    File 6 of 9: AuthGemJoin
                                    // hevm: flattened sources of /nix/store/k8y52yly1kzii65m0yw5pbidrq3jlajh-dss-deploy-001fb27/src/join.sol
                                    pragma solidity =0.5.12;
                                    
                                    ////// /nix/store/4vip6nyqfd0yhs15md21rzxsk5jgx6sv-dss/dapp/dss/src/lib.sol
                                    // This program is free software: you can redistribute it and/or modify
                                    // it under the terms of the GNU General Public License as published by
                                    // the Free Software Foundation, either version 3 of the License, or
                                    // (at your option) any later version.
                                    
                                    // This program is distributed in the hope that it will be useful,
                                    // but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    // GNU General Public License for more details.
                                    
                                    // You should have received a copy of the GNU General Public License
                                    // along with this program.  If not, see <http://www.gnu.org/licenses/>.
                                    
                                    /* pragma solidity 0.5.12; */
                                    
                                    contract LibNote {
                                        event LogNote(
                                            bytes4   indexed  sig,
                                            address  indexed  usr,
                                            bytes32  indexed  arg1,
                                            bytes32  indexed  arg2,
                                            bytes             data
                                        ) anonymous;
                                    
                                        modifier note {
                                            _;
                                            assembly {
                                                // log an 'anonymous' event with a constant 6 words of calldata
                                                // and four indexed topics: selector, caller, arg1 and arg2
                                                let mark := msize                         // end of memory ensures zero
                                                mstore(0x40, add(mark, 288))              // update free memory pointer
                                                mstore(mark, 0x20)                        // bytes type data offset
                                                mstore(add(mark, 0x20), 224)              // bytes size (padded)
                                                calldatacopy(add(mark, 0x40), 0, 224)     // bytes payload
                                                log4(mark, 288,                           // calldata
                                                     shl(224, shr(224, calldataload(0))), // msg.sig
                                                     caller,                              // msg.sender
                                                     calldataload(4),                     // arg1
                                                     calldataload(36)                     // arg2
                                                    )
                                            }
                                        }
                                    }
                                    
                                    ////// /nix/store/k8y52yly1kzii65m0yw5pbidrq3jlajh-dss-deploy-001fb27/src/join.sol
                                    /// join.sol -- Non-standard token adapters
                                    
                                    // Copyright (C) 2018 Rain <[email protected]>
                                    //
                                    // This program is free software: you can redistribute it and/or modify
                                    // it under the terms of the GNU Affero General Public License as published by
                                    // the Free Software Foundation, either version 3 of the License, or
                                    // (at your option) any later version.
                                    //
                                    // This program is distributed in the hope that it will be useful,
                                    // but WITHOUT ANY WARRANTY; without even the implied warranty of
                                    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                                    // GNU Affero General Public License for more details.
                                    //
                                    // You should have received a copy of the GNU Affero General Public License
                                    // along with this program.  If not, see <https://www.gnu.org/licenses/>.
                                    
                                    /* pragma solidity 0.5.12; */
                                    
                                    /* import "dss/lib.sol"; */
                                    
                                    contract VatLike {
                                        function slip(bytes32,address,int) public;
                                    }
                                    
                                    // GemJoin2
                                    
                                    // For a token that does not return a bool on transfer or transferFrom (like OMG)
                                    // This is one way of doing it. Check the balances before and after calling a transfer
                                    
                                    contract GemLike2 {
                                        function decimals() public view returns (uint);
                                        function transfer(address,uint) public;
                                        function transferFrom(address,address,uint) public;
                                        function balanceOf(address) public view returns (uint);
                                        function allowance(address,address) public view returns (uint);
                                    }
                                    
                                    contract GemJoin2 is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth { require(wards[msg.sender] == 1); _; }
                                    
                                        VatLike  public vat;
                                        bytes32  public ilk;
                                        GemLike2 public gem;
                                        uint     public dec;
                                        uint     public live;  // Access Flag
                                    
                                        constructor(address vat_, bytes32 ilk_, address gem_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                            gem = GemLike2(gem_);
                                            dec = gem.decimals();
                                        }
                                    
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                    
                                        function mul(uint x, uint y) internal pure returns (uint z) {
                                            require(y == 0 || (z = x * y) / y == x, "GemJoin2/overflow");
                                        }
                                    
                                        function join(address urn, uint wad) public note {
                                            require(live == 1, "GemJoin2/not-live");
                                            require(wad <= 2 ** 255, "GemJoin2/overflow");
                                            vat.slip(ilk, urn, int(wad));
                                            uint256 prevBalance = gem.balanceOf(msg.sender);
                                    
                                            require(prevBalance >= wad, "GemJoin2/no-funds");
                                            require(gem.allowance(msg.sender, address(this)) >= wad, "GemJoin2/no-allowance");
                                    
                                            (bool ok,) = address(gem).call(
                                                abi.encodeWithSignature("transferFrom(address,address,uint256)", msg.sender, address(this), wad)
                                            );
                                            require(ok, "GemJoin2/failed-transfer");
                                    
                                            require(prevBalance - wad == gem.balanceOf(msg.sender), "GemJoin2/failed-transfer");
                                        }
                                    
                                        function exit(address guy, uint wad) public note {
                                            require(wad <= 2 ** 255, "GemJoin2/overflow");
                                            vat.slip(ilk, msg.sender, -int(wad));
                                            uint256 prevBalance = gem.balanceOf(address(this));
                                    
                                            require(prevBalance >= wad, "GemJoin2/no-funds");
                                    
                                            (bool ok,) = address(gem).call(
                                                abi.encodeWithSignature("transfer(address,uint256)", guy, wad)
                                            );
                                            require(ok, "GemJoin2/failed-transfer");
                                    
                                            require(prevBalance - wad == gem.balanceOf(address(this)), "GemJoin2/failed-transfer");
                                        }
                                    }
                                    
                                    // GemJoin3
                                    // For a token that has a lower precision than 18 and doesn't have decimals field in place (like DGD)
                                    
                                    contract GemLike3 {
                                        function transfer(address,uint) public returns (bool);
                                        function transferFrom(address,address,uint) public returns (bool);
                                    }
                                    
                                    contract GemJoin3 is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth { require(wards[msg.sender] == 1); _; }
                                    
                                        VatLike  public vat;
                                        bytes32  public ilk;
                                        GemLike3 public gem;
                                        uint     public dec;
                                        uint     public live;  // Access Flag
                                    
                                        constructor(address vat_, bytes32 ilk_, address gem_, uint decimals) public {
                                            require(decimals < 18, "GemJoin3/decimals-18-or-higher");
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                            gem = GemLike3(gem_);
                                            dec = decimals;
                                        }
                                    
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                    
                                        function mul(uint x, uint y) internal pure returns (uint z) {
                                            require(y == 0 || (z = x * y) / y == x, "GemJoin3/overflow");
                                        }
                                    
                                        function join(address urn, uint wad) public note {
                                            require(live == 1, "GemJoin3/not-live");
                                            uint wad18 = mul(wad, 10 ** (18 - dec));
                                            require(wad18 <= 2 ** 255, "GemJoin3/overflow");
                                            vat.slip(ilk, urn, int(wad18));
                                            require(gem.transferFrom(msg.sender, address(this), wad), "GemJoin3/failed-transfer");
                                        }
                                    
                                        function exit(address guy, uint wad) public note {
                                            uint wad18 = mul(wad, 10 ** (18 - dec));
                                            require(wad18 <= 2 ** 255, "GemJoin3/overflow");
                                            vat.slip(ilk, msg.sender, -int(wad18));
                                            require(gem.transfer(guy, wad), "GemJoin3/failed-transfer");
                                        }
                                    }
                                    
                                    /// GemJoin4
                                    
                                    // Copyright (C) 2019 Lorenzo Manacorda <[email protected]>
                                    //
                                    // 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/>.
                                    
                                    // For tokens that do not implement transferFrom (like GNT), meaning the usual adapter
                                    // approach won't work: the adapter cannot call transferFrom and therefore
                                    // has no way of knowing when users deposit gems into it.
                                    
                                    // To work around this, we introduce the concept of a bag, which is a trusted
                                    // (it's created by the adapter), personalized component (one for each user).
                                    
                                    // Users first have to create their bag with `GemJoin4.make`, then transfer
                                    // gem to it, and then call `GemJoin4.join`, which transfer the gems from the
                                    // bag to the adapter.
                                    
                                    contract GemLike4 {
                                        function decimals() public view returns (uint);
                                        function balanceOf(address) public returns (uint256);
                                        function transfer(address, uint256) public returns (bool);
                                    }
                                    
                                    contract GemBag {
                                        address  public ada;
                                        address  public lad;
                                        GemLike4 public gem;
                                    
                                        constructor(address lad_, address gem_) public {
                                            ada = msg.sender;
                                            lad = lad_;
                                            gem = GemLike4(gem_);
                                        }
                                    
                                        function exit(address usr, uint256 wad) external {
                                            require(msg.sender == ada || msg.sender == lad, "GemBag/invalid-caller");
                                            require(gem.transfer(usr, wad), "GemBag/failed-transfer");
                                        }
                                    }
                                    
                                    contract GemJoin4 is LibNote {
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) external note auth { wards[usr] = 1; }
                                        function deny(address usr) external note auth { wards[usr] = 0; }
                                        modifier auth { require(wards[msg.sender] == 1); _; }
                                    
                                        VatLike  public vat;
                                        bytes32  public ilk;
                                        GemLike4 public gem;
                                        uint     public dec;
                                        uint     public live;  // Access Flag
                                    
                                        mapping(address => address) public bags;
                                    
                                        constructor(address vat_, bytes32 ilk_, address gem_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                            gem = GemLike4(gem_);
                                            dec = gem.decimals();
                                        }
                                    
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                    
                                        // -- admin --
                                        function make() external returns (address bag) {
                                            bag = make(msg.sender);
                                        }
                                    
                                        function make(address usr) public note returns (address bag) {
                                            require(bags[usr] == address(0), "GemJoin4/bag-already-exists");
                                    
                                            bag = address(new GemBag(address(usr), address(gem)));
                                            bags[usr] = bag;
                                        }
                                    
                                        // -- gems --
                                        function join(address urn, uint256 wad) external note {
                                            require(live == 1, "GemJoin4/not-live");
                                            require(int256(wad) >= 0, "GemJoin4/negative-amount");
                                    
                                            GemBag(bags[msg.sender]).exit(address(this), wad);
                                            vat.slip(ilk, urn, int256(wad));
                                        }
                                    
                                        function exit(address usr, uint256 wad) external note {
                                            require(int256(wad) >= 0, "GemJoin4/negative-amount");
                                    
                                            vat.slip(ilk, msg.sender, -int256(wad));
                                            require(gem.transfer(usr, wad), "GemJoin4/failed-transfer");
                                        }
                                    }
                                    
                                    // AuthGemJoin
                                    // For a token that needs restriction on the sources which are able to execute the join function (like SAI through Migration contract)
                                    
                                    contract GemLike {
                                        function decimals() public view returns (uint);
                                        function transfer(address,uint) public returns (bool);
                                        function transferFrom(address,address,uint) public returns (bool);
                                    }
                                    
                                    contract AuthGemJoin is LibNote {
                                        VatLike public vat;
                                        bytes32 public ilk;
                                        GemLike public gem;
                                        uint    public dec;
                                        uint    public live;  // Access Flag
                                    
                                        // --- Auth ---
                                        mapping (address => uint) public wards;
                                        function rely(address usr) public note auth { wards[usr] = 1; }
                                        function deny(address usr) public note auth { wards[usr] = 0; }
                                        modifier auth { require(wards[msg.sender] == 1, "AuthGemJoin/non-authed"); _; }
                                    
                                        constructor(address vat_, bytes32 ilk_, address gem_) public {
                                            wards[msg.sender] = 1;
                                            live = 1;
                                            vat = VatLike(vat_);
                                            ilk = ilk_;
                                            gem = GemLike(gem_);
                                            dec = gem.decimals();
                                        }
                                    
                                        function cage() external note auth {
                                            live = 0;
                                        }
                                    
                                        function join(address usr, uint wad) public auth note {
                                            require(live == 1, "AuthGemJoin/not-live");
                                            require(int(wad) >= 0, "AuthGemJoin/overflow");
                                            vat.slip(ilk, usr, int(wad));
                                            require(gem.transferFrom(msg.sender, address(this), wad), "AuthGemJoin/failed-transfer");
                                        }
                                    
                                        function exit(address usr, uint wad) public note {
                                            require(wad <= 2 ** 255, "AuthGemJoin/overflow");
                                            vat.slip(ilk, msg.sender, -int(wad));
                                            require(gem.transfer(usr, wad), "AuthGemJoin/failed-transfer");
                                        }
                                    }

                                    File 7 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 8 of 9: Vyper_contract
                                    # @title Uniswap Exchange Interface V1
                                    # @notice Source code found at https://github.com/uniswap
                                    # @notice Use at your own risk
                                    
                                    contract Factory():
                                        def getExchange(token_addr: address) -> address: constant
                                    
                                    contract Exchange():
                                        def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant
                                        def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying
                                        def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying
                                    
                                    TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)})
                                    EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))})
                                    AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256})
                                    Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256})
                                    
                                    name: public(bytes32)                             # Uniswap V1
                                    symbol: public(bytes32)                           # UNI-V1
                                    decimals: public(uint256)                         # 18
                                    totalSupply: public(uint256)                      # total number of UNI in existence
                                    balances: uint256[address]                        # UNI balance of an address
                                    allowances: (uint256[address])[address]           # UNI allowance of one address on another
                                    token: address(ERC20)                             # address of the ERC20 token traded on this contract
                                    factory: Factory                                  # interface for the factory that created this contract
                                    
                                    # @dev This function acts as a contract constructor which is not currently supported in contracts deployed
                                    #      using create_with_code_of(). It is called once by the factory during contract creation.
                                    @public
                                    def setup(token_addr: address):
                                        assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS
                                        self.factory = msg.sender
                                        self.token = token_addr
                                        self.name = 0x556e697377617020563100000000000000000000000000000000000000000000
                                        self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000
                                        self.decimals = 18
                                    
                                    # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens.
                                    # @dev min_liquidity does nothing when total UNI supply is 0.
                                    # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0.
                                    # @param max_tokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of UNI minted.
                                    @public
                                    @payable
                                    def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256:
                                        assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        if total_liquidity > 0:
                                            assert min_liquidity > 0
                                            eth_reserve: uint256(wei) = self.balance - msg.value
                                            token_reserve: uint256 = self.token.balanceOf(self)
                                            token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1
                                            liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve
                                            assert max_tokens >= token_amount and liquidity_minted >= min_liquidity
                                            self.balances[msg.sender] += liquidity_minted
                                            self.totalSupply = total_liquidity + liquidity_minted
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted)
                                            return liquidity_minted
                                        else:
                                            assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000
                                            assert self.factory.getExchange(self.token) == self
                                            token_amount: uint256 = max_tokens
                                            initial_liquidity: uint256 = as_unitless_number(self.balance)
                                            self.totalSupply = initial_liquidity
                                            self.balances[msg.sender] = initial_liquidity
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity)
                                            return initial_liquidity
                                    
                                    # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio.
                                    # @param amount Amount of UNI burned.
                                    # @param min_eth Minimum ETH withdrawn.
                                    # @param min_tokens Minimum Tokens withdrawn.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of ETH and Tokens withdrawn.
                                    @public
                                    def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256):
                                        assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        assert total_liquidity > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_amount: uint256(wei) = amount * self.balance / total_liquidity
                                        token_amount: uint256 = amount * token_reserve / total_liquidity
                                        assert eth_amount >= min_eth and token_amount >= min_tokens
                                        self.balances[msg.sender] -= amount
                                        self.totalSupply = total_liquidity - amount
                                        send(msg.sender, eth_amount)
                                        assert self.token.transfer(msg.sender, token_amount)
                                        log.RemoveLiquidity(msg.sender, eth_amount, token_amount)
                                        log.Transfer(msg.sender, ZERO_ADDRESS, amount)
                                        return eth_amount, token_amount
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param input_amount Amount of ETH or Tokens being sold.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens bought.
                                    @private
                                    @constant
                                    def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        input_amount_with_fee: uint256 = input_amount * 997
                                        numerator: uint256 = input_amount_with_fee * output_reserve
                                        denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee
                                        return numerator / denominator
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param output_amount Amount of ETH or Tokens being bought.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens sold.
                                    @private
                                    @constant
                                    def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        numerator: uint256 = input_reserve * output_amount * 1000
                                        denominator: uint256 = (output_reserve - output_amount) * 997
                                        return numerator / denominator + 1
                                    
                                    @private
                                    def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve)
                                        assert tokens_bought >= min_tokens
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, eth_sold, tokens_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value).
                                    # @dev User cannot specify minimum output or deadline.
                                    @public
                                    @payable
                                    def __default__():
                                        self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value) and minimum output.
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies exact input (msg.value) and minimum output
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve)
                                        # Throws if eth_sold > max_eth
                                        eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei')
                                        if eth_refund > 0:
                                            send(buyer, eth_refund)
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei):
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth
                                        send(recipient, wei_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return wei_bought
                                    
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei):
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens >= tokens_sold
                                        send(recipient, eth_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    @private
                                    def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact input.
                                    # @param eth_sold Amount of ETH sold.
                                    # @return Amount of Tokens that can be bought with input ETH.
                                    @public
                                    @constant
                                    def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256:
                                        assert eth_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact output.
                                    # @param tokens_bought Amount of Tokens bought.
                                    # @return Amount of ETH needed to buy output Tokens.
                                    @public
                                    @constant
                                    def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei):
                                        assert tokens_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact input.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @return Amount of ETH that can be bought with input Tokens.
                                    @public
                                    @constant
                                    def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei):
                                        assert tokens_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        return as_wei_value(eth_bought, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact output.
                                    # @param eth_bought Amount of output ETH.
                                    # @return Amount of Tokens needed to buy output ETH.
                                    @public
                                    @constant
                                    def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256:
                                        assert eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                    
                                    # @return Address of Token that is sold on this exchange.
                                    @public
                                    @constant
                                    def tokenAddress() -> address:
                                        return self.token
                                    
                                    # @return Address of factory that created this exchange.
                                    @public
                                    @constant
                                    def factoryAddress() -> address(Factory):
                                        return self.factory
                                    
                                    # ERC20 compatibility for exchange liquidity modified from
                                    # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy
                                    @public
                                    @constant
                                    def balanceOf(_owner : address) -> uint256:
                                        return self.balances[_owner]
                                    
                                    @public
                                    def transfer(_to : address, _value : uint256) -> bool:
                                        self.balances[msg.sender] -= _value
                                        self.balances[_to] += _value
                                        log.Transfer(msg.sender, _to, _value)
                                        return True
                                    
                                    @public
                                    def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
                                        self.balances[_from] -= _value
                                        self.balances[_to] += _value
                                        self.allowances[_from][msg.sender] -= _value
                                        log.Transfer(_from, _to, _value)
                                        return True
                                    
                                    @public
                                    def approve(_spender : address, _value : uint256) -> bool:
                                        self.allowances[msg.sender][_spender] = _value
                                        log.Approval(msg.sender, _spender, _value)
                                        return True
                                    
                                    @public
                                    @constant
                                    def allowance(_owner : address, _spender : address) -> uint256:
                                        return self.allowances[_owner][_spender]

                                    File 9 of 9: Vyper_contract
                                    # @title Uniswap Exchange Interface V1
                                    # @notice Source code found at https://github.com/uniswap
                                    # @notice Use at your own risk
                                    
                                    contract Factory():
                                        def getExchange(token_addr: address) -> address: constant
                                    
                                    contract Exchange():
                                        def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei): constant
                                        def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256: modifying
                                        def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei): modifying
                                    
                                    TokenPurchase: event({buyer: indexed(address), eth_sold: indexed(uint256(wei)), tokens_bought: indexed(uint256)})
                                    EthPurchase: event({buyer: indexed(address), tokens_sold: indexed(uint256), eth_bought: indexed(uint256(wei))})
                                    AddLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    RemoveLiquidity: event({provider: indexed(address), eth_amount: indexed(uint256(wei)), token_amount: indexed(uint256)})
                                    Transfer: event({_from: indexed(address), _to: indexed(address), _value: uint256})
                                    Approval: event({_owner: indexed(address), _spender: indexed(address), _value: uint256})
                                    
                                    name: public(bytes32)                             # Uniswap V1
                                    symbol: public(bytes32)                           # UNI-V1
                                    decimals: public(uint256)                         # 18
                                    totalSupply: public(uint256)                      # total number of UNI in existence
                                    balances: uint256[address]                        # UNI balance of an address
                                    allowances: (uint256[address])[address]           # UNI allowance of one address on another
                                    token: address(ERC20)                             # address of the ERC20 token traded on this contract
                                    factory: Factory                                  # interface for the factory that created this contract
                                    
                                    # @dev This function acts as a contract constructor which is not currently supported in contracts deployed
                                    #      using create_with_code_of(). It is called once by the factory during contract creation.
                                    @public
                                    def setup(token_addr: address):
                                        assert (self.factory == ZERO_ADDRESS and self.token == ZERO_ADDRESS) and token_addr != ZERO_ADDRESS
                                        self.factory = msg.sender
                                        self.token = token_addr
                                        self.name = 0x556e697377617020563100000000000000000000000000000000000000000000
                                        self.symbol = 0x554e492d56310000000000000000000000000000000000000000000000000000
                                        self.decimals = 18
                                    
                                    # @notice Deposit ETH and Tokens (self.token) at current ratio to mint UNI tokens.
                                    # @dev min_liquidity does nothing when total UNI supply is 0.
                                    # @param min_liquidity Minimum number of UNI sender will mint if total UNI supply is greater than 0.
                                    # @param max_tokens Maximum number of tokens deposited. Deposits max amount if total UNI supply is 0.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of UNI minted.
                                    @public
                                    @payable
                                    def addLiquidity(min_liquidity: uint256, max_tokens: uint256, deadline: timestamp) -> uint256:
                                        assert deadline > block.timestamp and (max_tokens > 0 and msg.value > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        if total_liquidity > 0:
                                            assert min_liquidity > 0
                                            eth_reserve: uint256(wei) = self.balance - msg.value
                                            token_reserve: uint256 = self.token.balanceOf(self)
                                            token_amount: uint256 = msg.value * token_reserve / eth_reserve + 1
                                            liquidity_minted: uint256 = msg.value * total_liquidity / eth_reserve
                                            assert max_tokens >= token_amount and liquidity_minted >= min_liquidity
                                            self.balances[msg.sender] += liquidity_minted
                                            self.totalSupply = total_liquidity + liquidity_minted
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, liquidity_minted)
                                            return liquidity_minted
                                        else:
                                            assert (self.factory != ZERO_ADDRESS and self.token != ZERO_ADDRESS) and msg.value >= 1000000000
                                            assert self.factory.getExchange(self.token) == self
                                            token_amount: uint256 = max_tokens
                                            initial_liquidity: uint256 = as_unitless_number(self.balance)
                                            self.totalSupply = initial_liquidity
                                            self.balances[msg.sender] = initial_liquidity
                                            assert self.token.transferFrom(msg.sender, self, token_amount)
                                            log.AddLiquidity(msg.sender, msg.value, token_amount)
                                            log.Transfer(ZERO_ADDRESS, msg.sender, initial_liquidity)
                                            return initial_liquidity
                                    
                                    # @dev Burn UNI tokens to withdraw ETH and Tokens at current ratio.
                                    # @param amount Amount of UNI burned.
                                    # @param min_eth Minimum ETH withdrawn.
                                    # @param min_tokens Minimum Tokens withdrawn.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return The amount of ETH and Tokens withdrawn.
                                    @public
                                    def removeLiquidity(amount: uint256, min_eth: uint256(wei), min_tokens: uint256, deadline: timestamp) -> (uint256(wei), uint256):
                                        assert (amount > 0 and deadline > block.timestamp) and (min_eth > 0 and min_tokens > 0)
                                        total_liquidity: uint256 = self.totalSupply
                                        assert total_liquidity > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_amount: uint256(wei) = amount * self.balance / total_liquidity
                                        token_amount: uint256 = amount * token_reserve / total_liquidity
                                        assert eth_amount >= min_eth and token_amount >= min_tokens
                                        self.balances[msg.sender] -= amount
                                        self.totalSupply = total_liquidity - amount
                                        send(msg.sender, eth_amount)
                                        assert self.token.transfer(msg.sender, token_amount)
                                        log.RemoveLiquidity(msg.sender, eth_amount, token_amount)
                                        log.Transfer(msg.sender, ZERO_ADDRESS, amount)
                                        return eth_amount, token_amount
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param input_amount Amount of ETH or Tokens being sold.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens bought.
                                    @private
                                    @constant
                                    def getInputPrice(input_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        input_amount_with_fee: uint256 = input_amount * 997
                                        numerator: uint256 = input_amount_with_fee * output_reserve
                                        denominator: uint256 = (input_reserve * 1000) + input_amount_with_fee
                                        return numerator / denominator
                                    
                                    # @dev Pricing function for converting between ETH and Tokens.
                                    # @param output_amount Amount of ETH or Tokens being bought.
                                    # @param input_reserve Amount of ETH or Tokens (input type) in exchange reserves.
                                    # @param output_reserve Amount of ETH or Tokens (output type) in exchange reserves.
                                    # @return Amount of ETH or Tokens sold.
                                    @private
                                    @constant
                                    def getOutputPrice(output_amount: uint256, input_reserve: uint256, output_reserve: uint256) -> uint256:
                                        assert input_reserve > 0 and output_reserve > 0
                                        numerator: uint256 = input_reserve * output_amount * 1000
                                        denominator: uint256 = (output_reserve - output_amount) * 997
                                        return numerator / denominator + 1
                                    
                                    @private
                                    def ethToTokenInput(eth_sold: uint256(wei), min_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and (eth_sold > 0 and min_tokens > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_bought: uint256 = self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance - eth_sold), token_reserve)
                                        assert tokens_bought >= min_tokens
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, eth_sold, tokens_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value).
                                    # @dev User cannot specify minimum output or deadline.
                                    @public
                                    @payable
                                    def __default__():
                                        self.ethToTokenInput(msg.value, 1, block.timestamp, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies exact input (msg.value) and minimum output.
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenSwapInput(min_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies exact input (msg.value) and minimum output
                                    # @param min_tokens Minimum Tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of Tokens bought.
                                    @public
                                    @payable
                                    def ethToTokenTransferInput(min_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenInput(msg.value, min_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def ethToTokenOutput(tokens_bought: uint256, max_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance - max_eth), token_reserve)
                                        # Throws if eth_sold > max_eth
                                        eth_refund: uint256(wei) = max_eth - as_wei_value(eth_sold, 'wei')
                                        if eth_refund > 0:
                                            send(buyer, eth_refund)
                                        assert self.token.transfer(recipient, tokens_bought)
                                        log.TokenPurchase(buyer, as_wei_value(eth_sold, 'wei'), tokens_bought)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Convert ETH to Tokens.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenSwapOutput(tokens_bought: uint256, deadline: timestamp) -> uint256(wei):
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert ETH to Tokens and transfers Tokens to recipient.
                                    # @dev User specifies maximum input (msg.value) and exact output.
                                    # @param tokens_bought Amount of tokens bought.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output Tokens.
                                    # @return Amount of ETH sold.
                                    @public
                                    @payable
                                    def ethToTokenTransferOutput(tokens_bought: uint256, deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.ethToTokenOutput(tokens_bought, msg.value, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, buyer: address, recipient: address) -> uint256(wei):
                                        assert deadline >= block.timestamp and (tokens_sold > 0 and min_eth > 0)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth
                                        send(recipient, wei_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return wei_bought
                                    
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthSwapInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp) -> uint256(wei):
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_eth Minimum ETH purchased.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of ETH bought.
                                    @public
                                    def tokenToEthTransferInput(tokens_sold: uint256, min_eth: uint256(wei), deadline: timestamp, recipient: address) -> uint256(wei):
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthInput(tokens_sold, min_eth, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToEthOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, buyer: address, recipient: address) -> uint256:
                                        assert deadline >= block.timestamp and eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens >= tokens_sold
                                        send(recipient, eth_bought)
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens to ETH.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthSwapOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp) -> uint256:
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, msg.sender)
                                    
                                    # @notice Convert Tokens to ETH and transfers ETH to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param eth_bought Amount of ETH purchased.
                                    # @param max_tokens Maximum Tokens sold.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @return Amount of Tokens sold.
                                    @public
                                    def tokenToEthTransferOutput(eth_bought: uint256(wei), max_tokens: uint256, deadline: timestamp, recipient: address) -> uint256:
                                        assert recipient != self and recipient != ZERO_ADDRESS
                                        return self.tokenToEthOutput(eth_bought, max_tokens, deadline, msg.sender, recipient)
                                    
                                    @private
                                    def tokenToTokenInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert (deadline >= block.timestamp and tokens_sold > 0) and (min_tokens_bought > 0 and min_eth_bought > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        wei_bought: uint256(wei) = as_wei_value(eth_bought, 'wei')
                                        assert wei_bought >= min_eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        tokens_bought: uint256 = Exchange(exchange_addr).ethToTokenTransferInput(min_tokens_bought, deadline, recipient, value=wei_bought)
                                        log.EthPurchase(buyer, tokens_sold, wei_bought)
                                        return tokens_bought
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (token_addr) bought.
                                    @public
                                    def tokenToTokenTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    @private
                                    def tokenToTokenOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, buyer: address, recipient: address, exchange_addr: address) -> uint256:
                                        assert deadline >= block.timestamp and (tokens_bought > 0 and max_eth_sold > 0)
                                        assert exchange_addr != self and exchange_addr != ZERO_ADDRESS
                                        eth_bought: uint256(wei) = Exchange(exchange_addr).getEthToTokenOutputPrice(tokens_bought)
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        tokens_sold: uint256 = self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                        # tokens sold is always > 0
                                        assert max_tokens_sold >= tokens_sold and max_eth_sold >= eth_bought
                                        assert self.token.transferFrom(buyer, self, tokens_sold)
                                        eth_sold: uint256(wei) = Exchange(exchange_addr).ethToTokenTransferOutput(tokens_bought, deadline, recipient, value=eth_bought)
                                        log.EthPurchase(buyer, tokens_sold, eth_bought)
                                        return tokens_sold
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr).
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (token_addr) and transfers
                                    #         Tokens (token_addr) to recipient.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToTokenTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, token_addr: address) -> uint256:
                                        exchange_addr: address = self.factory.getExchange(token_addr)
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeSwapInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies exact input and minimum output.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @param min_tokens_bought Minimum Tokens (token_addr) purchased.
                                    # @param min_eth_bought Minimum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (exchange_addr.token) bought.
                                    @public
                                    def tokenToExchangeTransferInput(tokens_sold: uint256, min_tokens_bought: uint256, min_eth_bought: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenInput(tokens_sold, min_tokens_bought, min_eth_bought, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token).
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param exchange_addr The address of the exchange for the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeSwapOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, exchange_addr: address) -> uint256:
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, msg.sender, exchange_addr)
                                    
                                    # @notice Convert Tokens (self.token) to Tokens (exchange_addr.token) and transfers
                                    #         Tokens (exchange_addr.token) to recipient.
                                    # @dev Allows trades through contracts that were not deployed from the same factory.
                                    # @dev User specifies maximum input and exact output.
                                    # @param tokens_bought Amount of Tokens (token_addr) bought.
                                    # @param max_tokens_sold Maximum Tokens (self.token) sold.
                                    # @param max_eth_sold Maximum ETH purchased as intermediary.
                                    # @param deadline Time after which this transaction can no longer be executed.
                                    # @param recipient The address that receives output ETH.
                                    # @param token_addr The address of the token being purchased.
                                    # @return Amount of Tokens (self.token) sold.
                                    @public
                                    def tokenToExchangeTransferOutput(tokens_bought: uint256, max_tokens_sold: uint256, max_eth_sold: uint256(wei), deadline: timestamp, recipient: address, exchange_addr: address) -> uint256:
                                        assert recipient != self
                                        return self.tokenToTokenOutput(tokens_bought, max_tokens_sold, max_eth_sold, deadline, msg.sender, recipient, exchange_addr)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact input.
                                    # @param eth_sold Amount of ETH sold.
                                    # @return Amount of Tokens that can be bought with input ETH.
                                    @public
                                    @constant
                                    def getEthToTokenInputPrice(eth_sold: uint256(wei)) -> uint256:
                                        assert eth_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getInputPrice(as_unitless_number(eth_sold), as_unitless_number(self.balance), token_reserve)
                                    
                                    # @notice Public price function for ETH to Token trades with an exact output.
                                    # @param tokens_bought Amount of Tokens bought.
                                    # @return Amount of ETH needed to buy output Tokens.
                                    @public
                                    @constant
                                    def getEthToTokenOutputPrice(tokens_bought: uint256) -> uint256(wei):
                                        assert tokens_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_sold: uint256 = self.getOutputPrice(tokens_bought, as_unitless_number(self.balance), token_reserve)
                                        return as_wei_value(eth_sold, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact input.
                                    # @param tokens_sold Amount of Tokens sold.
                                    # @return Amount of ETH that can be bought with input Tokens.
                                    @public
                                    @constant
                                    def getTokenToEthInputPrice(tokens_sold: uint256) -> uint256(wei):
                                        assert tokens_sold > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        eth_bought: uint256 = self.getInputPrice(tokens_sold, token_reserve, as_unitless_number(self.balance))
                                        return as_wei_value(eth_bought, 'wei')
                                    
                                    # @notice Public price function for Token to ETH trades with an exact output.
                                    # @param eth_bought Amount of output ETH.
                                    # @return Amount of Tokens needed to buy output ETH.
                                    @public
                                    @constant
                                    def getTokenToEthOutputPrice(eth_bought: uint256(wei)) -> uint256:
                                        assert eth_bought > 0
                                        token_reserve: uint256 = self.token.balanceOf(self)
                                        return self.getOutputPrice(as_unitless_number(eth_bought), token_reserve, as_unitless_number(self.balance))
                                    
                                    # @return Address of Token that is sold on this exchange.
                                    @public
                                    @constant
                                    def tokenAddress() -> address:
                                        return self.token
                                    
                                    # @return Address of factory that created this exchange.
                                    @public
                                    @constant
                                    def factoryAddress() -> address(Factory):
                                        return self.factory
                                    
                                    # ERC20 compatibility for exchange liquidity modified from
                                    # https://github.com/ethereum/vyper/blob/master/examples/tokens/ERC20.vy
                                    @public
                                    @constant
                                    def balanceOf(_owner : address) -> uint256:
                                        return self.balances[_owner]
                                    
                                    @public
                                    def transfer(_to : address, _value : uint256) -> bool:
                                        self.balances[msg.sender] -= _value
                                        self.balances[_to] += _value
                                        log.Transfer(msg.sender, _to, _value)
                                        return True
                                    
                                    @public
                                    def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
                                        self.balances[_from] -= _value
                                        self.balances[_to] += _value
                                        self.allowances[_from][msg.sender] -= _value
                                        log.Transfer(_from, _to, _value)
                                        return True
                                    
                                    @public
                                    def approve(_spender : address, _value : uint256) -> bool:
                                        self.allowances[msg.sender][_spender] = _value
                                        log.Approval(msg.sender, _spender, _value)
                                        return True
                                    
                                    @public
                                    @constant
                                    def allowance(_owner : address, _spender : address) -> uint256:
                                        return self.allowances[_owner][_spender]