ETH Price: $1,599.89 (+1.18%)

Transaction Decoder

Block:
12258191 at Apr-17-2021 02:31:57 PM +UTC
Transaction Fee:
0.023682664 ETH $37.89
Gas Used:
160,018 Gas / 148 Gwei

Emitted Events:

51 MultiSigWalletWithDailyLimit.Confirmation( sender=[Sender] 0x1f4f5967df6b5b70a2d7f1d031e12e7f4fc6e56c, transactionId=61 )
52 MultiSigWalletWithDailyLimit.ExecutionFailure( transactionId=61 )

Account State Difference:

  Address   Before After State Difference Code
0x1F4f5967...f4fC6E56c
1.196504550871208392 Eth
Nonce: 71
1.172821886871208392 Eth
Nonce: 72
0.023682664
0x31CbA7aD...5736a9615
(Spark Pool)
8.782277391575364545 Eth8.805960055575364545 Eth0.023682664

Execution Trace

MultiSigWalletWithDailyLimit.confirmTransaction( transactionId=61 )
  • 0xc0754d0a5cb5b25d452be07165180ef331a3241a.f3fef3a3( )
    • GnosisToken.balanceOf( _owner=0xC0754d0A5cb5B25d452be07165180eF331A3241A ) => ( 2831024305555555555556 )
    • GnosisToken.transfer( _to=0x31CbA7aD3483F9BFF236DF556E1C3695736a9615, _value=2831401969178082191781 )
      File 1 of 2: 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 2: 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;
          }
      }