Setting crowdsale rate manually

Traditionally when we create crowdsale smart contract we provide four parameters: initial rate, final rate, opening time, and closing time, which determines current rate when one buys tokens using Ether. For example OpenZeppelin contracts.

Why can't we simply define a function, say, setRate(uint) onlyAdjuster and adjust the rate manually? Isn't it more flexible?

The matter is that I have created my own ERC20 token and just want to sell it for Ether. I have no time restrictions or final rate, only finite amount of tokens I want to distribute. What is the best practice in my case?

1 Like

Hi @bayram,

Welcome to the community :wave:

OpenZeppelin provides a highly configurable Crowdsale base contract that can be combined with various other functionalities to construct a bespoke crowdsale.

You could include a manual rate adjustment. I would think of this as the equivalent of a vending machine for laundry or arcade tokens, where the owner could change the price of tokens.

I would recommend clearly advising participants under what circumstances the rate could be changed and who could change it, including by how much and how frequently.

You may want to code these types of restrictions on the rate change into your crowdsale. Such as limiting the frequency of a change (e.g. can only be changed after X time since the last change) and/or the amount (e.g. can only be adjusted up or down by Y%).


Your solution should also have appropriate testing and auditing:

1 Like

@abcoathup
Thanks for reply.
Yeah, I am using Crowdsale smart-contract.

As you recommend we do have our rules on under what circumstances the rate could be changed and who could change it. But I’d like simply to create a rate setter with restricted access and change it manually according to rules.

2 Likes

Hi @bayram,

You can have a manual rate setter with no restrictions (other than who can set it).
Though this means that your users will have to trust what you say that you are going to do, rather than knowing the restrictions are enforced in code.

I would recommend being very clear with your users under what circumstances you would change the rate, both with how frequently, with what notice, and by how much (along with any other conditions). I would also include why these conditions are not implemented in code.

As always, I recommend that smart contracts are appropriately tested and audited.

Also get appropriate advice on any regulatory requirements.

1 Like

Thanks, your advice is really helpful.

PS
I regularly mispronounce OpenZeppelin when we discuss, by saying Led Zeppelin, :smiley: I don’t know why though.

1 Like

Hi @bayram,

You are welcome. Feel free to ask all the questions that you need.

With OpenZeppelin and Led Zeppelin they are both great Zeppelins, it is understandable. :zap: :grinning:

@abcoathup
I wonder why are members of Crowdsale.sol such as _wallet, _rate, _token, and _weiRaised declared private? While they are readable, they are not accessible when we inherit from Crowdsale contract. This does not allow me to inherit from Crowdsale and for example define a setter function for _rate.

I made _rate internal in Crowdsale.sol and my derived contract worked fine.

pragma solidity >=0.4.21 <0.6.0;

import "../node_modules/@openzeppelin/contracts/access/Roles.sol";
import "../node_modules/@openzeppelin/contracts/crowdsale/Crowdsale.sol";

contract MyCrowdsale is Crowdsale{
  using Roles for Roles.Role;

  Roles.Role private _owners;

  constructor(uint256 initialRate, address payable wallet, IERC20 tokenAddr, address ownerAddr)
  Crowdsale(initialRate, wallet, tokenAddr)
  public
  {
    _owners.add(ownerAddr);
  }

  function setRate(uint256 newRate) public
  {
    require(_owners.has(msg.sender), "DOES_NOT_HAVE_RATE_SETTER_ROLE");
    _rate = newRate;
  }
}

What is the reason to make those variables private?

1 Like

Hi @bayram,

We shouldn't modify the OpenZeppelin Contracts themselves, we should inherit and where needed override.

https://docs.openzeppelin.com/contracts/2.x/#usage
Warning: You should always use the installed code as-is, and neither copy-paste it from online sources, nor modify it yourself.

As an aside, we don't need "../node_modules" on import statements.

import "../node_modules/@openzeppelin/contracts/crowdsale/Crowdsale.sol";

Regards state variables being private, the release notes for OpenZeppelin 2.0 explain:

https://github.com/OpenZeppelin/openzeppelin-contracts/releases/tag/v2.0.0
All state variables are now private, which means that derived contracts cannot access them directly, but have to use getters. This is to increase encapsulation, to be able to reason better about the code.

We can override Crowdsale functionality to give a changeable/settable rate so could do something like the following code.
Please note, I haven't tested this smart contract at all.

As always, I recommend that smart contracts are appropriately tested and audited.

pragma solidity ^0.5.0;

import "@openzeppelin/contracts/access/Roles.sol";
import "@openzeppelin/contracts/crowdsale/Crowdsale.sol";

contract MyCrowdsale is Crowdsale{
  using Roles for Roles.Role;

  Roles.Role private _owners;

  uint256 private _changeableRate;

  constructor(uint256 initialRate, address payable wallet, IERC20 tokenAddr, address ownerAddr)
  Crowdsale(initialRate, wallet, tokenAddr)
  public
  {
    _owners.add(ownerAddr);

    _changeableRate = initialRate;
  }

  function setRate(uint256 newRate) public
  {
    require(_owners.has(msg.sender), "DOES_NOT_HAVE_RATE_SETTER_ROLE");
    _changeableRate = newRate;
  }

  function rate() public view returns (uint256) {
    return _changeableRate;
  }

  function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) {
    return weiAmount.mul(_changeableRate);
  }
}
2 Likes

@abcoathup
Yeah, I fixed import "../node_modules/@openzeppelin/... to import "@openzeppelin/...

I agree with you, I always respect other’s code, never change private member. In my example I just wanted to show that if _rate was declared as internal then we could derive from Crowdsale without need to override ALL methods where _rate appears.

In fact, my contract looks exactly like you suggest.
I’ve also written tests for this contract, and I am going to test it on Ropsten before I deploy it on mainnet. You provide security audit as far as I know, so probably I will submit my code for the audit.

Thank you again for your suggestions. :slight_smile:

1 Like

Hi @bayram,

Whilst having internal state variables would make things easier, it would break encapsulation. I believe the code overriding functions using rate make it clearer what is being changed.

Good to hear that you have tests for your contract. A thorough test suite is very important. The following article on testing is worth a read: Test smart contracts like a rockstar

I recommend reading the following checklist for before an audit:

I found reading past audits very useful: https://blog.openzeppelin.com/security-audits/

Regards auditing, OpenZeppelin performs audits, see the website for details: https://openzeppelin.com/security-audits/

A post was split to a new topic: Setting crowdsale rate automatically after every purchase