The actual amount of the token owner not shown as expected - ethereum

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")

Related

How fix TypeError and DeclarationError with ChainLink Solidity smart contract?

I have created a smart contract which return to each user the amount deposited + a certain amount if the price of ETH decreases during the lock period. I have two problems with the last part of the code.
The first one concerns mapping the price of ethereum at the moment the user makes the deposit. I have tried several solutions but none of them seem to work. The problem arises on line 64 mapping(uint => uint) ethPrice;. Console returns:
DeclarationError: Identifier already declared.
--> oracle.sol:65:5:
|
65 | mapping(uint => uint) ethPrice;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note: The previous declaration is here:
--> oracle.sol:63:5:
|
63 | uint public ethPrice = 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^
The second is found on line no. 91. msg.sender.transfer(amountToWithdraw); with the transfer function. The console continues to return the following error despite the fact that the address of each user is defined as payable in the previous functions. Console returns:
TypeError: "send" and "transfer" are only available for objects of type "address payable", not "address".
--> oracle.sol:97:9:
|
97 | msg.sender.transfer(amountToWithdraw);
| ^^^^^^^^^^^^^^^^^^^
These two problems severely invalidate the smart contract and are holding up the completion of coding the latest functions. I have contacted several people and looked in forums concerning programming on solidity but no one seems to have an answer to my problem.
I hope that my question can be answered by the community and can help any other person trying to use ChainLink with Solidity in the future. I am happy to listen to any advice on the matter.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// EACAggregatorProxy is used for chainlink oracle
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
// Address dev
address public dev;
// Dev's public deposit amount
uint public devDeposit;
// Array dev's public amount
uint[] public devDeposits;
// List each user and amount
address[] public users;
uint[] public totalDeposited;
// Mapping user's deposit
mapping(address => uint) balances;
// Deployer = dev & Dev deposit function
function deployerIsDeveloper() public payable {
dev = msg.sender;
devDeposit = msg.value;
devDeposits.push(devDeposit);
}
// User's address
address user;
// Amount's address
uint amountDeposit;
// Deadline time
uint256 deadline;
// Amount's each user
uint256 lockAmount = lockAmounts[msg.sender];
// Mapping of deposit for each user
mapping(address => uint) lockAmounts;
// Timestamp for each user
uint256 startTime = startTimes[block.timestamp];
// Mapping timestamp for each user
mapping(uint => uint) startTimes;
// Kovan ETH/USD oracle address
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
// ethPrice
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) ethPrice;
// Deposit function for each user
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
amountDeposit = msg.value;
users.push(user);
totalDeposited.push(amountDeposit);
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
//return ethPrice = price;
//price.push(ethPrice);
}
// Withdraw function for each user
function withdraw() public payable {
require(block.timestamp >= deadline);
uint amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
msg.sender.transfer(amountToWithdraw);
}
}
For the first issue, Solidity compiler said that you declared two variables with the identifier. In details in your case, you give ethPrice for mapping and uint variable. To solve this issue, try to change one of these names in this way:
uint256 price = ethPrice;
mapping(uint => uint) mappingEthPrice;
Second issue refers that msg.sender keyword doesn't cast automatically with address payable and to solve it you can use payable() function that allows you convert an address to address payable.
In your smart contract you must to change in this way:
payable(msg.sender).transfer(amountToWithdraw);
This should be your smart contract fixed:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
// EACAggregatorProxy is used for chainlink oracle
interface EACAggregatorProxy {
function latestAnswer() external view returns (int256);
}
contract oracleLink {
// Address dev
address public dev;
// Dev's public deposit amount
uint public devDeposit;
// Array dev's public amount
uint[] public devDeposits;
// List each user and amount
address[] public users;
uint[] public totalDeposited;
// Mapping user's deposit
mapping(address => uint) balances;
// Deployer = dev & Dev deposit function
function deployerIsDeveloper() public payable {
dev = msg.sender;
devDeposit = msg.value;
devDeposits.push(devDeposit);
}
// User's address
address user;
// Amount's address
uint amountDeposit;
// Deadline time
uint256 deadline;
// Amount's each user
uint256 lockAmount = lockAmounts[msg.sender];
// Mapping of deposit for each user
mapping(address => uint) lockAmounts;
// Timestamp for each user
uint256 startTime = startTimes[block.timestamp];
// Mapping timestamp for each user
mapping(uint => uint) startTimes;
// Kovan ETH/USD oracle address
address public chainLinkETHUSDAddress = 0x9326BFA02ADD2366b30bacB125260Af641031331;
// ethPrice
uint public ethPrice = 0;
uint256 price = ethPrice;
mapping(uint => uint) mappingEthPrice;
// Deposit function for each user
function deposit(uint256 numberOfSeconds) public payable {
lockAmounts[msg.sender] = msg.value;
startTimes[block.timestamp] = block.timestamp;
user = msg.sender;
amountDeposit = msg.value;
users.push(user);
totalDeposited.push(amountDeposit);
deadline = block.timestamp + (numberOfSeconds * 1 seconds);
int256 chainLinkEthPrice = EACAggregatorProxy(chainLinkETHUSDAddress).latestAnswer();
ethPrice = uint(chainLinkEthPrice / 100000000);
//return ethPrice = price;
//price.push(ethPrice);
}
// Withdraw function for each user
function withdraw() public payable {
require(block.timestamp >= deadline);
uint amountToWithdraw = lockAmounts[msg.sender];
lockAmounts[msg.sender] = 0;
payable(msg.sender).transfer(amountToWithdraw);
}
}

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.

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.

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

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?

transfer hash verification in a smart contract

I have a contract which holds tokens on behalf of addresses and transfers them when a signed hash of a transfer is provided.
The contract looks like this
pragma solidity ^0.5.0;
import "openzeppelin-solidity/contracts/ownership/Ownable.sol";
import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
contract Settlement is Ownable {
using SafeMath for uint256;
struct Withdrawal {
uint256 amount;
address token;
uint256 timestamp;
}
// token => (holder => balance)
mapping(address => mapping(address => uint256)) public tokenBalances;
mapping(address => Withdrawal) withdrawals;
function transferInto(address recipient, uint256 amount, address token) public {
//get the tokens
IERC20(token).transferFrom(msg.sender, address(this), amount);
//increase the token balance in the payment contract
tokenBalances[token][recipient] = tokenBalances[token][recipient].add(amount);
}
string constant private prefix = "\u0019Ethereum Signed Message:\n32";
function transfer(address to, uint256 amount, address token, uint8 v, bytes32 r, bytes32 s)
public {
bytes32 paramHash = keccak256(abi.encodePacked(to, amount, token));
address signer = ecrecover(keccak256(abi.encodePacked(prefix, paramHash)), v, r, s);
//SafeMath ensures that the signer has enough tokens in their payment account
tokenBalances[token][signer] = tokenBalances[token][signer].sub(amount);
IERC20(token).transfer(to, amount);
}
}
and I have written a function to create the signature which is passed to the transfer function of the contract:
const ethers = require('ethers')
const BigNumber = require('bignumber.js')
const utils = require('web3-utils')
// the purpose of this function is to be able to create BN from exponent numbers like '2e22' they must be formatted as string in this case
const toBN = (num) => utils.toBN(new BigNumber(num).toString(10))
async function signTransfer(recipient, amount, tokenAddress, privateKey){
const wallet = new ethers.Wallet(privateKey)
const txMsg = utils.soliditySha3(recipient, toBN(amount), tokenAddress)
const messageHashBytes = ethers.utils.arrayify(txMsg)
const flatSig = await wallet.signMessage(messageHashBytes)
const sig = ethers.utils.splitSignature(flatSig)
return {
...sig,
hash: messageHashBytes
}
}
module.exports = signTransfer
this works but I had to use both ethers and web3-utils packages to implement this.
how can I replace the soliditySha3 function with an ethers version?
I had a look at the implementation of soliditySha3 and it looks mighty complex.
The thing is that web3js does not seem to have a function to create the messageHashBytes in my function. So I'm stuck with both. It's not super bad, but it would be nice to reduce the number of libraries.
If you're okay just using web3.js for everything, something like this should work:
function signTransfer(recipient, amount, tokenAddress, privateKey) {
return web3.eth.accounts.sign(
web3.utils.soliditySha3(recipient, toBN(amount), tokenAddress),
privateKey);
}