ETH Price: $3,012.22 (+2.56%)

Transaction Decoder

Block:
21093713 at Nov-01-2024 03:32:11 PM +UTC
Transaction Fee:
0.004254581996067468 ETH $12.82
Gas Used:
284,674 Gas / 14.945453382 Gwei

Emitted Events:

211 0x1522900b6dafac587d499a862861c0869be6e428.0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0( 0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0, 0000000000000000000000006634e1110433998296ee8767e2899f71224ad053, 00000000000000000000000000000000000000000000000000090a76c3ee7800, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )
212 0x6634e1110433998296ee8767e2899f71224ad053.0x69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b( 0x69b31548dea9b3b707b4dff357d326e3e9348b24e7a6080a218a6edeeec48f9b, 000000000000000000000000a9d1e08c7793af67e9d92fe308d5697fb81d3e43, 00000000000000000000000000000000000000000000000000090a76c3ee7800, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x04b6f084...f5ea13DDd 0.008512557421595997 Eth0.028181997421595997 Eth0.01966944
0x1522900B...69Be6E428
(Bitstamp 2)
31.756469373333872143 Eth31.759014153333872143 Eth0.00254478
0x2809F5F9...B82a8111B 0.419369550327544994 Eth0.425023630327544994 Eth0.00565408
0x2C927063...8E12dba26 0.004787431727100472 Eth0.006439731727100472 Eth0.0016523
0x316b4fFb...15E285a0d 0.0136927551770412 Eth0.5797873551770412 Eth0.5660946
0x36829772...07737aBf1 0.004030674643899816 Eth0.054926314643899816 Eth0.05089564
0x3A4982fC...07Dc197FB 0.03557791 Eth0.0715711 Eth0.03599319
0x3b48056F...DD937B72e 0.0272425 Eth0.05438632 Eth0.02714382
0x4608B82d...0b9fd9028 0.000622225773328604 Eth0.008399085773328604 Eth0.00777686
(Titan Builder)
5.254249219746089073 Eth5.254533893746089073 Eth0.000284674
0x562E528E...D88Cced1C 0.00120114943173232 Eth0.00283312943173232 Eth0.00163198
0x62a2a6cc...e8BB6A153 0.007022016976765 Eth0.049580376976765 Eth0.04255836
0x6Ad820c2...E3a5221b5 0.242516640084391485 Eth0.471262290084391485 Eth0.22874565
0x6fFeE02A...B88e8D682 0.00000775790652 Eth0.08743896790652 Eth0.08743121
0x72dB9d90...5F259802e 0.068912156689856014 Eth0.117550806689856014 Eth0.04863865
0x7830c87C...31FA86F43
(Coinbase: Deposit)
97.868541031827097998 Eth
Nonce: 1850565
97.86428644983103053 Eth
Nonce: 1850566
0.004254581996067468
0x7eF7513e...1A5a041Ae 0.006965407510816577 Eth0.015824817510816577 Eth0.00885941
0xA06aD3B8...9e16C2097 0.001038540639949948 Eth0.0012770375 Eth0.000238496860050052
0xA72c247F...58709BdF4 0.10004256 Eth0.12130479 Eth0.02126223
0xA9D1e08C...FB81d3E43
(Coinbase 10)
1,819.723761857186549986 Eth1,809.594764180326499934 Eth10.128997676860050052
0xB885c15F...5c5B0cDF3 0.01176394 Eth0.02158427 Eth0.00982033
0xc918a926...961311b31 0.000092238049659 Eth0.008640108049659 Eth0.00854787
0xCb2dbBC0...c756B0357 0.00844651 Eth0.012611 Eth0.00416449
0xD8A02BCB...80A9927bD 0.19161221 Eth0.20997683 Eth0.01836462
0xEA00230a...27Df85e23 0.05715461 Eth0.06873728 Eth0.01158267
0xf584F872...e9172D621
(Jump Trading)
21,487.160636839289043233 Eth21,496.080363839289043233 Eth8.919727

Execution Trace

Coinbase 10.1a1da075( )
  • ETH 0.00254478 0x6634e1110433998296ee8767e2899f71224ad053.CALL( )
    • ETH 0.00254478 Forwarder.DELEGATECALL( )
      • ETH 0.00254478 Bitstamp 2.CALL( )
      • ETH 0.05089564 0x36829772609b241d12424d19ed63f3707737abf1.CALL( )
      • ETH 0.04255836 0x62a2a6ccaed9538b5666e55c9c79dc1e8bb6a153.CALL( )
      • ETH 0.00777686 0x4608b82d2ca2523085b0f9e8760d1c00b9fd9028.CALL( )
      • ETH 0.00163198 0x562e528ec8b754c02b273a96b24eb20d88cced1c.CALL( )
      • ETH 0.03599319 0x3a4982fce804fc26edde987652024ad07dc197fb.CALL( )
      • ETH 0.00854787 0xc918a926c93a841f484cdfa53a14c61961311b31.CALL( )
      • ETH 0.01836462 0xd8a02bcbb68ced953bf519f2f61dc3580a9927bd.CALL( )
      • ETH 0.00982033 0xb885c15ff6cbad38e0398a9b3dc8dd85c5b0cdf3.CALL( )
      • ETH 0.000238496860050052 0xa06ad3b8a604b121c68a881da8e03be9e16c2097.CALL( )
      • ETH 0.01158267 0xea00230a8e842f299e4e456531e1d4b27df85e23.CALL( )
      • ETH 0.00565408 0x2809f5f989fe30256ca365d00c708bfb82a8111b.CALL( )
      • ETH 0.08743121 0x6ffee02ac255bb0ea187075e2c03ca8b88e8d682.CALL( )
      • ETH 0.0016523 0x2c927063313c6051a86a1cda691d51b8e12dba26.CALL( )
      • ETH 0.02714382 0x3b48056f9f9af7a3e8c8bae4eedc155dd937b72e.CALL( )
      • ETH 0.04863865 0x72db9d90792d12f2b21dab40952a9405f259802e.CALL( )
      • ETH 0.00416449 0xcb2dbbc0a5909b1e4dfa958d05f8515c756b0357.CALL( )
      • ETH 0.5660946 0x316b4ffb5dbda5b1dd88ca0d35b6a9e15e285a0d.CALL( )
      • ETH 0.01966944 0x04b6f084902108d4d1b8fa1f06db82af5ea13ddd.CALL( )
      • ETH 8.919727 Jump Trading.CALL( )
      • ETH 0.22874565 0x6ad820c24ac40620e4d07ff5ae43fa1e3a5221b5.CALL( )
      • ETH 0.02126223 0xa72c247f6a05e03ffc804b0b030b80858709bdf4.CALL( )
      • ETH 0.00885941 0x7ef7513eddc06141a58c94e1a4737d31a5a041ae.CALL( )
        File 1 of 2: Forwarder
        pragma solidity 0.7.5;
        
        /*
            The MIT License (MIT)
            Copyright (c) 2018 Murray Software, LLC.
            Permission is hereby granted, free of charge, to any person obtaining
            a copy of this software and associated documentation files (the
            "Software"), to deal in the Software without restriction, including
            without limitation the rights to use, copy, modify, merge, publish,
            distribute, sublicense, and/or sell copies of the Software, and to
            permit persons to whom the Software is furnished to do so, subject to
            the following conditions:
            The above copyright notice and this permission notice shall be included
            in all copies or substantial portions of the Software.
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
            OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
            MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
            IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
            CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
            TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
            SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
        */
        //solhint-disable max-line-length
        //solhint-disable no-inline-assembly
        
        contract CloneFactory {
          function createClone(address target, bytes32 salt)
            internal
            returns (address payable result)
          {
            bytes20 targetBytes = bytes20(target);
            assembly {
              // load the next free memory slot as a place to store the clone contract data
              let clone := mload(0x40)
        
              // The bytecode block below is responsible for contract initialization
              // during deployment, it is worth noting the proxied contract constructor will not be called during
              // the cloning procedure and that is why an initialization function needs to be called after the
              // clone is created
              mstore(
                clone,
                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
              )
        
              // This stores the address location of the implementation contract
              // so that the proxy knows where to delegate call logic to
              mstore(add(clone, 0x14), targetBytes)
        
              // The bytecode block is the actual code that is deployed for each clone created.
              // It forwards all calls to the already deployed implementation via a delegatecall
              mstore(
                add(clone, 0x28),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
              )
        
              // deploy the contract using the CREATE2 opcode
              // this deploys the minimal proxy defined above, which will proxy all
              // calls to use the logic defined in the implementation contract `target`
              result := create2(0, clone, 0x37, salt)
            }
          }
        
          function isClone(address target, address query)
            internal
            view
            returns (bool result)
          {
            bytes20 targetBytes = bytes20(target);
            assembly {
              // load the next free memory slot as a place to store the comparison clone
              let clone := mload(0x40)
        
              // The next three lines store the expected bytecode for a miniml proxy
              // that targets `target` as its implementation contract
              mstore(
                clone,
                0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
              )
              mstore(add(clone, 0xa), targetBytes)
              mstore(
                add(clone, 0x1e),
                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
              )
        
              // the next two lines store the bytecode of the contract that we are checking in memory
              let other := add(clone, 0x40)
              extcodecopy(query, other, 0, 0x2d)
        
              // Check if the expected bytecode equals the actual bytecode and return the result
              result := and(
                eq(mload(clone), mload(other)),
                eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
              )
            }
          }
        }
        
        
        /**
         * Contract that exposes the needed erc20 token functions
         */
        
        abstract contract ERC20Interface {
          // Send _value amount of tokens to address _to
          function transfer(address _to, uint256 _value)
            public
            virtual
            returns (bool success);
        
          // Get the account balance of another account with address _owner
          function balanceOf(address _owner)
            public
            virtual
            view
            returns (uint256 balance);
        }
        
        // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
        library TransferHelper {
            function safeApprove(
                address token,
                address to,
                uint256 value
            ) internal {
                // bytes4(keccak256(bytes('approve(address,uint256)')));
                (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
                require(
                    success && (data.length == 0 || abi.decode(data, (bool))),
                    'TransferHelper::safeApprove: approve failed'
                );
            }
        
            function safeTransfer(
                address token,
                address to,
                uint256 value
            ) internal {
                // bytes4(keccak256(bytes('transfer(address,uint256)')));
                (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
                require(
                    success && (data.length == 0 || abi.decode(data, (bool))),
                    'TransferHelper::safeTransfer: transfer failed'
                );
            }
        
            function safeTransferFrom(
                address token,
                address from,
                address to,
                uint256 value
            ) internal {
                // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
                (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
                require(
                    success && (data.length == 0 || abi.decode(data, (bool))),
                    'TransferHelper::transferFrom: transferFrom failed'
                );
            }
        
            function safeTransferETH(address to, uint256 value) internal {
                (bool success, ) = to.call{value: value}(new bytes(0));
                require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
            }
        }
        
        
        /**
         * Contract that will forward any incoming Ether to the creator of the contract
         *
         */
        contract Forwarder {
          // Address to which any funds sent to this contract will be forwarded
          address public parentAddress;
          event ForwarderDeposited(address from, uint256 value, bytes data);
        
          /**
           * Initialize the contract, and sets the destination address to that of the creator
           */
          function init(address _parentAddress) external onlyUninitialized {
            parentAddress = _parentAddress;
            uint256 value = address(this).balance;
        
            if (value == 0) {
              return;
            }
        
            (bool success, ) = parentAddress.call{ value: value }('');
            require(success, 'Flush failed');
            // NOTE: since we are forwarding on initialization,
            // we don't have the context of the original sender.
            // We still emit an event about the forwarding but set
            // the sender to the forwarder itself
            emit ForwarderDeposited(address(this), value, msg.data);
          }
        
          /**
           * Modifier that will execute internal code block only if the sender is the parent address
           */
          modifier onlyParent {
            require(msg.sender == parentAddress, 'Only Parent');
            _;
          }
        
          /**
           * Modifier that will execute internal code block only if the contract has not been initialized yet
           */
          modifier onlyUninitialized {
            require(parentAddress == address(0x0), 'Already initialized');
            _;
          }
        
          /**
           * Default function; Gets called when data is sent but does not match any other function
           */
          fallback() external payable {
            flush();
          }
        
          /**
           * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
           */
          receive() external payable {
            flush();
          }
        
          /**
           * Execute a token transfer of the full balance from the forwarder token to the parent address
           * @param tokenContractAddress the address of the erc20 token contract
           */
          function flushTokens(address tokenContractAddress) external onlyParent {
            ERC20Interface instance = ERC20Interface(tokenContractAddress);
            address forwarderAddress = address(this);
            uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
            if (forwarderBalance == 0) {
              return;
            }
        
            TransferHelper.safeTransfer(
              tokenContractAddress,
              parentAddress,
              forwarderBalance
            );
          }
        
          /**
           * Flush the entire balance of the contract to the parent address.
           */
          function flush() public {
            uint256 value = address(this).balance;
        
            if (value == 0) {
              return;
            }
        
            (bool success, ) = parentAddress.call{ value: value }('');
            require(success, 'Flush failed');
            emit ForwarderDeposited(msg.sender, value, msg.data);
          }
        }
        
        contract ForwarderFactory is CloneFactory {
          address public implementationAddress;
        
          event ForwarderCreated(address newForwarderAddress, address parentAddress);
        
          constructor(address _implementationAddress) {
            implementationAddress = _implementationAddress;
          }
        
          function createForwarder(address parent, bytes32 salt) external {
            // include the signers in the salt so any contract deployed to a given address must have the same signers
            bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt));
        
            address payable clone = createClone(implementationAddress, finalSalt);
            Forwarder(clone).init(parent);
            emit ForwarderCreated(clone, parent);
          }
        }

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