0

I want to explain you the problem so that you don't need to read the whole files. BirTokenSale contract is trying use the tokens given to it by another contract ,BirToken contract, and send the money to the requesting buyer.

To make sure that the requested amount is less than the tokens available, requie statemt is used , but

I got this error: AssertionError: cannot purchase more than tokens available.

I checked the line which showed this error and these are the lines responsible for this error in BirTokenSale.js:

// tokenSaleInstance is an instance of BirTokenSale contract(which has 500 tokens, given to it by BirToken contract)

 '''
  return tokenSaleInstance.BuyTokens(501,{from:buyer,value:numberOfTokens*tokenPrice}) ;
    }).then(assert.fail).catch(function(error) {
        assert(error.message.indexOf('revert') >=0,'cannot purchase more than tokens available');  
 '''

And the below require statemnt is in the BirTokenSale.sol :

// tokencontract is an instance of BirToken contract

function BuyTokens(uint _numberOfTokens)public payable{
    //require that value  is equal tp tokens
    require(msg.value == mul(_numberOfTokens,tokenPrice),'');

    //   THIS LINE!!!  
    require(tokenContract.balanceOf(address(this)) >= _numberOfTokens,'');

    //require that a trasfer is successful
    require(tokenContract.transfer(msg.sender,_numberOfTokens),'');

    //keep reack of tokensold
    tokenSold += _numberOfTokens;
    //trigger sell event
    emit Sell(msg.sender,_numberOfTokens);
}

earlier I had written : "require(tokenContract.balanceOf(this) >= _numberOfTokens,''); " , but this showed an error , so got the solution(from stackoverflow) that is to use 'address(this)', but the error remains.

Here are the files for your reference :

// BirTokenSale.sol

''' pragma solidity >=0.4.22 <0.7.0; import "./BirToken.sol"; contract BirTokenSale{

address admin;
BirToken public tokenContract;
//without public it showed the errpr that tokenPrice doesn'r exisst
uint public tokenPrice;
uint public tokenSold;
constructor(BirToken _takenContract,uint _tokenPrice)public{
    //assign an admin
    admin = msg.sender;
    //Takem contract
    tokenContract = _takenContract;
    //Tooken  Price
    tokenPrice = _tokenPrice;
}
event Sell(
    address _buyer,
    uint _amount
);

//multiply function
function mul(uint x, uint y) internal pure returns (uint z) {
    require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
}
//Buy Tokens
function BuyTokens(uint _numberOfTokens)public payable{
    //require that value  is equal tp tokens
    require(msg.value == mul(_numberOfTokens,tokenPrice),'');
    //require that the contract has enough tokens
    require(tokenContract.balanceOf(address(this)) >= _numberOfTokens,'');
    //require that a trasfer is successful
    require(tokenContract.transfer(msg.sender,_numberOfTokens),'');
    //keep reack of tokensold
    tokenSold += _numberOfTokens;
    //trigger sell event
    emit Sell(msg.sender,_numberOfTokens);
}

}

'''

// BirTokenSale.js

    var BirTokenSale=artifacts.require("BirTokenSale");
var BirToken=artifacts.require("BirToken");

contract('BirTokenSale',function(accounts){
    var tokenSaleInstance;
    var tokenPrice=1000000000000000;// in wei
    var buyer=accounts[1];
    var numberOfTokens;
    var tokenInstance;
    var admin=accounts[0];
    var tokensAvail=500;
    it('Initializes the contract with the correct the values',function(){
        return BirTokenSale.deployed().then(function(instance){
        tokenSaleInstance=instance;
            // to check if the contract address has been creatred
            return tokenSaleInstance.address
        })
        .then(function(address){
            assert.notEqual(address,0x0,'has contract addre ss');
            return tokenSaleInstance.tokenContract();
        })
        .then(function(address){
            assert.notEqual(address,0x0,'has a token contract');
            return tokenSaleInstance.tokenPrice();
        })
        .then(function(price){
            assert.equal(price,tokenPrice,'token price is correct');
        });
    });
    it('facilitates token buying',function(){
        return BirToken.deployed().then(function(instance){
            //gran tokenInstance first
            tokenInstance=instance;
            return BirTokenSale.deployed();
        }).then(function(instance){ 
            //then gran tokenSaleInstance
            tokenSaleInstance=instance;
            //provision 50% of tpkems tp the admin
            return tokenInstance.transfer(tokenSaleInstance.address,tokensAvail,{from:admin});    
        }).then(function(receipt){
           // return tokenInstance.transfer(tokenSaleInstance.address,tokensAvail,{from:admin});
            numberOfTokens=10;
            return tokenSaleInstance.BuyTokens(numberOfTokens,{from:buyer,value:numberOfTokens*tokenPrice});      
        })
        //below is the receipt due to the above transaction
        .then(function(receipt){
            assert.equal(receipt.logs.length, 1, 'triggers one event');
            assert.equal(receipt.logs[0].event, 'Sell', 'should be the "Sell" event');
            assert.equal(receipt.logs[0].args._buyer, buyer, 'logs the account that purchased the tokens');
            assert.equal(receipt.logs[0].args._amount, numberOfTokens, 'logs the number of tokens purchased');  
            return tokenSaleInstance.tokenSold();
        })
        .then(function(amount){
            assert.equal(amount.toNumber(),numberOfTokens,'increments the number of tokens sold');
            return tokenInstance.balanceOf(buyer); 
        }).then(function(balance){ 
            assert.equal(balance.toNumber,numberOfTokens);
            return tokenInstance.balanceOf(tokenSaleInstance.address); 
        }).then(function(balance){ 
            assert.equal(balance.toNumber,tokensAvail-numberOfTokens);
            //try to buy tokrns different from the ether value
            return tokenSaleInstance.BuyTokens(numberOfTokens,{from:buyer,value:1});      
        })
        .then(assert.fail).catch(function(error) {
            assert(error.message.indexOf('revert') >=    0,'msg.value must equal number if of tokens in wei');  
            return tokenSaleInstance.BuyTokens(501,{from:buyer,value:numberOfTokens*tokenPrice}) ;
        }).then(assert.fail).catch(function(error) {
            assert(error.message.indexOf('revert') >=0,'cannot purchase more than tokens available');  
        });
    });

});
0

The unit test is verifying that the transaction has failed.

I'd suggest to add OpenZeppelin Test Helpers to your project.

The modify the contract to revert with a message and test for that message.

//Buy Tokens
function BuyTokens(uint _numberOfTokens)public payable{
    //require that value  is equal tp tokens
    require(msg.value == mul(_numberOfTokens,tokenPrice),'Invalid price');
    //require that the contract has enough tokens
    require(tokenContract.balanceOf(address(this)) >= _numberOfTokens,'Not enough tokens available');
    //require that a trasfer is successful
    require(tokenContract.transfer(msg.sender,_numberOfTokens),'Transfer failed');
    //keep reack of tokensold
    tokenSold += _numberOfTokens;
    //trigger sell event
    emit Sell(msg.sender,_numberOfTokens);
}

Then modify the test to use helpers

const { expectRevert } = require('@openzeppelin/test-helpers');


.... // other tests


it("Revert buying - not enough tokens", async () => {
  await expectRevert(
    tokenSaleInstance.BuyTokens(501,{from:buyer,value:numberOfTokens*tokenPrice}),
    'Not enough tokens available'
  );
});

1
  • 1
    thanks @Ismael i will learn about openzeppelin as i am a beginner. thanks for your precious time May 2 '20 at 5:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.