ETH Price: $2,180.34 (+2.22%)

Transaction Decoder

Block:
13685215 at Nov-25-2021 07:04:45 PM +UTC
Transaction Fee:
0.006660688955877984 ETH $14.52
Gas Used:
54,627 Gas / 121.930344992 Gwei

Emitted Events:

285 Vyper_contract.Transfer( _from=Forwarder, _to=[Receiver] 0x1522900b6dafac587d499a862861c0869be6e428, _value=23080870000000000000000 )
286 Forwarder.TokensFlushed( tokenContractAddress=Vyper_contract, value=23080870000000000000000 )

Account State Difference:

  Address   Before After State Difference Code
0x00BDb569...b9Ae374eD
(Bitstamp 1)
49.948988809406941281 Eth
Nonce: 1319035
49.942328120451063297 Eth
Nonce: 1319036
0.006660688955877984
0xD533a949...bA034cd52
(Ethermine)
2,258.140015098598366255 Eth2,258.140097039098366255 Eth0.0000819405

Execution Trace

Bitstamp 2.2da03409( )
  • WalletSimple.flushForwarderTokens( forwarderAddress=0x91db9e27E750C43a96926B2E04D795c24f13F67B, tokenContractAddress=0xD533a949740bb3306d119CC777fa900bA034cd52 )
    • Forwarder.flushTokens( tokenContractAddress=0xD533a949740bb3306d119CC777fa900bA034cd52 )
      • Vyper_contract.balanceOf( arg0=0x91db9e27E750C43a96926B2E04D795c24f13F67B ) => ( 23080870000000000000000 )
      • Vyper_contract.transfer( _to=0x1522900B6daFac587d499a862861C0869Be6E428, _value=23080870000000000000000 ) => ( True )
        File 1 of 3: 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 3: Vyper_contract
        # @version 0.2.4
        """
        @title Curve DAO Token
        @author Curve Finance
        @license MIT
        @notice ERC20 with piecewise-linear mining supply.
        @dev Based on the ERC-20 token standard as defined at
             https://eips.ethereum.org/EIPS/eip-20
        """
        
        from vyper.interfaces import ERC20
        
        implements: ERC20
        
        
        event Transfer:
            _from: indexed(address)
            _to: indexed(address)
            _value: uint256
        
        event Approval:
            _owner: indexed(address)
            _spender: indexed(address)
            _value: uint256
        
        event UpdateMiningParameters:
            time: uint256
            rate: uint256
            supply: uint256
        
        event SetMinter:
            minter: address
        
        event SetAdmin:
            admin: address
        
        
        name: public(String[64])
        symbol: public(String[32])
        decimals: public(uint256)
        
        balanceOf: public(HashMap[address, uint256])
        allowances: HashMap[address, HashMap[address, uint256]]
        total_supply: uint256
        
        minter: public(address)
        admin: public(address)
        
        # General constants
        YEAR: constant(uint256) = 86400 * 365
        
        # Allocation:
        # =========
        # * shareholders - 30%
        # * emplyees - 3%
        # * DAO-controlled reserve - 5%
        # * Early users - 5%
        # == 43% ==
        # left for inflation: 57%
        
        # Supply parameters
        INITIAL_SUPPLY: constant(uint256) = 1_303_030_303
        INITIAL_RATE: constant(uint256) = 274_815_283 * 10 ** 18 / YEAR  # leading to 43% premine
        RATE_REDUCTION_TIME: constant(uint256) = YEAR
        RATE_REDUCTION_COEFFICIENT: constant(uint256) = 1189207115002721024  # 2 ** (1/4) * 1e18
        RATE_DENOMINATOR: constant(uint256) = 10 ** 18
        INFLATION_DELAY: constant(uint256) = 86400
        
        # Supply variables
        mining_epoch: public(int128)
        start_epoch_time: public(uint256)
        rate: public(uint256)
        
        start_epoch_supply: uint256
        
        
        @external
        def __init__(_name: String[64], _symbol: String[32], _decimals: uint256):
            """
            @notice Contract constructor
            @param _name Token full name
            @param _symbol Token symbol
            @param _decimals Number of decimals for token
            """
            init_supply: uint256 = INITIAL_SUPPLY * 10 ** _decimals
            self.name = _name
            self.symbol = _symbol
            self.decimals = _decimals
            self.balanceOf[msg.sender] = init_supply
            self.total_supply = init_supply
            self.admin = msg.sender
            log Transfer(ZERO_ADDRESS, msg.sender, init_supply)
        
            self.start_epoch_time = block.timestamp + INFLATION_DELAY - RATE_REDUCTION_TIME
            self.mining_epoch = -1
            self.rate = 0
            self.start_epoch_supply = init_supply
        
        
        @internal
        def _update_mining_parameters():
            """
            @dev Update mining rate and supply at the start of the epoch
                 Any modifying mining call must also call this
            """
            _rate: uint256 = self.rate
            _start_epoch_supply: uint256 = self.start_epoch_supply
        
            self.start_epoch_time += RATE_REDUCTION_TIME
            self.mining_epoch += 1
        
            if _rate == 0:
                _rate = INITIAL_RATE
            else:
                _start_epoch_supply += _rate * RATE_REDUCTION_TIME
                self.start_epoch_supply = _start_epoch_supply
                _rate = _rate * RATE_DENOMINATOR / RATE_REDUCTION_COEFFICIENT
        
            self.rate = _rate
        
            log UpdateMiningParameters(block.timestamp, _rate, _start_epoch_supply)
        
        
        @external
        def update_mining_parameters():
            """
            @notice Update mining rate and supply at the start of the epoch
            @dev Callable by any address, but only once per epoch
                 Total supply becomes slightly larger if this function is called late
            """
            assert block.timestamp >= self.start_epoch_time + RATE_REDUCTION_TIME  # dev: too soon!
            self._update_mining_parameters()
        
        
        @external
        def start_epoch_time_write() -> uint256:
            """
            @notice Get timestamp of the current mining epoch start
                    while simultaneously updating mining parameters
            @return Timestamp of the epoch
            """
            _start_epoch_time: uint256 = self.start_epoch_time
            if block.timestamp >= _start_epoch_time + RATE_REDUCTION_TIME:
                self._update_mining_parameters()
                return self.start_epoch_time
            else:
                return _start_epoch_time
        
        
        @external
        def future_epoch_time_write() -> uint256:
            """
            @notice Get timestamp of the next mining epoch start
                    while simultaneously updating mining parameters
            @return Timestamp of the next epoch
            """
            _start_epoch_time: uint256 = self.start_epoch_time
            if block.timestamp >= _start_epoch_time + RATE_REDUCTION_TIME:
                self._update_mining_parameters()
                return self.start_epoch_time + RATE_REDUCTION_TIME
            else:
                return _start_epoch_time + RATE_REDUCTION_TIME
        
        
        @internal
        @view
        def _available_supply() -> uint256:
            return self.start_epoch_supply + (block.timestamp - self.start_epoch_time) * self.rate
        
        
        @external
        @view
        def available_supply() -> uint256:
            """
            @notice Current number of tokens in existence (claimed or unclaimed)
            """
            return self._available_supply()
        
        
        @external
        @view
        def mintable_in_timeframe(start: uint256, end: uint256) -> uint256:
            """
            @notice How much supply is mintable from start timestamp till end timestamp
            @param start Start of the time interval (timestamp)
            @param end End of the time interval (timestamp)
            @return Tokens mintable from `start` till `end`
            """
            assert start <= end  # dev: start > end
            to_mint: uint256 = 0
            current_epoch_time: uint256 = self.start_epoch_time
            current_rate: uint256 = self.rate
        
            # Special case if end is in future (not yet minted) epoch
            if end > current_epoch_time + RATE_REDUCTION_TIME:
                current_epoch_time += RATE_REDUCTION_TIME
                current_rate = current_rate * RATE_DENOMINATOR / RATE_REDUCTION_COEFFICIENT
        
            assert end <= current_epoch_time + RATE_REDUCTION_TIME  # dev: too far in future
        
            for i in range(999):  # Curve will not work in 1000 years. Darn!
                if end >= current_epoch_time:
                    current_end: uint256 = end
                    if current_end > current_epoch_time + RATE_REDUCTION_TIME:
                        current_end = current_epoch_time + RATE_REDUCTION_TIME
        
                    current_start: uint256 = start
                    if current_start >= current_epoch_time + RATE_REDUCTION_TIME:
                        break  # We should never get here but what if...
                    elif current_start < current_epoch_time:
                        current_start = current_epoch_time
        
                    to_mint += current_rate * (current_end - current_start)
        
                    if start >= current_epoch_time:
                        break
        
                current_epoch_time -= RATE_REDUCTION_TIME
                current_rate = current_rate * RATE_REDUCTION_COEFFICIENT / RATE_DENOMINATOR  # double-division with rounding made rate a bit less => good
                assert current_rate <= INITIAL_RATE  # This should never happen
        
            return to_mint
        
        
        @external
        def set_minter(_minter: address):
            """
            @notice Set the minter address
            @dev Only callable once, when minter has not yet been set
            @param _minter Address of the minter
            """
            assert msg.sender == self.admin  # dev: admin only
            assert self.minter == ZERO_ADDRESS  # dev: can set the minter only once, at creation
            self.minter = _minter
            log SetMinter(_minter)
        
        
        @external
        def set_admin(_admin: address):
            """
            @notice Set the new admin.
            @dev After all is set up, admin only can change the token name
            @param _admin New admin address
            """
            assert msg.sender == self.admin  # dev: admin only
            self.admin = _admin
            log SetAdmin(_admin)
        
        
        @external
        @view
        def totalSupply() -> uint256:
            """
            @notice Total number of tokens in existence.
            """
            return self.total_supply
        
        
        @external
        @view
        def allowance(_owner : address, _spender : address) -> uint256:
            """
            @notice Check the amount of tokens that an owner allowed to a spender
            @param _owner The address which owns the funds
            @param _spender The address which will spend the funds
            @return uint256 specifying the amount of tokens still available for the spender
            """
            return self.allowances[_owner][_spender]
        
        
        @external
        def transfer(_to : address, _value : uint256) -> bool:
            """
            @notice Transfer `_value` tokens from `msg.sender` to `_to`
            @dev Vyper does not allow underflows, so the subtraction in
                 this function will revert on an insufficient balance
            @param _to The address to transfer to
            @param _value The amount to be transferred
            @return bool success
            """
            assert _to != ZERO_ADDRESS  # dev: transfers to 0x0 are not allowed
            self.balanceOf[msg.sender] -= _value
            self.balanceOf[_to] += _value
            log Transfer(msg.sender, _to, _value)
            return True
        
        
        @external
        def transferFrom(_from : address, _to : address, _value : uint256) -> bool:
            """
             @notice Transfer `_value` tokens from `_from` to `_to`
             @param _from address The address which you want to send tokens from
             @param _to address The address which you want to transfer to
             @param _value uint256 the amount of tokens to be transferred
             @return bool success
            """
            assert _to != ZERO_ADDRESS  # dev: transfers to 0x0 are not allowed
            # NOTE: vyper does not allow underflows
            #       so the following subtraction would revert on insufficient balance
            self.balanceOf[_from] -= _value
            self.balanceOf[_to] += _value
            self.allowances[_from][msg.sender] -= _value
            log Transfer(_from, _to, _value)
            return True
        
        
        @external
        def approve(_spender : address, _value : uint256) -> bool:
            """
            @notice Approve `_spender` to transfer `_value` tokens on behalf of `msg.sender`
            @dev Approval may only be from zero -> nonzero or from nonzero -> zero in order
                to mitigate the potential race condition described here:
                https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
            @param _spender The address which will spend the funds
            @param _value The amount of tokens to be spent
            @return bool success
            """
            assert _value == 0 or self.allowances[msg.sender][_spender] == 0
            self.allowances[msg.sender][_spender] = _value
            log Approval(msg.sender, _spender, _value)
            return True
        
        
        @external
        def mint(_to: address, _value: uint256) -> bool:
            """
            @notice Mint `_value` tokens and assign them to `_to`
            @dev Emits a Transfer event originating from 0x00
            @param _to The account that will receive the created tokens
            @param _value The amount that will be created
            @return bool success
            """
            assert msg.sender == self.minter  # dev: minter only
            assert _to != ZERO_ADDRESS  # dev: zero address
        
            if block.timestamp >= self.start_epoch_time + RATE_REDUCTION_TIME:
                self._update_mining_parameters()
        
            _total_supply: uint256 = self.total_supply + _value
            assert _total_supply <= self._available_supply()  # dev: exceeds allowable mint amount
            self.total_supply = _total_supply
        
            self.balanceOf[_to] += _value
            log Transfer(ZERO_ADDRESS, _to, _value)
        
            return True
        
        
        @external
        def burn(_value: uint256) -> bool:
            """
            @notice Burn `_value` tokens belonging to `msg.sender`
            @dev Emits a Transfer event with a destination of 0x00
            @param _value The amount that will be burned
            @return bool success
            """
            self.balanceOf[msg.sender] -= _value
            self.total_supply -= _value
        
            log Transfer(msg.sender, ZERO_ADDRESS, _value)
            return True
        
        
        @external
        def set_name(_name: String[64], _symbol: String[32]):
            """
            @notice Change the token name and symbol to `_name` and `_symbol`
            @dev Only callable by the admin account
            @param _name New token name
            @param _symbol New token symbol
            """
            assert msg.sender == self.admin, "Only admin is allowed to change name"
            self.name = _name
            self.symbol = _symbol

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