dappuniversity / token_sale

Code Your Own Cryptocurrency & ICO on Ethereum | Tutorial
406 stars 387 forks source link

How to fix: AssertionError: error message must contain revert #27

Closed faiznnshaik closed 4 years ago

faiznnshaik commented 4 years ago

I am trying to make my own cryptocurrency using the DAPPuniversity tutorial, however, my code keeps throwing an exception. I am using the Mac terminal and ATOM text editor. Here is my .sol code: `pragma solidity >=0.4.21 <0.6.0;

contract Faicoin { string public name = "Faicoin"; string public symbol = "FAI"; string public standard = "Faicoin v1.0"; uint256 public totalSupply;

event Transfer( address indexed _from, address indexed _to, uint256 _value );

mapping(address => uint256) public balanceOf;

constructor(uint256 _initialSupply) public { balanceOf[msg.sender] = _initialSupply; totalSupply = _initialSupply; }

function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value);

balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;

emit Transfer(msg.sender, _to, _value);

return true;

} } `

Here is my .js code:

`var Faicoin = artifacts.require("./Faicoin.sol");

contract('Faicoin', function(accounts){ var tokenInstance;

it('initalizes the contract with the correct values', function(){ return Faicoin.deployed().then(function(instance) { tokenInstance = instance; return tokenInstance.name(); }).then(function(name) { assert.equal(name, 'Faicoin', 'has the correct name'); return tokenInstance.symbol(); }).then(function(symbol){ assert.equal(symbol, 'FAI', 'has the correct symbol'); return tokenInstance.standard(); }).then(function(standard){ assert.equal(standard, 'Faicoin v1.0', 'has the correct standard'); }); });

it('allocates the initial supply upon deployment', function(){ return Faicoin.deployed().then(function(instance){ tokenInstance = instance; return tokenInstance.totalSupply(); }).then(function(totalSupply) { assert.equal(totalSupply.toNumber(), 1000000000, 'sets total supply to 1,000,000,000'); return tokenInstance.balanceOf(accounts[0]); }).then(function(adminBalance) { assert.equal(adminBalance.toNumber(), 1000000000, 'allocates the initial supply to the admin account'); }); });

it('transfers token ownership', function() { return Faicoin.deployed().then(function(instance){ tokenInstance = instance; return tokenInstance.transfer.call(accounts[1], 9999999999999999) }).then(assert.fail).catch(function(error){ assert(error.message.indexOf('revert') >= 0, 'error message must contain revert'); return tokenInstance.transfer(accounts[1],250000, {from: accounts[0] }); }).then(function(success) { assert.equal(success, true, 'it returns true'); return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] }); }).then(function(receipt) { assert.equal(receipt.logs.length, 1, 'triggers one event'); assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event'); assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from'); assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to'); assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount'); return tokenInstance.balanceOf(accounts[1]) }).then(function(reciept) { return tokenInstance.balanceOf(accounts[1]); }).then(function(balance){ assert.equal(balance.toNumber(), 250000, 'adds the amount to the recieving amount'); return tokenInstance.balanceOf(accounts[0]); }).then(function(balance){ assert.equal(balance.toNumber(), 999750000, 'deducts the amount from the sending account'); }); }); }); `

Here is what the terminal displays `Compiling ./contracts/Faicoin.sol... Compiling ./contracts/Migrations.sol...

Contract: Faicoin ✓ initalizes the contract with the correct values (91ms) ✓ allocates the initial supply upon deployment (40ms) 1) transfers token ownership

No events were emitted

2 passing (197ms) 1 failing

1) Contract: Faicoin transfers token ownership: AssertionError: error message must contain revert at test/Faicoin.js:38:7 at processTicksAndRejections (internal/process/task_queues.js:93:5)

`

faiznnshaik commented 4 years ago

This is how you fix any issues with the solidity updates `contract Faicoin { string public name = "Faicoin"; string public symbol = "FAI"; string public standard = "Faicoin v1.0"; uint256 public totalSupply;

event Transfer( address indexed _from, address indexed _to, uint256 _value );

mapping(address => uint256) public balanceOf;

constructor(uint256 _initialSupply) public { balanceOf[msg.sender] = _initialSupply; totalSupply = _initialSupply; }

function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value);

balanceOf[msg.sender] -= _value;
balanceOf[_to] += _value;

emit Transfer(msg.sender, _to, _value);

return true;

} }`

`var Faicoin = artifacts.require("./Faicoin.sol");

contract('Faicoin', function(accounts){ var tokenInstance;

it('initalizes the contract with the correct values', function(){ return Faicoin.deployed().then(function(instance) { tokenInstance = instance; return tokenInstance.name(); }).then(function(name) { assert.equal(name, 'Faicoin', 'has the correct name'); return tokenInstance.symbol(); }).then(function(symbol){ assert.equal(symbol, 'FAI', 'has the correct symbol'); return tokenInstance.standard(); }).then(function(standard){ assert.equal(standard, 'Faicoin v1.0', 'has the correct standard'); }); });

it('allocates the initial supply upon deployment', function(){ return Faicoin.deployed().then(function(instance){ tokenInstance = instance; return tokenInstance.totalSupply(); }).then(function(totalSupply) { assert.equal(totalSupply.toNumber(), 1000000000, 'sets total supply to 1,000,000,000'); return tokenInstance.balanceOf(accounts[0]); }).then(function(adminBalance) { assert.equal(adminBalance.toNumber(), 1000000000, 'allocates the initial supply to the admin account'); }); });

it('transfers token ownership', function() { return Faicoin.deployed().then(function(instance){ tokenInstance = instance; return tokenInstance.transfer.call(accounts[1], 9999999999999999) }).then(assert.fail).catch(function(error){ assert(error.message, 'error message must contain revert'); return tokenInstance.transfer.call(accounts[1],250000, {from: accounts[0] }); }).then(function(success) { assert(success, true, 'it returns true'); return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] }); }).then(function(receipt) { assert.equal(receipt.logs.length, 1, 'triggers one event'); assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event'); assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from'); assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to'); assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount'); return tokenInstance.balanceOf(accounts[1]) }).then(function(reciept) { return tokenInstance.balanceOf(accounts[1]); }).then(function(balance){ assert.equal(balance.toNumber(), 250000, 'adds the amount to the recieving amount'); return tokenInstance.balanceOf(accounts[0]); }).then(function(balance){ assert.equal(balance.toNumber(), 999750000, 'deducts the amount from the sending account'); }); }); }); `

Result: Contract: Faicoin ✓ initalizes the contract with the correct values (89ms) ✓ allocates the initial supply upon deployment (54ms) ✓ transfers token ownership (206ms)

3 passing (382ms)

Etienereum commented 4 years ago

Thank you so much for this.

mohitrakhade20 commented 4 years ago
it("transfers token ownership", function () {
    return ValleyToken.deployed()
      .then(function (instance) {
        tokenInstance = instance;
        return tokenInstance.transfer.call(accounts[1], 9999999999999999);
      })
      .then(assert.fail)
      .catch(function (error) {
        assert(error.message, "error message must contain revert");
        return tokenInstance.transfer.call(accounts[1], 250000, {
          from: accounts[0],
        });
      })
      .then(function (success) {
        assert(success, true, "it returns true");
        return tokenInstance.transfer(accounts[1], 250000, {
          from: accounts[0],
        });
      })
      .then(function (receipt) {
        assert.equal(receipt.logs.length, 1, "triggers one event");
        assert.equal(
          receipt.logs[0].event,
          "Transfer",
          'should be the "Transfer" event'
        );
        assert.equal(
          receipt.logs[0].args._from,
          accounts[0],
          "logs the account the tokens are transferred from"
        );
        assert.equal(
          receipt.logs[0].args._to,
          accounts[1],
          "logs the account the tokens are transferred to"
        );
        assert.equal(
          receipt.logs[0].args._value,
          250000,
          "logs the transfer amount"
        );
        return tokenInstance.balanceOf(accounts[1]);
      })
      .then(function (reciept) {
        return tokenInstance.balanceOf(accounts[1]);
      })
      .then(function (balance) {
        assert.equal(
          balance.toNumber(),
          250000,
          "adds the amount to the recieving amount"
        );
        return tokenInstance.balanceOf(accounts[0]);
      })
      .then(function (balance) {
        assert.equal(
          balance.toNumber(),
          750000,
          "deducts the amount from the sending account"
        );
      });
  });
cgascons commented 3 years ago

Hi, just realized that, by replacing this

assert(error.message.indexOf('revert') >= 0, 'error message must contain revert');

with this

assert(error.message, "error message must contain revert");

makes the error go away, but it just won't make the test properly, right? I mean, after replacing that line I commented the

require(balanceOf[msg.sender] >= _value);

line from the transfer function in the token contract and it returned no errors, which I believe isn't intended?

aparna-14 commented 3 years ago

Hi @cgascons, l i'm getting another issue after applying changes. Can you pls tell me how to solve this issue? Here the error of my code. Contract: DappToken allocates the initial supply upon deployment: sets the total supply to 1,000,000

AnthonyJamez12 commented 3 years ago

Goated status, thank you!

BitBoomBox commented 2 years ago

add toString()

assert(error.message.toString().indexOf('revert') >= 0, 'error message must contain revert');

harshit3101 commented 2 years ago

Completing my transfer function solved this issue for me.

function transfer(address _to, uint256 _value) public returns (bool success) { require(balanceOf[msg.sender] >= _value); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; return true; }

it("transfers tokens ownership", function() { return HanuToken.deployed().then(function(tok) { var token = tok; return token.transfer.call(accounts[1], 99999999999999); }).then(assert.fail).catch(function(error) { assert(error.message.toString().indexOf('revert') >=0, 'error msg must contains revert'); }); });

rajeebkm commented 2 years ago

Follow the Transfer function and test cases below to get solution.

//Transfer function transfer(address _to, uint256 _value) public returns(bool success){ //Exception if account doen't have enough value require(balanceOf[msg.sender] >= _value, "Sender doesn't have sufficient balance"); balanceOf[msg.sender] -= _value; balanceOf[_to] += _value; //Trigers Transfer event emit Transfer(msg.sender, _to, _value); //Returns a boolean return true; }

//Test case

-------------------------Passing larger amount----------------------------------------------

it('transfers token ownership', function() {
    return RAJToken.deployed().then(function(instance) {
      tokenInstance = instance;
      // Test `require` statement first by transferring something larger than the sender's balance
      return tokenInstance.transfer.call(accounts[1], 99999999999999999999999);
    }).then(assert.fail).catch(function(error) {
      console.log(error.message); //To know the error message through console.log
      assert(error.message.toString().includes('overflow'), 'error message must contain overflow');
      return tokenInstance.transfer.call(accounts[1], 250000, { from: accounts[0] });
    }).then(function(success) {
      assert.equal(success, true, 'it returns true');
      return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] });
    }).then(function(receipt) {
      assert.equal(receipt.logs.length, 1, 'triggers one event');
      assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event');
      assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from');
      assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to');
      assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount');
      return tokenInstance.balanceOf(accounts[1]);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 250000, 'adds the amount to the receiving account');
      return tokenInstance.balanceOf(accounts[0]);
    }).then(function(balance) {
      assert.equal(balance.toNumber(), 750000, 'deducts the amount from the sending account');
    });
  });

--------------------------------------------Output----------------------------------------------------- Contract: RAJToken ✓ initializes the contract with correct values (112ms) ✓ allocates the initial supply upon deployment (100ms) overflow (fault="overflow", operation="BigNumber.from", value=1e+23, code=NUMERIC_FAULT, version=bignumber/5.0.8) ✓ transfers token ownership (2750ms)

PS: If error.message contains overflow word as you can see above in output, it will pass the test case. That means if you send larger value than your balance, it will result in overflow. so if result contains overflow word that we are asserting, that means it will pass the test case.

----------------------Passing lesser value-------------------------------

it('transfers token ownership', function() { return RAJToken.deployed().then(function(instance) { tokenInstance = instance; // Test require statement first by transferring something larger than the sender's balance return tokenInstance.transfer.call(accounts[1], 1); }).then(assert.fail).catch(function(error) { console.log(error.message); assert(error.message.toString().includes('overflow'), 'error message must contain overflow'); return tokenInstance.transfer.call(accounts[1], 250000, { from: accounts[0] }); }).then(function(success) { assert.equal(success, true, 'it returns true'); return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] }); }).then(function(receipt) { assert.equal(receipt.logs.length, 1, 'triggers one event'); assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event'); assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from'); assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to'); assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount'); return tokenInstance.balanceOf(accounts[1]); }).then(function(balance) { assert.equal(balance.toNumber(), 250000, 'adds the amount to the receiving account'); return tokenInstance.balanceOf(accounts[0]); }).then(function(balance) { assert.equal(balance.toNumber(), 750000, 'deducts the amount from the sending account'); }); }); --------------------------------------Output--------------------------------------- Contract: RAJToken ✓ initializes the contract with correct values (68ms) ✓ allocates the initial supply upon deployment (150ms) true 1) transfers token ownership

No events were emitted

2 passing (497ms) 1 failing

1) Contract: RAJToken transfers token ownership: AssertionError: error message must contain overflow

PS: If error.message doesn't contain overflow word as you can see above in output, it willn't pass the test case. That means if you send lesser value than your balance, it (error.message) will result true. so the result doesn't contain overflow word. Our assertion is false,so it will give the error message (AssertionError: error message must contain overflow). Test case willn't pass.

--------------------Final resolve solution----------------------

it('transfers token ownership', function() { return RAJToken.deployed().then(function(instance) { tokenInstance = instance; // Test require statement first by transferring something larger than the sender's balance return tokenInstance.transfer.call(accounts[1], 9999999999999999); }).then(assert.fail).catch(function(error) { assert(error.message.toString().includes('overflow'), 'error message must contain overflow'); return tokenInstance.transfer.call(accounts[1], 250000, { from: accounts[0] }); }).then(function(success) { assert.equal(success, true, 'it returns true'); return tokenInstance.transfer(accounts[1], 250000, { from: accounts[0] }); }).then(function(receipt) { assert.equal(receipt.logs.length, 1, 'triggers one event'); assert.equal(receipt.logs[0].event, 'Transfer', 'should be the "Transfer" event'); assert.equal(receipt.logs[0].args._from, accounts[0], 'logs the account the tokens are transferred from'); assert.equal(receipt.logs[0].args._to, accounts[1], 'logs the account the tokens are transferred to'); assert.equal(receipt.logs[0].args._value, 250000, 'logs the transfer amount'); return tokenInstance.balanceOf(accounts[1]); }).then(function(balance) { assert.equal(balance.toNumber(), 250000, 'adds the amount to the receiving account'); return tokenInstance.balanceOf(accounts[0]); }).then(function(balance) { assert.equal(balance.toNumber(), 750000, 'deducts the amount from the sending account'); }); });

------------------Output-------------------------

Contract: RAJToken ✓ initializes the contract with correct values (67ms) ✓ allocates the initial supply upon deployment (106ms) ✓ transfers token ownership (2818ms)

3 passing (3s)

I hope, you can under stand and use this code for solution. It will work.

Thanks