ETH Price: $2,551.80 (+1.02%)

Transaction Decoder

Block:
20589440 at Aug-23-2024 06:13:11 AM +UTC
Transaction Fee:
0.00006148990900332 ETH $0.16
Gas Used:
66,648 Gas / 0.922606965 Gwei

Emitted Events:

403 TetherToken.Transfer( from=Forwarder, to=[Receiver] 0x1522900b6dafac587d499a862861c0869be6e428, value=32243778500 )
404 Forwarder.TokensFlushed( tokenContractAddress=[Receiver] TetherToken, value=32243778500 )

Account State Difference:

  Address   Before After State Difference Code
0x00BDb569...b9Ae374eD
(Bitstamp 1)
63.137742928968104232 Eth
Nonce: 1921870
63.137681439059100912 Eth
Nonce: 1921871
0.00006148990900332
0xdAC17F95...13D831ec7
(Flashbots: Builder 2)
10.039172968199146315 Eth10.039180049882053075 Eth0.00000708168290676

Execution Trace

Bitstamp 2.2da03409( )
  • WalletSimple.flushForwarderTokens( forwarderAddress=0x392FA185fc9DAb7B699023abcD5dF28b282B1987, tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
    • Forwarder.flushTokens( tokenContractAddress=0xdAC17F958D2ee523a2206206994597C13D831ec7 )
      • TetherToken.balanceOf( who=0x392FA185fc9DAb7B699023abcD5dF28b282B1987 ) => ( 32243778500 )
      • TetherToken.transfer( _to=0x1522900B6daFac587d499a862861C0869Be6E428, _value=32243778500 )
        flushForwarderTokens[WalletSimple (ln:215)]
        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: TetherToken
        pragma solidity ^0.4.17;
        
        /**
         * @title SafeMath
         * @dev Math operations with safety checks that throw on error
         */
        library SafeMath {
            function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                if (a == 0) {
                    return 0;
                }
                uint256 c = a * b;
                assert(c / a == b);
                return c;
            }
        
            function div(uint256 a, uint256 b) internal pure returns (uint256) {
                // assert(b > 0); // Solidity automatically throws when dividing by 0
                uint256 c = a / b;
                // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                return c;
            }
        
            function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                assert(b <= a);
                return a - b;
            }
        
            function add(uint256 a, uint256 b) internal pure returns (uint256) {
                uint256 c = a + b;
                assert(c >= a);
                return c;
            }
        }
        
        /**
         * @title Ownable
         * @dev The Ownable contract has an owner address, and provides basic authorization control
         * functions, this simplifies the implementation of "user permissions".
         */
        contract Ownable {
            address public owner;
        
            /**
              * @dev The Ownable constructor sets the original `owner` of the contract to the sender
              * account.
              */
            function Ownable() public {
                owner = msg.sender;
            }
        
            /**
              * @dev Throws if called by any account other than the owner.
              */
            modifier onlyOwner() {
                require(msg.sender == owner);
                _;
            }
        
            /**
            * @dev Allows the current owner to transfer control of the contract to a newOwner.
            * @param newOwner The address to transfer ownership to.
            */
            function transferOwnership(address newOwner) public onlyOwner {
                if (newOwner != address(0)) {
                    owner = newOwner;
                }
            }
        
        }
        
        /**
         * @title ERC20Basic
         * @dev Simpler version of ERC20 interface
         * @dev see https://github.com/ethereum/EIPs/issues/20
         */
        contract ERC20Basic {
            uint public _totalSupply;
            function totalSupply() public constant returns (uint);
            function balanceOf(address who) public constant returns (uint);
            function transfer(address to, uint value) public;
            event Transfer(address indexed from, address indexed to, uint value);
        }
        
        /**
         * @title ERC20 interface
         * @dev see https://github.com/ethereum/EIPs/issues/20
         */
        contract ERC20 is ERC20Basic {
            function allowance(address owner, address spender) public constant returns (uint);
            function transferFrom(address from, address to, uint value) public;
            function approve(address spender, uint value) public;
            event Approval(address indexed owner, address indexed spender, uint value);
        }
        
        /**
         * @title Basic token
         * @dev Basic version of StandardToken, with no allowances.
         */
        contract BasicToken is Ownable, ERC20Basic {
            using SafeMath for uint;
        
            mapping(address => uint) public balances;
        
            // additional variables for use if transaction fees ever became necessary
            uint public basisPointsRate = 0;
            uint public maximumFee = 0;
        
            /**
            * @dev Fix for the ERC20 short address attack.
            */
            modifier onlyPayloadSize(uint size) {
                require(!(msg.data.length < size + 4));
                _;
            }
        
            /**
            * @dev transfer token for a specified address
            * @param _to The address to transfer to.
            * @param _value The amount to be transferred.
            */
            function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                uint fee = (_value.mul(basisPointsRate)).div(10000);
                if (fee > maximumFee) {
                    fee = maximumFee;
                }
                uint sendAmount = _value.sub(fee);
                balances[msg.sender] = balances[msg.sender].sub(_value);
                balances[_to] = balances[_to].add(sendAmount);
                if (fee > 0) {
                    balances[owner] = balances[owner].add(fee);
                    Transfer(msg.sender, owner, fee);
                }
                Transfer(msg.sender, _to, sendAmount);
            }
        
            /**
            * @dev Gets the balance of the specified address.
            * @param _owner The address to query the the balance of.
            * @return An uint representing the amount owned by the passed address.
            */
            function balanceOf(address _owner) public constant returns (uint balance) {
                return balances[_owner];
            }
        
        }
        
        /**
         * @title Standard ERC20 token
         *
         * @dev Implementation of the basic standard token.
         * @dev https://github.com/ethereum/EIPs/issues/20
         * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
         */
        contract StandardToken is BasicToken, ERC20 {
        
            mapping (address => mapping (address => uint)) public allowed;
        
            uint public constant MAX_UINT = 2**256 - 1;
        
            /**
            * @dev Transfer tokens from one address to another
            * @param _from address The address which you want to send tokens from
            * @param _to address The address which you want to transfer to
            * @param _value uint the amount of tokens to be transferred
            */
            function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                var _allowance = allowed[_from][msg.sender];
        
                // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                // if (_value > _allowance) throw;
        
                uint fee = (_value.mul(basisPointsRate)).div(10000);
                if (fee > maximumFee) {
                    fee = maximumFee;
                }
                if (_allowance < MAX_UINT) {
                    allowed[_from][msg.sender] = _allowance.sub(_value);
                }
                uint sendAmount = _value.sub(fee);
                balances[_from] = balances[_from].sub(_value);
                balances[_to] = balances[_to].add(sendAmount);
                if (fee > 0) {
                    balances[owner] = balances[owner].add(fee);
                    Transfer(_from, owner, fee);
                }
                Transfer(_from, _to, sendAmount);
            }
        
            /**
            * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
            * @param _spender The address which will spend the funds.
            * @param _value The amount of tokens to be spent.
            */
            function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
        
                // To change the approve amount you first have to reduce the addresses`
                //  allowance to zero by calling `approve(_spender, 0)` if it is not
                //  already 0 to mitigate the race condition described here:
                //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
        
                allowed[msg.sender][_spender] = _value;
                Approval(msg.sender, _spender, _value);
            }
        
            /**
            * @dev Function to check the amount of tokens than an owner allowed to a spender.
            * @param _owner address The address which owns the funds.
            * @param _spender address The address which will spend the funds.
            * @return A uint specifying the amount of tokens still available for the spender.
            */
            function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                return allowed[_owner][_spender];
            }
        
        }
        
        
        /**
         * @title Pausable
         * @dev Base contract which allows children to implement an emergency stop mechanism.
         */
        contract Pausable is Ownable {
          event Pause();
          event Unpause();
        
          bool public paused = false;
        
        
          /**
           * @dev Modifier to make a function callable only when the contract is not paused.
           */
          modifier whenNotPaused() {
            require(!paused);
            _;
          }
        
          /**
           * @dev Modifier to make a function callable only when the contract is paused.
           */
          modifier whenPaused() {
            require(paused);
            _;
          }
        
          /**
           * @dev called by the owner to pause, triggers stopped state
           */
          function pause() onlyOwner whenNotPaused public {
            paused = true;
            Pause();
          }
        
          /**
           * @dev called by the owner to unpause, returns to normal state
           */
          function unpause() onlyOwner whenPaused public {
            paused = false;
            Unpause();
          }
        }
        
        contract BlackList is Ownable, BasicToken {
        
            /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
            function getBlackListStatus(address _maker) external constant returns (bool) {
                return isBlackListed[_maker];
            }
        
            function getOwner() external constant returns (address) {
                return owner;
            }
        
            mapping (address => bool) public isBlackListed;
            
            function addBlackList (address _evilUser) public onlyOwner {
                isBlackListed[_evilUser] = true;
                AddedBlackList(_evilUser);
            }
        
            function removeBlackList (address _clearedUser) public onlyOwner {
                isBlackListed[_clearedUser] = false;
                RemovedBlackList(_clearedUser);
            }
        
            function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                require(isBlackListed[_blackListedUser]);
                uint dirtyFunds = balanceOf(_blackListedUser);
                balances[_blackListedUser] = 0;
                _totalSupply -= dirtyFunds;
                DestroyedBlackFunds(_blackListedUser, dirtyFunds);
            }
        
            event DestroyedBlackFunds(address _blackListedUser, uint _balance);
        
            event AddedBlackList(address _user);
        
            event RemovedBlackList(address _user);
        
        }
        
        contract UpgradedStandardToken is StandardToken{
            // those methods are called by the legacy contract
            // and they must ensure msg.sender to be the contract address
            function transferByLegacy(address from, address to, uint value) public;
            function transferFromByLegacy(address sender, address from, address spender, uint value) public;
            function approveByLegacy(address from, address spender, uint value) public;
        }
        
        contract TetherToken is Pausable, StandardToken, BlackList {
        
            string public name;
            string public symbol;
            uint public decimals;
            address public upgradedAddress;
            bool public deprecated;
        
            //  The contract can be initialized with a number of tokens
            //  All the tokens are deposited to the owner address
            //
            // @param _balance Initial supply of the contract
            // @param _name Token Name
            // @param _symbol Token symbol
            // @param _decimals Token decimals
            function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                _totalSupply = _initialSupply;
                name = _name;
                symbol = _symbol;
                decimals = _decimals;
                balances[owner] = _initialSupply;
                deprecated = false;
            }
        
            // Forward ERC20 methods to upgraded contract if this one is deprecated
            function transfer(address _to, uint _value) public whenNotPaused {
                require(!isBlackListed[msg.sender]);
                if (deprecated) {
                    return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                } else {
                    return super.transfer(_to, _value);
                }
            }
        
            // Forward ERC20 methods to upgraded contract if this one is deprecated
            function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                require(!isBlackListed[_from]);
                if (deprecated) {
                    return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                } else {
                    return super.transferFrom(_from, _to, _value);
                }
            }
        
            // Forward ERC20 methods to upgraded contract if this one is deprecated
            function balanceOf(address who) public constant returns (uint) {
                if (deprecated) {
                    return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                } else {
                    return super.balanceOf(who);
                }
            }
        
            // Forward ERC20 methods to upgraded contract if this one is deprecated
            function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                if (deprecated) {
                    return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                } else {
                    return super.approve(_spender, _value);
                }
            }
        
            // Forward ERC20 methods to upgraded contract if this one is deprecated
            function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                if (deprecated) {
                    return StandardToken(upgradedAddress).allowance(_owner, _spender);
                } else {
                    return super.allowance(_owner, _spender);
                }
            }
        
            // deprecate current contract in favour of a new one
            function deprecate(address _upgradedAddress) public onlyOwner {
                deprecated = true;
                upgradedAddress = _upgradedAddress;
                Deprecate(_upgradedAddress);
            }
        
            // deprecate current contract if favour of a new one
            function totalSupply() public constant returns (uint) {
                if (deprecated) {
                    return StandardToken(upgradedAddress).totalSupply();
                } else {
                    return _totalSupply;
                }
            }
        
            // Issue a new amount of tokens
            // these tokens are deposited into the owner address
            //
            // @param _amount Number of tokens to be issued
            function issue(uint amount) public onlyOwner {
                require(_totalSupply + amount > _totalSupply);
                require(balances[owner] + amount > balances[owner]);
        
                balances[owner] += amount;
                _totalSupply += amount;
                Issue(amount);
            }
        
            // Redeem tokens.
            // These tokens are withdrawn from the owner address
            // if the balance must be enough to cover the redeem
            // or the call will fail.
            // @param _amount Number of tokens to be issued
            function redeem(uint amount) public onlyOwner {
                require(_totalSupply >= amount);
                require(balances[owner] >= amount);
        
                _totalSupply -= amount;
                balances[owner] -= amount;
                Redeem(amount);
            }
        
            function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                // Ensure transparency by hardcoding limit beyond which fees can never be added
                require(newBasisPoints < 20);
                require(newMaxFee < 50);
        
                basisPointsRate = newBasisPoints;
                maximumFee = newMaxFee.mul(10**decimals);
        
                Params(basisPointsRate, maximumFee);
            }
        
            // Called when new token are issued
            event Issue(uint amount);
        
            // Called when tokens are redeemed
            event Redeem(uint amount);
        
            // Called when contract is deprecated
            event Deprecate(address newAddress);
        
            // Called if contract ever adds fees
            event Params(uint feeBasisPoints, uint maxFee);
        }

        File 3 of 3: WalletSimple
        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;
          }
        }