0

Think about having two contracts:

  • MockToken
  • Faucet (which takes token address as constructor parameter)

To unit test Faucet I would create two new instances:

const token = await MockToken.new()
const faucet = await Faucet.new(token.address)

Now I can perform all my tests in isolation to be sure that Faucet works as expected but how do I make sure that the deployed Faucet refers to the correct token address and that I have not mistakenly provided a wrong address in the migration?

Do I just get the Faucet.deployed() and check that his token address is the one that I expect? If so, should I do it inside the same file that contains unit tests or in a sepate file?

0

There may be a better way to do this, but usually, I pre-calculate the expected deployed contract address(es) and then I run a check to validate that the deployed contract address(es) matches the expected address(es), if any don't match, I abort the migration:

const ethers = require('ethers');
const utils = require('../lib/utils/utils.js');
const Governance = artifacts.require("Governance");

const privateKey = process.env["PRIVATE_KEY"];

module.exports = function(deployer, network, accounts) {
  deployer.then(async () => {

    let provider = ethers.getDefaultProvider("rinkeby");
    let walletWithProvider = new ethers.Wallet(privateKey, provider);
    let walletPublicKey = walletWithProvider.address;

    const nonce = await walletWithProvider.getTransactionCount();

    console.log('\r\nCurrent nonce: ', nonce);

    const GovernanceAddress = await utils.getAddress(walletPublicKey, nonce + 1);

    console.log(`\r\nExpected GovernanceAddress: ${GovernanceAddress}`);

    const GovernanceContract = await deployer.deploy(Governance);

    if(GovernanceContract.address.toLowerCase() !== GovernanceAddress) {
        throw new Error("GovernanceContract Address Does Not Match Expected Address (GovernanceAddress) - Aborting Deployment");
    }

  });
}

Here is the utils function being used as utils.getAddress to pre-calculate the contract address(es):

import { solidityKeccak256 } from 'ethers/utils';
import * as rlp from 'rlp';

export const getAddress = (deployer, nonce) => {
  return (
    '0x' +
    solidityKeccak256(['bytes'], [rlp.encode([deployer, nonce])])
      .slice(12)
      .substring(14)
  );
};

Hope that helps in your context :)

|improve this answer|||||
0

When you want two contracts to be closely related I create both before running the tests

contract('MyContract', async () => {
    let token
    let faucet

    // This function will execute once before all the tests
    before(async () => {
        token = await MockToken.new()
        faucet = await Faucet.new(token.address)
    })

    it('Faucet', async () => {
        assert(....)
    })
})
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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