![Maven Central Adds Sigstore Signature Validation](https://cdn.sanity.io/images/cgdhsj6q/production/7da3bc8a946cfb5df15d7fcf49767faedc72b483-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Maven Central Adds Sigstore Signature Validation
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
@gregdhill/mock-contract
Advanced tools
Library for mocking smart contract dependencies during unit testing.
In the current version of waffle (v2.x.x) you will install this package as a dependency of the main waffle package - ethereum-waffle
.
yarn add --dev ethereum-waffle
npm install --save-dev ethereum-waffle
If you want to use this package directly please install it via:
yarn add --dev @ethereum-waffle/mock-contract
npm install --save-dev @ethereum-waffle/mock-contract
Create an instance of a mock contract providing the ABI/interface of the smart contract you want to mock:
const {deployMockContract} = require('@ethereum-waffle/mock-contract');
...
const mockContract = await deployMockContract(wallet, contractAbi);
Mock contract can now be passed into other contracts by using the address
attribute.
Return values for mocked functions can be set using:
await mockContract.mock.<nameOfMethod>.returns(<value>)
await mockContract.mock.<nameOfMethod>.withArgs(<arguments>).returns(<value>)
Methods can also be set up to be reverted using:
await mockContract.mock.<nameOfMethod>.reverts()
await mockContract.mock.<nameOfMethod>.withArgs(<arguments>).reverts()
Sometimes you may have an overloaded function name:
contract OverloadedFunctions is Ownable {
function burn(uint256 amount) external returns (bool) {
// ...
}
function burn(address user, uint256 amount) external onlyOwner returns (bool) {
// ...
}
}
You may choose which function to call by using its signature:
await mockContract.mock['burn(uint256)'].returns(true)
await mockContract.mock['burn(address,uint256)'].withArgs('0x1234...', 1000).reverts()
You may wish to execute another contract through a mock. Given the "AmIRichAlready" code below, you could call constant functions using staticcall
:
const contractFactory = new ContractFactory(AmIRichAlready.abi, AmIRichAlready.bytecode, sender);
const amIRich = await contractFactory.deploy()
const mockERC20 = await deployMockContract(sender, IERC20.abi);
let result = await mockERC20.staticcall(amIRich, 'check()')
// you may also just use the function name
result = await mockERC20.staticcall(amIRich, 'check')
expect(result).to.equal(true) // result will be true if you have enough tokens
You may also execute transactions through the mock, using call
:
const contractFactory = new ContractFactory(AmIRichAlready.abi, AmIRichAlready.bytecode, sender);
const amIRich = await contractFactory.deploy()
const mockERC20 = await deployMockContract(sender, IERC20.abi);
let result = await mockERC20.call(amIRich, 'setRichness(uint256)', 1000)
// you may also just use the function name
result = await mockERC20.call(amIRich, 'setRichness', 1000)
expect(await amIRich.richness()).to.equal('1000') // richness was updated
The example below illustrates how mock-contract
can be used to test the very simple AmIRichAlready
contract.
pragma solidity ^0.6.0;
interface IERC20 {
function balanceOf(address account) external view returns (uint256);
}
contract AmIRichAlready {
IERC20 private tokenContract;
uint public richness = 1000000 * 10 ** 18;
constructor (IERC20 _tokenContract) public {
tokenContract = _tokenContract;
}
function check() public view returns (bool) {
uint balance = tokenContract.balanceOf(msg.sender);
return balance > richness;
}
function setRichness(uint256 _richness) {
richness = _richness;
}
}
We are mostly interested in the tokenContract.balanceOf
call. Mock contract will be used to mock exactly this call with values that are significant for the return of the check()
method.
const {use, expect} = require('chai');
const {ContractFactory, utils} = require('ethers');
const {MockProvider} = require('@ethereum-waffle/provider');
const {waffleChai} = require('@ethereum-waffle/chai');
const {deployMockContract} = require('@ethereum-waffle/mock-contract');
const IERC20 = require('../build/IERC20');
const AmIRichAlready = require('../build/AmIRichAlready');
use(waffleChai);
describe('Am I Rich Already', () => {
async function setup() {
const [sender, receiver] = new MockProvider().getWallets();
const mockERC20 = await deployMockContract(sender, IERC20.abi);
const contractFactory = new ContractFactory(AmIRichAlready.abi, AmIRichAlready.bytecode, sender);
const contract = await contractFactory.deploy(mockERC20.address);
return {sender, receiver, contract, mockERC20};
}
it('returns false if the wallet has less then 1000000 coins', async () => {
const {contract, mockERC20} = await setup();
await mockERC20.mock.balanceOf.returns(utils.parseEther('999999'));
expect(await contract.check()).to.be.equal(false);
});
it('returns true if the wallet has at least 1000000 coins', async () => {
const {contract, mockERC20} = await setup();
await mockERC20.mock.balanceOf.returns(utils.parseEther('1000001'));
expect(await contract.check()).to.equal(true);
});
it('reverts if the ERC20 reverts', async () => {
const {contract, mockERC20} = await setup();
await mockERC20.mock.balanceOf.reverts();
await expect(contract.check()).to.be.revertedWith('Mock revert');
});
it('returns 1000001 coins for my address and 0 otherwise', async () => {
const {contract, mockERC20, sender, receiver} = await setup();
await mockERC20.mock.balanceOf.returns('0');
await mockERC20.mock.balanceOf.withArgs(sender.address).returns(utils.parseEther('1000001'));
expect(await contract.check()).to.equal(true);
expect(await contract.connect(receiver.address).check()).to.equal(false);
});
});
Special thanks to @spherefoundry for creating the original Doppelganger project.
FAQs
Mock smart contracts in a smart way.
The npm package @gregdhill/mock-contract receives a total of 0 weekly downloads. As such, @gregdhill/mock-contract popularity was classified as not popular.
We found that @gregdhill/mock-contract demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.
Security News
CISOs are racing to adopt AI for cybersecurity, but hurdles in budgets and governance may leave some falling behind in the fight against cyber threats.
Research
Security News
Socket researchers uncovered a backdoored typosquat of BoltDB in the Go ecosystem, exploiting Go Module Proxy caching to persist undetected for years.