ETH Price: $2,451.08 (+1.94%)

Transaction Decoder

Block:
19291372 at Feb-23-2024 04:06:11 PM +UTC
Transaction Fee:
0.02021317594928591 ETH $49.54
Gas Used:
271,703 Gas / 74.39437897 Gwei

Emitted Events:

179 0x1522900b6dafac587d499a862861c0869be6e428.0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0( 0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0, 0000000000000000000000009966b2af3a46a025bb712db91cf5c15a3af309fe, 000000000000000000000000000000000000000000000000018074268e304800, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )
180 Forwarder.ForwarderDeposited( from=[Receiver] 0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43, value=108214100000000000, data=0x )

Account State Difference:

  Address   Before After State Difference Code
0x062e7f29...Ff2FEb09B 0.007040418964291372 Eth0.012697128964291372 Eth0.00565671
0x0eC5372C...4f36A2A94 0.035544792343137273 Eth0.121639012343137273 Eth0.08609422
0x1118106C...2106df3e4 0.002764969380523054 Eth0.005039833 Eth0.002274863619476946
0x1522900B...69Be6E428
(Bitstamp 2)
984.882418251432595144 Eth984.990632351432595144 Eth0.1082141
0x1c11E2aC...f4e2d217d 0.021230329220568474 Eth0.072682829220568474 Eth0.0514525
0x2E9Cd177...5b60F0f0a 0.000408256303833 Eth0.137712896303833 Eth0.13730464
0x524307A6...75b0430a8 1.080593841124162311 Eth2.110593841124162311 Eth1.03
0x577f21a4...F473D1fA4 0.000000003156783646 Eth0.059987593156783646 Eth0.05998759
0x57DB5558...B625AE29F 0.007142598665533 Eth0.037856208665533 Eth0.03071361
0x684D8C6B...142bE0a75 0.0038896283874312 Eth0.009624046 Eth0.0057344176125688
0x6D1A2820...7ABf1Df48 0.00293769 Eth0.00890739 Eth0.0059697
0x73E4E272...72EeB3012 0.001039655735660308 Eth0.00499479125 Eth0.003955135514339692
0x7830c87C...31FA86F43
(Coinbase: Deposit)
24.967798618542600149 Eth
Nonce: 1258801
24.947585442593314239 Eth
Nonce: 1258802
0.02021317594928591
0x793E408f...424947570 0.000681940688478 Eth0.023447840688478 Eth0.0227659
0x8630c19e...a4C756064 0.36789004 Eth3.14061077 Eth2.77272073
0x89c50D41...F13Cad976 0.002905446715713046 Eth0.070804496715713046 Eth0.06789905
(beaverbuild)
5.986490762863081075 Eth5.986762465863081075 Eth0.000271703
0x972B9493...be7122DBA 0.000386541422043 Eth0.217887071422043 Eth0.21750053
0xa3151B6D...f11537b02 0 Eth0.0241448 Eth0.0241448
0xA9D1e08C...FB81d3E43
(Coinbase 10)
4,254.912310466567566559 Eth4,249.075307314396915198 Eth5.837003152170651361
0xB05DCBCB...E24f23814 0.003847079952101981 Eth0.044694369952101981 Eth0.04084729
0xbA142725...FDBCC8c98 0.309202575201277 Eth0.395121685201277 Eth0.08591911
0xc4067b2C...9c15d900F 0.000790192075734077 Eth0.0038783975 Eth0.003088205424265923
0xd096FF69...120E624D1 0.051765820903933295 Eth1.093745890903933295 Eth1.04198007
0xeb70Fcd2...5527852Ef 0.016637967738372628 Eth0.049417947738372628 Eth0.03277998

Execution Trace

Coinbase 10.1a1da075( )
  • ETH 0.002274863619476946 0x1118106ca3333be48f2761b210321dc2106df3e4.CALL( )
  • ETH 0.003088205424265923 0xc4067b2c6ce55c3e216c76bec22bf629c15d900f.CALL( )
  • ETH 0.003955135514339692 0x73e4e2726c688a09af7e72107ee92a372eeb3012.CALL( )
  • ETH 0.00565671 0x062e7f2992c23d916bbc956efabea8aff2feb09b.CALL( )
  • ETH 0.0057344176125688 0x684d8c6b581ca0d99068550a9662d51142be0a75.CALL( )
  • ETH 0.0059697 0x6d1a28208ca17a054f2a77fbdd5343b7abf1df48.CALL( )
  • ETH 0.0227659 0x793e408fc5a2ac78a90164128cb4d91424947570.CALL( )
  • ETH 0.0241448 0xa3151b6da12da5eae774ae3b3fa7fe7f11537b02.CALL( )
  • ETH 0.03071361 0x57db55585597d719728eec3fb82f7ffb625ae29f.CALL( )
  • ETH 0.03277998 0xeb70fcd28b354d93cfd0dd724a4ad425527852ef.CALL( )
  • ETH 0.04084729 0xb05dcbcbfa66acb88d82890bdef7e18e24f23814.CALL( )
  • ETH 0.0514525 0x1c11e2ac310f5975bdc9fa06919ceeff4e2d217d.CALL( )
  • ETH 0.05998759 0x577f21a46cb3843e1e65290e73d0fa6f473d1fa4.CALL( )
  • ETH 0.06789905 0x89c50d41bef923cc949051e1358d67bf13cad976.CALL( )
  • ETH 0.08591911 0xba142725be9b67218f4c8d4257b54a7fdbcc8c98.CALL( )
  • ETH 0.08609422 0x0ec5372c7e10d9cdb03f4ec57cc09974f36a2a94.CALL( )
  • ETH 0.1082141 Forwarder.CALL( )
    • ETH 0.1082141 Bitstamp 2.CALL( )
    • ETH 0.13730464 0x2e9cd1774b4031afe6fdc2b010665635b60f0f0a.CALL( )
    • ETH 0.21750053 0x972b9493d3d8a746e94593ae3d4d113be7122dba.CALL( )
    • ETH 1.03 0x524307a62ff6fcb920618082aaacf1c75b0430a8.CALL( )
    • ETH 1.04198007 0xd096ff693d346706120b279c4fafa88120e624d1.CALL( )
    • ETH 2.77272073 0x8630c19ec4233ea9a1470dcbda60cdca4c756064.CALL( )
      File 1 of 2: 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 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;
        }
      }