Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/modern-tools-drop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@ethereum-waffle/chai": patch
"@ethereum-waffle/hardhat": patch
"@ethereum-waffle/optimism": patch
---

🦷 (Experimental) Automatically inject call history into hardhat provider
3 changes: 2 additions & 1 deletion waffle-chai/.mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ process.env.NODE_ENV = 'test'
module.exports = {
require: 'ts-node/register/transpile-only',
timeout: 50000,
spec: 'test/**/*.{js,ts}'
spec: 'test/**/*.{js,ts}',
file: 'test/test-setup.ts'
}
1 change: 1 addition & 0 deletions waffle-chai/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {supportChangeTokenBalance} from './matchers/changeTokenBalance';
import {supportChangeTokenBalances} from './matchers/changeTokenBalances';
import {supportCalledOnContract} from './matchers/calledOnContract/calledOnContract';
import {supportCalledOnContractWith} from './matchers/calledOnContract/calledOnContractWith';
import './inject-call-history';

export function waffleChai(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils) {
supportBigNumber(chai.Assertion, utils);
Expand Down
78 changes: 78 additions & 0 deletions waffle-chai/src/inject-call-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import type {RecordedCall} from '@ethereum-waffle/provider';
import {utils} from 'ethers';

/**
* Injects call history into hardhat provider,
* making it possible to use matchers like calledOnContract
*/

class CallHistory {
recordedCalls: RecordedCall[] = [];

addUniqueCall(call: RecordedCall) {
if (!this.recordedCalls.find(c => c.address === call.address && c.data === call.data)) {
this.recordedCalls.push(call);
}
}

clearAll() {
this.recordedCalls = [];
}
}

function toRecordedCall(message: any): RecordedCall {
return {
address: message.to?.buf ? utils.getAddress(utils.hexlify(message.to.buf)) : undefined,
data: message.data ? utils.hexlify(message.data) : '0x'
};
}

const inject = () => {
let waffle: any;
try {
waffle = require('hardhat')?.waffle;
} catch { return; }
if (!waffle || !waffle.provider) return;
const callHistory = new CallHistory();
(waffle.provider as any).clearCallHistory = () => {
callHistory.clearAll();
};

let beforeMessageListener: (message: any) => void | undefined;
const init = waffle.provider?._hardhatNetwork?.provider?._wrapped?._wrapped?._wrapped?._init;
if (!init) return;
waffle.provider._hardhatNetwork.provider._wrapped._wrapped._wrapped._init = async function () {
await init.apply(this);
if (typeof beforeMessageListener === 'function') {
// has to be here because of weird behaviour of init function, which requires us to re-register the handler.
waffle.provider
?._hardhatNetwork
?.provider
?._wrapped
?._wrapped
?._wrapped
?._node
?._vmTracer
?._vm
?.off?.('beforeMessage', beforeMessageListener);
}
beforeMessageListener = (message: any) => {
callHistory.addUniqueCall(toRecordedCall(message));
};
waffle.provider.callHistory = callHistory.recordedCalls;
waffle.provider
?._hardhatNetwork.provider
?._wrapped._wrapped
?._wrapped
?._node
?._vmTracer
?._vm
?.on?.('beforeMessage', beforeMessageListener);
};
};

let injected = false;
if (!injected && !!process.env.WAFFLE_EXPERIMENTAL_HARDHAT_CALL_HISTORY) {
injected = true;
inject();
}
7 changes: 0 additions & 7 deletions waffle-chai/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import {waffleChai} from '../src';

chai.use(chaiAsPromised);
chai.use(waffleChai);

export {calledOnContractTest} from './matchers/calledOnContract/calledOnContractTest';
export {calledOnContractValidatorsTest} from './matchers/calledOnContract/calledOnContractValidatorsTest';
export {calledOnContractWithTest} from './matchers/calledOnContract/calledOnContractWithTest';
Expand Down
6 changes: 6 additions & 0 deletions waffle-chai/test/test-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import {waffleChai} from '../src';

chai.use(chaiAsPromised);
chai.use(waffleChai);
1 change: 1 addition & 0 deletions waffle-hardhat/.mocharc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
process.env.NODE_ENV = 'test'
process.env.WAFFLE_EXPERIMENTAL_HARDHAT_CALL_HISTORY = true
module.exports = {
require: 'ts-node/register/transpile-only',
timeout: 50000,
Expand Down
62 changes: 0 additions & 62 deletions waffle-hardhat/src/inject-call-history.ts

This file was deleted.

7 changes: 6 additions & 1 deletion waffle-hardhat/test/test-setup.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
import '../src/inject-call-history';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import {solidity} from 'ethereum-waffle';

chai.use(chaiAsPromised);
chai.use(solidity);
3 changes: 2 additions & 1 deletion waffle-optimism/.mocharc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ process.env.NODE_ENV = 'test'
module.exports = {
require: 'ts-node/register/transpile-only',
timeout: 50000,
spec: 'test/**/*.test.{js,ts}'
spec: 'test/**/*.test.{js,ts}',
file: 'test/test-setup.ts'
}
6 changes: 6 additions & 0 deletions waffle-optimism/test/test-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import {solidity} from 'ethereum-waffle';

chai.use(chaiAsPromised);
chai.use(solidity);