0

I am trying to call a function in another contract, that is protected with an openzepellin Role library.

I am calling availableFunction on the javascript side, which in turn calls protectedFunction. Even though I pass the adminRole address to the constructor of contract B, and then call availableFunction with adminRole, the function reverts.

In A.sol

contract interfaceB {
  function protectedFunc() public;
}

contract A {
  B b;

  constructor(address _B) {
    b = new interfaceB(_B);
  }

  function availableFunction() {
    b.protectedFunc();
  }
}

In B.sol

contract B {
  using Roles for Roles.Role;
  Roles.Role private adminRole;

  constructor(address _adminRole) public {
    adminRole.add(_adminRole);
  }

  function protectedFunc() public {
    require(adminRole.has(msg.sender), "DOES_NOT_HAVE_ADMIN_ROLE");
    ...
  }

}

In A.test.js

const A = artifacts.require("A");
const B = artifacts.require("B");

contract("A", function ([_, adminRole]) {
  beforeEach(async function () {
    b = B.new(adminRole);
    a = A.new(b.address);

  }
  describe("availableFunc", function () {
    it("should pass!", async function () {
      a.availableFunc({from: adminRole)}); // REVERTS!
    })
  }
})

Error: Returned error: VM Exception while processing transaction: revert DOES_NOT_HAVE_ADMIN_ROLE

1

I'm pretty sure your test calling b.protectedFunc(..) passes and if you call a.availableFunction() it will fail. When protectedFunc is called from A then msg.sender will be the address of A.

To make it work you have to use A address in the admin role.

const A = artifacts.require("A");
const B = artifacts.require("B");

contract("A", function ([_, adminRole]) {
  beforeEach(async function () {
    a = await A.new();
    b = await B.new(a.address);
  }
  describe("protectedFunc", function () {
    it("should pass!", async function () {
      a.availableFunction({from: adminRole)});
    })
  }
})
  • Thank you, that looks about right. I've changed my answer please, as there is an extra layer of complication that I missed - namely the constructor of contract A needs B.address! Is there any solution in this case please? – isaacsultan Feb 1 at 7:59
  • 1
    You have a circular dependency A needs B address and B needs A address. You have to split creation in two steps for example 1) contract creation, 2) initialize admin rol. – Ismael Feb 1 at 17:24

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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