Reputation: 1810
I have been following this tutorial by Gregory from Dapp University on how to create your own ERC20 token along with a crowd-sale smart contract. I have been successful so far, but I am stuck where I need to make the buytokens() function work so a transfer of tokens from the address of the crowd-sale contract to the buyer's can take place. The test I am about to show makes use of the async/await pattern, different from what is on the video tutorial. Below you can find the code of
Thanks for your help.
Development Environment
Truffle v5.4.18 (core: 5.4.18)
Solidity - 0.8.9 (solc-js)
Node v16.1.0
Web3.js v1.5.3
Crowd-sale Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
import "./NzouaToken.sol";
contract NzouaTokenSale {
address admin;
NzouaToken public tokenContract;
uint256 public tokenPrice;
uint256 public tokensSold;
event Sell(address _buyer, uint256 _amount);
constructor(NzouaToken _tokenContract, uint256 _tokenPrice) {
admin = msg.sender;
tokenContract = _tokenContract;
tokenPrice = _tokenPrice;
}
function multiply(uint x, uint y) internal pure returns(uint z){
require(y == 0 || (z = x * y) / y == x);
}
function buyTokens(uint256 _numberOfTokens) public payable{
require(msg.value == multiply(_numberOfTokens, tokenPrice));
require(tokenContract.balanceOf(address(this)) >= _numberOfTokens);
require(tokenContract.transfer(msg.sender, _numberOfTokens));
tokensSold += _numberOfTokens;
emit Sell(msg.sender, _numberOfTokens);
}
}
ERC20 Token Contract
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0;
contract NzouaToken {
string public name = "Nzouat Token";
string public symbol = "NZT";
uint256 public totalSupply;
event Transfer(
address indexed _from,
address indexed _to,
uint256 _value
);
event Approval(
address indexed _owner,
address indexed _spender,
uint256 _value
);
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
constructor(uint256 _initialSupply) {
balanceOf[msg.sender] = _initialSupply;
totalSupply = _initialSupply;
}
function transfer(address _to, uint256 _value) public returns(bool success){
require(balanceOf[msg.sender] >= _value, 'The account has low funds');
balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;
emit Transfer(msg.sender, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) public returns(bool success) {
allowance[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success){
require(_value <= balanceOf[_from]);
require(_value <= allowance[_from][msg.sender]);
balanceOf[_from] -= _value;
balanceOf[_to] += _value;
allowance[_from][msg.sender] -= _value;
emit Transfer(_from, _to, _value);
return true;
}
}
Deployment Script
const NzouaToken = artifacts.require("NzouaToken");
const NzouaTokenSale = artifacts.require("NzouaTokenSale");
module.exports = async function (deployer, network, accounts) {
await deployer.deploy(NzouaToken, 1000000); // 1000000 NZT tokens
await deployer.deploy(NzouaTokenSale, NzouaToken.address, 1000000000000000);
};
Unit Testing With Mocha (Part of the crowd-sale test that is failing)
var NzouaToken = artifacts.require('./NzouaToken');
var NzouaTokenSale = artifacts.require('./NzouaTokenSale');
contract('NzouaTokenSale', async (accounts) => {
let tokenSale;
let token;
let tokenPrice = 1000000000000000; // in wei
const adminAccount = accounts[0];
const buyerAccount = accounts[1];
describe('Facilitates Token Buying', async () => {
it('Required a successful Transfer of Tokens', async () => {
token = await NzouaToken.deployed();
tokenSale = await NzouaTokenSale.deployed();
let tokenSaleBalance;
let buyerBalance;
const numberOfTokens = 10;
const tokensAvailable = 750000;
// try {
let receipt = await token.transfer.call(tokenSale.address, tokensAvailable, {
from: adminAccount
})
tokenSaleBalance = await token.balanceOf(tokenSale.address);
assert.equal(tokenSaleBalance.toNumber(), tokensAvailable, 'Contract received funds.')
await tokenSale.buyTokens(numberOfTokens, {
from: buyerAccount,
value: numberOfTokens * tokenPrice
});
// Grab the new balance of the buyerAccount
buyerBalance = await token.balanceOf(buyerAccount);
buyerBalance = buyerBalance.toNumber()
assert.equal(tokenSaleBalance, numberOfTokens, 'Buyer Balance updated');
// Grab the new balance of the Token Sale Contract
tokenSaleBalance = await token.balanceOf(tokenSale.address);
tokenSaleBalance = tokenSaleBalance.toNumber()
assert.equal(tokenSaleBalance, tokensAvailable - numberOfTokens, 'Token Sale Balance updated');
// } catch (error) {
// // console.log(error.message)
// assert(error.message.indexOf('revert') >= 0, 'Something went wrong while making the transfer');
// }
});
});
});
If I uncomment the try{}catch{} section, the test will pass but it is not the behavior I am expecting.
When I run my test using truffle truffle test
inside the truffle console, All my other tests pass but one, and I get this revert error
What am I doing wrong here?
Upvotes: 0
Views: 273
Reputation: 49709
You are getting error because your transfer
function has this require
require(balanceOf[msg.sender] >= _value, 'The account has low funds');
so make sure your transfer amount is less than msg.sender
's balance
Upvotes: 0