Skip to content

Commit 9940630

Browse files
authoredAug 19, 2022
🦷 Automatically inject call history into hardhat provider (#776)
1 parent b6fd45b commit 9940630

File tree

11 files changed

+109
-72
lines changed

11 files changed

+109
-72
lines changed
 

‎.changeset/modern-tools-drop.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@ethereum-waffle/chai": patch
3+
"@ethereum-waffle/hardhat": patch
4+
"@ethereum-waffle/optimism": patch
5+
---
6+
7+
🦷 (Experimental) Automatically inject call history into hardhat provider

‎waffle-chai/.mocharc.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ process.env.NODE_ENV = 'test'
22
module.exports = {
33
require: 'ts-node/register/transpile-only',
44
timeout: 50000,
5-
spec: 'test/**/*.{js,ts}'
5+
spec: 'test/**/*.{js,ts}',
6+
file: 'test/test-setup.ts'
67
}

‎waffle-chai/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {supportChangeTokenBalance} from './matchers/changeTokenBalance';
1515
import {supportChangeTokenBalances} from './matchers/changeTokenBalances';
1616
import {supportCalledOnContract} from './matchers/calledOnContract/calledOnContract';
1717
import {supportCalledOnContractWith} from './matchers/calledOnContract/calledOnContractWith';
18+
import './inject-call-history';
1819

1920
export function waffleChai(chai: Chai.ChaiStatic, utils: Chai.ChaiUtils) {
2021
supportBigNumber(chai.Assertion, utils);
+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type {RecordedCall} from '@ethereum-waffle/provider';
2+
import {utils} from 'ethers';
3+
4+
/**
5+
* Injects call history into hardhat provider,
6+
* making it possible to use matchers like calledOnContract
7+
*/
8+
9+
class CallHistory {
10+
recordedCalls: RecordedCall[] = [];
11+
12+
addUniqueCall(call: RecordedCall) {
13+
if (!this.recordedCalls.find(c => c.address === call.address && c.data === call.data)) {
14+
this.recordedCalls.push(call);
15+
}
16+
}
17+
18+
clearAll() {
19+
this.recordedCalls = [];
20+
}
21+
}
22+
23+
function toRecordedCall(message: any): RecordedCall {
24+
return {
25+
address: message.to?.buf ? utils.getAddress(utils.hexlify(message.to.buf)) : undefined,
26+
data: message.data ? utils.hexlify(message.data) : '0x'
27+
};
28+
}
29+
30+
const inject = () => {
31+
let waffle: any;
32+
try {
33+
waffle = require('hardhat')?.waffle;
34+
} catch { return; }
35+
if (!waffle || !waffle.provider) return;
36+
const callHistory = new CallHistory();
37+
(waffle.provider as any).clearCallHistory = () => {
38+
callHistory.clearAll();
39+
};
40+
41+
let beforeMessageListener: (message: any) => void | undefined;
42+
const init = waffle.provider?._hardhatNetwork?.provider?._wrapped?._wrapped?._wrapped?._init;
43+
if (!init) return;
44+
waffle.provider._hardhatNetwork.provider._wrapped._wrapped._wrapped._init = async function () {
45+
await init.apply(this);
46+
if (typeof beforeMessageListener === 'function') {
47+
// has to be here because of weird behaviour of init function, which requires us to re-register the handler.
48+
waffle.provider
49+
?._hardhatNetwork
50+
?.provider
51+
?._wrapped
52+
?._wrapped
53+
?._wrapped
54+
?._node
55+
?._vmTracer
56+
?._vm
57+
?.off?.('beforeMessage', beforeMessageListener);
58+
}
59+
beforeMessageListener = (message: any) => {
60+
callHistory.addUniqueCall(toRecordedCall(message));
61+
};
62+
waffle.provider.callHistory = callHistory.recordedCalls;
63+
waffle.provider
64+
?._hardhatNetwork.provider
65+
?._wrapped._wrapped
66+
?._wrapped
67+
?._node
68+
?._vmTracer
69+
?._vm
70+
?.on?.('beforeMessage', beforeMessageListener);
71+
};
72+
};
73+
74+
let injected = false;
75+
if (!injected && !!process.env.WAFFLE_EXPERIMENTAL_HARDHAT_CALL_HISTORY) {
76+
injected = true;
77+
inject();
78+
}

‎waffle-chai/test/index.ts

-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
import chai from 'chai';
2-
import chaiAsPromised from 'chai-as-promised';
3-
import {waffleChai} from '../src';
4-
5-
chai.use(chaiAsPromised);
6-
chai.use(waffleChai);
7-
81
export {calledOnContractTest} from './matchers/calledOnContract/calledOnContractTest';
92
export {calledOnContractValidatorsTest} from './matchers/calledOnContract/calledOnContractValidatorsTest';
103
export {calledOnContractWithTest} from './matchers/calledOnContract/calledOnContractWithTest';

‎waffle-chai/test/test-setup.ts

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import chai from 'chai';
2+
import chaiAsPromised from 'chai-as-promised';
3+
import {waffleChai} from '../src';
4+
5+
chai.use(chaiAsPromised);
6+
chai.use(waffleChai);

‎waffle-hardhat/.mocharc.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
process.env.NODE_ENV = 'test'
2+
process.env.WAFFLE_EXPERIMENTAL_HARDHAT_CALL_HISTORY = true
23
module.exports = {
34
require: 'ts-node/register/transpile-only',
45
timeout: 50000,

‎waffle-hardhat/src/inject-call-history.ts

-62
This file was deleted.

‎waffle-hardhat/test/test-setup.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
import '../src/inject-call-history';
1+
import chai from 'chai';
2+
import chaiAsPromised from 'chai-as-promised';
3+
import {solidity} from 'ethereum-waffle';
4+
5+
chai.use(chaiAsPromised);
6+
chai.use(solidity);

‎waffle-optimism/.mocharc.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ process.env.NODE_ENV = 'test'
22
module.exports = {
33
require: 'ts-node/register/transpile-only',
44
timeout: 50000,
5-
spec: 'test/**/*.test.{js,ts}'
5+
spec: 'test/**/*.test.{js,ts}',
6+
file: 'test/test-setup.ts'
67
}
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import chai from 'chai';
2+
import chaiAsPromised from 'chai-as-promised';
3+
import {solidity} from 'ethereum-waffle';
4+
5+
chai.use(chaiAsPromised);
6+
chai.use(solidity);

0 commit comments

Comments
 (0)
Please sign in to comment.