ETH Price: $1,920.34 (+3.40%)

Transaction Decoder

Block:
10636767 at Aug-11-2020 05:28:57 AM +UTC
Transaction Fee:
0.005523471 ETH $10.61
Gas Used:
56,943 Gas / 97 Gwei

Account State Difference:

  Address   Before After State Difference Code
(Nanopool)
3,199.020516200270768971 Eth3,199.026039671270768971 Eth0.005523471
0x860bd2db...5F6D78F66
(MEV Bot: 0x860...F66)
0xc8db9117...503e5f73a
0.071004668 Eth
Nonce: 7293
0.065481197 Eth
Nonce: 7294
0.005523471

Execution Trace

MEV Bot: 0x860...F66.c89e4361( )
  • 0x67fd56402147831a32b28b31d887fa0b59e6d0dd.689c49c0( )
    • Vyper_contract.getEthToTokenInputPrice( eth_sold=1026104252400548696 ) => ( out=684072616319009805960 )
      • Vyper_contract.getEthToTokenInputPrice( eth_sold=1026104252400548696 ) => ( out=684072616319009805960 )
        • VXV.balanceOf( tokenOwner=0x7b9B5084aFF35D3E9D87Fb1e384853B806120bED ) => ( balance=7191863382288527369085 )
        • UniswapV2Pair.STATICCALL( )
        • UniswapV2Pair.STATICCALL( )
          File 1 of 4: 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 4: 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 3 of 4: VXV
          pragma solidity ^0.4.24;
          
          
          contract SafeMath {
              function safeAdd(uint a, uint b) public pure returns (uint c) {
                  c = a + b;
                  require(c >= a);
              }
              function safeSub(uint a, uint b) public pure returns (uint c) {
                  require(b <= a);
                  c = a - b;
              }
              function safeMul(uint a, uint b) public pure returns (uint c) {
                  c = a * b;
                  require(a == 0 || c / a == b);
              }
              function safeDiv(uint a, uint b) public pure returns (uint c) {
                  require(b > 0);
                  c = a / b;
              }
          }
          
          
          // ----------------------------------------------------------------------------
          // ERC Token Standard #20 Interface
          // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
          // ----------------------------------------------------------------------------
          contract ERC20Interface {
              function totalSupply() public view returns (uint);
              function balanceOf(address tokenOwner) public view returns (uint balance);
              function allowance(address tokenOwner, address spender) public view returns (uint remaining);
              function transfer(address to, uint tokens) public returns (bool success);
              function approve(address spender, uint tokens) public returns (bool success);
              function transferFrom(address from, address to, uint tokens) public returns (bool success);
          
              event Transfer(address indexed from, address indexed to, uint tokens);
              event Approval(address indexed tokenOwner, address indexed spender, uint tokens);
          }
          
          
          // ----------------------------------------------------------------------------
          // Contract function to receive approval and execute function in one call
          //
          // Borrowed from MiniMeToken
          // ----------------------------------------------------------------------------
          contract ApproveAndCallFallBack {
              function receiveApproval(address from, uint256 tokens, address token, bytes data) public;
          }
          
          
          contract Owned {
              address public owner;
              // address public newOwner;
          
              event OwnershipTransferred(address indexed _from, address indexed _to);
          
              constructor() public {
                  owner = msg.sender;
              }
          
              modifier onlyOwner {
                  require(msg.sender == owner);
                  _;
              }
          
              // function transferOwnership(address _newOwner) public onlyOwner {
              //     newOwner = _newOwner;
              // }
          
              // function acceptOwnership() public {
              //     require(msg.sender == newOwner);
              //     emit OwnershipTransferred(owner, newOwner);
              //     owner = newOwner;
              //     newOwner = address(0);
              // }
          }
          
          
          contract VXV is ERC20Interface, Owned, SafeMath {
              string public symbol;
              string public name;
              uint8 public decimals;
              uint public totalSupply;
              uint public rate;
          
              mapping(address => uint) balances;
              mapping(address => mapping(address => uint)) allowed;
          
              constructor() public {
                  symbol = "VXV";
                  name = "VectorspaceAI";
                  decimals = 18;
                  totalSupply = 50000000 * 10 ** uint256(decimals);
                  rate = 203;
                  balances[owner] = totalSupply;
                  emit Transfer(address(0), owner, totalSupply);
              }
          
              function changeRate(uint newRate) public onlyOwner {
                  require(newRate > 0);
                  rate = newRate;
              }
          
              function totalSupply() public view returns (uint) {
                  return totalSupply - balances[address(0)];
              }
          
              function balanceOf(address tokenOwner) public view returns (uint balance) {
                  return balances[tokenOwner];
              }
          
              modifier validTo(address to) {
                  require(to != address(0));
                  require(to != address(this));
                  _;
              }
          
              function transferInternal(address from, address to, uint tokens) internal {
                  balances[from] = safeSub(balances[from], tokens);
                  balances[to] = safeAdd(balances[to], tokens);
                  emit Transfer(from, to, tokens);
              }
          
              function transfer(address to, uint tokens) public validTo(to) returns (bool success) {
                  transferInternal(msg.sender, to, tokens);
                  return true;
              }
          
              // ------------------------------------------------------------------------
              // Transfer `tokens` from the `from` account to the `to` account
              //
              // The calling account must already have sufficient tokens approve(...)-d
              // for spending from the `from` account and
              // - From account must have sufficient balance to transfer
              // - Spender must have sufficient allowance to transfer
              // - 0 value transfers are allowed
              // ------------------------------------------------------------------------
              function transferFrom(address from, address to, uint tokens) public validTo(to) returns (bool success) {
                  allowed[from][msg.sender] = safeSub(allowed[from][msg.sender], tokens);
                  transferInternal(from, to, tokens);
                  return true;
              }
          
              // ------------------------------------------------------------------------
              // Token owner can approve for `spender` to transferFrom(...) `tokens`
              // from the token owner's account
              //
              // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md
              // recommends that there are no checks for the approval double-spend attack
              // as this should be implemented in user interfaces
              // ------------------------------------------------------------------------
              function approve(address spender, uint tokens) public returns (bool success) {
                  allowed[msg.sender][spender] = tokens;
                  emit Approval(msg.sender, spender, tokens);
                  return true;
              }
          
              function allowance(address tokenOwner, address spender) public view returns (uint remaining) {
                  return allowed[tokenOwner][spender];
              }
          
              // ------------------------------------------------------------------------
              // Token owner can approve for `spender` to transferFrom(...) `tokens`
              // from the token owner's account. The `spender` contract function
              // `receiveApproval(...)` is then executed
              // ------------------------------------------------------------------------
              function approveAndCall(address spender, uint tokens, bytes data) public returns (bool success) {
                  if (approve(spender, tokens)) {
                      ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, this, data);
                      return true;
                  }
              }
          
              function () public payable {
                  uint tokens;
                  tokens = safeMul(msg.value, rate);
          
                  balances[owner] = safeSub(balances[owner], tokens);
                  balances[msg.sender] = safeAdd(balances[msg.sender], tokens);
          
                  emit Transfer(address(0), msg.sender, tokens);
                  owner.transfer(msg.value);
              }
          
              // ------------------------------------------------------------------------
              // Owner can transfer out any accidentally sent ERC20 tokens
              // ------------------------------------------------------------------------
              // function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) {
              //     return ERC20Interface(tokenAddress).transfer(owner, tokens);
              // }
          }

          File 4 of 4: UniswapV2Pair
          // File: contracts/interfaces/IUniswapV2Pair.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Pair {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external pure returns (string memory);
              function symbol() external pure returns (string memory);
              function decimals() external pure returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          
              function DOMAIN_SEPARATOR() external view returns (bytes32);
              function PERMIT_TYPEHASH() external pure returns (bytes32);
              function nonces(address owner) external view returns (uint);
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
          
              event Mint(address indexed sender, uint amount0, uint amount1);
              event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
              event Swap(
                  address indexed sender,
                  uint amount0In,
                  uint amount1In,
                  uint amount0Out,
                  uint amount1Out,
                  address indexed to
              );
              event Sync(uint112 reserve0, uint112 reserve1);
          
              function MINIMUM_LIQUIDITY() external pure returns (uint);
              function factory() external view returns (address);
              function token0() external view returns (address);
              function token1() external view returns (address);
              function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
              function price0CumulativeLast() external view returns (uint);
              function price1CumulativeLast() external view returns (uint);
              function kLast() external view returns (uint);
          
              function mint(address to) external returns (uint liquidity);
              function burn(address to) external returns (uint amount0, uint amount1);
              function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
              function skim(address to) external;
              function sync() external;
          
              function initialize(address, address) external;
          }
          
          // File: contracts/interfaces/IUniswapV2ERC20.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2ERC20 {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external pure returns (string memory);
              function symbol() external pure returns (string memory);
              function decimals() external pure returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          
              function DOMAIN_SEPARATOR() external view returns (bytes32);
              function PERMIT_TYPEHASH() external pure returns (bytes32);
              function nonces(address owner) external view returns (uint);
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
          }
          
          // File: contracts/libraries/SafeMath.sol
          
          pragma solidity =0.5.16;
          
          // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
          
          library SafeMath {
              function add(uint x, uint y) internal pure returns (uint z) {
                  require((z = x + y) >= x, 'ds-math-add-overflow');
              }
          
              function sub(uint x, uint y) internal pure returns (uint z) {
                  require((z = x - y) <= x, 'ds-math-sub-underflow');
              }
          
              function mul(uint x, uint y) internal pure returns (uint z) {
                  require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow');
              }
          }
          
          // File: contracts/UniswapV2ERC20.sol
          
          pragma solidity =0.5.16;
          
          
          
          contract UniswapV2ERC20 is IUniswapV2ERC20 {
              using SafeMath for uint;
          
              string public constant name = 'Uniswap V2';
              string public constant symbol = 'UNI-V2';
              uint8 public constant decimals = 18;
              uint  public totalSupply;
              mapping(address => uint) public balanceOf;
              mapping(address => mapping(address => uint)) public allowance;
          
              bytes32 public DOMAIN_SEPARATOR;
              // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
              bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
              mapping(address => uint) public nonces;
          
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              constructor() public {
                  uint chainId;
                  assembly {
                      chainId := chainid
                  }
                  DOMAIN_SEPARATOR = keccak256(
                      abi.encode(
                          keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                          keccak256(bytes(name)),
                          keccak256(bytes('1')),
                          chainId,
                          address(this)
                      )
                  );
              }
          
              function _mint(address to, uint value) internal {
                  totalSupply = totalSupply.add(value);
                  balanceOf[to] = balanceOf[to].add(value);
                  emit Transfer(address(0), to, value);
              }
          
              function _burn(address from, uint value) internal {
                  balanceOf[from] = balanceOf[from].sub(value);
                  totalSupply = totalSupply.sub(value);
                  emit Transfer(from, address(0), value);
              }
          
              function _approve(address owner, address spender, uint value) private {
                  allowance[owner][spender] = value;
                  emit Approval(owner, spender, value);
              }
          
              function _transfer(address from, address to, uint value) private {
                  balanceOf[from] = balanceOf[from].sub(value);
                  balanceOf[to] = balanceOf[to].add(value);
                  emit Transfer(from, to, value);
              }
          
              function approve(address spender, uint value) external returns (bool) {
                  _approve(msg.sender, spender, value);
                  return true;
              }
          
              function transfer(address to, uint value) external returns (bool) {
                  _transfer(msg.sender, to, value);
                  return true;
              }
          
              function transferFrom(address from, address to, uint value) external returns (bool) {
                  if (allowance[from][msg.sender] != uint(-1)) {
                      allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
                  }
                  _transfer(from, to, value);
                  return true;
              }
          
              function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
                  require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
                  bytes32 digest = keccak256(
                      abi.encodePacked(
                          '\x19\x01',
                          DOMAIN_SEPARATOR,
                          keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                      )
                  );
                  address recoveredAddress = ecrecover(digest, v, r, s);
                  require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
                  _approve(owner, spender, value);
              }
          }
          
          // File: contracts/libraries/Math.sol
          
          pragma solidity =0.5.16;
          
          // a library for performing various math operations
          
          library Math {
              function min(uint x, uint y) internal pure returns (uint z) {
                  z = x < y ? x : y;
              }
          
              // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
              function sqrt(uint y) internal pure returns (uint z) {
                  if (y > 3) {
                      z = y;
                      uint x = y / 2 + 1;
                      while (x < z) {
                          z = x;
                          x = (y / x + x) / 2;
                      }
                  } else if (y != 0) {
                      z = 1;
                  }
              }
          }
          
          // File: contracts/libraries/UQ112x112.sol
          
          pragma solidity =0.5.16;
          
          // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format))
          
          // range: [0, 2**112 - 1]
          // resolution: 1 / 2**112
          
          library UQ112x112 {
              uint224 constant Q112 = 2**112;
          
              // encode a uint112 as a UQ112x112
              function encode(uint112 y) internal pure returns (uint224 z) {
                  z = uint224(y) * Q112; // never overflows
              }
          
              // divide a UQ112x112 by a uint112, returning a UQ112x112
              function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) {
                  z = x / uint224(y);
              }
          }
          
          // File: contracts/interfaces/IERC20.sol
          
          pragma solidity >=0.5.0;
          
          interface IERC20 {
              event Approval(address indexed owner, address indexed spender, uint value);
              event Transfer(address indexed from, address indexed to, uint value);
          
              function name() external view returns (string memory);
              function symbol() external view returns (string memory);
              function decimals() external view returns (uint8);
              function totalSupply() external view returns (uint);
              function balanceOf(address owner) external view returns (uint);
              function allowance(address owner, address spender) external view returns (uint);
          
              function approve(address spender, uint value) external returns (bool);
              function transfer(address to, uint value) external returns (bool);
              function transferFrom(address from, address to, uint value) external returns (bool);
          }
          
          // File: contracts/interfaces/IUniswapV2Factory.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Factory {
              event PairCreated(address indexed token0, address indexed token1, address pair, uint);
          
              function feeTo() external view returns (address);
              function feeToSetter() external view returns (address);
          
              function getPair(address tokenA, address tokenB) external view returns (address pair);
              function allPairs(uint) external view returns (address pair);
              function allPairsLength() external view returns (uint);
          
              function createPair(address tokenA, address tokenB) external returns (address pair);
          
              function setFeeTo(address) external;
              function setFeeToSetter(address) external;
          }
          
          // File: contracts/interfaces/IUniswapV2Callee.sol
          
          pragma solidity >=0.5.0;
          
          interface IUniswapV2Callee {
              function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external;
          }
          
          // File: contracts/UniswapV2Pair.sol
          
          pragma solidity =0.5.16;
          
          
          
          
          
          
          
          
          contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 {
              using SafeMath  for uint;
              using UQ112x112 for uint224;
          
              uint public constant MINIMUM_LIQUIDITY = 10**3;
              bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
          
              address public factory;
              address public token0;
              address public token1;
          
              uint112 private reserve0;           // uses single storage slot, accessible via getReserves
              uint112 private reserve1;           // uses single storage slot, accessible via getReserves
              uint32  private blockTimestampLast; // uses single storage slot, accessible via getReserves
          
              uint public price0CumulativeLast;
              uint public price1CumulativeLast;
              uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event
          
              uint private unlocked = 1;
              modifier lock() {
                  require(unlocked == 1, 'UniswapV2: LOCKED');
                  unlocked = 0;
                  _;
                  unlocked = 1;
              }
          
              function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {
                  _reserve0 = reserve0;
                  _reserve1 = reserve1;
                  _blockTimestampLast = blockTimestampLast;
              }
          
              function _safeTransfer(address token, address to, uint value) private {
                  (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
                  require(success && (data.length == 0 || abi.decode(data, (bool))), 'UniswapV2: TRANSFER_FAILED');
              }
          
              event Mint(address indexed sender, uint amount0, uint amount1);
              event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
              event Swap(
                  address indexed sender,
                  uint amount0In,
                  uint amount1In,
                  uint amount0Out,
                  uint amount1Out,
                  address indexed to
              );
              event Sync(uint112 reserve0, uint112 reserve1);
          
              constructor() public {
                  factory = msg.sender;
              }
          
              // called once by the factory at time of deployment
              function initialize(address _token0, address _token1) external {
                  require(msg.sender == factory, 'UniswapV2: FORBIDDEN'); // sufficient check
                  token0 = _token0;
                  token1 = _token1;
              }
          
              // update reserves and, on the first call per block, price accumulators
              function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private {
                  require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'UniswapV2: OVERFLOW');
                  uint32 blockTimestamp = uint32(block.timestamp % 2**32);
                  uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired
                  if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) {
                      // * never overflows, and + overflow is desired
                      price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed;
                      price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed;
                  }
                  reserve0 = uint112(balance0);
                  reserve1 = uint112(balance1);
                  blockTimestampLast = blockTimestamp;
                  emit Sync(reserve0, reserve1);
              }
          
              // if fee is on, mint liquidity equivalent to 1/6th of the growth in sqrt(k)
              function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) {
                  address feeTo = IUniswapV2Factory(factory).feeTo();
                  feeOn = feeTo != address(0);
                  uint _kLast = kLast; // gas savings
                  if (feeOn) {
                      if (_kLast != 0) {
                          uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1));
                          uint rootKLast = Math.sqrt(_kLast);
                          if (rootK > rootKLast) {
                              uint numerator = totalSupply.mul(rootK.sub(rootKLast));
                              uint denominator = rootK.mul(5).add(rootKLast);
                              uint liquidity = numerator / denominator;
                              if (liquidity > 0) _mint(feeTo, liquidity);
                          }
                      }
                  } else if (_kLast != 0) {
                      kLast = 0;
                  }
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function mint(address to) external lock returns (uint liquidity) {
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  uint balance0 = IERC20(token0).balanceOf(address(this));
                  uint balance1 = IERC20(token1).balanceOf(address(this));
                  uint amount0 = balance0.sub(_reserve0);
                  uint amount1 = balance1.sub(_reserve1);
          
                  bool feeOn = _mintFee(_reserve0, _reserve1);
                  uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                  if (_totalSupply == 0) {
                      liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
                     _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
                  } else {
                      liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
                  }
                  require(liquidity > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_MINTED');
                  _mint(to, liquidity);
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                  emit Mint(msg.sender, amount0, amount1);
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function burn(address to) external lock returns (uint amount0, uint amount1) {
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  address _token0 = token0;                                // gas savings
                  address _token1 = token1;                                // gas savings
                  uint balance0 = IERC20(_token0).balanceOf(address(this));
                  uint balance1 = IERC20(_token1).balanceOf(address(this));
                  uint liquidity = balanceOf[address(this)];
          
                  bool feeOn = _mintFee(_reserve0, _reserve1);
                  uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee
                  amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
                  amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
                  require(amount0 > 0 && amount1 > 0, 'UniswapV2: INSUFFICIENT_LIQUIDITY_BURNED');
                  _burn(address(this), liquidity);
                  _safeTransfer(_token0, to, amount0);
                  _safeTransfer(_token1, to, amount1);
                  balance0 = IERC20(_token0).balanceOf(address(this));
                  balance1 = IERC20(_token1).balanceOf(address(this));
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date
                  emit Burn(msg.sender, amount0, amount1, to);
              }
          
              // this low-level function should be called from a contract which performs important safety checks
              function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock {
                  require(amount0Out > 0 || amount1Out > 0, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT');
                  (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings
                  require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: INSUFFICIENT_LIQUIDITY');
          
                  uint balance0;
                  uint balance1;
                  { // scope for _token{0,1}, avoids stack too deep errors
                  address _token0 = token0;
                  address _token1 = token1;
                  require(to != _token0 && to != _token1, 'UniswapV2: INVALID_TO');
                  if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
                  if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
                  if (data.length > 0) IUniswapV2Callee(to).uniswapV2Call(msg.sender, amount0Out, amount1Out, data);
                  balance0 = IERC20(_token0).balanceOf(address(this));
                  balance1 = IERC20(_token1).balanceOf(address(this));
                  }
                  uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0;
                  uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0;
                  require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT');
                  { // scope for reserve{0,1}Adjusted, avoids stack too deep errors
                  uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3));
                  uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3));
                  require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: K');
                  }
          
                  _update(balance0, balance1, _reserve0, _reserve1);
                  emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to);
              }
          
              // force balances to match reserves
              function skim(address to) external lock {
                  address _token0 = token0; // gas savings
                  address _token1 = token1; // gas savings
                  _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0));
                  _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1));
              }
          
              // force reserves to match balances
              function sync() external lock {
                  _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1);
              }
          }