Error: gas required exceeds allowance or always failing transaction - web3js - ethereum

I get the following error when I try to deploy a smartcontract using web3js. But if I deploy the same contract using Truffle or geth console, deployment succeeds.
Error: gas required exceeds allowance or always failing transaction
Smart Contract solidity code:
pragma solidity >=0.4.25 <0.6.0;
contract Election {
// Model a Candidate
struct Candidate {
uint id;
string name;
uint voteCount;
}
// Store accounts that have voted
mapping(address => bool) public voters;
// voted event
event votedEvent (
uint indexed _candidateId
);
// Store Candidates
// Read Candidate
mapping(uint => Candidate) public candidates;
// Store Candidates count
uint public candidatesCount;
// Constructor
constructor() public{
addCandidate('ABC');
addCandidate('XYZ');
addCandidate('PQR');
}
function addCandidate(string memory _name) private{
candidatesCount++;
candidates[candidatesCount] = Candidate(candidatesCount, _name, 0);
}
function vote(uint _candidateId) public{
// require that they haven't voted before
require(!voters[msg.sender]);
// require a valid candidate
require(_candidateId > 0 && _candidateId <= candidatesCount);
// record that voter has voted
voters[msg.sender] = true;
// update candidate vote Count
candidates[_candidateId].voteCount ++;
// trigger voted event
emit votedEvent(_candidateId);
}
}
Following is the code, I am using to deploy the smartcontract:
const provider = new HDWalletProvider(mnemonic, nodeAccessToken, 1);
const web3 = new Web3(provider);
const contract = new web3.eth.Contract(abi);
const accounts = await web3.eth.getAccounts();
try{
const deployedContract = await contract.deploy({
data: '0x' + bytecodeData, // Adding '0x' since generated bytecodedata doesn't have '0x' prefix.
arguments: args
});
let result = await deployedContract.send({
from: accounts[0],
gasPrice: 0
})
}catch(e){}
Did anyone else face the same issue?

Related

Checking and granting role in Solidity

I'm trying to create a factory contract which is used to mint ERC721 tokens, at two different prices depending on whether it's during presale.
I'm using the Access library from OpenZeppelin, and have my contract set up with two roles (plus the default administrator role). Some lines are excluded for brevity:
import "#openzeppelin/contracts/access/AccessControl.sol";
import "./Example.sol";
contract ExampleFactory is AccessControl {
// ...
bool public ONLY_WHITELISTED = true;
uint256 public PRESALE_COST = 6700000 gwei;
uint256 public SALE_COST = 13400000 gwei;
uint256 MAX_PRESALE_MINT = 2;
uint256 MAX_LIVE_MINT = 10;
uint256 TOTAL_SUPPLY = 100;
// ...
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
bytes32 public constant ROLE_PRESALE = keccak256("ROLE_PRESALE");
// ...
constructor(address _nftAddress) {
nftAddress = _nftAddress;
// Grant the contract deployer the default admin role: it will be able
// to grant and revoke any roles
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
_setupRole(ROLE_MINTER, msg.sender);
_setupRole(ROLE_PRESALE, msg.sender);
}
function mint(uint256 _mintAmount, address _toAddress) public payable {
// If the user doesn't have the minter role then require payment
if (hasRole(ROLE_MINTER, msg.sender) == false) {
if (ONLY_WHITELISTED == true) {
// If still in whitelist mode then require presale role & enough value
require(hasRole(ROLE_PRESALE, msg.sender), "address is not whitelisted");
require(msg.value >= PRESALE_COST * _mintAmount, "tx value too low for quantity");
} else {
require(msg.value >= SALE_COST * _mintAmount, "tx value too low for quantity");
}
}
// Check there are enough tokens left to mint
require(canMint(_mintAmount), "remaining supply too low");
Example token = Example(nftAddress);
for (uint256 i = 0; i < _mintAmount; i++) {
token.mintTo(_toAddress);
}
}
function canMint(uint256 _mintAmount) public view returns (bool) {
if (hasRole(ROLE_MINTER, msg.sender) == false) {
if (ONLY_WHITELISTED == true) {
require((_mintAmount <= MAX_PRESALE_MINT), "max 2 tokens can be minted during presale");
} else {
require((_mintAmount <= MAX_LIVE_MINT), "max 10 tokens can be minted during sale");
}
}
Example token = Example(nftAddress);
uint256 issuedSupply = token.totalSupply();
return issuedSupply < (TOTAL_SUPPLY - _mintAmount);
}
}
There are a couple of different paths to mint:
If the user has ROLE_MINTER, they can mint without payment or limits
If ONLY_WHITELISTED is true, the transaction must have enough value for presale price, and they must have ROLE_PRESALE
If ONLY_WHITELISTED is false, anyone can mint
I've written a script to test minting:
const factoryContract = new web3Instance.eth.Contract(
FACTORY_ABI,
FACTORY_CONTRACT_ADDRESS,
{ gasLimit: '1000000' }
);
console.log('Testing mint x3 from minter role')
try {
const result = await factoryContract.methods
.mint(3, OWNER_ADDRESS)
.send({ from: OWNER_ADDRESS });
console.log(' ✅ Minted 3x. Transaction: ' + result.transactionHash);
} catch (err) {
console.log(' 🚨 Mint failed')
console.log(err)
}
Running this successfully mints 3 tokens to the factory owner. No value is attached to this call, and it's minting more than the maximum, so in order for it to be successful it has to follow the ROLE_MINTER path.
However, if I call hasRole from the same address, the result is false which doesn't make sense.
const minterHex = web3.utils.fromAscii('ROLE_MINTER')
const result = await factoryContract.methods.hasRole(minterHex, OWNER_ADDRESS).call({ from: OWNER_ADDRESS });
// result = false
If I try to run the test mint script from another address (with no roles) it failed as expected, which suggests roles are working but I'm using hasRole wrong?
const minterHex = web3.utils.fromAscii('ROLE_MINTER')
This JS snippet returns the hex representation of the ROLE_MINTER string: 0x524f4c455f4d494e544552
bytes32 public constant ROLE_MINTER = keccak256("ROLE_MINTER");
But this Solidity snippet returns the keccak256 hash of the ROLE_MINTER string: 0xaeaef46186eb59f884e36929b6d682a6ae35e1e43d8f05f058dcefb92b601461
So when you're querying the contract if the OWNER_ADDRESS has the role 0x524f4c455f4d494e544552, it returns false because this address doesn't have this role.
You can calculate the hash using the web3.utils.soliditySha3() function (docs).
const minterHash = web3.utils.soliditySha3('ROLE_MINTER');
const result = await factoryContract.methods.hasRole(minterHash, OWNER_ADDRESS).call();
Also note that the OpenZeppelin hasRole() function doesn't check for msg.sender, so you don't need to specify the caller inside the call() function. Just the 2nd argument of the hasRole() as the account that you're asking about their role.

Smart Contract Method Reverted in Ganache but Worked Fine in Remix

Overview
I am working on a project for a Blockchain Developer Course, the project must be tested with Ganache because the Reviewer Team for the course will use Ganache.
The Smart Contract that I am working right now works with two different smart contracts, one is for data storage and the other is for the application purposes (user interaction).
When an user interacts with the registerOracle function the smart contract will ask for 1 ether to generate 1 oracle (this oracle will have an ID and 3 Indexes).
I tested the Smart Contract on Remix and everything works find but when I try to test the oracle generator function in Ganache it gives me a revert error.
Project URL
The project's files are in my Github's repository along with some screenshot I took showcasting the procedure to test the smart contract on Remix and the error I get on Ganache.
The code is too extend, but I will be posting here the relevant parts that are giving me the errors. The complete code can be seen on my repository.
TestingEnv.js File
const Web3 = require('web3');
const fs = require('fs').promises;
async function main () {
/**
* IGNORE FROM HERE
*/
const web3 = new Web3(new Web3.providers.WebsocketProvider("HTTP://127.0.0.1:8545"));
const appABI = (JSON.parse(await fs.readFile("./bin/appAbi.json", "utf8"))).abi;
const appBYTECODE = (JSON.parse(await fs.readFile("./bin/appByteCode.json", "utf8"))).bytecode;
const dataABI = (JSON.parse(await fs.readFile("./bin/dataAbi.json", "utf8"))).abi;
const dataBYTECODE = (JSON.parse(await fs.readFile("./bin/dataByteCode.json", "utf8"))).bytecode;
const owner = (await web3.eth.getAccounts())[0];
const appContract = await new web3.eth.Contract(appABI).deploy({data: '0x' + appBYTECODE})
.send({from: owner, gasLimit: 6000000, gasPrice: web3.utils.toWei('5', 'gwei')});
const dataContract = await new web3.eth.Contract(dataABI).deploy({data: '0x' + dataBYTECODE})
.send({from: owner, gasLimit: 6000000, gasPrice: web3.utils.toWei('5', 'gwei')});
const appAddress = appContract._address;
const dataAddress = dataContract._address;
await appContract.methods.registerDataContract(dataAddress).send({from: owner});
await dataContract.methods.registerApplicationContract(appAddress).send({from: owner});
/**
* TO HERE
*/
/**
* REVERT ERROR - STARTS
*/
const oracleFee = await web3.utils.toWei("1", "ether");
const server = (await web3.eth.getAccounts())[2];
// I AM REGISTERING 20 ORACLES
for (var i=0; i<20; i++) {
await appContract.methods.registerOracle().send({from: server, value: oracleFee});
await new Promise(resolve => setTimeout(resolve, 2000));
};
const totalOracles = await appContract.methods.getTotalOracles().call({from: server});
console.log(`Total Numbers of Oracles Registered: ${totalOracles}`);
for (var i = 0; i<totalOracles; i++) {
var indexes = await appContract.methods.getOraceIndexes(i).call({from: server});
if (i >= 0 && i <= 9) {
console.log(`Oracle 0${i} indexes: ${indexes._index1.toString()} ${indexes._index2.toString()} ${indexes._index2.toString()}`);
} else {
console.log(`Oracle ${i} indexes: ${indexes._index1.toString()} ${indexes._index2.toString()} ${indexes._index2.toString()}`);
};
};
};
main();
FlightSuretyApp.sol Contract
pragma solidity ^0.4.24;
interface iFlightSuretyData {
function registerOracle(address server, uint8 index1, uint8 index2, uint8 index3) external payable;
}
import "./SafeMath.sol";
contract FlightSuretyApp {
using SafeMath for uint256;
bool operationalStatus;
address owner;
iFlightSuretyData FlightSecuretyData;
constructor() public {
operationalStatus = true;
owner = msg.sender;
}
modifier requireOwner() {
require(msg.sender == owner, "Owner is required");
_;
}
modifier requireOperational() {
require(operationalStatus == true, "Contract is not operational");
_;
}
function registerDataContract(address dataContract) external
requireOwner {
FlightSecuretyData = iFlightSuretyData(dataContract);
}
uint256 constant ORACLE_REGISTRATION_FEE = 1 ether;
modifier requireOracleRegistrationFee() {
require(msg.value == ORACLE_REGISTRATION_FEE, "Oracle Registration Cost 1 ether");
_;
}
function registerOracle() external payable
requireOperational
requireOracleRegistrationFee {
(uint8 index1, uint8 index2, uint8 index3) = indexesThrown();
FlightSecuretyData.registerOracle.value(msg.value)(msg.sender, index1, index2, index3);
}
function indexesThrown() private view returns(uint8 _index1, uint8 _index2, uint8 _index3)
{
uint8 index1 = generateIndex1();
uint8 index2 = generateIndex2(index1);
uint8 index3 = generateIndex3(index1, index2);
return (index1, index2, index3);
}
function generateIndex1() private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
return value;
}
function generateIndex2(uint8 _index1) private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
while(value == _index1) {
time = SafeMath.add(time, 500);
difficulty = SafeMath.add(difficulty, 700);
value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
}
return value;
}
function generateIndex3(uint8 _index1, uint8 _index2) private view returns(uint8 _index) {
uint256 mod = 10;
uint256 time = block.timestamp;
uint256 difficulty = block.difficulty;
uint8 value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
while((value == _index1) || (value == _index2)) {
time = SafeMath.add(time, 500);
difficulty = SafeMath.add(difficulty, 700);
value = uint8(SafeMath.mod(uint256(keccak256(abi.encodePacked(time, difficulty, msg.sender))), mod));
}
return value;
}
}
FlightSuretyData.sol
import "./SafeMath.sol";
contract FlightSuretyData {
using SafeMath for uint256;
bool operationalStatus;
address owner;
address appContract;
constructor() public {
operationalStatus = true;
owner = msg.sender;
airlines[owner].registrationStatus = true;
}
modifier requireOwner() {
require(msg.sender == owner, "Require contract owner");
_;
}
modifier requireApplication() {
require(msg.sender == appContract, "Require application");
_;
}
modifier requireOperational() {
require(operationalStatus == true, "Contract is not operational");
_;
}
function registerApplicationContract(address application) external
requireOwner
requireOperational {
appContract = application;
}
struct oracle {
uint8 index1;
uint8 index2;
uint8 index3;
mapping(bytes32 => bool) voteState;
}
struct oracleServer {
mapping(uint256 => oracle) oracles;
uint256 numberOfOracles;
}
mapping(address => oracleServer) private oracleServers;
function registerOracle(address server, uint8 index1, uint8 index2, uint8 index3) external payable
requireOperational
requireApplication {
uint256 counter = oracleServers[server].numberOfOracles;
oracleServers[server].oracles[counter].index1 = index1;
oracleServers[server].oracles[counter].index2 = index2;
oracleServers[server].oracles[counter].index3 = index3;
counter = SafeMath.add(counter, 1);
oracleServers[server].numberOfOracles = counter;
}
}
How to Run the Project?
It is easy, just install the dependencies and run the TestingEnv.js file.
My Environment Specifications
Windows 10 Home version 21H1
Ganache version 2.5.4 (Use the Ganache Desktop Application from Ganache and not some dependencies)
Node version 11.0.0
Solidity version 0.4.24
Proof that Works on Remix
Proof that Doesn't Work on Ganache
Request
How can I solve it? I am stuck on my project because I can make the project work, I've teste others functions of my smart contracts and they are working fine, but when I try to test the oracle generator it gives an error and doesn't work.
What am I missing?

Solidity function implementing `public onlyOwner` cannot be called even by the owner

I am following along the documentation here: https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft/how-to-mint-a-nft. And have a smart contract of form:
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract NFTA is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter public _tokenIds;
mapping (uint256 => string) public _tokenURIs;
mapping(string => uint8) public hashes;
constructor() public ERC721("NFTA", "NFT") {}
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
/**
* #dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
}
When I attempt to estimate the gas cost of minting with this:
const MY_PUBLIC_KEY = '..'
const MY_PRIVATE_KEY = '..'
const ALCHEMY = {
http: '',
websocket:'',
}
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const web3 = createAlchemyWeb3(ALCHEMY.http);
const NFTA = require("../artifacts/contracts/OpenSea.sol/NFTA.json");
const address_a = '0x...';
const nft_A = new web3.eth.Contract(NFTA.abi, address_a);
async function mint({ tokenURI, run }){
const nonce = await web3.eth.getTransactionCount(MY_PUBLIC_KEY, 'latest');
const fn = nft_A.methods.mintNFT(MY_PUBLIC_KEY, '')
console.log( 'fn: ', fn.estimateGas() )
}
mint({ tokenURI: '', run: true })
I receive error:
(node:29262) UnhandledPromiseRejectionWarning: Error: Returned error: execution reverted: Ownable: caller is not the owner
Presumably because mintNFT is public onlyOwner. However, when I check Etherscan, the From field is the same as MY_PUBLIC_KEY, and I'm not sure what else can be done to sign the transaction as from MY_PUBLIC_KEY. The easy way to solve this is to remove the onlyOwner from function mintNFT, and everything runs as expected. But suppose we want to keep onlyOwner, how would I sign the transaction beyond what is already written above.
Note I'm using hardHat to compile the contracts and deploying them. That is:
npx hardhat compile
npx hardhat run scripts/deploy.js
=============================================
addendum
The exact code given by alchemy to deploy the mint is:
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
};
Note in the transaction the from field is PUBLIC_KEY, the same PUBLIC_KEY that deployed the contract, and in this case the nftContract has public onlyOwner specified. This is exactly what I have done. So conceptually who owns this NFT code? On etherscan is it the to address ( the contract address ), or the from address, which is my public key, the address that deployed the contract, and the one that is calling mint, which is now failing with caller is not the owner error.
Search the internet, I see others have encountered this problem here: https://ethereum.stackexchange.com/questions/94114/erc721-testing-transferfrom, for Truffle you can specify the caller with extra field:
await nft.transferFrom(accounts[0], accounts[1], 1, { from: accounts[1] })
Extra parameters is not an option here because I'm using hardhat.
OpenZeppelin's Ownable.sol defines the default owner value as the contract deployer. You can later change it by calling transferOwnership() or renounce the owner (i.e. set to 0x0) by calling renounceOwnership().
The onlyOwner modifier reverts the transaction if it's not sent by the current owner. (see the code)
So you need to call the mintNFT() function from the same address that deployed the contract, because that's the current owner. Or you can change the owner first by calling transferOwnership() (from the current owner address).
Removing the onlyOwner modifier from the mintNFT() function would allow anyone to call the function.
Answering this for anyone else who stumbles across the issue while using the Alchemy tutorial:
In the tutorial, it says to init the contract in your mint method like this:
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");
const contractAddress = "0x81c587EB0fE773404c42c1d2666b5f557C470eED";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
However, if you attempt to call estimateGas() or encodeABI() it will fail with the onlyOwner error.
The solution is to change the third line to:
const nftContract = new web3.eth.Contract(contract.abi, contractAddress, {
from: PUBLIC_KEY
});
This will set a default value of "From" so that when you call estimateGas() on a mint function marked onlyOwner, it will be able to use that from field to see that its the owner calling the estimateGas.
Took forever to figure this out.
I finally figured it out, the contract does not initialize the way I deploy it. So you have to initialize it after deployment.

AssertionError: expected '0x0000000000000000000000000000000000000000'

I am getting this error in testing my upgradeable smart contract.
I am really stuck with this can anyone help me get out of this?
contracts/StakingContract.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import "#openzeppelin/contracts-upgradeable/math/SafeMathUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/token/ERC20/SafeERC20Upgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "#openzeppelin/contracts-upgradeable/proxy/Initializable.sol";
contract StakingContract is ERC20Upgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
using SafeMathUpgradeable for uint256;
using AddressUpgradeable for address;
using SafeERC20Upgradeable for IERC20Upgradeable;
event TokensStaked(address _tokenStaker, uint256 _amount, uint256 unlockTime);
event TokenUnstaked(address _tokenStaker, uint256 _amount);
// Variable that prevents _deposit method from being called 2 times
bool private locked;
// The total staked amount
uint256 public totalStaked;
mapping (address => uint256) public stakeBalances;
mapping(address => uint256) private timestamp;
function initialize(uint256 initialSupply) public initializer {
__ERC20_init("MyToken", "TKN");
_mint(owner(), initialSupply);
}
function stakeTokens(address token, uint amount) external {
stakeBalances[msg.sender] = stakeBalances[msg.sender].add(amount);
timestamp[msg.sender] = block.timestamp.add(30 days);
require(IERC20Upgradeable(token).allowance(msg.sender, address(this)) >= amount, "Check the token allowance");
require(IERC20Upgradeable(token).transferFrom(msg.sender, address(this), amount), "Transfer failed!");
totalStaked = totalStaked.add(amount);
emit TokensStaked(msg.sender, amount, timestamp[msg.sender]);
}
function unstakeTokens(address token, uint256 amount) external nonReentrant() {
require(amount <= stakeBalances[msg.sender], "Sorry! You don't have sufficient stake balance.");
require(block.timestamp >= timestamp[msg.sender], "Sorry! you cannot withdraw tokens before your stake time.");
stakeBalances[msg.sender] = stakeBalances[msg.sender].sub(amount);
require(IERC20Upgradeable(token).transfer(msg.sender, amount));
totalStaked = totalStaked.sub(amount);
emit TokenUnstaked(msg.sender, amount);
}
function ownerWithdraw(address token) external onlyOwner() nonReentrant() {
require(IERC20Upgradeable(token).transfer(owner(), totalStaked), "Transfer Failed!");
uint256 ownerStakedBalance = stakeBalances[msg.sender];
stakeBalances[msg.sender] = stakeBalances[msg.sender].sub(ownerStakedBalance);
totalStaked = totalStaked.sub(totalStaked);
}
}
test/StakingContract.test.js
const { accounts, contract, web3 } = require('#openzeppelin/test-environment');
const { expect } = require('chai');
const { TestHelper } = require('#openzeppelin/cli');
const { Contracts, ZWeb3 } = require('#openzeppelin/upgrades');
// Import utilities from Test Helpers
const { BN, expectEvent, expectRevert } = require('#openzeppelin/test-helpers');
ZWeb3.initialize(web3.currentProvider);
const Box = Contracts.getFromLocal('StakingContract');
describe('StakingContract', function () {
const [ owner, other ] = accounts;
beforeEach(async function () {
this.project = await TestHelper();
this.proxy = await this.project.createProxy(Box);
});
it('retrieve returns a value previously stored', async function () {
// Use large integer comparisons
expect(await this.proxy.methods.owner().call()).to.equal(owner);
});
});
it gives the following error:
0 passing (864ms)
1 failing
1) StakingContract
retrieve returns a value previously stored:
AssertionError: expected '0x0000000000000000000000000000000000000000' to equal '0xA05c7D52b924DceB23a766ccB1e91e67b4aCF014'
+ expected - actual
-0x0000000000000000000000000000000000000000
+0xA05c7D52b924DceB23a766ccB1e91e67b4aCF014
I have tried to fix it with other things but the still issue persists.
Thanks in advance.

The actual amount of the token owner not shown as expected

I created an ERC20 SC, this is the initial supply amount 100000000000. But, when I run unit test (truffle test) to show the total balance amount of the accounts[0] and the actual amount is 99999998877, expected amount should be 100000000000. Can someone explain to me, why that's happened?
Thank you.
it("should return the total supply", function() {
return CToken.deployed().then(function(instance){
return tokenInstance.totalSupply.call();
}).then(function(result){
assert.equal(result.toNumber(), 100000000000, 'total supply is wrong');
})
});
it("should return the balance of token owner", function() {
var token;
return CToken.deployed().then(function(instance){
token = instance
return tokenInstance.balanceOf.call(accounts[0]);
}).then(function(result){
assert.equal(result.toNumber(), 99999998877, 'balance is wrong');
})
});
Contract code:
pragma solidity >=0.4.21 <0.6.0;
import "../node_modules/openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol";
import "../node_modules/openzeppelin-solidity/contracts/ownership/Ownable.sol";
/**
* #title BearToken is a basic ERC20 Token
*/
contract CToken is StandardToken, Ownable{
uint256 public totalSupply;
string public name;
string public symbol;
uint32 public decimals;
/**
* #dev assign totalSupply to account creating this contract
*/
constructor() public {
symbol = "CT";
name = "CToken";
decimals = 18;
totalSupply = 100000000000;
owner = msg.sender;
balances[msg.sender] = totalSupply;
//emit Transfer(0x0, msg.sender, totalSupply);
}
}
Your total supply is 10^29 (10^11 tokens, each token has 10^18 decimal points), which is not something javascript number can safely handle. https://docs.ethers.io/ethers.js/html/notes.html#why-can-t-i-just-use-numbers
web3 returns a BN instance, don't convert it to number.
You can assert like this:
const BN = web3.utils.BN
const ten = new BN("10")
const expected = ten.pow(new BN("27"))
assert(result.eq(expected), "Result doesn't match expected value")