Well, I'm creating a contract to be my ICO, but I have a "simple" problem using the SafeMath lib.
What is the problem? I need to limit the purchase of my token to a maximum of "5 ether(bnb)", so I created a variable called "investorBalances" where I save the amount that was purchased.
That done, I put a check on my code where I confirm that the amount purchased by the investor is not higher than the limit. But then the error happens, it returns my "revert" message saying that it has already reached the limit, however, this is the first purchase...
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.2;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract SALES is Ownable {
using SafeMath for uint256;
IERC20 token;
uint256 private rate = 3000; // Number of tokens per BNB
uint256 private start = 1636914760; // 16/11/2021
uint256 private dayMax = 45; // 45 Day
uint256 private buyMax = 5; //5 bnb
uint256 public initialTokens; // Initial number of tokens available
bool public initialized = false;
uint256 public raisedAmount = 0;
mapping(address => uint256) investorBalances;
/**
* BoughtTokens
* @dev Log tokens bought onto the blockchain
*/
event BoughtTokens(address indexed to, uint256 value);
constructor(address _token){
setAddrERC20(_token);
}
/**
* @dev Fallback function if ether is sent to address insted of buyTokens function
**/
receive() external payable {
buyTokens();
}
/**
* buyTokens
* @dev function that sells available tokens
**/
function buyTokens() public payable whenSaleIsActive {
uint256 weiAmount = msg.value; // Calculate tokens to sell
uint256 tokens = weiAmount.mul(rate);
uint256 amountMax = investorBalances[msg.sender].add(weiAmount);
if(amountMax >= buyMax){
revert("You have reached the purchase limit");
}
emit BoughtTokens(msg.sender, tokens); // log event onto the blockchain
raisedAmount = raisedAmount.add(msg.value); // Increment raised amount
token.transfer(msg.sender, tokens); // Send tokens to buyer
investorBalances[msg.sender] = amountMax;
payable(owner()).transfer(msg.value);// Send money to owner
}
/**
* whenSaleIsActive
* @dev ensures that the contract is still active
**/
modifier whenSaleIsActive() {
// Check if sale is active
assert(isActive());
_;
}
function isActive() public view returns (bool) {
return (
initialized == true &&
block.timestamp >= start && // Must be after the START date
block.timestamp <= start.add(dayMax * 1 days)// Must be before the end date
);
}
/**
* terminate
* @notice Terminate contract and refund to owner
**/
function terminateSales() public onlyOwner {
// Transfer tokens back to owner
uint256 balance = token.balanceOf(address(this));
assert(balance > 0);
token.transfer(owner(), balance);
}
/**
* tokensAvailable
* @dev returns the number of tokens allocated to this contract
**/
function tokensAvailable() public view returns (uint256) {
return token.balanceOf(address(this));
}
/**
* investorBalanceAvailable
* @dev returns the number of tokens the investor bought
**/
function investorBalanceAvailable(address _investor) public view returns (uint256) {
return investorBalances[_investor];
}
/**
* initialize
* @dev Initialize the contract
**/
function initialize() public onlyOwner {
require(initialized == false); // Can only be initialized once
initialized = true;
}
function setRate(uint _rate) public onlyOwner{
rate = _rate;
}
function setBuyMax(uint _buyMax) public onlyOwner{
buyMax = _buyMax;
}
function setStart(uint _start) public onlyOwner{
start = _start;
}
function setDays(uint _days) public onlyOwner{
dayMax = _days;
}
function setAddrERC20(address _tokenAddr) public onlyOwner{
require(_tokenAddr != address(0));
token = IERC20(_tokenAddr);
}
}
My function in test.js
it(`Buy with account Investor1 4 ether = 12000 tokens`, async () => {
await contractInstance.initialize();
await contractInstance.buyTokens({
from: investor1,
value: web3.utils.toWei("4", "ether"),
gas: 200000
})
let total = await coinInstance.balanceOf(investor1);
expect(web3.utils.fromWei(total)).to.be.equal("12000");
});
Output:
Validate pre-sales from account privateSales
Buy with account Investor1 4 ether = 12000 tokens:
Error: Returned error: VM Exception while processing transaction: revert You have reached the purchase limit -- Reason given: You have reached the purchase limit. ```