1

Let's define an orchestrated contract as one that contains at least one function that can be called by another contract - and that contract only.

The function would implement the restriction like this:

function foo() external {
  require(msg.sender == someOtherContract, "ERR_NOT_AUTHORIZED");
  ...
}

How would one go about writing a unit test for such a function?

I see two possible solutions:

  • Replace msg.sender with a getMsgSender() function that is moved to a library, which is stubbed while testing
  • Stub msg.sender, but no Ethereum development framework I'm aware of (Truffle, Waffle or Hardhat) can do this

Is there a third solution? None of the above excite me. For the latter I'm at the mercy of the framework devs.

3
  • Depending on the particular test I'd use a mock contract or an EOA directly.
    – Ismael
    Sep 8 '20 at 3:29
  • Yeah I think I'll have to use a bespoke mock contract - but how would you use an EOA in this case? Sep 8 '20 at 10:04
  • In this particular test you can use a EOA to call foo, it should revert since it will not match someOtherContract. Depending on the test I may be able to use and EOA to instead of someOtherContract.
    – Ismael
    Sep 8 '20 at 15:23
0
  1. Change the someContract member (e.g using a sub-class that can modify this internal member)
  2. Move the require into a modifier, and in a sub-class, modify the modifier
  3. Use modified vm, like https://www.npmjs.com/package/godmode-for-test
1
  • For 1, changing someOtherContract would break my set-up, since it is currently a MockContract. I purport to keep my tests as unit tests and not integration tests. For 2, that was mentioned in my OP. For 3, thanks, I'll take a look. Sep 7 '20 at 21:31
0

I eventually found a more elegant third solution.

It involves inheriting from the contract that I'm unit-testing and writing additional functions that give unfettered privilege to anyone for modifying the contract storage.

The implementation looks something like this:

/* SDPX-License-Identifier: LGPL-3.0-or-later */
pragma solidity ^0.6.10;

contract Foo {

  uint256 public myStorageVar;

  function foo(uint256 newValue) external {
    require(msg.sender == someOtherContract, "ERR_NOT_AUTHORIZED");
    myStorageVar = newValue;
  }
}

contract Bar is Foo {
  function __godmode_foo(uint256 newValue) external {
    myStorageVar = newValue;
  }
}
3

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.