3

I have a smart contract that is dependent on a pre-deployed ERC-20 smart contract that is always deployed to the same address (in the local test network as well as public ones).

I want to override the address of a mock smart contract to be the same as that address, but documentation doesn't provide any insight.

So the example smart contract I'm experimenting with is rudimentary example from the documentation:

pragma solidity ^0.6.2;

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;
    }
}

And the test setup is as follows:

import { expect, use } from "chai"
import { Contract, utils, Wallet } from "ethers"
import {
  deployContract,
  deployMockContract,
  MockProvider,
  solidity,
} from "ethereum-waffle"

import IERC20 from "../build/IERC20.json"
import AmIRichAlready from "../build/AmIRichAlready.json"

use(solidity)

describe("Am I Rich Already", () => {
  let mockERC20: Contract
  let contract: Contract
  let wallet: Wallet

  beforeEach(async () => {
    ;[wallet] = new MockProvider().getWallets()
    mockERC20 = await deployMockContract(wallet, IERC20.abi)
    contract = await deployContract(wallet, AmIRichAlready, [mockERC20.address])
  })
})

So I'd like to assign a certain address for the mockERC20, so that calling a method at that address will be handled by the mock smart contract.

I've tried digging through the source code, but no luck so far. Does anyone have any clue wether or not this is even possible?

2 Answers 2

2

Two ways to do this:

  1. (Recommended): If you're using hardhat, use smock. To mock a contract, you can use const myFake = await smock.fake('MyContract', {address: ERC-20 token's address}). You can set the return values of the mock contract with myFake.functionName.returns(returnValue). This works both with external calls (from ethers) and internal calls (from other contracts). I highly recommend learning Smock instead of manually writing mock contracts, it will save you a lot of time in the long run.

  2. (Not Recommended): If you impersonate the account that deployed the ERC20 token, you can usually deploy a contract to the same address as long as your deployment transaction has the same nonce as the original deployment transaction. You can do this with ganache or hardhat. For more info, please see How is the address of an Ethereum contract computed?

0

Hardhat allows users to do this in-house using the "hardhat_setCode" functionality.

        // Deploy the contract you want to replace with 
        const yourFake = await ethers.getContractFactory("YourFake")
        const yourFakeContract = await yourFake.deploy(// your args here)

        // Get the bytecode for that contract using "eth_getCode"
        const yourFakeBytecode = await hre.network.provider.send("eth_getCode", [yourFakeContract.address])

        // Replace the bytecode at the target contract address with your bytecode   
        await hre.network.provider.send("hardhat_setCode", [targetAddress, yourFakeBytecode])

NOTE: Fork the blockchain you want to you want before running this code

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.