ETH Price: $2,515.90 (-1.45%)

Transaction Decoder

Block:
9610751 at Mar-05-2020 10:44:51 AM +UTC
Transaction Fee:
0.0005993 ETH $1.51
Gas Used:
119,860 Gas / 5 Gwei

Account State Difference:

  Address   Before After State Difference Code
0xD1898665...6df34AC33
0.025491308046892547 Eth
Nonce: 216
0.024892008046892547 Eth
Nonce: 217
0.0005993
(UUPool)
68.496884483567653755 Eth68.497483783567653755 Eth0.0005993

Execution Trace

Unipool.stake( amount=98612435804521291 )
  • Vyper_contract.transferFrom( _from=0xD1898665a01A91AC10bD2C6cb1899336df34AC33, _to=0x48D7f315feDcaD332F68aafa017c7C158BC54760, _value=98612435804521291 )
    • Vyper_contract.transferFrom( _from=0xD1898665a01A91AC10bD2C6cb1899336df34AC33, _to=0x48D7f315feDcaD332F68aafa017c7C158BC54760, _value=98612435804521291 )
      File 1 of 3: Unipool
      // File: @openzeppelin/contracts/math/Math.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @dev Standard math utilities missing in the Solidity language.
       */
      library Math {
          /**
           * @dev Returns the largest of two numbers.
           */
          function max(uint256 a, uint256 b) internal pure returns (uint256) {
              return a >= b ? a : b;
          }
      
          /**
           * @dev Returns the smallest of two numbers.
           */
          function min(uint256 a, uint256 b) internal pure returns (uint256) {
              return a < b ? a : b;
          }
      
          /**
           * @dev Returns the average of two numbers. The result is rounded towards
           * zero.
           */
          function average(uint256 a, uint256 b) internal pure returns (uint256) {
              // (a + b) / 2 can overflow, so we distribute
              return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);
          }
      }
      
      // File: @openzeppelin/contracts/math/SafeMath.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @dev Wrappers over Solidity's arithmetic operations with added overflow
       * checks.
       *
       * Arithmetic operations in Solidity wrap on overflow. This can easily result
       * in bugs, because programmers usually assume that an overflow raises an
       * error, which is the standard behavior in high level programming languages.
       * `SafeMath` restores this intuition by reverting the transaction when an
       * operation overflows.
       *
       * Using this library instead of the unchecked operations eliminates an entire
       * class of bugs, so it's recommended to use it always.
       */
      library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
              uint256 c = a + b;
              require(c >= a, "SafeMath: addition overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
              return sub(a, b, "SafeMath: subtraction overflow");
          }
      
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           *
           * _Available since v2.4.0._
           */
          function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b <= a, errorMessage);
              uint256 c = a - b;
      
              return c;
          }
      
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
              // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
              // benefit is lost if 'b' is also tested.
              // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
              if (a == 0) {
                  return 0;
              }
      
              uint256 c = a * b;
              require(c / a == b, "SafeMath: multiplication overflow");
      
              return c;
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
              return div(a, b, "SafeMath: division by zero");
          }
      
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           *
           * _Available since v2.4.0._
           */
          function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              // Solidity only automatically asserts when dividing by 0
              require(b > 0, errorMessage);
              uint256 c = a / b;
              // assert(a == b * c + a % b); // There is no case in which this doesn't hold
      
              return c;
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
              return mod(a, b, "SafeMath: modulo by zero");
          }
      
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           *
           * _Available since v2.4.0._
           */
          function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
              require(b != 0, errorMessage);
              return a % b;
          }
      }
      
      // File: @openzeppelin/contracts/GSN/Context.sol
      
      pragma solidity ^0.5.0;
      
      /*
       * @dev Provides information about the current execution context, including the
       * sender of the transaction and its data. While these are generally available
       * via msg.sender and msg.data, they should not be accessed in such a direct
       * manner, since when dealing with GSN meta-transactions the account sending and
       * paying for execution may not be the actual sender (as far as an application
       * is concerned).
       *
       * This contract is only required for intermediate, library-like contracts.
       */
      contract Context {
          // Empty internal constructor, to prevent people from mistakenly deploying
          // an instance of this contract, which should be used via inheritance.
          constructor () internal { }
          // solhint-disable-previous-line no-empty-blocks
      
          function _msgSender() internal view returns (address payable) {
              return msg.sender;
          }
      
          function _msgData() internal view returns (bytes memory) {
              this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
              return msg.data;
          }
      }
      
      // File: @openzeppelin/contracts/ownership/Ownable.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @dev Contract module which provides a basic access control mechanism, where
       * there is an account (an owner) that can be granted exclusive access to
       * specific functions.
       *
       * This module is used through inheritance. It will make available the modifier
       * `onlyOwner`, which can be applied to your functions to restrict their use to
       * the owner.
       */
      contract Ownable is Context {
          address private _owner;
      
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
      
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor () internal {
              _owner = _msgSender();
              emit OwnershipTransferred(address(0), _owner);
          }
      
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view returns (address) {
              return _owner;
          }
      
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
              require(isOwner(), "Ownable: caller is not the owner");
              _;
          }
      
          /**
           * @dev Returns true if the caller is the current owner.
           */
          function isOwner() public view returns (bool) {
              return _msgSender() == _owner;
          }
      
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public onlyOwner {
              emit OwnershipTransferred(_owner, address(0));
              _owner = address(0);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public onlyOwner {
              _transferOwnership(newOwner);
          }
      
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           */
          function _transferOwnership(address newOwner) internal {
              require(newOwner != address(0), "Ownable: new owner is the zero address");
              emit OwnershipTransferred(_owner, newOwner);
              _owner = newOwner;
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/IERC20.sol
      
      pragma solidity ^0.5.0;
      
      /**
       * @dev Interface of the ERC20 standard as defined in the EIP. Does not include
       * the optional functions; to access them see {ERC20Detailed}.
       */
      interface IERC20 {
          /**
           * @dev Returns the amount of tokens in existence.
           */
          function totalSupply() external view returns (uint256);
      
          /**
           * @dev Returns the amount of tokens owned by `account`.
           */
          function balanceOf(address account) external view returns (uint256);
      
          /**
           * @dev Moves `amount` tokens from the caller's account to `recipient`.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transfer(address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Returns the remaining number of tokens that `spender` will be
           * allowed to spend on behalf of `owner` through {transferFrom}. This is
           * zero by default.
           *
           * This value changes when {approve} or {transferFrom} are called.
           */
          function allowance(address owner, address spender) external view returns (uint256);
      
          /**
           * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * IMPORTANT: Beware that changing an allowance with this method brings the risk
           * that someone may use both the old and the new allowance by unfortunate
           * transaction ordering. One possible solution to mitigate this race
           * condition is to first reduce the spender's allowance to 0 and set the
           * desired value afterwards:
           * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
           *
           * Emits an {Approval} event.
           */
          function approve(address spender, uint256 amount) external returns (bool);
      
          /**
           * @dev Moves `amount` tokens from `sender` to `recipient` using the
           * allowance mechanism. `amount` is then deducted from the caller's
           * allowance.
           *
           * Returns a boolean value indicating whether the operation succeeded.
           *
           * Emits a {Transfer} event.
           */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
      
          /**
           * @dev Emitted when `value` tokens are moved from one account (`from`) to
           * another (`to`).
           *
           * Note that `value` may be zero.
           */
          event Transfer(address indexed from, address indexed to, uint256 value);
      
          /**
           * @dev Emitted when the allowance of a `spender` for an `owner` is set by
           * a call to {approve}. `value` is the new allowance.
           */
          event Approval(address indexed owner, address indexed spender, uint256 value);
      }
      
      // File: @openzeppelin/contracts/utils/Address.sol
      
      pragma solidity ^0.5.5;
      
      /**
       * @dev Collection of functions related to the address type
       */
      library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * This test is non-exhaustive, and there may be false-negatives: during the
           * execution of a contract's constructor, its address will be reported as
           * not containing a contract.
           *
           * IMPORTANT: It is unsafe to assume that an address for which this
           * function returns false is an externally-owned account (EOA) and not a
           * contract.
           */
          function isContract(address account) internal view returns (bool) {
              // This method relies in extcodesize, which returns 0 for contracts in
              // construction, since the code is only stored at the end of the
              // constructor execution.
      
              // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
              // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
              // for accounts without code, i.e. `keccak256('')`
              bytes32 codehash;
              bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
              // solhint-disable-next-line no-inline-assembly
              assembly { codehash := extcodehash(account) }
              return (codehash != 0x0 && codehash != accountHash);
          }
      
          /**
           * @dev Converts an `address` into `address payable`. Note that this is
           * simply a type cast: the actual underlying value is not changed.
           *
           * _Available since v2.4.0._
           */
          function toPayable(address account) internal pure returns (address payable) {
              return address(uint160(account));
          }
      
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           *
           * _Available since v2.4.0._
           */
          function sendValue(address payable recipient, uint256 amount) internal {
              require(address(this).balance >= amount, "Address: insufficient balance");
      
              // solhint-disable-next-line avoid-call-value
              (bool success, ) = recipient.call.value(amount)("");
              require(success, "Address: unable to send value, recipient may have reverted");
          }
      }
      
      // File: @openzeppelin/contracts/token/ERC20/SafeERC20.sol
      
      pragma solidity ^0.5.0;
      
      
      
      
      /**
       * @title SafeERC20
       * @dev Wrappers around ERC20 operations that throw on failure (when the token
       * contract returns false). Tokens that return no value (and instead revert or
       * throw on failure) are also supported, non-reverting calls are assumed to be
       * successful.
       * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
       * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
       */
      library SafeERC20 {
          using SafeMath for uint256;
          using Address for address;
      
          function safeTransfer(IERC20 token, address to, uint256 value) internal {
              callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
      
          function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
              callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
      
          function safeApprove(IERC20 token, address spender, uint256 value) internal {
              // safeApprove should only be called when setting an initial allowance,
              // or when resetting it to zero. To increase and decrease it, use
              // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
              // solhint-disable-next-line max-line-length
              require((value == 0) || (token.allowance(address(this), spender) == 0),
                  "SafeERC20: approve from non-zero to non-zero allowance"
              );
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
      
          function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 newAllowance = token.allowance(address(this), spender).add(value);
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
      
          function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
              uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
              callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
          }
      
          /**
           * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
           * on the return value: the return value is optional (but if data is returned, it must not be false).
           * @param token The token targeted by the call.
           * @param data The call data (encoded using abi.encode or one of its variants).
           */
          function callOptionalReturn(IERC20 token, bytes memory data) private {
              // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
              // we're implementing it ourselves.
      
              // A Solidity high level call has three parts:
              //  1. The target address is checked to verify it contains contract code
              //  2. The call itself is made, and success asserted
              //  3. The return value is decoded, which in turn checks the size of the returned data.
              // solhint-disable-next-line max-line-length
              require(address(token).isContract(), "SafeERC20: call to non-contract");
      
              // solhint-disable-next-line avoid-low-level-calls
              (bool success, bytes memory returndata) = address(token).call(data);
              require(success, "SafeERC20: low-level call failed");
      
              if (returndata.length > 0) { // Return data is optional
                  // solhint-disable-next-line max-line-length
                  require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
              }
          }
      }
      
      // File: contracts/IRewardDistributionRecipient.sol
      
      pragma solidity ^0.5.0;
      
      
      
      contract IRewardDistributionRecipient is Ownable {
          address rewardDistribution;
      
          function notifyRewardAmount(uint256 reward) external;
      
          modifier onlyRewardDistribution() {
              require(_msgSender() == rewardDistribution, "Caller is not reward distribution");
              _;
          }
      
          function setRewardDistribution(address _rewardDistribution)
              external
              onlyOwner
          {
              rewardDistribution = _rewardDistribution;
          }
      }
      
      // File: contracts/Unipool.sol
      
      pragma solidity ^0.5.0;
      
      
      
      
      
      
      contract LPTokenWrapper {
          using SafeMath for uint256;
          using SafeERC20 for IERC20;
      
          IERC20 public uni = IERC20(0xe9Cf7887b93150D4F2Da7dFc6D502B216438F244);
      
          uint256 private _totalSupply;
          mapping(address => uint256) private _balances;
      
          function totalSupply() public view returns (uint256) {
              return _totalSupply;
          }
      
          function balanceOf(address account) public view returns (uint256) {
              return _balances[account];
          }
      
          function stake(uint256 amount) public {
              _totalSupply = _totalSupply.add(amount);
              _balances[msg.sender] = _balances[msg.sender].add(amount);
              uni.safeTransferFrom(msg.sender, address(this), amount);
          }
      
          function withdraw(uint256 amount) public {
              _totalSupply = _totalSupply.sub(amount);
              _balances[msg.sender] = _balances[msg.sender].sub(amount);
              uni.safeTransfer(msg.sender, amount);
          }
      }
      
      contract Unipool is LPTokenWrapper, IRewardDistributionRecipient {
          IERC20 public snx = IERC20(0xC011a73ee8576Fb46F5E1c5751cA3B9Fe0af2a6F);
          uint256 public constant DURATION = 7 days;
      
          uint256 public periodFinish = 0;
          uint256 public rewardRate = 0;
          uint256 public lastUpdateTime;
          uint256 public rewardPerTokenStored;
          mapping(address => uint256) public userRewardPerTokenPaid;
          mapping(address => uint256) public rewards;
      
          event RewardAdded(uint256 reward);
          event Staked(address indexed user, uint256 amount);
          event Withdrawn(address indexed user, uint256 amount);
          event RewardPaid(address indexed user, uint256 reward);
      
          modifier updateReward(address account) {
              rewardPerTokenStored = rewardPerToken();
              lastUpdateTime = lastTimeRewardApplicable();
              if (account != address(0)) {
                  rewards[account] = earned(account);
                  userRewardPerTokenPaid[account] = rewardPerTokenStored;
              }
              _;
          }
      
          function lastTimeRewardApplicable() public view returns (uint256) {
              return Math.min(block.timestamp, periodFinish);
          }
      
          function rewardPerToken() public view returns (uint256) {
              if (totalSupply() == 0) {
                  return rewardPerTokenStored;
              }
              return
                  rewardPerTokenStored.add(
                      lastTimeRewardApplicable()
                          .sub(lastUpdateTime)
                          .mul(rewardRate)
                          .mul(1e18)
                          .div(totalSupply())
                  );
          }
      
          function earned(address account) public view returns (uint256) {
              return
                  balanceOf(account)
                      .mul(rewardPerToken().sub(userRewardPerTokenPaid[account]))
                      .div(1e18)
                      .add(rewards[account]);
          }
      
          // stake visibility is public as overriding LPTokenWrapper's stake() function
          function stake(uint256 amount) public updateReward(msg.sender) {
              require(amount > 0, "Cannot stake 0");
              super.stake(amount);
              emit Staked(msg.sender, amount);
          }
      
          function withdraw(uint256 amount) public updateReward(msg.sender) {
              require(amount > 0, "Cannot withdraw 0");
              super.withdraw(amount);
              emit Withdrawn(msg.sender, amount);
          }
      
          function exit() external {
              withdraw(balanceOf(msg.sender));
              getReward();
          }
      
          function getReward() public updateReward(msg.sender) {
              uint256 reward = earned(msg.sender);
              if (reward > 0) {
                  rewards[msg.sender] = 0;
                  snx.safeTransfer(msg.sender, reward);
                  emit RewardPaid(msg.sender, reward);
              }
          }
      
          function notifyRewardAmount(uint256 reward)
              external
              onlyRewardDistribution
              updateReward(address(0))
          {
              if (block.timestamp >= periodFinish) {
                  rewardRate = reward.div(DURATION);
              } else {
                  uint256 remaining = periodFinish.sub(block.timestamp);
                  uint256 leftover = remaining.mul(rewardRate);
                  rewardRate = reward.add(leftover).div(DURATION);
              }
              lastUpdateTime = block.timestamp;
              periodFinish = block.timestamp.add(DURATION);
              emit RewardAdded(reward);
          }
      }

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

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