Skip to content
This repository has been archived by the owner. It is now read-only.
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
lib
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Depreciation notice

This npm is deprecated and not supported anymore. For smart contract mocking functionality use @ethereum-waffle/mock-contract.

Doppelganger

doppelgänger /ˈdɒp(ə)lˌɡaŋə,ˈdɒp(ə)lˌɡɛŋə/ - an apparition or double of a living person

Build Status

Library for mocking smart contract dependencies during unit testing.

Install

To start using with npm, type:

npm i -D ethereum-doppelganger

or with Yarn:

yarn add --dev ethereum-doppelganger

Doppelganger is currently developed to work with ethers-js exclusively. Support for other framework will be added in a future version.

Usage

Create a instance of Doppelganger providing the ABI/interface of the smart contract you want to mock:

import Doppelganger from 'ethereum-doppelganger';

...

const doppelganger = new Doppelganger(abi);

Deploy a instance of the Doppelganger smart contract:

await doppelganger.deploy(wallet);

Doppelganger can now be passed into other contracts by using the address attribute.

Return values for mocked functions can be set using:

await doppelganger.<nameOfMethod>.returns(<value>)

Example

Below example illustrates how Doppelganger can be used to test the very simple AmIRichAlready contract.

pragma solidity ^0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/IERC20.sol";

contract AmIRichAlready {
    IERC20 private tokenContract;
    address private wallet;
    uint private constant RICHNESS = 1000000 * 10 ** 18;

    constructor (IERC20 _tokenContract) public {
        tokenContract = _tokenContract;
        wallet = msg.sender;
    }

    function check() public view returns(bool) {
        uint balance = tokenContract.balanceOf(wallet);
        return balance > RICHNESS;
    }
}

We are mostly interested in the tokenContract.balanceOf call. Doppelganger will be used to mock exactly this call with values that are significant for the return of the check() method.

import chai, {expect} from 'chai';
import chaiAsPromised from 'chai-as-promised';
import ethers from 'ethers';
import {createMockProvider, deployContract, getWallets} from 'ethereum-waffle';
import Doppelganger from 'ethereum-doppelganger';

import IERC20 from '../../build/IERC20';
import AmIRichAlready from '../../build/AmIRichAlready';

chai.use(chaiAsPromised);

describe('Am I Rich Already?', () => {
  let provider; // connector to the ethereum network - in our case a Ganache instance 
  let user; // the account issuing interactions on the network
  let contract; // an instance of the AmIRichAlready contract
  let doppelganger; // an instance of doppelganger for the ERC20 token we want to observe

  before(async () => {
    provider = createMockProvider(); 
    [user] = await getWallets(provider);
  });

  beforeEach(async () => {
    doppelganger = new Doppelganger(IERC20.interface); // say doppelganger what it should pretend to be
    await doppelganger.deploy(user); // deploy the doppelganger to the chain
    contract = await deployContract(user, AmIRichAlready, [doppelganger.address]); // deploy the contract under test to the chain
  });

  describe('check method', () => {
    it('returns false if the wallet has less then 1000000 DAI', async () => {
      await doppelganger.balanceOf.returns(ethers.utils.parseEther('999999')); // configure doppelganger to return 999999 when balanceOf is called
      await expect(contract.check()).to.eventually.be.fulfilled.and.equal(false);
    });

    it('returns false if the wallet has exactly 1000000 DAI', async () => {
      await doppelganger.balanceOf.returns(ethers.utils.parseEther('1000000')); // subsequent calls override the previous config
      await expect(contract.check()).to.eventually.be.fulfilled.and.equal(false);
    });

    it('returns true if the wallet has more then 1000000 DAI', async () => {
      await doppelganger.balanceOf.returns(ethers.utils.parseEther('1000001'));
      await expect(contract.check()).to.eventually.be.fulfilled.and.equal(true);
    });
  });
});

About

Smart contract mocking tool

Resources

License

Releases

No releases published

Packages

No packages published
You can’t perform that action at this time.