10

I'm using Hardhat with TypeScript/Ethers/Chai. I can't find a way to test BigNumber values.

For example, expect(someBigNumber).to.be.equal.to.(otherBigNumber) will (understandably) throw an error like this one: AssertionError: expected 9999969797040000000000 to be a number or a date.

I installed chai-bn and followed the example here. I can't run the tests because Property 'bignumber' does not exist on type 'Assertion'. I can't figure out the issue and I can't find a working example either. chai-bignumber doesn't work either.

I'd appreciate if someone could point me in the right direction.

frostpad
  • 201
  • 1
  • 2
  • 5
  • The following package: https://www.npmjs.com/package/chai-ethers-bn works like a charm, but it's deprecated. – frostpad Jul 22 '21 at 14:39
  • 1
    The easy but verbose solution is to convert the bignumbers to strings before comparing them. That could work for you if you don't want to install anything else. Alternatively, you could try the @nomiclabs/hardhat-waffle plugin, that adds some chai matchers, including one for comparing big numbers. – Franco Victorio Jul 29 '21 at 12:54
  • My Hardhat-based template comes pre-configured with Hardhat and Waffle, which makes comparing BigNumbers a breeze. – Paul Razvan Berg Jun 21 '22 at 08:39

5 Answers5

7

I had the same error and solve it casting the BigNumber into Number.

  const contractBalance = await ethers.provider.getBalance(contract.address);
  const ownerBalance = await ethers.provider.getBalance(owner.address);

expect(Number(contractBalance)).to.be.greaterThan(0);

await contract.connect(owner).withdraw();

const contractBalanceAfterTxn = await ethers.provider.getBalance( contract.address ); const ownerBalanceAfterTxn = await ethers.provider.getBalance( owner.address );

expect(Number(contractBalanceAfterTxn)).to.be.equal(0); expect(Number(ownerBalanceAfterTxn)).to.be.greaterThan( Number(ownerBalance) );

contractBalanceAfterTxn BigNumber { value: "0" }

ownerBalance BigNumber { value: "9996943908220612206777" }

ownerBalanceAfterTxn BigNumber { value: "9997943866356142795098" }

✔ should withdraw if i'm the contract owner (942ms)

✔ should fail if i'm not the contract owner (233ms)

chiri
  • 71
  • 1
  • 1
  • Awesome and straightforward. Up voted. – Hooman Limouee Jun 21 '22 at 06:36
  • Number is a float. If your BigNumber value is bigger than Number.MAX_SAFE_INTEGER, storing it in a number will lose precision and/or fail. MAX_SAFE_INTEGER is 16 digits, 18 digit decimal tokens are ubiquitous, tread carefully. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER – WindowsEscapist Jun 21 '23 at 19:16
4

The ethereum-waffle package does this very well.

To use it add this to your hardhat.config.ts:

import chai from "chai";
import { solidity } from "ethereum-waffle";

chai.use(solidity);

Then in your tests you can directly compare ethers.js BigNumber values:

expect(await token.balanceOf(wallet.address)).to.equal(993);

See ethereum-waffle docs for more details.

3

Going through the ethers github, I saw this solution:

let num = ethers.BigNumber.from(12);
const INTEREST_RATE = 12;
assert(num.eq(ethers.BigNumber.from(INTEREST_RATE)));

Explanation: the eq() TypeScript function is in https://github.com/ethers-io/ethers.js/blob/master/packages/bignumber/src.ts/bignumber.ts#L156

The normal assert works for numbers, but not for BigNumbers

assert.equal(1, 1);           // equals

assert.equal(num, ethers.BigNumber.from(INTEREST_RATE)); // not equals

Jose4Linux
  • 221
  • 2
  • 5
3

Here I have a cleaner approach for future readers :

expect(await contract.bigNumFunc()).to.equal(ethers.utils.parseUnits("1000", 18));

contract is the contract that you have deployed.

bigNumFunc is a function in your solidity contract that returns a big number, it can be balanceOf or any other function.

Notice the ethers.utils.parseUnits is expecting first argument as string and the second argument is number of decimal points.

0

It is part of the ethers library. Here is a simple hardhat task that prints the account and their eth balance:

import { Signer } from '@ethersproject/abstract-signer';
import { BigNumber, ethers } from 'ethers';
import { task } from 'hardhat/config';
import { TASK_ACCOUNTS } from './task-names';

task(TASK_ACCOUNTS, 'Prints the list of accounts and their balances', async (_taskArgs, hre) => { const accounts: Signer[] = await hre.ethers.getSigners();

for (const account of accounts) { const address: string = await account.getAddress(); const balance: BigNumber = await hre.ethers.provider.getBalance(address); const eth = ethers.utils.formatEther(balance); console.log(address, eth); } });

Olshansky
  • 185
  • 9