ETH Price: $2,508.92 (+0.91%)

Transaction Decoder

Block:
9080724 at Dec-10-2019 02:24:39 AM +UTC
Transaction Fee:
0.000424137 ETH $1.06
Gas Used:
60,591 Gas / 7 Gwei

Emitted Events:

28 DSToken.Transfer( from=[Receiver] Forwarder, to=[Sender] 0x2d9e7f7887bb496592430ef62400dd9007925b88, value=500000000000000000 )
29 Forwarder.0xcd60aa75dea3072fbc07ae6d7d856b5dc5f4eee88854f5b4abf7b680ef8bc50f( 0xcd60aa75dea3072fbc07ae6d7d856b5dc5f4eee88854f5b4abf7b680ef8bc50f, 0x0000000000000000000000002d9e7f7887bb496592430ef62400dd9007925b88, 0x00000000000000000000000000000000000000000000000017a195cfe4792e48, 0x00000000000000000000000000000000000000000000000006f05b59d3b20000 )

Account State Difference:

  Address   Before After State Difference Code
0x2C4Bd064...C2FA50957 9,769.836481491240622527 Eth9,771.539288345487296519 Eth1.702806854246673992
0x2d9E7f78...007925b88
4.954330091706603648 Eth
Nonce: 3971
3.251099100459929656 Eth
Nonce: 3972
1.703230991246673992
0x9f8F72aA...cC3A579A2
(Ethermine)
351.166061761518113103 Eth351.166485898518113103 Eth0.000424137

Execution Trace

ETH 1.719834922789140731 Forwarder.6b1d4db7( )
  • ETH 1.719834922789140731 Vyper_contract.ethToTokenSwapOutput( tokens_bought=500000000000000000, deadline=1575945572 ) => ( out=1702806854246673992 )
    • DSToken.balanceOf( src=0x2C4Bd064b998838076fa341A83d007FC2FA50957 ) => ( 2877876890868394004861 )
    • ETH 0.017028068542466739 0x2d9e7f7887bb496592430ef62400dd9007925b88.CALL( )
    • DSToken.transfer( dst=0x2d9E7f7887BB496592430ef62400dd9007925b88, wad=500000000000000000 ) => ( True )
      File 1 of 3: Forwarder
      pragma solidity ^0.4.14;
      
      /**
       * Contract that exposes the needed erc20 token functions
       */
      
      contract ERC20Interface {
        // Send _value amount of tokens to address _to
        function transfer(address _to, uint256 _value) returns (bool success);
        // Get the account balance of another account with address _owner
        function balanceOf(address _owner) constant returns (uint256 balance);
      }
      
      /**
       * Contract that will forward any incoming Ether to its creator
       */
      contract Forwarder {
        // Address to which any funds sent to this contract will be forwarded
        address public parentAddress;
        event ForwarderDeposited(address from, uint value, bytes data);
      
        event TokensFlushed(
          address tokenContractAddress, // The contract address of the token
          uint value // Amount of token sent
        );
      
        /**
         * Create the contract, and set the destination address to that of the creator
         */
        function Forwarder() {
          parentAddress = msg.sender;
        }
      
        /**
         * Modifier that will execute internal code block only if the sender is a parent of the forwarder contract
         */
        modifier onlyParent {
          if (msg.sender != parentAddress) {
            throw;
          }
          _;
        }
      
        /**
         * Default function; Gets called when Ether is deposited, and forwards it to the destination address
         */
        function() payable {
          if (!parentAddress.call.value(msg.value)(msg.data))
            throw;
          // Fire off the deposited event if we can forward it  
          ForwarderDeposited(msg.sender, msg.value, msg.data);
        }
      
        /**
         * Execute a token transfer of the full balance from the forwarder token to the main wallet contract
         * @param tokenContractAddress the address of the erc20 token contract
         */
        function flushTokens(address tokenContractAddress) onlyParent {
          ERC20Interface instance = ERC20Interface(tokenContractAddress);
          var forwarderAddress = address(this);
          var forwarderBalance = instance.balanceOf(forwarderAddress);
          if (forwarderBalance == 0) {
            return;
          }
          if (!instance.transfer(parentAddress, forwarderBalance)) {
            throw;
          }
          TokensFlushed(tokenContractAddress, forwarderBalance);
        }
      
        /**
         * It is possible that funds were sent to this address before the contract was deployed.
         * We can flush those funds to the destination address.
         */
        function flush() {
          if (!parentAddress.call.value(this.balance)())
            throw;
        }
      }
      
      /**
       * Basic multi-signer wallet designed for use in a co-signing environment where 2 signatures are required to move funds.
       * Typically used in a 2-of-3 signing configuration. Uses ecrecover to allow for 2 signatures in a single transaction.
       */
      contract WalletSimple {
        // Events
        event Deposited(address from, uint value, bytes data);
        event SafeModeActivated(address msgSender);
        event Transacted(
          address msgSender, // Address of the sender of the message initiating the transaction
          address otherSigner, // Address of the signer (second signature) used to initiate the transaction
          bytes32 operation, // Operation hash (sha3 of toAddress, value, data, expireTime, sequenceId)
          address toAddress, // The address the transaction was sent to
          uint value, // Amount of Wei sent to the address
          bytes data // Data sent when invoking the transaction
        );
        event TokenTransacted(
          address msgSender, // Address of the sender of the message initiating the transaction
          address otherSigner, // Address of the signer (second signature) used to initiate the transaction
          bytes32 operation, // Operation hash (sha3 of toAddress, value, tokenContractAddress, expireTime, sequenceId)
          address toAddress, // The address the transaction was sent to
          uint value, // Amount of token sent
          address tokenContractAddress // The contract address of the token
        );
      
        // Public fields
        address[] public signers; // The addresses that can co-sign transactions on the wallet
        bool public safeMode = false; // When active, wallet may only send to signer addresses
      
        // Internal fields
        uint constant SEQUENCE_ID_WINDOW_SIZE = 10;
        uint[10] recentSequenceIds;
      
        /**
         * Modifier that will execute internal code block only if the sender is an authorized signer on this wallet
         */
        modifier onlysigner {
          if (!isSigner(msg.sender)) {
            throw;
          }
          _;
        }
      
        /**
         * Set up a simple multi-sig wallet by specifying the signers allowed to be used on this wallet.
         * 2 signers will be required to send a transaction from this wallet.
         * Note: The sender is NOT automatically added to the list of signers.
         * Signers CANNOT be changed once they are set
         *
         * @param allowedSigners An array of signers on the wallet
         */
        function WalletSimple(address[] allowedSigners) {
          if (allowedSigners.length != 3) {
            // Invalid number of signers
            throw;
          }
          signers = allowedSigners;
        }
      
        /**
         * Gets called when a transaction is received without calling a method
         */
        function() payable {
          if (msg.value > 0) {
            // Fire deposited event if we are receiving funds
            Deposited(msg.sender, msg.value, msg.data);
          }
        }
      
        /**
         * Create a new contract (and also address) that forwards funds to this contract
         * returns address of newly created forwarder address
         */
        function createForwarder() onlysigner returns (address) {
          return new Forwarder();
        }
      
        /**
         * Execute a multi-signature transaction from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
         * The signature is a signed form (using eth.sign) of tightly packed toAddress, value, data, expireTime and sequenceId
         * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
         *
         * @param toAddress the destination address to send an outgoing transaction
         * @param value the amount in Wei to be sent
         * @param data the data to send to the toAddress when invoking the transaction
         * @param expireTime the number of seconds since 1970 for which this transaction is valid
         * @param sequenceId the unique sequence id obtainable from getNextSequenceId
         * @param signature the result of eth.sign on the operationHash sha3(toAddress, value, data, expireTime, sequenceId)
         */
        function sendMultiSig(address toAddress, uint value, bytes data, uint expireTime, uint sequenceId, bytes signature) onlysigner {
          // Verify the other signer
          var operationHash = sha3("ETHER", toAddress, value, data, expireTime, sequenceId);
          
          var otherSigner = verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
      
          // Success, send the transaction
          if (!(toAddress.call.value(value)(data))) {
            // Failed executing transaction
            throw;
          }
          Transacted(msg.sender, otherSigner, operationHash, toAddress, value, data);
        }
        
        /**
         * Execute a multi-signature token transfer from this wallet using 2 signers: one from msg.sender and the other from ecrecover.
         * The signature is a signed form (using eth.sign) of tightly packed toAddress, value, tokenContractAddress, expireTime and sequenceId
         * Sequence IDs are numbers starting from 1. They are used to prevent replay attacks and may not be repeated.
         *
         * @param toAddress the destination address to send an outgoing transaction
         * @param value the amount in tokens to be sent
         * @param tokenContractAddress the address of the erc20 token contract
         * @param expireTime the number of seconds since 1970 for which this transaction is valid
         * @param sequenceId the unique sequence id obtainable from getNextSequenceId
         * @param signature the result of eth.sign on the operationHash sha3(toAddress, value, tokenContractAddress, expireTime, sequenceId)
         */
        function sendMultiSigToken(address toAddress, uint value, address tokenContractAddress, uint expireTime, uint sequenceId, bytes signature) onlysigner {
          // Verify the other signer
          var operationHash = sha3("ERC20", toAddress, value, tokenContractAddress, expireTime, sequenceId);
          
          var otherSigner = verifyMultiSig(toAddress, operationHash, signature, expireTime, sequenceId);
          
          ERC20Interface instance = ERC20Interface(tokenContractAddress);
          if (!instance.transfer(toAddress, value)) {
              throw;
          }
          TokenTransacted(msg.sender, otherSigner, operationHash, toAddress, value, tokenContractAddress);
        }
      
        /**
         * Execute a token flush from one of the forwarder addresses. This transfer needs only a single signature and can be done by any signer
         *
         * @param forwarderAddress the address of the forwarder address to flush the tokens from
         * @param tokenContractAddress the address of the erc20 token contract
         */
        function flushForwarderTokens(address forwarderAddress, address tokenContractAddress) onlysigner {    
          Forwarder forwarder = Forwarder(forwarderAddress);
          forwarder.flushTokens(tokenContractAddress);
        }  
        
        /**
         * Do common multisig verification for both eth sends and erc20token transfers
         *
         * @param toAddress the destination address to send an outgoing transaction
         * @param operationHash the sha3 of the toAddress, value, data/tokenContractAddress and expireTime
         * @param signature the tightly packed signature of r, s, and v as an array of 65 bytes (returned by eth.sign)
         * @param expireTime the number of seconds since 1970 for which this transaction is valid
         * @param sequenceId the unique sequence id obtainable from getNextSequenceId
         * returns address of the address to send tokens or eth to
         */
        function verifyMultiSig(address toAddress, bytes32 operationHash, bytes signature, uint expireTime, uint sequenceId) private returns (address) {
      
          var otherSigner = recoverAddressFromSignature(operationHash, signature);
      
          // Verify if we are in safe mode. In safe mode, the wallet can only send to signers
          if (safeMode && !isSigner(toAddress)) {
            // We are in safe mode and the toAddress is not a signer. Disallow!
            throw;
          }
          // Verify that the transaction has not expired
          if (expireTime < block.timestamp) {
            // Transaction expired
            throw;
          }
      
          // Try to insert the sequence ID. Will throw if the sequence id was invalid
          tryInsertSequenceId(sequenceId);
      
          if (!isSigner(otherSigner)) {
            // Other signer not on this wallet or operation does not match arguments
            throw;
          }
          if (otherSigner == msg.sender) {
            // Cannot approve own transaction
            throw;
          }
      
          return otherSigner;
        }
      
        /**
         * Irrevocably puts contract into safe mode. When in this mode, transactions may only be sent to signing addresses.
         */
        function activateSafeMode() onlysigner {
          safeMode = true;
          SafeModeActivated(msg.sender);
        }
      
        /**
         * Determine if an address is a signer on this wallet
         * @param signer address to check
         * returns boolean indicating whether address is signer or not
         */
        function isSigner(address signer) returns (bool) {
          // Iterate through all signers on the wallet and
          for (uint i = 0; i < signers.length; i++) {
            if (signers[i] == signer) {
              return true;
            }
          }
          return false;
        }
      
        /**
         * Gets the second signer's address using ecrecover
         * @param operationHash the sha3 of the toAddress, value, data/tokenContractAddress and expireTime
         * @param signature the tightly packed signature of r, s, and v as an array of 65 bytes (returned by eth.sign)
         * returns address recovered from the signature
         */
        function recoverAddressFromSignature(bytes32 operationHash, bytes signature) private returns (address) {
          if (signature.length != 65) {
            throw;
          }
          // We need to unpack the signature, which is given as an array of 65 bytes (from eth.sign)
          bytes32 r;
          bytes32 s;
          uint8 v;
          assembly {
            r := mload(add(signature, 32))
            s := mload(add(signature, 64))
            v := and(mload(add(signature, 65)), 255)
          }
          if (v < 27) {
            v += 27; // Ethereum versions are 27 or 28 as opposed to 0 or 1 which is submitted by some signing libs
          }
          return ecrecover(operationHash, v, r, s);
        }
      
        /**
         * Verify that the sequence id has not been used before and inserts it. Throws if the sequence ID was not accepted.
         * We collect a window of up to 10 recent sequence ids, and allow any sequence id that is not in the window and
         * greater than the minimum element in the window.
         * @param sequenceId to insert into array of stored ids
         */
        function tryInsertSequenceId(uint sequenceId) onlysigner private {
          // Keep a pointer to the lowest value element in the window
          uint lowestValueIndex = 0;
          for (uint i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
            if (recentSequenceIds[i] == sequenceId) {
              // This sequence ID has been used before. Disallow!
              throw;
            }
            if (recentSequenceIds[i] < recentSequenceIds[lowestValueIndex]) {
              lowestValueIndex = i;
            }
          }
          if (sequenceId < recentSequenceIds[lowestValueIndex]) {
            // The sequence ID being used is lower than the lowest value in the window
            // so we cannot accept it as it may have been used before
            throw;
          }
          if (sequenceId > (recentSequenceIds[lowestValueIndex] + 10000)) {
            // Block sequence IDs which are much higher than the lowest value
            // This prevents people blocking the contract by using very large sequence IDs quickly
            throw;
          }
          recentSequenceIds[lowestValueIndex] = sequenceId;
        }
      
        /**
         * Gets the next available sequence ID for signing when using executeAndConfirm
         * returns the sequenceId one higher than the highest currently stored
         */
        function getNextSequenceId() returns (uint) {
          uint highestSequenceId = 0;
          for (uint i = 0; i < SEQUENCE_ID_WINDOW_SIZE; i++) {
            if (recentSequenceIds[i] > highestSequenceId) {
              highestSequenceId = recentSequenceIds[i];
            }
          }
          return highestSequenceId + 1;
        }
      }

      File 2 of 3: DSToken
      // MKR Token
      
      // hevm: flattened sources of src/mkr-499.sol
      pragma solidity ^0.4.15;
      
      ////// lib/ds-roles/lib/ds-auth/src/auth.sol
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      contract DSAuthority {
          function canCall(
              address src, address dst, bytes4 sig
          ) public view returns (bool);
      }
      
      contract DSAuthEvents {
          event LogSetAuthority (address indexed authority);
          event LogSetOwner     (address indexed owner);
      }
      
      contract DSAuth is DSAuthEvents {
          DSAuthority  public  authority;
          address      public  owner;
      
          function DSAuth() public {
              owner = msg.sender;
              LogSetOwner(msg.sender);
          }
      
          function setOwner(address owner_)
              public
              auth
          {
              owner = owner_;
              LogSetOwner(owner);
          }
      
          function setAuthority(DSAuthority authority_)
              public
              auth
          {
              authority = authority_;
              LogSetAuthority(authority);
          }
      
          modifier auth {
              require(isAuthorized(msg.sender, msg.sig));
              _;
          }
      
          function isAuthorized(address src, bytes4 sig) internal view returns (bool) {
              if (src == address(this)) {
                  return true;
              } else if (src == owner) {
                  return true;
              } else if (authority == DSAuthority(0)) {
                  return false;
              } else {
                  return authority.canCall(src, this, sig);
              }
          }
      }
      
      ////// lib/ds-thing/lib/ds-math/src/math.sol
      /// math.sol -- mixin for inline numerical wizardry
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      contract DSMath {
          function add(uint x, uint y) internal pure returns (uint z) {
              require((z = x + y) >= x);
          }
          function sub(uint x, uint y) internal pure returns (uint z) {
              require((z = x - y) <= x);
          }
          function mul(uint x, uint y) internal pure returns (uint z) {
              require(y == 0 || (z = x * y) / y == x);
          }
      
          function min(uint x, uint y) internal pure returns (uint z) {
              return x <= y ? x : y;
          }
          function max(uint x, uint y) internal pure returns (uint z) {
              return x >= y ? x : y;
          }
          function imin(int x, int y) internal pure returns (int z) {
              return x <= y ? x : y;
          }
          function imax(int x, int y) internal pure returns (int z) {
              return x >= y ? x : y;
          }
      
          uint constant WAD = 10 ** 18;
          uint constant RAY = 10 ** 27;
      
          function wmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), WAD / 2) / WAD;
          }
          function rmul(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, y), RAY / 2) / RAY;
          }
          function wdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, WAD), y / 2) / y;
          }
          function rdiv(uint x, uint y) internal pure returns (uint z) {
              z = add(mul(x, RAY), y / 2) / y;
          }
      
          // This famous algorithm is called "exponentiation by squaring"
          // and calculates x^n with x as fixed-point and n as regular unsigned.
          //
          // It's O(log n), instead of O(n) for naive repeated multiplication.
          //
          // These facts are why it works:
          //
          //  If n is even, then x^n = (x^2)^(n/2).
          //  If n is odd,  then x^n = x * x^(n-1),
          //   and applying the equation for even x gives
          //    x^n = x * (x^2)^((n-1) / 2).
          //
          //  Also, EVM division is flooring and
          //    floor[(n-1) / 2] = floor[n / 2].
          //
          function rpow(uint x, uint n) internal pure returns (uint z) {
              z = n % 2 != 0 ? x : RAY;
      
              for (n /= 2; n != 0; n /= 2) {
                  x = rmul(x, x);
      
                  if (n % 2 != 0) {
                      z = rmul(z, x);
                  }
              }
          }
      }
      
      ////// lib/ds-thing/lib/ds-note/src/note.sol
      /// note.sol -- the `note' modifier, for logging calls as events
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      contract DSNote {
          event LogNote(
              bytes4   indexed  sig,
              address  indexed  guy,
              bytes32  indexed  foo,
              bytes32  indexed  bar,
              uint              wad,
              bytes             fax
          ) anonymous;
      
          modifier note {
              bytes32 foo;
              bytes32 bar;
      
              assembly {
                  foo := calldataload(4)
                  bar := calldataload(36)
              }
      
              LogNote(msg.sig, msg.sender, foo, bar, msg.value, msg.data);
      
              _;
          }
      }
      
      ////// lib/ds-thing/src/thing.sol
      // thing.sol - `auth` with handy mixins. your things should be DSThings
      
      // Copyright (C) 2017  DappHub, LLC
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      /* import 'ds-auth/auth.sol'; */
      /* import 'ds-note/note.sol'; */
      /* import 'ds-math/math.sol'; */
      
      contract DSThing is DSAuth, DSNote, DSMath {
      }
      
      ////// lib/ds-token/lib/ds-stop/src/stop.sol
      /// stop.sol -- mixin for enable/disable functionality
      
      // Copyright (C) 2017  DappHub, LLC
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      /* import "ds-auth/auth.sol"; */
      /* import "ds-note/note.sol"; */
      
      contract DSStop is DSNote, DSAuth {
      
          bool public stopped;
      
          modifier stoppable {
              require(!stopped);
              _;
          }
          function stop() public auth note {
              stopped = true;
          }
          function start() public auth note {
              stopped = false;
          }
      
      }
      
      ////// lib/ds-token/lib/erc20/src/erc20.sol
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.8; */
      
      // Token standard API
      // https://github.com/ethereum/EIPs/issues/20
      
      contract ERC20 {
          function totalSupply() public view returns (uint supply);
          function balanceOf( address who ) public view returns (uint value);
          function allowance( address owner, address spender ) public view returns (uint _allowance);
      
          function transfer( address to, uint value) public returns (bool ok);
          function transferFrom( address from, address to, uint value) public returns (bool ok);
          function approve( address spender, uint value ) public returns (bool ok);
      
          event Transfer( address indexed from, address indexed to, uint value);
          event Approval( address indexed owner, address indexed spender, uint value);
      }
      
      ////// lib/ds-token/src/base.sol
      /// base.sol -- basic ERC20 implementation
      
      // Copyright (C) 2015, 2016, 2017  DappHub, LLC
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      /* import "erc20/erc20.sol"; */
      /* import "ds-math/math.sol"; */
      
      contract DSTokenBase is ERC20, DSMath {
          uint256                                            _supply;
          mapping (address => uint256)                       _balances;
          mapping (address => mapping (address => uint256))  _approvals;
      
          function DSTokenBase(uint supply) public {
              _balances[msg.sender] = supply;
              _supply = supply;
          }
      
          function totalSupply() public view returns (uint) {
              return _supply;
          }
          function balanceOf(address src) public view returns (uint) {
              return _balances[src];
          }
          function allowance(address src, address guy) public view returns (uint) {
              return _approvals[src][guy];
          }
      
          function transfer(address dst, uint wad) public returns (bool) {
              return transferFrom(msg.sender, dst, wad);
          }
      
          function transferFrom(address src, address dst, uint wad)
              public
              returns (bool)
          {
              if (src != msg.sender) {
                  _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
              }
      
              _balances[src] = sub(_balances[src], wad);
              _balances[dst] = add(_balances[dst], wad);
      
              Transfer(src, dst, wad);
      
              return true;
          }
      
          function approve(address guy, uint wad) public returns (bool) {
              _approvals[msg.sender][guy] = wad;
      
              Approval(msg.sender, guy, wad);
      
              return true;
          }
      }
      
      ////// lib/ds-token/src/token.sol
      /// token.sol -- ERC20 implementation with minting and burning
      
      // Copyright (C) 2015, 2016, 2017  DappHub, LLC
      
      // This program is free software: you can redistribute it and/or modify
      // it under the terms of the GNU General Public License as published by
      // the Free Software Foundation, either version 3 of the License, or
      // (at your option) any later version.
      
      // This program is distributed in the hope that it will be useful,
      // but WITHOUT ANY WARRANTY; without even the implied warranty of
      // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      // GNU General Public License for more details.
      
      // You should have received a copy of the GNU General Public License
      // along with this program.  If not, see <http://www.gnu.org/licenses/>.
      
      /* pragma solidity ^0.4.13; */
      
      /* import "ds-stop/stop.sol"; */
      
      /* import "./base.sol"; */
      
      contract DSToken is DSTokenBase(0), DSStop {
      
          bytes32  public  symbol;
          uint256  public  decimals = 18; // standard token precision. override to customize
      
          function DSToken(bytes32 symbol_) public {
              symbol = symbol_;
          }
      
          event Mint(address indexed guy, uint wad);
          event Burn(address indexed guy, uint wad);
      
          function approve(address guy) public stoppable returns (bool) {
              return super.approve(guy, uint(-1));
          }
      
          function approve(address guy, uint wad) public stoppable returns (bool) {
              return super.approve(guy, wad);
          }
      
          function transferFrom(address src, address dst, uint wad)
              public
              stoppable
              returns (bool)
          {
              if (src != msg.sender && _approvals[src][msg.sender] != uint(-1)) {
                  _approvals[src][msg.sender] = sub(_approvals[src][msg.sender], wad);
              }
      
              _balances[src] = sub(_balances[src], wad);
              _balances[dst] = add(_balances[dst], wad);
      
              Transfer(src, dst, wad);
      
              return true;
          }
      
          function push(address dst, uint wad) public {
              transferFrom(msg.sender, dst, wad);
          }
          function pull(address src, uint wad) public {
              transferFrom(src, msg.sender, wad);
          }
          function move(address src, address dst, uint wad) public {
              transferFrom(src, dst, wad);
          }
      
          function mint(uint wad) public {
              mint(msg.sender, wad);
          }
          function burn(uint wad) public {
              burn(msg.sender, wad);
          }
          function mint(address guy, uint wad) public auth stoppable {
              _balances[guy] = add(_balances[guy], wad);
              _supply = add(_supply, wad);
              Mint(guy, wad);
          }
          function burn(address guy, uint wad) public auth stoppable {
              if (guy != msg.sender && _approvals[guy][msg.sender] != uint(-1)) {
                  _approvals[guy][msg.sender] = sub(_approvals[guy][msg.sender], wad);
              }
      
              _balances[guy] = sub(_balances[guy], wad);
              _supply = sub(_supply, wad);
              Burn(guy, wad);
          }
      
          // Optional token name
          bytes32   public  name = "";
      
          function setName(bytes32 name_) public auth {
              name = name_;
          }
      }

      File 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]