ETH Price: $2,673.92 (+9.14%)

Transaction Decoder

Block:
5463680 at Apr-18-2018 05:03:07 PM +UTC
Transaction Fee:
0.00040828 ETH $1.09
Gas Used:
102,070 Gas / 4 Gwei

Emitted Events:

9 MultiSigWalletWithDailyLimit.Confirmation( sender=[Sender] 0x313de3ff48cb69ec56bea74e89b8485fdfba63db, transactionId=27 )
10 GnosisToken.Transfer( from=[Receiver] MultiSigWalletWithDailyLimit, to=UserWallet, value=735840000000000000000 )
11 MultiSigWalletWithDailyLimit.Execution( transactionId=27 )

Account State Difference:

  Address   Before After State Difference Code
0x313dE3fF...fDFBa63DB
0.037489622570964954 Eth
Nonce: 13
0.037081342570964954 Eth
Nonce: 14
0.00040828
0x31CbA7aD...5736a9615
(Nanopool)
5,363.788092873246732125 Eth5,363.788501153246732125 Eth0.00040828
0x6810e776...8e5386b96

Execution Trace

MultiSigWalletWithDailyLimit.confirmTransaction( transactionId=27 )
  • GnosisToken.transfer( _to=0x239D3f730ef7037EbD516f28De4119f9740379f4, _value=735840000000000000000 ) => ( True )
    File 1 of 3: MultiSigWalletWithDailyLimit
    pragma solidity 0.4.4;
    
    
    /// @title Multisignature wallet - Allows multiple parties to agree on transactions before execution.
    /// @author Stefan George - <[email protected]>
    contract MultiSigWallet {
    
        uint constant public MAX_OWNER_COUNT = 50;
    
        event Confirmation(address indexed sender, uint indexed transactionId);
        event Revocation(address indexed sender, uint indexed transactionId);
        event Submission(uint indexed transactionId);
        event Execution(uint indexed transactionId);
        event ExecutionFailure(uint indexed transactionId);
        event Deposit(address indexed sender, uint value);
        event OwnerAddition(address indexed owner);
        event OwnerRemoval(address indexed owner);
        event RequirementChange(uint required);
    
        mapping (uint => Transaction) public transactions;
        mapping (uint => mapping (address => bool)) public confirmations;
        mapping (address => bool) public isOwner;
        address[] public owners;
        uint public required;
        uint public transactionCount;
    
        struct Transaction {
            address destination;
            uint value;
            bytes data;
            bool executed;
        }
    
        modifier onlyWallet() {
            if (msg.sender != address(this))
                throw;
            _;
        }
    
        modifier ownerDoesNotExist(address owner) {
            if (isOwner[owner])
                throw;
            _;
        }
    
        modifier ownerExists(address owner) {
            if (!isOwner[owner])
                throw;
            _;
        }
    
        modifier transactionExists(uint transactionId) {
            if (transactions[transactionId].destination == 0)
                throw;
            _;
        }
    
        modifier confirmed(uint transactionId, address owner) {
            if (!confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notConfirmed(uint transactionId, address owner) {
            if (confirmations[transactionId][owner])
                throw;
            _;
        }
    
        modifier notExecuted(uint transactionId) {
            if (transactions[transactionId].executed)
                throw;
            _;
        }
    
        modifier notNull(address _address) {
            if (_address == 0)
                throw;
            _;
        }
    
        modifier validRequirement(uint ownerCount, uint _required) {
            if (   ownerCount > MAX_OWNER_COUNT
                || _required > ownerCount
                || _required == 0
                || ownerCount == 0)
                throw;
            _;
        }
    
        /// @dev Fallback function allows to deposit ether.
        function()
            payable
        {
            if (msg.value > 0)
                Deposit(msg.sender, msg.value);
        }
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners and required number of confirmations.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        function MultiSigWallet(address[] _owners, uint _required)
            public
            validRequirement(_owners.length, _required)
        {
            for (uint i=0; i<_owners.length; i++) {
                if (isOwner[_owners[i]] || _owners[i] == 0)
                    throw;
                isOwner[_owners[i]] = true;
            }
            owners = _owners;
            required = _required;
        }
    
        /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of new owner.
        function addOwner(address owner)
            public
            onlyWallet
            ownerDoesNotExist(owner)
            notNull(owner)
            validRequirement(owners.length + 1, required)
        {
            isOwner[owner] = true;
            owners.push(owner);
            OwnerAddition(owner);
        }
    
        /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner.
        function removeOwner(address owner)
            public
            onlyWallet
            ownerExists(owner)
        {
            isOwner[owner] = false;
            for (uint i=0; i<owners.length - 1; i++)
                if (owners[i] == owner) {
                    owners[i] = owners[owners.length - 1];
                    break;
                }
            owners.length -= 1;
            if (required > owners.length)
                changeRequirement(owners.length);
            OwnerRemoval(owner);
        }
    
        /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
        /// @param owner Address of owner to be replaced.
        /// @param owner Address of new owner.
        function replaceOwner(address owner, address newOwner)
            public
            onlyWallet
            ownerExists(owner)
            ownerDoesNotExist(newOwner)
        {
            for (uint i=0; i<owners.length; i++)
                if (owners[i] == owner) {
                    owners[i] = newOwner;
                    break;
                }
            isOwner[owner] = false;
            isOwner[newOwner] = true;
            OwnerRemoval(owner);
            OwnerAddition(newOwner);
        }
    
        /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
        /// @param _required Number of required confirmations.
        function changeRequirement(uint _required)
            public
            onlyWallet
            validRequirement(owners.length, _required)
        {
            required = _required;
            RequirementChange(_required);
        }
    
        /// @dev Allows an owner to submit and confirm a transaction.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function submitTransaction(address destination, uint value, bytes data)
            public
            returns (uint transactionId)
        {
            transactionId = addTransaction(destination, value, data);
            confirmTransaction(transactionId);
        }
    
        /// @dev Allows an owner to confirm a transaction.
        /// @param transactionId Transaction ID.
        function confirmTransaction(uint transactionId)
            public
            ownerExists(msg.sender)
            transactionExists(transactionId)
            notConfirmed(transactionId, msg.sender)
        {
            confirmations[transactionId][msg.sender] = true;
            Confirmation(msg.sender, transactionId);
            executeTransaction(transactionId);
        }
    
        /// @dev Allows an owner to revoke a confirmation for a transaction.
        /// @param transactionId Transaction ID.
        function revokeConfirmation(uint transactionId)
            public
            ownerExists(msg.sender)
            confirmed(transactionId, msg.sender)
            notExecuted(transactionId)
        {
            confirmations[transactionId][msg.sender] = false;
            Revocation(msg.sender, transactionId);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            notExecuted(transactionId)
        {
            if (isConfirmed(transactionId)) {
                Transaction tx = transactions[transactionId];
                tx.executed = true;
                if (tx.destination.call.value(tx.value)(tx.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    tx.executed = false;
                }
            }
        }
    
        /// @dev Returns the confirmation status of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Confirmation status.
        function isConfirmed(uint transactionId)
            public
            constant
            returns (bool)
        {
            uint count = 0;
            for (uint i=0; i<owners.length; i++) {
                if (confirmations[transactionId][owners[i]])
                    count += 1;
                if (count == required)
                    return true;
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
        /// @param destination Transaction target address.
        /// @param value Transaction ether value.
        /// @param data Transaction data payload.
        /// @return Returns transaction ID.
        function addTransaction(address destination, uint value, bytes data)
            internal
            notNull(destination)
            returns (uint transactionId)
        {
            transactionId = transactionCount;
            transactions[transactionId] = Transaction({
                destination: destination,
                value: value,
                data: data,
                executed: false
            });
            transactionCount += 1;
            Submission(transactionId);
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns number of confirmations of a transaction.
        /// @param transactionId Transaction ID.
        /// @return Number of confirmations.
        function getConfirmationCount(uint transactionId)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]])
                    count += 1;
        }
    
        /// @dev Returns total number of transactions after filers are applied.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Total number of transactions after filters are applied.
        function getTransactionCount(bool pending, bool executed)
            public
            constant
            returns (uint count)
        {
            for (uint i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                    count += 1;
        }
    
        /// @dev Returns list of owners.
        /// @return List of owner addresses.
        function getOwners()
            public
            constant
            returns (address[])
        {
            return owners;
        }
    
        /// @dev Returns array with owner addresses, which confirmed transaction.
        /// @param transactionId Transaction ID.
        /// @return Returns array of owner addresses.
        function getConfirmations(uint transactionId)
            public
            constant
            returns (address[] _confirmations)
        {
            address[] memory confirmationsTemp = new address[](owners.length);
            uint count = 0;
            uint i;
            for (i=0; i<owners.length; i++)
                if (confirmations[transactionId][owners[i]]) {
                    confirmationsTemp[count] = owners[i];
                    count += 1;
                }
            _confirmations = new address[](count);
            for (i=0; i<count; i++)
                _confirmations[i] = confirmationsTemp[i];
        }
    
        /// @dev Returns list of transaction IDs in defined range.
        /// @param from Index start position of transaction array.
        /// @param to Index end position of transaction array.
        /// @param pending Include pending transactions.
        /// @param executed Include executed transactions.
        /// @return Returns array of transaction IDs.
        function getTransactionIds(uint from, uint to, bool pending, bool executed)
            public
            constant
            returns (uint[] _transactionIds)
        {
            uint[] memory transactionIdsTemp = new uint[](transactionCount);
            uint count = 0;
            uint i;
            for (i=0; i<transactionCount; i++)
                if (   pending && !transactions[i].executed
                    || executed && transactions[i].executed)
                {
                    transactionIdsTemp[count] = i;
                    count += 1;
                }
            _transactionIds = new uint[](to - from);
            for (i=from; i<to; i++)
                _transactionIds[i - from] = transactionIdsTemp[i];
        }
    }
    
    /// @title Multisignature wallet with daily limit - Allows an owner to withdraw a daily limit without multisig.
    /// @author Stefan George - <[email protected]>
    contract MultiSigWalletWithDailyLimit is MultiSigWallet {
    
        event DailyLimitChange(uint dailyLimit);
    
        uint public dailyLimit;
        uint public lastDay;
        uint public spentToday;
    
        /*
         * Public functions
         */
        /// @dev Contract constructor sets initial owners, required number of confirmations and daily withdraw limit.
        /// @param _owners List of initial owners.
        /// @param _required Number of required confirmations.
        /// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis.
        function MultiSigWalletWithDailyLimit(address[] _owners, uint _required, uint _dailyLimit)
            public
            MultiSigWallet(_owners, _required)
        {
            dailyLimit = _dailyLimit;
        }
    
        /// @dev Allows to change the daily limit. Transaction has to be sent by wallet.
        /// @param _dailyLimit Amount in wei.
        function changeDailyLimit(uint _dailyLimit)
            public
            onlyWallet
        {
            dailyLimit = _dailyLimit;
            DailyLimitChange(_dailyLimit);
        }
    
        /// @dev Allows anyone to execute a confirmed transaction or ether withdraws until daily limit is reached.
        /// @param transactionId Transaction ID.
        function executeTransaction(uint transactionId)
            public
            notExecuted(transactionId)
        {
            Transaction tx = transactions[transactionId];
            bool confirmed = isConfirmed(transactionId);
            if (confirmed || tx.data.length == 0 && isUnderLimit(tx.value)) {
                tx.executed = true;
                if (!confirmed)
                    spentToday += tx.value;
                if (tx.destination.call.value(tx.value)(tx.data))
                    Execution(transactionId);
                else {
                    ExecutionFailure(transactionId);
                    tx.executed = false;
                    if (!confirmed)
                        spentToday -= tx.value;
                }
            }
        }
    
        /*
         * Internal functions
         */
        /// @dev Returns if amount is within daily limit and resets spentToday after one day.
        /// @param amount Amount to withdraw.
        /// @return Returns if amount is under daily limit.
        function isUnderLimit(uint amount)
            internal
            returns (bool)
        {
            if (now > lastDay + 24 hours) {
                lastDay = now;
                spentToday = 0;
            }
            if (spentToday + amount > dailyLimit || spentToday + amount < spentToday)
                return false;
            return true;
        }
    
        /*
         * Web3 call functions
         */
        /// @dev Returns maximum withdraw amount.
        /// @return Returns amount.
        function calcMaxWithdraw()
            public
            constant
            returns (uint)
        {
            if (now > lastDay + 24 hours)
                return dailyLimit;
            return dailyLimit - spentToday;
        }
    }

    File 2 of 3: UserWallet
    pragma solidity ^0.4.10;
    
    // Copyright 2017 Bittrex
    
    contract AbstractSweeper {
        function sweep(address token, uint amount) returns (bool);
    
        function () { throw; }
    
        Controller controller;
    
        function AbstractSweeper(address _controller) {
            controller = Controller(_controller);
        }
    
        modifier canSweep() {
            if (msg.sender != controller.authorizedCaller() && msg.sender != controller.owner()) throw;
            if (controller.halted()) throw;
            _;
        }
    }
    
    contract Token {
        function balanceOf(address a) returns (uint) {
            (a);
            return 0;
        }
    
        function transfer(address a, uint val) returns (bool) {
            (a);
            (val);
            return false;
        }
    }
    
    contract DefaultSweeper is AbstractSweeper {
        function DefaultSweeper(address controller)
                 AbstractSweeper(controller) {}
    
        function sweep(address _token, uint _amount)
        canSweep
        returns (bool) {
            bool success = false;
            address destination = controller.destination();
    
            if (_token != address(0)) {
                Token token = Token(_token);
                uint amount = _amount;
                if (amount > token.balanceOf(this)) {
                    return false;
                }
    
                success = token.transfer(destination, amount);
            }
            else {
                uint amountInWei = _amount;
                if (amountInWei > this.balance) {
                    return false;
                }
    
                success = destination.send(amountInWei);
            }
    
            if (success) {
                controller.logSweep(this, destination, _token, _amount);
            }
            return success;
        }
    }
    
    contract UserWallet {
        AbstractSweeperList sweeperList;
        function UserWallet(address _sweeperlist) {
            sweeperList = AbstractSweeperList(_sweeperlist);
        }
    
        function () public payable { }
    
        function tokenFallback(address _from, uint _value, bytes _data) {
            (_from);
            (_value);
            (_data);
         }
    
        function sweep(address _token, uint _amount)
        returns (bool) {
            (_amount);
            return sweeperList.sweeperOf(_token).delegatecall(msg.data);
        }
    }
    
    contract AbstractSweeperList {
        function sweeperOf(address _token) returns (address);
    }
    
    contract Controller is AbstractSweeperList {
        address public owner;
        address public authorizedCaller;
    
        address public destination;
    
        bool public halted;
    
        event LogNewWallet(address receiver);
        event LogSweep(address indexed from, address indexed to, address indexed token, uint amount);
        
        modifier onlyOwner() {
            if (msg.sender != owner) throw; 
            _;
        }
    
        modifier onlyAuthorizedCaller() {
            if (msg.sender != authorizedCaller) throw; 
            _;
        }
    
        modifier onlyAdmins() {
            if (msg.sender != authorizedCaller && msg.sender != owner) throw; 
            _;
        }
    
        function Controller() 
        {
            owner = msg.sender;
            destination = msg.sender;
            authorizedCaller = msg.sender;
        }
    
        function changeAuthorizedCaller(address _newCaller) onlyOwner {
            authorizedCaller = _newCaller;
        }
    
        function changeDestination(address _dest) onlyOwner {
            destination = _dest;
        }
    
        function changeOwner(address _owner) onlyOwner {
            owner = _owner;
        }
    
        function makeWallet() onlyAdmins returns (address wallet)  {
            wallet = address(new UserWallet(this));
            LogNewWallet(wallet);
        }
    
        function halt() onlyAdmins {
            halted = true;
        }
    
        function start() onlyOwner {
            halted = false;
        }
    
        address public defaultSweeper = address(new DefaultSweeper(this));
        mapping (address => address) sweepers;
    
        function addSweeper(address _token, address _sweeper) onlyOwner {
            sweepers[_token] = _sweeper;
        }
    
        function sweeperOf(address _token) returns (address) {
            address sweeper = sweepers[_token];
            if (sweeper == 0) sweeper = defaultSweeper;
            return sweeper;
        }
    
        function logSweep(address from, address to, address token, uint amount) {
            LogSweep(from, to, token, amount);
        }
    }

    File 3 of 3: GnosisToken
    pragma solidity 0.4.10;
    
    
    /// @title Abstract token contract - Functions to be implemented by token contracts.
    contract Token {
        function transfer(address to, uint256 value) returns (bool success);
        function transferFrom(address from, address to, uint256 value) returns (bool success);
        function approve(address spender, uint256 value) returns (bool success);
    
        // This is not an abstract function, because solc won't recognize generated getter functions for public variables as functions.
        function totalSupply() constant returns (uint256 supply) {}
        function balanceOf(address owner) constant returns (uint256 balance);
        function allowance(address owner, address spender) constant returns (uint256 remaining);
    
        event Transfer(address indexed from, address indexed to, uint256 value);
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    
    
    /// @title Standard token contract - Standard token interface implementation.
    contract StandardToken is Token {
    
        /*
         *  Data structures
         */
        mapping (address => uint256) balances;
        mapping (address => mapping (address => uint256)) allowed;
        uint256 public totalSupply;
    
        /*
         *  Public functions
         */
        /// @dev Transfers sender's tokens to a given address. Returns success.
        /// @param _to Address of token receiver.
        /// @param _value Number of tokens to transfer.
        /// @return Returns success of function call.
        function transfer(address _to, uint256 _value)
            public
            returns (bool)
        {
            if (balances[msg.sender] < _value) {
                // Balance too low
                throw;
            }
            balances[msg.sender] -= _value;
            balances[_to] += _value;
            Transfer(msg.sender, _to, _value);
            return true;
        }
    
        /// @dev Allows allowed third party to transfer tokens from one address to another. Returns success.
        /// @param _from Address from where tokens are withdrawn.
        /// @param _to Address to where tokens are sent.
        /// @param _value Number of tokens to transfer.
        /// @return Returns success of function call.
        function transferFrom(address _from, address _to, uint256 _value)
            public
            returns (bool)
        {
            if (balances[_from] < _value || allowed[_from][msg.sender] < _value) {
                // Balance or allowance too low
                throw;
            }
            balances[_to] += _value;
            balances[_from] -= _value;
            allowed[_from][msg.sender] -= _value;
            Transfer(_from, _to, _value);
            return true;
        }
    
        /// @dev Sets approved amount of tokens for spender. Returns success.
        /// @param _spender Address of allowed account.
        /// @param _value Number of approved tokens.
        /// @return Returns success of function call.
        function approve(address _spender, uint256 _value)
            public
            returns (bool)
        {
            allowed[msg.sender][_spender] = _value;
            Approval(msg.sender, _spender, _value);
            return true;
        }
    
        /*
         * Read functions
         */
        /// @dev Returns number of allowed tokens for given address.
        /// @param _owner Address of token owner.
        /// @param _spender Address of token spender.
        /// @return Returns remaining allowance for spender.
        function allowance(address _owner, address _spender)
            constant
            public
            returns (uint256)
        {
            return allowed[_owner][_spender];
        }
    
        /// @dev Returns number of tokens owned by given address.
        /// @param _owner Address of token owner.
        /// @return Returns balance of owner.
        function balanceOf(address _owner)
            constant
            public
            returns (uint256)
        {
            return balances[_owner];
        }
    }
    
    
    /// @title Gnosis token contract
    /// @author Stefan George - <[email protected]>
    contract GnosisToken is StandardToken {
    
        /*
         *  Token meta data
         */
        string constant public name = "Gnosis Token";
        string constant public symbol = "GNO";
        uint8 constant public decimals = 18;
    
        /*
         *  Public functions
         */
        /// @dev Contract constructor function sets dutch auction contract address and assigns all tokens to dutch auction.
        /// @param dutchAuction Address of dutch auction contract.
        /// @param owners Array of addresses receiving preassigned tokens.
        /// @param tokens Array of preassigned token amounts.
        function GnosisToken(address dutchAuction, address[] owners, uint[] tokens)
            public
        {
            if (dutchAuction == 0)
                // Address should not be null.
                throw;
            totalSupply = 10000000 * 10**18;
            balances[dutchAuction] = 9000000 * 10**18;
            Transfer(0, dutchAuction, balances[dutchAuction]);
            uint assignedTokens = balances[dutchAuction];
            for (uint i=0; i<owners.length; i++) {
                if (owners[i] == 0)
                    // Address should not be null.
                    throw;
                balances[owners[i]] += tokens[i];
                Transfer(0, owners[i], tokens[i]);
                assignedTokens += tokens[i];
            }
            if (assignedTokens != totalSupply)
                throw;
        }
    }