ETH Price: $2,138.30 (+1.19%)

Transaction Decoder

Block:
24760502 at Mar-29-2026 03:17:47 AM +UTC
Transaction Fee:
0.000015477973684236 ETH $0.03
Gas Used:
141,022 Gas / 0.109755738 Gwei

Account State Difference:

  Address   Before After State Difference Code
(quasarbuilder)
16.296541905565665246 Eth16.296541905565806268 Eth0.000000000000141022
0x894b36c2...09bCE4544
0.196507413147014225 Eth
Nonce: 290
0.196491935173329989 Eth
Nonce: 291
0.000015477973684236

Execution Trace

0x278d858f05b94576c1e6f73285886876ff6ef8d2.42e3dcf3( )
  • 0x617e169f98f966d520946282de52340b94b59a7c.42e3dcf3( )
    • Uniswap V3: CRV-USDT 2.128acb08( )
      • Vyper_contract.transfer( _to=0x278d858f05b94576C1E6f73285886876ff6eF8D2, _value=648876638447366689899 ) => ( True )
      • TetherToken.balanceOf( who=0x07B1c12BE0d62fe548a2b4b025Ab7A5cA8DEf21E ) => ( 88834656624 )
      • 0x278d858f05b94576c1e6f73285886876ff6ef8d2.fa461e33( )
        • 0x617e169f98f966d520946282de52340b94b59a7c.fa461e33( )
          • TetherToken.transfer( _to=0x07B1c12BE0d62fe548a2b4b025Ab7A5cA8DEf21E, _value=137740951 )
          • TetherToken.balanceOf( who=0x07B1c12BE0d62fe548a2b4b025Ab7A5cA8DEf21E ) => ( 88972397575 )
            File 1 of 2: 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 2 of 2: TetherToken
            pragma solidity ^0.4.17;
            
            /**
             * @title SafeMath
             * @dev Math operations with safety checks that throw on error
             */
            library SafeMath {
                function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                    if (a == 0) {
                        return 0;
                    }
                    uint256 c = a * b;
                    assert(c / a == b);
                    return c;
                }
            
                function div(uint256 a, uint256 b) internal pure returns (uint256) {
                    // assert(b > 0); // Solidity automatically throws when dividing by 0
                    uint256 c = a / b;
                    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
                    return c;
                }
            
                function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                    assert(b <= a);
                    return a - b;
                }
            
                function add(uint256 a, uint256 b) internal pure returns (uint256) {
                    uint256 c = a + b;
                    assert(c >= a);
                    return c;
                }
            }
            
            /**
             * @title Ownable
             * @dev The Ownable contract has an owner address, and provides basic authorization control
             * functions, this simplifies the implementation of "user permissions".
             */
            contract Ownable {
                address public owner;
            
                /**
                  * @dev The Ownable constructor sets the original `owner` of the contract to the sender
                  * account.
                  */
                function Ownable() public {
                    owner = msg.sender;
                }
            
                /**
                  * @dev Throws if called by any account other than the owner.
                  */
                modifier onlyOwner() {
                    require(msg.sender == owner);
                    _;
                }
            
                /**
                * @dev Allows the current owner to transfer control of the contract to a newOwner.
                * @param newOwner The address to transfer ownership to.
                */
                function transferOwnership(address newOwner) public onlyOwner {
                    if (newOwner != address(0)) {
                        owner = newOwner;
                    }
                }
            
            }
            
            /**
             * @title ERC20Basic
             * @dev Simpler version of ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20Basic {
                uint public _totalSupply;
                function totalSupply() public constant returns (uint);
                function balanceOf(address who) public constant returns (uint);
                function transfer(address to, uint value) public;
                event Transfer(address indexed from, address indexed to, uint value);
            }
            
            /**
             * @title ERC20 interface
             * @dev see https://github.com/ethereum/EIPs/issues/20
             */
            contract ERC20 is ERC20Basic {
                function allowance(address owner, address spender) public constant returns (uint);
                function transferFrom(address from, address to, uint value) public;
                function approve(address spender, uint value) public;
                event Approval(address indexed owner, address indexed spender, uint value);
            }
            
            /**
             * @title Basic token
             * @dev Basic version of StandardToken, with no allowances.
             */
            contract BasicToken is Ownable, ERC20Basic {
                using SafeMath for uint;
            
                mapping(address => uint) public balances;
            
                // additional variables for use if transaction fees ever became necessary
                uint public basisPointsRate = 0;
                uint public maximumFee = 0;
            
                /**
                * @dev Fix for the ERC20 short address attack.
                */
                modifier onlyPayloadSize(uint size) {
                    require(!(msg.data.length < size + 4));
                    _;
                }
            
                /**
                * @dev transfer token for a specified address
                * @param _to The address to transfer to.
                * @param _value The amount to be transferred.
                */
                function transfer(address _to, uint _value) public onlyPayloadSize(2 * 32) {
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[msg.sender] = balances[msg.sender].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(msg.sender, owner, fee);
                    }
                    Transfer(msg.sender, _to, sendAmount);
                }
            
                /**
                * @dev Gets the balance of the specified address.
                * @param _owner The address to query the the balance of.
                * @return An uint representing the amount owned by the passed address.
                */
                function balanceOf(address _owner) public constant returns (uint balance) {
                    return balances[_owner];
                }
            
            }
            
            /**
             * @title Standard ERC20 token
             *
             * @dev Implementation of the basic standard token.
             * @dev https://github.com/ethereum/EIPs/issues/20
             * @dev Based oncode by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
             */
            contract StandardToken is BasicToken, ERC20 {
            
                mapping (address => mapping (address => uint)) public allowed;
            
                uint public constant MAX_UINT = 2**256 - 1;
            
                /**
                * @dev Transfer tokens from one address to another
                * @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 uint the amount of tokens to be transferred
                */
                function transferFrom(address _from, address _to, uint _value) public onlyPayloadSize(3 * 32) {
                    var _allowance = allowed[_from][msg.sender];
            
                    // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
                    // if (_value > _allowance) throw;
            
                    uint fee = (_value.mul(basisPointsRate)).div(10000);
                    if (fee > maximumFee) {
                        fee = maximumFee;
                    }
                    if (_allowance < MAX_UINT) {
                        allowed[_from][msg.sender] = _allowance.sub(_value);
                    }
                    uint sendAmount = _value.sub(fee);
                    balances[_from] = balances[_from].sub(_value);
                    balances[_to] = balances[_to].add(sendAmount);
                    if (fee > 0) {
                        balances[owner] = balances[owner].add(fee);
                        Transfer(_from, owner, fee);
                    }
                    Transfer(_from, _to, sendAmount);
                }
            
                /**
                * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
                * @param _spender The address which will spend the funds.
                * @param _value The amount of tokens to be spent.
                */
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
            
                    // To change the approve amount you first have to reduce the addresses`
                    //  allowance to zero by calling `approve(_spender, 0)` if it is not
                    //  already 0 to mitigate the race condition described here:
                    //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                    require(!((_value != 0) && (allowed[msg.sender][_spender] != 0)));
            
                    allowed[msg.sender][_spender] = _value;
                    Approval(msg.sender, _spender, _value);
                }
            
                /**
                * @dev Function to check the amount of tokens than an owner allowed to a spender.
                * @param _owner address The address which owns the funds.
                * @param _spender address The address which will spend the funds.
                * @return A uint specifying the amount of tokens still available for the spender.
                */
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    return allowed[_owner][_spender];
                }
            
            }
            
            
            /**
             * @title Pausable
             * @dev Base contract which allows children to implement an emergency stop mechanism.
             */
            contract Pausable is Ownable {
              event Pause();
              event Unpause();
            
              bool public paused = false;
            
            
              /**
               * @dev Modifier to make a function callable only when the contract is not paused.
               */
              modifier whenNotPaused() {
                require(!paused);
                _;
              }
            
              /**
               * @dev Modifier to make a function callable only when the contract is paused.
               */
              modifier whenPaused() {
                require(paused);
                _;
              }
            
              /**
               * @dev called by the owner to pause, triggers stopped state
               */
              function pause() onlyOwner whenNotPaused public {
                paused = true;
                Pause();
              }
            
              /**
               * @dev called by the owner to unpause, returns to normal state
               */
              function unpause() onlyOwner whenPaused public {
                paused = false;
                Unpause();
              }
            }
            
            contract BlackList is Ownable, BasicToken {
            
                /////// Getters to allow the same blacklist to be used also by other contracts (including upgraded Tether) ///////
                function getBlackListStatus(address _maker) external constant returns (bool) {
                    return isBlackListed[_maker];
                }
            
                function getOwner() external constant returns (address) {
                    return owner;
                }
            
                mapping (address => bool) public isBlackListed;
                
                function addBlackList (address _evilUser) public onlyOwner {
                    isBlackListed[_evilUser] = true;
                    AddedBlackList(_evilUser);
                }
            
                function removeBlackList (address _clearedUser) public onlyOwner {
                    isBlackListed[_clearedUser] = false;
                    RemovedBlackList(_clearedUser);
                }
            
                function destroyBlackFunds (address _blackListedUser) public onlyOwner {
                    require(isBlackListed[_blackListedUser]);
                    uint dirtyFunds = balanceOf(_blackListedUser);
                    balances[_blackListedUser] = 0;
                    _totalSupply -= dirtyFunds;
                    DestroyedBlackFunds(_blackListedUser, dirtyFunds);
                }
            
                event DestroyedBlackFunds(address _blackListedUser, uint _balance);
            
                event AddedBlackList(address _user);
            
                event RemovedBlackList(address _user);
            
            }
            
            contract UpgradedStandardToken is StandardToken{
                // those methods are called by the legacy contract
                // and they must ensure msg.sender to be the contract address
                function transferByLegacy(address from, address to, uint value) public;
                function transferFromByLegacy(address sender, address from, address spender, uint value) public;
                function approveByLegacy(address from, address spender, uint value) public;
            }
            
            contract TetherToken is Pausable, StandardToken, BlackList {
            
                string public name;
                string public symbol;
                uint public decimals;
                address public upgradedAddress;
                bool public deprecated;
            
                //  The contract can be initialized with a number of tokens
                //  All the tokens are deposited to the owner address
                //
                // @param _balance Initial supply of the contract
                // @param _name Token Name
                // @param _symbol Token symbol
                // @param _decimals Token decimals
                function TetherToken(uint _initialSupply, string _name, string _symbol, uint _decimals) public {
                    _totalSupply = _initialSupply;
                    name = _name;
                    symbol = _symbol;
                    decimals = _decimals;
                    balances[owner] = _initialSupply;
                    deprecated = false;
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transfer(address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[msg.sender]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferByLegacy(msg.sender, _to, _value);
                    } else {
                        return super.transfer(_to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function transferFrom(address _from, address _to, uint _value) public whenNotPaused {
                    require(!isBlackListed[_from]);
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).transferFromByLegacy(msg.sender, _from, _to, _value);
                    } else {
                        return super.transferFrom(_from, _to, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function balanceOf(address who) public constant returns (uint) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).balanceOf(who);
                    } else {
                        return super.balanceOf(who);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function approve(address _spender, uint _value) public onlyPayloadSize(2 * 32) {
                    if (deprecated) {
                        return UpgradedStandardToken(upgradedAddress).approveByLegacy(msg.sender, _spender, _value);
                    } else {
                        return super.approve(_spender, _value);
                    }
                }
            
                // Forward ERC20 methods to upgraded contract if this one is deprecated
                function allowance(address _owner, address _spender) public constant returns (uint remaining) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).allowance(_owner, _spender);
                    } else {
                        return super.allowance(_owner, _spender);
                    }
                }
            
                // deprecate current contract in favour of a new one
                function deprecate(address _upgradedAddress) public onlyOwner {
                    deprecated = true;
                    upgradedAddress = _upgradedAddress;
                    Deprecate(_upgradedAddress);
                }
            
                // deprecate current contract if favour of a new one
                function totalSupply() public constant returns (uint) {
                    if (deprecated) {
                        return StandardToken(upgradedAddress).totalSupply();
                    } else {
                        return _totalSupply;
                    }
                }
            
                // Issue a new amount of tokens
                // these tokens are deposited into the owner address
                //
                // @param _amount Number of tokens to be issued
                function issue(uint amount) public onlyOwner {
                    require(_totalSupply + amount > _totalSupply);
                    require(balances[owner] + amount > balances[owner]);
            
                    balances[owner] += amount;
                    _totalSupply += amount;
                    Issue(amount);
                }
            
                // Redeem tokens.
                // These tokens are withdrawn from the owner address
                // if the balance must be enough to cover the redeem
                // or the call will fail.
                // @param _amount Number of tokens to be issued
                function redeem(uint amount) public onlyOwner {
                    require(_totalSupply >= amount);
                    require(balances[owner] >= amount);
            
                    _totalSupply -= amount;
                    balances[owner] -= amount;
                    Redeem(amount);
                }
            
                function setParams(uint newBasisPoints, uint newMaxFee) public onlyOwner {
                    // Ensure transparency by hardcoding limit beyond which fees can never be added
                    require(newBasisPoints < 20);
                    require(newMaxFee < 50);
            
                    basisPointsRate = newBasisPoints;
                    maximumFee = newMaxFee.mul(10**decimals);
            
                    Params(basisPointsRate, maximumFee);
                }
            
                // Called when new token are issued
                event Issue(uint amount);
            
                // Called when tokens are redeemed
                event Redeem(uint amount);
            
                // Called when contract is deprecated
                event Deprecate(address newAddress);
            
                // Called if contract ever adds fees
                event Params(uint feeBasisPoints, uint maxFee);
            }