What are fakes?

Fakes are JavaScript objects that emulate the interface of a given Solidity contract. You can use fakes to customize the behavior of any public method or variable that a smart contract exposes.

When should I use a fake?

Fakes are a powerful tool when you want to test how a smart contract will interact with other contracts. Instead of initializing a full-fledged smart contract to interact with, you can simply create a fake that can provide pre-programmed responses.

Fakes are especially useful when the contracts that you need to interact with are relatively complex. For example, imagine that you’re testing a contract that needs to interact with another (very stateful) contract. Without smock, you’ll probably have to:

  1. Deploy the contract you need to interact with.

  2. Perform a series of transactions to get the contract into the relevant state.

  3. Run the test.

  4. Do this all over again for each test.

This is annoying, slow, and brittle. You might have to update a bunch of tests if the behavior of the other contract ever changes. Developers usually end up using tricks like state snapshots and complex test fixtures to get around this problem. Instead, you can use smock:

  1. Create a fake.

  2. Make your fake return the value you want it to return.

  3. Run the test.

Using fakes


Initialize with a contract name

const myFake = await smock.fake('MyContract');

Initialize with a contract ABI

const myFake = await smock.fake([ { ... } ]);

Initialize with a contract factory

const myContractFactory = await hre.ethers.getContractFactory('MyContract');
const myFake = await smock.fake(myContractFactory);

Initialize with a contract instance

const myContractFactory = await hre.ethers.getContractFactory('MyContract');
const myContract = await myContractFactory.deploy();
const myFake = await smock.fake(myContract);

Take full advantage of typescript and typechain

const myFake = await smock.fake<MyContract>('MyContract');


await smock.fake('MyContract', { ... }); // how to use

// options
  address?: string; // initialize fake at a specific address
  provider?: Provider; // initialize fake with a custom provider

Signing transactions

Every fake comes with a wallet property in order to make easy to sign transactions


Making a function return

Returning with the default value


Returning a fixed value


Returning a struct

  valueA: 1234,
  valueB: false,

Returning an array

myFake.myFunctionArray.returns([1, 2, 3]);

Returning a dynamic value

myFake.myFunction.returns(() => {
  if (Math.random() < 0.5) {
    return 0;
  } else {
    return 1;

Returning a value based on arguments


await myFake.myFunction(123); // returns 456

Returning a value with custom logic

myFake.getDynamicInput.returns(arg1 => arg1 * 10);

await myFake.getDynamicInput(123); // returns 1230

Returning at a specific call count

myFake.myFunction.returnsAtCall(0, 5678);
myFake.myFunction.returnsAtCall(1, 1234);

await myFake.myFunction(); // returns 5678
await myFake.myFunction(); // returns 1234

Making a function revert

Reverting with no data


Reverting with a string message

myFake.myFunction.reverts('Something went wrong');

Reverting with bytes data


Reverting at a specific call count

myFake.myFunction.revertsAtCall(1, 'Something went wrong');

await myFake.myFunction(); // returns 1234
await myFake.myFunction(); // reverts with 'Something went wrong'
await myFake.myFunction(); // returns 1234

Reverting based on arguments

myFake.myFunction.whenCalledWith(123).reverts('Something went wrong');

await myFake.myFunction(); // returns 1
await myFake.myFunction(123); // reverts with 'Something went wrong'

Resetting function behavior

Resetting a function to original behavior


await myFake.myFunction(); // reverts

myFake.myFunction.reset(); // resets behavior for all inputs of the function

await myFake.myFunction(); // returns 0

Asserting call count

Any number of calls


Called once


Called twice


Called three times


Called N times


Asserting call arguments or value

Called with specific arguments

expect(myFake.myFunction).to.have.been.calledWith(123, true, 'abcd');

Called with struct arguments

  myData: [1, 2, 3, 4],
  myNestedStruct: {
    otherValue: 5678

Called at a specific call index with arguments

expect(myFake.myFunction.atCall(2)).to.have.been.calledWith(1234, false);

Called once with specific arguments

expect(myFake.myFunction).to.have.been.calledOnceWith(1234, false);

Called with an specific call value


Asserting call order

Called before other function


Called after other function


Called immediately before other function


Called immediately after other function


Querying call arguments

Getting arguments at a specific call index


Getting call value at a specific call index


Manipulating fallback functions

Modifying the fallback function


Modifying the receive function


Delegated calls

Calls to a contract function via delegated calls do behave the same as a regular call, so you can enforce a return value, assert the calls details, etc… In addition, you also have custom assertions for delegated calls.

Assert delegated caller