Skip to content

Commit

Permalink
chore(release): 2.3.0 (#157)
Browse files Browse the repository at this point in the history
* feat: added support for call value (#142)
* feat: arrays support for setVariable (#144)
* feat: update ethereumjs vm and hardhat (#155)

Co-authored-by: 0xOneTony <[email protected]>
  • Loading branch information
0xGorilla and 0xOneTony authored Sep 8, 2022
1 parent 466d944 commit 9a2b350
Show file tree
Hide file tree
Showing 22 changed files with 975 additions and 369 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v1
with:
node-version: "12.x"
node-version: "14.x"

- name: Install dependencies
run: yarn --frozen-lockfile
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
- name: Install node
uses: actions/setup-node@v1
with:
node-version: "12.x"
node-version: "14.x"

- name: Install dependencies
run: yarn --frozen-lockfile
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

## [2.3.0](https://github.com/defi-wonderland/smock/compare/v2.1.0...v2.3.0) (2022-09-08)


### Features

* added support for call value ([#142](https://github.com/defi-wonderland/smock/issues/142)) ([3c2b80b](https://github.com/defi-wonderland/smock/commit/3c2b80b72fe146634b999df5b9bb9ef5ffc27508))
* arrays support for setVariable ([#144](https://github.com/defi-wonderland/smock/issues/144)) ([91a7aad](https://github.com/defi-wonderland/smock/commit/91a7aadf0cfa14ba52edb98c15fa0d38562fef39))
* return hardhat errors on factory failures ([#125](https://github.com/defi-wonderland/smock/issues/125)) ([3b626a3](https://github.com/defi-wonderland/smock/commit/3b626a3891c07ba224d2f12386bae95522843e2b))
* update ethereumjs vm and hardhat ([#155](https://github.com/defi-wonderland/smock/issues/155)) ([b71cfd1](https://github.com/defi-wonderland/smock/commit/b71cfd118a2a9579517769c0c31abede7d83ca71))


### Bug Fixes

* delegated calls support ([#132](https://github.com/defi-wonderland/smock/issues/132)) ([812c335](https://github.com/defi-wonderland/smock/commit/812c3354d77603d8a6db172f5297c8e49625a98b))
* duplicated type ([#138](https://github.com/defi-wonderland/smock/issues/138)) ([823b0ea](https://github.com/defi-wonderland/smock/commit/823b0ea7ed422636e4e763576b6975a422728522))

## [2.2.0](https://github.com/defi-wonderland/smock/compare/v2.1.0...v2.2.0) (2022-07-12)


Expand Down
18 changes: 16 additions & 2 deletions docs/source/fakes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,8 @@ Called N times
expect(myFake.myFunction).to.have.callCount(123);
Asserting call arguments
************************
Asserting call arguments or value
*********************************

Called with specific arguments
##############################
Expand Down Expand Up @@ -313,6 +313,13 @@ Called once with specific arguments
expect(myFake.myFunction).to.have.been.calledOnceWith(1234, false);
Called with an specific call value
###################################

.. code-block:: typescript
expect(myFake.myFunction).to.have.been.calledWithValue(1234);
Asserting call order
********************

Expand Down Expand Up @@ -355,6 +362,13 @@ Getting arguments at a specific call index
expect(myFake.myFunction.getCall(0).args[0]).to.be.gt(50);
Getting call value at a specific call index
##########################################

.. code-block:: typescript
expect(myFake.myFunction.getCall(0).value).to.eq(1);
Manipulating fallback functions
*******************************

Expand Down
15 changes: 10 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@defi-wonderland/smock",
"version": "2.2.0",
"version": "2.3.0",
"description": "The Solidity mocking library",
"keywords": [
"ethereum",
Expand Down Expand Up @@ -44,7 +44,8 @@
"release": "yarn build && yarn docs:md && standard-version",
"pre-release": "yarn build && standard-version --prerelease rc",
"docs:install": "pip install -r docs/requirements.txt",
"docs:watch": "sphinx-autobuild -a docs/source docs/_build/html --watch docs/source --watch README.rst"
"docs:watch": "sphinx-autobuild -a docs/source docs/_build/html --watch docs/source --watch README.rst",
"clean": "rm -rf ./dist ./artifacts ./cache ./node_modules ./typechained"
},
"lint-staged": {
"*.{js,css,md,ts}": "prettier --write",
Expand All @@ -59,7 +60,9 @@
"@ethereumjs/vm": "5.3.1"
},
"dependencies": {
"@nomiclabs/ethereumjs-vm": "^4.2.2",
"@nomicfoundation/ethereumjs-evm": "^1.0.0-rc.3",
"@nomicfoundation/ethereumjs-util": "^8.0.0-rc.3",
"@nomicfoundation/ethereumjs-vm": "^6.0.0-rc.3",
"diff": "^5.0.0",
"lodash.isequal": "^4.5.0",
"lodash.isequalwith": "^4.4.0",
Expand All @@ -75,19 +78,21 @@
"@typechain/hardhat": "2.0.2",
"@types/chai": "4.2.18",
"@types/chai-as-promised": "7.1.5",
"@types/debug": "^4.1.4",
"@types/diff": "^5.0.1",
"@types/lodash": "4.14.170",
"@types/lodash.isequal": "^4.5.5",
"@types/lodash.isequalwith": "^4.4.6",
"@types/mocha": "8.2.2",
"@types/node": "15.12.2",
"@types/readable-stream": "^2.3.13",
"@types/semver": "^7.3.8",
"chai": "4.3.4",
"chai-as-promised": "7.1.1",
"cross-env": "7.0.3",
"ethereum-waffle": "3.4.0",
"ethers": "5.4.1",
"hardhat": "2.3.0",
"hardhat": "2.11.0",
"hardhat-preprocessor": "0.1.4",
"husky": "6.0.0",
"inquirer": "8.1.0",
Expand All @@ -104,7 +109,7 @@
"ts-node": "10.0.0",
"tsconfig-paths": "^3.9.0",
"typechain": "5.1.1",
"typescript": "4.3.2"
"typescript": "4.5.2"
},
"peerDependencies": {
"@ethersproject/abi": "^5",
Expand Down
1 change: 1 addition & 0 deletions src/chai-plugin/matchers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export const matchers: Chai.ChaiPlugin = (chai: Chai.ChaiStatic, utils: Chai.Cha
smockMethodWithWatchableContractArg('calledImmediatelyBefore', 'been called immediately before %1');
smockMethodWithWatchableContractArg('calledImmediatelyAfter', 'been called immediately after %1');
smockMethod('calledWith', 'been called with arguments %*', '%D');
smockMethod('calledWithValue', 'been called with value %*', '%D');
smockMethod('calledOnceWith', 'been called exactly once with arguments %*', '%D');
smockMethod('delegatedFrom', 'been called via a delegated call by %*', '');
};
5 changes: 5 additions & 0 deletions src/chai-plugin/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { BigNumber } from 'ethers';
import { WatchableContractFunction } from '../index';

declare global {
Expand Down Expand Up @@ -50,6 +51,10 @@ declare global {
* Returns true if call received provided arguments.
*/
calledWith(...args: any[]): Assertion;
/**
* Returns true if call received the provided value.
*/
calledWithValue(value: BigNumber): Assertion;
/**
* Returns true when called at exactly once with the provided arguments.
*/
Expand Down
11 changes: 6 additions & 5 deletions src/factories/smock-contract.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Message from '@nomiclabs/ethereumjs-vm/dist/evm/message';
import { Message } from '@nomicfoundation/ethereumjs-evm/dist/message';
import { FactoryOptions } from '@nomiclabs/hardhat-ethers/types';
import { BaseContract, ContractFactory, ethers } from 'ethers';
import { BaseContract, BigNumber, ContractFactory, ethers } from 'ethers';
import { Interface } from 'ethers/lib/utils';
import { ethers as hardhatEthers } from 'hardhat';
import { Observable } from 'rxjs';
Expand Down Expand Up @@ -158,7 +158,7 @@ function parseAndFilterBeforeMessages(
// Ensure the message is directed to this contract
filter((message) => {
const target = message.delegatecall ? message.codeAddress : message.to;
return target.toString().toLowerCase() === contractAddress.toLowerCase();
return target?.toString().toLowerCase() === contractAddress.toLowerCase();
}),
map((message) => parseMessage(message, contractInterface, sighash)),
share()
Expand Down Expand Up @@ -205,8 +205,9 @@ function parseMessage(message: Message, contractInterface: Interface, sighash: s
return {
args: sighash === null ? toHexString(message.data) : getMessageArgs(message.data, contractInterface, sighash),
nonce: Sandbox.getNextNonce(),
target: fromFancyAddress(message.delegatecall ? message.codeAddress : message.to),
delegatedFrom: message.delegatecall ? fromFancyAddress(message.to) : undefined,
value: BigNumber.from(message.value.toString()),
target: fromFancyAddress(message.delegatecall ? message.codeAddress : message.to!),
delegatedFrom: message.delegatecall ? fromFancyAddress(message.to!) : undefined,
};
}

Expand Down
12 changes: 5 additions & 7 deletions src/logic/programmable-function-logic.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { EVMResult } from '@nomiclabs/ethereumjs-vm/dist/evm/evm';
import { VmError } from '@nomiclabs/ethereumjs-vm/dist/exceptions';
import BN from 'bn.js';
import { EVMResult } from '@nomicfoundation/ethereumjs-evm/dist/evm';
import { EvmError } from '@nomicfoundation/ethereumjs-evm/dist/exceptions';
import { ethers } from 'ethers';
import { findLast } from 'lodash';
import { Observable, withLatestFrom } from 'rxjs';
Expand Down Expand Up @@ -87,10 +86,9 @@ export class ProgrammableFunctionLogic extends WatchableFunctionLogic {
const answer = this.getCallAnswer(call);

if (answer) {
result.gasUsed = new BN(0);
result.execResult.gasUsed = new BN(0);
result.execResult.gas = BigInt(0);
if (answer.shouldRevert) {
result.execResult.exceptionError = new VmError('smock revert' as any);
result.execResult.exceptionError = new EvmError('smock revert' as any);
result.execResult.returnValue = this.encodeRevertReason(answer.value);
} else {
result.execResult.exceptionError = undefined;
Expand Down Expand Up @@ -122,7 +120,7 @@ export class ProgrammableFunctionLogic extends WatchableFunctionLogic {
let encodedReturnValue: string = '0x';
try {
encodedReturnValue = this.encoder(toEncode);
} catch (err) {
} catch (err: any) {
if (err.code === 'INVALID_ARGUMENT') {
if (typeof toEncode !== 'string') {
throw new Error(`Failed to encode return value for ${this.name}`);
Expand Down
4 changes: 4 additions & 0 deletions src/logic/watchable-function-logic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class WatchableFunctionLogic {
return !!this.callHistory.find((call) => this.isDeepEqual(call.args, expectedCallArgs));
}

calledWithValue(value: BigNumber): boolean {
return !!this.callHistory.find((call) => call.value.eq(value));
}

alwaysCalledWith(...expectedCallArgs: unknown[]): boolean {
const callWithOtherArgs = this.callHistory.find((call) => !this.isDeepEqual(call.args, expectedCallArgs));
return this.getCalled() && !callWithOtherArgs;
Expand Down
19 changes: 6 additions & 13 deletions src/observable-vm.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,25 @@
import VM from '@nomiclabs/ethereumjs-vm';
import { EVMResult } from '@nomiclabs/ethereumjs-vm/dist/evm/evm';
import Message from '@nomiclabs/ethereumjs-vm/dist/evm/message';
import { Transaction } from 'ethers';
import { EVMResult } from '@nomicfoundation/ethereumjs-evm/dist/evm';
import { Message } from '@nomicfoundation/ethereumjs-evm/dist/message';
import { VM } from '@nomicfoundation/ethereumjs-vm';
import { Observable, Subject } from 'rxjs';
import { filter, share } from 'rxjs/operators';
import { SmockVMManager } from './types';

export class ObservableVM {
private vm: VM;
private beforeTx$: Observable<Transaction>;
private beforeMessage$: Observable<Message>;
private afterMessage$: Observable<EVMResult>;

constructor(vm: VM) {
if (!vm) throw new Error('VM is not defined');

this.vm = vm;
this.beforeTx$ = ObservableVM.fromEvent<Transaction>(vm, 'beforeTx');
this.beforeMessage$ = ObservableVM.fromEvent<Message>(vm, 'beforeMessage');
this.afterMessage$ = ObservableVM.fromEvent<EVMResult>(vm, 'afterMessage');
}

getManager(): SmockVMManager {
return (this.vm.pStateManager || this.vm.stateManager) as SmockVMManager;
}

getBeforeTx(): Observable<Transaction> {
return this.beforeTx$;
return this.vm.stateManager as SmockVMManager;
}

getBeforeMessages(): Observable<Message> {
Expand All @@ -37,9 +30,9 @@ export class ObservableVM {
return this.afterMessage$;
}

private static fromEvent<T>(vm: VM, eventName: string): Observable<T> {
private static fromEvent<T>(vm: VM, eventName: 'beforeMessage' | 'afterMessage'): Observable<T> {
const subject = new Subject<T>();
vm.on(eventName, (event: T) => subject.next(event));
vm.evm.events?.on(eventName, (event: any) => subject.next(event));
return subject.asObservable().pipe(share());
}
}
2 changes: 1 addition & 1 deletion src/sandbox.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import VM from '@nomiclabs/ethereumjs-vm';
import { VM } from '@nomicfoundation/ethereumjs-vm';
import { FactoryOptions } from '@nomiclabs/hardhat-ethers/types';
import { BaseContract, ContractFactory, ethers } from 'ethers';
import hre from 'hardhat';
Expand Down
10 changes: 6 additions & 4 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import { Fragment, Interface, JsonFragment } from '@ethersproject/abi';
import { Provider } from '@ethersproject/abstract-provider';
import { Signer } from '@ethersproject/abstract-signer';
import { BaseContract, ContractFactory, ethers } from 'ethers';
import { Address } from '@nomicfoundation/ethereumjs-util/dist/address';
import { BaseContract, BigNumber, ContractFactory, ethers } from 'ethers';
import { EditableStorageLogic } from './logic/editable-storage-logic';
import { ReadableStorageLogic } from './logic/readable-storage-logic';
import { WatchableFunctionLogic } from './logic/watchable-function-logic';
Expand All @@ -20,9 +21,9 @@ export interface FakeContractOptions {
export type ProgrammedReturnValue = any;

export interface SmockVMManager {
putContractCode: (address: Buffer, code: Buffer) => Promise<void>;
getContractStorage: (address: Buffer, slotHash: Buffer) => Promise<Buffer>;
putContractStorage: (address: Buffer, slotHash: Buffer, slotValue: Buffer) => Promise<void>;
putContractCode: (address: Address, code: Buffer) => Promise<void>;
getContractStorage: (address: Address, slotHash: Buffer) => Promise<Buffer>;
putContractStorage: (address: Address, slotHash: Buffer, slotValue: Buffer) => Promise<void>;
}

export interface WatchableContractFunction {
Expand All @@ -35,6 +36,7 @@ export interface ContractCall {
args: unknown[] | string;
nonce: number;
target: string;
value: BigNumber;
delegatedFrom?: string;
}

Expand Down
23 changes: 7 additions & 16 deletions src/utils/hardhat.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* Imports: External */
import { Address } from '@nomicfoundation/ethereumjs-util/dist/address';
import { HardhatNetworkProvider } from 'hardhat/internal/hardhat-network/provider/provider';
import { HardhatRuntimeEnvironment } from 'hardhat/types';
import { fromHexString, toHexString } from '.';
import { toHexString } from '.';

/**
* Finds the "base" Ethereum provider of the current hardhat environment.
Expand Down Expand Up @@ -51,23 +52,13 @@ export const getHardhatBaseProvider = async (runtime: HardhatRuntimeEnvironment)
};

/**
* Converts a string into the fancy new address thing that ethereumjs-vm v5 expects while also
* maintaining backwards compatibility with ethereumjs-vm v4.
* Converts a string into the fancy new address thing that ethereumjs-vm v6 expects
*
* @param address String address to convert into the fancy new address type.
* @returns Fancified address.
*/
export const toFancyAddress = (address: string): Buffer => {
const fancyAddress = fromHexString(address);
(fancyAddress as any).buf = fromHexString(address);
(fancyAddress as any).toString = (encoding?: any) => {
if (encoding === undefined) {
return address.toLowerCase();
} else {
return fromHexString(address).toString(encoding);
}
};
return fancyAddress;
export const toFancyAddress = (address: string): Address => {
return Address.fromString(address);
};

/**
Expand All @@ -76,10 +67,10 @@ export const toFancyAddress = (address: string): Buffer => {
* @param fancyAddress Fancy address to turn into a string.
* @returns Way more boring address.
*/
export const fromFancyAddress = (fancyAddress: any): string => {
export const fromFancyAddress = (fancyAddress: Address): string => {
if (fancyAddress.buf) {
return toHexString(fancyAddress.buf);
} else {
return toHexString(fancyAddress);
return fancyAddress.toString();
}
};
Loading

0 comments on commit 9a2b350

Please sign in to comment.