UNPKG

@ethereum-waffle/chai

Version:

A sweet set of chai matchers for your blockchain testing needs.

73 lines 4.27 kB
import { BigNumber } from 'ethers'; import { callPromise } from '../call-promise'; import { getAddressOf } from './misc/account'; import { getAddresses, getBalances } from './misc/balance'; export function supportChangeEtherBalances(Assertion) { Assertion.addMethod('changeEtherBalances', function (accounts, balanceChanges, options) { callPromise(this); const isNegated = this.__flags.negate === true; const derivedPromise = this.callPromise.then(() => { if (!('txResponse' in this)) { throw new Error('The changeEtherBalances matcher must be called on a transaction'); } if (accounts.some(account => typeof account === 'string')) { throw new Error('A string address cannot be used as an account in changeEtherBalances.' + ' Expecting an instance of Ethers Account.'); } return Promise.all([ getBalanceChanges(this.txResponse, accounts, options), getAddresses(accounts) ]); }).then(([actualChanges, accountAddresses]) => { const isCurrentlyNegated = this.__flags.negate === true; this.__flags.negate = isNegated; const margin = (options === null || options === void 0 ? void 0 : options.errorMargin) ? options.errorMargin : '0'; if (BigNumber.from(margin).eq(0)) { this.assert(actualChanges.every((change, ind) => change.lte(BigNumber.from(balanceChanges[ind]).add(margin)) && change.gte(BigNumber.from(balanceChanges[ind]).sub(margin))), `Expected ${accountAddresses} to change balance by ${balanceChanges} wei, ` + `but it has changed by ${actualChanges} wei`, `Expected ${accountAddresses} to not change balance by ${balanceChanges} wei,`, balanceChanges.map((balanceChange) => balanceChange.toString()), actualChanges.map((actualChange) => actualChange.toString())); } else { actualChanges.forEach((change, ind) => { const low = BigNumber.from(balanceChanges[ind]).sub(margin); const high = BigNumber.from(balanceChanges[ind]).add(margin); this.assert(change.lte(high) && change.gte(low), `Expected "${accountAddresses[ind]}" balance to change within [${[low, high]}] wei, ` + `but it has changed by ${change} wei`, `Expected "${accountAddresses[ind]}" balance to not change within [${[low, high]}] wei`, balanceChanges[ind], change); }); } this.__flags.negate = isCurrentlyNegated; }); this.then = derivedPromise.then.bind(derivedPromise); this.catch = derivedPromise.catch.bind(derivedPromise); this.callPromise = derivedPromise; return this; }); } export async function getBalanceChanges(txResponse, accounts, options) { const txReceipt = await txResponse.wait(); const txBlockNumber = txReceipt.blockNumber; const balancesAfter = await getBalances(accounts, txBlockNumber); const balancesBefore = await getBalances(accounts, txBlockNumber - 1); const txFees = await getTxFees(accounts, txResponse, options); return balancesAfter.map((balance, ind) => balance.add(txFees[ind]).sub(balancesBefore[ind])); } async function getTxFees(accounts, txResponse, options) { return Promise.all(accounts.map(async (account) => { var _a; if ((options === null || options === void 0 ? void 0 : options.includeFee) !== true && await getAddressOf(account) === txResponse.from) { const txReceipt = await txResponse.wait(); const gasPrice = (_a = txResponse.gasPrice) !== null && _a !== void 0 ? _a : txReceipt.effectiveGasPrice; const gasUsed = txReceipt.gasUsed; const txFee = gasPrice.mul(gasUsed); const provider = account.provider; if (typeof provider.getL1Fee === 'function') { const l1Fee = await provider.getL1Fee(txReceipt.transactionHash); return txFee.add(l1Fee); } return txFee; } return 0; })); } //# sourceMappingURL=changeEtherBalances.js.map