ETH Price: $1,805.89 (-0.39%)

Transaction Decoder

Block:
21763813 at Feb-03-2025 05:12:11 AM +UTC
Transaction Fee:
0.032526634991662316 ETH $58.74
Gas Used:
1,057,367 Gas / 30.761916148 Gwei

Emitted Events:

197 0x1522900b6dafac587d499a862861c0869be6e428.0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0( 0x6e89d517057028190560dd200cf6bf792842861353d1173761dfa362e1c133f0, 00000000000000000000000091db9e27e750c43a96926b2e04d795c24f13f67b, 00000000000000000000000000000000000000000000001d61bf3b971bc90000, 0000000000000000000000000000000000000000000000000000000000000060, 0000000000000000000000000000000000000000000000000000000000000000 )
198 Forwarder.ForwarderDeposited( from=[Receiver] 0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43, value=541998992000000000000, data=0x )

Account State Difference:

  Address   Before After State Difference Code
0x03aE1A79...A774B9D3e
(OKX 82)
1,123.980905015815974664 Eth1,690.979897015815974664 Eth566.998992
0x04ee9C7f...741c5795B 0.000067983846046947 Eth0.00168850875 Eth0.001620524903953053
0x058C9a19...f082f2A65
0 Eth
Nonce: 0
0.00168908775 Eth
Nonce: 0
0.00168908775From: 0 To: 0
0x0Bd0bCfC...18a64Da32
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0x11caB33a...54AEA4386
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0x1522900B...69Be6E428
(Bitstamp 2)
114.469977248832206855 Eth656.468969248832206855 Eth541.998992
0x181063e2...B6d280811 0.001250612800272 Eth0.001999896 Eth0.000749283199728
0x1BE62A05...83D963f35
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
0x28f12Ca7...85fA57D62
0 Eth
Nonce: 0
0.00168966675 Eth
Nonce: 0
0.00168966675From: 0 To: 0
0x31010E1f...236D7Fae2 10,831.7504113669811428 Eth11,118.8764624272538549 Eth287.1260510602727121
0x4369f0Ad...fB94D5813
0 Eth
Nonce: 0
0.00168966675 Eth
Nonce: 0
0.00168966675From: 0 To: 0
0x438f1936...0829c3d34
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0x5B27277D...015A495eD 10,831.7504113669811428 Eth11,118.8764624272538549 Eth287.1260510602727121
0x662EB93b...9610E1B75 0.008086164489797701 Eth0.029936424489797701 Eth0.02185026
0x6ad632Cd...788755745
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
0x6DC81B8a...DFbCa2156 0.000413996384249817 Eth0.00168966675 Eth0.001275670365750183
0x6E7E2912...a685965B9
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
0x75Ada0bd...6AE774EF1
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0x770196CF...A546F2a69
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
0x7830c87C...31FA86F43
(Coinbase: Deposit)
147.781910434585857355 Eth
Nonce: 2110642
147.749383799594195039 Eth
Nonce: 2110643
0.032526634991662316
0x7882d041...daCeEd0Be
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0x7d0Adfb8...69312a59E
0 Eth
Nonce: 0
0.00168966675 Eth
Nonce: 0
0.00168966675From: 0 To: 0
0x862B67ea...E968E39CC
0 Eth
Nonce: 0
0.001999298 Eth
Nonce: 0
0.001999298From: 0 To: 0
0x87cC4872...a744adf44 0.0006536403841232 Eth0.001696434 Eth0.0010427936158768
0x8D4635ab...477C56BFC 0.000118838339600832 Eth0.001999298 Eth0.001880459660399168
0x94BdEAA3...07f3C4f53
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
(beaverbuild)
5.886556903693169514 Eth5.887614270693169514 Eth0.001057367
0x994B2426...D3A8dAC89 10,831.7504113669811428 Eth11,118.8764624272538549 Eth287.1260510602727121
0x9979E109...285F632E6
0 Eth
Nonce: 0
0.00168908775 Eth
Nonce: 0
0.00168908775From: 0 To: 0
0x9C473E7E...A1cA89ef2 10,831.7504113669811428 Eth11,118.8764624272538549 Eth287.1260510602727121
0xA66145b7...f5D7F66F5 0.003746453010699 Eth0.075315173010699 Eth0.07156872
0xA6e71fD0...14e7cC958
0 Eth
Nonce: 0
0.001600294 Eth
Nonce: 0
0.001600294From: 0 To: 0
0xA7121cdF...E83C04c0c 10,831.7504113669811428 Eth11,118.8764624272538549 Eth287.1260510602727121
0xA9D1e08C...FB81d3E43
(Coinbase 10)
3,287.838930722754249136 Eth743.063519985097400722 Eth2,544.775410737656848414
0xB2bEB0a3...604D2b58B
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0xba5cfAeB...D33378e85
0 Eth
Nonce: 0
0.00168908775 Eth
Nonce: 0
0.00168908775From: 0 To: 0
0xbEb270Fc...bF0ffcD7a
0 Eth
Nonce: 0
0.00168908775 Eth
Nonce: 0
0.00168908775From: 0 To: 0
0xc0Ab2bC3...593E37515 0.001168227634757044 Eth0.001468441 Eth0.000300213365242956
0xc46C9083...C8d42E43e
0 Eth
Nonce: 0
0.002000448 Eth
Nonce: 0
0.002000448From: 0 To: 0
0xC8332131...D535563d6
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0xe94Bba1C...A44519471
0 Eth
Nonce: 0
0.001999896 Eth
Nonce: 0
0.001999896From: 0 To: 0
0xeB775BD5...51197Ab26 0.000232244817662246 Eth0.002000448 Eth0.001768203182337754
0xEBC986B7...4515080AA
0 Eth
Nonce: 0
0.00168850875 Eth
Nonce: 0
0.00168850875From: 0 To: 0

Execution Trace

Coinbase 10.1a1da075( )
  • ETH 566.998992 OKX 82.CALL( )
  • ETH 541.998992 Forwarder.CALL( )
    • ETH 541.998992 Bitstamp 2.CALL( )
    • ETH 287.1260510602727121 0x5b27277d1448c78e8fd0a707b8c375e015a495ed.CALL( )
    • ETH 287.1260510602727121 0xa7121cdf3ea0745bccf701055f3a69ce83c04c0c.CALL( )
    • ETH 287.1260510602727121 0x9c473e7e3d9a4b36d546ad362568b2da1ca89ef2.CALL( )
    • ETH 287.1260510602727121 0x31010e1f4236fcedc1dd91c1d168750236d7fae2.CALL( )
    • ETH 287.1260510602727121 0x994b242663b5d5769560677fb1b0a04d3a8dac89.CALL( )
    • ETH 0.0010427936158768 0x87cc4872725e3119b4e72d5417c6460a744adf44.CALL( )
    • ETH 0.001999896 0x11cab33af12088175b7d8d0e6aff56f54aea4386.CALL( )
    • ETH 0.001999896 0xe94bba1c0b8e9e1cb37f6bfcb1d0b52a44519471.CALL( )
    • ETH 0.001999896 0x438f193657612ab9bf4f642821a01cc0829c3d34.CALL( )
    • ETH 0.002000448 0x94bdeaa39e9d499fcea25f394f4261607f3c4f53.CALL( )
    • ETH 0.002000448 0x6e7e291220a353b256a4dd7f77a37aea685965b9.CALL( )
    • ETH 0.001999896 0x75ada0bd4b0fce9c11f44385917a9dc6ae774ef1.CALL( )
    • ETH 0.001999896 0xc8332131c505057359c69a476451005d535563d6.CALL( )
    • ETH 0.002000448 0x770196cf6bacd7a76fa8e1e54d65ac6a546f2a69.CALL( )
    • ETH 0.002000448 0x6ad632cdcacbc11756824cbe89c1310788755745.CALL( )
    • ETH 0.001999298 0x862b67eaf6c9f1e5ee3511852e4a206e968e39cc.CALL( )
    • ETH 0.001999896 0x7882d041c94c0960a0fec5767d462dddaceed0be.CALL( )
    • ETH 0.000749283199728 0x181063e20eb04becff98f791fa50b07b6d280811.CALL( )
    • ETH 0.002000448 0xc46c9083bbec66d204dc6c50783dfb7c8d42e43e.CALL( )
    • ETH 0.001999896 0x0bd0bcfc7dbf5b77f9242a883b9e8ac18a64da32.CALL( )
    • ETH 0.001768203182337754 0xeb775bd56e2cecedecf7bc00f05548a51197ab26.CALL( )
    • ETH 0.001999896 0xb2beb0a370310b35176b298982a4ed4604d2b58b.CALL( )
    • ETH 0.001880459660399168 0x8d4635abf104818fbafd37bc6da7ce8477c56bfc.CALL( )
    • ETH 0.002000448 0x1be62a05eb235662747cb6f6152472583d963f35.CALL( )
    • ETH 0.07156872 0xa66145b7f233cf3bfe3fc5a6a063375f5d7f66f5.CALL( )
    • ETH 0.02185026 0x662eb93b9577cf07f1a4c53026ee8ff9610e1b75.CALL( )
    • ETH 0.000300213365242956 0xc0ab2bc356276beea9b246e7375be67593e37515.CALL( )
    • ETH 0.001600294 0xa6e71fd036070175df808663058c35e14e7cc958.CALL( )
    • ETH 0.001620524903953053 0x04ee9c7f706401474e845a8712c4ea2741c5795b.CALL( )
    • ETH 0.00168966675 0x4369f0ad1038a2bfadde400676b8ea4fb94d5813.CALL( )
    • ETH 0.00168908775 0x058c9a190676fbded7d520b635a21fcf082f2a65.CALL( )
    • ETH 0.00168908775 0xbeb270fcd34e2df3ae679cfc5c1f744bf0ffcd7a.CALL( )
    • ETH 0.00168966675 0x28f12ca7c5cfeceda42bf624a4f80b585fa57d62.CALL( )
    • ETH 0.00168966675 0x7d0adfb88dd57aad70b2eefa2f0f0fd69312a59e.CALL( )
    • ETH 0.00168908775 0xba5cfaeba5500711845f4cd0df925b5d33378e85.CALL( )
    • ETH 0.001275670365750183 0x6dc81b8a27988f9a0e36441dc791a80dfbca2156.CALL( )
    • ETH 0.00168908775 0x9979e109626ee531c31e0e80fa3d5e1285f632e6.CALL( )
    • ETH 0.00168850875 0xebc986b7b49081ee3f31ffa844805514515080aa.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;
        }
      }