Help wanted with rate testing for crowdsale

I tried out using the Crowdsale.test.js and tweaking it for my crowdsale. The only thing that doesn’t work is when I try to assign ‘ether(‘42’)’ to the const ‘value’ it spits out an error saying “safeerc20 low level call failed”. If I switch “const value = ether(‘5’)” to “const value = new BN(42)” it works fine. Why isn’t the ether() helper working? Or am I just doing something wrong?

const { balance, BN, constants, ether, expectEvent, expectRevert } = require('openzeppelin-test-helpers');
const { ZERO_ADDRESS } = constants;

const { expect } = require('chai');

const Crowdsale = artifacts.require('EduChainCrowdsale');
const SimpleToken = artifacts.require('EduChain');

contract('Crowdsale', function ([_, investor, wallet, purchaser]) {
  const rate = new BN(1);
  const value = ether('42');
  const tokenSupply = 105000000;
  const expectedTokenAmount = rate.mul(value)


  it('requires a non-null token', async function () {
await expectRevert(
  Crowdsale.new(rate, wallet, ZERO_ADDRESS),
  'Crowdsale: token is the zero address'
);
  });

  context('with token', async function () {
beforeEach(async function () {
  this.token = await SimpleToken.new(tokenSupply);
});

it('requires a non-zero rate', async function () {
  await expectRevert(
    Crowdsale.new(0, wallet, this.token.address), 'Crowdsale: rate is 0'
  );
});

it('requires a non-null wallet', async function () {
  await expectRevert(
    Crowdsale.new(rate, ZERO_ADDRESS, this.token.address), 'Crowdsale: wallet is the zero address'
  );
});

context('once deployed', async function () {
  beforeEach(async function () {
    this.crowdsale = await Crowdsale.new(rate, wallet, this.token.address);
    await this.token.transfer(this.crowdsale.address, tokenSupply);
  });

  describe('accepting payments', function () {
    describe('bare payments', function () {
      it('should accept payments', async function () {
        await this.crowdsale.send(value, { from: purchaser });
      });

      it('reverts on zero-valued payments', async function () {
        await expectRevert(
          this.crowdsale.send(0, { from: purchaser }), 'Crowdsale: weiAmount is 0'
        );
      });
    });

    describe('buyTokens', function () {
      it('should accept payments', async function () {
        await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
      });

      it('reverts on zero-valued payments', async function () {
        await expectRevert(
          this.crowdsale.buyTokens(investor, { value: 0, from: purchaser }), 'Crowdsale: weiAmount is 0'
        );
      });

      it('requires a non-null beneficiary', async function () {
        await expectRevert(
          this.crowdsale.buyTokens(ZERO_ADDRESS, { value: value, from: purchaser }),
          'Crowdsale: beneficiary is the zero address'
        );
      });
    });
  });

  describe('high-level purchase', function () {
    it('should log purchase', async function () {
      const { logs } = await this.crowdsale.sendTransaction({ value: value, from: investor });
      expectEvent.inLogs(logs, 'TokensPurchased', {
        purchaser: investor,
        beneficiary: investor,
        value: value,
        amount: expectedTokenAmount,
      });
    });

    it('should assign tokens to sender', async function () {
      await this.crowdsale.sendTransaction({ value: value, from: investor });
      expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
    });

    it('should forward funds to wallet', async function () {
      const balanceTracker = await balance.tracker(wallet);
      await this.crowdsale.sendTransaction({ value, from: investor });
      expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
    });
  });

  describe('low-level purchase', function () {
    it('should log purchase', async function () {
      const { logs } = await this.crowdsale.buyTokens(investor, { value: value, from: purchaser });
      expectEvent.inLogs(logs, 'TokensPurchased', {
        purchaser: purchaser,
        beneficiary: investor,
        value: value,
        amount: expectedTokenAmount,
      });
    });

    it('should assign tokens to beneficiary', async function () {
      await this.crowdsale.buyTokens(investor, { value, from: purchaser });
      expect(await this.token.balanceOf(investor)).to.be.bignumber.equal(expectedTokenAmount);
    });

    it('should forward funds to wallet', async function () {
      const balanceTracker = await balance.tracker(wallet);
      await this.crowdsale.buyTokens(investor, { value, from: purchaser });
      expect(await balanceTracker.delta()).to.be.bignumber.equal(value);
    });
  });
});
  });
});
1 Like

Hi @Roodiger

The reason why you are getting the error is that there aren’t enough tokens to fulfill the purchase in your test.

Rate: 1
Supply: 105,000,000 TKNbits

The Tokens documentation explains decimals:
https://docs.openzeppelin.com/contracts/2.x/tokens#a-note-on-decimals

The Crowdsale documentation explains rate:
https://docs.openzeppelin.com/contracts/2.x/crowdsales#crowdsale-rate

5 ETH = 5 * 10^18 wei
Using the formula TKNbits = rate * wei then the participant should get
1 * 5 * 10^18 = 5 * 10^18 TKNbits but the supply is only 105 * 10^6 TKNbits so there is not enough tokens to fulfill the purchase which results in an error.

1 Like

Hi @Roodiger Did the explanation make sense? If it answered your question can you mark my reply as the solution. Thanks :smile:

1 Like