ETH Price: $2,231.65 (-2.84%)

Transaction Decoder

Block:
10317495 at Jun-22-2020 07:36:55 PM +UTC
Transaction Fee:
0.00223701 ETH $4.99
Gas Used:
74,567 Gas / 30 Gwei

Emitted Events:

68 FLAMA.Transfer( from=[Receiver] Vyper_contract, to=0x0000000000000000000000000000000000000000, value=118759084227160740231 )
69 FLAMA.Transfer( from=[Receiver] Vyper_contract, to=[Sender] 0xa19dd3ffa9b94e28aefe696584ab3b015bdac77e, value=3839877056678197267510 )
70 Vyper_contract.TokenPurchase( buyer=[Sender] 0xa19dd3ffa9b94e28aefe696584ab3b015bdac77e, eth_sold=100000000000000000, tokens_bought=3958636140905358007741 )

Account State Difference:

  Address   Before After State Difference Code
0x0fd9C185...00cBF8BA4 62.611708842545658844 Eth62.711708842545658844 Eth0.1
0x2afd9cE0...60a8E1F70
(Spark Pool)
21.949918334181290556 Eth21.952155344181290556 Eth0.00223701
0xa19DD3FF...15bdAC77e
23.93943347329072298 Eth
Nonce: 7
23.83719646329072298 Eth
Nonce: 8
0.10223701

Execution Trace

ETH 0.1 Vyper_contract.ethToTokenSwapInput( min_tokens=3938842960200831217703, deadline=1592855484 ) => ( out=3958636140905358007741 )
  • ETH 0.1 Vyper_contract.ethToTokenSwapInput( min_tokens=3938842960200831217703, deadline=1592855484 ) => ( out=3958636140905358007741 )
    • FLAMA.balanceOf( owner=0x0fd9C18518fe793E02E20ADEBF4515600cBF8BA4 ) => ( 2489986454274755174246137 )
    • FLAMA.transfer( to=0xa19DD3FFA9b94e28aEFe696584Ab3b015bdAC77e, value=3958636140905358007741 ) => ( True )
      File 1 of 3: 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 3: FLAMA
      {"FLAMA.sol":{"content":"pragma solidity ^0.4.25;\n\nimport \"./IERC20.sol\";\nimport \"./SafeMath.sol\";\n\n\n\n/**\n * @title Standard ERC20 token (compatible with ERC20 token)\n *\n * @dev Implementation of the basic standard token.\n * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md\n * Originally based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n */\ncontract FLAMA is IERC20 {\n   using SafeMath for uint256;\n    string private _name;\n    string private _symbol;\n    uint8 private _decimals;\n    uint256 private _totalSupply;\n    mapping (address =\u003e uint256) private _balances;\n\n    mapping (address =\u003e mapping (address =\u003e uint256)) private _allowed;\n\n\n/**\n     * @dev Burns a specific amount of tokens.\n     * @param value The amount of token to be burned.\n     */\n    function burn(uint256 value) public {\n        _burn(msg.sender, value);\n    }\n\n\n\n\n    constructor (string name, string symbol, uint8 decimals, uint256 totalSupply ) public {\n        _name = name;\n        _symbol = symbol;\n        _decimals = decimals;\n        _totalSupply = totalSupply;\n        _balances[msg.sender] = _totalSupply;\n    }\n\n    /**\n     * @return the name of the token.\n     */\n    function name() public view returns (string) {\n        return _name;\n    }\n\n    /**\n     * @return the symbol of the token.\n     */\n    function symbol() public view returns (string) {\n        return _symbol;\n    }\n\n    /**\n     * @return the number of decimals of the token.\n     */\n    function decimals() public view returns (uint8) {\n        return _decimals;\n    }\n        /**\n     * @dev Total number of tokens in existence\n     */\n    function totalSupply() public view returns (uint256) {\n        return _totalSupply;\n    }\n\n\n    /**\n     * @dev Gets the balance of the specified address.\n     * @param owner The address to query the balance of.\n     * @return An uint256 representing the amount owned by the passed address.\n     */\n    function balanceOf(address owner) public view returns (uint256) {\n        return _balances[owner];\n    }\n\n    /**\n     * @dev Function to check the amount of tokens that an owner allowed to a spender.\n     * @param owner address The address which owns the funds.\n     * @param spender address The address which will spend the funds.\n     * @return A uint256 specifying the amount of tokens still available for the spender.\n     */\n    function allowance(\n        address owner,\n        address spender\n    )\n    public\n    view\n    returns (uint256)\n    {\n        return _allowed[owner][spender];\n    }\n\n    /**\n     * @dev Transfer token for a specified address\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function transfer(address to, uint256 value) public returns (bool) {\n\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.\n     * Beware that changing an allowance with this method brings the risk that someone may use both the old\n     * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this\n     * race condition is to first reduce the spender\u0027s allowance to 0 and set the desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     */\n    function approve(address spender, uint256 value) public returns (bool) {\n        require(spender != address(0));\n\n        _allowed[msg.sender][spender] = value;\n        emit Approval(msg.sender, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev Transfer tokens from one address to another\n     * @param from address The address which you want to send tokens from\n     * @param to address The address which you want to transfer to\n     * @param value uint256 the amount of tokens to be transferred\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 value\n    )\n    public\n    returns (bool)\n    {\n        _allowed[from][msg.sender] = _allowed[from][msg.sender].sub(value);\n        _transfer(from, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Increase the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To increment\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * @param spender The address which will spend the funds.\n     * @param addedValue The amount of tokens to increase the allowance by.\n     */\n    function increaseAllowance(\n        address spender,\n        uint256 addedValue\n    )\n    public\n    returns (bool)\n    {\n        require(spender != address(0));\n\n        _allowed[msg.sender][spender] = (\n        _allowed[msg.sender][spender].add(addedValue));\n        emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);\n        return true;\n    }\n\n    /**\n     * @dev Decrease the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To decrement\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * @param spender The address which will spend the funds.\n     * @param subtractedValue The amount of tokens to decrease the allowance by.\n     */\n    function decreaseAllowance(\n        address spender,\n        uint256 subtractedValue\n    )\n    public\n    returns (bool)\n    {\n        require(spender != address(0));\n\n        _allowed[msg.sender][spender] = (\n        _allowed[msg.sender][spender].sub(subtractedValue));\n        emit Approval(msg.sender, spender, _allowed[msg.sender][spender]);\n        return true;\n    }\n\n    /**\n     * @dev Transfer token for a specified addresses\n     * @param from The address to transfer from.\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        require(to != address(0));\n        uint256 onePercent = value.div(100);\n        uint256 burnAmount = onePercent.mul(3);\n        uint256 newTransferAmount = value.sub(burnAmount);\n        _totalSupply = _totalSupply.sub(burnAmount);\n        _balances[from] = _balances[from].sub(value);\n        _balances[to] = _balances[to].add(newTransferAmount);\n        emit Transfer(from, address(0), burnAmount);\n        emit Transfer(from, to, newTransferAmount);\n    }\n\n  \n\n    /**\n     * @dev Internal function that burns an amount of the token of a given\n     * account.\n     * @param account The account whose tokens will be burnt.\n     * @param value The amount that will be burnt.\n     */\n    function _burn(address account, uint256 value) internal {\n        require(account != address(0));\n\n        _totalSupply = _totalSupply.sub(value);\n        _balances[account] = _balances[account].sub(value);\n        emit Transfer(account, address(0), value);\n    }\n\n\n}\n\n\n\n \n\n\n"},"IERC20.sol":{"content":"pragma solidity ^0.4.25;\n\n/**\n * @title ERC20 interface (compatible with ERC20 interface)\n * @dev see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md\n */\ninterface IERC20 {\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address who) external view returns (uint256);\n\n    function allowance(address owner, address spender)\n    external view returns (uint256);\n\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function approve(address spender, uint256 value)\n    external returns (bool);\n\n    function transferFrom(address from, address to, uint256 value)\n    external returns (bool);\n\n    event Transfer(\n        address indexed from,\n        address indexed to,\n        uint256 value\n    );\n\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n}\n"},"SafeMath.sol":{"content":"pragma solidity ^0.4.25;\n\n/**\n * @title SafeMath\n * @dev Math operations with safety checks that revert on error\n */\nlibrary SafeMath {\n\n    /**\n     * @dev Multiplies two numbers, reverts on overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Gas optimization: this is cheaper than requiring \u0027a\u0027 not being zero, but the\n        // benefit is lost if \u0027b\u0027 is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b);\n\n        return c;\n    }\n\n    /**\n     * @dev Integer division of two numbers truncating the quotient, reverts on division by zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b \u003e 0); // Solidity only automatically asserts when dividing by 0\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn\u0027t hold\n\n        return c;\n    }\n\n    /**\n     * @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b \u003c= a);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Adds two numbers, reverts on overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c \u003e= a);\n\n        return c;\n    }\n\n    /**\n     * @dev Divides two numbers and returns the remainder (unsigned integer modulo),\n     * reverts when dividing by zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b != 0);\n        return a % b;\n    }\n}\n\n"}}

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