add old Purchase and Sell events back, to stay compatible with app

pragma solidity 0.4.11;

import "../ERC20.sol";
import "../Ownable.sol";
import "../controller/ControllerInterface.sol";

/**
 * Nutz implements a price floor and a price ceiling on the token being
 * sold. It is based of the zeppelin token contract.
 */
contract Nutz is Ownable, ERC20 {

  event Purchase(address indexed purchaser, uint256 value);
  event Sell(address indexed seller, uint256 value);

  string public name = "Acebusters Nutz";
  // acebusters units:
  // 10^12 - Nutz   (NTZ)
  // 10^9 - Jonyz
  // 10^6 - Helcz
  // 10^3 - Pascalz
  // 10^0 - Babz
  string public symbol = "NTZ";
  uint256 public decimals = 12;
  address internal powerUpContant = 0x000000000000000000000000000000706f776572; // 0xPOW
  address internal powerDownConst = 0x00000000000000000000000000000061626e747a; // 0xNTZ
  address internal sellConstant =   0x0000000000000000000000000000006574686572; // 0xETH

  // returns balances of active holders
  function balanceOf(address _owner) constant returns (uint) {
    return ControllerInterface(owner).babzBalanceOf(_owner);
  }

  function totalSupply() constant returns (uint256) {
    return ControllerInterface(owner).totalSupply();
  }

  function activeSupply() constant returns (uint256) {
    return ControllerInterface(owner).activeSupply();
  }

  // return remaining allowance
  // if calling return allowed[address(this)][_spender];
  // returns balance of ether parked to be withdrawn
  function allowance(address _owner, address _spender) constant returns (uint256) {
    return ControllerInterface(owner).allowance(_owner, _spender);
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function floor() constant returns (uint256) {
    return ControllerInterface(owner).floor();
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function ceiling() constant returns (uint256) {
    return ControllerInterface(owner).ceiling();
  }

  function powerPool() constant returns (uint256) {
    return ControllerInterface(owner).powerPool();
  }

  // ############################################
  // ########### ADMIN FUNCTIONS ################
  // ############################################

  function powerDown(address _holder, uint256 _amountBabz) onlyOwner {
    // NTZ transfered from power pool to user's balance
    Transfer(powerDownConst, _holder, _amountBabz);
  }

  // ############################################
  // ########### PUBLIC FUNCTIONS ###############
  // ############################################

  function approve(address _spender, uint256 _amountBabz) public {
    ControllerInterface(owner).approve(msg.sender, _spender, _amountBabz);
    Approval(msg.sender, _spender, _amountBabz);
  }

  function transfer(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    if (_to == sellConstant) {
      ControllerInterface(owner).sell(msg.sender, _amountBabz);
      Sell(msg.sender, _amountBabz);
    } else if (_to == powerUpContant) {
      ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
      Transfer(msg.sender, _to, _amountBabz);
    } else {
      ControllerInterface(owner).transfer(msg.sender, _to, _amountBabz, _data);
      Transfer(msg.sender, _to, _amountBabz);
    }
    return true;
  }

  function transfer(address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transfer(_to, _amountBabz, empty);
  }

  function transData(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    return transfer(_to, _amountBabz, _data);
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    if (_to == powerUpContant) {
      ControllerInterface(owner).powerUp(msg.sender, _from, _amountBabz);
    } else {
      ControllerInterface(owner).transferFrom(msg.sender, _from, _to, _amountBabz, _data);
    }
    Transfer(_from, _to, _amountBabz);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transferFrom(_from, _to, _amountBabz, empty);
  }

  function purchase() public payable {
    require(msg.value > 0);
    uint256 amountBabz = ControllerInterface(owner).purchase.value(msg.value)(msg.sender);
    Purchase(msg.sender, amountBabz);
  }

  function sell(uint256 _amountBabz) public {
    ControllerInterface(owner).sell(msg.sender, _amountBabz);
    Sell(msg.sender, _amountBabz);
  }

  function powerUp(uint256 _amountBabz) public {
    ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
    // NTZ transfered from user's balance to power pool
    Transfer(msg.sender, powerUpContant, _amountBabz);
  }

}

pragma solidity 0.4.11;

import "../ERC20.sol";
import "../Ownable.sol";
import "../controller/ControllerInterface.sol";

/**
 * Nutz implements a price floor and a price ceiling on the token being
 * sold. It is based of the zeppelin token contract.
 */
contract Nutz is Ownable, ERC20 {

  string public name = "Acebusters Nutz";
  // acebusters units:
  // 10^12 - Nutz   (NTZ)
  // 10^9 - Jonyz
  // 10^6 - Helcz
  // 10^3 - Pascalz
  // 10^0 - Babz
  string public symbol = "NTZ";
  uint256 public decimals = 12;
  address internal powerUpContant = 0x000000000000000000000000000000706f776572; // 0xPOW
  address internal powerDownConst = 0x00000000000000000000000000000061626e747a; // 0xNTZ
  address internal sellConstant =   0x0000000000000000000000000000006574686572; // 0xETH

  // returns balances of active holders
  function balanceOf(address _owner) constant returns (uint) {
    return ControllerInterface(owner).babzBalanceOf(_owner);
  }

  function totalSupply() constant returns (uint256) {
    return ControllerInterface(owner).totalSupply();
  }

  function activeSupply() constant returns (uint256) {
    return ControllerInterface(owner).activeSupply();
  }

  // return remaining allowance
  // if calling return allowed[address(this)][_spender];
  // returns balance of ether parked to be withdrawn
  function allowance(address _owner, address _spender) constant returns (uint256) {
    return ControllerInterface(owner).allowance(_owner, _spender);
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function floor() constant returns (uint256) {
    return ControllerInterface(owner).floor();
  }

  // returns either the salePrice, or if reserve does not suffice
  // for active supply, returns maxFloor
  function ceiling() constant returns (uint256) {
    return ControllerInterface(owner).ceiling();
  }

  function powerPool() constant returns (uint256) {
    return ControllerInterface(owner).powerPool();
  }

  // ############################################
  // ########### ADMIN FUNCTIONS ################
  // ############################################

  function powerDown(address _holder, uint256 _amountBabz) onlyOwner {
    // NTZ transfered from power pool to user's balance
    Transfer(powerDownConst, _holder, _amountBabz);
  }

  // ############################################
  // ########### PUBLIC FUNCTIONS ###############
  // ############################################

  function approve(address _spender, uint256 _amountBabz) public {
    ControllerInterface(owner).approve(msg.sender, _spender, _amountBabz);
    Approval(msg.sender, _spender, _amountBabz);
  }

  function transfer(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    if (_to == sellConstant) {
      ControllerInterface(owner).sell(msg.sender, _amountBabz);
    } else if (_to == powerUpContant) {
      ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
    } else {
      ControllerInterface(owner).transfer(msg.sender, _to, _amountBabz, _data);
    }
    Transfer(msg.sender, _to, _amountBabz);
    return true;
  }

  function transfer(address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transfer(_to, _amountBabz, empty);
  }

  function transData(address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    return transfer(_to, _amountBabz, _data);
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz, bytes _data) public returns (bool) {
    if (_to == powerUpContant) {
      ControllerInterface(owner).powerUp(msg.sender, _from, _amountBabz);
    } else {
      ControllerInterface(owner).transferFrom(msg.sender, _from, _to, _amountBabz, _data);
    }
    Transfer(_from, _to, _amountBabz);
    return true;
  }

  function transferFrom(address _from, address _to, uint256 _amountBabz) public returns (bool) {
    bytes memory empty;
    return transferFrom(_from, _to, _amountBabz, empty);
  }

  function purchase() public payable {
    require(msg.value > 0);
    uint256 amountBabz = ControllerInterface(owner).purchase.value(msg.value)(msg.sender);
    Transfer(sellConstant, msg.sender, amountBabz);
  }

  function sell(uint256 _amountBabz) public {
    ControllerInterface(owner).sell(msg.sender, _amountBabz);
    Transfer(msg.sender, sellConstant, _amountBabz);
  }

  function powerUp(uint256 _amountBabz) public {
    ControllerInterface(owner).powerUp(msg.sender, msg.sender, _amountBabz);
    // NTZ transfered from user's balance to power pool
    Transfer(msg.sender, powerUpContant, _amountBabz);
  }

}


Fix broken forum URL (#3537)

Fix broken forum URL (#3537)

Co-authored-by: Francisco <4223852eec80914c4c190cdc031e06592b151a67@gmail.com>

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * The default value of {decimals} is 18. To select a different value for
     * {decimals} you should overload it.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless this function is
     * overridden;
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(
        address owner,
        address spender,
        uint256 amount
    ) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {}
}


Re-arrange function order in abstract contract.

pragma solidity ^0.4.2;

/**
 * @title AbstractBlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract AbstractBlobStore {

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param blobId Id of the blob.
     */
    function transferEnable(bytes32 blobId) external;

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param blobId Id of the blob.
     */
    function transferDisable(bytes32 blobId) external;

    /**
     * @dev Get the id for this BlobStore contract.
     * @return contractId Id of the contract.
     */
    function getContractId() constant external returns (bytes12 contractId);

    /**
     * @dev Check if a blob exists.
     * @param blobId Id of the blob.
     * @return exists True if the blob exists.
     */
    function getExists(bytes32 blobId) constant external returns (bool exists);

    /**
     * @dev Determine if a blob is updatable.
     * @param blobId Id of the blob.
     * @return updatable True if the blob is updatable.
     */
    function getUpdatable(bytes32 blobId) constant external returns (bool updatable);

    /**
     * @dev Determine if a blob enforces revisions.
     * @param blobId Id of the blob.
     * @return enforceRevisions True if the blob enforces revisions.
     */
    function getEnforceRevisions(bytes32 blobId) constant external returns (bool enforceRevisions);

    /**
     * @dev Determine if a blob is retractable.
     * @param blobId Id of the blob.
     * @return retractable True if the blob is blob retractable.
     */
    function getRetractable(bytes32 blobId) constant external returns (bool retractable);

    /**
     * @dev Determine if a blob is transferable.
     * @param blobId Id of the blob.
     * @return transferable True if the blob is transferable.
     */
    function getTransferable(bytes32 blobId) constant external returns (bool transferable);

    /**
     * @dev Get the owner of a blob.
     * @param blobId Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 blobId) constant external returns (address owner);

    /**
     * @dev Get the number of revisions a blob has.
     * @param blobId Id of the blob.
     * @return revisionCount How many revisions the blob has.
     */
    function getRevisionCount(bytes32 blobId) constant external returns (uint revisionCount);

}

pragma solidity ^0.4.2;

/**
 * @title AbstractBlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract AbstractBlobStore {

    /**
     * @dev Enable transfer of the blob to the current user.
     * @param blobId Id of the blob.
     */
    function transferEnable(bytes32 blobId) external;

    /**
     * @dev Disable transfer of the blob to the current user.
     * @param blobId Id of the blob.
     */
    function transferDisable(bytes32 blobId) external;

    /**
     * @dev Get the id for this BlobStore contract.
     * @return Id of the contract.
     */
    function getContractId() constant external returns (bytes12 contractId);

    /**
     * @dev Check if a blob exists.
     * @param blobId Id of the blob.
     * @return exists True if the blob exists.
     */
    function getExists(bytes32 blobId) constant external returns (bool exists);

    /**
     * @dev Get the owner of a blob.
     * @param blobId Id of the blob.
     * @return owner Owner of the blob.
     */
    function getOwner(bytes32 blobId) constant external returns (address owner);

    /**
     * @dev Get the number of revisions a blob has.
     * @param blobId Id of the blob.
     * @return revisionCount How many revisions the blob has.
     */
    function getRevisionCount(bytes32 blobId) constant external returns (uint revisionCount);

    /**
     * @dev Determine if a blob is updatable.
     * @param blobId Id of the blob.
     * @return updatable True if the blob is updatable.
     */
    function getUpdatable(bytes32 blobId) constant external returns (bool updatable);

    /**
     * @dev Determine if a blob enforces revisions.
     * @param blobId Id of the blob.
     * @return enforceRevisions True if the blob enforces revisions.
     */
    function getEnforceRevisions(bytes32 blobId) constant external returns (bool enforceRevisions);

    /**
     * @dev Determine if a blob is retractable.
     * @param blobId Id of the blob.
     * @return retractable True if the blob is blob retractable.
     */
    function getRetractable(bytes32 blobId) constant external returns (bool retractable);

    /**
     * @dev Determine if a blob is transferable.
     * @param blobId Id of the blob.
     * @return transferable True if the blob is transferable.
     */
    function getTransferable(bytes32 blobId) constant external returns (bool transferable);

}


The beneficiary parameter of claimRefund is replaced with refundee (#1481)

* signing prefix added

* Minor improvement

* Tests changed

* Successfully tested

* Minor improvements

* Minor improvements

* Revert "Dangling commas are now required. (#1359)"

This reverts commit a6889776f46adca374b6ebf014aa7b0038112a9d.

* updates

* fixes #1404

* approve failing test

* suggested changes done

* ISafeERC20 removed

* conflict fixes

* fixes #1456

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "./FinalizableCrowdsale.sol";
import "../../payment/escrow/RefundEscrow.sol";

/**
 * @title RefundableCrowdsale
 * @dev Extension of Crowdsale contract that adds a funding goal, and
 * the possibility of users getting a refund if goal is not met.
 * WARNING: note that if you allow tokens to be traded before the goal
 * is met, then an attack is possible in which the attacker purchases
 * tokens from the crowdsale and when they sees that the goal is
 * unlikely to be met, they sell their tokens (possibly at a discount).
 * The attacker will be refunded when the crowdsale is finalized, and
 * the users that purchased from them will be left with worthless
 * tokens. There are many possible ways to avoid this, like making the
 * the crowdsale inherit from PostDeliveryCrowdsale, or imposing
 * restrictions on token trading until the crowdsale is finalized.
 * This is being discussed in
 * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/877
 * This contract will be updated when we agree on a general solution
 * for this problem.
 */
contract RefundableCrowdsale is FinalizableCrowdsale {
  using SafeMath for uint256;

  // minimum amount of funds to be raised in weis
  uint256 private _goal;

  // refund escrow used to hold funds while crowdsale is running
  RefundEscrow private _escrow;

  /**
   * @dev Constructor, creates RefundEscrow.
   * @param goal Funding goal
   */
  constructor(uint256 goal) internal {
    require(goal > 0);
    _escrow = new RefundEscrow(wallet());
    _goal = goal;
  }

  /**
   * @return minimum amount of funds to be raised in wei.
   */
  function goal() public view returns(uint256) {
    return _goal;
  }

  /**
   * @dev Investors can claim refunds here if crowdsale is unsuccessful
   * @param refundee Whose refund will be claimed.
   */
  function claimRefund(address refundee) public {
    require(finalized());
    require(!goalReached());

    _escrow.withdraw(refundee);
  }

  /**
   * @dev Checks whether funding goal was reached.
   * @return Whether funding goal was reached
   */
  function goalReached() public view returns (bool) {
    return weiRaised() >= _goal;
  }

  /**
   * @dev escrow finalization task, called when finalize() is called
   */
  function _finalization() internal {
    if (goalReached()) {
      _escrow.close();
      _escrow.beneficiaryWithdraw();
    } else {
      _escrow.enableRefunds();
    }

    super._finalization();
  }

  /**
   * @dev Overrides Crowdsale fund forwarding, sending funds to escrow.
   */
  function _forwardFunds() internal {
    _escrow.deposit.value(msg.value)(msg.sender);
  }

}

pragma solidity ^0.4.24;

import "../../math/SafeMath.sol";
import "./FinalizableCrowdsale.sol";
import "../../payment/escrow/RefundEscrow.sol";

/**
 * @title RefundableCrowdsale
 * @dev Extension of Crowdsale contract that adds a funding goal, and
 * the possibility of users getting a refund if goal is not met.
 * WARNING: note that if you allow tokens to be traded before the goal
 * is met, then an attack is possible in which the attacker purchases
 * tokens from the crowdsale and when they sees that the goal is
 * unlikely to be met, they sell their tokens (possibly at a discount).
 * The attacker will be refunded when the crowdsale is finalized, and
 * the users that purchased from them will be left with worthless
 * tokens. There are many possible ways to avoid this, like making the
 * the crowdsale inherit from PostDeliveryCrowdsale, or imposing
 * restrictions on token trading until the crowdsale is finalized.
 * This is being discussed in
 * https://github.com/OpenZeppelin/openzeppelin-solidity/issues/877
 * This contract will be updated when we agree on a general solution
 * for this problem.
 */
contract RefundableCrowdsale is FinalizableCrowdsale {
  using SafeMath for uint256;

  // minimum amount of funds to be raised in weis
  uint256 private _goal;

  // refund escrow used to hold funds while crowdsale is running
  RefundEscrow private _escrow;

  /**
   * @dev Constructor, creates RefundEscrow.
   * @param goal Funding goal
   */
  constructor(uint256 goal) internal {
    require(goal > 0);
    _escrow = new RefundEscrow(wallet());
    _goal = goal;
  }

  /**
   * @return minimum amount of funds to be raised in wei.
   */
  function goal() public view returns(uint256) {
    return _goal;
  }

  /**
   * @dev Investors can claim refunds here if crowdsale is unsuccessful
   * @param beneficiary Whose refund will be claimed.
   */
  function claimRefund(address beneficiary) public {
    require(finalized());
    require(!goalReached());

    _escrow.withdraw(beneficiary);
  }

  /**
   * @dev Checks whether funding goal was reached.
   * @return Whether funding goal was reached
   */
  function goalReached() public view returns (bool) {
    return weiRaised() >= _goal;
  }

  /**
   * @dev escrow finalization task, called when finalize() is called
   */
  function _finalization() internal {
    if (goalReached()) {
      _escrow.close();
      _escrow.beneficiaryWithdraw();
    } else {
      _escrow.enableRefunds();
    }

    super._finalization();
  }

  /**
   * @dev Overrides Crowdsale fund forwarding, sending funds to escrow.
   */
  function _forwardFunds() internal {
    _escrow.deposit.value(msg.value)(msg.sender);
  }

}


Add revisioning.

Add revisioning.

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    mapping (bytes32 => bytes32) blobInfo;      // Block number and user.

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;
    event logRetraction(bytes32 indexed hash) anonymous;

    modifier isOwner(bytes32 hash) {
        if (address(blobInfo[hash] & (2**160)) == msg.sender) {
            throw;
        }
        _
    }

    /**
     * @dev Stores a blob in the transaction log. It is guaranteed that each user will get a different hash when storing the same blob.
     * @param blob Blob that should be stored.
     * @return hash Hash of sender and blob.
     */
    function storeBlob(bytes blob) external returns (bytes32 hash) {
        // Calculate the hash.
        hash = sha3(msg.sender, blob);
        // Store the blob owner and block number in state.
        blobInfo[hash] = bytes32(block.number * (2**208)) | bytes32(msg.sender);
        // Store the blob in a log in the current block.
        logBlob(hash, blob);
    }

    function updateBlob(bytes32 hash, bytes blob) isOwner(hash) external {
        // Update block number in state.
        blobInfo[hash] = bytes32(block.number * (2**208)) | bytes32(msg.sender);
        // Store the new blob in a log in the current block.
        logBlob(hash, blob);
    }

    function retractBlob(bytes32 hash) isOwner(hash) external {
        // Get a refund for the storage slot.
        delete blobInfo[hash];
        // Log the retraction.
        logRetraction(hash);
    }

    function getBlobInfo(bytes32 hash) constant external returns (address owner, uint256 blockNumber) {
        owner = address(blobInfo[hash] & ((2**208) - 1));
        blockNumber = uint256(blobInfo[hash]) / (2**208);
    }

    function() {
        throw;      // Do not maintain an ether balance.
    }

}

/**
 * @title BlobStore
 * @author Jonathan Brown <jbrown@bluedroplet.com>
 */
contract BlobStore {

    event logBlob(bytes32 indexed hash, bytes blob) anonymous;

    /**
     * @dev Stores a blob in the transaction log. It is guaranteed that each user will get a different hash when storing the same blob.
     * @param blob Blob that should be stored.
     * @return hash Hash of sender and blob.
     */
    function storeBlob(bytes blob) external returns (bytes32 hash) {
        // Calculate the hash.
        hash = sha3(msg.sender, blob);
        // Store the blob in a log in the current block.
        logBlob(hash, blob);
    }

    function() {
        throw;      // Do not maintain an ether balance.
    }

}


updated comments

updated comments

pragma solidity ^0.4.10;
import './BancorEventsDispatcher.sol';
import './TokenChangerInterface.sol';
import './SmartTokenInterface.sol';
import './SafeMath.sol';

/*
    Open issues:
    - all values are placeholders, need to update them with real values
    - verify ERC20 token addresses, transferFrom (must return a boolean flag) and update them with the correct values
*/

// interfaces

contract EtherToken {
    function deposit() public payable returns (bool success);
    function transfer(address _to, uint256 _value) public returns (bool success);
}

/*
    Crowdsale Changer v0.1

    The crowdsale version of the token changer, allows buying the smart token with ether/other ERC20 tokens
*/
contract CrowdsaleChanger is BancorEventsDispatcher, TokenChangerInterface, SafeMath {
    struct ERC20TokenData {
        uint256 valueN;     // 1 smallest unit in wei (numerator)
        uint256 valueD;     // 1 smallest unit in wei (denominator)
        uint16 limit;       // maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000, 0 to disable
        bool isEnabled;     // is purchase of the smart token enabled with the ERC20 token, can be set by the owner
        bool isSet;         // used to tell if the mapping element is defined
    }

    uint256 public constant DURATION = 30 days;                     // crowdsale duration
    uint256 public constant ETHER_CAP = 1000000 ether;              // maximum ether contribution
    uint256 public constant BITCOIN_SUISSE_ETHER_CAP = 20000 ether; // maximum bitcoin suisse ether contribution
    uint256 public constant INITIAL_PRICE_N = 1;                    // initial price in wei (numerator)
    uint256 public constant INITIAL_PRICE_D = 100;                  // initial price in wei (denominator)
    uint8 public constant RESERVE_RATIO = 21;                       // constant reserve ratio for the new token, used to calculate the current price
    uint8 public constant BENEFICIARY_PERCENTAGE = 30;              // percentage out of the total supply that should be issued to the beneficiary

    // phases
    uint256 public constant PHASE1_MIN_CONTRIBUTION = 0 ether;
    uint256 public constant PHASE2_MIN_CONTRIBUTION = 100000 ether;
    uint256 public constant PHASE3_MIN_CONTRIBUTION = 300000 ether;
    // % of contribution allocated to the reserve
    uint8 public constant PHASE1_RESERVE_ALLOCATION = 30;
    uint8 public constant PHASE2_RESERVE_ALLOCATION = 50;
    uint8 public constant PHASE3_RESERVE_ALLOCATION = 70;

    string public version = '0.1';
    string public changerType = 'crowdsale';

    uint256 public startTime = 0;                           // crowdsale start time (in seconds)
    uint256 public endTime = 0;                             // crowdsale end time (in seconds)
    uint256 public etherContributed = 0;                    // ether contributed so far
    uint256 public tokenReserveBalance = 0;                 // amount of the ether contributed so far that gets into the smart token's reserve, used to calculate the current price
    address public etherToken = 0x0;                        // ether token contract address
    address public beneficiary = 0x0;                       // address to receive all contributed ether
    address public bitcoinSuisse = 0x0;                     // bitcoin suisse address
    SmartTokenInterface public token;                       // smart token governed by the changer
    bool public isActive = false;                           // true if the crowdsale functionality can be used, false if not
    address[] public acceptedTokens;                        // ERC20 standard token addresses
    mapping (address => ERC20TokenData) public tokenData;   // ERC20 token addresses -> ERC20 token data

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Change(address indexed _fromToken, address indexed _toToken, address indexed _trader, uint256 _amount, uint256 _return);

    /*
        _token          smart token governed by the changer
        _etherToken     ether token contract address
        _startTime      crowdsale start time
        _beneficiary    address to receive all contributed ether
        _bitcoinSuisse  bitcoin suisse address
        _events         optional, address of a bancor events contract
    */
    function CrowdsaleChanger(address _token, address _etherToken, uint256 _startTime, address _beneficiary, address _bitcoinSuisse, address _events)
        BancorEventsDispatcher(_events)
        validAddress(_token)
        validAddress(_etherToken)
        validAddress(_beneficiary)
        validAddress(_bitcoinSuisse)
        earlierThan(_startTime)
    {
        token = SmartTokenInterface(_token);
        etherToken = _etherToken;
        startTime = _startTime;
        endTime = startTime + DURATION;
        beneficiary = _beneficiary;
        bitcoinSuisse = _bitcoinSuisse;

        addERC20Token(_etherToken, 0, 1, 1); // Ether

        addERC20Token(0xa74476443119A942dE498590Fe1f2454d7D4aC0d, 20, 1, 1); // Golem
        addERC20Token(0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5, 20, 1, 1); // Augur

        addERC20Token(0x6810e776880C02933D47DB1b9fc05908e5386b96, 10, 1, 1); // Gnosis
        addERC20Token(0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009, 10, 1, 1); // SingularDTV
        addERC20Token(0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A, 10, 1, 1); // DigixDAO

        addERC20Token(0x4993CB95c7443bdC06155c5f5688Be9D8f6999a5, 5, 1, 1); // ROUND
        addERC20Token(0x607F4C5BB672230e8672085532f7e901544a7375, 5, 1, 1); // iEx.ec
        addERC20Token(0x888666CA69E0f178DED6D75b5726Cee99A87D698, 5, 1, 1); // ICONOMI
        addERC20Token(0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7, 5, 1, 1); // FirstBlood
        addERC20Token(0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1, 5, 1, 1); // Melon
        addERC20Token(0x667088b212ce3d06a1b553a7221E1fD19000d9aF, 5, 1, 1); // Wings
    }

    // validates an address - currently only checks that it isn't null
    modifier validAddress(address _address) {
        require(_address != 0x0);
        _;
    }

    // validates an ERC20 token address - verifies that the address belongs to one of the ERC20 tokens
    modifier validERC20Token(address _address) {
        require(tokenData[_address].isSet);
        _;
    }

    // validates a token address - verifies that the address belongs to one of the changable tokens
    modifier validToken(address _address) {
        require(_address == address(token) || tokenData[_address].isSet);
        _;
    }

    // validates ERC20 token limit
    modifier validERC20TokenLimit(uint16 _limit) {
        require(_limit <= 1000);
        _;
    }

    // ensures that the contract is active
    modifier active() {
        assert(isActive);
        _;
    }

    // ensures that the contract is not active
    modifier inactive() {
        assert(!isActive);
        _;
    }

    // ensures that it's earlier than the given time
    modifier earlierThan(uint256 _time) {
        assert(now < _time);
        _;
    }

    // ensures that it's later than the given time
    modifier laterThan(uint256 _time) {
        assert(now > _time);
        _;
    }

    // ensures that we didn't reach the ether cap
    modifier etherCapNotReached() {
        assert(etherContributed < ETHER_CAP);
        _;
    }

    // ensures that the sender is bitcoin suisse
    modifier bitcoinSuisseOnly() {
        assert(msg.sender == bitcoinSuisse);
        _;
    }

    // ensures that we didn't reach the ether cap
    modifier bitcoinSuisseEtherCapNotReached() {
        assert(etherContributed < BITCOIN_SUISSE_ETHER_CAP);
        _;
    }

    /*
        returns the number of changeable tokens supported by the contract
        note that the number of changable tokens is the number of ERC20 tokens plus the smart token
    */
    function changeableTokenCount() public constant returns (uint16 count) {
        return uint16(acceptedTokens.length + 1);
    }

    /*
        given a changable token index, returns the changable token contract address
    */
    function changeableToken(uint16 _tokenIndex) public constant returns (address tokenAddress) {
        if (_tokenIndex == 0)
            return token;
        return acceptedTokens[_tokenIndex - 1];
    }

    /*
        defines a new ERC20 token
        can only be called by the changer owner while the changer is inactive

        _token      address of the ERC20 token
        _limit      maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000
        _valueN     1 smallest unit in wei (numerator)
        _valueD     1 smallest unit in wei (denominator)
    */
    function addERC20Token(address _token, uint16 _limit, uint256 _valueN, uint256 _valueD)
        public
        ownerOnly
        inactive
        validAddress(_token)
        validERC20TokenLimit(_limit)
        returns (bool success)
    {
        require(_token != address(this) && _token != address(token) && !tokenData[_token].isSet && _valueN != 0 && _valueD != 0); // validate input

        tokenData[_token].limit = _limit;
        tokenData[_token].valueN = _valueN;
        tokenData[_token].valueD = _valueD;
        tokenData[_token].isEnabled = true;
        tokenData[_token].isSet = true;
        acceptedTokens.push(_token);
        return true;
    }

    /*
        updates one of the ERC20 tokens
        can only be called by the changer owner

        _erc20Token     address of the ERC20 token
        _limit          maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000
        _valueN         1 smallest unit in wei (numerator)
        _valueD         1 smallest unit in wei (denominator)
    */
    function updateERC20Token(address _erc20Token, uint16 _limit, uint256 _valueN, uint256 _valueD)
        public
        ownerOnly
        validERC20Token(_erc20Token)
        validERC20TokenLimit(_limit)
        returns (bool success)
    {
        require(_valueN != 0 && _valueD != 0); // validate input
        ERC20TokenData data = tokenData[_erc20Token];
        data.limit = _limit;
        data.valueN = _valueN;
        data.valueD = _valueD;
        return true;
    }

    /*
        disables purchasing with the given ERC20 token in case the token got compromised
        can only be called by the changer owner

        _erc20Token     ERC20 token contract address
        _disable        true to disable the token, false to re-enable it
    */
    function disableERC20Token(address _erc20Token, bool _disable)
        public
        ownerOnly
        validERC20Token(_erc20Token)
    {
        tokenData[_erc20Token].isEnabled = !_disable;
    }

    /*
        withdraws tokens from one of the ERC20 tokens and sends them to an account
        can only be called by the changer owner
        this is a mechanism to allow the owner to return tokens that were sent directly to this contract by mistake

        _erc20Token     ERC20 token contract address
        _to             account to receive the new amount
        _amount         amount to withdraw (in the ERC20 token)
    */
    function withdraw(address _erc20Token, address _to, uint256 _amount)
        public
        ownerOnly
        validERC20Token(_erc20Token)
        validAddress(_to)
        returns (bool success)
    {
        require(_to != address(this) && _to != address(token) && _amount != 0); // validate input

        ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
        assert(erc20Token.transfer(_to, _amount));
        return true;
    }

    /*
        sets the smart token's changer address to a different one instead of the current contract address
        can only be called by the owner
        the changer can be set to null to transfer ownership from the changer to the original smart token's owner

        _changer    new changer contract address (can also be set to 0x0 to remove the current changer)
    */
    function setTokenChanger(address _changer)
        public
        ownerOnly
        validAddress(_changer)
        returns (bool success)
    {
        require(_changer != address(this) && _changer != address(token)); // validate input
        return token.setChanger(_changer);
    }

    /*
        activates/deactivates the contract logic
        can only be called by the owner
        activating the change logic also disables transfers in the smart token
        this can also be used as an emergency stop

        _activate   true to activate the contract, false to deactivate it
    */
    function activate(bool _activate) public ownerOnly returns (bool success)
    {
        assert(!_activate || acceptedTokens.length > 0); // validate state
        if (_activate)
            token.disableTransfers(true);

        isActive = _activate;
        return true;
    }

    /*
        returns the expected return for changing a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
    */
    function getReturn(address _fromToken, address _toToken, uint256 _amount) public constant returns (uint256 amount) {
        require(_toToken == address(token)); // validate input
        return getPurchaseReturn(_fromToken, _amount);
    }

    /*
        returns the expected return for buying the token for an ERC20 token

        _erc20Token     ERC20 token contract address
        _depositAmount  amount to deposit (in the ERC20 token)
    */
    function getPurchaseReturn(address _erc20Token, uint256 _depositAmount)
        public
        constant
        active
        etherCapNotReached
        validERC20Token(_erc20Token)
        returns (uint256 amount)
    {
        ERC20TokenData data = tokenData[_erc20Token];
        require(data.isEnabled && _depositAmount != 0); // validate input

        uint256 depositEthValue = safeMul(_depositAmount, data.valueN) / data.valueD;
        if (depositEthValue == 0)
            return 0;

        // check ether cap
        require(safeAdd(etherContributed, depositEthValue) <= ETHER_CAP);

        // check limit
        if (data.limit != 0) {
            ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
            uint256 balance = erc20Token.balanceOf(beneficiary);
            uint256 balanceEthValue = safeMul(balance, data.valueN) / data.valueD;  // ether value of the ERC20 token beneficiary balance
            uint256 limit = safeMul(etherContributed, data.limit) / 1000; // current limit of the ERC20 token
            require(safeAdd(balanceEthValue, depositEthValue) <= limit);
        }

        // first contribution can't use the simplified bancor formula, so using the predefined initial price instead
        if (tokenReserveBalance == 0 || token.totalSupply() == 0)
            return safeMul(depositEthValue, INITIAL_PRICE_D) / INITIAL_PRICE_N;

        // using the simplified bancor formula -
        // Price = Reserve / (Supply * CRR)
        uint256 temp = safeMul(depositEthValue, token.totalSupply());
        temp = safeMul(temp, RESERVE_RATIO);
        return temp / 100 / tokenReserveBalance;
    }

    /*
        changes a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
        _minReturn  if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function change(address _fromToken, address _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256 amount) {
        require(_toToken == address(token)); // validate input
        return buyERC20(_fromToken, _amount, _minReturn);
    }

    /*
        buys the token with one of the ERC20 tokens
        requires the called to approve and allowance for the crowdsale contract

        _erc20Token     ERC20 token contract address
        _depositAmount  amount to deposit (in the ERC20 token)
        _minReturn      if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function buyERC20(address _erc20Token, uint256 _depositAmount, uint256 _minReturn)
        public
        laterThan(startTime)
        earlierThan(endTime)
        returns (uint256 amount)
    {
        amount = getPurchaseReturn(_erc20Token, _depositAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
        assert(erc20Token.transferFrom(msg.sender, beneficiary, _depositAmount)); // transfer _depositAmount funds from the caller in the ERC20 token

        ERC20TokenData data = tokenData[_erc20Token];
        uint256 depositEthValue = safeMul(_depositAmount, data.valueN) / data.valueD;
        handleContribution(msg.sender, depositEthValue, amount);
        dispatchChange(_erc20Token, token, msg.sender, _depositAmount, amount);
        return amount;
    }

    /*
        buys the token with ETH
    */
    function buyETH()
        public
        payable
        laterThan(startTime)
        earlierThan(endTime)
        returns (uint256 amount)
    {
        amount = handleETHDeposit(msg.sender, msg.value);
        dispatchChange(etherToken, token, msg.sender, msg.value, amount);
        return amount;
    }

    /*
        buys the token with BTCs (Bitcoin Suisse only)
        can only be called before the crowdsale started

        _contributor    account that should receive the new tokens
    */
    function buyBitcoinSuisse(address _contributor)
        public
        payable
        bitcoinSuisseOnly
        bitcoinSuisseEtherCapNotReached
        earlierThan(startTime)
        returns (uint256 amount)
    {
        require(safeAdd(etherContributed, msg.value) <= BITCOIN_SUISSE_ETHER_CAP); // validate input
        amount = handleETHDeposit(_contributor, msg.value);
        dispatchChange(etherToken, token, msg.sender, msg.value, amount);
        return amount;
    }

    /*
        handles direct ETH deposits (as opposed to ERC20 contributions)

        _contributor    account that should receive the new tokens
        _depositAmount  amount contributed by the account, in wei
    */
    function handleETHDeposit(address _contributor, uint256 _depositAmount) private returns (uint256 amount) {
        require(_depositAmount > 0); // validate input
        amount = getPurchaseReturn(etherToken, _depositAmount);
        assert(amount != 0); // ensure the trade gives something in return

        EtherToken ethToken = EtherToken(etherToken);
        assert(ethToken.deposit.value(_depositAmount)()); // transfer the ether to the ether contract
        assert(ethToken.transfer(beneficiary, _depositAmount)); // transfer the ther to the beneficiary account
        handleContribution(_contributor, _depositAmount, amount);
        return amount;
    }

    /*
        handles the generic part of the contribution - regardless of the type of contribution
        assumes that the contribution was already added to the beneficiary account in the different tokens
        updates the reserve balance, total contributed amount and issues new tokens to the contributor and to the beneficiary

        _contributor        account that should the new tokens
        _depositEthValue    amount contributed by the account, in wei
        _return             amount to be issued to the contributor, in the smart token
    */
    function handleContribution(address _contributor, uint256 _depositEthValue, uint256 _return) private {
        // update the reserve balance
        uint8 reserveAllocationPercentage;
        if (etherContributed >= PHASE3_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE3_RESERVE_ALLOCATION;
        else if (etherContributed >= PHASE2_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE2_RESERVE_ALLOCATION;
        else if (etherContributed >= PHASE1_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE1_RESERVE_ALLOCATION;

        uint256 addToReserve = safeMul(_depositEthValue, reserveAllocationPercentage) / 100;
        tokenReserveBalance = safeAdd(tokenReserveBalance, addToReserve);

        // update the total contribution amount
        etherContributed = safeAdd(etherContributed, _depositEthValue);
        // issue new funds to the contributor in the smart token
        assert(token.issue(_contributor, _return));

        // issued tokens to the beneficiary
        uint256 amount = safeMul(100, _return) / BENEFICIARY_PERCENTAGE;
        if (amount == 0)
            return;

        assert(token.issue(beneficiary, amount));
    }

    // utility

    function dispatchChange(address _fromToken, address _toToken, address _trader, uint256 _amount, uint256 _return) private {
        Change(_fromToken, _toToken, _trader, _amount, _return);

        if (address(events) != 0x0)
            events.tokenChange(_fromToken, _toToken, _trader, _amount, _return);
    }

    // fallback
    function() payable {
        buyETH();
    }
}

pragma solidity ^0.4.10;
import './BancorEventsDispatcher.sol';
import './TokenChangerInterface.sol';
import './SmartTokenInterface.sol';
import './SafeMath.sol';

/*
    Open issues:
    - all values are placeholders, need to update them with real values
    - verify ERC20 token addresses, transferFrom (must return a boolean flag) and update them with the correct values
*/

// interfaces

contract EtherToken {
    function deposit() public payable returns (bool success);
    function transfer(address _to, uint256 _value) public returns (bool success);
}

/*
    Crowdsale Changer v0.1

    The crowdsale version of the token changer, allows buying the smart token with ether/other ERC20 tokens
*/
contract CrowdsaleChanger is BancorEventsDispatcher, TokenChangerInterface, SafeMath {
    struct ERC20TokenData {
        uint256 valueN;     // 1 smallest unit in wei (numerator)
        uint256 valueD;     // 1 smallest unit in wei (denominator)
        uint16 limit;       // maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000, 0 to disable
        bool isEnabled;     // is purchase of the smart token enabled with the ERC20 token, can be set by the owner
        bool isSet;         // used to tell if the mapping element is defined
    }

    uint256 public constant DURATION = 30 days;                     // crowdsale duration
    uint256 public constant ETHER_CAP = 1000000 ether;              // maximum ether contribution
    uint256 public constant BITCOIN_SUISSE_ETHER_CAP = 20000 ether; // maximum bitcoin suisse ether contribution
    uint256 public constant INITIAL_PRICE_N = 1;                    // initial price in wei (numerator)
    uint256 public constant INITIAL_PRICE_D = 100;                  // initial price in wei (denominator)
    uint8 public constant RESERVE_RATIO = 21;                       // constant reserve ratio for the new token, used to calculate the current price
    uint8 public constant BENEFICIARY_PERCENTAGE = 30;              // percentage out of the total supply that should be issued to the beneficiary

    // phases
    uint256 public constant PHASE1_MIN_CONTRIBUTION = 0 ether;
    uint256 public constant PHASE2_MIN_CONTRIBUTION = 100000 ether;
    uint256 public constant PHASE3_MIN_CONTRIBUTION = 300000 ether;
    // % of contribution allocated to the reserve
    uint8 public constant PHASE1_RESERVE_ALLOCATION = 30;
    uint8 public constant PHASE2_RESERVE_ALLOCATION = 50;
    uint8 public constant PHASE3_RESERVE_ALLOCATION = 70;

    string public version = '0.1';
    string public changerType = 'crowdsale';

    uint256 public startTime = 0;                           // crowdsale start time (in seconds)
    uint256 public endTime = 0;                             // crowdsale end time (in seconds)
    uint256 public etherContributed = 0;                    // ether contributed so far
    uint256 public tokenReserveBalance = 0;                 // amount of the ether contributed so far that gets into the smart token's reserve, used to calculate the current price
    address public etherToken = 0x0;                        // ether token contract address
    address public beneficiary = 0x0;                       // address to receive all contributed ether
    address public bitcoinSuisse = 0x0;                     // bitcoin suisse address
    SmartTokenInterface public token;                       // smart token governed by the changer
    bool public isActive = false;                           // true if the crowdsale functionality can be used, false if not
    address[] public acceptedTokens;                        // ERC20 standard token addresses
    mapping (address => ERC20TokenData) public tokenData;   // ERC20 token addresses -> ERC20 token data

    // events, can be used to listen to the contract directly, as opposed to through the events contract
    event Change(address indexed _fromToken, address indexed _toToken, address indexed _trader, uint256 _amount, uint256 _return);

    /*
        _token          smart token governed by the changer
        _etherToken     ether token contract address
        _startTime      crowdsale start time
        _beneficiary    address to receive all contributed ether
        _bitcoinSuisse  bitcoin suisse address
        _events         optional, address of a bancor events contract
    */
    function CrowdsaleChanger(address _token, address _etherToken, uint256 _startTime, address _beneficiary, address _bitcoinSuisse, address _events)
        BancorEventsDispatcher(_events)
        validAddress(_token)
        validAddress(_etherToken)
        validAddress(_beneficiary)
        validAddress(_bitcoinSuisse)
        earlierThan(_startTime)
    {
        token = SmartTokenInterface(_token);
        etherToken = _etherToken;
        startTime = _startTime;
        endTime = startTime + DURATION;
        beneficiary = _beneficiary;
        bitcoinSuisse = _bitcoinSuisse;

        addERC20Token(_etherToken, 0, 1, 1); // Ether

        addERC20Token(0xa74476443119A942dE498590Fe1f2454d7D4aC0d, 20, 1, 1); // Golem
        addERC20Token(0x48c80F1f4D53D5951e5D5438B54Cba84f29F32a5, 20, 1, 1); // Augur

        addERC20Token(0x6810e776880C02933D47DB1b9fc05908e5386b96, 10, 1, 1); // Gnosis
        addERC20Token(0xaeC2E87E0A235266D9C5ADc9DEb4b2E29b54D009, 10, 1, 1); // SingularDTV
        addERC20Token(0xE0B7927c4aF23765Cb51314A0E0521A9645F0E2A, 10, 1, 1); // DigixDAO

        addERC20Token(0x4993CB95c7443bdC06155c5f5688Be9D8f6999a5, 5, 1, 1); // ROUND
        addERC20Token(0x607F4C5BB672230e8672085532f7e901544a7375, 5, 1, 1); // iEx.ec
        addERC20Token(0x888666CA69E0f178DED6D75b5726Cee99A87D698, 5, 1, 1); // ICONOMI
        addERC20Token(0xAf30D2a7E90d7DC361c8C4585e9BB7D2F6f15bc7, 5, 1, 1); // FirstBlood
        addERC20Token(0xBEB9eF514a379B997e0798FDcC901Ee474B6D9A1, 5, 1, 1); // Melon
        addERC20Token(0x667088b212ce3d06a1b553a7221E1fD19000d9aF, 5, 1, 1); // Wings
    }

    // validates an address - currently only checks that it isn't null
    modifier validAddress(address _address) {
        require(_address != 0x0);
        _;
    }

    // validates an ERC20 token address - verifies that the address belongs to one of the ERC20 tokens
    modifier validERC20Token(address _address) {
        require(tokenData[_address].isSet);
        _;
    }

    // validates a token address - verifies that the address belongs to one of the changable tokens
    modifier validToken(address _address) {
        require(_address == address(token) || tokenData[_address].isSet);
        _;
    }

    // validates ERC20 token limit
    modifier validERC20TokenLimit(uint16 _limit) {
        require(_limit <= 1000);
        _;
    }

    // ensures that the contract is active
    modifier active() {
        assert(isActive);
        _;
    }

    // ensures that the contract is not active
    modifier inactive() {
        assert(!isActive);
        _;
    }

    // ensures that it's earlier than the given time
    modifier earlierThan(uint256 _time) {
        assert(now < _time);
        _;
    }

    // ensures that it's later than the given time
    modifier laterThan(uint256 _time) {
        assert(now > _time);
        _;
    }

    // ensures that we didn't reach the ether cap
    modifier etherCapNotReached() {
        assert(etherContributed < ETHER_CAP);
        _;
    }

    // ensures that the sender is bitcoin suisse
    modifier bitcoinSuisseOnly() {
        assert(msg.sender == bitcoinSuisse);
        _;
    }

    // ensures that we didn't reach the ether cap
    modifier bitcoinSuisseEtherCapNotReached() {
        assert(etherContributed < BITCOIN_SUISSE_ETHER_CAP);
        _;
    }

    /*
        returns the number of changeable tokens supported by the contract
        note that the number of changable tokens is the number of ERC20 tokens plus the smart token
    */
    function changeableTokenCount() public constant returns (uint16 count) {
        return uint16(acceptedTokens.length + 1);
    }

    /*
        given a changable token index, returns the changable token contract address
    */
    function changeableToken(uint16 _tokenIndex) public constant returns (address tokenAddress) {
        if (_tokenIndex == 0)
            return token;
        return acceptedTokens[_tokenIndex - 1];
    }

    /*
        defines a new ERC20 token
        can only be called by the changer owner while the changer is inactive

        _token      address of the ERC20 token
        _limit      maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000
        _valueN     1 smallest unit in wei (numerator)
        _valueD     1 smallest unit in wei (denominator)
    */
    function addERC20Token(address _token, uint16 _limit, uint256 _valueN, uint256 _valueD)
        public
        ownerOnly
        inactive
        validAddress(_token)
        validERC20TokenLimit(_limit)
        returns (bool success)
    {
        require(_token != address(this) && _token != address(token) && !tokenData[_token].isSet && _valueN != 0 && _valueD != 0); // validate input

        tokenData[_token].limit = _limit;
        tokenData[_token].valueN = _valueN;
        tokenData[_token].valueD = _valueD;
        tokenData[_token].isEnabled = true;
        tokenData[_token].isSet = true;
        acceptedTokens.push(_token);
        return true;
    }

    /*
        updates one of the ERC20 tokens
        can only be called by the changer owner

        _erc20Token     address of the ERC20 token
        _limit          maximum contribution in percentage out of the total ETH raised so far. 1-1000 (10 == 1%), divided by 1000
        _valueN         1 smallest unit in wei (numerator)
        _valueD         1 smallest unit in wei (denominator)
    */
    function updateERC20Token(address _erc20Token, uint16 _limit, uint256 _valueN, uint256 _valueD)
        public
        ownerOnly
        validERC20Token(_erc20Token)
        validERC20TokenLimit(_limit)
        returns (bool success)
    {
        require(_valueN != 0 && _valueD != 0); // validate input
        ERC20TokenData data = tokenData[_erc20Token];
        data.limit = _limit;
        data.valueN = _valueN;
        data.valueD = _valueD;
        return true;
    }

    /*
        disables purchasing with the given ERC20 token in case the token got compromised
        can only be called by the changer owner

        _erc20Token     ERC20 token contract address
        _disable        true to disable the token, false to re-enable it
    */
    function disableERC20Token(address _erc20Token, bool _disable)
        public
        ownerOnly
        validERC20Token(_erc20Token)
    {
        tokenData[_erc20Token].isEnabled = !_disable;
    }

    /*
        withdraws tokens from one of the ERC20 tokens and sends them to an account
        can only be called by the changer owner
        this is a mechanism to allow the owner to return tokens that were sent directly to this contract by mistake

        _erc20Token     ERC20 token contract address
        _to             account to receive the new amount
        _amount         amount to withdraw (in the ERC20 token)
    */
    function withdraw(address _erc20Token, address _to, uint256 _amount)
        public
        ownerOnly
        validERC20Token(_erc20Token)
        validAddress(_to)
        returns (bool success)
    {
        require(_to != address(this) && _to != address(token) && _amount != 0); // validate input

        ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
        assert(erc20Token.transfer(_to, _amount));
        return true;
    }

    /*
        sets the smart token's changer address to a different one instead of the current contract address
        can only be called by the owner
        the changer can be set to null to transfer ownership from the changer to the original smart token's owner

        _changer    new changer contract address (can also be set to 0x0 to remove the current changer)
    */
    function setTokenChanger(address _changer)
        public
        ownerOnly
        validAddress(_changer)
        returns (bool success)
    {
        require(_changer != address(this) && _changer != address(token)); // validate input
        return token.setChanger(_changer);
    }

    /*
        activates/deactivates the contract logic
        can only be called by the owner
        activating the change logic also disables transfers in the smart token
        this can also be used as an emergency stop

        _activate   true to activate the contract, false to deactivate it
    */
    function activate(bool _activate) public ownerOnly returns (bool success)
    {
        assert(!_activate || acceptedTokens.length > 0); // validate state
        if (_activate)
            token.disableTransfers(true);

        isActive = _activate;
        return true;
    }

    /*
        returns the expected return for changing a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
    */
    function getReturn(address _fromToken, address _toToken, uint256 _amount) public constant returns (uint256 amount) {
        require(_toToken == address(token)); // validate input
        return getPurchaseReturn(_fromToken, _amount);
    }

    /*
        returns the expected return for buying the token for an ERC20 token

        _erc20Token     ERC20 token contract address
        _depositAmount  amount to deposit (in the ERC20 token)
    */
    function getPurchaseReturn(address _erc20Token, uint256 _depositAmount)
        public
        constant
        active
        etherCapNotReached
        validERC20Token(_erc20Token)
        returns (uint256 amount)
    {
        ERC20TokenData data = tokenData[_erc20Token];
        require(data.isEnabled && _depositAmount != 0); // validate input

        uint256 depositEthValue = safeMul(_depositAmount, data.valueN) / data.valueD;
        if (depositEthValue == 0)
            return 0;

        // check ether cap
        require(safeAdd(etherContributed, depositEthValue) <= ETHER_CAP);

        // check limit
        if (data.limit != 0) {
            ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
            uint256 balance = erc20Token.balanceOf(beneficiary);
            uint256 balanceEthValue = safeMul(balance, data.valueN) / data.valueD;  // ether value of the ERC20 token beneficiary balance
            uint256 limit = safeMul(etherContributed, data.limit) / 1000; // current limit of the ERC20 token
            require(safeAdd(balanceEthValue, depositEthValue) <= limit);
        }

        // first contribution can't use the simplified bancor formula, so using the predefined initial price instead
        if (tokenReserveBalance == 0 || token.totalSupply() == 0)
            return safeMul(depositEthValue, INITIAL_PRICE_D) / INITIAL_PRICE_N;

        // using the simplified bancor formula -
        // Price = Reserve / (Supply * CRR)
        uint256 temp = safeMul(depositEthValue, token.totalSupply());
        temp = safeMul(temp, RESERVE_RATIO);
        return temp / 100 / tokenReserveBalance;
    }

    /*
        changes a specific amount of _fromToken to _toToken

        _fromToken  token to change from
        _toToken    token to change to
        _amount     amount to change, in fromToken
        _minReturn  if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function change(address _fromToken, address _toToken, uint256 _amount, uint256 _minReturn) public returns (uint256 amount) {
        require(_toToken == address(token)); // validate input
        return buyERC20(_fromToken, _amount, _minReturn);
    }

    /*
        buys the token with one of the ERC20 tokens
        requires the called to approve and allowance for the crowdsale contract

        _erc20Token     ERC20 token contract address
        _depositAmount  amount to deposit (in the ERC20 token)
        _minReturn      if the change results in an amount smaller than the minimum return, it is cancelled
    */
    function buyERC20(address _erc20Token, uint256 _depositAmount, uint256 _minReturn)
        public
        laterThan(startTime)
        earlierThan(endTime)
        returns (uint256 amount)
    {
        amount = getPurchaseReturn(_erc20Token, _depositAmount);
        assert(amount != 0 && amount >= _minReturn); // ensure the trade gives something in return and meets the minimum requested amount

        ERC20TokenInterface erc20Token = ERC20TokenInterface(_erc20Token);
        assert(erc20Token.transferFrom(msg.sender, beneficiary, _depositAmount)); // transfer _depositAmount funds from the caller in the ERC20 token

        ERC20TokenData data = tokenData[_erc20Token];
        uint256 depositEthValue = safeMul(_depositAmount, data.valueN) / data.valueD;
        handleContribution(msg.sender, depositEthValue, amount);
        dispatchChange(_erc20Token, token, msg.sender, _depositAmount, amount);
        return amount;
    }

    /*
        buys the token with ETH
    */
    function buyETH()
        public
        payable
        laterThan(startTime)
        earlierThan(endTime)
        returns (uint256 amount)
    {
        amount = handleETHDeposit(msg.sender, msg.value);
        dispatchChange(etherToken, token, msg.sender, msg.value, amount);
        return amount;
    }

    /*
        buys the token with BTCs (Bitcoin Suisse only)

        _contributor    account that should receive the new tokens
    */
    function buyBitcoinSuisse(address _contributor)
        public
        payable
        bitcoinSuisseOnly
        bitcoinSuisseEtherCapNotReached
        earlierThan(startTime)
        returns (uint256 amount)
    {
        require(safeAdd(etherContributed, msg.value) <= BITCOIN_SUISSE_ETHER_CAP); // validate input
        amount = handleETHDeposit(_contributor, msg.value);
        dispatchChange(etherToken, token, msg.sender, msg.value, amount);
        return amount;
    }

    /*
        handles direct ETH deposits (as opposed to ERC20 contributions)

        _contributor    account that should receive the new tokens
        _depositAmount  amount contributed by the account, in wei
    */
    function handleETHDeposit(address _contributor, uint256 _depositAmount) private returns (uint256 amount) {
        require(_depositAmount > 0); // validate input
        amount = getPurchaseReturn(etherToken, _depositAmount);
        assert(amount != 0); // ensure the trade gives something in return

        EtherToken ethToken = EtherToken(etherToken);
        assert(ethToken.deposit.value(_depositAmount)()); // transfer the ether to the ether contract
        assert(ethToken.transfer(beneficiary, _depositAmount)); // transfer the ther to the beneficiary account
        handleContribution(_contributor, _depositAmount, amount);
        return amount;
    }

    /*
        handles the generic part of the contribution - regardless of the type of contribution
        assumes that the contribution was already added to the beneficiary account in the different tokens
        updates the reserve balance, total contributed amount and issues new tokens to the contributor and to the beneficiary

        _contributor        account that should the new tokens
        _depositEthValue    amount contributed by the account, in wei
        _return             amount to be issued to the contributor, in the smart token
    */
    function handleContribution(address _contributor, uint256 _depositEthValue, uint256 _return) private {
        // update the reserve balance
        uint8 reserveAllocationPercentage;
        if (etherContributed >= PHASE3_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE3_RESERVE_ALLOCATION;
        else if (etherContributed >= PHASE2_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE2_RESERVE_ALLOCATION;
        else if (etherContributed >= PHASE1_MIN_CONTRIBUTION)
            reserveAllocationPercentage = PHASE1_RESERVE_ALLOCATION;

        uint256 addToReserve = safeMul(_depositEthValue, reserveAllocationPercentage) / 100;
        tokenReserveBalance = safeAdd(tokenReserveBalance, addToReserve);

        // update the total contribution amount
        etherContributed = safeAdd(etherContributed, _depositEthValue);
        // issue new funds to the contributor in the smart token
        assert(token.issue(_contributor, _return));

        // issued tokens to the beneficiary
        uint256 amount = safeMul(100, _return) / BENEFICIARY_PERCENTAGE;
        if (amount == 0)
            return;

        assert(token.issue(beneficiary, amount));
    }

    // utility

    function dispatchChange(address _fromToken, address _toToken, address _trader, uint256 _amount, uint256 _return) private {
        Change(_fromToken, _toToken, _trader, _amount, _return);

        if (address(events) != 0x0)
            events.tokenChange(_fromToken, _toToken, _trader, _amount, _return);
    }

    // fallback
    function() payable {
        buyETH();
    }
}


standartdummy token added

standartdummy token added

pragma solidity ^0.4.4;

import "./zeppelin/token/StandardToken.sol";

/*
 * CrowdsaleToken
 *
 * Simple ERC20 Token example, with crowdsale token creation
 */
contract dummyToken is StandardToken {

  string public name = "CrowdsaleToken";
  string public symbol = "CRW";
  uint public decimals = 18;

  // 1 ether = 500 example tokens
  uint PRICE = 500;

  function () payable {
    createTokens(msg.sender);
  }

  //Mul - умножение
  function createTokens(address recipient) payable {
    if (msg.value == 0) throw;

    uint tokens = safeMul(msg.value, getPrice());

    totalSupply = safeAdd(totalSupply, tokens);
    balances[recipient] = safeAdd(balances[recipient], tokens);
  }

  // replace this with any other price function
  function getPrice() constant returns (uint result){
    return PRICE;
  }
}

error: pathspec 'contracts/dummyCrowdToken.sol' did not match any file(s) known to git